@octane-xplat/patches 0.9.0 → 0.10.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.
- package/package.json +1 -1
- package/patches/@lexical__link@0.51.0.patch +29 -0
- package/patches/@nativescript-community__octane@0.2.4.patch +25 -0
- package/patches/@nativescript__core@9.1.3-next.2.patch +1196 -0
- package/patches/@nativescript__vite@8.0.17.patch +135 -1
- package/patches/octane@0.6.3.patch +418 -26
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
diff --git a/application/application.windows.js b/application/application.windows.js
|
|
2
|
+
index 599c126890de6173fbfadc4cca4bb061e311f749..21b1b14884cc61d2e931416c4121883c1ffba4e5 100644
|
|
3
|
+
--- a/application/application.windows.js
|
|
4
|
+
+++ b/application/application.windows.js
|
|
5
|
+
@@ -338,6 +338,7 @@ function updateAccessibilityProperties(view) {
|
|
6
|
+
if (!view || !view.nativeViewProtected) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
+ Microsoft.UI.Xaml.Automation.AutomationProperties.SetName(view.nativeViewProtected, view.accessibilityLabel ?? '');
|
|
10
|
+
}
|
|
11
|
+
setA11yUpdatePropertiesCallback(updateAccessibilityProperties);
|
|
12
|
+
const applicationEvents = [Application.orientationChangedEvent, Application.systemAppearanceChangedEvent];
|
|
1
13
|
diff --git a/css/css-tree-parser.js b/css/css-tree-parser.js
|
|
2
14
|
index 0c13e7e67a8eb306248d738bb73189b772b4a409..7ce38a9ba8f1f9aef709136b46f8e5b2435ba714 100644
|
|
3
15
|
--- a/css/css-tree-parser.js
|
|
@@ -47,6 +59,247 @@ index 3ac4f618f307864cb95b70cd01f4ecdc42c9d9e4..1906ed1457de195a799c9e938136f078
|
|
|
47
59
|
export interface StyleSheet {
|
|
48
60
|
rules: Rule[];
|
|
49
61
|
}
|
|
62
|
+
diff --git a/ui/core/properties/index.js b/ui/core/properties/index.js
|
|
63
|
+
index 333ac76a172c54da8049ed6807439fa52d09a0aa..0974c33b80b8f25d0542487c7f231bdf2d6ec682 100644
|
|
64
|
+
--- a/ui/core/properties/index.js
|
|
65
|
+
+++ b/ui/core/properties/index.js
|
|
66
|
+
@@ -280,7 +280,7 @@ export class Property {
|
|
67
|
+
};
|
|
68
|
+
const property = this;
|
|
69
|
+
this.set = function (boxedValue, origin) {
|
|
70
|
+
- const reset = isResetValue(boxedValue);
|
|
71
|
+
+ const reset = boxedValue === unsetValue;
|
|
72
|
+
let value;
|
|
73
|
+
let wrapped;
|
|
74
|
+
if (reset) {
|
|
75
|
+
@@ -446,7 +446,7 @@ export class CoercibleProperty extends Property {
|
|
76
|
+
target[propertyName] = originalValue;
|
|
77
|
+
};
|
|
78
|
+
this.set = function (boxedValue) {
|
|
79
|
+
- const reset = isResetValue(boxedValue);
|
|
80
|
+
+ const reset = boxedValue === unsetValue;
|
|
81
|
+
let value;
|
|
82
|
+
let wrapped;
|
|
83
|
+
if (reset) {
|
|
84
|
+
@@ -542,7 +542,7 @@ export class InheritedProperty extends Property {
|
|
85
|
+
const that = this;
|
|
86
|
+
let unboxedValue;
|
|
87
|
+
let newValueSource;
|
|
88
|
+
- if (isResetValue(value)) {
|
|
89
|
+
+ if (value === unsetValue) {
|
|
90
|
+
const parent = that.parent;
|
|
91
|
+
// If value is not initial or unset and view has a parent that has non-default value, use it as the reset value.
|
|
92
|
+
if (value !== 'initial' && parent && parent[sourceKey] !== 0 /* ValueSource.Default */) {
|
|
93
|
+
diff --git a/ui/core/view/index.windows.d.ts b/ui/core/view/index.windows.d.ts
|
|
94
|
+
index 8c55d09f9cf58714b8981ebbe33d5989e295a8b9..81555e90bee14d3b3ed47c925f3dc1b1de92300b 100644
|
|
95
|
+
--- a/ui/core/view/index.windows.d.ts
|
|
96
|
+
+++ b/ui/core/view/index.windows.d.ts
|
|
97
|
+
@@ -1,7 +1,8 @@
|
|
98
|
+
export * from './view-common';
|
|
99
|
+
export * from './view-helper';
|
|
100
|
+
export * from '../properties';
|
|
101
|
+
-import { ViewCommon, originXProperty, originYProperty } from './view-common';
|
|
102
|
+
+import { ViewCommon, originXProperty, originYProperty, isEnabledProperty } from './view-common';
|
|
103
|
+
+import { accessibilityLabelProperty } from '../../../accessibility/accessibility-properties';
|
|
104
|
+
import type { CoreTypes } from '../../../core-types';
|
|
105
|
+
import { visibilityProperty, opacityProperty, backgroundInternalProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, rotateProperty, rotateXProperty, rotateYProperty, perspectiveProperty, horizontalAlignmentProperty, verticalAlignmentProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from '../../styling/style-properties';
|
|
106
|
+
import { widthProperty, heightProperty, minWidthProperty, minHeightProperty, marginLeftProperty, marginTopProperty, marginRightProperty, marginBottomProperty } from '../../styling/style-properties';
|
|
107
|
+
@@ -13,6 +14,8 @@ export declare function _ensureNativeTransforms(native: any): {
|
|
108
|
+
translate: any;
|
|
109
|
+
} | null;
|
|
110
|
+
export declare class View extends ViewCommon {
|
|
111
|
+
+ [isEnabledProperty.setNative]: (value: boolean) => void;
|
|
112
|
+
+ [accessibilityLabelProperty.setNative]: (_value: string) => void;
|
|
113
|
+
[backgroundInternalProperty.getDefault]: () => any;
|
|
114
|
+
[backgroundInternalProperty.setNative]: (value: any) => void;
|
|
115
|
+
[widthProperty.setNative]: (value: CoreTypes.PercentLengthType) => void;
|
|
116
|
+
diff --git a/ui/core/view/index.windows.js b/ui/core/view/index.windows.js
|
|
117
|
+
index 9adf9e78c4714b02c8fa53b45fc7c53e7f93a72d..20826905d88ff7a7634ae6f20325a3c2e0097ada 100644
|
|
118
|
+
--- a/ui/core/view/index.windows.js
|
|
119
|
+
+++ b/ui/core/view/index.windows.js
|
|
120
|
+
@@ -1,7 +1,9 @@
|
|
121
|
+
export * from './view-common';
|
|
122
|
+
export * from './view-helper';
|
|
123
|
+
export * from '../properties';
|
|
124
|
+
-import { ViewCommon, originXProperty, originYProperty } from './view-common';
|
|
125
|
+
+import { ViewCommon, originXProperty, originYProperty, isEnabledProperty } from './view-common';
|
|
126
|
+
+import { accessibilityLabelProperty } from '../../../accessibility/accessibility-properties';
|
|
127
|
+
+import { updateA11yPropertiesCallback } from '../../../application/helpers-common';
|
|
128
|
+
import { visibilityProperty, opacityProperty, backgroundInternalProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, rotateProperty, rotateXProperty, rotateYProperty, perspectiveProperty, horizontalAlignmentProperty, verticalAlignmentProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from '../../styling/style-properties';
|
|
129
|
+
import { widthProperty, heightProperty, minWidthProperty, minHeightProperty, marginLeftProperty, marginTopProperty, marginRightProperty, marginBottomProperty } from '../../styling/style-properties';
|
|
130
|
+
import { layout } from '../../../utils';
|
|
131
|
+
@@ -645,6 +647,10 @@ export class View extends ViewCommon {
|
|
132
|
+
this._nativeBackgroundState = 'invalid';
|
|
133
|
+
this._percentWidth = null; // null = not set
|
|
134
|
+
this._percentHeight = null;
|
|
135
|
+
+ this._percentParent = null;
|
|
136
|
+
+ this._percentSizingGeneration = 0;
|
|
137
|
+
+ this._percentSizingPending = false;
|
|
138
|
+
+ this._percentParentChanged = () => this._schedulePercentSizing();
|
|
139
|
+
// Held SizeChanged delegate (prevents GC; see _ensureSizeWatch).
|
|
140
|
+
this._sizeChangedDelegate = null;
|
|
141
|
+
this._sizeWatchWired = false;
|
|
142
|
+
@@ -1164,6 +1170,15 @@ export class View extends ViewCommon {
|
|
143
|
+
})
|
|
144
|
+
.catch(() => { });
|
|
145
|
+
}
|
|
146
|
+
+ [isEnabledProperty.setNative](value) {
|
|
147
|
+
+ const native = this.nativeViewProtected;
|
|
148
|
+
+ if (native && typeof native.IsEnabled !== 'undefined') {
|
|
149
|
+
+ native.IsEnabled = value;
|
|
150
|
+
+ }
|
|
151
|
+
+ }
|
|
152
|
+
+ [accessibilityLabelProperty.setNative](_value) {
|
|
153
|
+
+ updateA11yPropertiesCallback(this);
|
|
154
|
+
+ }
|
|
155
|
+
initNativeView() {
|
|
156
|
+
super.initNativeView();
|
|
157
|
+
// Size-dependent work (percent sizing, border/shadow/clip redraw) is wired ON DEMAND via
|
|
158
|
+
@@ -1173,6 +1188,56 @@ export class View extends ViewCommon {
|
|
159
|
+
this._ensureSizeWatch();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
+ onLoaded() {
|
|
163
|
+
+ super.onLoaded();
|
|
164
|
+
+ this._syncPercentParent();
|
|
165
|
+
+ }
|
|
166
|
+
+ onUnloaded() {
|
|
167
|
+
+ this._clearPercentParent();
|
|
168
|
+
+ super.onUnloaded();
|
|
169
|
+
+ }
|
|
170
|
+
+ _parentChanged(oldParent) {
|
|
171
|
+
+ super._parentChanged(oldParent);
|
|
172
|
+
+ this._syncPercentParent();
|
|
173
|
+
+ }
|
|
174
|
+
+ _clearPercentParent() {
|
|
175
|
+
+ this._percentSizingGeneration++;
|
|
176
|
+
+ this._percentSizingPending = false;
|
|
177
|
+
+ this._percentParent?.off(ViewCommon.layoutChangedEvent, this._percentParentChanged);
|
|
178
|
+
+ for (const eventName of ['paddingLeftChange', 'paddingRightChange', 'paddingTopChange', 'paddingBottomChange']) {
|
|
179
|
+
+ this._percentParent?.style.off(eventName, this._percentParentChanged);
|
|
180
|
+
+ }
|
|
181
|
+
+ this._percentParent = null;
|
|
182
|
+
+ }
|
|
183
|
+
+ _syncPercentParent() {
|
|
184
|
+
+ const parent = this.isLoaded && (this._percentWidth != null || this._percentHeight != null) && this.parent instanceof View ? this.parent : null;
|
|
185
|
+
+ if (parent !== this._percentParent) {
|
|
186
|
+
+ this._clearPercentParent();
|
|
187
|
+
+ this._percentParent = parent;
|
|
188
|
+
+ // Core Observable multiplexes listeners over the parent's existing deferred size watch.
|
|
189
|
+
+ parent?.on(ViewCommon.layoutChangedEvent, this._percentParentChanged);
|
|
190
|
+
+ for (const eventName of ['paddingLeftChange', 'paddingRightChange', 'paddingTopChange', 'paddingBottomChange']) {
|
|
191
|
+
+ parent?.style.on(eventName, this._percentParentChanged);
|
|
192
|
+
+ }
|
|
193
|
+
+ }
|
|
194
|
+
+ if (parent)
|
|
195
|
+
+ this._schedulePercentSizing();
|
|
196
|
+
+ }
|
|
197
|
+
+ _schedulePercentSizing() {
|
|
198
|
+
+ if (this._percentSizingPending)
|
|
199
|
+
+ return;
|
|
200
|
+
+ this._percentSizingPending = true;
|
|
201
|
+
+ const generation = this._percentSizingGeneration;
|
|
202
|
+
+ const ref = new WeakRef(this);
|
|
203
|
+
+ setTimeout(() => {
|
|
204
|
+
+ const owner = ref.deref();
|
|
205
|
+
+ if (!owner || generation !== owner._percentSizingGeneration)
|
|
206
|
+
+ return;
|
|
207
|
+
+ owner._percentSizingPending = false;
|
|
208
|
+
+ if (owner.isLoaded && owner._percentParent === owner.parent)
|
|
209
|
+
+ owner._applyPercentSizing();
|
|
210
|
+
+ }, 0);
|
|
211
|
+
+ }
|
|
212
|
+
// XAML lays views out natively, so core's own layout pass (and the bounds it records) never runs:
|
|
213
|
+
// read the bounds off the element. In device pixels relative to the parent, as on Android.
|
|
214
|
+
_getCurrentLayoutBounds() {
|
|
215
|
+
@@ -1477,6 +1542,7 @@ export class View extends ViewCommon {
|
|
216
|
+
step();
|
|
217
|
+
}
|
|
218
|
+
disposeNativeView() {
|
|
219
|
+
+ this._clearPercentParent();
|
|
220
|
+
const nativeView = this.nativeViewProtected;
|
|
221
|
+
if (nativeView && this._sizeWatchWired) {
|
|
222
|
+
nativeView.SizeChanged = null;
|
|
223
|
+
@@ -1484,6 +1550,8 @@ export class View extends ViewCommon {
|
|
224
|
+
// Reset so a recycled view re-wires on the next size-dependent property set.
|
|
225
|
+
this._sizeWatchWired = false;
|
|
226
|
+
this._sizeChangedDelegate = null;
|
|
227
|
+
+ this._lastLayoutW = NaN;
|
|
228
|
+
+ this._lastLayoutH = NaN;
|
|
229
|
+
// Its shadow and border overlays are siblings in the old parent.
|
|
230
|
+
this._viewCompositionHandler?.Free();
|
|
231
|
+
this._viewCompositionHandler = null;
|
|
232
|
+
@@ -1554,18 +1622,22 @@ export class View extends ViewCommon {
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const parentNative = this.parent?.nativeViewProtected;
|
|
236
|
+
- const parentWidth = parentNative?.ActualWidth || 0;
|
|
237
|
+
- const parentHeight = parentNative?.ActualHeight || 0;
|
|
238
|
+
+ const parentStyle = this.parent?.style;
|
|
239
|
+
+ // Percentages refer to the content box, including when the parent owns native padding.
|
|
240
|
+
+ const parentWidth = Math.max(0, (parentNative?.ActualWidth || 0) - (toXamlLength(parentStyle?.paddingLeft) || 0) - (toXamlLength(parentStyle?.paddingRight) || 0));
|
|
241
|
+
+ const parentHeight = Math.max(0, (parentNative?.ActualHeight || 0) - (toXamlLength(parentStyle?.paddingTop) || 0) - (toXamlLength(parentStyle?.paddingBottom) || 0));
|
|
242
|
+
// Only apply when parent has a real layout size. Using Window.Bounds as fallback when
|
|
243
|
+
// parent is 0 causes nested height="100%" views to overflow the container and cover
|
|
244
|
+
// sibling rows; LayoutUpdated fires again once the parent is properly sized.
|
|
245
|
+
- if (this._percentWidth != null && parentWidth > 0) {
|
|
246
|
+
+ if (this._percentWidth != null && parentNative?.ActualWidth > 0) {
|
|
247
|
+
const w = parentWidth * (this._percentWidth);
|
|
248
|
+
- nativeView.Width = isFinite(w) ? w : NaN;
|
|
249
|
+
+ if (Math.abs(nativeView.Width - w) >= 0.01 || !isFinite(nativeView.Width))
|
|
250
|
+
+ nativeView.Width = isFinite(w) ? w : NaN;
|
|
251
|
+
}
|
|
252
|
+
- if (this._percentHeight != null && parentHeight > 0) {
|
|
253
|
+
+ if (this._percentHeight != null && parentNative?.ActualHeight > 0) {
|
|
254
|
+
const h = parentHeight * (this._percentHeight);
|
|
255
|
+
- nativeView.Height = isFinite(h) ? h : NaN;
|
|
256
|
+
+ if (Math.abs(nativeView.Height - h) >= 0.01 || !isFinite(nativeView.Height))
|
|
257
|
+
+ nativeView.Height = isFinite(h) ? h : NaN;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
catch (_e) { }
|
|
261
|
+
@@ -1586,10 +1658,12 @@ export class View extends ViewCommon {
|
|
262
|
+
const pct = value.value;
|
|
263
|
+
if (this.parent instanceof View && this.parent._setChildPercentSize(this, true, pct)) {
|
|
264
|
+
this._percentWidth = null;
|
|
265
|
+
+ this._syncPercentParent();
|
|
266
|
+
this.nativeViewProtected.Width = NaN;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
this._percentWidth = pct;
|
|
270
|
+
+ this._syncPercentParent();
|
|
271
|
+
this._ensureSizeWatch(); // re-apply percent when the parent resizes
|
|
272
|
+
this.nativeViewProtected.Width = NaN;
|
|
273
|
+
if (pct >= 1) {
|
|
274
|
+
@@ -1613,6 +1687,7 @@ export class View extends ViewCommon {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
this._percentWidth = null;
|
|
278
|
+
+ this._syncPercentParent();
|
|
279
|
+
if (this.parent instanceof View)
|
|
280
|
+
this.parent._setChildPercentSize(this, true, null);
|
|
281
|
+
// Clear any previously set flex-basis so the C++ widget falls back to DesiredSize.
|
|
282
|
+
@@ -1631,10 +1706,12 @@ export class View extends ViewCommon {
|
|
283
|
+
const pct = value.value;
|
|
284
|
+
if (this.parent instanceof View && this.parent._setChildPercentSize(this, false, pct)) {
|
|
285
|
+
this._percentHeight = null;
|
|
286
|
+
+ this._syncPercentParent();
|
|
287
|
+
this.nativeViewProtected.Height = NaN;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
this._percentHeight = pct;
|
|
291
|
+
+ this._syncPercentParent();
|
|
292
|
+
this._ensureSizeWatch(); // re-apply percent when the parent resizes
|
|
293
|
+
this.nativeViewProtected.Height = NaN;
|
|
294
|
+
if (pct >= 1) {
|
|
295
|
+
@@ -1657,6 +1734,7 @@ export class View extends ViewCommon {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
this._percentHeight = null;
|
|
299
|
+
+ this._syncPercentParent();
|
|
300
|
+
if (this.parent instanceof View)
|
|
301
|
+
this.parent._setChildPercentSize(this, false, null);
|
|
302
|
+
this.nativeViewProtected.Height = toXamlLength(value);
|
|
50
303
|
diff --git a/ui/core/view-base/index.d.ts b/ui/core/view-base/index.d.ts
|
|
51
304
|
index 170ceb1c65bbf17cffb1c648f2cc5c7c21065115..6941110802e2ade9b4d48a172dbb95801bba96d1 100644
|
|
52
305
|
--- a/ui/core/view-base/index.d.ts
|
|
@@ -83,6 +336,190 @@ index 5f54440b3a3e0a36ddc0139d49db5cbcd6695b75..580061c78ae9326f733f7ea5ebd0dbf9
|
|
|
83
336
|
/**
|
|
84
337
|
* Core logic for removing a child view from this instance. Used by the framework to handle lifecycle events more centralized. Do not use outside the UI Stack implementation.
|
|
85
338
|
*/
|
|
339
|
+
diff --git a/ui/editable-text-base/index.windows.d.ts b/ui/editable-text-base/index.windows.d.ts
|
|
340
|
+
index 33d2058f382c3c83512209b2e18623a8c653454b..79f0f50310533b9d681fc14017db49909e01c653 100644
|
|
341
|
+
--- a/ui/editable-text-base/index.windows.d.ts
|
|
342
|
+
+++ b/ui/editable-text-base/index.windows.d.ts
|
|
343
|
+
@@ -2,8 +2,10 @@ export * from './editable-text-base-common';
|
|
344
|
+
import { EditableTextBase as EditableTextBaseCommon, autofillTypeProperty, keyboardTypeProperty, returnKeyTypeProperty, editableProperty, autocapitalizationTypeProperty, autocorrectProperty, hintProperty, placeholderColorProperty, maxLengthProperty } from './editable-text-base-common';
|
|
345
|
+
import { textProperty } from '../text-base';
|
|
346
|
+
import { Color } from '../../color';
|
|
347
|
+
+import { isEnabledProperty } from '../core/view/view-common';
|
|
348
|
+
export * from './editable-text-base-common';
|
|
349
|
+
export declare abstract class EditableTextBase extends EditableTextBaseCommon {
|
|
350
|
+
+ [isEnabledProperty.setNative]: (_value: boolean) => void;
|
|
351
|
+
[textProperty.setNative]: (value: string | symbol) => void;
|
|
352
|
+
[keyboardTypeProperty.getDefault]: () => string;
|
|
353
|
+
[keyboardTypeProperty.setNative]: (_value: string) => void;
|
|
354
|
+
@@ -18,9 +20,17 @@ export declare abstract class EditableTextBase extends EditableTextBaseCommon {
|
|
355
|
+
[maxLengthProperty.setNative]: (value: number) => void;
|
|
356
|
+
nativeViewProtected: Microsoft.UI.Xaml.Controls.TextBox | Microsoft.UI.Xaml.Controls.PasswordBox;
|
|
357
|
+
private _changeFromCode;
|
|
358
|
+
- private _textChangeDelegate;
|
|
359
|
+
+ private _inputNative;
|
|
360
|
+
+ private _inputDisposers;
|
|
361
|
+
+ private _focused;
|
|
362
|
+
initNativeView(): void;
|
|
363
|
+
+ onLoaded(): void;
|
|
364
|
+
+ onUnloaded(): void;
|
|
365
|
+
+ disposeNativeView(): void;
|
|
366
|
+
+ private _notifyFocus;
|
|
367
|
+
+ private _detachInputListeners;
|
|
368
|
+
_attachTextChangeListener(): void;
|
|
369
|
+
+ protected _updateInputEnabled(): void;
|
|
370
|
+
private _onNativeTextChanged;
|
|
371
|
+
dismissSoftInput(): void;
|
|
372
|
+
focus(): boolean;
|
|
373
|
+
diff --git a/ui/editable-text-base/index.windows.js b/ui/editable-text-base/index.windows.js
|
|
374
|
+
index 1ea9d7502e405266a5369b10eee7b5ce971c7649..0496d481a8bfc9570ca591d8376b2a802f0227dc 100644
|
|
375
|
+
--- a/ui/editable-text-base/index.windows.js
|
|
376
|
+
+++ b/ui/editable-text-base/index.windows.js
|
|
377
|
+
@@ -2,47 +2,83 @@ export * from './editable-text-base-common';
|
|
378
|
+
import { EditableTextBase as EditableTextBaseCommon, autofillTypeProperty, keyboardTypeProperty, returnKeyTypeProperty, editableProperty, autocapitalizationTypeProperty, autocorrectProperty, hintProperty, placeholderColorProperty, maxLengthProperty } from './editable-text-base-common';
|
|
379
|
+
import { textProperty, resetSymbol } from '../text-base';
|
|
380
|
+
import { Color } from '../../color';
|
|
381
|
+
+import { isEnabledProperty } from '../core/view/view-common';
|
|
382
|
+
+import { subscribeNativeEvent } from '../gestures/pointer-events.windows';
|
|
383
|
+
export * from './editable-text-base-common';
|
|
384
|
+
export class EditableTextBase extends EditableTextBaseCommon {
|
|
385
|
+
constructor() {
|
|
386
|
+
super(...arguments);
|
|
387
|
+
- // Guards against the native TextChanged firing while we write text from JS (avoids loops).
|
|
388
|
+
this._changeFromCode = false;
|
|
389
|
+
- this._textChangeDelegate = null; // held so the handler isn't GC'd (would go dead)
|
|
390
|
+
+ this._inputNative = null;
|
|
391
|
+
+ this._inputDisposers = [];
|
|
392
|
+
+ this._focused = false;
|
|
393
|
+
}
|
|
394
|
+
initNativeView() {
|
|
395
|
+
super.initNativeView();
|
|
396
|
+
this._attachTextChangeListener();
|
|
397
|
+
+ this._updateInputEnabled();
|
|
398
|
+
+ }
|
|
399
|
+
+ onLoaded() {
|
|
400
|
+
+ super.onLoaded();
|
|
401
|
+
+ this._attachTextChangeListener();
|
|
402
|
+
+ }
|
|
403
|
+
+ onUnloaded() {
|
|
404
|
+
+ this._detachInputListeners();
|
|
405
|
+
+ super.onUnloaded();
|
|
406
|
+
+ }
|
|
407
|
+
+ disposeNativeView() {
|
|
408
|
+
+ this._detachInputListeners();
|
|
409
|
+
+ super.disposeNativeView();
|
|
410
|
+
+ }
|
|
411
|
+
+ _notifyFocus(focused) {
|
|
412
|
+
+ if (this._focused === focused)
|
|
413
|
+
+ return;
|
|
414
|
+
+ this._focused = focused;
|
|
415
|
+
+ this.notify({ eventName: focused ? EditableTextBaseCommon.focusEvent : EditableTextBaseCommon.blurEvent, object: this });
|
|
416
|
+
+ }
|
|
417
|
+
+ _detachInputListeners() {
|
|
418
|
+
+ this._inputNative = null;
|
|
419
|
+
+ for (const dispose of this._inputDisposers.splice(0))
|
|
420
|
+
+ dispose();
|
|
421
|
+
+ this._notifyFocus(false);
|
|
422
|
+
}
|
|
423
|
+
- // Wires the native text-change event so typing flows back into the framework (valueFormatter,
|
|
424
|
+
- // `textChange`). Re-callable because TextField swaps its native view on `secure`.
|
|
425
|
+
_attachTextChangeListener() {
|
|
426
|
+
- const nv = this.nativeViewProtected;
|
|
427
|
+
- if (!nv) {
|
|
428
|
+
+ const native = this.nativeViewProtected;
|
|
429
|
+
+ if (this._inputNative === native)
|
|
430
|
+
return;
|
|
431
|
+
- }
|
|
432
|
+
+ this._detachInputListeners();
|
|
433
|
+
+ if (!native || !this.isLoaded)
|
|
434
|
+
+ return;
|
|
435
|
+
+ this._inputNative = native;
|
|
436
|
+
const ref = new WeakRef(this);
|
|
437
|
+
- const asTextBox = nv;
|
|
438
|
+
- const asPassword = nv;
|
|
439
|
+
- if (typeof asTextBox.Text !== 'undefined') {
|
|
440
|
+
- this._textChangeDelegate = NSWinRT.asDelegate('Microsoft.UI.Xaml.Controls.TextChangedEventHandler', (sender) => {
|
|
441
|
+
+ const listen = (name, type, callback) => {
|
|
442
|
+
+ this._inputDisposers.push(subscribeNativeEvent(native, name, (sender) => {
|
|
443
|
+
const owner = ref.deref();
|
|
444
|
+
- if (owner)
|
|
445
|
+
- owner._onNativeTextChanged(sender.Text ?? '');
|
|
446
|
+
- });
|
|
447
|
+
- asTextBox.TextChanged = this._textChangeDelegate;
|
|
448
|
+
+ if (owner?.isLoaded && owner._inputNative === native && owner.nativeViewProtected === native)
|
|
449
|
+
+ callback(owner, sender);
|
|
450
|
+
+ }, null, (handler) => NSWinRT.asDelegate(type, handler)));
|
|
451
|
+
+ };
|
|
452
|
+
+ if (typeof native.Text !== 'undefined') {
|
|
453
|
+
+ listen('TextChanged', 'Microsoft.UI.Xaml.Controls.TextChangedEventHandler', (owner, sender) => owner._onNativeTextChanged(sender.Text ?? ''));
|
|
454
|
+
}
|
|
455
|
+
- else if (typeof asPassword.Password !== 'undefined') {
|
|
456
|
+
- this._textChangeDelegate = NSWinRT.asDelegate('Microsoft.UI.Xaml.RoutedEventHandler', (sender) => {
|
|
457
|
+
- const owner = ref.deref();
|
|
458
|
+
- if (owner)
|
|
459
|
+
- owner._onNativeTextChanged(sender.Password ?? '');
|
|
460
|
+
- });
|
|
461
|
+
- asPassword.PasswordChanged = this._textChangeDelegate;
|
|
462
|
+
+ else {
|
|
463
|
+
+ listen('PasswordChanged', 'Microsoft.UI.Xaml.RoutedEventHandler', (owner, sender) => owner._onNativeTextChanged(sender.Password ?? ''));
|
|
464
|
+
}
|
|
465
|
+
+ listen('GotFocus', 'Microsoft.UI.Xaml.RoutedEventHandler', (owner) => owner._notifyFocus(true));
|
|
466
|
+
+ listen('LostFocus', 'Microsoft.UI.Xaml.RoutedEventHandler', (owner) => owner._notifyFocus(false));
|
|
467
|
+
+ }
|
|
468
|
+
+ _updateInputEnabled() {
|
|
469
|
+
+ const native = this.nativeViewProtected;
|
|
470
|
+
+ if (!native)
|
|
471
|
+
+ return;
|
|
472
|
+
+ // PasswordBox has no readonly mode; disable it to protect the value.
|
|
473
|
+
+ native.IsEnabled = this.isEnabled && (typeof native.Password === 'undefined' || this.editable);
|
|
474
|
+
+ }
|
|
475
|
+
+ [isEnabledProperty.setNative](_value) {
|
|
476
|
+
+ this._updateInputEnabled();
|
|
477
|
+
}
|
|
478
|
+
_onNativeTextChanged(rawText) {
|
|
479
|
+
- if (this._changeFromCode) {
|
|
480
|
+
+ if (this._changeFromCode || !this.isEnabled || !this.editable) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
let value = rawText;
|
|
484
|
+
@@ -86,19 +122,20 @@ export class EditableTextBase extends EditableTextBaseCommon {
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
dismissSoftInput() {
|
|
488
|
+
- const nativeView = this.nativeViewProtected;
|
|
489
|
+
- if (nativeView) {
|
|
490
|
+
- // Toggling focusability is the only way to drop focus from a TextBox/PasswordBox.
|
|
491
|
+
- nativeView.IsEnabled = false;
|
|
492
|
+
- nativeView.IsEnabled = true;
|
|
493
|
+
+ const native = this.nativeViewProtected;
|
|
494
|
+
+ if (!native || !native.IsEnabled || native.FocusState === Microsoft.UI.Xaml.FocusState.Unfocused)
|
|
495
|
+
+ return;
|
|
496
|
+
+ native.IsEnabled = false;
|
|
497
|
+
+ try {
|
|
498
|
+
+ this._notifyFocus(false);
|
|
499
|
+
+ }
|
|
500
|
+
+ finally {
|
|
501
|
+
+ this._updateInputEnabled();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
focus() {
|
|
505
|
+
- const result = super.focus();
|
|
506
|
+
- if (result && this.nativeViewProtected) {
|
|
507
|
+
- this.nativeViewProtected.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
|
|
508
|
+
- }
|
|
509
|
+
- return result;
|
|
510
|
+
+ const native = this.nativeViewProtected;
|
|
511
|
+
+ return !!(this.isLoaded && native?.IsEnabled && native.Focus(Microsoft.UI.Xaml.FocusState.Programmatic));
|
|
512
|
+
}
|
|
513
|
+
[keyboardTypeProperty.getDefault]() {
|
|
514
|
+
return '';
|
|
515
|
+
@@ -118,6 +155,7 @@ export class EditableTextBase extends EditableTextBaseCommon {
|
|
516
|
+
if (typeof nativeView.IsReadOnly !== 'undefined') {
|
|
517
|
+
nativeView.IsReadOnly = !value;
|
|
518
|
+
}
|
|
519
|
+
+ this._updateInputEnabled();
|
|
520
|
+
}
|
|
521
|
+
[autocapitalizationTypeProperty.setNative](_value) { }
|
|
522
|
+
[autocorrectProperty.setNative](_value) { }
|
|
86
523
|
diff --git a/ui/frame/frame-common.js b/ui/frame/frame-common.js
|
|
87
524
|
index 8637cacf417baebce945c58681daa86ca83dce46..c06da239d58b6174652b120e024f853f58d2c13f 100644
|
|
88
525
|
--- a/ui/frame/frame-common.js
|
|
@@ -163,6 +600,621 @@ index 9ded225f53e4c4af92166a3e019671a1a65a2db2..9a9f5d5f9f891c9bcf6035b0345f4bb2
|
|
|
163
600
|
export function _popFromFrameStack(frame) {
|
|
164
601
|
if (!frame._isInFrameStack) {
|
|
165
602
|
return;
|
|
603
|
+
diff --git a/ui/gestures/index.windows.d.ts b/ui/gestures/index.windows.d.ts
|
|
604
|
+
index bf1d68d4b7c014d2bc129ca6cea0bc26c722ea9f..cbb3c5109305730bc3ad82513be86794f8e471d3 100644
|
|
605
|
+
--- a/ui/gestures/index.windows.d.ts
|
|
606
|
+
+++ b/ui/gestures/index.windows.d.ts
|
|
607
|
+
@@ -8,15 +8,7 @@ export declare function isHovered(view: View): boolean;
|
|
608
|
+
export declare class GesturesObserver extends GesturesObserverBase {
|
|
609
|
+
private _onTargetLoaded;
|
|
610
|
+
private _onTargetUnloaded;
|
|
611
|
+
- private _pointerPressedHandler;
|
|
612
|
+
- private _pointerMovedHandler;
|
|
613
|
+
- private _pointerReleasedHandler;
|
|
614
|
+
- private _rightTappedHandler;
|
|
615
|
+
- private _pointerPressedDelegate;
|
|
616
|
+
- private _pointerMovedDelegate;
|
|
617
|
+
- private _pointerReleasedDelegate;
|
|
618
|
+
- private _rightTappedDelegate;
|
|
619
|
+
- private _usingAddHandler;
|
|
620
|
+
+ private _disposers;
|
|
621
|
+
private _pointerDownMap;
|
|
622
|
+
private _lastUpTime;
|
|
623
|
+
private _tapTimeoutId;
|
|
624
|
+
@@ -25,6 +17,7 @@ export declare class GesturesObserver extends GesturesObserverBase {
|
|
625
|
+
disconnect(): void;
|
|
626
|
+
private _detach;
|
|
627
|
+
private _attach;
|
|
628
|
+
+ private _onPointerCanceled;
|
|
629
|
+
androidOnTouchEvent(_motionEvent: any): void;
|
|
630
|
+
private _onPointerPressed;
|
|
631
|
+
private _onPointerMoved;
|
|
632
|
+
diff --git a/ui/gestures/index.windows.js b/ui/gestures/index.windows.js
|
|
633
|
+
index ba8319e96ef61748380875267b797e52cdfba252..fccc5ef84929e8c5fc10c2377eb68c5ab9245055 100644
|
|
634
|
+
--- a/ui/gestures/index.windows.js
|
|
635
|
+
+++ b/ui/gestures/index.windows.js
|
|
636
|
+
@@ -3,6 +3,7 @@ export * from './gestures-types';
|
|
637
|
+
export * from './touch-manager';
|
|
638
|
+
import { GesturesObserverBase, GestureTypes, GestureEvents, GestureStateTypes, toString } from './gestures-common';
|
|
639
|
+
import * as timer from '../../timer';
|
|
640
|
+
+import { subscribeNativeEvent } from './pointer-events.windows';
|
|
641
|
+
// Per-view hover tracking to enable CSS :hover pseudo-class.
|
|
642
|
+
const _hoverViews = new WeakSet();
|
|
643
|
+
let _routedEvents;
|
|
644
|
+
@@ -19,8 +20,10 @@ function routedEvents() {
|
|
645
|
+
rightTapped: UIElement.RightTappedEvent,
|
|
646
|
+
entered: UIElement.PointerEnteredEvent,
|
|
647
|
+
exited: UIElement.PointerExitedEvent,
|
|
648
|
+
+ canceled: UIElement.PointerCanceledEvent,
|
|
649
|
+
+ captureLost: UIElement.PointerCaptureLostEvent,
|
|
650
|
+
};
|
|
651
|
+
- _routedEvents = Object.values(events).every(Boolean) ? events : null;
|
|
652
|
+
+ _routedEvents = events;
|
|
653
|
+
}
|
|
654
|
+
catch (_e) {
|
|
655
|
+
_routedEvents = null;
|
|
656
|
+
@@ -28,82 +31,62 @@ function routedEvents() {
|
|
657
|
+
}
|
|
658
|
+
return _routedEvents;
|
|
659
|
+
}
|
|
660
|
+
-function _attachHoverHandlers(view) {
|
|
661
|
+
- const native = view.nativeViewProtected;
|
|
662
|
+
- if (!native || native.__ns_hover_attached)
|
|
663
|
+
- return;
|
|
664
|
+
- const onEnter = () => {
|
|
665
|
+
- if (_hoverViews.has(view))
|
|
666
|
+
- return;
|
|
667
|
+
- _hoverViews.add(view);
|
|
668
|
+
- try {
|
|
669
|
+
+// Hover belongs to the view, not whichever observer happened to attach last.
|
|
670
|
+
+const hoverOwners = new WeakMap();
|
|
671
|
+
+function _attachHoverHandlers(view, native) {
|
|
672
|
+
+ let owner = hoverOwners.get(view);
|
|
673
|
+
+ if (owner && owner.native !== native) {
|
|
674
|
+
+ owner.dispose();
|
|
675
|
+
+ hoverOwners.delete(view);
|
|
676
|
+
+ owner = undefined;
|
|
677
|
+
+ }
|
|
678
|
+
+ if (!owner) {
|
|
679
|
+
+ const onEnter = () => {
|
|
680
|
+
+ if (_hoverViews.has(view) || view.isEnabled === false)
|
|
681
|
+
+ return;
|
|
682
|
+
+ _hoverViews.add(view);
|
|
683
|
+
view._addVisualState?.('hover');
|
|
684
|
+
- }
|
|
685
|
+
- catch (_e) { }
|
|
686
|
+
- try {
|
|
687
|
+
- view.notify?.({ eventName: 'mouseEnter', object: view });
|
|
688
|
+
- }
|
|
689
|
+
- catch (_e) { }
|
|
690
|
+
- };
|
|
691
|
+
- const onLeave = () => {
|
|
692
|
+
- if (!_hoverViews.has(view))
|
|
693
|
+
- return;
|
|
694
|
+
- _hoverViews.delete(view);
|
|
695
|
+
- try {
|
|
696
|
+
+ view.notify({ eventName: 'mouseEnter', object: view });
|
|
697
|
+
+ };
|
|
698
|
+
+ const onLeave = () => {
|
|
699
|
+
+ if (!_hoverViews.has(view))
|
|
700
|
+
+ return;
|
|
701
|
+
+ _hoverViews.delete(view);
|
|
702
|
+
view._removeVisualState?.('hover');
|
|
703
|
+
- }
|
|
704
|
+
- catch (_e) { }
|
|
705
|
+
+ view.notify({ eventName: 'mouseLeave', object: view });
|
|
706
|
+
+ };
|
|
707
|
+
+ const entered = subscribeNativeEvent(native, 'PointerEntered', onEnter, routedEvents()?.entered, _wrapPointerHandler);
|
|
708
|
+
+ let exited;
|
|
709
|
+
try {
|
|
710
|
+
- view.notify?.({ eventName: 'mouseLeave', object: view });
|
|
711
|
+
+ exited = subscribeNativeEvent(native, 'PointerExited', onLeave, routedEvents()?.exited, _wrapPointerHandler);
|
|
712
|
+
}
|
|
713
|
+
- catch (_e) { }
|
|
714
|
+
- };
|
|
715
|
+
- const enterDelegate = _wrapPointerHandler(onEnter);
|
|
716
|
+
- const leaveDelegate = _wrapPointerHandler(onLeave);
|
|
717
|
+
- let usingAddHandler = false;
|
|
718
|
+
- try {
|
|
719
|
+
- const events = routedEvents();
|
|
720
|
+
- if (!events)
|
|
721
|
+
- throw new Error('RoutedEvent statics unavailable');
|
|
722
|
+
- native.AddHandler(events.entered, enterDelegate, true);
|
|
723
|
+
- native.AddHandler(events.exited, leaveDelegate, true);
|
|
724
|
+
- usingAddHandler = true;
|
|
725
|
+
- }
|
|
726
|
+
- catch (_e) {
|
|
727
|
+
- try {
|
|
728
|
+
- _assignPointerHandler(native, 'PointerEntered', enterDelegate);
|
|
729
|
+
- _assignPointerHandler(native, 'PointerExited', leaveDelegate);
|
|
730
|
+
+ catch (error) {
|
|
731
|
+
+ entered();
|
|
732
|
+
+ throw error;
|
|
733
|
+
}
|
|
734
|
+
- catch (_e2) { }
|
|
735
|
+
+ owner = { count: 0, native, dispose: () => {
|
|
736
|
+
+ try {
|
|
737
|
+
+ entered();
|
|
738
|
+
+ }
|
|
739
|
+
+ finally {
|
|
740
|
+
+ exited();
|
|
741
|
+
+ }
|
|
742
|
+
+ onLeave();
|
|
743
|
+
+ } };
|
|
744
|
+
+ hoverOwners.set(view, owner);
|
|
745
|
+
}
|
|
746
|
+
- native.__ns_hover_attached = true;
|
|
747
|
+
- native.__ns_hover_using_add_handler = usingAddHandler;
|
|
748
|
+
- native.__ns_hover_enter_fn = onEnter;
|
|
749
|
+
- native.__ns_hover_leave_fn = onLeave;
|
|
750
|
+
- native.__ns_hover_enter_delegate = enterDelegate;
|
|
751
|
+
- native.__ns_hover_leave_delegate = leaveDelegate;
|
|
752
|
+
-}
|
|
753
|
+
-function _detachHoverHandlers(view) {
|
|
754
|
+
- const native = view.nativeViewProtected;
|
|
755
|
+
- if (!native || !native.__ns_hover_attached)
|
|
756
|
+
- return;
|
|
757
|
+
- const events = routedEvents();
|
|
758
|
+
- if (native.__ns_hover_using_add_handler && events) {
|
|
759
|
+
- try {
|
|
760
|
+
- if (native.__ns_hover_enter_delegate)
|
|
761
|
+
- native.RemoveHandler(events.entered, native.__ns_hover_enter_delegate);
|
|
762
|
+
- if (native.__ns_hover_leave_delegate)
|
|
763
|
+
- native.RemoveHandler(events.exited, native.__ns_hover_leave_delegate);
|
|
764
|
+
+ owner.count++;
|
|
765
|
+
+ const retained = owner;
|
|
766
|
+
+ let disposed = false;
|
|
767
|
+
+ return () => {
|
|
768
|
+
+ if (disposed)
|
|
769
|
+
+ return;
|
|
770
|
+
+ disposed = true;
|
|
771
|
+
+ if (--retained.count === 0 && hoverOwners.get(view) === retained) {
|
|
772
|
+
+ hoverOwners.delete(view);
|
|
773
|
+
+ retained.dispose();
|
|
774
|
+
}
|
|
775
|
+
- catch (_e) { }
|
|
776
|
+
- }
|
|
777
|
+
- native.__ns_hover_attached = false;
|
|
778
|
+
- native.__ns_hover_using_add_handler = false;
|
|
779
|
+
- native.__ns_hover_enter_fn = null;
|
|
780
|
+
- native.__ns_hover_leave_fn = null;
|
|
781
|
+
- native.__ns_hover_enter_delegate = null;
|
|
782
|
+
- native.__ns_hover_leave_delegate = null;
|
|
783
|
+
- _hoverViews.delete(view);
|
|
784
|
+
+ };
|
|
785
|
+
}
|
|
786
|
+
/** Returns true if the view is currently in a hover state (mouse over). */
|
|
787
|
+
export function isHovered(view) {
|
|
788
|
+
@@ -118,12 +101,6 @@ function _wrapPointerHandler(fn) {
|
|
789
|
+
function _wrapRightTappedHandler(fn) {
|
|
790
|
+
return NSWinRT.asDelegate('Microsoft.UI.Xaml.Input.RightTappedEventHandler', fn);
|
|
791
|
+
}
|
|
792
|
+
-function _assignPointerHandler(native, prop, del) {
|
|
793
|
+
- native[prop] = del;
|
|
794
|
+
-}
|
|
795
|
+
-function _assignRightTappedHandler(native, del) {
|
|
796
|
+
- native.RightTapped = del;
|
|
797
|
+
-}
|
|
798
|
+
function _executeCallback(observer, args) {
|
|
799
|
+
if (observer && observer.callback) {
|
|
800
|
+
observer.callback.call(observer.context, args);
|
|
801
|
+
@@ -176,7 +153,7 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
802
|
+
super(...arguments);
|
|
803
|
+
this._onTargetLoaded = null;
|
|
804
|
+
this._onTargetUnloaded = null;
|
|
805
|
+
- this._usingAddHandler = false;
|
|
806
|
+
+ this._disposers = [];
|
|
807
|
+
this._pointerDownMap = new Map();
|
|
808
|
+
this._lastUpTime = 0;
|
|
809
|
+
this._longPressTimeouts = new Map();
|
|
810
|
+
@@ -196,14 +173,6 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
811
|
+
}
|
|
812
|
+
disconnect() {
|
|
813
|
+
this._detach();
|
|
814
|
+
- this._pointerPressedHandler = null;
|
|
815
|
+
- this._pointerMovedHandler = null;
|
|
816
|
+
- this._pointerReleasedHandler = null;
|
|
817
|
+
- this._rightTappedHandler = null;
|
|
818
|
+
- this._pointerPressedDelegate = null;
|
|
819
|
+
- this._pointerMovedDelegate = null;
|
|
820
|
+
- this._pointerReleasedDelegate = null;
|
|
821
|
+
- this._rightTappedDelegate = null;
|
|
822
|
+
if (this.target) {
|
|
823
|
+
if (this._onTargetLoaded) {
|
|
824
|
+
this.target.off('loaded', this._onTargetLoaded);
|
|
825
|
+
@@ -217,40 +186,17 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
826
|
+
super.disconnect();
|
|
827
|
+
}
|
|
828
|
+
_detach() {
|
|
829
|
+
- try {
|
|
830
|
+
- const native = (this.target && this.target.nativeViewProtected);
|
|
831
|
+
- if (native) {
|
|
832
|
+
- const events = routedEvents();
|
|
833
|
+
- if (this._usingAddHandler && events) {
|
|
834
|
+
- try {
|
|
835
|
+
- if (this._pointerPressedDelegate)
|
|
836
|
+
- native.RemoveHandler(events.pressed, this._pointerPressedDelegate);
|
|
837
|
+
- if (this._pointerMovedDelegate)
|
|
838
|
+
- native.RemoveHandler(events.moved, this._pointerMovedDelegate);
|
|
839
|
+
- if (this._pointerReleasedDelegate)
|
|
840
|
+
- native.RemoveHandler(events.released, this._pointerReleasedDelegate);
|
|
841
|
+
- if (this._rightTappedDelegate)
|
|
842
|
+
- native.RemoveHandler(events.rightTapped, this._rightTappedDelegate);
|
|
843
|
+
- }
|
|
844
|
+
- catch (_e) { }
|
|
845
|
+
- }
|
|
846
|
+
- else {
|
|
847
|
+
- native.PointerPressed = null;
|
|
848
|
+
- native.PointerMoved = null;
|
|
849
|
+
- native.PointerReleased = null;
|
|
850
|
+
- native.RightTapped = null;
|
|
851
|
+
- }
|
|
852
|
+
+ for (const dispose of this._disposers.splice(0).reverse()) {
|
|
853
|
+
+ try {
|
|
854
|
+
+ dispose();
|
|
855
|
+
}
|
|
856
|
+
+ catch (_) { }
|
|
857
|
+
}
|
|
858
|
+
- catch (_e) { }
|
|
859
|
+
- if (this.target) {
|
|
860
|
+
- _detachHoverHandlers(this.target);
|
|
861
|
+
- }
|
|
862
|
+
- this._usingAddHandler = false;
|
|
863
|
+
this._pointerDownMap.clear();
|
|
864
|
+
+ this._lastUpTime = 0;
|
|
865
|
+
this._longPressTimeouts.forEach((id) => timer.clearTimeout(id));
|
|
866
|
+
this._longPressTimeouts.clear();
|
|
867
|
+
- if (this._tapTimeoutId) {
|
|
868
|
+
+ if (this._tapTimeoutId != null) {
|
|
869
|
+
timer.clearTimeout(this._tapTimeoutId);
|
|
870
|
+
this._tapTimeoutId = null;
|
|
871
|
+
}
|
|
872
|
+
@@ -258,70 +204,56 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
873
|
+
_attach(target, type) {
|
|
874
|
+
this._detach();
|
|
875
|
+
const native = target.nativeViewProtected;
|
|
876
|
+
- if (!native) {
|
|
877
|
+
+ if (!native)
|
|
878
|
+
return;
|
|
879
|
+
- }
|
|
880
|
+
- // Kept across load/unload: a view re-attaches each time it is shown again.
|
|
881
|
+
- if (!this._pointerPressedDelegate) {
|
|
882
|
+
- this._pointerPressedHandler = (s, e) => this._onPointerPressed(e || s);
|
|
883
|
+
- this._pointerReleasedHandler = (s, e) => this._onPointerReleased(e || s);
|
|
884
|
+
- this._pointerPressedDelegate = _wrapPointerHandler(this._pointerPressedHandler);
|
|
885
|
+
- this._pointerReleasedDelegate = _wrapPointerHandler(this._pointerReleasedHandler);
|
|
886
|
+
- }
|
|
887
|
+
- // Only touch observers report moves; for the others every mouse move would still call into JS.
|
|
888
|
+
- const wantsMoves = type === GestureTypes.touch;
|
|
889
|
+
- if (wantsMoves && !this._pointerMovedDelegate) {
|
|
890
|
+
- this._pointerMovedHandler = (s, e) => this._onPointerMoved(e || s);
|
|
891
|
+
- this._pointerMovedDelegate = _wrapPointerHandler(this._pointerMovedHandler);
|
|
892
|
+
- }
|
|
893
|
+
- // Use AddHandler with handledEventsToo=true so events fire even when Button (and other
|
|
894
|
+
- // controls) mark pointer events as handled internally.
|
|
895
|
+
- this._usingAddHandler = false;
|
|
896
|
+
+ const events = routedEvents();
|
|
897
|
+
+ const subscribe = (name, event, callback, wrap = _wrapPointerHandler) => {
|
|
898
|
+
+ this._disposers.push(subscribeNativeEvent(native, name, (sender, args) => callback(args || sender), event, wrap));
|
|
899
|
+
+ };
|
|
900
|
+
try {
|
|
901
|
+
- const events = routedEvents();
|
|
902
|
+
- if (!events)
|
|
903
|
+
- throw new Error('RoutedEvent statics unavailable');
|
|
904
|
+
- native.AddHandler(events.pressed, this._pointerPressedDelegate, true);
|
|
905
|
+
- if (wantsMoves)
|
|
906
|
+
- native.AddHandler(events.moved, this._pointerMovedDelegate, true);
|
|
907
|
+
- native.AddHandler(events.released, this._pointerReleasedDelegate, true);
|
|
908
|
+
- this._usingAddHandler = true;
|
|
909
|
+
+ subscribe('PointerPressed', events?.pressed, (args) => this._onPointerPressed(args));
|
|
910
|
+
+ subscribe('PointerMoved', events?.moved, (args) => this._onPointerMoved(args));
|
|
911
|
+
+ subscribe('PointerReleased', events?.released, (args) => this._onPointerReleased(args));
|
|
912
|
+
+ subscribe('PointerCanceled', events?.canceled, (args) => this._onPointerCanceled(args));
|
|
913
|
+
+ subscribe('PointerCaptureLost', events?.captureLost, (args) => this._onPointerCanceled(args));
|
|
914
|
+
+ if (type === GestureTypes.longPress) {
|
|
915
|
+
+ subscribe('RightTapped', events?.rightTapped, (args) => this._onRightTapped(args), _wrapRightTappedHandler);
|
|
916
|
+
+ }
|
|
917
|
+
+ this._disposers.push(_attachHoverHandlers(target, native));
|
|
918
|
+
}
|
|
919
|
+
- catch (_e) {
|
|
920
|
+
- // Fallback: plain property assignment (only one handler per event, can be overwritten).
|
|
921
|
+
- _assignPointerHandler(native, 'PointerPressed', this._pointerPressedDelegate);
|
|
922
|
+
- if (wantsMoves)
|
|
923
|
+
- _assignPointerHandler(native, 'PointerMoved', this._pointerMovedDelegate);
|
|
924
|
+
- _assignPointerHandler(native, 'PointerReleased', this._pointerReleasedDelegate);
|
|
925
|
+
+ catch (error) {
|
|
926
|
+
+ this._detach();
|
|
927
|
+
+ throw error;
|
|
928
|
+
}
|
|
929
|
+
- // RightTapped (mouse right-click) fires longPress for mouse/touchpad users.
|
|
930
|
+
- if (type === GestureTypes.longPress) {
|
|
931
|
+
- if (!this._rightTappedDelegate) {
|
|
932
|
+
- this._rightTappedHandler = (s, e) => this._onRightTapped(e || s);
|
|
933
|
+
- this._rightTappedDelegate = _wrapRightTappedHandler(this._rightTappedHandler);
|
|
934
|
+
- }
|
|
935
|
+
- try {
|
|
936
|
+
- if (this._usingAddHandler) {
|
|
937
|
+
- native.AddHandler(routedEvents().rightTapped, this._rightTappedDelegate, true);
|
|
938
|
+
- }
|
|
939
|
+
- else {
|
|
940
|
+
- _assignRightTappedHandler(native, this._rightTappedDelegate);
|
|
941
|
+
- }
|
|
942
|
+
+ target.notify({ eventName: GestureEvents.gestureAttached, object: target, type, view: target, windows: native });
|
|
943
|
+
+ }
|
|
944
|
+
+ _onPointerCanceled(e) {
|
|
945
|
+
+ try {
|
|
946
|
+
+ const id = extractPointerId(e);
|
|
947
|
+
+ if (!this._pointerDownMap.delete(id))
|
|
948
|
+
+ return;
|
|
949
|
+
+ const timeout = this._longPressTimeouts.get(id);
|
|
950
|
+
+ if (timeout != null)
|
|
951
|
+
+ timer.clearTimeout(timeout);
|
|
952
|
+
+ this._longPressTimeouts.delete(id);
|
|
953
|
+
+ this._lastUpTime = 0;
|
|
954
|
+
+ if (this.type === GestureTypes.touch) {
|
|
955
|
+
+ const relativeTo = this.target?.nativeViewProtected;
|
|
956
|
+
+ const point = extractPoint(e, relativeTo);
|
|
957
|
+
+ _executeCallback(this, {
|
|
958
|
+
+ type: GestureTypes.touch, view: this.target, object: this.target, windows: e,
|
|
959
|
+
+ eventName: toString(GestureTypes.touch), action: 'cancel',
|
|
960
|
+
+ getPointerCount: () => 1, getActivePointers: () => [new WindowsPointer(id, e, relativeTo)],
|
|
961
|
+
+ getAllPointers: () => [new WindowsPointer(id, e, relativeTo)], getX: () => point.x, getY: () => point.y,
|
|
962
|
+
+ });
|
|
963
|
+
}
|
|
964
|
+
- catch (_e) { }
|
|
965
|
+
}
|
|
966
|
+
- // Always attach hover handlers for CSS :hover and mouseEnter/mouseLeave events.
|
|
967
|
+
- _attachHoverHandlers(target);
|
|
968
|
+
- target.notify({
|
|
969
|
+
- eventName: GestureEvents.gestureAttached,
|
|
970
|
+
- object: target,
|
|
971
|
+
- type: type,
|
|
972
|
+
- view: target,
|
|
973
|
+
- windows: native,
|
|
974
|
+
- });
|
|
975
|
+
+ catch (_e) { }
|
|
976
|
+
}
|
|
977
|
+
androidOnTouchEvent(_motionEvent) { }
|
|
978
|
+
_onPointerPressed(e) {
|
|
979
|
+
+ if (this.target?.isEnabled === false)
|
|
980
|
+
+ return;
|
|
981
|
+
try {
|
|
982
|
+
const relativeTo = this.target?.nativeViewProtected ?? null;
|
|
983
|
+
const id = extractPointerId(e);
|
|
984
|
+
@@ -333,6 +265,9 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
985
|
+
this._pointerDownMap.set(id, { x: pt.x, y: pt.y, t: Date.now(), nativeTs });
|
|
986
|
+
if (this.type === GestureTypes.longPress) {
|
|
987
|
+
const timeoutId = timer.setTimeout(() => {
|
|
988
|
+
+ this._longPressTimeouts.delete(id);
|
|
989
|
+
+ if (this.target?.isEnabled === false || !this._pointerDownMap.has(id))
|
|
990
|
+
+ return;
|
|
991
|
+
const args = {
|
|
992
|
+
type: GestureTypes.longPress,
|
|
993
|
+
view: this.target,
|
|
994
|
+
@@ -349,6 +284,7 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
995
|
+
const args = {
|
|
996
|
+
type: GestureTypes.touch,
|
|
997
|
+
view: this.target,
|
|
998
|
+
+ windows: e,
|
|
999
|
+
ios: undefined,
|
|
1000
|
+
android: undefined,
|
|
1001
|
+
object: this.target,
|
|
1002
|
+
@@ -370,10 +306,20 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
1003
|
+
const relativeTo = this.target?.nativeViewProtected ?? null;
|
|
1004
|
+
const id = extractPointerId(e);
|
|
1005
|
+
const pt = extractPoint(e, relativeTo);
|
|
1006
|
+
+ const start = this._pointerDownMap.get(id);
|
|
1007
|
+
+ if (!start)
|
|
1008
|
+
+ return;
|
|
1009
|
+
+ if (Math.hypot(pt.x - start.x, pt.y - start.y) >= TAP_SLOP) {
|
|
1010
|
+
+ const timeout = this._longPressTimeouts.get(id);
|
|
1011
|
+
+ if (timeout != null)
|
|
1012
|
+
+ timer.clearTimeout(timeout);
|
|
1013
|
+
+ this._longPressTimeouts.delete(id);
|
|
1014
|
+
+ }
|
|
1015
|
+
if (this.type === GestureTypes.touch) {
|
|
1016
|
+
const args = {
|
|
1017
|
+
type: GestureTypes.touch,
|
|
1018
|
+
view: this.target,
|
|
1019
|
+
+ windows: e,
|
|
1020
|
+
ios: undefined,
|
|
1021
|
+
android: undefined,
|
|
1022
|
+
object: this.target,
|
|
1023
|
+
@@ -396,6 +342,12 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
1024
|
+
const id = extractPointerId(e);
|
|
1025
|
+
const pt = extractPoint(e, relativeTo);
|
|
1026
|
+
const start = this._pointerDownMap.get(id);
|
|
1027
|
+
+ if (!start)
|
|
1028
|
+
+ return;
|
|
1029
|
+
+ if (this.target?.isEnabled === false) {
|
|
1030
|
+
+ this._onPointerCanceled(e);
|
|
1031
|
+
+ return;
|
|
1032
|
+
+ }
|
|
1033
|
+
const now = Date.now();
|
|
1034
|
+
// Use WinRT hardware timestamps when available so the tap-duration check reflects the actual
|
|
1035
|
+
// gesture time, not V8 scheduling latency. When JS is busy (e.g. processing a navigation),
|
|
1036
|
+
@@ -426,56 +378,39 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
1037
|
+
};
|
|
1038
|
+
_executeCallback(this, args);
|
|
1039
|
+
}
|
|
1040
|
+
- if (start) {
|
|
1041
|
+
- const dx = pt.x - start.x;
|
|
1042
|
+
- const dy = pt.y - start.y;
|
|
1043
|
+
- const dist = Math.sqrt(dx * dx + dy * dy);
|
|
1044
|
+
- if (dt < DOUBLE_TAP_TIMEOUT && dist < TAP_SLOP) {
|
|
1045
|
+
- if (this.target.getGestureObservers && this.target.getGestureObservers(GestureTypes.doubleTap) && this.target.getGestureObservers(GestureTypes.doubleTap).length) {
|
|
1046
|
+
+ const distance = Math.hypot(pt.x - start.x, pt.y - start.y);
|
|
1047
|
+
+ if (dt < DOUBLE_TAP_TIMEOUT && distance < TAP_SLOP) {
|
|
1048
|
+
+ const args = {
|
|
1049
|
+
+ type: this.type, view: this.target, windows: e, object: this.target,
|
|
1050
|
+
+ eventName: toString(this.type), getPointerCount: () => 1,
|
|
1051
|
+
+ getX: () => pt.x, getY: () => pt.y,
|
|
1052
|
+
+ };
|
|
1053
|
+
+ if (this.type === GestureTypes.tap) {
|
|
1054
|
+
+ const doubleTap = this.target.getGestureObservers?.(GestureTypes.doubleTap)?.length;
|
|
1055
|
+
+ if (!doubleTap) {
|
|
1056
|
+
+ _executeCallback(this, args);
|
|
1057
|
+
+ }
|
|
1058
|
+
+ else if (this._lastUpTime && now - this._lastUpTime <= DOUBLE_TAP_TIMEOUT) {
|
|
1059
|
+
+ timer.clearTimeout(this._tapTimeoutId);
|
|
1060
|
+
+ this._tapTimeoutId = null;
|
|
1061
|
+
+ this._lastUpTime = 0;
|
|
1062
|
+
+ }
|
|
1063
|
+
+ else {
|
|
1064
|
+
+ this._lastUpTime = now;
|
|
1065
|
+
this._tapTimeoutId = timer.setTimeout(() => {
|
|
1066
|
+
- const args = {
|
|
1067
|
+
- type: GestureTypes.tap,
|
|
1068
|
+
- view: this.target,
|
|
1069
|
+
- windows: e,
|
|
1070
|
+
- object: this.target,
|
|
1071
|
+
- eventName: toString(GestureTypes.tap),
|
|
1072
|
+
- getPointerCount: () => 1,
|
|
1073
|
+
- getX: () => pt.x ?? 0,
|
|
1074
|
+
- getY: () => pt.y ?? 0,
|
|
1075
|
+
- };
|
|
1076
|
+
- _executeCallback(this, args);
|
|
1077
|
+
+ this._tapTimeoutId = null;
|
|
1078
|
+
+ if (this.target?.isEnabled !== false)
|
|
1079
|
+
+ _executeCallback(this, args);
|
|
1080
|
+
}, DOUBLE_TAP_TIMEOUT);
|
|
1081
|
+
}
|
|
1082
|
+
- else {
|
|
1083
|
+
- const args = {
|
|
1084
|
+
- type: GestureTypes.tap,
|
|
1085
|
+
- view: this.target,
|
|
1086
|
+
- ios: undefined,
|
|
1087
|
+
- android: undefined,
|
|
1088
|
+
- object: this.target,
|
|
1089
|
+
- eventName: toString(GestureTypes.tap),
|
|
1090
|
+
- getPointerCount: () => 1,
|
|
1091
|
+
- getX: () => pt.x ?? 0,
|
|
1092
|
+
- getY: () => pt.y ?? 0,
|
|
1093
|
+
- };
|
|
1094
|
+
+ }
|
|
1095
|
+
+ else if (this.type === GestureTypes.doubleTap) {
|
|
1096
|
+
+ if (this._lastUpTime && now - this._lastUpTime <= DOUBLE_TAP_TIMEOUT) {
|
|
1097
|
+
+ this._lastUpTime = 0;
|
|
1098
|
+
_executeCallback(this, args);
|
|
1099
|
+
}
|
|
1100
|
+
- if (this.target.getGestureObservers && this.target.getGestureObservers(GestureTypes.doubleTap) && this.target.getGestureObservers(GestureTypes.doubleTap).length) {
|
|
1101
|
+
- const nowUp = Date.now();
|
|
1102
|
+
- if (this._lastUpTime && nowUp - this._lastUpTime <= DOUBLE_TAP_TIMEOUT) {
|
|
1103
|
+
- const args = {
|
|
1104
|
+
- type: GestureTypes.doubleTap,
|
|
1105
|
+
- view: this.target,
|
|
1106
|
+
- windows: e,
|
|
1107
|
+
- object: this.target,
|
|
1108
|
+
- eventName: toString(GestureTypes.doubleTap),
|
|
1109
|
+
- getPointerCount: () => 1,
|
|
1110
|
+
- getX: () => pt.x ?? 0,
|
|
1111
|
+
- getY: () => pt.y ?? 0,
|
|
1112
|
+
- };
|
|
1113
|
+
- _executeCallback(this, args);
|
|
1114
|
+
- }
|
|
1115
|
+
- this._lastUpTime = nowUp;
|
|
1116
|
+
+ else {
|
|
1117
|
+
+ this._lastUpTime = now;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
@@ -484,6 +419,8 @@ export class GesturesObserver extends GesturesObserverBase {
|
|
1122
|
+
catch (_e) { }
|
|
1123
|
+
}
|
|
1124
|
+
_onRightTapped(e) {
|
|
1125
|
+
+ if (this.target?.isEnabled === false)
|
|
1126
|
+
+ return;
|
|
1127
|
+
try {
|
|
1128
|
+
const relativeTo = this.target?.nativeViewProtected ?? null;
|
|
1129
|
+
const pt = extractPoint(e, relativeTo);
|
|
1130
|
+
@@ -507,4 +444,3 @@ export function observe(target, type, callback, context) {
|
|
1131
|
+
observer.observe(type);
|
|
1132
|
+
return observer;
|
|
1133
|
+
}
|
|
1134
|
+
-//# sourceMappingURL=index.windows.js.map
|
|
1135
|
+
|
|
1136
|
+
diff --git a/ui/gestures/pointer-events.windows.d.ts b/ui/gestures/pointer-events.windows.d.ts
|
|
1137
|
+
new file mode 100644
|
|
1138
|
+
index 0000000000000000000000000000000000000000..a355a6930792b05c64f66f9051ad927ba3784dde
|
|
1139
|
+
--- /dev/null
|
|
1140
|
+
+++ b/ui/gestures/pointer-events.windows.d.ts
|
|
1141
|
+
@@ -0,0 +1,4 @@
|
|
1142
|
+
+type Handler = (sender: any, args: any) => void;
|
|
1143
|
+
+/** Share the bridge's replacement-only event property between independent owners. */
|
|
1144
|
+
+export declare function subscribeNativeEvent(native: any, name: string, callback: Handler, routedEvent: any, wrap: (handler: Handler) => any): () => void;
|
|
1145
|
+
+export {};
|
|
1146
|
+
diff --git a/ui/gestures/pointer-events.windows.js b/ui/gestures/pointer-events.windows.js
|
|
1147
|
+
new file mode 100644
|
|
1148
|
+
index 0000000000000000000000000000000000000000..f19ca9970f8f8f7ce8224f516a6bdcea740210bc
|
|
1149
|
+
--- /dev/null
|
|
1150
|
+
+++ b/ui/gestures/pointer-events.windows.js
|
|
1151
|
+
@@ -0,0 +1,66 @@
|
|
1152
|
+
+const nativeEvents = new WeakMap();
|
|
1153
|
+
+/** Share the bridge's replacement-only event property between independent owners. */
|
|
1154
|
+
+export function subscribeNativeEvent(native, name, callback, routedEvent, wrap) {
|
|
1155
|
+
+ let events = nativeEvents.get(native);
|
|
1156
|
+
+ if (!events) {
|
|
1157
|
+
+ events = new Map();
|
|
1158
|
+
+ nativeEvents.set(native, events);
|
|
1159
|
+
+ }
|
|
1160
|
+
+ let entry = events.get(name);
|
|
1161
|
+
+ if (!entry) {
|
|
1162
|
+
+ const subscribers = new Set();
|
|
1163
|
+
+ const delegate = wrap((sender, args) => {
|
|
1164
|
+
+ // Removal during dispatch takes effect immediately; new subscribers wait for the next event.
|
|
1165
|
+
+ for (const subscription of Array.from(subscribers)) {
|
|
1166
|
+
+ if (subscribers.has(subscription))
|
|
1167
|
+
+ subscription.callback(sender, args);
|
|
1168
|
+
+ }
|
|
1169
|
+
+ });
|
|
1170
|
+
+ let detach;
|
|
1171
|
+
+ try {
|
|
1172
|
+
+ if (!routedEvent || typeof native.AddHandler !== 'function')
|
|
1173
|
+
+ throw new Error('RoutedEvent unavailable');
|
|
1174
|
+
+ native.AddHandler(routedEvent, delegate, true);
|
|
1175
|
+
+ detach = () => native.RemoveHandler(routedEvent, delegate);
|
|
1176
|
+
+ }
|
|
1177
|
+
+ catch (error) {
|
|
1178
|
+
+ // A bridge can fail after attaching. Remove that exact delegate before falling back.
|
|
1179
|
+
+ if (routedEvent && typeof native.AddHandler === 'function') {
|
|
1180
|
+
+ try {
|
|
1181
|
+
+ native.RemoveHandler(routedEvent, delegate);
|
|
1182
|
+
+ }
|
|
1183
|
+
+ catch (_) {
|
|
1184
|
+
+ // E_NOINTERFACE rejects the delegate projection before registration. For an
|
|
1185
|
+
+ // ambiguous failure, do not add a second listener if rollback also failed.
|
|
1186
|
+
+ const code = error?.hresult ?? error?.HResult ?? error?.code;
|
|
1187
|
+
+ const unsupported = (typeof code === 'number' && (code >>> 0) === 0x80004002) || /E_NOINTERFACE|80004002/i.test(String(error));
|
|
1188
|
+
+ if (!unsupported)
|
|
1189
|
+
+ throw error;
|
|
1190
|
+
+ }
|
|
1191
|
+
+ }
|
|
1192
|
+
+ native[name] = delegate;
|
|
1193
|
+
+ detach = () => { native[name] = null; };
|
|
1194
|
+
+ }
|
|
1195
|
+
+ entry = { subscribers, detach };
|
|
1196
|
+
+ events.set(name, entry);
|
|
1197
|
+
+ }
|
|
1198
|
+
+ const subscription = { callback };
|
|
1199
|
+
+ entry.subscribers.add(subscription);
|
|
1200
|
+
+ let disposed = false;
|
|
1201
|
+
+ return () => {
|
|
1202
|
+
+ if (disposed)
|
|
1203
|
+
+ return;
|
|
1204
|
+
+ disposed = true;
|
|
1205
|
+
+ entry.subscribers.delete(subscription);
|
|
1206
|
+
+ if (!entry.subscribers.size) {
|
|
1207
|
+
+ try {
|
|
1208
|
+
+ entry.detach();
|
|
1209
|
+
+ }
|
|
1210
|
+
+ finally {
|
|
1211
|
+
+ events.delete(name);
|
|
1212
|
+
+ if (!events.size)
|
|
1213
|
+
+ nativeEvents.delete(native);
|
|
1214
|
+
+ }
|
|
1215
|
+
+ }
|
|
1216
|
+
+ };
|
|
1217
|
+
+}
|
|
166
1218
|
diff --git a/ui/layouts/flexbox-layout/flexbox-layout-common.js b/ui/layouts/flexbox-layout/flexbox-layout-common.js
|
|
167
1219
|
index 50c747a85135d761c1a646a007c4930f790fb0a3..8f3a627224cf903555574480a0cdeba74b1c3e35 100644
|
|
168
1220
|
--- a/ui/layouts/flexbox-layout/flexbox-layout-common.js
|
|
@@ -426,3 +1478,147 @@ index 66672f1fa5ccb31f06a83a2a21bfe1e5c668712f..1eb3676f0346d7ee21ab7ff1c1b78292
|
|
|
426
1478
|
onSelectedIndexChanged(oldIndex, newIndex) {
|
|
427
1479
|
// to be overridden in platform specific files
|
|
428
1480
|
this.notify({
|
|
1481
|
+
diff --git a/ui/text-field/index.windows.d.ts b/ui/text-field/index.windows.d.ts
|
|
1482
|
+
index a88815c17ff87271143e457f7e81e3c651ef0ab3..9c0c2a7db4dcd4bcb185e1e1c0f42cfa1aba53bb 100644
|
|
1483
|
+
--- a/ui/text-field/index.windows.d.ts
|
|
1484
|
+
+++ b/ui/text-field/index.windows.d.ts
|
|
1485
|
+
@@ -14,10 +14,16 @@ export declare class TextField extends TextFieldBase {
|
|
1486
|
+
[colorProperty.setNative]: (value: Color | null) => void;
|
|
1487
|
+
nativeViewProtected: Microsoft.UI.Xaml.Controls.TextBox | Microsoft.UI.Xaml.Controls.PasswordBox;
|
|
1488
|
+
private _isSecure;
|
|
1489
|
+
- private _keyDownDelegate;
|
|
1490
|
+
+ private _returnNative;
|
|
1491
|
+
+ private _returnDisposer;
|
|
1492
|
+
_attachTextChangeListener: () => void;
|
|
1493
|
+
+ protected _updateInputEnabled: () => void;
|
|
1494
|
+
createNativeView(): Microsoft.UI.Xaml.Controls.TextBox | Microsoft.UI.Xaml.Controls.PasswordBox;
|
|
1495
|
+
initNativeView(): void;
|
|
1496
|
+
private _neutralizeStateBackgrounds;
|
|
1497
|
+
+ onLoaded(): void;
|
|
1498
|
+
+ onUnloaded(): void;
|
|
1499
|
+
+ disposeNativeView(): void;
|
|
1500
|
+
+ private _detachReturnKeyListener;
|
|
1501
|
+
_attachReturnKeyListener(): void;
|
|
1502
|
+
}
|
|
1503
|
+
diff --git a/ui/text-field/index.windows.js b/ui/text-field/index.windows.js
|
|
1504
|
+
index 1dcaa390d7ad1a37fecc5e0edfaa0cd38380146e..be96ae1b112f9d084c2f9ef0db48fc3de84e4bb1 100644
|
|
1505
|
+
--- a/ui/text-field/index.windows.js
|
|
1506
|
+
+++ b/ui/text-field/index.windows.js
|
|
1507
|
+
@@ -1,8 +1,10 @@
|
|
1508
|
+
export * from './text-field-common';
|
|
1509
|
+
import { TextFieldBase, secureProperty } from './text-field-common';
|
|
1510
|
+
import { hintProperty, editableProperty, maxLengthProperty, keyboardTypeProperty, autocapitalizationTypeProperty } from '../editable-text-base/editable-text-base-common';
|
|
1511
|
+
+import { textProperty } from '../text-base';
|
|
1512
|
+
import { colorProperty } from '../styling/style-properties';
|
|
1513
|
+
import { Color } from '../../color';
|
|
1514
|
+
+import { subscribeNativeEvent } from '../gestures/pointer-events.windows';
|
|
1515
|
+
import { nativeChildIndex } from '../core/view/native-children.windows';
|
|
1516
|
+
const KEYBOARD_SCOPE = {
|
|
1517
|
+
number: 29,
|
|
1518
|
+
@@ -31,7 +33,8 @@ export class TextField extends TextFieldBase {
|
|
1519
|
+
constructor() {
|
|
1520
|
+
super(...arguments);
|
|
1521
|
+
this._isSecure = false;
|
|
1522
|
+
- this._keyDownDelegate = null;
|
|
1523
|
+
+ this._returnNative = null;
|
|
1524
|
+
+ this._returnDisposer = null;
|
|
1525
|
+
}
|
|
1526
|
+
createNativeView() {
|
|
1527
|
+
// `secure` is parsed before the native view is created; pick the correct control up-front.
|
|
1528
|
+
@@ -66,30 +69,38 @@ export class TextField extends TextFieldBase {
|
|
1529
|
+
}
|
|
1530
|
+
catch (_e) { }
|
|
1531
|
+
}
|
|
1532
|
+
+ onLoaded() {
|
|
1533
|
+
+ super.onLoaded();
|
|
1534
|
+
+ this._attachReturnKeyListener();
|
|
1535
|
+
+ }
|
|
1536
|
+
+ onUnloaded() {
|
|
1537
|
+
+ this._detachReturnKeyListener();
|
|
1538
|
+
+ super.onUnloaded();
|
|
1539
|
+
+ }
|
|
1540
|
+
+ disposeNativeView() {
|
|
1541
|
+
+ this._detachReturnKeyListener();
|
|
1542
|
+
+ super.disposeNativeView();
|
|
1543
|
+
+ }
|
|
1544
|
+
+ _detachReturnKeyListener() {
|
|
1545
|
+
+ this._returnNative = null;
|
|
1546
|
+
+ this._returnDisposer?.();
|
|
1547
|
+
+ this._returnDisposer = null;
|
|
1548
|
+
+ }
|
|
1549
|
+
_attachReturnKeyListener() {
|
|
1550
|
+
- const nv = this.nativeViewProtected;
|
|
1551
|
+
- if (!nv) {
|
|
1552
|
+
+ const native = this.nativeViewProtected;
|
|
1553
|
+
+ if (this._returnNative === native)
|
|
1554
|
+
+ return;
|
|
1555
|
+
+ this._detachReturnKeyListener();
|
|
1556
|
+
+ if (!native || !this.isLoaded)
|
|
1557
|
+
return;
|
|
1558
|
+
- }
|
|
1559
|
+
const ref = new WeakRef(this);
|
|
1560
|
+
- this._keyDownDelegate = NSWinRT.asDelegate('Microsoft.UI.Xaml.Input.KeyEventHandler', (_sender, e) => {
|
|
1561
|
+
- if (e.Key === Windows.System.VirtualKey.Enter) {
|
|
1562
|
+
- const owner = ref.deref();
|
|
1563
|
+
- if (owner)
|
|
1564
|
+
- owner.notify({ eventName: TextFieldBase.returnPressEvent, object: owner });
|
|
1565
|
+
+ this._returnNative = native;
|
|
1566
|
+
+ this._returnDisposer = subscribeNativeEvent(native, 'KeyDown', (_sender, args) => {
|
|
1567
|
+
+ const owner = ref.deref();
|
|
1568
|
+
+ if (owner?.isLoaded && owner._returnNative === native && owner.nativeViewProtected === native && owner.isEnabled && owner.editable && args.Key === Windows.System.VirtualKey.Enter) {
|
|
1569
|
+
+ owner.notify({ eventName: TextFieldBase.returnPressEvent, object: owner });
|
|
1570
|
+
}
|
|
1571
|
+
- });
|
|
1572
|
+
- // AddHandler(KeyDownEvent) throws E_INVALIDARG (0x80070057) in the runtime's RoutedEvent
|
|
1573
|
+
- // projection: an uncaught throw jams frame navigation. Fall back to instance KeyDown.
|
|
1574
|
+
- try {
|
|
1575
|
+
- nv.AddHandler(Microsoft.UI.Xaml.UIElement.KeyDownEvent, this._keyDownDelegate, true);
|
|
1576
|
+
- }
|
|
1577
|
+
- catch (_e) {
|
|
1578
|
+
- try {
|
|
1579
|
+
- nv.KeyDown = this._keyDownDelegate;
|
|
1580
|
+
- }
|
|
1581
|
+
- catch (_e2) { }
|
|
1582
|
+
- }
|
|
1583
|
+
+ }, null, (handler) => NSWinRT.asDelegate('Microsoft.UI.Xaml.Input.KeyEventHandler', handler));
|
|
1584
|
+
}
|
|
1585
|
+
// @ts-ignore: setNative is a symbol index whose value type is widened across properties.
|
|
1586
|
+
[secureProperty.setNative](value) {
|
|
1587
|
+
@@ -99,7 +110,7 @@ export class TextField extends TextFieldBase {
|
|
1588
|
+
this._isSecure = !!value;
|
|
1589
|
+
const prev = this.nativeViewProtected;
|
|
1590
|
+
// Carry the value across the swap from the JS model (source of truth), not off `prev`.
|
|
1591
|
+
- const currentText = this.text ?? '';
|
|
1592
|
+
+ const wasFocused = !!prev && prev.FocusState !== Microsoft.UI.Xaml.FocusState.Unfocused;
|
|
1593
|
+
const newView = this._isSecure ? new Microsoft.UI.Xaml.Controls.PasswordBox() : new Microsoft.UI.Xaml.Controls.TextBox();
|
|
1594
|
+
// Must swap in the ACTUAL visual parent (not the NS parent's nativeViewProtected).
|
|
1595
|
+
// Using the NS parent's Border missed the real container and the swap silently no-op'd,
|
|
1596
|
+
@@ -129,15 +140,11 @@ export class TextField extends TextFieldBase {
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
- this.nativeViewProtected = newView;
|
|
1601
|
+
- if (this._isSecure) {
|
|
1602
|
+
- newView.Password = currentText;
|
|
1603
|
+
- }
|
|
1604
|
+
- else {
|
|
1605
|
+
- newView.Text = currentText;
|
|
1606
|
+
- }
|
|
1607
|
+
- this._attachTextChangeListener();
|
|
1608
|
+
- this._attachReturnKeyListener();
|
|
1609
|
+
+ this.disposeNativeView();
|
|
1610
|
+
+ this.setNativeView(newView);
|
|
1611
|
+
+ this[textProperty.setNative](this.text ?? '');
|
|
1612
|
+
+ if (wasFocused)
|
|
1613
|
+
+ this.focus();
|
|
1614
|
+
}
|
|
1615
|
+
[hintProperty.setNative](value) {
|
|
1616
|
+
const nativeView = this.nativeViewProtected;
|
|
1617
|
+
@@ -151,6 +158,7 @@ export class TextField extends TextFieldBase {
|
|
1618
|
+
if (typeof nativeView.IsReadOnly !== 'undefined') {
|
|
1619
|
+
nativeView.IsReadOnly = !value;
|
|
1620
|
+
}
|
|
1621
|
+
+ this._updateInputEnabled();
|
|
1622
|
+
}
|
|
1623
|
+
// @ts-ignore: setNative is a symbol index whose value type is widened across properties.
|
|
1624
|
+
[maxLengthProperty.setNative](value) {
|