winui-svelte 0.0.2 → 0.0.4
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/API.md +120 -6
- package/README.md +70 -90
- package/dist/bindings/.dynwinrt-managed +1 -1
- package/dist/components/convert.d.ts +3 -3
- package/dist/components/convert.d.ts.map +1 -1
- package/dist/components/fluent-glyph.d.ts +4 -0
- package/dist/components/fluent-glyph.d.ts.map +1 -1
- package/dist/components/generated/controls/FontIcon.svelte.d.ts +1 -1
- package/dist/components/generated/controls/FontIconSource.svelte.d.ts +1 -1
- package/dist/components/generated/controls/UIElement.svelte.d.ts +1 -1
- package/dist/components/index.d.ts +4 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/css/runtime/resources.d.ts +1 -1
- package/dist/dev/dev-window.d.ts +23 -0
- package/dist/dev/dev-window.d.ts.map +1 -0
- package/dist/dev/dev-window.js +42 -0
- package/dist/dev/dev-window.js.map +1 -0
- package/dist/dev/index.d.ts +3 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +2 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/start-dev.d.ts +47 -0
- package/dist/dev/start-dev.d.ts.map +1 -0
- package/dist/dev/start-dev.js +81 -0
- package/dist/dev/start-dev.js.map +1 -0
- package/dist/enums.d.ts +2 -0
- package/dist/enums.d.ts.map +1 -1
- package/dist/enums.js +2 -0
- package/dist/enums.js.map +1 -1
- package/dist/media/media-player.d.ts +8 -0
- package/dist/media/media-player.d.ts.map +1 -1
- package/dist/media/media-player.js +15 -0
- package/dist/media/media-player.js.map +1 -1
- package/dist/web-apis/window-geometry.d.ts +39 -0
- package/dist/web-apis/window-geometry.d.ts.map +1 -0
- package/dist/web-apis/window-geometry.js +95 -0
- package/dist/web-apis/window-geometry.js.map +1 -0
- package/dist/win2d/Canvas.svelte +1 -0
- package/dist/window/anchor.d.ts +92 -0
- package/dist/window/anchor.d.ts.map +1 -0
- package/dist/window/anchor.js +100 -0
- package/dist/window/anchor.js.map +1 -0
- package/dist/window/backdrop.d.ts +4 -1
- package/dist/window/backdrop.d.ts.map +1 -1
- package/dist/window/backdrop.js +10 -2
- package/dist/window/backdrop.js.map +1 -1
- package/dist/window/create-window.d.ts +1 -1
- package/dist/window/create-window.d.ts.map +1 -1
- package/dist/window/create-window.js +3 -1
- package/dist/window/create-window.js.map +1 -1
- package/dist/window/css-pixels.d.ts +14 -0
- package/dist/window/css-pixels.d.ts.map +1 -0
- package/dist/window/css-pixels.js +12 -0
- package/dist/window/css-pixels.js.map +1 -0
- package/dist/window/dock.d.ts +51 -0
- package/dist/window/dock.d.ts.map +1 -0
- package/dist/window/dock.js +69 -0
- package/dist/window/dock.js.map +1 -0
- package/dist/window/index.d.ts +4 -0
- package/dist/window/index.d.ts.map +1 -1
- package/dist/window/index.js +2 -0
- package/dist/window/index.js.map +1 -1
- package/dist/window/native.d.ts +2 -0
- package/dist/window/native.d.ts.map +1 -1
- package/dist/window/native.js +10 -0
- package/dist/window/native.js.map +1 -1
- package/dist/window/transparent-backdrop.d.ts +11 -0
- package/dist/window/transparent-backdrop.d.ts.map +1 -0
- package/dist/window/transparent-backdrop.js +35 -0
- package/dist/window/transparent-backdrop.js.map +1 -0
- package/dist/window/window-handle.d.ts +17 -0
- package/dist/window/window-handle.d.ts.map +1 -1
- package/dist/window/window-handle.js +23 -0
- package/dist/window/window-handle.js.map +1 -1
- package/dist/window/window-host.svelte.d.ts +17 -12
- package/dist/window/window-host.svelte.d.ts.map +1 -1
- package/dist/window/window-host.svelte.js +208 -23
- package/dist/window/window-host.svelte.js.map +1 -1
- package/dist/winui.d.ts +5 -0
- package/dist/winui.d.ts.map +1 -1
- package/dist/winui.js +5 -0
- package/dist/winui.js.map +1 -1
- package/package.json +25 -7
- package/src/components/convert.ts +3 -3
- package/src/components/fluent-glyph.ts +6 -0
- package/src/components/generated/controls/FontIcon.svelte.ts +1 -1
- package/src/components/generated/controls/FontIconSource.svelte.ts +1 -1
- package/src/components/generated/controls/UIElement.svelte.ts +1 -1
- package/src/components/index.ts +13 -2
- package/src/dev/dev-window.ts +63 -0
- package/src/dev/index.ts +2 -0
- package/src/dev/start-dev.ts +120 -0
- package/src/enums.ts +2 -0
- package/src/media/media-player.ts +17 -0
- package/src/web-apis/window-geometry.ts +106 -0
- package/src/window/anchor.ts +156 -0
- package/src/window/backdrop.ts +11 -2
- package/src/window/create-window.ts +5 -1
- package/src/window/css-pixels.ts +18 -0
- package/src/window/dock.ts +99 -0
- package/src/window/index.ts +4 -0
- package/src/window/native.ts +12 -0
- package/src/window/transparent-backdrop.ts +38 -0
- package/src/window/window-handle.ts +26 -0
- package/src/window/window-host.svelte.ts +256 -36
- package/src/winui.ts +5 -0
- package/web-types.json +3203 -1507
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SizeToContent, WindowAnchor, WindowBounds, WindowSize } from "./anchor.ts";
|
|
2
|
+
import { fittedBounds, SizeToContent as SizeToContentKind, WindowAnchor as WindowAnchorKind } from "./anchor.ts";
|
|
1
3
|
import {
|
|
2
4
|
applyCaptionButtonColors,
|
|
3
5
|
applyPresentation,
|
|
@@ -13,6 +15,7 @@ import { isBackgroundRun } from "./background-mode.ts";
|
|
|
13
15
|
import { backgroundPlacement, keepInBackground } from "./background.ts";
|
|
14
16
|
import type { CaptionButtonColors, CaptionButtonProperty, TitleBarHeight, WindowRegion } from "./chrome.ts";
|
|
15
17
|
import { TitleBarHeight as TitleBarHeightKind, WindowPresentation, WindowTheme } from "./chrome.ts";
|
|
18
|
+
import { toDevicePixels } from "./css-pixels.ts";
|
|
16
19
|
import {
|
|
17
20
|
clearWindowClip,
|
|
18
21
|
clipToRoundedRectangle,
|
|
@@ -28,22 +31,20 @@ import type { FrameworkElement } from "#src/winui.js";
|
|
|
28
31
|
import {
|
|
29
32
|
DisplayArea,
|
|
30
33
|
DisplayAreaFallback,
|
|
34
|
+
Grid,
|
|
31
35
|
NonClientRegionKind,
|
|
36
|
+
ScrollBarVisibility,
|
|
37
|
+
ScrollMode,
|
|
38
|
+
ScrollViewer,
|
|
32
39
|
Window,
|
|
33
40
|
WindowActivationState
|
|
34
41
|
} from "#src/winui.js";
|
|
35
42
|
|
|
43
|
+
export type { WindowBounds, WindowSize } from "./anchor.ts";
|
|
44
|
+
|
|
36
45
|
// What <Window> (components/hand-written/Window.svelte) does: a native window
|
|
37
46
|
// around the component's content, kept in line with its props.
|
|
38
47
|
|
|
39
|
-
/** The window's position and size, in device pixels, as AppWindow has them. */
|
|
40
|
-
export interface WindowBounds {
|
|
41
|
-
x: number;
|
|
42
|
-
y: number;
|
|
43
|
-
width: number;
|
|
44
|
-
height: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
48
|
/**
|
|
48
49
|
* Where the window opens, in device pixels; a size left out is the width or
|
|
49
50
|
* height prop's.
|
|
@@ -110,6 +111,23 @@ export interface WindowProps {
|
|
|
110
111
|
width?: number;
|
|
111
112
|
height?: number;
|
|
112
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Which sides of the window follow its content: the content is measured
|
|
116
|
+
* after every layout pass and the window is resized to it (frame included,
|
|
117
|
+
* within the size limits) with one `AppWindow.MoveAndResize`, so a growing
|
|
118
|
+
* content never flickers. A side that follows the content ignores the
|
|
119
|
+
* `width` or `height` prop and the user's resizing. Windowed presentation
|
|
120
|
+
* only; the default is `none`.
|
|
121
|
+
*/
|
|
122
|
+
sizeToContent?: SizeToContent | undefined;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The corner that stays where it is when the window is sized to its content
|
|
126
|
+
* (and when the scale changes the size): a window docked bottom-right whose
|
|
127
|
+
* content grows taller grows upward. The default is `topLeft`.
|
|
128
|
+
*/
|
|
129
|
+
anchor?: WindowAnchor | undefined;
|
|
130
|
+
|
|
113
131
|
/** The least the user can resize to, in device-independent pixels. */
|
|
114
132
|
minWidth?: number;
|
|
115
133
|
minHeight?: number;
|
|
@@ -228,12 +246,6 @@ export interface WindowProps {
|
|
|
228
246
|
onboundschanged?: (bounds: WindowBounds) => void;
|
|
229
247
|
}
|
|
230
248
|
|
|
231
|
-
/** A size in device pixels. */
|
|
232
|
-
export interface WindowSize {
|
|
233
|
-
width: number;
|
|
234
|
-
height: number;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
249
|
/** What `attachWindow` opens a window around, and how. */
|
|
238
250
|
export interface AttachOptions {
|
|
239
251
|
content: FrameworkElement;
|
|
@@ -244,11 +256,40 @@ export interface AttachOptions {
|
|
|
244
256
|
size?: WindowSize | undefined;
|
|
245
257
|
}
|
|
246
258
|
|
|
247
|
-
|
|
248
|
-
|
|
259
|
+
// A side of the window in device pixels: the prop's, unless the prop is left
|
|
260
|
+
// out or the content sets that side.
|
|
261
|
+
function sideOf({ value, current, isFitted, scale }: {
|
|
262
|
+
value: number | undefined;
|
|
263
|
+
current: number;
|
|
264
|
+
isFitted: boolean;
|
|
249
265
|
scale: number;
|
|
250
266
|
}) {
|
|
251
|
-
|
|
267
|
+
const isKept = value === undefined || isFitted;
|
|
268
|
+
if (isKept) {
|
|
269
|
+
return current;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return toDevicePixels({
|
|
273
|
+
value,
|
|
274
|
+
scale
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// A size limit in device pixels; `fallback` when the app names none.
|
|
279
|
+
function limitOf({ value, fallback, scale }: {
|
|
280
|
+
value: number | undefined;
|
|
281
|
+
fallback: number;
|
|
282
|
+
scale: number;
|
|
283
|
+
}) {
|
|
284
|
+
const isNamed = value !== undefined;
|
|
285
|
+
if (!isNamed) {
|
|
286
|
+
return fallback;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return toDevicePixels({
|
|
290
|
+
value,
|
|
291
|
+
scale
|
|
292
|
+
});
|
|
252
293
|
}
|
|
253
294
|
|
|
254
295
|
// A prop the app left out is undefined; a guard names the test.
|
|
@@ -256,6 +297,11 @@ function isGiven<Value>(value: Value | undefined): value is Value {
|
|
|
256
297
|
return value !== undefined;
|
|
257
298
|
}
|
|
258
299
|
|
|
300
|
+
// Windows whose component is gone while the application goes on, waiting one
|
|
301
|
+
// tick for the component that replaces it (a hot update re-creates it) to take
|
|
302
|
+
// the same window over; a window nobody takes is closed.
|
|
303
|
+
const orphans: Window[] = [];
|
|
304
|
+
|
|
259
305
|
class WindowHost {
|
|
260
306
|
readonly handle: WindowHandle;
|
|
261
307
|
private readonly props: WindowProps;
|
|
@@ -276,13 +322,16 @@ class WindowHost {
|
|
|
276
322
|
private isClipApplied = false;
|
|
277
323
|
private isTopApplied = false;
|
|
278
324
|
private hasShown = false;
|
|
325
|
+
private isFitting = false;
|
|
326
|
+
private scroller: ScrollViewer | null = null;
|
|
327
|
+
private readonly isTakenOver: boolean;
|
|
279
328
|
private readonly openSize: WindowSize | undefined;
|
|
280
329
|
private appliedSize: {
|
|
281
330
|
width: number | undefined;
|
|
282
331
|
height: number | undefined;
|
|
283
332
|
};
|
|
284
333
|
|
|
285
|
-
constructor({ content, props, titleBar, size }: AttachOptions) {
|
|
334
|
+
constructor({ content, props, titleBar, size }: AttachOptions, orphan: Window | undefined) {
|
|
286
335
|
this.props = props;
|
|
287
336
|
this.openSize = size;
|
|
288
337
|
this.content = content;
|
|
@@ -297,15 +346,18 @@ class WindowHost {
|
|
|
297
346
|
joinAppUserModel(appUserModelId);
|
|
298
347
|
}
|
|
299
348
|
|
|
300
|
-
const window = new Window();
|
|
349
|
+
const window = orphan ?? new Window();
|
|
350
|
+
this.isTakenOver = orphan !== undefined;
|
|
301
351
|
this.handle = new WindowHandle(window);
|
|
302
352
|
|
|
303
|
-
|
|
353
|
+
const isNewBackgroundWindow = isBackgroundRun() && !this.isTakenOver;
|
|
354
|
+
if (isNewBackgroundWindow) {
|
|
304
355
|
keepInBackground(this.handle.appWindow.id.value);
|
|
305
356
|
}
|
|
306
357
|
|
|
307
358
|
this.handle.guardClose(() => this.isCloseRefused());
|
|
308
359
|
window.content = content;
|
|
360
|
+
this.keepInLine(() => this.syncContainer());
|
|
309
361
|
this.keepInLine(() => this.syncText());
|
|
310
362
|
this.keepInLine(() => this.syncBackdrop());
|
|
311
363
|
this.keepInLine(() => this.syncTheme());
|
|
@@ -316,8 +368,13 @@ class WindowHost {
|
|
|
316
368
|
this.keepInLine(() => this.syncLimits());
|
|
317
369
|
this.keepInLine(() => this.syncFrame());
|
|
318
370
|
this.keepInLine(() => this.syncShape());
|
|
319
|
-
|
|
371
|
+
|
|
372
|
+
if (!this.isTakenOver) {
|
|
373
|
+
this.placeFirst();
|
|
374
|
+
}
|
|
375
|
+
|
|
320
376
|
$effect(() => this.syncSize());
|
|
377
|
+
$effect(() => this.fitToContent());
|
|
321
378
|
this.syncOwner();
|
|
322
379
|
this.listen();
|
|
323
380
|
this.watchScale();
|
|
@@ -325,7 +382,14 @@ class WindowHost {
|
|
|
325
382
|
$effect(() => this.syncVisibility());
|
|
326
383
|
}
|
|
327
384
|
|
|
328
|
-
|
|
385
|
+
/**
|
|
386
|
+
* Ends the host. `isClosedLater`: its component is going while the
|
|
387
|
+
* application goes on (a hot update re-creates it). The window is not closed
|
|
388
|
+
* but offered for one tick to the component that replaces it, which takes it
|
|
389
|
+
* over (no relaunch), and closed if nobody does. Closing it during the
|
|
390
|
+
* component's teardown is no option: WinUI aborts Window.Close (E_ABORT).
|
|
391
|
+
*/
|
|
392
|
+
dispose(isClosedLater: boolean) {
|
|
329
393
|
this.releaseBackdrop?.();
|
|
330
394
|
this.releaseBackdrop = null;
|
|
331
395
|
for (const unsubscribe of this.unsubscribe.splice(0)) {
|
|
@@ -333,9 +397,26 @@ class WindowHost {
|
|
|
333
397
|
}
|
|
334
398
|
|
|
335
399
|
this.handle.guardClose(() => false);
|
|
400
|
+
|
|
401
|
+
if (isClosedLater) {
|
|
402
|
+
const { window } = this.handle;
|
|
403
|
+
orphans.push(window);
|
|
404
|
+
setTimeout(() => this.closeIfOrphan(window), 0);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
336
408
|
this.handle.close();
|
|
337
409
|
}
|
|
338
410
|
|
|
411
|
+
private closeIfOrphan(window: Window) {
|
|
412
|
+
const index = orphans.indexOf(window);
|
|
413
|
+
const isOrphan = index !== -1;
|
|
414
|
+
if (isOrphan) {
|
|
415
|
+
orphans.splice(index, 1);
|
|
416
|
+
this.handle.close();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
339
420
|
// Applied now, so the window opens as it is meant to, and again whenever
|
|
340
421
|
// what `sync` reads changes.
|
|
341
422
|
private keepInLine(sync: () => void) {
|
|
@@ -343,6 +424,51 @@ class WindowHost {
|
|
|
343
424
|
$effect(sync);
|
|
344
425
|
}
|
|
345
426
|
|
|
427
|
+
// A measure offers an element the space it has and clamps what it asks for
|
|
428
|
+
// to that, so a root as large as the window could never ask for more or
|
|
429
|
+
// less than the window is. Inside a ScrollViewer that may scroll along a
|
|
430
|
+
// side the content sets, the root is offered all the room there (the
|
|
431
|
+
// scroll bars stay hidden), and what it asks for is what it needs.
|
|
432
|
+
private syncContainer() {
|
|
433
|
+
const { isWidthFitted, isHeightFitted } = this.fittedSides;
|
|
434
|
+
const isAnySideFitted = isWidthFitted || isHeightFitted;
|
|
435
|
+
const isFitted = isAnySideFitted && this.isWindowed;
|
|
436
|
+
const { window } = this.handle;
|
|
437
|
+
if (!isFitted) {
|
|
438
|
+
this.uncontain();
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const scroller = this.scroller ?? new ScrollViewer();
|
|
443
|
+
scroller.horizontalScrollBarVisibility = isWidthFitted ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Disabled;
|
|
444
|
+
scroller.horizontalScrollMode = isWidthFitted ? ScrollMode.Enabled : ScrollMode.Disabled;
|
|
445
|
+
scroller.verticalScrollBarVisibility = isHeightFitted ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Disabled;
|
|
446
|
+
scroller.verticalScrollMode = isHeightFitted ? ScrollMode.Enabled : ScrollMode.Disabled;
|
|
447
|
+
const isContained = this.scroller !== null;
|
|
448
|
+
if (isContained) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
window.content = new Grid();
|
|
453
|
+
scroller.content = this.content;
|
|
454
|
+
window.content = scroller;
|
|
455
|
+
this.scroller = scroller;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private uncontain() {
|
|
459
|
+
const { scroller } = this;
|
|
460
|
+
const isContained = scroller !== null;
|
|
461
|
+
if (!isContained) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const { window } = this.handle;
|
|
466
|
+
window.content = new Grid();
|
|
467
|
+
scroller.content = null;
|
|
468
|
+
window.content = this.content;
|
|
469
|
+
this.scroller = null;
|
|
470
|
+
}
|
|
471
|
+
|
|
346
472
|
private syncText() {
|
|
347
473
|
const { window } = this.handle;
|
|
348
474
|
window.title = this.props.title ?? "";
|
|
@@ -504,28 +630,28 @@ class WindowHost {
|
|
|
504
630
|
}
|
|
505
631
|
|
|
506
632
|
if (isGiven(minWidth)) {
|
|
507
|
-
presenter.preferredMinimumWidth =
|
|
633
|
+
presenter.preferredMinimumWidth = toDevicePixels({
|
|
508
634
|
value: minWidth,
|
|
509
635
|
scale
|
|
510
636
|
});
|
|
511
637
|
}
|
|
512
638
|
|
|
513
639
|
if (isGiven(minHeight)) {
|
|
514
|
-
presenter.preferredMinimumHeight =
|
|
640
|
+
presenter.preferredMinimumHeight = toDevicePixels({
|
|
515
641
|
value: minHeight,
|
|
516
642
|
scale
|
|
517
643
|
});
|
|
518
644
|
}
|
|
519
645
|
|
|
520
646
|
if (isGiven(maxWidth)) {
|
|
521
|
-
presenter.preferredMaximumWidth =
|
|
647
|
+
presenter.preferredMaximumWidth = toDevicePixels({
|
|
522
648
|
value: maxWidth,
|
|
523
649
|
scale
|
|
524
650
|
});
|
|
525
651
|
}
|
|
526
652
|
|
|
527
653
|
if (isGiven(maxHeight)) {
|
|
528
|
-
presenter.preferredMaximumHeight =
|
|
654
|
+
presenter.preferredMaximumHeight = toDevicePixels({
|
|
529
655
|
value: maxHeight,
|
|
530
656
|
scale
|
|
531
657
|
});
|
|
@@ -629,7 +755,7 @@ class WindowHost {
|
|
|
629
755
|
hwnd,
|
|
630
756
|
width,
|
|
631
757
|
height,
|
|
632
|
-
radius:
|
|
758
|
+
radius: toDevicePixels({
|
|
633
759
|
value: cornerRadius,
|
|
634
760
|
scale: this.handle.scale
|
|
635
761
|
})
|
|
@@ -684,11 +810,11 @@ class WindowHost {
|
|
|
684
810
|
const { scale } = this.handle;
|
|
685
811
|
const current = this.openSize ?? appWindow.size;
|
|
686
812
|
const size = {
|
|
687
|
-
width: props.width === undefined ? current.width :
|
|
813
|
+
width: props.width === undefined ? current.width : toDevicePixels({
|
|
688
814
|
value: props.width,
|
|
689
815
|
scale
|
|
690
816
|
}),
|
|
691
|
-
height: props.height === undefined ? current.height :
|
|
817
|
+
height: props.height === undefined ? current.height : toDevicePixels({
|
|
692
818
|
value: props.height,
|
|
693
819
|
scale
|
|
694
820
|
})
|
|
@@ -733,7 +859,8 @@ class WindowHost {
|
|
|
733
859
|
}
|
|
734
860
|
|
|
735
861
|
// A new width or height resizes the window; the user's own resizing is not
|
|
736
|
-
// undone, since the props did not change.
|
|
862
|
+
// undone, since the props did not change. A side that follows the content
|
|
863
|
+
// (sizeToContent) is the content's to set.
|
|
737
864
|
private syncSize() {
|
|
738
865
|
const { width, height } = this.props;
|
|
739
866
|
const isChanged = width !== this.appliedSize.width || height !== this.appliedSize.height;
|
|
@@ -747,18 +874,108 @@ class WindowHost {
|
|
|
747
874
|
};
|
|
748
875
|
const { appWindow } = this.handle.window;
|
|
749
876
|
const { scale } = this.handle;
|
|
877
|
+
const { isWidthFitted, isHeightFitted } = this.fittedSides;
|
|
750
878
|
appWindow.resize({
|
|
751
|
-
width:
|
|
879
|
+
width: sideOf({
|
|
752
880
|
value: width,
|
|
881
|
+
current: appWindow.size.width,
|
|
882
|
+
isFitted: isWidthFitted,
|
|
753
883
|
scale
|
|
754
884
|
}),
|
|
755
|
-
height:
|
|
885
|
+
height: sideOf({
|
|
756
886
|
value: height,
|
|
887
|
+
current: appWindow.size.height,
|
|
888
|
+
isFitted: isHeightFitted,
|
|
757
889
|
scale
|
|
758
890
|
})
|
|
759
891
|
});
|
|
760
892
|
}
|
|
761
893
|
|
|
894
|
+
private get fittedSides() {
|
|
895
|
+
const mode = this.props.sizeToContent ?? SizeToContentKind.none;
|
|
896
|
+
return {
|
|
897
|
+
isWidthFitted: mode === SizeToContentKind.width || mode === SizeToContentKind.both,
|
|
898
|
+
isHeightFitted: mode === SizeToContentKind.height || mode === SizeToContentKind.both
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Sizes the window to what its content asks for, whenever the prop, the
|
|
903
|
+
// limits, the scale or a layout pass changes it: one MoveAndResize, so the
|
|
904
|
+
// anchor corner never moves between the size and the position.
|
|
905
|
+
private fitToContent() {
|
|
906
|
+
const mode = this.props.sizeToContent ?? SizeToContentKind.none;
|
|
907
|
+
const anchor = this.props.anchor ?? WindowAnchorKind.topLeft;
|
|
908
|
+
const { minWidth, minHeight, maxWidth, maxHeight } = this.props;
|
|
909
|
+
const isIdle = mode === SizeToContentKind.none || !this.isWindowed || this.isFitting;
|
|
910
|
+
if (isIdle) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const { desiredSize } = this.content;
|
|
915
|
+
const isMeasured = desiredSize.width > 0 && desiredSize.height > 0;
|
|
916
|
+
if (!isMeasured) {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
const { appWindow, scale } = this.handle;
|
|
921
|
+
const { size, position, clientSize } = appWindow;
|
|
922
|
+
const frame = {
|
|
923
|
+
width: size.width - clientSize.width,
|
|
924
|
+
height: size.height - clientSize.height
|
|
925
|
+
};
|
|
926
|
+
const target = fittedBounds({
|
|
927
|
+
bounds: {
|
|
928
|
+
...position,
|
|
929
|
+
...size
|
|
930
|
+
},
|
|
931
|
+
desired: {
|
|
932
|
+
width: toDevicePixels({
|
|
933
|
+
value: desiredSize.width,
|
|
934
|
+
scale
|
|
935
|
+
}) + frame.width,
|
|
936
|
+
height: toDevicePixels({
|
|
937
|
+
value: desiredSize.height,
|
|
938
|
+
scale
|
|
939
|
+
}) + frame.height
|
|
940
|
+
},
|
|
941
|
+
mode,
|
|
942
|
+
anchor,
|
|
943
|
+
limits: {
|
|
944
|
+
minWidth: limitOf({
|
|
945
|
+
value: minWidth,
|
|
946
|
+
fallback: 0,
|
|
947
|
+
scale
|
|
948
|
+
}),
|
|
949
|
+
minHeight: limitOf({
|
|
950
|
+
value: minHeight,
|
|
951
|
+
fallback: 0,
|
|
952
|
+
scale
|
|
953
|
+
}),
|
|
954
|
+
maxWidth: limitOf({
|
|
955
|
+
value: maxWidth,
|
|
956
|
+
fallback: Infinity,
|
|
957
|
+
scale
|
|
958
|
+
}),
|
|
959
|
+
maxHeight: limitOf({
|
|
960
|
+
value: maxHeight,
|
|
961
|
+
fallback: Infinity,
|
|
962
|
+
scale
|
|
963
|
+
})
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
const hasTarget = target !== null;
|
|
967
|
+
if (!hasTarget) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
this.isFitting = true;
|
|
972
|
+
try {
|
|
973
|
+
appWindow.moveAndResize(target);
|
|
974
|
+
} finally {
|
|
975
|
+
this.isFitting = false;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
762
979
|
private isCloseRefused() {
|
|
763
980
|
return this.props.onclosing?.() === true;
|
|
764
981
|
}
|
|
@@ -779,6 +996,7 @@ class WindowHost {
|
|
|
779
996
|
this.releaseBackdrop = null;
|
|
780
997
|
this.props.onclosed?.();
|
|
781
998
|
}),
|
|
999
|
+
this.content.onLayoutUpdated(() => this.fitToContent()),
|
|
782
1000
|
window.appWindow.onChanged((_sender, event) => {
|
|
783
1001
|
const isMoved = event.didPositionChange || event.didSizeChange;
|
|
784
1002
|
if (isMoved) {
|
|
@@ -800,6 +1018,7 @@ class WindowHost {
|
|
|
800
1018
|
this.syncLimits();
|
|
801
1019
|
this.syncRegions();
|
|
802
1020
|
this.syncShape();
|
|
1021
|
+
this.fitToContent();
|
|
803
1022
|
this.props.onscalechanged?.(scale);
|
|
804
1023
|
}
|
|
805
1024
|
});
|
|
@@ -824,7 +1043,8 @@ class WindowHost {
|
|
|
824
1043
|
// them (to reopen where the window was) needs them before the user moves it.
|
|
825
1044
|
private show() {
|
|
826
1045
|
const isHidden = this.props.isHidden === true;
|
|
827
|
-
|
|
1046
|
+
const isToShow = !isHidden && !this.isTakenOver;
|
|
1047
|
+
if (isToShow) {
|
|
828
1048
|
this.showWindow();
|
|
829
1049
|
}
|
|
830
1050
|
|
|
@@ -850,14 +1070,14 @@ class WindowHost {
|
|
|
850
1070
|
* where an effect can be created (a component, or an effect root).
|
|
851
1071
|
*/
|
|
852
1072
|
export function attachWindow(options: AttachOptions) {
|
|
853
|
-
const host = new WindowHost(options);
|
|
854
|
-
const forget = onTeardown(() => host.dispose());
|
|
1073
|
+
const host = new WindowHost(options, orphans.shift());
|
|
1074
|
+
const forget = onTeardown(() => host.dispose(false));
|
|
855
1075
|
host.handle.window.onClosed(forget);
|
|
856
1076
|
return {
|
|
857
1077
|
handle: host.handle,
|
|
858
1078
|
dispose() {
|
|
859
1079
|
forget();
|
|
860
|
-
host.dispose();
|
|
1080
|
+
host.dispose(true);
|
|
861
1081
|
}
|
|
862
1082
|
};
|
|
863
1083
|
}
|
package/src/winui.ts
CHANGED
|
@@ -8,6 +8,9 @@ export { Application } from "#winui/microsoft/ui/xaml/Application";
|
|
|
8
8
|
export { ColumnDefinition } from "#winui/microsoft/ui/xaml/controls/ColumnDefinition";
|
|
9
9
|
export { Grid } from "#winui/microsoft/ui/xaml/controls/Grid";
|
|
10
10
|
export { RowDefinition } from "#winui/microsoft/ui/xaml/controls/RowDefinition";
|
|
11
|
+
export { ScrollBarVisibility } from "#winui/microsoft/ui/xaml/controls/ScrollBarVisibility";
|
|
12
|
+
export { ScrollMode } from "#winui/microsoft/ui/xaml/controls/ScrollMode";
|
|
13
|
+
export { ScrollViewer } from "#winui/microsoft/ui/xaml/controls/ScrollViewer";
|
|
11
14
|
export { Run } from "#winui/microsoft/ui/xaml/documents/Run";
|
|
12
15
|
export { DispatcherQueue } from "#winui/microsoft/ui/dispatching/DispatcherQueue";
|
|
13
16
|
export { DesktopAcrylicBackdrop } from "#winui/microsoft/ui/xaml/media/DesktopAcrylicBackdrop";
|
|
@@ -18,6 +21,8 @@ export { DesktopAcrylicKind } from "#winui/microsoft/ui/composition/system-backd
|
|
|
18
21
|
export { SystemBackdropConfiguration } from "#winui/microsoft/ui/composition/system-backdrops/SystemBackdropConfiguration";
|
|
19
22
|
export { SystemBackdropTheme } from "#winui/microsoft/ui/composition/system-backdrops/SystemBackdropTheme";
|
|
20
23
|
export { ICompositionSupportsSystemBackdrop } from "#winui/microsoft/ui/composition/ICompositionSupportsSystemBackdrop";
|
|
24
|
+
export { Compositor as SystemCompositor } from "#winui/windows/ui/composition/Compositor";
|
|
25
|
+
export { CompositionColorBrush as SystemCompositionColorBrush } from "#winui/windows/ui/composition/CompositionColorBrush";
|
|
21
26
|
export { MicaKind } from "#winui/microsoft/ui/composition/system-backdrops/MicaKind";
|
|
22
27
|
export { AppWindow } from "#winui/microsoft/ui/windowing/AppWindow";
|
|
23
28
|
export { AppWindowPresenterKind } from "#winui/microsoft/ui/windowing/AppWindowPresenterKind";
|