react-x11 2.29.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -1
- package/src/cocoa/app.js +157 -9
- package/src/cocoa/panehost.js +226 -2
- package/src/cocoa/panewindow.js +204 -14
- package/src/cocoa/promotion.js +21 -1
- package/src/cocoa/sprites.js +54 -11
- package/src/components/Select.js +98 -7
- package/src/frame/index.js +60 -7
- package/src/imagedecode.js +255 -0
- package/src/imagesource.js +20 -15
- package/src/node.d.ts +5 -0
- package/src/nodes/image.js +44 -45
- package/src/nodes/window/floors.js +76 -15
- package/src/nodes/window/window.js +11 -1
- package/src/types/components.d.ts +10 -0
- package/src/types/elements.d.ts +10 -6
|
@@ -136,11 +136,14 @@ export function receivesFloor(child, axis) {
|
|
|
136
136
|
* A differential run over random trees, laid out with and without the
|
|
137
137
|
* rule, found why each clause is there. An auto basis is yoga's own
|
|
138
138
|
* measurement of the content, which can come out short of what the content
|
|
139
|
-
* needs, and the floor is what holds the item open. A named size that
|
|
140
|
-
* grow
|
|
141
|
-
* floor then
|
|
142
|
-
*
|
|
143
|
-
*
|
|
139
|
+
* needs, and the floor is what holds the item open. A named size that could
|
|
140
|
+
* grow was written as the size it grew to in the measuring pass, which the
|
|
141
|
+
* floor then kept; nothing grows in that pass any more
|
|
142
|
+
* (`setMeasuringShrink`), so its floor is the size itself, but the clause
|
|
143
|
+
* stays until the random trees are run against it again. And a `flexBasis`
|
|
144
|
+
* of its own is where the basis comes from instead of the size, and a
|
|
145
|
+
* percentage one is a different length in a measuring pass than in the real
|
|
146
|
+
* one.
|
|
144
147
|
*/
|
|
145
148
|
function floorIsNamedSize(child, axis) {
|
|
146
149
|
const style = child.style;
|
|
@@ -473,6 +476,17 @@ function markHeightStale(node, root, hit, stop = root) {
|
|
|
473
476
|
* pass has to be told, or every node would shrink to nothing and answer that
|
|
474
477
|
* the content needs no room — which is true of no content anywhere.
|
|
475
478
|
*
|
|
479
|
+
* And nothing grows. A min-content measurement hands out no free space, but
|
|
480
|
+
* a box with a size of its own has some in this pass all the same — a
|
|
481
|
+
* `width: 400` row is 400 wide whatever is offered at the root — and an item
|
|
482
|
+
* that grew into it was read back at the size it grew to: an empty spacer as
|
|
483
|
+
* its share of the row, a box that clips as its share. That share is a fact
|
|
484
|
+
* about the item's siblings, not its content, and the extent is cached as
|
|
485
|
+
* content (`contentSpan`), so it outlived the siblings it came from. A
|
|
486
|
+
* `<Select>`'s trigger is a caption, a growing spacer and a chevron in a row
|
|
487
|
+
* of its own width: the spacer's floor was the room the first caption left
|
|
488
|
+
* over, and a longer caption picked later was elided at the old one's width.
|
|
489
|
+
*
|
|
476
490
|
* Every child of a node being measured is told, so that the node's own
|
|
477
491
|
* layout is the one it always was; below a child whose extent is still
|
|
478
492
|
* good nothing is, since nothing in there is read. `out` collects what was
|
|
@@ -485,8 +499,10 @@ export function setMeasuringShrink(node, axis, out) {
|
|
|
485
499
|
// not read and the floors are not written back through
|
|
486
500
|
if (child.style.display === 'none') continue;
|
|
487
501
|
const shrink = namesOwnFloor(child, axis) ? 1 : 0;
|
|
488
|
-
|
|
502
|
+
const grows = child.style.flexGrow > 0;
|
|
503
|
+
if ((child.style.flexShrink ?? 1) !== shrink || grows) {
|
|
489
504
|
child.yoga.setFlexShrink(shrink);
|
|
505
|
+
if (grows) child.yoga.setFlexGrow(0);
|
|
490
506
|
out.push(child);
|
|
491
507
|
}
|
|
492
508
|
// not into a layout host's children: they are not flex items, and
|
|
@@ -585,22 +601,55 @@ const ACROSS_EDGES = [
|
|
|
585
601
|
Yoga.EDGE_ALL,
|
|
586
602
|
];
|
|
587
603
|
|
|
604
|
+
/** …and a vertical one. */
|
|
605
|
+
const DOWN_EDGES = [
|
|
606
|
+
Yoga.EDGE_TOP,
|
|
607
|
+
Yoga.EDGE_BOTTOM,
|
|
608
|
+
Yoga.EDGE_VERTICAL,
|
|
609
|
+
Yoga.EDGE_ALL,
|
|
610
|
+
];
|
|
611
|
+
|
|
588
612
|
/** Whether an in-flow child of a column is as wide as something other than
|
|
589
613
|
* its content: a width it names, or the column's, which it stretches to
|
|
590
614
|
* unless an alignment or an `auto` margin says otherwise. */
|
|
591
615
|
function widthNotItsOwn(yoga, items) {
|
|
592
616
|
const width = yoga.getWidth().unit;
|
|
593
617
|
if (width === Yoga.UNIT_POINT || width === Yoga.UNIT_PERCENT) return true;
|
|
618
|
+
return stretches(yoga, items, ACROSS_EDGES);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/** Whether an item is stretched across its container, whose alignment is
|
|
622
|
+
* `items`: unless its own alignment or an `auto` margin on one of `edges`
|
|
623
|
+
* — the ones across the container — says otherwise. A size of its own on
|
|
624
|
+
* that axis is the caller's to rule out. */
|
|
625
|
+
function stretches(yoga, items, edges) {
|
|
594
626
|
const self = yoga.getAlignSelf();
|
|
595
627
|
if ((self === Yoga.ALIGN_AUTO ? items : self) !== Yoga.ALIGN_STRETCH) {
|
|
596
628
|
return false;
|
|
597
629
|
}
|
|
598
|
-
for (const edge of
|
|
630
|
+
for (const edge of edges) {
|
|
599
631
|
if (yoga.getMargin(edge).unit === Yoga.UNIT_AUTO) return false;
|
|
600
632
|
}
|
|
601
633
|
return true;
|
|
602
634
|
}
|
|
603
635
|
|
|
636
|
+
/** Whether `node`'s size along `axis` is its container's cross size rather
|
|
637
|
+
* than anything of its own: an item in flow, stretched, naming no size on
|
|
638
|
+
* that axis. */
|
|
639
|
+
function stretchedAlong(node, axis) {
|
|
640
|
+
const parent = node.parent;
|
|
641
|
+
if (!parent || parent._host !== null || !inFlow(node)) return false;
|
|
642
|
+
if (mainAxisOf(parent) === axis) return false;
|
|
643
|
+
const yoga = node.yoga;
|
|
644
|
+
const size = (axis === 'width' ? yoga.getWidth() : yoga.getHeight()).unit;
|
|
645
|
+
if (size === Yoga.UNIT_POINT || size === Yoga.UNIT_PERCENT) return false;
|
|
646
|
+
return stretches(
|
|
647
|
+
yoga,
|
|
648
|
+
parent.yoga.getAlignItems(),
|
|
649
|
+
axis === 'width' ? ACROSS_EDGES : DOWN_EDGES,
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
604
653
|
/**
|
|
605
654
|
* Where a column's height comes from, down a pass with none on offer: its
|
|
606
655
|
* `'content'`, when it names nothing that bounds it; its `'own'`, when all it
|
|
@@ -637,6 +686,7 @@ function heightFollowsParent(yoga) {
|
|
|
637
686
|
export function restoreShrink(shrunk) {
|
|
638
687
|
for (const child of shrunk) {
|
|
639
688
|
child.yoga.setFlexShrink(child.style.flexShrink ?? 1);
|
|
689
|
+
if (child.style.flexGrow > 0) child.yoga.setFlexGrow(child.style.flexGrow);
|
|
640
690
|
}
|
|
641
691
|
}
|
|
642
692
|
|
|
@@ -804,6 +854,11 @@ export function contentSpan(node, axis, intrinsic, root, read = true) {
|
|
|
804
854
|
}
|
|
805
855
|
// a span nobody reads, and — for a leaf — a measurement nobody needs
|
|
806
856
|
if (!read) return 0;
|
|
857
|
+
const edges =
|
|
858
|
+
yoga.getComputedPadding(startEdge) +
|
|
859
|
+
yoga.getComputedPadding(endEdge) +
|
|
860
|
+
yoga.getComputedBorder(startEdge) +
|
|
861
|
+
yoga.getComputedBorder(endEdge);
|
|
807
862
|
if (start === Infinity) {
|
|
808
863
|
// A leaf: nothing inside to look at, and what the pass did to it may
|
|
809
864
|
// have been a stretch rather than a measurement. So it is asked again.
|
|
@@ -814,7 +869,7 @@ export function contentSpan(node, axis, intrinsic, root, read = true) {
|
|
|
814
869
|
// rather than joining it in a `max`, because a measured leaf's base size
|
|
815
870
|
// is its max-content width — the whole line, unwrapped — and taking the
|
|
816
871
|
// larger of the two would floor every label at the width it would like
|
|
817
|
-
// to be.
|
|
872
|
+
// to be.
|
|
818
873
|
//
|
|
819
874
|
// **Down**, it is what the leaf measured before the collapse squashed
|
|
820
875
|
// it: a height at a settled width is not a leaf's to give.
|
|
@@ -825,15 +880,21 @@ export function contentSpan(node, axis, intrinsic, root, read = true) {
|
|
|
825
880
|
undefined,
|
|
826
881
|
Yoga.MEASURE_MODE_UNDEFINED,
|
|
827
882
|
)?.width;
|
|
828
|
-
|
|
883
|
+
if (measured !== undefined) return measured;
|
|
884
|
+
} else if (node._measureFn) {
|
|
885
|
+
return Math.max(own, intrinsic?.get(node) ?? 0);
|
|
829
886
|
}
|
|
830
|
-
|
|
887
|
+
// A leaf that measures nothing has only its own box to report: padding
|
|
888
|
+
// and border, a basis, a ratio — what the pass laid it out at, now that
|
|
889
|
+
// nothing grows in it (`setMeasuringShrink`) — except where the box was
|
|
890
|
+
// its container's, stretched across it. Then it is the leaf's edges and
|
|
891
|
+
// nothing more: the stretch is as wide as its siblings were, and the
|
|
892
|
+
// extent outlives them. So is what it was laid out at before the
|
|
893
|
+
// collapse, which grew: a spacer in a column of a height of its own was
|
|
894
|
+
// floored at the room the column had left over, whatever later came to
|
|
895
|
+
// need it.
|
|
896
|
+
return stretchedAlong(node, axis) ? edges : own;
|
|
831
897
|
}
|
|
832
|
-
const edges =
|
|
833
|
-
yoga.getComputedPadding(startEdge) +
|
|
834
|
-
yoga.getComputedPadding(endEdge) +
|
|
835
|
-
yoga.getComputedBorder(startEdge) +
|
|
836
|
-
yoga.getComputedBorder(endEdge);
|
|
837
898
|
return end - start + edges;
|
|
838
899
|
}
|
|
839
900
|
|
|
@@ -550,12 +550,22 @@ export class WindowNode extends Scrollable(Node) {
|
|
|
550
550
|
* relative to the *frame*, not the root. A popup anchored with them lands
|
|
551
551
|
* near the corner of the screen instead of under its trigger. The server
|
|
552
552
|
* will translate for us, and its answer is right whatever the WM did.
|
|
553
|
+
*
|
|
554
|
+
* A backend with no server to ask keeps the origin on its window object
|
|
555
|
+
* itself, current as of the event that moved it — Cocoa's
|
|
556
|
+
* `_nativeResized`, a frame pane's `setPaneSize`. There is no question to
|
|
557
|
+
* ask there, and what is left is what the answer would have done: tell
|
|
558
|
+
* whatever is anchored to this window that it moved. Without it a popup
|
|
559
|
+
* stayed where the window had been, and a frame pane told its new place
|
|
560
|
+
* on the screen dropped its next menu from the old one.
|
|
553
561
|
*/
|
|
554
562
|
_refreshScreenOrigin() {
|
|
555
563
|
const wnd = this.window;
|
|
564
|
+
if (!wnd) return;
|
|
556
565
|
const X = this.app?.X;
|
|
557
566
|
const root = X?.display?.screen?.[0]?.root;
|
|
558
|
-
if (
|
|
567
|
+
if (root == null || typeof X.TranslateCoordinates !== 'function') {
|
|
568
|
+
this._notifyAnchorChange();
|
|
559
569
|
return;
|
|
560
570
|
}
|
|
561
571
|
X.TranslateCoordinates(wnd.id, root, 0, 0, (err, res) => {
|
|
@@ -521,6 +521,16 @@ export interface SelectProps<T = unknown>
|
|
|
521
521
|
/** The chevron's style, over `textMuted` at the caption's cap height.
|
|
522
522
|
* `display: 'none'` leaves it out. */
|
|
523
523
|
chevronStyle?: StyleProp;
|
|
524
|
+
/**
|
|
525
|
+
* The menu's half of `native`: where the backend drops a control's menu
|
|
526
|
+
* as the platform's own (macOS, with `@windowkit/appkit` 0.20 or later),
|
|
527
|
+
* the list is that menu rather than a drawn one. Follows the trigger by
|
|
528
|
+
* default — the native bezel's select gets the native menu, a drawn one
|
|
529
|
+
* the drawn menu. `true` asks for the platform's menu under a drawn
|
|
530
|
+
* trigger too, set at the caption's size; `false` keeps the drawn menu.
|
|
531
|
+
* Ignored where the backend has no such menu.
|
|
532
|
+
*/
|
|
533
|
+
nativeMenu?: boolean;
|
|
524
534
|
}
|
|
525
535
|
export function Select<T = unknown>(props: SelectProps<T>): ReactNode;
|
|
526
536
|
|
package/src/types/elements.d.ts
CHANGED
|
@@ -805,9 +805,9 @@ export interface FileUrl {
|
|
|
805
805
|
}
|
|
806
806
|
|
|
807
807
|
/**
|
|
808
|
-
* What `src` accepts: a file path or file URL (PNG
|
|
809
|
-
*
|
|
810
|
-
* symbol by name.
|
|
808
|
+
* What `src` accepts: a file path or file URL, encoded bytes (PNG, JPEG or
|
|
809
|
+
* WebP; GIF, BMP, TIFF, HEIC and AVIF too under Bun), raw RGBA pixels, an
|
|
810
|
+
* ntk `Image`/`Surface`, or a symbol by name.
|
|
811
811
|
*/
|
|
812
812
|
export type ImageSource =
|
|
813
813
|
| string
|
|
@@ -862,9 +862,13 @@ export interface ImageDrawableSource {
|
|
|
862
862
|
|
|
863
863
|
export interface ImageProps extends DrawnProps<DrawnNode> {
|
|
864
864
|
/**
|
|
865
|
-
* Client-side pixels: a file path or file URL
|
|
866
|
-
*
|
|
867
|
-
*
|
|
865
|
+
* Client-side pixels: a file path or file URL, encoded bytes (no temp
|
|
866
|
+
* file), raw RGBA (`{ width, height, data }`), or an ntk
|
|
867
|
+
* `Image`/`Surface` used as-is. Files and bytes are PNG, JPEG or WebP —
|
|
868
|
+
* and under Bun, which decodes them off the JavaScript thread, GIF and BMP
|
|
869
|
+
* too, with TIFF, HEIC and AVIF on macOS and Windows. A file, any format
|
|
870
|
+
* under Bun, and a WebP elsewhere arrive a moment after the first frame:
|
|
871
|
+
* the element takes no room until then, unless styled a size.
|
|
868
872
|
*
|
|
869
873
|
* One source per element: `src`, `picture` and `drawable` are mutually
|
|
870
874
|
* exclusive, and passing two throws.
|