drawnui-react 0.1.0-preview.2 → 0.1.0-preview.21
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/README.md +17 -4
- package/SKIPPED.md +33 -27
- package/dist/controls/AnimatedFramesRenderer.d.ts +7 -0
- package/dist/controls/AnimatedFramesRenderer.js +16 -1
- package/dist/controls/DrawnGame.d.ts +40 -0
- package/dist/controls/DrawnGame.js +64 -0
- package/dist/controls/GridStructure.d.ts +16 -2
- package/dist/controls/GridStructure.js +40 -4
- package/dist/controls/SkiaBackdrop.d.ts +8 -2
- package/dist/controls/SkiaBackdrop.js +48 -8
- package/dist/controls/SkiaButton.d.ts +19 -2
- package/dist/controls/SkiaButton.js +41 -11
- package/dist/controls/SkiaCarousel.d.ts +9 -1
- package/dist/controls/SkiaCarousel.js +16 -3
- package/dist/controls/SkiaCheckbox.d.ts +0 -1
- package/dist/controls/SkiaCheckbox.js +0 -6
- package/dist/controls/SkiaDrawer.d.ts +2 -0
- package/dist/controls/SkiaDrawer.js +2 -0
- package/dist/controls/SkiaEditor.d.ts +12 -1
- package/dist/controls/SkiaEditor.js +46 -19
- package/dist/controls/SkiaGif.d.ts +3 -0
- package/dist/controls/SkiaGif.js +12 -2
- package/dist/controls/SkiaImage.js +15 -10
- package/dist/controls/SkiaLabel.d.ts +54 -3
- package/dist/controls/SkiaLabel.js +235 -52
- package/dist/controls/SkiaLabelFps.d.ts +16 -0
- package/dist/controls/SkiaLabelFps.js +41 -0
- package/dist/controls/SkiaLayout.d.ts +64 -7
- package/dist/controls/SkiaLayout.js +316 -19
- package/dist/controls/SkiaLottie.js +4 -2
- package/dist/controls/SkiaProgress.d.ts +2 -1
- package/dist/controls/SkiaProgress.js +6 -3
- package/dist/controls/SkiaRadioButton.js +4 -3
- package/dist/controls/SkiaScroll.d.ts +35 -5
- package/dist/controls/SkiaScroll.js +233 -23
- package/dist/controls/SkiaScrollBar.d.ts +27 -0
- package/dist/controls/SkiaScrollBar.js +51 -2
- package/dist/controls/SkiaShaderCarousel.d.ts +5 -0
- package/dist/controls/SkiaShaderCarousel.js +5 -0
- package/dist/controls/SkiaShape.d.ts +13 -2
- package/dist/controls/SkiaShape.js +50 -10
- package/dist/controls/SkiaSlider.d.ts +20 -2
- package/dist/controls/SkiaSlider.js +59 -5
- package/dist/controls/SkiaSprite.d.ts +1 -0
- package/dist/controls/SkiaSprite.js +4 -0
- package/dist/controls/SkiaSvg.js +1 -1
- package/dist/controls/SkiaSwitch.d.ts +0 -1
- package/dist/controls/SkiaSwitch.js +0 -6
- package/dist/controls/SkiaToggle.d.ts +25 -5
- package/dist/controls/SkiaToggle.js +58 -5
- package/dist/controls/SnappingLayout.d.ts +12 -1
- package/dist/controls/SnappingLayout.js +19 -1
- package/dist/core/Accessibility.d.ts +80 -0
- package/dist/core/Accessibility.js +365 -8
- package/dist/core/Animators.d.ts +37 -1
- package/dist/core/Animators.js +102 -9
- package/dist/core/Canvas.d.ts +108 -7
- package/dist/core/Canvas.js +363 -35
- package/dist/core/Easing.d.ts +12 -1
- package/dist/core/Easing.js +25 -1
- package/dist/core/Gestures.d.ts +48 -2
- package/dist/core/Gestures.js +95 -3
- package/dist/core/Hover.d.ts +47 -0
- package/dist/core/Hover.js +134 -0
- package/dist/core/KeyboardManager.d.ts +13 -0
- package/dist/core/KeyboardManager.js +18 -0
- package/dist/core/ScrollAnimators.js +9 -0
- package/dist/core/SkiaControl.d.ts +216 -7
- package/dist/core/SkiaControl.js +516 -59
- package/dist/core/SkiaEffect.d.ts +17 -0
- package/dist/core/SkiaEffect.js +43 -8
- package/dist/core/SkiaImageManager.js +1 -1
- package/dist/core/Styles.d.ts +51 -0
- package/dist/core/Styles.js +92 -0
- package/dist/core/Super.d.ts +17 -1
- package/dist/core/Super.js +35 -4
- package/dist/core/ViewsAdapter.d.ts +7 -2
- package/dist/core/ViewsAdapter.js +10 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/react/SkiaShell.js +33 -14
- package/dist/react/index.d.ts +15 -4
- package/dist/react/index.js +102 -15
- package/dist/react/reconciler.js +34 -12
- package/dist/vite/index.d.ts +9 -0
- package/dist/vite/index.js +36 -3
- package/package.json +33 -3
|
@@ -119,12 +119,29 @@ export declare class SkiaShaderEffect extends SkiaEffect implements IPostRendere
|
|
|
119
119
|
get NeedApply(): boolean;
|
|
120
120
|
/** Loads (async, once) and compiles (sync) when needed; true when a compiled effect exists. */
|
|
121
121
|
EnsureCompiled(): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* C# ShouldInvalidateParentCache (default false): animation ticks, `SetUniform` and `UpdateUniforms()` only redraw
|
|
124
|
+
* this effect over the parent's cache (ancestor caches still redraw), because the effect paints over the parent's
|
|
125
|
+
* cached content and a uniform change needs no new cache. True: they also invalidate the parent's cache, so the parent
|
|
126
|
+
* re-renders its content on every change; set it when that content refreshes only through the effect's redraws (a
|
|
127
|
+
* custom Paint reading changing data without calling Update()). `Update()` always invalidates the cache.
|
|
128
|
+
*/
|
|
129
|
+
ShouldInvalidateParentCache: boolean;
|
|
130
|
+
/** Call after changing a value only the shader reads (a uniform, an animation progress): redraws the effect over the parent's cache, or `Update()` when ShouldInvalidateParentCache is true. */
|
|
131
|
+
UpdateUniforms(): void;
|
|
122
132
|
SetUniform(name: string, ...values: number[]): this;
|
|
123
133
|
ReleaseFrozenSnapshot(): void;
|
|
124
134
|
private DisposeImage;
|
|
125
135
|
protected ApplyShaderSource(): void;
|
|
126
136
|
/** Snapshot of what the parent painted (C# CreateSnapshot): the surface the pixels are on, mapped through its origin. */
|
|
127
137
|
protected CreateSnapshot(ctx: DrawingContext, destination: SKRect): CachedTexture | undefined;
|
|
138
|
+
private frozenEpoch;
|
|
139
|
+
/** Canvas.GpuEpoch: GPU textures made before a WebGL context restore are made again. */
|
|
140
|
+
protected GpuEpoch(): number;
|
|
141
|
+
/** Where the parent was when the texture was frozen (Once): the texture moves with it, as its cache does. */
|
|
142
|
+
private frozenAt?;
|
|
143
|
+
private ParentOrigin;
|
|
144
|
+
private FollowParent;
|
|
128
145
|
/** C# GetPrimaryTexture: the parent's cache, a frozen snapshot (Once) or nothing (Never). */
|
|
129
146
|
protected GetPrimaryTexture(_ctx: DrawingContext, _destination: SKRect): CachedTexture | undefined;
|
|
130
147
|
/** Image → shader with the effect's sampling, translated so texel (0,0) = bounds top-left; cached per image. */
|
package/dist/core/SkiaEffect.js
CHANGED
|
@@ -2,7 +2,7 @@ import { SkiaValueAnimator } from "./Animators";
|
|
|
2
2
|
import { Easing } from "./Easing";
|
|
3
3
|
import { SkiaImageManager } from "./SkiaImageManager";
|
|
4
4
|
import { Super } from "./Super";
|
|
5
|
-
import { Thickness } from "./Types";
|
|
5
|
+
import { SKRect, Thickness } from "./Types";
|
|
6
6
|
/**
|
|
7
7
|
* Mirrors DrawnUi SkiaEffect: something attached to a control through `VisualEffects`. `Update()` re-renders the
|
|
8
8
|
* parent (C# invalidates the parent's cache and redraws), `GetEffectMargin` reports what it paints outside the box.
|
|
@@ -116,11 +116,27 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
116
116
|
}
|
|
117
117
|
return this.compiled !== undefined;
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* C# ShouldInvalidateParentCache (default false): animation ticks, `SetUniform` and `UpdateUniforms()` only redraw
|
|
121
|
+
* this effect over the parent's cache (ancestor caches still redraw), because the effect paints over the parent's
|
|
122
|
+
* cached content and a uniform change needs no new cache. True: they also invalidate the parent's cache, so the parent
|
|
123
|
+
* re-renders its content on every change; set it when that content refreshes only through the effect's redraws (a
|
|
124
|
+
* custom Paint reading changing data without calling Update()). `Update()` always invalidates the cache.
|
|
125
|
+
*/
|
|
126
|
+
ShouldInvalidateParentCache = false;
|
|
127
|
+
/** Call after changing a value only the shader reads (a uniform, an animation progress): redraws the effect over the parent's cache, or `Update()` when ShouldInvalidateParentCache is true. */
|
|
128
|
+
UpdateUniforms() {
|
|
129
|
+
if (this.ShouldInvalidateParentCache) {
|
|
130
|
+
this.Update();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this.Parent?.RepaintComposition();
|
|
134
|
+
}
|
|
119
135
|
// ---- uniforms API (C# SetUniform overloads) ----
|
|
120
136
|
SetUniform(name, ...values) {
|
|
121
137
|
if (name && values.length > 0) {
|
|
122
138
|
this.Uniforms.set(name, values);
|
|
123
|
-
this.
|
|
139
|
+
this.UpdateUniforms();
|
|
124
140
|
}
|
|
125
141
|
return this;
|
|
126
142
|
}
|
|
@@ -129,6 +145,7 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
129
145
|
this.DisposeImage(this.frozen.Image);
|
|
130
146
|
this.frozen = undefined;
|
|
131
147
|
this.frozenOwned = false;
|
|
148
|
+
this.frozenAt = undefined;
|
|
132
149
|
}
|
|
133
150
|
DisposeImage(image) {
|
|
134
151
|
const sv = this.Parent?.Superview;
|
|
@@ -158,12 +175,27 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
158
175
|
return undefined;
|
|
159
176
|
return { Image: image, Bounds: destination, Origin: { X: ox, Y: oy } };
|
|
160
177
|
}
|
|
178
|
+
frozenEpoch = 0;
|
|
179
|
+
/** Canvas.GpuEpoch: GPU textures made before a WebGL context restore are made again. */
|
|
180
|
+
GpuEpoch() { return this.Parent?.Superview?.GpuEpoch ?? 0; }
|
|
181
|
+
/** Where the parent was when the texture was frozen (Once): the texture moves with it, as its cache does. */
|
|
182
|
+
frozenAt;
|
|
183
|
+
ParentOrigin() { const r = this.Parent?.DrawingRect; return { X: r?.Left ?? 0, Y: r?.Top ?? 0 }; }
|
|
184
|
+
FollowParent(texture) {
|
|
185
|
+
if (!texture || !this.frozenAt)
|
|
186
|
+
return texture;
|
|
187
|
+
const now = this.ParentOrigin(), dx = now.X - this.frozenAt.X, dy = now.Y - this.frozenAt.Y;
|
|
188
|
+
if (dx === 0 && dy === 0)
|
|
189
|
+
return texture;
|
|
190
|
+
const b = texture.Bounds;
|
|
191
|
+
return { Image: texture.Image, Bounds: new SKRect(b.Left + dx, b.Top + dy, b.Right + dx, b.Bottom + dy), Origin: texture.Origin && { X: texture.Origin.X + dx, Y: texture.Origin.Y + dy } };
|
|
192
|
+
}
|
|
161
193
|
/** C# GetPrimaryTexture: the parent's cache, a frozen snapshot (Once) or nothing (Never). */
|
|
162
194
|
GetPrimaryTexture(_ctx, _destination) {
|
|
163
195
|
switch (this.UseBackground) {
|
|
164
196
|
case "Never": return undefined;
|
|
165
197
|
case "Once":
|
|
166
|
-
if (!this.AquiredBackground || !this.frozen) {
|
|
198
|
+
if (!this.AquiredBackground || !this.frozen || this.frozenEpoch !== this.GpuEpoch()) { // a frozen texture of a lost GPU context is taken again
|
|
167
199
|
this.ReleaseFrozenSnapshot();
|
|
168
200
|
let snapshot = this.Parent?.CachedImage;
|
|
169
201
|
let owned = false;
|
|
@@ -175,9 +207,11 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
175
207
|
this.frozen = snapshot;
|
|
176
208
|
this.frozenOwned = owned;
|
|
177
209
|
this.AquiredBackground = true;
|
|
210
|
+
this.frozenAt = this.ParentOrigin();
|
|
211
|
+
this.frozenEpoch = this.GpuEpoch();
|
|
178
212
|
}
|
|
179
213
|
}
|
|
180
|
-
return this.frozen;
|
|
214
|
+
return this.FollowParent(this.frozen);
|
|
181
215
|
default:
|
|
182
216
|
return this.Parent?.CachedImage;
|
|
183
217
|
}
|
|
@@ -228,7 +262,7 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
228
262
|
static async FetchText(url) {
|
|
229
263
|
let p = sourceCache.get(url);
|
|
230
264
|
if (!p) {
|
|
231
|
-
p = fetch(url).then((r) => { if (!r.ok)
|
|
265
|
+
p = fetch(Super.ResolveAssetUrl(url)).then((r) => { if (!r.ok)
|
|
232
266
|
throw new Error(`${r.status} ${url}`); return r.text(); });
|
|
233
267
|
sourceCache.set(url, p);
|
|
234
268
|
}
|
|
@@ -420,7 +454,8 @@ export class ShaderDoubleTexturesEffect extends SkiaShaderEffect {
|
|
|
420
454
|
return undefined;
|
|
421
455
|
const w = Math.round(d.Width), h = Math.round(d.Height);
|
|
422
456
|
const cur = slot === "p" ? this.resizedPrimary : this.resizedSecondary;
|
|
423
|
-
|
|
457
|
+
const epoch = this.GpuEpoch();
|
|
458
|
+
if (cur && cur.source === source && cur.w === w && cur.h === h && cur.epoch === epoch)
|
|
424
459
|
return cur.image;
|
|
425
460
|
const main = ctx.Context.Surface;
|
|
426
461
|
if (!main)
|
|
@@ -435,7 +470,7 @@ export class ShaderDoubleTexturesEffect extends SkiaShaderEffect {
|
|
|
435
470
|
const image = surface.makeImageSnapshot();
|
|
436
471
|
surface.delete();
|
|
437
472
|
cur?.image.delete();
|
|
438
|
-
const entry = { source, w, h, image };
|
|
473
|
+
const entry = { source, w, h, epoch, image };
|
|
439
474
|
if (slot === "p")
|
|
440
475
|
this.resizedPrimary = entry;
|
|
441
476
|
else
|
|
@@ -546,7 +581,7 @@ export class AnimatedShaderEffect extends SkiaShaderEffect {
|
|
|
546
581
|
return;
|
|
547
582
|
if (!this.Animator) {
|
|
548
583
|
const a = new SkiaValueAnimator(parent);
|
|
549
|
-
a.OnUpdated = (v) => { this.Progress = v; this.
|
|
584
|
+
a.OnUpdated = (v) => { this.Progress = v; this.UpdateUniforms(); };
|
|
550
585
|
a.Finished = () => this.Completed?.(this);
|
|
551
586
|
this.Animator = a;
|
|
552
587
|
}
|
|
@@ -39,7 +39,7 @@ export class SkiaImageManager {
|
|
|
39
39
|
return inflight;
|
|
40
40
|
}
|
|
41
41
|
async Fetch(source, signal) {
|
|
42
|
-
const response = await fetch(source, signal ? { signal } : undefined);
|
|
42
|
+
const response = await fetch(Super.ResolveAssetUrl(source), signal ? { signal } : undefined);
|
|
43
43
|
if (!response.ok)
|
|
44
44
|
throw new Error(`DrawnUi: ${response.status} loading image '${source}'`);
|
|
45
45
|
const image = Super.CK.MakeImageFromEncoded(await response.arrayBuffer());
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { SkiaControl } from "./SkiaControl";
|
|
2
|
+
/**
|
|
3
|
+
* Mirrors DrawnUi.Net `Style` (SharedNet/Internals/Core/Style.cs): a set of property defaults for one control type,
|
|
4
|
+
* registered once at startup through `Super.UseDrawnUi().ConfigureStyles(...)`.
|
|
5
|
+
*
|
|
6
|
+
* The C# `Setters` list of `Setter { Property, Value }` becomes a plain object here, because React controls are
|
|
7
|
+
* classes with plain properties instead of BindableProperty: `Setters: { FontFamily: "FontText", FontSize: 14 }`.
|
|
8
|
+
*/
|
|
9
|
+
export interface Style {
|
|
10
|
+
/** The control class the style targets, e.g. `SkiaLabel`. */
|
|
11
|
+
TargetType: Function;
|
|
12
|
+
/** Also style classes deriving from TargetType (C# Style.ApplyToDerivedTypes). Default false. */
|
|
13
|
+
ApplyToDerivedTypes?: boolean;
|
|
14
|
+
/** Property defaults, by property name. Anything the app sets itself wins over these. */
|
|
15
|
+
Setters: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
/** Mirrors DrawnUi.Net `IStylesCollection` / `StylesCollection`: the startup registry, static like the C# one. */
|
|
18
|
+
export declare class StylesCollection {
|
|
19
|
+
/** Every style registered through ConfigureStyles, in registration order (C# StylesCollection.Styles). */
|
|
20
|
+
static readonly Styles: Style[];
|
|
21
|
+
AddStyle(style: Style): StylesCollection;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Applies registered styles to controls. Port of the C# `SkiaControl` styles partial
|
|
25
|
+
* (SharedNet/Draw/SkiaControl.NetShared.cs) with one difference forced by the language: C# knows which properties the
|
|
26
|
+
* app set explicitly (BindableProperty + ExplicitPropertiesSet) and skips those; here a property counts as "not set by
|
|
27
|
+
* the app" while it still equals the value the control's own constructor left, captured once per class.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SkiaStyles {
|
|
30
|
+
private static readonly resolved;
|
|
31
|
+
private static readonly defaults;
|
|
32
|
+
/** True while no style is registered: lets Measure skip the whole feature at zero cost. */
|
|
33
|
+
static get IsEmpty(): boolean;
|
|
34
|
+
/** C# InvalidateStylesCache: drop the per-type resolution after the registry changed. */
|
|
35
|
+
static InvalidateStylesCache(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Setters that apply to a control class: the exact-type style plus every ApplyToDerivedTypes style of a base class,
|
|
38
|
+
* furthest base first so a nearer style overrides it, exact type last (C# sorts by inheritance distance).
|
|
39
|
+
*/
|
|
40
|
+
private static For;
|
|
41
|
+
/** The values a freshly constructed control of this class carries, for the properties a style touches. */
|
|
42
|
+
private static SnapshotDefaults;
|
|
43
|
+
/**
|
|
44
|
+
* C# ApplyInitialStyles: applies the registered defaults to one control. `atConstruction` is true when nothing has
|
|
45
|
+
* touched the control yet (the reconciler calls it between `new` and the JSX props), so every setter applies and the
|
|
46
|
+
* pre-style values are kept as this class's defaults; a control styled later only gets the properties that still
|
|
47
|
+
* hold those defaults, which is how an explicit assignment wins — the C# ExplicitPropertiesSet rule without
|
|
48
|
+
* property accessors.
|
|
49
|
+
*/
|
|
50
|
+
static Apply(control: SkiaControl, atConstruction: boolean): void;
|
|
51
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Mirrors DrawnUi.Net `IStylesCollection` / `StylesCollection`: the startup registry, static like the C# one. */
|
|
2
|
+
export class StylesCollection {
|
|
3
|
+
/** Every style registered through ConfigureStyles, in registration order (C# StylesCollection.Styles). */
|
|
4
|
+
static Styles = [];
|
|
5
|
+
AddStyle(style) {
|
|
6
|
+
StylesCollection.Styles.push(style);
|
|
7
|
+
SkiaStyles.InvalidateStylesCache();
|
|
8
|
+
return this;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Applies registered styles to controls. Port of the C# `SkiaControl` styles partial
|
|
13
|
+
* (SharedNet/Draw/SkiaControl.NetShared.cs) with one difference forced by the language: C# knows which properties the
|
|
14
|
+
* app set explicitly (BindableProperty + ExplicitPropertiesSet) and skips those; here a property counts as "not set by
|
|
15
|
+
* the app" while it still equals the value the control's own constructor left, captured once per class.
|
|
16
|
+
*/
|
|
17
|
+
export class SkiaStyles {
|
|
18
|
+
static resolved = new Map();
|
|
19
|
+
static defaults = new Map();
|
|
20
|
+
/** True while no style is registered: lets Measure skip the whole feature at zero cost. */
|
|
21
|
+
static get IsEmpty() { return StylesCollection.Styles.length === 0; }
|
|
22
|
+
/** C# InvalidateStylesCache: drop the per-type resolution after the registry changed. */
|
|
23
|
+
static InvalidateStylesCache() { SkiaStyles.resolved.clear(); SkiaStyles.defaults.clear(); }
|
|
24
|
+
/**
|
|
25
|
+
* Setters that apply to a control class: the exact-type style plus every ApplyToDerivedTypes style of a base class,
|
|
26
|
+
* furthest base first so a nearer style overrides it, exact type last (C# sorts by inheritance distance).
|
|
27
|
+
*/
|
|
28
|
+
static For(type) {
|
|
29
|
+
let hit = SkiaStyles.resolved.get(type);
|
|
30
|
+
if (hit)
|
|
31
|
+
return hit;
|
|
32
|
+
const inherited = [];
|
|
33
|
+
let exact;
|
|
34
|
+
for (const style of StylesCollection.Styles) {
|
|
35
|
+
if (style.TargetType === type) {
|
|
36
|
+
exact = style;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!style.ApplyToDerivedTypes)
|
|
40
|
+
continue;
|
|
41
|
+
let distance = 0;
|
|
42
|
+
for (let base = Object.getPrototypeOf(type); base; base = Object.getPrototypeOf(base)) {
|
|
43
|
+
distance++;
|
|
44
|
+
if (base === style.TargetType) {
|
|
45
|
+
inherited.push({ Distance: distance, Style: style });
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
inherited.sort((a, b) => b.Distance - a.Distance);
|
|
51
|
+
const setters = {};
|
|
52
|
+
for (const i of inherited)
|
|
53
|
+
Object.assign(setters, i.Style.Setters);
|
|
54
|
+
if (exact)
|
|
55
|
+
Object.assign(setters, exact.Setters);
|
|
56
|
+
hit = { Setters: setters, Empty: Object.keys(setters).length === 0 };
|
|
57
|
+
SkiaStyles.resolved.set(type, hit);
|
|
58
|
+
return hit;
|
|
59
|
+
}
|
|
60
|
+
/** The values a freshly constructed control of this class carries, for the properties a style touches. */
|
|
61
|
+
static SnapshotDefaults(type, sample, keys) {
|
|
62
|
+
if (SkiaStyles.defaults.has(type))
|
|
63
|
+
return;
|
|
64
|
+
const known = {};
|
|
65
|
+
for (const key of keys)
|
|
66
|
+
known[key] = sample[key];
|
|
67
|
+
SkiaStyles.defaults.set(type, known);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* C# ApplyInitialStyles: applies the registered defaults to one control. `atConstruction` is true when nothing has
|
|
71
|
+
* touched the control yet (the reconciler calls it between `new` and the JSX props), so every setter applies and the
|
|
72
|
+
* pre-style values are kept as this class's defaults; a control styled later only gets the properties that still
|
|
73
|
+
* hold those defaults, which is how an explicit assignment wins — the C# ExplicitPropertiesSet rule without
|
|
74
|
+
* property accessors.
|
|
75
|
+
*/
|
|
76
|
+
static Apply(control, atConstruction) {
|
|
77
|
+
const type = control.constructor;
|
|
78
|
+
const resolved = SkiaStyles.For(type);
|
|
79
|
+
if (resolved.Empty)
|
|
80
|
+
return;
|
|
81
|
+
const keys = Object.keys(resolved.Setters);
|
|
82
|
+
const target = control;
|
|
83
|
+
if (atConstruction)
|
|
84
|
+
SkiaStyles.SnapshotDefaults(type, control, keys);
|
|
85
|
+
const defaults = atConstruction ? undefined : SkiaStyles.defaults.get(type);
|
|
86
|
+
for (const key of keys) {
|
|
87
|
+
// no snapshot for this class (nothing of it ever went through the reconciler): apply as a plain default
|
|
88
|
+
if (!defaults || Object.is(target[key], defaults[key]))
|
|
89
|
+
target[key] = resolved.Setters[key];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/dist/core/Super.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Thickness } from "./Types";
|
|
2
|
+
import { StylesCollection } from "./Styles";
|
|
2
3
|
import type { CanvasKit, Font, Typeface } from "canvaskit-wasm";
|
|
3
4
|
/** Mirrors DrawnUi.Net IFontCollection: fonts.AddFont(source, alias[, weight]), plus the Blazor-head AddSymbols/AddEmojis. */
|
|
4
5
|
export declare class FontCollection {
|
|
@@ -16,10 +17,16 @@ export declare class FontCollection {
|
|
|
16
17
|
/** Registers a face under an alias; weight 100..900 lets FontWeight / FontAttributes=Bold pick the right file. */
|
|
17
18
|
AddFont(source: string, alias: string, weight?: number): FontCollection;
|
|
18
19
|
}
|
|
19
|
-
/** Mirrors DrawnUi.Net DrawnUiBuilder: Super.UseDrawnUi().ConfigureFonts(...).BuildAsync(). */
|
|
20
|
+
/** Mirrors DrawnUi.Net DrawnUiBuilder: Super.UseDrawnUi().ConfigureFonts(...).ConfigureStyles(...).BuildAsync(). */
|
|
20
21
|
export declare class DrawnUiBuilder {
|
|
21
22
|
private readonly fonts;
|
|
22
23
|
ConfigureFonts(configure: (fonts: FontCollection) => void): DrawnUiBuilder;
|
|
24
|
+
/**
|
|
25
|
+
* Mirrors DrawnUi.Net ConfigureStyles: property defaults per control type, applied to every control unless the app
|
|
26
|
+
* sets that property itself. The usual one, same as the .NET Blazor / Fiddle hosts:
|
|
27
|
+
* `styles.AddStyle({ TargetType: SkiaLabel, ApplyToDerivedTypes: true, Setters: { FontFamily: "FontText" } })`.
|
|
28
|
+
*/
|
|
29
|
+
ConfigureStyles(configure: (styles: StylesCollection) => void): DrawnUiBuilder;
|
|
23
30
|
/** Loads CanvasKit + registered fonts. Must complete before the first Canvas is created. */
|
|
24
31
|
BuildAsync(): Promise<void>;
|
|
25
32
|
}
|
|
@@ -39,10 +46,19 @@ export declare class Super {
|
|
|
39
46
|
static readonly Fonts: Map<string, Map<number, Typeface>>;
|
|
40
47
|
/** First registered font, or CanvasKit's built-in one. */
|
|
41
48
|
static DefaultTypeface?: Typeface;
|
|
49
|
+
/** CanvasKit's built-in face: what an empty FontFamily resolves to, like C# SKTypeface.CreateDefault(). */
|
|
50
|
+
static SkiaDefaultTypeface?: Typeface;
|
|
42
51
|
private static readonly fontCache;
|
|
43
52
|
static UseDrawnUi(): DrawnUiBuilder;
|
|
44
53
|
/** Master switch: false makes every control render uncached (DrawnUi Super.CacheEnabled). */
|
|
45
54
|
static CacheEnabled: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Address every engine loader fetches a source from (images, sprites, fonts, SVG, GIF, Lottie, shaders); caches
|
|
57
|
+
* stay keyed by the source itself. Web-only, no C# counterpart. Default: a file listed in
|
|
58
|
+
* `globalThis.DrawnUiAssetStamps` (written into index.html by the `drawnUiAssetStamps()` Vite plugin) gets
|
|
59
|
+
* `?v=<content hash>`, so a browser never keeps an old copy of a changed file. Replace it to map sources elsewhere.
|
|
60
|
+
*/
|
|
61
|
+
static ResolveAssetUrl: (source: string) => string;
|
|
46
62
|
private static readonly colorCache;
|
|
47
63
|
/**
|
|
48
64
|
* Color string -> CanvasKit color. Hex follows the MAUI/DrawnUi convention: #RGB, #ARGB, #RRGGBB, #AARRGGBB
|
package/dist/core/Super.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Thickness } from "./Types";
|
|
2
|
+
import { StylesCollection } from "./Styles";
|
|
2
3
|
// the "full" build: same API plus Skottie (SkiaLottie) and the paragraph module; +0.9 MB raw over the default build
|
|
3
4
|
import CanvasKitInit from "canvaskit-wasm/bin/full/canvaskit.js";
|
|
4
5
|
import wasmUrl from "canvaskit-wasm/bin/full/canvaskit.wasm?url";
|
|
@@ -22,13 +23,22 @@ export class FontCollection {
|
|
|
22
23
|
return this;
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
|
-
/** Mirrors DrawnUi.Net DrawnUiBuilder: Super.UseDrawnUi().ConfigureFonts(...).BuildAsync(). */
|
|
26
|
+
/** Mirrors DrawnUi.Net DrawnUiBuilder: Super.UseDrawnUi().ConfigureFonts(...).ConfigureStyles(...).BuildAsync(). */
|
|
26
27
|
export class DrawnUiBuilder {
|
|
27
28
|
fonts = new FontCollection();
|
|
28
29
|
ConfigureFonts(configure) {
|
|
29
30
|
configure(this.fonts);
|
|
30
31
|
return this;
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Mirrors DrawnUi.Net ConfigureStyles: property defaults per control type, applied to every control unless the app
|
|
35
|
+
* sets that property itself. The usual one, same as the .NET Blazor / Fiddle hosts:
|
|
36
|
+
* `styles.AddStyle({ TargetType: SkiaLabel, ApplyToDerivedTypes: true, Setters: { FontFamily: "FontText" } })`.
|
|
37
|
+
*/
|
|
38
|
+
ConfigureStyles(configure) {
|
|
39
|
+
configure(new StylesCollection());
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
32
42
|
/** Loads CanvasKit + registered fonts. Must complete before the first Canvas is created. */
|
|
33
43
|
async BuildAsync() {
|
|
34
44
|
Super.CK = await CanvasKitInit({ locateFile: () => wasmUrl });
|
|
@@ -36,7 +46,7 @@ export class DrawnUiBuilder {
|
|
|
36
46
|
for (const f of this.fonts.Fonts) {
|
|
37
47
|
let face = loaded.get(f.Source);
|
|
38
48
|
if (!face) {
|
|
39
|
-
const data = await (await fetch(f.Source)).arrayBuffer();
|
|
49
|
+
const data = await (await fetch(Super.ResolveAssetUrl(f.Source))).arrayBuffer();
|
|
40
50
|
face = Super.CK.Typeface.MakeFreeTypeFaceFromData(data) ?? undefined;
|
|
41
51
|
if (!face)
|
|
42
52
|
throw new Error(`DrawnUi: cannot load font '${f.Source}'`);
|
|
@@ -61,7 +71,8 @@ export class DrawnUiBuilder {
|
|
|
61
71
|
if (!Super.DefaultFontAlias)
|
|
62
72
|
Super.DefaultFontAlias = f.Alias;
|
|
63
73
|
}
|
|
64
|
-
Super.
|
|
74
|
+
Super.SkiaDefaultTypeface ??= Super.CK.Typeface.GetDefault() ?? undefined;
|
|
75
|
+
Super.DefaultTypeface ??= Super.SkiaDefaultTypeface;
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
78
|
/** Mirrors DrawnUi static Super: global engine state. */
|
|
@@ -105,10 +116,26 @@ export class Super {
|
|
|
105
116
|
static Fonts = new Map();
|
|
106
117
|
/** First registered font, or CanvasKit's built-in one. */
|
|
107
118
|
static DefaultTypeface;
|
|
119
|
+
/** CanvasKit's built-in face: what an empty FontFamily resolves to, like C# SKTypeface.CreateDefault(). */
|
|
120
|
+
static SkiaDefaultTypeface;
|
|
108
121
|
static fontCache = new Map();
|
|
109
122
|
static UseDrawnUi() { return new DrawnUiBuilder(); }
|
|
110
123
|
/** Master switch: false makes every control render uncached (DrawnUi Super.CacheEnabled). */
|
|
111
124
|
static CacheEnabled = true;
|
|
125
|
+
/**
|
|
126
|
+
* Address every engine loader fetches a source from (images, sprites, fonts, SVG, GIF, Lottie, shaders); caches
|
|
127
|
+
* stay keyed by the source itself. Web-only, no C# counterpart. Default: a file listed in
|
|
128
|
+
* `globalThis.DrawnUiAssetStamps` (written into index.html by the `drawnUiAssetStamps()` Vite plugin) gets
|
|
129
|
+
* `?v=<content hash>`, so a browser never keeps an old copy of a changed file. Replace it to map sources elsewhere.
|
|
130
|
+
*/
|
|
131
|
+
static ResolveAssetUrl = (source) => {
|
|
132
|
+
const stamps = globalThis.DrawnUiAssetStamps;
|
|
133
|
+
if (!stamps)
|
|
134
|
+
return source;
|
|
135
|
+
const q = source.indexOf("?");
|
|
136
|
+
const v = stamps[(q < 0 ? source : source.slice(0, q)).replace(/^\.?\//, "")];
|
|
137
|
+
return v ? `${source}${q < 0 ? "?" : "&"}v=${v}` : source;
|
|
138
|
+
};
|
|
112
139
|
static colorCache = new Map();
|
|
113
140
|
/**
|
|
114
141
|
* Color string -> CanvasKit color. Hex follows the MAUI/DrawnUi convention: #RGB, #ARGB, #RRGGBB, #AARRGGBB
|
|
@@ -145,7 +172,11 @@ export class Super {
|
|
|
145
172
|
}
|
|
146
173
|
/** Nearest registered weight of the alias (empty alias = the first registered family); reports the weight actually used. */
|
|
147
174
|
static ResolveTypeface(alias, weight) {
|
|
148
|
-
|
|
175
|
+
// No family: the Skia built-in face, like C# SkiaFontManager.GetFont("") -> SKTypeface.CreateDefault(). An app that
|
|
176
|
+
// wants its own font everywhere registers it as a style default (ConfigureStyles), exactly as the .NET hosts do.
|
|
177
|
+
if (!alias)
|
|
178
|
+
return { Typeface: Super.SkiaDefaultTypeface ?? Super.DefaultTypeface ?? null, Weight: 400 };
|
|
179
|
+
const weights = Super.Fonts.get(alias);
|
|
149
180
|
const target = weight > 0 ? weight : 400;
|
|
150
181
|
if (weights && weights.size > 0) {
|
|
151
182
|
if (weights.has(target))
|
|
@@ -16,6 +16,8 @@ export declare class ViewsAdapter {
|
|
|
16
16
|
Created: number;
|
|
17
17
|
constructor(parent: SkiaControl);
|
|
18
18
|
get PoolSize(): number;
|
|
19
|
+
/** The items views are bound to. */
|
|
20
|
+
get Items(): readonly unknown[];
|
|
19
21
|
get InUseCount(): number;
|
|
20
22
|
/** New template / items / mode: every realized view is dropped (DrawnUi ApplyItemsSource). */
|
|
21
23
|
Initialize(template: (() => SkiaControl) | undefined, items: readonly unknown[], recycling: RecyclingTemplate): void;
|
|
@@ -26,8 +28,11 @@ export declare class ViewsAdapter {
|
|
|
26
28
|
ShiftIndices(by: number, items: readonly unknown[]): void;
|
|
27
29
|
/** The realized view for an index, if any (no creation). */
|
|
28
30
|
GetViewForIndex(index: number): SkiaControl | undefined;
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
+
/**
|
|
32
|
+
* View bound to items[index]: existing, recycled from the pool, or freshly created. `quiet`: bound before it is
|
|
33
|
+
* attached, so the rebind invalidates the view alone and not the layout, which measures or draws it right away.
|
|
34
|
+
*/
|
|
35
|
+
GetOrCreateViewForIndex(index: number, quiet?: boolean): SkiaControl | undefined;
|
|
31
36
|
/** Index left the visible range: recycled views go back to the pool, non-recycled ones stay realized. */
|
|
32
37
|
ReleaseViewAt(index: number): void;
|
|
33
38
|
/** Releases every realized index outside [first, last]. */
|
|
@@ -16,6 +16,8 @@ export class ViewsAdapter {
|
|
|
16
16
|
this.parent = parent;
|
|
17
17
|
}
|
|
18
18
|
get PoolSize() { return this.pool.length; }
|
|
19
|
+
/** The items views are bound to. */
|
|
20
|
+
get Items() { return this.items; }
|
|
19
21
|
get InUseCount() { return this.inUse.size; }
|
|
20
22
|
/** New template / items / mode: every realized view is dropped (DrawnUi ApplyItemsSource). */
|
|
21
23
|
Initialize(template, items, recycling) {
|
|
@@ -52,8 +54,11 @@ export class ViewsAdapter {
|
|
|
52
54
|
}
|
|
53
55
|
/** The realized view for an index, if any (no creation). */
|
|
54
56
|
GetViewForIndex(index) { return this.inUse.get(index); }
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
+
/**
|
|
58
|
+
* View bound to items[index]: existing, recycled from the pool, or freshly created. `quiet`: bound before it is
|
|
59
|
+
* attached, so the rebind invalidates the view alone and not the layout, which measures or draws it right away.
|
|
60
|
+
*/
|
|
61
|
+
GetOrCreateViewForIndex(index, quiet = false) {
|
|
57
62
|
const existing = this.inUse.get(index);
|
|
58
63
|
if (existing)
|
|
59
64
|
return existing;
|
|
@@ -64,9 +69,11 @@ export class ViewsAdapter {
|
|
|
64
69
|
view = this.template();
|
|
65
70
|
this.Created++;
|
|
66
71
|
}
|
|
67
|
-
|
|
72
|
+
if (!quiet)
|
|
73
|
+
view.Parent = this.parent;
|
|
68
74
|
view.ContextIndex = index;
|
|
69
75
|
view.BindingContext = this.items[index];
|
|
76
|
+
view.Parent = this.parent;
|
|
70
77
|
this.inUse.set(index, view);
|
|
71
78
|
return view;
|
|
72
79
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./core/Types";
|
|
2
2
|
export * from "./core/Gestures";
|
|
3
|
+
export * from "./core/Styles";
|
|
3
4
|
export * from "./core/Easing";
|
|
4
5
|
export * from "./core/Animators";
|
|
5
6
|
export * from "./core/ScrollAnimators";
|
|
@@ -8,9 +9,11 @@ export * from "./core/SkiaControl";
|
|
|
8
9
|
export * from "./core/Canvas";
|
|
9
10
|
export * from "./controls/SkiaLayout";
|
|
10
11
|
export * from "./core/Accessibility";
|
|
12
|
+
export * from "./core/Hover";
|
|
11
13
|
export * from "./controls/SkiaLabel";
|
|
12
14
|
export * from "./controls/TextSpan";
|
|
13
15
|
export * from "./controls/SkiaRichLabel";
|
|
16
|
+
export * from "./controls/SkiaLabelFps";
|
|
14
17
|
export * from "./core/ControlStyle";
|
|
15
18
|
export * from "./core/ImageEffects";
|
|
16
19
|
export * from "./controls/SkiaToggle";
|
|
@@ -39,6 +42,7 @@ export * from "./controls/SkiaBackdrop";
|
|
|
39
42
|
export * from "./controls/SkiaEditor";
|
|
40
43
|
export * from "./controls/SkiaSprite";
|
|
41
44
|
export * from "./controls/SkiaSpriteSet";
|
|
45
|
+
export * from "./controls/DrawnGame";
|
|
42
46
|
export * from "./core/KeyboardManager";
|
|
43
47
|
export * from "./controls/AnimatedFramesRenderer";
|
|
44
48
|
export * from "./controls/SkiaLottie";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./core/Types";
|
|
2
2
|
export * from "./core/Gestures";
|
|
3
|
+
export * from "./core/Styles";
|
|
3
4
|
export * from "./core/Easing";
|
|
4
5
|
export * from "./core/Animators";
|
|
5
6
|
export * from "./core/ScrollAnimators";
|
|
@@ -8,9 +9,11 @@ export * from "./core/SkiaControl";
|
|
|
8
9
|
export * from "./core/Canvas";
|
|
9
10
|
export * from "./controls/SkiaLayout";
|
|
10
11
|
export * from "./core/Accessibility";
|
|
12
|
+
export * from "./core/Hover";
|
|
11
13
|
export * from "./controls/SkiaLabel";
|
|
12
14
|
export * from "./controls/TextSpan";
|
|
13
15
|
export * from "./controls/SkiaRichLabel";
|
|
16
|
+
export * from "./controls/SkiaLabelFps";
|
|
14
17
|
export * from "./core/ControlStyle";
|
|
15
18
|
export * from "./core/ImageEffects";
|
|
16
19
|
export * from "./controls/SkiaToggle";
|
|
@@ -39,6 +42,7 @@ export * from "./controls/SkiaBackdrop";
|
|
|
39
42
|
export * from "./controls/SkiaEditor";
|
|
40
43
|
export * from "./controls/SkiaSprite";
|
|
41
44
|
export * from "./controls/SkiaSpriteSet";
|
|
45
|
+
export * from "./controls/DrawnGame";
|
|
42
46
|
export * from "./core/KeyboardManager";
|
|
43
47
|
export * from "./controls/AnimatedFramesRenderer";
|
|
44
48
|
export * from "./controls/SkiaLottie";
|