drawnui-react 0.1.0-preview.1
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/LICENSE +21 -0
- package/PARITY.md +287 -0
- package/README.md +92 -0
- package/SKIPPED.md +107 -0
- package/dist/controls/AnimatedFramesRenderer.d.ts +58 -0
- package/dist/controls/AnimatedFramesRenderer.js +133 -0
- package/dist/controls/GridStructure.d.ts +79 -0
- package/dist/controls/GridStructure.js +403 -0
- package/dist/controls/RefreshIndicator.d.ts +35 -0
- package/dist/controls/RefreshIndicator.js +82 -0
- package/dist/controls/SkiaBackdrop.d.ts +25 -0
- package/dist/controls/SkiaBackdrop.js +80 -0
- package/dist/controls/SkiaButton.d.ts +58 -0
- package/dist/controls/SkiaButton.js +148 -0
- package/dist/controls/SkiaCarousel.d.ts +133 -0
- package/dist/controls/SkiaCarousel.js +603 -0
- package/dist/controls/SkiaCheckbox.d.ts +21 -0
- package/dist/controls/SkiaCheckbox.js +118 -0
- package/dist/controls/SkiaDecoratedGrid.d.ts +15 -0
- package/dist/controls/SkiaDecoratedGrid.js +46 -0
- package/dist/controls/SkiaDrawer.d.ts +46 -0
- package/dist/controls/SkiaDrawer.js +212 -0
- package/dist/controls/SkiaDynamicDrawnCell.d.ts +11 -0
- package/dist/controls/SkiaDynamicDrawnCell.js +17 -0
- package/dist/controls/SkiaEditor.d.ts +163 -0
- package/dist/controls/SkiaEditor.js +803 -0
- package/dist/controls/SkiaGif.d.ts +54 -0
- package/dist/controls/SkiaGif.js +206 -0
- package/dist/controls/SkiaHotspot.d.ts +13 -0
- package/dist/controls/SkiaHotspot.js +36 -0
- package/dist/controls/SkiaImage.d.ts +75 -0
- package/dist/controls/SkiaImage.js +222 -0
- package/dist/controls/SkiaImageTiles.d.ts +27 -0
- package/dist/controls/SkiaImageTiles.js +76 -0
- package/dist/controls/SkiaLabel.d.ts +160 -0
- package/dist/controls/SkiaLabel.js +580 -0
- package/dist/controls/SkiaLayout.d.ts +163 -0
- package/dist/controls/SkiaLayout.js +723 -0
- package/dist/controls/SkiaLottie.d.ts +75 -0
- package/dist/controls/SkiaLottie.js +290 -0
- package/dist/controls/SkiaProgress.d.ts +40 -0
- package/dist/controls/SkiaProgress.js +80 -0
- package/dist/controls/SkiaRadioButton.d.ts +32 -0
- package/dist/controls/SkiaRadioButton.js +157 -0
- package/dist/controls/SkiaRichLabel.d.ts +77 -0
- package/dist/controls/SkiaRichLabel.js +274 -0
- package/dist/controls/SkiaScroll.d.ts +231 -0
- package/dist/controls/SkiaScroll.js +958 -0
- package/dist/controls/SkiaScrollBar.d.ts +56 -0
- package/dist/controls/SkiaScrollBar.js +158 -0
- package/dist/controls/SkiaShaderCarousel.d.ts +67 -0
- package/dist/controls/SkiaShaderCarousel.js +246 -0
- package/dist/controls/SkiaShape.d.ts +63 -0
- package/dist/controls/SkiaShape.js +317 -0
- package/dist/controls/SkiaSlider.d.ts +74 -0
- package/dist/controls/SkiaSlider.js +243 -0
- package/dist/controls/SkiaSprite.d.ts +99 -0
- package/dist/controls/SkiaSprite.js +324 -0
- package/dist/controls/SkiaSpriteSet.d.ts +27 -0
- package/dist/controls/SkiaSpriteSet.js +75 -0
- package/dist/controls/SkiaSvg.d.ts +43 -0
- package/dist/controls/SkiaSvg.js +181 -0
- package/dist/controls/SkiaSwitch.d.ts +26 -0
- package/dist/controls/SkiaSwitch.js +147 -0
- package/dist/controls/SkiaToggle.d.ts +50 -0
- package/dist/controls/SkiaToggle.js +71 -0
- package/dist/controls/SnappingLayout.d.ts +78 -0
- package/dist/controls/SnappingLayout.js +217 -0
- package/dist/controls/TextSpan.d.ts +70 -0
- package/dist/controls/TextSpan.js +76 -0
- package/dist/core/Accessibility.d.ts +104 -0
- package/dist/core/Accessibility.js +150 -0
- package/dist/core/Animators.d.ts +82 -0
- package/dist/core/Animators.js +247 -0
- package/dist/core/Canvas.d.ts +89 -0
- package/dist/core/Canvas.js +328 -0
- package/dist/core/ControlStyle.d.ts +6 -0
- package/dist/core/ControlStyle.js +11 -0
- package/dist/core/Easing.d.ts +13 -0
- package/dist/core/Easing.js +15 -0
- package/dist/core/Gestures.d.ts +74 -0
- package/dist/core/Gestures.js +104 -0
- package/dist/core/ImageEffects.d.ts +29 -0
- package/dist/core/ImageEffects.js +55 -0
- package/dist/core/KeyboardManager.d.ts +25 -0
- package/dist/core/KeyboardManager.js +54 -0
- package/dist/core/ScrollAnimators.d.ts +90 -0
- package/dist/core/ScrollAnimators.js +244 -0
- package/dist/core/SkiaControl.d.ts +401 -0
- package/dist/core/SkiaControl.js +1239 -0
- package/dist/core/SkiaEffect.d.ts +216 -0
- package/dist/core/SkiaEffect.js +571 -0
- package/dist/core/SkiaImageManager.d.ts +43 -0
- package/dist/core/SkiaImageManager.js +122 -0
- package/dist/core/Super.d.ts +61 -0
- package/dist/core/Super.js +178 -0
- package/dist/core/TextInputProxy.d.ts +31 -0
- package/dist/core/TextInputProxy.js +144 -0
- package/dist/core/Types.d.ts +177 -0
- package/dist/core/Types.js +122 -0
- package/dist/core/ViewsAdapter.d.ts +41 -0
- package/dist/core/ViewsAdapter.js +113 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +48 -0
- package/dist/react/SkiaShell.d.ts +144 -0
- package/dist/react/SkiaShell.js +490 -0
- package/dist/react/index.d.ts +110 -0
- package/dist/react/index.js +158 -0
- package/dist/react/reconciler.d.ts +14 -0
- package/dist/react/reconciler.js +160 -0
- package/package.json +60 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Colors, Thickness } from "../core/Types";
|
|
2
|
+
import { SkiaShape } from "./SkiaShape";
|
|
3
|
+
import { SkiaSvg } from "./SkiaSvg";
|
|
4
|
+
import { SkiaToggle } from "./SkiaToggle";
|
|
5
|
+
const SvgCupertinoCheck = '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none"><path d="M4 12.6111L8.92308 17.5L20 6.5" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
6
|
+
const SvgMaterialCheck = '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none"><path d="M5 13L9 17L19 7" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
7
|
+
const SvgWindowsCheck = '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none"><path d="M4 11.6L10 17.6L20 7.6" stroke="#000000" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="round"/></svg>';
|
|
8
|
+
/** Mirrors DrawnUi SkiaCheckbox: `FrameOff` outline, `FrameOn` filled frame with a `ViewCheckOn` mark, per-style looks. */
|
|
9
|
+
export class SkiaCheckbox extends SkiaToggle {
|
|
10
|
+
static DefaultAccessibilityRole = "checkbox";
|
|
11
|
+
FrameOff;
|
|
12
|
+
FrameOn;
|
|
13
|
+
ViewCheckOn;
|
|
14
|
+
colorCheckOn;
|
|
15
|
+
static DefaultAccent = "#DC143C";
|
|
16
|
+
static DefaultOutline = "#8E959D";
|
|
17
|
+
/** Color of the check mark (inner square for the default look). */
|
|
18
|
+
get ColorCheckOn() { return this.colorCheckOn ?? (this.UsingControlStyle === "Unset" ? SkiaCheckbox.DefaultAccent : Colors.White); }
|
|
19
|
+
set ColorCheckOn(v) { this.colorCheckOn = v; this.ApplyProperties(); }
|
|
20
|
+
StyleDefault(name) {
|
|
21
|
+
const table = {
|
|
22
|
+
Unset: { ColorFrameOff: SkiaCheckbox.DefaultOutline, ColorFrameOn: SkiaCheckbox.DefaultAccent },
|
|
23
|
+
Cupertino: { ColorFrameOff: "#BFBFBF", ColorFrameOn: "#007AFF" },
|
|
24
|
+
Material: { ColorFrameOff: "#757575", ColorFrameOn: "#2196F3" },
|
|
25
|
+
Material3: { ColorFrameOff: "#49454F", ColorFrameOn: "#6750A4" },
|
|
26
|
+
Windows: { ColorFrameOff: "#999999", ColorFrameOn: "#0078D7" },
|
|
27
|
+
};
|
|
28
|
+
return table[this.UsingControlStyle]?.[name];
|
|
29
|
+
}
|
|
30
|
+
SetContentSize(w, h) {
|
|
31
|
+
if (this.WidthRequest < 0)
|
|
32
|
+
this.WidthRequest = w;
|
|
33
|
+
if (this.HeightRequest < 0)
|
|
34
|
+
this.HeightRequest = h;
|
|
35
|
+
}
|
|
36
|
+
CreateDefaultContent() {
|
|
37
|
+
const off = new SkiaShape();
|
|
38
|
+
off.Tag = "FrameOff";
|
|
39
|
+
off.Type = "Rectangle";
|
|
40
|
+
off.HorizontalOptions = "Fill";
|
|
41
|
+
off.VerticalOptions = "Fill";
|
|
42
|
+
const on = new SkiaShape();
|
|
43
|
+
on.Tag = "FrameOn";
|
|
44
|
+
on.Type = "Rectangle";
|
|
45
|
+
on.HorizontalOptions = "Fill";
|
|
46
|
+
on.VerticalOptions = "Fill";
|
|
47
|
+
let check;
|
|
48
|
+
const svg = (markup, margin) => { const v = new SkiaSvg(); v.Tag = "ViewCheckOn"; v.SvgString = markup; v.TintColor = Colors.White; v.Margin = new Thickness(margin); v.HorizontalOptions = "Fill"; v.VerticalOptions = "Fill"; return v; };
|
|
49
|
+
switch (this.usingStyle) {
|
|
50
|
+
case "Cupertino":
|
|
51
|
+
this.SetContentSize(22, 22);
|
|
52
|
+
off.StrokeWidth = 1.5;
|
|
53
|
+
off.CornerRadius = 4;
|
|
54
|
+
on.CornerRadius = 4;
|
|
55
|
+
check = svg(SvgCupertinoCheck, 2);
|
|
56
|
+
break;
|
|
57
|
+
case "Material":
|
|
58
|
+
this.SetContentSize(24, 24);
|
|
59
|
+
off.StrokeWidth = 2;
|
|
60
|
+
off.CornerRadius = 2;
|
|
61
|
+
on.CornerRadius = 2;
|
|
62
|
+
check = svg(SvgMaterialCheck, 2);
|
|
63
|
+
break;
|
|
64
|
+
case "Material3":
|
|
65
|
+
this.SetContentSize(18, 18);
|
|
66
|
+
off.StrokeWidth = 2;
|
|
67
|
+
off.CornerRadius = 2;
|
|
68
|
+
on.CornerRadius = 2;
|
|
69
|
+
check = svg(SvgMaterialCheck, 2);
|
|
70
|
+
break;
|
|
71
|
+
case "Windows":
|
|
72
|
+
this.SetContentSize(20, 20);
|
|
73
|
+
off.StrokeWidth = 1;
|
|
74
|
+
off.CornerRadius = 0;
|
|
75
|
+
on.CornerRadius = 0;
|
|
76
|
+
check = svg(SvgWindowsCheck, 1);
|
|
77
|
+
break;
|
|
78
|
+
default: {
|
|
79
|
+
this.SetContentSize(22, 22);
|
|
80
|
+
off.StrokeWidth = 1;
|
|
81
|
+
on.StrokeWidth = 1;
|
|
82
|
+
const sq = new SkiaShape();
|
|
83
|
+
sq.Tag = "ViewCheckOn";
|
|
84
|
+
sq.Type = "Rectangle";
|
|
85
|
+
sq.Margin = new Thickness(3);
|
|
86
|
+
sq.LockRatio = 1;
|
|
87
|
+
sq.HorizontalOptions = "Fill";
|
|
88
|
+
sq.VerticalOptions = "Fill";
|
|
89
|
+
sq.UseCache = "Operations";
|
|
90
|
+
check = sq;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
on.AddSubView(check);
|
|
94
|
+
this.FrameOff = off;
|
|
95
|
+
this.FrameOn = on;
|
|
96
|
+
this.ViewCheckOn = check;
|
|
97
|
+
this.AddSubView(off);
|
|
98
|
+
this.AddSubView(on);
|
|
99
|
+
}
|
|
100
|
+
ApplyProperties() {
|
|
101
|
+
if (!this.contentCreated)
|
|
102
|
+
return;
|
|
103
|
+
const on = this.IsToggled;
|
|
104
|
+
this.FrameOff.StrokeColor = this.ColorFrameOff;
|
|
105
|
+
if (this.usingStyle === "Unset") {
|
|
106
|
+
this.FrameOn.StrokeColor = this.ColorFrameOn;
|
|
107
|
+
this.ViewCheckOn.BackgroundColor = this.ColorCheckOn;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.FrameOn.BackgroundColor = this.ColorFrameOn;
|
|
111
|
+
this.ViewCheckOn.TintColor = this.ColorCheckOn;
|
|
112
|
+
}
|
|
113
|
+
this.FrameOn.IsVisible = on;
|
|
114
|
+
this.ViewCheckOn.IsVisible = on;
|
|
115
|
+
this.FrameOff.IsVisible = !on;
|
|
116
|
+
this.Update();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DrawingContext } from "../core/SkiaControl";
|
|
2
|
+
import { type SkiaGradient } from "../core/Types";
|
|
3
|
+
import { SkiaGrid } from "./SkiaLayout";
|
|
4
|
+
/**
|
|
5
|
+
* Mirrors DrawnUi SkiaDecoratedGrid: a SkiaGrid painting separator lines in the spacing between its tracks,
|
|
6
|
+
* `VerticalLine` (a ColumnSpacing wide gradient between columns) and `HorizontalLine` (a RowSpacing tall gradient
|
|
7
|
+
* over black between rows), set either to undefined to skip. Lines draw under the children (C# ZIndex -1 overlay).
|
|
8
|
+
*/
|
|
9
|
+
export declare class SkiaDecoratedGrid extends SkiaGrid {
|
|
10
|
+
static readonly HorizontalGradient: SkiaGradient;
|
|
11
|
+
static readonly VerticalGradient: SkiaGradient;
|
|
12
|
+
HorizontalLine?: SkiaGradient;
|
|
13
|
+
VerticalLine?: SkiaGradient;
|
|
14
|
+
protected Paint(ctx: DrawingContext): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Super } from "../core/Super";
|
|
2
|
+
import { SKRect } from "../core/Types";
|
|
3
|
+
import { SkiaGrid } from "./SkiaLayout";
|
|
4
|
+
/**
|
|
5
|
+
* Mirrors DrawnUi SkiaDecoratedGrid: a SkiaGrid painting separator lines in the spacing between its tracks,
|
|
6
|
+
* `VerticalLine` (a ColumnSpacing wide gradient between columns) and `HorizontalLine` (a RowSpacing tall gradient
|
|
7
|
+
* over black between rows), set either to undefined to skip. Lines draw under the children (C# ZIndex -1 overlay).
|
|
8
|
+
*/
|
|
9
|
+
export class SkiaDecoratedGrid extends SkiaGrid {
|
|
10
|
+
static HorizontalGradient = { Type: "Linear", Colors: ["#00E8E3D7", "#78E8E3D7", "#78E8E3D7", "#00E8E3D7"], ColorPositions: [0, 0.1, 0.9, 1], StartXRatio: 0, StartYRatio: 0, EndXRatio: 1, EndYRatio: 0 };
|
|
11
|
+
static VerticalGradient = { Type: "Linear", Colors: ["#00E8E3D7", "#78E8E3D7", "#78E8E3D7", "#00E8E3D7"], ColorPositions: [0, 0.1, 0.9, 1], StartXRatio: 0, StartYRatio: 0, EndXRatio: 0, EndYRatio: 1 };
|
|
12
|
+
HorizontalLine = SkiaDecoratedGrid.HorizontalGradient;
|
|
13
|
+
VerticalLine = SkiaDecoratedGrid.VerticalGradient;
|
|
14
|
+
Paint(ctx) {
|
|
15
|
+
const g = this.GridStructure;
|
|
16
|
+
if (g) {
|
|
17
|
+
const CK = Super.CK, canvas = ctx.Context.Canvas, scale = ctx.Scale, p = this.Padding, r = this.DrawingRect;
|
|
18
|
+
const inner = new SKRect(r.Left + p.Left * scale, r.Top + p.Top * scale, r.Right - p.Right * scale, r.Bottom - p.Bottom * scale);
|
|
19
|
+
const paint = new CK.Paint();
|
|
20
|
+
paint.setAntiAlias(true);
|
|
21
|
+
if (this.VerticalLine && this.ColumnSpacing > 0) {
|
|
22
|
+
for (let col = 1; col < g.Columns.length; col++) {
|
|
23
|
+
const x = inner.Left + (g.LeftEdgeOfColumn(col) - this.ColumnSpacing) * scale;
|
|
24
|
+
const rect = new SKRect(x, inner.Top, x + this.ColumnSpacing * scale, inner.Bottom);
|
|
25
|
+
paint.setShader(null);
|
|
26
|
+
if (this.SetupGradient(paint, this.VerticalLine, rect))
|
|
27
|
+
canvas.drawRect(CK.LTRBRect(rect.Left, rect.Top, rect.Right, rect.Bottom), paint);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (this.HorizontalLine && this.RowSpacing > 0) {
|
|
31
|
+
for (let row = 1; row < g.Rows.length; row++) {
|
|
32
|
+
const y = inner.Top + (g.TopEdgeOfRow(row) - this.RowSpacing) * scale;
|
|
33
|
+
const rect = new SKRect(inner.Left, y, inner.Right, y + this.RowSpacing * scale);
|
|
34
|
+
const skRect = CK.LTRBRect(rect.Left, rect.Top, rect.Right, rect.Bottom);
|
|
35
|
+
paint.setShader(null);
|
|
36
|
+
paint.setColor(CK.BLACK); // C#: a black SkiaShape under the gradient
|
|
37
|
+
canvas.drawRect(skRect, paint);
|
|
38
|
+
if (this.SetupGradient(paint, this.HorizontalLine, rect))
|
|
39
|
+
canvas.drawRect(skRect, paint);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
paint.delete();
|
|
43
|
+
}
|
|
44
|
+
super.Paint(ctx);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SkiaControl } from "../core/SkiaControl";
|
|
2
|
+
import { type GestureEventProcessingInfo, SKPoint, type SkiaGesturesParameters } from "../core/Gestures";
|
|
3
|
+
import type { DrawerDirection } from "../core/Types";
|
|
4
|
+
import { SnappingLayout } from "./SnappingLayout";
|
|
5
|
+
/**
|
|
6
|
+
* Mirrors DrawnUi SkiaDrawer: a panel that slides from an edge (`Direction`), leaving `HeaderSize` points
|
|
7
|
+
* visible when closed (or travelling `AmplitudeSize`), dragged by gestures and snapped open/closed with
|
|
8
|
+
* velocity; `IsOpen` drives and reports the state. The drawer moves itself with TranslationX/Y (like C#),
|
|
9
|
+
* so it must be aligned to its edge by the parent (VerticalOptions="End" for FromBottom, etc.).
|
|
10
|
+
*/
|
|
11
|
+
export declare class SkiaDrawer extends SnappingLayout {
|
|
12
|
+
Direction: DrawerDirection;
|
|
13
|
+
/** Points that stay visible when closed. */
|
|
14
|
+
HeaderSize: number;
|
|
15
|
+
/** Travel distance override, points; -1 = size minus header. */
|
|
16
|
+
AmplitudeSize: number;
|
|
17
|
+
/** Close when a touch lands outside the drawer while open. */
|
|
18
|
+
AutoClose: boolean;
|
|
19
|
+
IsOpenChanged?: (sender: SkiaDrawer, isOpen: boolean) => void;
|
|
20
|
+
StateTransitionComplete?: (sender: SkiaDrawer, isOpen: boolean) => void;
|
|
21
|
+
private isOpen;
|
|
22
|
+
private lastSize;
|
|
23
|
+
private wasDrawn;
|
|
24
|
+
private panningOffset;
|
|
25
|
+
private childWasTapped;
|
|
26
|
+
private hadDown;
|
|
27
|
+
constructor();
|
|
28
|
+
get IsOpen(): boolean;
|
|
29
|
+
set IsOpen(v: boolean);
|
|
30
|
+
Open(): void;
|
|
31
|
+
Close(): void;
|
|
32
|
+
get Horizontal(): boolean;
|
|
33
|
+
/** C# GetOffsetToHide: translation that hides everything but the header. */
|
|
34
|
+
private OffsetToHide;
|
|
35
|
+
protected GetAutoVelocity(displacement: SKPoint): SKPoint;
|
|
36
|
+
/** C# ApplyOptions: SnapPoints = [open, hidden]; snap to the current IsOpen. */
|
|
37
|
+
private ApplyOptions;
|
|
38
|
+
protected OnLayoutChanged(): void;
|
|
39
|
+
ApplyPosition(position: SKPoint): void;
|
|
40
|
+
UpdateReportedPosition(): void;
|
|
41
|
+
/** IsOpen from the anchor the drawer rests on / travels to. */
|
|
42
|
+
private ReportFromSnap;
|
|
43
|
+
CheckTransitionEnded(): boolean;
|
|
44
|
+
ProcessGestures(args: SkiaGesturesParameters, apply: GestureEventProcessingInfo): SkiaControl | null;
|
|
45
|
+
protected DefaultAccessibilityLabel(): string | undefined;
|
|
46
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { SKPoint } from "../core/Gestures";
|
|
2
|
+
import { SnappingLayout } from "./SnappingLayout";
|
|
3
|
+
/**
|
|
4
|
+
* Mirrors DrawnUi SkiaDrawer: a panel that slides from an edge (`Direction`), leaving `HeaderSize` points
|
|
5
|
+
* visible when closed (or travelling `AmplitudeSize`), dragged by gestures and snapped open/closed with
|
|
6
|
+
* velocity; `IsOpen` drives and reports the state. The drawer moves itself with TranslationX/Y (like C#),
|
|
7
|
+
* so it must be aligned to its edge by the parent (VerticalOptions="End" for FromBottom, etc.).
|
|
8
|
+
*/
|
|
9
|
+
export class SkiaDrawer extends SnappingLayout {
|
|
10
|
+
Direction = "FromBottom";
|
|
11
|
+
/** Points that stay visible when closed. */
|
|
12
|
+
HeaderSize = 0;
|
|
13
|
+
/** Travel distance override, points; -1 = size minus header. */
|
|
14
|
+
AmplitudeSize = -1;
|
|
15
|
+
/** Close when a touch lands outside the drawer while open. */
|
|
16
|
+
AutoClose = false;
|
|
17
|
+
IsOpenChanged;
|
|
18
|
+
StateTransitionComplete;
|
|
19
|
+
isOpen = false;
|
|
20
|
+
lastSize = { W: 0, H: 0 };
|
|
21
|
+
wasDrawn = false;
|
|
22
|
+
panningOffset = SKPoint.Empty;
|
|
23
|
+
childWasTapped = false;
|
|
24
|
+
hadDown = false;
|
|
25
|
+
constructor() { super(); this.HorizontalOptions = "Fill"; }
|
|
26
|
+
get IsOpen() { return this.isOpen; }
|
|
27
|
+
set IsOpen(v) {
|
|
28
|
+
if (this.isOpen === v)
|
|
29
|
+
return;
|
|
30
|
+
this.isOpen = v;
|
|
31
|
+
this.IsOpenChanged?.(this, v);
|
|
32
|
+
this.NotifyAccessibility();
|
|
33
|
+
if (this.SnapPoints.length === 2)
|
|
34
|
+
this.ScrollToOffset(v ? this.SnapPoints[0] : this.SnapPoints[1], SKPoint.Empty, this.Animated && this.wasDrawn);
|
|
35
|
+
}
|
|
36
|
+
Open() { this.IsOpen = true; }
|
|
37
|
+
Close() { this.IsOpen = false; }
|
|
38
|
+
get Horizontal() { return this.Direction === "FromLeft" || this.Direction === "FromRight"; }
|
|
39
|
+
/** C# GetOffsetToHide: translation that hides everything but the header. */
|
|
40
|
+
OffsetToHide() {
|
|
41
|
+
const w = this.DrawingRect.Width / this.RenderingScale, h = this.DrawingRect.Height / this.RenderingScale;
|
|
42
|
+
const travelH = this.AmplitudeSize >= 0 ? this.AmplitudeSize : h - this.HeaderSize;
|
|
43
|
+
const travelW = this.AmplitudeSize >= 0 ? this.AmplitudeSize : w - this.HeaderSize;
|
|
44
|
+
switch (this.Direction) {
|
|
45
|
+
case "FromLeft": return new SKPoint(-travelW, 0);
|
|
46
|
+
case "FromRight": return new SKPoint(travelW, 0);
|
|
47
|
+
case "FromTop": return new SKPoint(0, -travelH);
|
|
48
|
+
default: return new SKPoint(0, travelH);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
GetAutoVelocity(displacement) {
|
|
52
|
+
const v = 1500;
|
|
53
|
+
return this.Horizontal ? new SKPoint(-v * Math.sign(displacement.X), 0) : new SKPoint(0, -v * Math.sign(displacement.Y));
|
|
54
|
+
}
|
|
55
|
+
/** C# ApplyOptions: SnapPoints = [open, hidden]; snap to the current IsOpen. */
|
|
56
|
+
ApplyOptions() {
|
|
57
|
+
const hide = this.OffsetToHide();
|
|
58
|
+
this.SnapPoints = [SKPoint.Empty, hide];
|
|
59
|
+
this.ContentOffsetBounds = this.BoundsFromSnapPoints();
|
|
60
|
+
this.CurrentSnap = new SKPoint(-1, -1);
|
|
61
|
+
this.ScrollToOffset(this.isOpen ? this.SnapPoints[0] : this.SnapPoints[1], SKPoint.Empty, this.Animated && this.wasDrawn);
|
|
62
|
+
}
|
|
63
|
+
OnLayoutChanged() {
|
|
64
|
+
super.OnLayoutChanged();
|
|
65
|
+
const w = this.DrawingRect.Width, h = this.DrawingRect.Height;
|
|
66
|
+
if (w !== this.lastSize.W || h !== this.lastSize.H) {
|
|
67
|
+
this.lastSize = { W: w, H: h };
|
|
68
|
+
this.ApplyOptions();
|
|
69
|
+
}
|
|
70
|
+
this.wasDrawn = true;
|
|
71
|
+
}
|
|
72
|
+
ApplyPosition(position) {
|
|
73
|
+
this.TranslationX = position.X;
|
|
74
|
+
this.TranslationY = position.Y;
|
|
75
|
+
super.ApplyPosition(position);
|
|
76
|
+
this.RepaintComposition();
|
|
77
|
+
}
|
|
78
|
+
UpdateReportedPosition() {
|
|
79
|
+
if (this.InTransition)
|
|
80
|
+
return;
|
|
81
|
+
this.ReportFromSnap();
|
|
82
|
+
}
|
|
83
|
+
/** IsOpen from the anchor the drawer rests on / travels to. */
|
|
84
|
+
ReportFromSnap() {
|
|
85
|
+
if (this.SnapPoints.length < 2)
|
|
86
|
+
return;
|
|
87
|
+
const hidden = this.SnapPoints[1];
|
|
88
|
+
const open = !(Math.abs(hidden.X - this.CurrentSnap.X) <= 1 && Math.abs(hidden.Y - this.CurrentSnap.Y) <= 1);
|
|
89
|
+
if (open !== this.isOpen) {
|
|
90
|
+
this.isOpen = open;
|
|
91
|
+
this.IsOpenChanged?.(this, open);
|
|
92
|
+
this.NotifyAccessibility();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
CheckTransitionEnded() {
|
|
96
|
+
const ended = super.CheckTransitionEnded();
|
|
97
|
+
// the transition just ended: report the reached state first (a gesture-driven close has not been reported yet)
|
|
98
|
+
if (ended && this.InTransition) {
|
|
99
|
+
this.ReportFromSnap();
|
|
100
|
+
this.StateTransitionComplete?.(this, this.isOpen);
|
|
101
|
+
}
|
|
102
|
+
return ended;
|
|
103
|
+
}
|
|
104
|
+
// ---- gestures (port of C# SkiaDrawer.ProcessGestures, single pointer) ----
|
|
105
|
+
ProcessGestures(args, apply) {
|
|
106
|
+
const consumedDefault = this.BlockGesturesBelow ? this : null;
|
|
107
|
+
const scale = this.RenderingScale;
|
|
108
|
+
const e = args.Event;
|
|
109
|
+
// the drawer sits in a full-size layer: touches outside its (translated) box are not ours
|
|
110
|
+
const local = apply.MappedLocation;
|
|
111
|
+
const hit = this.HitIsInside(local.X + apply.ChildOffset.X, local.Y + apply.ChildOffset.Y);
|
|
112
|
+
if (!this.hadDown && args.Type !== "Up") {
|
|
113
|
+
if (!hit) {
|
|
114
|
+
if (this.AutoClose && this.isOpen && !this.InTransition)
|
|
115
|
+
this.IsOpen = false;
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
let passed = false;
|
|
120
|
+
const passToChildren = () => { passed = true; return super.ProcessGestures(args, apply); };
|
|
121
|
+
let consumed = null;
|
|
122
|
+
if (args.Type === "Up" || args.Type === "Tapped" || !this.IsUserPanning || !this.RespondsToGestures) {
|
|
123
|
+
consumed = passToChildren();
|
|
124
|
+
if (consumed === this)
|
|
125
|
+
consumed = null;
|
|
126
|
+
if (consumed && args.Type !== "Up") {
|
|
127
|
+
if (args.Type === "Tapped")
|
|
128
|
+
this.childWasTapped = true;
|
|
129
|
+
return consumed;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!this.RespondsToGestures)
|
|
133
|
+
return consumed;
|
|
134
|
+
const resetPan = () => {
|
|
135
|
+
this.IsUserFocused = true;
|
|
136
|
+
this.IsUserPanning = false;
|
|
137
|
+
this.childWasTapped = false;
|
|
138
|
+
this.StopSnapAnimators();
|
|
139
|
+
this.velocityAccumulator.Clear();
|
|
140
|
+
this.panningOffset = new SKPoint(this.TranslationX, this.TranslationY);
|
|
141
|
+
};
|
|
142
|
+
switch (args.Type) {
|
|
143
|
+
case "Tapped":
|
|
144
|
+
case "LongPressing":
|
|
145
|
+
consumed = this;
|
|
146
|
+
break;
|
|
147
|
+
case "Down":
|
|
148
|
+
this.hadDown = true;
|
|
149
|
+
resetPan();
|
|
150
|
+
break;
|
|
151
|
+
case "Panning": {
|
|
152
|
+
if (!this.hadDown)
|
|
153
|
+
return consumedDefault;
|
|
154
|
+
const horizontal = this.Horizontal;
|
|
155
|
+
// dragging further open at the open edge: no rubber (C# lockBounce)
|
|
156
|
+
const openEdge = this.SnapPoints[0], atOpen = openEdge && Math.abs(this.CurrentPosition.X - openEdge.X) <= 1 && Math.abs(this.CurrentPosition.Y - openEdge.Y) <= 1;
|
|
157
|
+
const dx = e.Distance.Delta.X, dy = e.Distance.Delta.Y;
|
|
158
|
+
const lockBounce = !!atOpen && ((this.Direction === "FromLeft" && dx > 0) || (this.Direction === "FromRight" && dx < 0) || (this.Direction === "FromBottom" && dy < 0) || (this.Direction === "FromTop" && dy > 0));
|
|
159
|
+
if (!this.IsUserFocused) {
|
|
160
|
+
resetPan();
|
|
161
|
+
this.panningOffset = new SKPoint(this.panningOffset.X - dx / scale, this.panningOffset.Y - dy / scale);
|
|
162
|
+
}
|
|
163
|
+
let x = this.panningOffset.X + dx / scale, y = this.panningOffset.Y + dy / scale;
|
|
164
|
+
if (!this.IsUserPanning) {
|
|
165
|
+
const tx = Math.abs(e.Distance.Total.X), ty = Math.abs(e.Distance.Total.Y);
|
|
166
|
+
const mainHorizontal = tx > ty * 0.9, mainVertical = ty > tx * 0.9;
|
|
167
|
+
if (this.IgnoreWrongDirection && ((horizontal && !mainHorizontal) || (!horizontal && !mainVertical)))
|
|
168
|
+
break;
|
|
169
|
+
if (horizontal ? tx < scale : ty < scale)
|
|
170
|
+
break;
|
|
171
|
+
this.IsUserPanning = true;
|
|
172
|
+
}
|
|
173
|
+
if (horizontal) {
|
|
174
|
+
this.velocityAccumulator.CaptureVelocity(e.Distance.Velocity.X / scale, 0, args.ArrivedTimeNanos);
|
|
175
|
+
y = 0;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
this.velocityAccumulator.CaptureVelocity(0, e.Distance.Velocity.Y / scale, args.ArrivedTimeNanos);
|
|
179
|
+
x = 0;
|
|
180
|
+
}
|
|
181
|
+
this.panningOffset = new SKPoint(x, y);
|
|
182
|
+
const clamped = this.ClampOffset(x, y, this.Bounces && !lockBounce);
|
|
183
|
+
if (!this.Bounces && lockBounce && Math.abs(clamped.X) <= 1 && Math.abs(clamped.Y) <= 1) {
|
|
184
|
+
this.IsUserPanning = false;
|
|
185
|
+
return null;
|
|
186
|
+
} // let a parent scroll take it
|
|
187
|
+
this.ApplyPosition(clamped);
|
|
188
|
+
consumed = this;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case "Up": {
|
|
192
|
+
this.hadDown = false;
|
|
193
|
+
if (this.childWasTapped || !this.IsUserPanning)
|
|
194
|
+
break;
|
|
195
|
+
const final = this.velocityAccumulator.CalculateFinalVelocity(3000);
|
|
196
|
+
const v = this.Horizontal ? new SKPoint(final.X, 0) : new SKPoint(0, final.Y);
|
|
197
|
+
this.CurrentSnap = this.CurrentPosition;
|
|
198
|
+
this.ScrollToNearestAnchor(this.CurrentPosition, v);
|
|
199
|
+
this.IsUserPanning = false;
|
|
200
|
+
this.IsUserFocused = false;
|
|
201
|
+
consumed = this;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (consumed || this.IsUserPanning)
|
|
206
|
+
return consumed ?? (args.Type !== "Up" ? this : consumedDefault);
|
|
207
|
+
if (!passed)
|
|
208
|
+
return passToChildren();
|
|
209
|
+
return consumedDefault;
|
|
210
|
+
}
|
|
211
|
+
DefaultAccessibilityLabel() { return this.isOpen ? "Drawer open" : "Drawer closed"; }
|
|
212
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SkiaLayout } from "./SkiaLayout";
|
|
2
|
+
/**
|
|
3
|
+
* Mirrors DrawnUi SkiaDynamicDrawnCell: base for recycled cells. Build the visuals once in the
|
|
4
|
+
* constructor, override SetContent(ctx) to push the bound item into them — it runs on every rebind.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SkiaDynamicDrawnCell extends SkiaLayout {
|
|
7
|
+
constructor();
|
|
8
|
+
protected OnBindingContextChanged(): void;
|
|
9
|
+
/** Called with the item (BindingContext) whenever the cell is (re)bound. */
|
|
10
|
+
protected SetContent(_ctx: unknown): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SkiaLayout } from "./SkiaLayout";
|
|
2
|
+
/**
|
|
3
|
+
* Mirrors DrawnUi SkiaDynamicDrawnCell: base for recycled cells. Build the visuals once in the
|
|
4
|
+
* constructor, override SetContent(ctx) to push the bound item into them — it runs on every rebind.
|
|
5
|
+
*/
|
|
6
|
+
export class SkiaDynamicDrawnCell extends SkiaLayout {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this.HorizontalOptions = "Fill";
|
|
10
|
+
}
|
|
11
|
+
OnBindingContextChanged() {
|
|
12
|
+
super.OnBindingContextChanged();
|
|
13
|
+
this.SetContent(this.BindingContext);
|
|
14
|
+
}
|
|
15
|
+
/** Called with the item (BindingContext) whenever the cell is (re)bound. */
|
|
16
|
+
SetContent(_ctx) { }
|
|
17
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { DrawingContext, SkiaControl } from "../core/SkiaControl";
|
|
2
|
+
import { type GestureEventProcessingInfo, type SkiaGesturesParameters } from "../core/Gestures";
|
|
3
|
+
import { type PrebuiltControlStyle } from "../core/ControlStyle";
|
|
4
|
+
import { type Color, type DrawTextAlignment, type ReturnType, ScaledSize, type SkiaEditorKeyboard, type SkiaGradient, type TextAlignment } from "../core/Types";
|
|
5
|
+
import { SkiaLabel } from "./SkiaLabel";
|
|
6
|
+
import { SkiaShape } from "./SkiaShape";
|
|
7
|
+
/**
|
|
8
|
+
* Mirrors DrawnUi SkiaEditor: a drawn text input. The text is a SkiaLabel inside a shape with padding, a
|
|
9
|
+
* placeholder label, a blinking caret and a selection overlay painted by the editor; single line
|
|
10
|
+
* (`MaxLines` 1, horizontal scrolling to the caret) or multiline (`MaxLines` != 1, `AutoHeight`). Keys come from
|
|
11
|
+
* the window-level `KeyboardManager` like the DrawnUi.Blazor / Wasm heads (no DOM text input: no IME, no mobile
|
|
12
|
+
* soft keyboard) and are applied by the same stub editing methods (`StubTypeText`, `StubBackspace`, arrows,
|
|
13
|
+
* Home / End, Ctrl+A / C / X / V). Taps place the caret, drags select, a long press selects the word, Enter submits
|
|
14
|
+
* (single line, or multiline with `ReturnType` Send).
|
|
15
|
+
*/
|
|
16
|
+
export declare class SkiaEditor extends SkiaShape {
|
|
17
|
+
/** The editor currently holding the keyboard, if any. */
|
|
18
|
+
static Focused?: SkiaEditor;
|
|
19
|
+
static DefaultAccessibilityRole?: string;
|
|
20
|
+
TextChanged?: (sender: SkiaEditor, text: string) => void;
|
|
21
|
+
FocusChanged?: (sender: SkiaEditor, focused: boolean) => void;
|
|
22
|
+
CursorMoved?: (sender: SkiaEditor) => void;
|
|
23
|
+
TextSubmitted?: (sender: SkiaEditor, text: string) => void;
|
|
24
|
+
private text;
|
|
25
|
+
private placeholderText;
|
|
26
|
+
PlaceholderColor: Color;
|
|
27
|
+
PlaceholderHorizontalAlignment: DrawTextAlignment;
|
|
28
|
+
private fontSize;
|
|
29
|
+
private fontFamily;
|
|
30
|
+
private fontWeight;
|
|
31
|
+
private textColor;
|
|
32
|
+
TextGradient?: SkiaGradient;
|
|
33
|
+
private lineHeight;
|
|
34
|
+
private horizontalTextAlignment;
|
|
35
|
+
private verticalTextAlignment;
|
|
36
|
+
private maxLines;
|
|
37
|
+
AutoHeight: boolean;
|
|
38
|
+
private isPassword;
|
|
39
|
+
/** Enter on a multiline editor: Send submits, anything else inserts a line break. */
|
|
40
|
+
ReturnType: ReturnType;
|
|
41
|
+
KeyboardType: SkiaEditorKeyboard;
|
|
42
|
+
private fontFamilyFallback;
|
|
43
|
+
/** Fallback font aliases for glyphs the main font lacks (symbols, emoji), forwarded to the text and placeholder labels. */
|
|
44
|
+
get FontFamilyFallback(): string;
|
|
45
|
+
set FontFamilyFallback(v: string);
|
|
46
|
+
IsSpellCheckEnabled: boolean;
|
|
47
|
+
/** Accepted for parity: the React label always renders unicode; markdown formatting while editing is not ported. */
|
|
48
|
+
UseMarkdown: boolean;
|
|
49
|
+
UseUnicode: boolean;
|
|
50
|
+
CursorColor: Color;
|
|
51
|
+
CanShowCursor: boolean;
|
|
52
|
+
SelectionColor: Color;
|
|
53
|
+
private cursorPosition;
|
|
54
|
+
private selectionLength;
|
|
55
|
+
private isFocused;
|
|
56
|
+
private controlStyle;
|
|
57
|
+
readonly Label: SkiaLabel;
|
|
58
|
+
private readonly placeholder;
|
|
59
|
+
private scrollX;
|
|
60
|
+
private scrollY;
|
|
61
|
+
private blink;
|
|
62
|
+
private caretVisible;
|
|
63
|
+
private subscribed;
|
|
64
|
+
private stubSelectionStop;
|
|
65
|
+
private selectionMovingEdge;
|
|
66
|
+
private readonly onKeyDown;
|
|
67
|
+
private readonly onKeyChar;
|
|
68
|
+
private selectionAnchor;
|
|
69
|
+
private dragSelecting;
|
|
70
|
+
private styleApplied;
|
|
71
|
+
private layoutVersion;
|
|
72
|
+
private boxes;
|
|
73
|
+
constructor();
|
|
74
|
+
get Text(): string;
|
|
75
|
+
set Text(v: string);
|
|
76
|
+
get PlaceholderText(): string;
|
|
77
|
+
set PlaceholderText(v: string);
|
|
78
|
+
get FontSize(): number;
|
|
79
|
+
set FontSize(v: number);
|
|
80
|
+
get FontFamily(): string;
|
|
81
|
+
set FontFamily(v: string);
|
|
82
|
+
get FontWeight(): number;
|
|
83
|
+
set FontWeight(v: number);
|
|
84
|
+
get TextColor(): Color;
|
|
85
|
+
set TextColor(v: Color);
|
|
86
|
+
get LineHeight(): number;
|
|
87
|
+
set LineHeight(v: number);
|
|
88
|
+
get HorizontalTextAlignment(): DrawTextAlignment;
|
|
89
|
+
set HorizontalTextAlignment(v: DrawTextAlignment);
|
|
90
|
+
get VerticalTextAlignment(): TextAlignment;
|
|
91
|
+
set VerticalTextAlignment(v: TextAlignment);
|
|
92
|
+
/** 1 = single line (default); anything else = multiline, -1 unbounded. */
|
|
93
|
+
get MaxLines(): number;
|
|
94
|
+
set MaxLines(v: number);
|
|
95
|
+
get IsPassword(): boolean;
|
|
96
|
+
set IsPassword(v: boolean);
|
|
97
|
+
get IsMultiline(): boolean;
|
|
98
|
+
get HasSelection(): boolean;
|
|
99
|
+
get ShouldSubmitOnEnter(): boolean;
|
|
100
|
+
/** Caret index (UTF-16 units) = the left edge of the selection when one exists. */
|
|
101
|
+
get CursorPosition(): number;
|
|
102
|
+
set CursorPosition(v: number);
|
|
103
|
+
get SelectionLength(): number;
|
|
104
|
+
set SelectionLength(v: number);
|
|
105
|
+
private OnCursorMoved;
|
|
106
|
+
get IsFocused(): boolean;
|
|
107
|
+
set IsFocused(v: boolean);
|
|
108
|
+
get ControlStyle(): PrebuiltControlStyle;
|
|
109
|
+
set ControlStyle(v: PrebuiltControlStyle);
|
|
110
|
+
/** C# ApplyControlStyleVisuals: background, corners, border, cursor per style, applied only over values the app has not changed. */
|
|
111
|
+
private ApplyControlStyleVisuals;
|
|
112
|
+
private static NormalizeLineBreaks;
|
|
113
|
+
/** C# UpdateLabel: pushes the editor's text props into the content and placeholder labels. */
|
|
114
|
+
UpdateLabel(): void;
|
|
115
|
+
/** Visual height of one line in points (C# GetSingleLineHeightPts). */
|
|
116
|
+
GetSingleLineHeightPts(): number;
|
|
117
|
+
private Inner;
|
|
118
|
+
protected MeasureAbsolute(w: number, h: number, scale: number): ScaledSize;
|
|
119
|
+
protected OnLayoutChanged(): void;
|
|
120
|
+
private ClampScroll;
|
|
121
|
+
/** Keeps the caret inside the padded box by scrolling the label (C#: SkiaScroll under the label). */
|
|
122
|
+
private ScrollToCaret;
|
|
123
|
+
private Boxes;
|
|
124
|
+
/** Rect of the caret before character `index` (label pixels), or undefined before the first layout. */
|
|
125
|
+
private CaretRectLabelPx;
|
|
126
|
+
/** C# GetCursorPosition: the text index nearest to a point in label pixels. */
|
|
127
|
+
private HitTestIndex;
|
|
128
|
+
private LabelPoint;
|
|
129
|
+
protected Paint(ctx: DrawingContext): void;
|
|
130
|
+
ProcessGestures(args: SkiaGesturesParameters, apply: GestureEventProcessingInfo): SkiaControl | null;
|
|
131
|
+
OnAccessibilityActivated(): void;
|
|
132
|
+
protected DefaultAccessibilityLabel(): string | undefined;
|
|
133
|
+
Submit(): void;
|
|
134
|
+
private ExecuteSubmit;
|
|
135
|
+
SelectAll(): void;
|
|
136
|
+
SetSelection(start: number, end: number): void;
|
|
137
|
+
/** Selects the word around a character index (C# SelectWord). */
|
|
138
|
+
SelectWord(index: number): void;
|
|
139
|
+
GetSelectedText(): string;
|
|
140
|
+
DeleteSelection(): void;
|
|
141
|
+
InsertAtCursor(value: string): void;
|
|
142
|
+
CutSelection(): void;
|
|
143
|
+
CopySelection(): void;
|
|
144
|
+
PasteFromClipboard(): void;
|
|
145
|
+
private ReplaceSelection;
|
|
146
|
+
private SetFocusNative;
|
|
147
|
+
private OnKeyDown;
|
|
148
|
+
StubTypeText(value: string): void;
|
|
149
|
+
StubPressEnter(splitLine?: boolean, shift?: boolean): void;
|
|
150
|
+
StubBackspace(count?: number): void;
|
|
151
|
+
StubDelete(count?: number): void;
|
|
152
|
+
/** Arrow / Home / End: the anchor stays, the moving edge follows (shift), or the selection collapses in the move direction. */
|
|
153
|
+
StubMoveCursor(delta: number, extendSelection?: boolean): void;
|
|
154
|
+
StubSelectRange(start: number, length: number): void;
|
|
155
|
+
StubSelectAll(): void;
|
|
156
|
+
/** Up / Down keep the caret x on the neighbouring line (C# HandleVerticalArrow). */
|
|
157
|
+
protected HandleVerticalArrow(up: boolean): void;
|
|
158
|
+
/** UTF-16 units of `count` grapheme clusters before the caret (C# CodeUnitsBeforeCaret). */
|
|
159
|
+
static CodeUnitsBeforeCaret(text: string, caret: number, count: number): number;
|
|
160
|
+
static CodeUnitsAfterCaret(text: string, caret: number, count: number): number;
|
|
161
|
+
private static Graphemes;
|
|
162
|
+
protected OnDisposing(): void;
|
|
163
|
+
}
|