@swiftbrowser/react 0.4.0 → 0.5.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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, createElement, useRef, useLayoutEffect, useEffect, useState, useId, Fragment as Fragment$1, Children, isValidElement, cloneElement, useSyncExternalStore } from "react";
1
+ import { createContext, useContext, createElement, useRef, useLayoutEffect, useState, useEffect, Children, useId, Fragment as Fragment$1, isValidElement, cloneElement, useSyncExternalStore } from "react";
2
2
  import { DefaultEventPriority, ConcurrentRoot } from "react-reconciler/constants";
3
3
  import Reconciler from "react-reconciler";
4
4
  import { horizontalSizeClassFor } from "@swiftbrowser/web/src/protocol";
@@ -534,6 +534,185 @@ function readBinding(value, onChange) {
534
534
  return [value, onChange ?? (() => {
535
535
  })];
536
536
  }
537
+ function sb(kind, props, on, children, target) {
538
+ const hostProps = { kind };
539
+ if (props) hostProps.props = props;
540
+ if (on) hostProps.on = on;
541
+ if (target) hostProps.target = target;
542
+ return children === void 0 ? createElement("sb", hostProps) : createElement("sb", hostProps, children);
543
+ }
544
+ const CoordinateSpacesContext = createContext({});
545
+ function useCoordinateSpaces() {
546
+ return useContext(CoordinateSpacesContext);
547
+ }
548
+ function CoordinateSpace({ name, children }) {
549
+ const spaces = useContext(CoordinateSpacesContext);
550
+ const [frame2, setFrame] = useState(null);
551
+ return /* @__PURE__ */ jsx(CoordinateSpacesContext.Provider, { value: { ...spaces, [name]: frame2 }, children: sb(
552
+ "zstack",
553
+ { alignment: "center", reportsSize: true, reportsFrame: true },
554
+ {
555
+ geometry: (event) => {
556
+ const next = { x: event.x ?? 0, y: event.y ?? 0, width: event.width, height: event.height };
557
+ if (!frame2 || frame2.x !== next.x || frame2.y !== next.y || frame2.width !== next.width || frame2.height !== next.height) setFrame(next);
558
+ }
559
+ },
560
+ children
561
+ ) });
562
+ }
563
+ let active = null;
564
+ function Draggable({ payload, children }) {
565
+ return sb(
566
+ "draggable",
567
+ {},
568
+ {
569
+ dragstart: (event) => {
570
+ active = { id: event.id, payload };
571
+ },
572
+ dragend: (event) => {
573
+ if (active?.id === event.id) active = null;
574
+ }
575
+ },
576
+ children
577
+ );
578
+ }
579
+ function itemValue(item) {
580
+ if (item.text !== void 0) {
581
+ if (item.type === "text/uri-list") {
582
+ try {
583
+ return new URL(item.text.split(/\r?\n/)[0].trim());
584
+ } catch {
585
+ return item.text;
586
+ }
587
+ }
588
+ return item.text;
589
+ }
590
+ const binary = atob(item.data ?? "");
591
+ const bytes = new Uint8Array(binary.length);
592
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
593
+ return typeof File !== "undefined" ? new File([bytes], item.name ?? "file", { type: item.type }) : bytes;
594
+ }
595
+ function DropDestination({ action, isTargeted, accepts, children }) {
596
+ return sb(
597
+ "dropdestination",
598
+ { accepts: accepts ?? [] },
599
+ {
600
+ drop: (event) => {
601
+ if (event.phase === "entered") {
602
+ isTargeted?.(true);
603
+ return;
604
+ }
605
+ isTargeted?.(false);
606
+ if (event.phase !== "performed") return;
607
+ let items;
608
+ if (event.source !== void 0) items = active && active.id === event.source ? [active.payload] : [];
609
+ else items = (event.items ?? []).map(itemValue);
610
+ if (items.length > 0) action(items, { x: event.x, y: event.y });
611
+ }
612
+ },
613
+ children
614
+ );
615
+ }
616
+ function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
617
+ const [presented, setPresented] = readBinding(isPresented);
618
+ if (!presented) return null;
619
+ const dismiss = () => {
620
+ setPresented(false);
621
+ onDismiss?.();
622
+ };
623
+ const detents = fullScreen ? ["full"] : ["large"];
624
+ return sb(
625
+ HOIST_KIND,
626
+ void 0,
627
+ void 0,
628
+ sb(
629
+ "sheet",
630
+ { detents },
631
+ { tap: dismiss },
632
+ /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) })
633
+ ),
634
+ "root"
635
+ );
636
+ }
637
+ function presentationDetents(detents) {
638
+ const encoded = detents.map(
639
+ (detent) => typeof detent === "string" ? detent : "height" in detent ? `height:${detent.height}` : `fraction:${detent.fraction}`
640
+ );
641
+ return sb(PREF_KIND, { detents: encoded }, void 0, void 0, "sheet");
642
+ }
643
+ function AlertPresenter({ title, isPresented, message, actions, style }) {
644
+ const [presented, setPresented] = readBinding(isPresented);
645
+ if (!presented) return null;
646
+ const dismiss = () => setPresented(false);
647
+ return sb(
648
+ HOIST_KIND,
649
+ void 0,
650
+ void 0,
651
+ sb(
652
+ "alert",
653
+ { title, message: message ?? null, style: style ?? "alert" },
654
+ { tap: dismiss },
655
+ withEnvironment({ dismissAlert: dismiss }, actions)
656
+ ),
657
+ "root"
658
+ );
659
+ }
660
+ function Lifecycle({ onAppear, onDisappear }) {
661
+ useEffect(() => {
662
+ onAppear?.();
663
+ return () => onDisappear?.();
664
+ }, []);
665
+ return null;
666
+ }
667
+ function Inspector({ isPresented, content, columnWidth, children }) {
668
+ const sizeClass = useHorizontalSizeClass();
669
+ const [presented, setPresented] = readBinding(isPresented);
670
+ if (sizeClass === "compact") {
671
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
672
+ children,
673
+ /* @__PURE__ */ jsx(SheetPresenter, { isPresented: [presented, setPresented], content })
674
+ ] });
675
+ }
676
+ const panelContent = columnWidth !== void 0 ? sb("styled", { style: { inspectorColumnWidth: columnWidth } }, void 0, content) : content;
677
+ return sb("inspector", { presented }, void 0, [
678
+ /* @__PURE__ */ jsx(InspectorPart, { children }, "content"),
679
+ /* @__PURE__ */ jsx(InspectorPart, { children: sb("inspectorpanel", {}, void 0, panelContent) }, "panel")
680
+ ]);
681
+ }
682
+ function InspectorPart({ children }) {
683
+ return children;
684
+ }
685
+ function Task({ id, action }) {
686
+ const latest = useRef(action);
687
+ latest.current = action;
688
+ useEffect(() => {
689
+ const controller = new AbortController();
690
+ Promise.resolve().then(() => latest.current(controller.signal)).catch((error) => {
691
+ if (!controller.signal.aborted) console.error(error);
692
+ });
693
+ return () => controller.abort();
694
+ }, [id]);
695
+ return null;
696
+ }
697
+ function OnChange({
698
+ value,
699
+ action,
700
+ initial
701
+ }) {
702
+ const previous = useRef(null);
703
+ const latest = useRef(action);
704
+ latest.current = action;
705
+ useEffect(() => {
706
+ const last = previous.current;
707
+ previous.current = { value };
708
+ if (last === null) {
709
+ if (initial) latest.current(value, value);
710
+ return;
711
+ }
712
+ if (!Object.is(last.value, value)) latest.current(last.value, value);
713
+ }, [value, initial]);
714
+ return null;
715
+ }
537
716
  const HIERARCHY = { primary: 1, secondary: 2, tertiary: 3, quaternary: 4 };
538
717
  function rgb(r2, g, b, a = 1) {
539
718
  return { r: r2, g, b, a };
@@ -680,346 +859,102 @@ function insets(edges, amount) {
680
859
  }
681
860
  return result;
682
861
  }
683
- const r = (n) => {
684
- const v = Math.round(n * 100) / 100;
685
- return Object.is(v, -0) ? "0" : String(v);
686
- };
687
- class Path {
688
- parts = [];
689
- current = null;
690
- start = null;
691
- constructor(build) {
692
- build?.(this);
693
- }
694
- /** `Path(rect)` */
695
- static rect(rect) {
696
- return new Path().addRect(rect);
697
- }
698
- /** `Path(roundedRect:cornerRadius:)` */
699
- static roundedRect(rect, cornerRadius) {
700
- return new Path().addRoundedRect(rect, cornerRadius);
862
+ const ScrollRequestContext = createContext(null);
863
+ let nextSerial = 1;
864
+ function ScrollViewReader({ children }) {
865
+ const [request, setRequest] = useState(null);
866
+ const proxy = {
867
+ scrollTo: (id, anchor) => setRequest({ id, anchor: anchor === void 0 ? null : unitPoint(anchor), serial: nextSerial++ })
868
+ };
869
+ return /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: request, children: children(proxy) });
870
+ }
871
+ function ScrollTarget({ id, children }) {
872
+ const request = useContext(ScrollRequestContext);
873
+ if (request && request.id === id) return styled({ scrollID: true, scrollTo: { anchor: request.anchor, serial: request.serial } }, children);
874
+ return styled({ scrollID: true }, children);
875
+ }
876
+ const ScrollSettingsContext = createContext({});
877
+ function edgesOf(edges) {
878
+ const list = Array.isArray(edges) ? edges : [edges];
879
+ const all = list.some((edge) => edge === "all" || edge === "vertical");
880
+ return { top: all || list.includes("top"), bottom: all || list.includes("bottom") };
881
+ }
882
+ function edgeStyleSettings(value) {
883
+ const [style, edges] = Array.isArray(value) ? value : [value, "all"];
884
+ const on = edgesOf(edges);
885
+ const name = style === "automatic" ? void 0 : style;
886
+ const result = {};
887
+ if (on.top) result.topStyle = name;
888
+ if (on.bottom) result.bottomStyle = name;
889
+ return result;
890
+ }
891
+ function edgeHiddenSettings(value) {
892
+ const [hidden, edges] = Array.isArray(value) ? value : [value, "all"];
893
+ const on = edgesOf(edges);
894
+ const result = {};
895
+ if (on.top) result.topHidden = hidden;
896
+ if (on.bottom) result.bottomHidden = hidden;
897
+ return result;
898
+ }
899
+ function marginSettings(value) {
900
+ return { margins: padding(value) };
901
+ }
902
+ function mergeScrollSettings(outer, inner) {
903
+ const result = { ...outer };
904
+ for (const key of ["topStyle", "bottomStyle", "topHidden", "bottomHidden"]) {
905
+ if (key in inner) result[key] = inner[key];
701
906
  }
702
- /** `Path(ellipseIn:)` */
703
- static ellipse(rect) {
704
- return new Path().addEllipse(rect);
705
- }
706
- move(to) {
707
- this.parts.push(`M${r(to.x)} ${r(to.y)}`);
708
- this.current = to;
709
- this.start = to;
710
- return this;
711
- }
712
- addLine(to) {
713
- if (!this.current) return this.move(to);
714
- this.parts.push(`L${r(to.x)} ${r(to.y)}`);
715
- this.current = to;
716
- return this;
717
- }
718
- addLines(points) {
719
- points.forEach((point, index) => index === 0 ? this.move(point) : this.addLine(point));
720
- return this;
721
- }
722
- addQuadCurve(to, control) {
723
- if (!this.current) this.move(control);
724
- this.parts.push(`Q${r(control.x)} ${r(control.y)} ${r(to.x)} ${r(to.y)}`);
725
- this.current = to;
726
- return this;
727
- }
728
- addCurve(to, control1, control2) {
729
- if (!this.current) this.move(control1);
730
- this.parts.push(`C${r(control1.x)} ${r(control1.y)} ${r(control2.x)} ${r(control2.y)} ${r(to.x)} ${r(to.y)}`);
731
- this.current = to;
732
- return this;
733
- }
734
- /**
735
- * `addArc(center:radius:startAngle:endAngle:clockwise:)`, angles in
736
- * degrees. As in SwiftUI's flipped coordinates, `clockwise: false` draws
737
- * clockwise on screen.
738
- */
739
- addArc(center, radius, startAngle, endAngle, clockwise) {
740
- const rad = (deg) => deg * Math.PI / 180;
741
- const point = (deg) => ({ x: center.x + radius * Math.cos(rad(deg)), y: center.y + radius * Math.sin(rad(deg)) });
742
- const from = point(startAngle);
743
- if (this.current) this.addLine(from);
744
- else this.move(from);
745
- const sweepPositive = !clockwise;
746
- let delta = endAngle - startAngle;
747
- if (sweepPositive) while (delta < 0) delta += 360;
748
- else while (delta > 0) delta -= 360;
749
- if (Math.abs(delta) >= 360) {
750
- const half = point(startAngle + (sweepPositive ? 180 : -180));
751
- const flag = sweepPositive ? 1 : 0;
752
- this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(half.x)} ${r(half.y)}`);
753
- this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(from.x)} ${r(from.y)}`);
754
- this.current = from;
755
- return this;
756
- }
757
- const to = point(startAngle + delta);
758
- const large = Math.abs(delta) > 180 ? 1 : 0;
759
- this.parts.push(`A${r(radius)} ${r(radius)} 0 ${large} ${sweepPositive ? 1 : 0} ${r(to.x)} ${r(to.y)}`);
760
- this.current = to;
761
- return this;
762
- }
763
- addRect(rect) {
764
- this.move({ x: rect.x, y: rect.y });
765
- this.addLine({ x: rect.x + rect.width, y: rect.y });
766
- this.addLine({ x: rect.x + rect.width, y: rect.y + rect.height });
767
- this.addLine({ x: rect.x, y: rect.y + rect.height });
768
- return this.closeSubpath();
769
- }
770
- addRoundedRect(rect, cornerRadius) {
771
- const c = Math.max(0, Math.min(cornerRadius, rect.width / 2, rect.height / 2));
772
- if (c === 0) return this.addRect(rect);
773
- const { x, y, width: w, height: h } = rect;
774
- this.move({ x: x + c, y });
775
- this.addLine({ x: x + w - c, y });
776
- this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w)} ${r(y + c)}`);
777
- this.current = { x: x + w, y: y + c };
778
- this.addLine({ x: x + w, y: y + h - c });
779
- this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w - c)} ${r(y + h)}`);
780
- this.current = { x: x + w - c, y: y + h };
781
- this.addLine({ x: x + c, y: y + h });
782
- this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x)} ${r(y + h - c)}`);
783
- this.current = { x, y: y + h - c };
784
- this.addLine({ x, y: y + c });
785
- this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + c)} ${r(y)}`);
786
- this.current = { x: x + c, y };
787
- return this.closeSubpath();
788
- }
789
- addEllipse(rect) {
790
- const rx = rect.width / 2;
791
- const ry = rect.height / 2;
792
- const cx = rect.x + rx;
793
- const cy = rect.y + ry;
794
- this.move({ x: cx + rx, y: cy });
795
- this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx - rx)} ${r(cy)}`);
796
- this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx + rx)} ${r(cy)}`);
797
- this.current = { x: cx + rx, y: cy };
798
- return this.closeSubpath();
799
- }
800
- addPath(path) {
801
- this.parts.push(path.svg());
802
- return this;
803
- }
804
- closeSubpath() {
805
- this.parts.push("Z");
806
- this.current = this.start;
807
- return this;
808
- }
809
- get isEmpty() {
810
- return this.parts.length === 0;
811
- }
812
- /** The SVG path data. */
813
- svg() {
814
- return this.parts.join("");
815
- }
816
- toString() {
817
- return this.svg();
818
- }
819
- }
820
- function sb(kind, props, on, children, target) {
821
- const hostProps = { kind };
822
- if (props) hostProps.props = props;
823
- if (on) hostProps.on = on;
824
- if (target) hostProps.target = target;
825
- return children === void 0 ? createElement("sb", hostProps) : createElement("sb", hostProps, children);
826
- }
827
- let active = null;
828
- function Draggable({ payload, children }) {
829
- return sb(
830
- "draggable",
831
- {},
832
- {
833
- dragstart: (event) => {
834
- active = { id: event.id, payload };
835
- },
836
- dragend: (event) => {
837
- if (active?.id === event.id) active = null;
838
- }
839
- },
840
- children
841
- );
842
- }
843
- function itemValue(item) {
844
- if (item.text !== void 0) {
845
- if (item.type === "text/uri-list") {
846
- try {
847
- return new URL(item.text.split(/\r?\n/)[0].trim());
848
- } catch {
849
- return item.text;
850
- }
851
- }
852
- return item.text;
853
- }
854
- const binary = atob(item.data ?? "");
855
- const bytes = new Uint8Array(binary.length);
856
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
857
- return typeof File !== "undefined" ? new File([bytes], item.name ?? "file", { type: item.type }) : bytes;
858
- }
859
- function DropDestination({ action, isTargeted, accepts, children }) {
860
- return sb(
861
- "dropdestination",
862
- { accepts: accepts ?? [] },
863
- {
864
- drop: (event) => {
865
- if (event.phase === "entered") {
866
- isTargeted?.(true);
867
- return;
868
- }
869
- isTargeted?.(false);
870
- if (event.phase !== "performed") return;
871
- let items;
872
- if (event.source !== void 0) items = active && active.id === event.source ? [active.payload] : [];
873
- else items = (event.items ?? []).map(itemValue);
874
- if (items.length > 0) action(items, { x: event.x, y: event.y });
875
- }
876
- },
877
- children
878
- );
879
- }
880
- function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
881
- const [presented, setPresented] = readBinding(isPresented);
882
- if (!presented) return null;
883
- const dismiss = () => {
884
- setPresented(false);
885
- onDismiss?.();
886
- };
887
- const detents = fullScreen ? ["full"] : ["large"];
888
- return sb(
889
- HOIST_KIND,
890
- void 0,
891
- void 0,
892
- sb(
893
- "sheet",
894
- { detents },
895
- { tap: dismiss },
896
- /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) })
897
- ),
898
- "root"
899
- );
900
- }
901
- function presentationDetents(detents) {
902
- const encoded = detents.map(
903
- (detent) => typeof detent === "string" ? detent : "height" in detent ? `height:${detent.height}` : `fraction:${detent.fraction}`
904
- );
905
- return sb(PREF_KIND, { detents: encoded }, void 0, void 0, "sheet");
906
- }
907
- function AlertPresenter({ title, isPresented, message, actions, style }) {
908
- const [presented, setPresented] = readBinding(isPresented);
909
- if (!presented) return null;
910
- const dismiss = () => setPresented(false);
911
- return sb(
912
- HOIST_KIND,
913
- void 0,
914
- void 0,
915
- sb(
916
- "alert",
917
- { title, message: message ?? null, style: style ?? "alert" },
918
- { tap: dismiss },
919
- withEnvironment({ dismissAlert: dismiss }, actions)
920
- ),
921
- "root"
922
- );
923
- }
924
- function Lifecycle({ onAppear, onDisappear }) {
925
- useEffect(() => {
926
- onAppear?.();
927
- return () => onDisappear?.();
928
- }, []);
929
- return null;
930
- }
931
- function Inspector({ isPresented, content, columnWidth, children }) {
932
- const sizeClass = useHorizontalSizeClass();
933
- const [presented, setPresented] = readBinding(isPresented);
934
- if (sizeClass === "compact") {
935
- return /* @__PURE__ */ jsxs(Fragment, { children: [
936
- children,
937
- /* @__PURE__ */ jsx(SheetPresenter, { isPresented: [presented, setPresented], content })
938
- ] });
939
- }
940
- const panelContent = columnWidth !== void 0 ? sb("styled", { style: { inspectorColumnWidth: columnWidth } }, void 0, content) : content;
941
- return sb("inspector", { presented }, void 0, [
942
- /* @__PURE__ */ jsx(InspectorPart, { children }, "content"),
943
- /* @__PURE__ */ jsx(InspectorPart, { children: sb("inspectorpanel", {}, void 0, panelContent) }, "panel")
944
- ]);
945
- }
946
- function InspectorPart({ children }) {
947
- return children;
948
- }
949
- function Task({ id, action }) {
950
- const latest = useRef(action);
951
- latest.current = action;
952
- useEffect(() => {
953
- const controller = new AbortController();
954
- Promise.resolve().then(() => latest.current(controller.signal)).catch((error) => {
955
- if (!controller.signal.aborted) console.error(error);
956
- });
957
- return () => controller.abort();
958
- }, [id]);
959
- return null;
960
- }
961
- function OnChange({
962
- value,
963
- action,
964
- initial
965
- }) {
966
- const previous = useRef(null);
967
- const latest = useRef(action);
968
- latest.current = action;
969
- useEffect(() => {
970
- const last = previous.current;
971
- previous.current = { value };
972
- if (last === null) {
973
- if (initial) latest.current(value, value);
974
- return;
975
- }
976
- if (!Object.is(last.value, value)) latest.current(last.value, value);
977
- }, [value, initial]);
978
- return null;
979
- }
980
- const CoordinateSpacesContext = createContext({});
981
- function useCoordinateSpaces() {
982
- return useContext(CoordinateSpacesContext);
983
- }
984
- function CoordinateSpace({ name, children }) {
985
- const spaces = useContext(CoordinateSpacesContext);
986
- const [frame2, setFrame] = useState(null);
987
- return /* @__PURE__ */ jsx(CoordinateSpacesContext.Provider, { value: { ...spaces, [name]: frame2 }, children: sb(
988
- "zstack",
989
- { alignment: "center", reportsSize: true, reportsFrame: true },
990
- {
991
- geometry: (event) => {
992
- const next = { x: event.x ?? 0, y: event.y ?? 0, width: event.width, height: event.height };
993
- if (!frame2 || frame2.x !== next.x || frame2.y !== next.y || frame2.width !== next.width || frame2.height !== next.height) setFrame(next);
994
- }
995
- },
996
- children
997
- ) });
998
- }
999
- function Hover({ action, children }) {
1000
- return sb("styled", { style: { hover: true } }, { hover: (event) => action(event.value) }, children);
1001
- }
1002
- const CURSORS = {
1003
- link: "pointer",
1004
- automatic: "auto",
1005
- default: "default",
1006
- text: "text",
1007
- verticalText: "vertical-text",
1008
- grabIdle: "grab",
1009
- grabActive: "grabbing",
1010
- rectSelection: "crosshair",
1011
- columnResize: "col-resize",
1012
- rowResize: "row-resize"
1013
- };
1014
- function cursorFor(style) {
1015
- return CURSORS[style] ?? style;
1016
- }
1017
- function SymbolEffect({ spec, children }) {
1018
- const serial = useRef(null);
1019
- const discrete = "value" in spec;
1020
- if (discrete) {
1021
- if (!serial.current) serial.current = { value: spec.value, count: 0 };
1022
- else if (!Object.is(serial.current.value, spec.value)) serial.current = { value: spec.value, count: serial.current.count + 1 };
907
+ if (inner.margins) result.margins = { ...outer.margins, ...inner.margins };
908
+ return result;
909
+ }
910
+ function withScrollSettings(settings, children) {
911
+ return createElement(ScrollSettingsExtender, { settings }, children);
912
+ }
913
+ function ScrollSettingsExtender({ settings, children }) {
914
+ const outer = useContext(ScrollSettingsContext);
915
+ return createElement(ScrollSettingsContext.Provider, { value: mergeScrollSettings(outer, settings) }, children);
916
+ }
917
+ function useScrollSettings(own) {
918
+ return mergeScrollSettings(useContext(ScrollSettingsContext), own);
919
+ }
920
+ function edgeEffectProp(settings) {
921
+ const edges = {};
922
+ const top = settings.topHidden ? "hidden" : settings.topStyle;
923
+ const bottom = settings.bottomHidden ? "hidden" : settings.bottomStyle;
924
+ if (top) edges.top = top;
925
+ if (bottom) edges.bottom = bottom;
926
+ return top || bottom ? edges : void 0;
927
+ }
928
+ function marginedContent(children, margins, axis) {
929
+ if (!margins || Object.values(margins).every((value) => !value)) return children;
930
+ const list = Children.toArray(children);
931
+ const content = list.length === 1 ? list[0] : sb(axis === "horizontal" ? "hstack" : "vstack", { spacing: null, alignment: "center" }, void 0, children);
932
+ return sb("styled", { style: { padding: margins } }, void 0, content);
933
+ }
934
+ function Hover({ action, children }) {
935
+ return sb("styled", { style: { hover: true } }, { hover: (event) => action(event.value) }, children);
936
+ }
937
+ const CURSORS = {
938
+ link: "pointer",
939
+ automatic: "auto",
940
+ default: "default",
941
+ text: "text",
942
+ verticalText: "vertical-text",
943
+ grabIdle: "grab",
944
+ grabActive: "grabbing",
945
+ rectSelection: "crosshair",
946
+ columnResize: "col-resize",
947
+ rowResize: "row-resize"
948
+ };
949
+ function cursorFor(style) {
950
+ return CURSORS[style] ?? style;
951
+ }
952
+ function SymbolEffect({ spec, children }) {
953
+ const serial = useRef(null);
954
+ const discrete = "value" in spec;
955
+ if (discrete) {
956
+ if (!serial.current) serial.current = { value: spec.value, count: 0 };
957
+ else if (!Object.is(serial.current.value, spec.value)) serial.current = { value: spec.value, count: serial.current.count + 1 };
1023
958
  }
1024
959
  if (!discrete && spec.isActive === false) return children;
1025
960
  const effect = { effect: spec.effect };
@@ -1132,6 +1067,25 @@ function toolbarPlacement(name) {
1132
1067
  return "trailing";
1133
1068
  }
1134
1069
  }
1070
+ function containerRelativeFrame(value) {
1071
+ const spec = typeof value === "string" ? { axes: value } : value;
1072
+ const horizontal = spec.axes !== "vertical";
1073
+ const vertical = spec.axes !== "horizontal";
1074
+ let a = 1;
1075
+ let b = 0;
1076
+ if (spec.length) {
1077
+ const axis = horizontal ? "horizontal" : "vertical";
1078
+ b = spec.length(0, axis);
1079
+ a = (spec.length(1e3, axis) - b) / 1e3;
1080
+ } else if (spec.count !== void 0) {
1081
+ const n = Math.max(spec.count, 1);
1082
+ const span = Math.max(spec.span ?? 1, 1);
1083
+ const spacing = spec.spacing ?? 0;
1084
+ a = span / n;
1085
+ b = -spacing * (n - 1) * span / n + spacing * (span - 1);
1086
+ }
1087
+ return { ...horizontal ? { horizontal: true } : {}, ...vertical ? { vertical: true } : {}, a, b, alignment: spec.alignment ?? "center" };
1088
+ }
1135
1089
  const MODIFIER_KEYS = /* @__PURE__ */ new Set([
1136
1090
  "padding",
1137
1091
  "font",
@@ -1230,7 +1184,13 @@ const MODIFIER_KEYS = /* @__PURE__ */ new Set([
1230
1184
  "sensoryFeedback",
1231
1185
  "textCase",
1232
1186
  "coordinateSpace",
1233
- "contentTransition"
1187
+ "contentTransition",
1188
+ "scrollEdgeEffectStyle",
1189
+ "scrollEdgeEffectHidden",
1190
+ "contentMargins",
1191
+ "containerRelativeFrame",
1192
+ "visualEffect",
1193
+ "scrollTransition"
1234
1194
  ]);
1235
1195
  function splitProps(props) {
1236
1196
  const own = {};
@@ -1535,7 +1495,7 @@ function apply(key, value, node, sides) {
1535
1495
  const spec = value;
1536
1496
  const at = (width, height) => spec.value({ width, height });
1537
1497
  const a = at(0, 0);
1538
- const round = (n) => Math.round(n * 1e6) / 1e6;
1498
+ const round2 = (n) => Math.round(n * 1e6) / 1e6;
1539
1499
  const vertical = ["top", "bottom", "verticalCenter", "firstTextBaseline", "lastTextBaseline"].includes(spec.guide);
1540
1500
  const name = spec.guide === "horizontalCenter" || spec.guide === "verticalCenter" ? "center" : spec.guide;
1541
1501
  return styled(
@@ -1543,7 +1503,7 @@ function apply(key, value, node, sides) {
1543
1503
  alignmentGuide: {
1544
1504
  axis: vertical ? "vertical" : "horizontal",
1545
1505
  name,
1546
- value: [round(a), round((at(100, 0) - a) / 100), round((at(0, 100) - a) / 100)]
1506
+ value: [round2(a), round2((at(100, 0) - a) / 100), round2((at(0, 100) - a) / 100)]
1547
1507
  }
1548
1508
  },
1549
1509
  node
@@ -1586,291 +1546,809 @@ function apply(key, value, node, sides) {
1586
1546
  const spec = value;
1587
1547
  return styled({ matchedGeometry: `${spec.namespace ?? ""}:${spec.id}` }, node);
1588
1548
  }
1589
- case "layoutValue":
1590
- return node;
1591
- case "safeAreaInset": {
1592
- const spec = value;
1593
- const vertical = spec.edge === "top" || spec.edge === "bottom";
1594
- const before = spec.edge === "top" || spec.edge === "leading";
1595
- const children = before ? [createElement(Fragment$1, { key: "inset" }, spec.content), createElement(Fragment$1, { key: "content" }, node)] : [createElement(Fragment$1, { key: "content" }, node), createElement(Fragment$1, { key: "inset" }, spec.content)];
1596
- return vertical ? sb("vstack", { spacing: spec.spacing ?? 0, alignment: spec.alignment ?? "center" }, void 0, children) : sb("hstack", { spacing: spec.spacing ?? 0, alignment: spec.alignment ?? "center" }, void 0, children);
1549
+ case "layoutValue":
1550
+ return node;
1551
+ case "safeAreaInset": {
1552
+ const spec = value;
1553
+ const vertical = spec.edge === "top" || spec.edge === "bottom";
1554
+ const before = spec.edge === "top" || spec.edge === "leading";
1555
+ const children = before ? [createElement(Fragment$1, { key: "inset" }, spec.content), createElement(Fragment$1, { key: "content" }, node)] : [createElement(Fragment$1, { key: "content" }, node), createElement(Fragment$1, { key: "inset" }, spec.content)];
1556
+ return vertical ? sb("vstack", { spacing: spec.spacing ?? 0, alignment: spec.alignment ?? "center" }, void 0, children) : sb("hstack", { spacing: spec.spacing ?? 0, alignment: spec.alignment ?? "center" }, void 0, children);
1557
+ }
1558
+ case "popover":
1559
+ sides.push(createElement(SheetPresenter, value));
1560
+ return node;
1561
+ case "redacted":
1562
+ return withEnvironment({ redacted: Boolean(value) }, node);
1563
+ case "keyboardShortcut":
1564
+ return node;
1565
+ case "onKeyPress":
1566
+ sides.push(createElement(KeyPressListener, { spec: value }));
1567
+ return node;
1568
+ case "sensoryFeedback": {
1569
+ const spec = value;
1570
+ sides.push(createElement(SensoryFeedbackPlayer, spec));
1571
+ return node;
1572
+ }
1573
+ case "textCase":
1574
+ return withEnvironment({ textCase: value }, node);
1575
+ case "coordinateSpace":
1576
+ return createElement(CoordinateSpace, { name: value }, node);
1577
+ case "scrollEdgeEffectStyle":
1578
+ return withScrollSettings(edgeStyleSettings(value), node);
1579
+ case "scrollEdgeEffectHidden":
1580
+ return withScrollSettings(edgeHiddenSettings(value), node);
1581
+ case "contentMargins":
1582
+ return withScrollSettings(marginSettings(value), node);
1583
+ case "containerRelativeFrame":
1584
+ return styled({ containerRelativeFrame: containerRelativeFrame(value) }, node);
1585
+ case "visualEffect":
1586
+ return createElement(VisualEffectView, { effect: value }, node);
1587
+ case "scrollTransition": {
1588
+ const spec = typeof value === "function" ? { transition: value } : value;
1589
+ return createElement(ScrollTransitionView, { spec }, node);
1590
+ }
1591
+ case "contentTransition": {
1592
+ if (value === "identity") return node;
1593
+ if (typeof value === "object") {
1594
+ const countsDown = value.numericText.countsDown;
1595
+ return styled({ contentTransition: { kind: "numericText", ...countsDown !== void 0 ? { countsDown } : {} } }, node);
1596
+ }
1597
+ return styled({ contentTransition: { kind: value } }, node);
1598
+ }
1599
+ case "modifiers": {
1600
+ let result = node;
1601
+ for (const extra of value) {
1602
+ result = wrap(result, Object.entries(extra), sides);
1603
+ }
1604
+ return result;
1605
+ }
1606
+ default: {
1607
+ const unknown = key;
1608
+ throw new Error(`Unknown modifier ${String(unknown)}`);
1609
+ }
1610
+ }
1611
+ }
1612
+ const ListSelectionContext = createContext(null);
1613
+ function Row({ tag, onDelete, deletable, onMove, movable, index, containerIndex, children }) {
1614
+ const selection = useContext(ListSelectionContext);
1615
+ const selectable = selection !== null && tag !== void 0;
1616
+ const canDelete = onDelete !== void 0 && deletable !== false;
1617
+ const canMove = onMove !== void 0 && movable !== false;
1618
+ if (!selectable && !canDelete && !canMove) return children;
1619
+ const props = {};
1620
+ if (selectable) {
1621
+ props["selectable"] = true;
1622
+ props["selected"] = selection.isSelected(tag);
1623
+ }
1624
+ if (canDelete) props["deletable"] = true;
1625
+ if (canMove) props["movable"] = true;
1626
+ return sb(
1627
+ "listrow",
1628
+ props,
1629
+ {
1630
+ tap: () => selectable && selection.select(tag),
1631
+ delete: () => onDelete?.(),
1632
+ move: (event) => {
1633
+ const start = (containerIndex ?? index ?? 0) - (index ?? 0);
1634
+ onMove?.(Math.max(0, event.to - start));
1635
+ }
1636
+ },
1637
+ children
1638
+ );
1639
+ }
1640
+ const LAZY_BATCH = 12;
1641
+ const LazyContext = createContext(null);
1642
+ function LazyGroup({ rows, start = 0, wrap: wrap2 }) {
1643
+ const axis = useContext(LazyContext);
1644
+ const request = useContext(ScrollRequestContext);
1645
+ const [count, setCount] = useState(LAZY_BATCH);
1646
+ const target = request ? rows.findIndex((row) => rowMatches(row, request.id)) : -1;
1647
+ const needed = target >= 0 ? Math.ceil((target + 1) / LAZY_BATCH) * LAZY_BATCH : 0;
1648
+ useEffect(() => {
1649
+ if (needed > count) setCount(needed);
1650
+ }, [needed, count]);
1651
+ const visible = Math.max(count, needed);
1652
+ const shown = axis === null ? rows : rows.slice(0, visible);
1653
+ const built = shown.map((row, index) => wrap2 ? wrap2(row, start + index) : row);
1654
+ if (axis === null || shown.length >= rows.length) return built;
1655
+ return [
1656
+ ...built,
1657
+ createElement(
1658
+ LazySpacer,
1659
+ { key: `lazy-${visible}`, axis, remaining: rows.length - shown.length, more: () => setCount(visible + LAZY_BATCH) }
1660
+ )
1661
+ ];
1662
+ }
1663
+ function LazySpacer({ axis, remaining, more }) {
1664
+ return sb("lazyspacer", { axis, remaining }, { lazy: more });
1665
+ }
1666
+ function rowMatches(row, id) {
1667
+ if (row.key !== null && row.key === String(id)) return true;
1668
+ let element = row;
1669
+ for (let depth = 0; element && depth < 3; depth++) {
1670
+ const props = element.props;
1671
+ if (props.scrollID === id) return true;
1672
+ element = isValidElement(props.children) ? props.children : null;
1673
+ }
1674
+ return false;
1675
+ }
1676
+ function VStack(props) {
1677
+ const { own, modifiers } = splitProps(props);
1678
+ const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
1679
+ if (own.scrollTargetLayout) stack["scrollTarget"] = true;
1680
+ return applyModifiers(sb("vstack", stack, void 0, own.children), modifiers);
1681
+ }
1682
+ function HStack(props) {
1683
+ const { own, modifiers } = splitProps(props);
1684
+ const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
1685
+ if (own.scrollTargetLayout) stack["scrollTarget"] = true;
1686
+ return applyModifiers(sb("hstack", stack, void 0, own.children), modifiers);
1687
+ }
1688
+ function ZStack(props) {
1689
+ const { own, modifiers } = splitProps(props);
1690
+ return applyModifiers(sb("zstack", { alignment: own.alignment ?? "center" }, void 0, own.children), modifiers);
1691
+ }
1692
+ function Spacer(props) {
1693
+ const { own, modifiers } = splitProps(props);
1694
+ return applyModifiers(sb("spacer", { minLength: own.minLength ?? null }), modifiers);
1695
+ }
1696
+ function Divider(props) {
1697
+ const { modifiers } = splitProps(props);
1698
+ return applyModifiers(sb("divider", {}), modifiers);
1699
+ }
1700
+ function ScrollView(props) {
1701
+ const { own, modifiers } = splitProps(props);
1702
+ const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
1703
+ const ownSettings = takeScrollSettings(modifiers);
1704
+ const settings = useScrollSettings(ownSettings);
1705
+ const axes = own.axes ?? "vertical";
1706
+ const scroll = { axes, ...refresh.props };
1707
+ if (own.scrollTargetBehavior) scroll["snap"] = own.scrollTargetBehavior;
1708
+ if (own.scrollDismissesKeyboard) scroll["dismissesKeyboard"] = true;
1709
+ const edgeEffect = edgeEffectProp(settings);
1710
+ if (edgeEffect) scroll["edgeEffect"] = edgeEffect;
1711
+ const content = marginedContent(own.children, settings.margins, axes === "horizontal" ? "horizontal" : "vertical");
1712
+ return applyModifiers(sb("scrollview", scroll, refresh.handlers, providingScrollSettings(ownSettings, content)), modifiers);
1713
+ }
1714
+ function takeScrollSettings(modifiers) {
1715
+ let settings = {};
1716
+ const own = [];
1717
+ for (const key of ["scrollEdgeEffectStyle", "scrollEdgeEffectHidden", "contentMargins"]) {
1718
+ const value = takeModifier(modifiers, key);
1719
+ if (value === void 0) continue;
1720
+ if (key === "scrollEdgeEffectStyle") own.push(edgeStyleSettings(value));
1721
+ else if (key === "scrollEdgeEffectHidden") own.push(edgeHiddenSettings(value));
1722
+ else own.push(marginSettings(value));
1723
+ }
1724
+ for (const each of own) settings = mergeScrollSettings(settings, each);
1725
+ return settings;
1726
+ }
1727
+ function providingScrollSettings(settings, children) {
1728
+ return Object.keys(settings).length > 0 ? withScrollSettings(settings, children) : children;
1729
+ }
1730
+ function useRefreshable(own) {
1731
+ const environment = useViewEnvironment();
1732
+ const refresh = own ?? environment.refresh;
1733
+ const [refreshing, setRefreshing] = useState(false);
1734
+ if (!refresh) return { props: {} };
1735
+ return {
1736
+ props: { refreshable: true, refreshing },
1737
+ handlers: {
1738
+ refresh: () => {
1739
+ if (refreshing) return;
1740
+ setRefreshing(true);
1741
+ Promise.resolve().then(refresh).catch((error) => console.error(error)).finally(() => setRefreshing(false));
1742
+ }
1743
+ }
1744
+ };
1745
+ }
1746
+ function Group(props) {
1747
+ const { own, modifiers } = splitProps(props);
1748
+ if (modifiers.length === 0) return own.children;
1749
+ return Children.map(own.children, (child) => applyModifiers(child, modifiers));
1750
+ }
1751
+ function moveItems(items, offsets, to) {
1752
+ const moving = new Set(offsets);
1753
+ const picked = items.filter((_, index) => moving.has(index));
1754
+ const rest = items.filter((_, index) => !moving.has(index));
1755
+ const before = offsets.filter((offset) => offset < to).length;
1756
+ const at = to - before;
1757
+ return [...rest.slice(0, at), ...picked, ...rest.slice(at)];
1758
+ }
1759
+ function ForEach(props) {
1760
+ const { own, modifiers } = splitProps(props);
1761
+ const rows = own.data.map((element, index) => {
1762
+ const key = own.id ? own.id(element, index) : keyOf(element, index);
1763
+ const content = applyModifiers(own.children(element, index), modifiers);
1764
+ if (!own.onDelete && !own.onMove) return createElement(Fragment$1, { key }, content);
1765
+ const { onDelete, onMove } = own;
1766
+ const row = { tag: key, index };
1767
+ if (onDelete) {
1768
+ row.onDelete = () => onDelete([index]);
1769
+ row.deletable = !own.deleteDisabled?.(element, index);
1770
+ }
1771
+ if (onMove) {
1772
+ row.onMove = (to) => onMove([index], to);
1773
+ row.movable = !own.moveDisabled?.(element, index);
1774
+ }
1775
+ return createElement(Row, { key, ...row }, content);
1776
+ });
1777
+ return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
1778
+ }
1779
+ function keyOf(element, index) {
1780
+ if (typeof element === "string" || typeof element === "number") return element;
1781
+ if (typeof element === "object" && element !== null && "id" in element) {
1782
+ const id = element.id;
1783
+ if (typeof id === "string" || typeof id === "number") return id;
1784
+ }
1785
+ return index;
1786
+ }
1787
+ function flattenChildren(children, options = {}) {
1788
+ const result = [];
1789
+ const visit = (node) => {
1790
+ if (node === null || node === void 0 || typeof node === "boolean") return;
1791
+ if (Array.isArray(node)) {
1792
+ node.forEach(visit);
1793
+ return;
1794
+ }
1795
+ if (!isValidElement(node)) return;
1796
+ const element = node;
1797
+ if (element.type === Fragment$1) {
1798
+ const inner = element.props["children"];
1799
+ if (element.key !== null && isValidElement(inner) && inner.key === null && inner.type !== Fragment$1) {
1800
+ visit({ ...inner, key: element.key });
1801
+ return;
1802
+ }
1803
+ visit(inner);
1804
+ return;
1805
+ }
1806
+ if (element.type === ForEach) {
1807
+ visit(ForEach(element.props));
1808
+ return;
1597
1809
  }
1598
- case "popover":
1599
- sides.push(createElement(SheetPresenter, value));
1600
- return node;
1601
- case "redacted":
1602
- return withEnvironment({ redacted: Boolean(value) }, node);
1603
- case "keyboardShortcut":
1604
- return node;
1605
- case "onKeyPress":
1606
- sides.push(createElement(KeyPressListener, { spec: value }));
1607
- return node;
1608
- case "sensoryFeedback": {
1609
- const spec = value;
1610
- sides.push(createElement(SensoryFeedbackPlayer, spec));
1611
- return node;
1810
+ if (element.type === LazyGroup && !options.keepLazy) {
1811
+ visit(element.props.rows);
1812
+ return;
1612
1813
  }
1613
- case "textCase":
1614
- return withEnvironment({ textCase: value }, node);
1615
- case "coordinateSpace":
1616
- return createElement(CoordinateSpace, { name: value }, node);
1617
- case "contentTransition": {
1618
- if (value === "identity") return node;
1619
- if (typeof value === "object") {
1620
- const countsDown = value.numericText.countsDown;
1621
- return styled({ contentTransition: { kind: "numericText", ...countsDown !== void 0 ? { countsDown } : {} } }, node);
1622
- }
1623
- return styled({ contentTransition: { kind: value } }, node);
1814
+ result.push(element);
1815
+ };
1816
+ visit(children);
1817
+ return result;
1818
+ }
1819
+ function GridItem(spec = {}) {
1820
+ const dimension = (n) => n === void 0 || n === Infinity ? "infinity" : n;
1821
+ let size;
1822
+ if (spec.size && "fixed" in spec.size) size = { kind: "fixed", value: spec.size.fixed };
1823
+ else if (spec.size && "adaptive" in spec.size) {
1824
+ size = { kind: "adaptive", minimum: spec.size.adaptive.minimum, maximum: dimension(spec.size.adaptive.maximum) };
1825
+ } else {
1826
+ const flexible = spec.size && "flexible" in spec.size ? spec.size.flexible : {};
1827
+ size = { kind: "flexible", minimum: flexible.minimum ?? 10, maximum: dimension(flexible.maximum) };
1828
+ }
1829
+ return { size, spacing: spec.spacing ?? null, alignment: spec.alignment ?? null };
1830
+ }
1831
+ GridItem.flexible = (options = {}) => GridItem({ size: { flexible: options }, spacing: options.spacing, alignment: options.alignment });
1832
+ GridItem.fixed = (value, options = {}) => GridItem({ size: { fixed: value }, spacing: options.spacing, alignment: options.alignment });
1833
+ GridItem.adaptive = (options) => GridItem({ size: { adaptive: options }, spacing: options.spacing, alignment: options.alignment });
1834
+ function LazyVGrid(props) {
1835
+ const { own, modifiers } = splitProps(props);
1836
+ return applyModifiers(
1837
+ sb("lazyvgrid", { columns: own.columns, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" }, void 0, own.children),
1838
+ modifiers
1839
+ );
1840
+ }
1841
+ function LazyHGrid(props) {
1842
+ const { own, modifiers } = splitProps(props);
1843
+ return applyModifiers(
1844
+ sb("lazyhgrid", { rows: own.rows, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" }, void 0, own.children),
1845
+ modifiers
1846
+ );
1847
+ }
1848
+ function Grid(props) {
1849
+ const { own, modifiers } = splitProps(props);
1850
+ return applyModifiers(
1851
+ sb(
1852
+ "grid",
1853
+ { horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
1854
+ void 0,
1855
+ own.children
1856
+ ),
1857
+ modifiers
1858
+ );
1859
+ }
1860
+ function GridRow(props) {
1861
+ const { own, modifiers } = splitProps(props);
1862
+ return applyModifiers(sb("gridrow", { alignment: own.alignment ?? null }, void 0, own.children), modifiers);
1863
+ }
1864
+ const NO_INSETS = { top: 0, leading: 0, bottom: 0, trailing: 0 };
1865
+ const NO_GEOMETRY = { size: { width: 0, height: 0 }, origin: null, safeArea: NO_INSETS, scrollView: null };
1866
+ function nextGeometry(event, reported) {
1867
+ const hasOrigin = event.x !== void 0 && event.y !== void 0;
1868
+ return {
1869
+ size: { width: event.width, height: event.height },
1870
+ origin: hasOrigin ? { x: event.x, y: event.y } : reported.origin,
1871
+ safeArea: event.safeArea ?? reported.safeArea,
1872
+ // A frame report without a scroll view means the reader is in none.
1873
+ scrollView: hasOrigin ? event.scrollView ?? null : reported.scrollView
1874
+ };
1875
+ }
1876
+ function geometryProxy(reported, spaces, onReadFrame) {
1877
+ return {
1878
+ size: reported.size,
1879
+ frame: (space = "local") => {
1880
+ if (space === "local") return { x: 0, y: 0, ...reported.size };
1881
+ onReadFrame();
1882
+ const origin = reported.origin ?? { x: 0, y: 0 };
1883
+ if (space === "global") return { ...origin, ...reported.size };
1884
+ const named = spaces[space.named];
1885
+ return { x: origin.x - (named?.x ?? 0), y: origin.y - (named?.y ?? 0), ...reported.size };
1886
+ },
1887
+ bounds: () => {
1888
+ onReadFrame();
1889
+ const view = reported.scrollView;
1890
+ if (!view || !reported.origin) return null;
1891
+ return { x: view.x - reported.origin.x, y: view.y - reported.origin.y, width: view.width, height: view.height };
1892
+ },
1893
+ get safeAreaInsets() {
1894
+ onReadFrame();
1895
+ return reported.safeArea;
1624
1896
  }
1625
- case "modifiers": {
1626
- let result = node;
1627
- for (const extra of value) {
1628
- result = wrap(result, Object.entries(extra), sides);
1897
+ };
1898
+ }
1899
+ function GeometryReader(props) {
1900
+ const { own, modifiers } = splitProps(props);
1901
+ const [reported, setReported] = useState(NO_GEOMETRY);
1902
+ const [needsFrame, setNeedsFrame] = useState(false);
1903
+ let readFrame = false;
1904
+ const proxy = geometryProxy(reported, useCoordinateSpaces(), () => {
1905
+ readFrame = true;
1906
+ });
1907
+ const content = own.children(proxy);
1908
+ useEffect(() => {
1909
+ if (readFrame && !needsFrame) setNeedsFrame(true);
1910
+ });
1911
+ return applyModifiers(
1912
+ sb(
1913
+ "geometry",
1914
+ needsFrame ? { reportsFrame: true } : {},
1915
+ {
1916
+ geometry: (event) => {
1917
+ const next = nextGeometry(event, reported);
1918
+ if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
1919
+ }
1920
+ },
1921
+ content
1922
+ ),
1923
+ modifiers
1924
+ );
1925
+ }
1926
+ const DEFAULT_VIEW_SPACING = { distance: () => 8 };
1927
+ function subviewTraits(children) {
1928
+ return flattenChildren(children).map((element) => {
1929
+ const props = element.props;
1930
+ return { priority: props.layoutPriority ?? 0, values: props.layoutValue ?? {} };
1931
+ });
1932
+ }
1933
+ const fromDimension = (value) => value === "infinity" ? Infinity : value;
1934
+ const toDimension = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : "infinity";
1935
+ const toSize = (size) => ({
1936
+ width: fromDimension(size.width) ?? 0,
1937
+ height: fromDimension(size.height) ?? 0
1938
+ });
1939
+ const GUIDES = ["leading", "horizontalCenter", "trailing", "top", "verticalCenter", "bottom", "firstTextBaseline", "lastTextBaseline"];
1940
+ function clamp(value, min, max) {
1941
+ return Math.min(Math.max(value, min), max);
1942
+ }
1943
+ function answerLayout(layout, record, traits = []) {
1944
+ const frames = record.children.map(() => null);
1945
+ const subviews = record.children.map((measurement, index) => {
1946
+ const min = toSize(measurement.min);
1947
+ const ideal = toSize(measurement.ideal);
1948
+ const max = toSize(measurement.max);
1949
+ const sizeThatFits = (proposal) => ({
1950
+ width: proposal.width === null ? ideal.width : clamp(proposal.width, min.width, max.width),
1951
+ height: proposal.height === null ? ideal.height : clamp(proposal.height, min.height, max.height)
1952
+ });
1953
+ return {
1954
+ min,
1955
+ ideal,
1956
+ max,
1957
+ priority: traits[index]?.priority ?? 0,
1958
+ values: traits[index]?.values ?? {},
1959
+ spacing: DEFAULT_VIEW_SPACING,
1960
+ sizeThatFits,
1961
+ place: ({ x, y, anchor, proposal }) => {
1962
+ const size2 = sizeThatFits(proposal ?? { width: null, height: null });
1963
+ const point = unitPoint(anchor ?? "topLeading");
1964
+ frames[index] = { x: x - point.x * size2.width, y: y - point.y * size2.height, ...size2 };
1629
1965
  }
1630
- return result;
1966
+ };
1967
+ });
1968
+ const cache = layout.makeCache ? layout.makeCache(subviews) : void 0;
1969
+ const measure = (proposal) => layout.sizeThatFits(proposal, subviews, cache);
1970
+ const size = measure(record.proposal);
1971
+ layout.placeSubviews({ x: 0, y: 0, ...size }, record.proposal, subviews, cache);
1972
+ const placed = frames.map((frame2, index) => {
1973
+ if (frame2) return frame2;
1974
+ const own = subviews[index].sizeThatFits({ width: size.width, height: size.height });
1975
+ return { x: (size.width - own.width) / 2, y: (size.height - own.height) / 2, ...own };
1976
+ });
1977
+ const guides = {};
1978
+ if (layout.explicitAlignment) {
1979
+ const bounds = { x: 0, y: 0, ...size };
1980
+ for (const guide of GUIDES) {
1981
+ const value = layout.explicitAlignment(guide, bounds, record.proposal, subviews, cache);
1982
+ if (value !== null && value !== void 0 && Number.isFinite(value)) guides[guide] = value;
1631
1983
  }
1632
- default: {
1633
- const unknown = key;
1634
- throw new Error(`Unknown modifier ${String(unknown)}`);
1984
+ }
1985
+ return {
1986
+ size,
1987
+ frames: placed,
1988
+ guides,
1989
+ sizes: {
1990
+ min: measure({ width: 0, height: 0 }),
1991
+ ideal: measure({ width: null, height: null }),
1992
+ max: measure({ width: Infinity, height: Infinity })
1635
1993
  }
1994
+ };
1995
+ }
1996
+ function Layout(props) {
1997
+ const { own, modifiers } = splitProps(props);
1998
+ const [record, setRecord] = useState(null);
1999
+ let layoutProps = { proposal: null, size: null, frames: null };
2000
+ const guideModifiers = [];
2001
+ if (record) {
2002
+ const answer = answerLayout(own.layout, record, subviewTraits(own.children));
2003
+ for (const [guide, value] of Object.entries(answer.guides)) guideModifiers.push(["alignmentGuide", { guide, value: () => value }]);
2004
+ const encode = (size) => ({ width: toDimension(size.width), height: toDimension(size.height) });
2005
+ const round2 = (value) => Math.round(value * 100) / 100;
2006
+ layoutProps = {
2007
+ proposal: {
2008
+ width: record.proposal.width === null ? null : toDimension(record.proposal.width),
2009
+ height: record.proposal.height === null ? null : toDimension(record.proposal.height)
2010
+ },
2011
+ size: { width: round2(answer.size.width), height: round2(answer.size.height) },
2012
+ frames: answer.frames.map((frame2) => ({ x: round2(frame2.x), y: round2(frame2.y), width: round2(frame2.width), height: round2(frame2.height) })),
2013
+ sizes: { min: encode(answer.sizes.min), ideal: encode(answer.sizes.ideal), max: encode(answer.sizes.max) }
2014
+ };
2015
+ }
2016
+ return applyModifiers(
2017
+ sb(
2018
+ "layout",
2019
+ layoutProps,
2020
+ {
2021
+ layout: (event) => {
2022
+ const proposal = event.proposal;
2023
+ setRecord({
2024
+ proposal: { width: fromDimension(proposal.width), height: fromDimension(proposal.height) },
2025
+ children: event.children
2026
+ });
2027
+ }
2028
+ },
2029
+ own.children
2030
+ ),
2031
+ [...guideModifiers, ...modifiers]
2032
+ );
2033
+ }
2034
+ const IDENTITY$1 = {
2035
+ offsetX: 0,
2036
+ offsetY: 0,
2037
+ scaleX: 1,
2038
+ scaleY: 1,
2039
+ rotation: 0,
2040
+ opacity: 1,
2041
+ blur: 0,
2042
+ brightness: 0,
2043
+ contrast: 1,
2044
+ saturation: 1,
2045
+ grayscale: 0,
2046
+ hueRotation: 0
2047
+ };
2048
+ class VisualEffect {
2049
+ /** @internal */
2050
+ constructor(values = IDENTITY$1) {
2051
+ this.values = values;
2052
+ }
2053
+ values;
2054
+ with(patch) {
2055
+ return new VisualEffect({ ...this.values, ...patch });
2056
+ }
2057
+ offset(offset) {
2058
+ return this.with({ offsetX: this.values.offsetX + (offset.x ?? 0), offsetY: this.values.offsetY + (offset.y ?? 0) });
2059
+ }
2060
+ scaleEffect(scale, anchor) {
2061
+ const x = typeof scale === "number" ? scale : scale.x ?? 1;
2062
+ const y = typeof scale === "number" ? scale : scale.y ?? 1;
2063
+ return this.with({ scaleX: this.values.scaleX * x, scaleY: this.values.scaleY * y, ...anchor !== void 0 ? { scaleAnchor: unitPoint(anchor) } : {} });
2064
+ }
2065
+ /** Degrees. */
2066
+ rotationEffect(degrees, anchor) {
2067
+ return this.with({ rotation: this.values.rotation + degrees, ...anchor !== void 0 ? { rotationAnchor: unitPoint(anchor) } : {} });
2068
+ }
2069
+ rotation3DEffect(spec) {
2070
+ const rotation = { angle: spec.angle, axis: spec.axis };
2071
+ if (spec.anchor !== void 0) rotation.anchor = unitPoint(spec.anchor);
2072
+ if (spec.perspective !== void 0) rotation.perspective = spec.perspective;
2073
+ return this.with({ rotation3D: rotation });
2074
+ }
2075
+ opacity(opacity2) {
2076
+ return this.with({ opacity: this.values.opacity * opacity2 });
2077
+ }
2078
+ blur(radius) {
2079
+ return this.with({ blur: this.values.blur + radius });
2080
+ }
2081
+ brightness(amount) {
2082
+ return this.with({ brightness: this.values.brightness + amount });
2083
+ }
2084
+ contrast(amount) {
2085
+ return this.with({ contrast: this.values.contrast * amount });
2086
+ }
2087
+ saturation(amount) {
2088
+ return this.with({ saturation: this.values.saturation * amount });
2089
+ }
2090
+ grayscale(amount) {
2091
+ return this.with({ grayscale: Math.min(1, this.values.grayscale + amount) });
2092
+ }
2093
+ /** Degrees. */
2094
+ hueRotation(degrees) {
2095
+ return this.with({ hueRotation: this.values.hueRotation + degrees });
2096
+ }
2097
+ }
2098
+ const EMPTY_EFFECT = new VisualEffect();
2099
+ const round = (value) => Math.round(value * 1e3) / 1e3;
2100
+ function effectStyle(values) {
2101
+ const style = {};
2102
+ if (values.offsetX !== 0 || values.offsetY !== 0) style.offset = { x: round(values.offsetX), y: round(values.offsetY) };
2103
+ if (values.scaleX !== 1 || values.scaleY !== 1) {
2104
+ style.scale = { x: round(values.scaleX), y: round(values.scaleY) };
2105
+ if (values.scaleAnchor) style.scaleAnchor = values.scaleAnchor;
2106
+ }
2107
+ if (values.rotation !== 0) {
2108
+ style.rotation = round(values.rotation);
2109
+ if (values.rotationAnchor) style.rotationAnchor = values.rotationAnchor;
1636
2110
  }
2111
+ if (values.rotation3D && values.rotation3D.angle !== 0) style.rotation3D = { ...values.rotation3D, angle: round(values.rotation3D.angle) };
2112
+ if (values.opacity !== 1) style.opacity = round(values.opacity);
2113
+ if (values.blur !== 0) style.blur = round(values.blur);
2114
+ if (values.brightness !== 0) style.brightness = round(values.brightness);
2115
+ if (values.contrast !== 1) style.contrast = round(values.contrast);
2116
+ if (values.saturation !== 1) style.saturation = round(values.saturation);
2117
+ if (values.grayscale !== 0) style.grayscale = round(values.grayscale);
2118
+ if (values.hueRotation !== 0) style.hueRotation = round(values.hueRotation);
2119
+ return style;
1637
2120
  }
1638
- const ScrollRequestContext = createContext(null);
1639
- let nextSerial = 1;
1640
- function ScrollViewReader({ children }) {
1641
- const [request, setRequest] = useState(null);
1642
- const proxy = {
1643
- scrollTo: (id, anchor) => setRequest({ id, anchor: anchor === void 0 ? null : unitPoint(anchor), serial: nextSerial++ })
2121
+ function interpolateEffects(from, to, t) {
2122
+ const mix = (a, b) => a + (b - a) * t;
2123
+ const result = {
2124
+ offsetX: mix(from.offsetX, to.offsetX),
2125
+ offsetY: mix(from.offsetY, to.offsetY),
2126
+ scaleX: mix(from.scaleX, to.scaleX),
2127
+ scaleY: mix(from.scaleY, to.scaleY),
2128
+ rotation: mix(from.rotation, to.rotation),
2129
+ opacity: mix(from.opacity, to.opacity),
2130
+ blur: mix(from.blur, to.blur),
2131
+ brightness: mix(from.brightness, to.brightness),
2132
+ contrast: mix(from.contrast, to.contrast),
2133
+ saturation: mix(from.saturation, to.saturation),
2134
+ grayscale: mix(from.grayscale, to.grayscale),
2135
+ hueRotation: mix(from.hueRotation, to.hueRotation)
1644
2136
  };
1645
- return /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: request, children: children(proxy) });
1646
- }
1647
- function ScrollTarget({ id, children }) {
1648
- const request = useContext(ScrollRequestContext);
1649
- if (request && request.id === id) return styled({ scrollID: true, scrollTo: { anchor: request.anchor, serial: request.serial } }, children);
1650
- return styled({ scrollID: true }, children);
2137
+ const scaleAnchor = to.scaleAnchor ?? from.scaleAnchor;
2138
+ if (scaleAnchor) result.scaleAnchor = scaleAnchor;
2139
+ const rotationAnchor = to.rotationAnchor ?? from.rotationAnchor;
2140
+ if (rotationAnchor) result.rotationAnchor = rotationAnchor;
2141
+ const rotation3D = to.rotation3D ?? from.rotation3D;
2142
+ if (rotation3D) result.rotation3D = { ...rotation3D, angle: mix(from.rotation3D?.angle ?? 0, to.rotation3D?.angle ?? 0) };
2143
+ return result;
1651
2144
  }
1652
- const ListSelectionContext = createContext(null);
1653
- function Row({ tag, onDelete, deletable, onMove, movable, index, containerIndex, children }) {
1654
- const selection = useContext(ListSelectionContext);
1655
- const selectable = selection !== null && tag !== void 0;
1656
- const canDelete = onDelete !== void 0 && deletable !== false;
1657
- const canMove = onMove !== void 0 && movable !== false;
1658
- if (!selectable && !canDelete && !canMove) return children;
1659
- const props = {};
1660
- if (selectable) {
1661
- props["selectable"] = true;
1662
- props["selected"] = selection.isSelected(tag);
1663
- }
1664
- if (canDelete) props["deletable"] = true;
1665
- if (canMove) props["movable"] = true;
2145
+ function EffectBox({
2146
+ render,
2147
+ alwaysFrame,
2148
+ animationToken,
2149
+ children
2150
+ }) {
2151
+ const [reported, setReported] = useState(NO_GEOMETRY);
2152
+ const [needsFrame, setNeedsFrame] = useState(alwaysFrame);
2153
+ let readFrame = false;
2154
+ const style = render(reported, () => {
2155
+ readFrame = true;
2156
+ });
2157
+ useEffect(() => {
2158
+ if (readFrame && !needsFrame) setNeedsFrame(true);
2159
+ });
2160
+ let content = Object.keys(style).length > 0 ? sb("styled", { style }, void 0, children) : children;
2161
+ if (animationToken) content = sb("styled", { style: { animation: { type: "default" }, animationToken: animationToken(reported) } }, void 0, content);
1666
2162
  return sb(
1667
- "listrow",
1668
- props,
2163
+ "zstack",
2164
+ { alignment: "center", reportsSize: true, ...needsFrame ? { reportsFrame: true } : {} },
1669
2165
  {
1670
- tap: () => selectable && selection.select(tag),
1671
- delete: () => onDelete?.(),
1672
- move: (event) => {
1673
- const start = (containerIndex ?? index ?? 0) - (index ?? 0);
1674
- onMove?.(Math.max(0, event.to - start));
2166
+ geometry: (event) => {
2167
+ const next = nextGeometry(event, reported);
2168
+ if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
1675
2169
  }
1676
2170
  },
1677
- children
2171
+ content
1678
2172
  );
1679
2173
  }
1680
- const LAZY_BATCH = 12;
1681
- const LazyContext = createContext(null);
1682
- function LazyGroup({ rows, start = 0, wrap: wrap2 }) {
1683
- const axis = useContext(LazyContext);
1684
- const request = useContext(ScrollRequestContext);
1685
- const [count, setCount] = useState(LAZY_BATCH);
1686
- const target = request ? rows.findIndex((row) => rowMatches(row, request.id)) : -1;
1687
- const needed = target >= 0 ? Math.ceil((target + 1) / LAZY_BATCH) * LAZY_BATCH : 0;
1688
- useEffect(() => {
1689
- if (needed > count) setCount(needed);
1690
- }, [needed, count]);
1691
- const visible = Math.max(count, needed);
1692
- const shown = axis === null ? rows : rows.slice(0, visible);
1693
- const built = shown.map((row, index) => wrap2 ? wrap2(row, start + index) : row);
1694
- if (axis === null || shown.length >= rows.length) return built;
1695
- return [
1696
- ...built,
1697
- createElement(
1698
- LazySpacer,
1699
- { key: `lazy-${visible}`, axis, remaining: rows.length - shown.length, more: () => setCount(visible + LAZY_BATCH) }
1700
- )
1701
- ];
1702
- }
1703
- function LazySpacer({ axis, remaining, more }) {
1704
- return sb("lazyspacer", { axis, remaining }, { lazy: more });
1705
- }
1706
- function rowMatches(row, id) {
1707
- if (row.key !== null && row.key === String(id)) return true;
1708
- let element = row;
1709
- for (let depth = 0; element && depth < 3; depth++) {
1710
- const props = element.props;
1711
- if (props.scrollID === id) return true;
1712
- element = isValidElement(props.children) ? props.children : null;
1713
- }
1714
- return false;
1715
- }
1716
- function VStack(props) {
1717
- const { own, modifiers } = splitProps(props);
1718
- const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
1719
- if (own.scrollTargetLayout) stack["scrollTarget"] = true;
1720
- return applyModifiers(sb("vstack", stack, void 0, own.children), modifiers);
1721
- }
1722
- function HStack(props) {
1723
- const { own, modifiers } = splitProps(props);
1724
- const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
1725
- if (own.scrollTargetLayout) stack["scrollTarget"] = true;
1726
- return applyModifiers(sb("hstack", stack, void 0, own.children), modifiers);
1727
- }
1728
- function ZStack(props) {
1729
- const { own, modifiers } = splitProps(props);
1730
- return applyModifiers(sb("zstack", { alignment: own.alignment ?? "center" }, void 0, own.children), modifiers);
1731
- }
1732
- function Spacer(props) {
1733
- const { own, modifiers } = splitProps(props);
1734
- return applyModifiers(sb("spacer", { minLength: own.minLength ?? null }), modifiers);
1735
- }
1736
- function Divider(props) {
1737
- const { modifiers } = splitProps(props);
1738
- return applyModifiers(sb("divider", {}), modifiers);
1739
- }
1740
- function ScrollView(props) {
1741
- const { own, modifiers } = splitProps(props);
1742
- const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
1743
- const scroll = { axes: own.axes ?? "vertical", ...refresh.props };
1744
- if (own.scrollTargetBehavior) scroll["snap"] = own.scrollTargetBehavior;
1745
- if (own.scrollDismissesKeyboard) scroll["dismissesKeyboard"] = true;
1746
- return applyModifiers(sb("scrollview", scroll, refresh.handlers, own.children), modifiers);
1747
- }
1748
- function useRefreshable(own) {
1749
- const environment = useViewEnvironment();
1750
- const refresh = own ?? environment.refresh;
1751
- const [refreshing, setRefreshing] = useState(false);
1752
- if (!refresh) return { props: {} };
1753
- return {
1754
- props: { refreshable: true, refreshing },
1755
- handlers: {
1756
- refresh: () => {
1757
- if (refreshing) return;
1758
- setRefreshing(true);
1759
- Promise.resolve().then(refresh).catch((error) => console.error(error)).finally(() => setRefreshing(false));
1760
- }
1761
- }
1762
- };
1763
- }
1764
- function Group(props) {
1765
- const { own, modifiers } = splitProps(props);
1766
- if (modifiers.length === 0) return own.children;
1767
- return Children.map(own.children, (child) => applyModifiers(child, modifiers));
1768
- }
1769
- function moveItems(items, offsets, to) {
1770
- const moving = new Set(offsets);
1771
- const picked = items.filter((_, index) => moving.has(index));
1772
- const rest = items.filter((_, index) => !moving.has(index));
1773
- const before = offsets.filter((offset) => offset < to).length;
1774
- const at = to - before;
1775
- return [...rest.slice(0, at), ...picked, ...rest.slice(at)];
2174
+ function VisualEffectView({ effect, children }) {
2175
+ const spaces = useCoordinateSpaces();
2176
+ return /* @__PURE__ */ jsx(EffectBox, { alwaysFrame: false, render: (reported, markRead) => effectStyle(effect(EMPTY_EFFECT, geometryProxy(reported, spaces, markRead)).values), children });
1776
2177
  }
1777
- function ForEach(props) {
1778
- const { own, modifiers } = splitProps(props);
1779
- const rows = own.data.map((element, index) => {
1780
- const key = own.id ? own.id(element, index) : keyOf(element, index);
1781
- const content = applyModifiers(own.children(element, index), modifiers);
1782
- if (!own.onDelete && !own.onMove) return createElement(Fragment$1, { key }, content);
1783
- const { onDelete, onMove } = own;
1784
- const row = { tag: key, index };
1785
- if (onDelete) {
1786
- row.onDelete = () => onDelete([index]);
1787
- row.deletable = !own.deleteDisabled?.(element, index);
1788
- }
1789
- if (onMove) {
1790
- row.onMove = (to) => onMove([index], to);
1791
- row.movable = !own.moveDisabled?.(element, index);
2178
+ const PHASES = {
2179
+ topLeading: { phase: "topLeading", value: -1, isIdentity: false },
2180
+ identity: { phase: "identity", value: 0, isIdentity: true },
2181
+ bottomTrailing: { phase: "bottomTrailing", value: 1, isIdentity: false }
2182
+ };
2183
+ function scrollProgress(reported, axis) {
2184
+ const view = reported.scrollView;
2185
+ const origin = reported.origin;
2186
+ if (!view || !origin) return 0;
2187
+ const horizontal = (axis ?? view.axis) === "horizontal";
2188
+ const start = horizontal ? origin.x : origin.y;
2189
+ const length = horizontal ? reported.size.width : reported.size.height;
2190
+ const viewStart = horizontal ? view.x : view.y;
2191
+ const viewEnd = viewStart + (horizontal ? view.width : view.height);
2192
+ if (length <= 0) return 0;
2193
+ if (start < viewStart) return -Math.min(1, (viewStart - start) / length);
2194
+ if (start + length > viewEnd) return Math.min(1, (start + length - viewEnd) / length);
2195
+ return 0;
2196
+ }
2197
+ function scrollTransitionValues(spec, progress) {
2198
+ const identity = spec.transition(EMPTY_EFFECT, PHASES.identity).values;
2199
+ const configuration = spec.configuration ?? "interactive";
2200
+ if (configuration === "identity" || progress === 0) return identity;
2201
+ const edge = spec.transition(EMPTY_EFFECT, progress < 0 ? PHASES.topLeading : PHASES.bottomTrailing).values;
2202
+ if (configuration === "animated") return edge;
2203
+ return interpolateEffects(identity, edge, Math.abs(progress));
2204
+ }
2205
+ function ScrollTransitionView({ spec, children }) {
2206
+ return /* @__PURE__ */ jsx(
2207
+ EffectBox,
2208
+ {
2209
+ alwaysFrame: true,
2210
+ render: (reported) => effectStyle(scrollTransitionValues(spec, scrollProgress(reported, spec.axis))),
2211
+ ...spec.configuration === "animated" ? { animationToken: (reported) => Math.sign(scrollProgress(reported, spec.axis)) + 1 } : {},
2212
+ children
1792
2213
  }
1793
- return createElement(Row, { key, ...row }, content);
1794
- });
1795
- return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
2214
+ );
1796
2215
  }
1797
- function keyOf(element, index) {
1798
- if (typeof element === "string" || typeof element === "number") return element;
1799
- if (typeof element === "object" && element !== null && "id" in element) {
1800
- const id = element.id;
1801
- if (typeof id === "string" || typeof id === "number") return id;
2216
+ const r = (n) => {
2217
+ const v = Math.round(n * 100) / 100;
2218
+ return Object.is(v, -0) ? "0" : String(v);
2219
+ };
2220
+ class Path {
2221
+ parts = [];
2222
+ current = null;
2223
+ start = null;
2224
+ constructor(build) {
2225
+ build?.(this);
1802
2226
  }
1803
- return index;
1804
- }
1805
- function flattenChildren(children, options = {}) {
1806
- const result = [];
1807
- const visit = (node) => {
1808
- if (node === null || node === void 0 || typeof node === "boolean") return;
1809
- if (Array.isArray(node)) {
1810
- node.forEach(visit);
1811
- return;
1812
- }
1813
- if (!isValidElement(node)) return;
1814
- const element = node;
1815
- if (element.type === Fragment$1) {
1816
- const inner = element.props["children"];
1817
- if (element.key !== null && isValidElement(inner) && inner.key === null && inner.type !== Fragment$1) {
1818
- visit({ ...inner, key: element.key });
1819
- return;
1820
- }
1821
- visit(inner);
1822
- return;
1823
- }
1824
- if (element.type === ForEach) {
1825
- visit(ForEach(element.props));
1826
- return;
1827
- }
1828
- if (element.type === LazyGroup && !options.keepLazy) {
1829
- visit(element.props.rows);
1830
- return;
2227
+ /** `Path(rect)` */
2228
+ static rect(rect) {
2229
+ return new Path().addRect(rect);
2230
+ }
2231
+ /** `Path(roundedRect:cornerRadius:)` */
2232
+ static roundedRect(rect, cornerRadius) {
2233
+ return new Path().addRoundedRect(rect, cornerRadius);
2234
+ }
2235
+ /** `Path(ellipseIn:)` */
2236
+ static ellipse(rect) {
2237
+ return new Path().addEllipse(rect);
2238
+ }
2239
+ move(to) {
2240
+ this.parts.push(`M${r(to.x)} ${r(to.y)}`);
2241
+ this.current = to;
2242
+ this.start = to;
2243
+ return this;
2244
+ }
2245
+ addLine(to) {
2246
+ if (!this.current) return this.move(to);
2247
+ this.parts.push(`L${r(to.x)} ${r(to.y)}`);
2248
+ this.current = to;
2249
+ return this;
2250
+ }
2251
+ addLines(points) {
2252
+ points.forEach((point, index) => index === 0 ? this.move(point) : this.addLine(point));
2253
+ return this;
2254
+ }
2255
+ addQuadCurve(to, control) {
2256
+ if (!this.current) this.move(control);
2257
+ this.parts.push(`Q${r(control.x)} ${r(control.y)} ${r(to.x)} ${r(to.y)}`);
2258
+ this.current = to;
2259
+ return this;
2260
+ }
2261
+ addCurve(to, control1, control2) {
2262
+ if (!this.current) this.move(control1);
2263
+ this.parts.push(`C${r(control1.x)} ${r(control1.y)} ${r(control2.x)} ${r(control2.y)} ${r(to.x)} ${r(to.y)}`);
2264
+ this.current = to;
2265
+ return this;
2266
+ }
2267
+ /**
2268
+ * `addArc(center:radius:startAngle:endAngle:clockwise:)`, angles in
2269
+ * degrees. As in SwiftUI's flipped coordinates, `clockwise: false` draws
2270
+ * clockwise on screen.
2271
+ */
2272
+ addArc(center, radius, startAngle, endAngle, clockwise) {
2273
+ const rad = (deg) => deg * Math.PI / 180;
2274
+ const point = (deg) => ({ x: center.x + radius * Math.cos(rad(deg)), y: center.y + radius * Math.sin(rad(deg)) });
2275
+ const from = point(startAngle);
2276
+ if (this.current) this.addLine(from);
2277
+ else this.move(from);
2278
+ const sweepPositive = !clockwise;
2279
+ let delta = endAngle - startAngle;
2280
+ if (sweepPositive) while (delta < 0) delta += 360;
2281
+ else while (delta > 0) delta -= 360;
2282
+ if (Math.abs(delta) >= 360) {
2283
+ const half = point(startAngle + (sweepPositive ? 180 : -180));
2284
+ const flag = sweepPositive ? 1 : 0;
2285
+ this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(half.x)} ${r(half.y)}`);
2286
+ this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(from.x)} ${r(from.y)}`);
2287
+ this.current = from;
2288
+ return this;
1831
2289
  }
1832
- result.push(element);
1833
- };
1834
- visit(children);
1835
- return result;
1836
- }
1837
- function GridItem(spec = {}) {
1838
- const dimension = (n) => n === void 0 || n === Infinity ? "infinity" : n;
1839
- let size;
1840
- if (spec.size && "fixed" in spec.size) size = { kind: "fixed", value: spec.size.fixed };
1841
- else if (spec.size && "adaptive" in spec.size) {
1842
- size = { kind: "adaptive", minimum: spec.size.adaptive.minimum, maximum: dimension(spec.size.adaptive.maximum) };
1843
- } else {
1844
- const flexible = spec.size && "flexible" in spec.size ? spec.size.flexible : {};
1845
- size = { kind: "flexible", minimum: flexible.minimum ?? 10, maximum: dimension(flexible.maximum) };
2290
+ const to = point(startAngle + delta);
2291
+ const large = Math.abs(delta) > 180 ? 1 : 0;
2292
+ this.parts.push(`A${r(radius)} ${r(radius)} 0 ${large} ${sweepPositive ? 1 : 0} ${r(to.x)} ${r(to.y)}`);
2293
+ this.current = to;
2294
+ return this;
2295
+ }
2296
+ addRect(rect) {
2297
+ this.move({ x: rect.x, y: rect.y });
2298
+ this.addLine({ x: rect.x + rect.width, y: rect.y });
2299
+ this.addLine({ x: rect.x + rect.width, y: rect.y + rect.height });
2300
+ this.addLine({ x: rect.x, y: rect.y + rect.height });
2301
+ return this.closeSubpath();
2302
+ }
2303
+ addRoundedRect(rect, cornerRadius) {
2304
+ const c = Math.max(0, Math.min(cornerRadius, rect.width / 2, rect.height / 2));
2305
+ if (c === 0) return this.addRect(rect);
2306
+ const { x, y, width: w, height: h } = rect;
2307
+ this.move({ x: x + c, y });
2308
+ this.addLine({ x: x + w - c, y });
2309
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w)} ${r(y + c)}`);
2310
+ this.current = { x: x + w, y: y + c };
2311
+ this.addLine({ x: x + w, y: y + h - c });
2312
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w - c)} ${r(y + h)}`);
2313
+ this.current = { x: x + w - c, y: y + h };
2314
+ this.addLine({ x: x + c, y: y + h });
2315
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x)} ${r(y + h - c)}`);
2316
+ this.current = { x, y: y + h - c };
2317
+ this.addLine({ x, y: y + c });
2318
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + c)} ${r(y)}`);
2319
+ this.current = { x: x + c, y };
2320
+ return this.closeSubpath();
2321
+ }
2322
+ addEllipse(rect) {
2323
+ const rx = rect.width / 2;
2324
+ const ry = rect.height / 2;
2325
+ const cx = rect.x + rx;
2326
+ const cy = rect.y + ry;
2327
+ this.move({ x: cx + rx, y: cy });
2328
+ this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx - rx)} ${r(cy)}`);
2329
+ this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx + rx)} ${r(cy)}`);
2330
+ this.current = { x: cx + rx, y: cy };
2331
+ return this.closeSubpath();
2332
+ }
2333
+ addPath(path) {
2334
+ this.parts.push(path.svg());
2335
+ return this;
2336
+ }
2337
+ closeSubpath() {
2338
+ this.parts.push("Z");
2339
+ this.current = this.start;
2340
+ return this;
2341
+ }
2342
+ get isEmpty() {
2343
+ return this.parts.length === 0;
2344
+ }
2345
+ /** The SVG path data. */
2346
+ svg() {
2347
+ return this.parts.join("");
2348
+ }
2349
+ toString() {
2350
+ return this.svg();
1846
2351
  }
1847
- return { size, spacing: spec.spacing ?? null, alignment: spec.alignment ?? null };
1848
- }
1849
- GridItem.flexible = (options = {}) => GridItem({ size: { flexible: options }, spacing: options.spacing, alignment: options.alignment });
1850
- GridItem.fixed = (value, options = {}) => GridItem({ size: { fixed: value }, spacing: options.spacing, alignment: options.alignment });
1851
- GridItem.adaptive = (options) => GridItem({ size: { adaptive: options }, spacing: options.spacing, alignment: options.alignment });
1852
- function LazyVGrid(props) {
1853
- const { own, modifiers } = splitProps(props);
1854
- return applyModifiers(
1855
- sb("lazyvgrid", { columns: own.columns, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" }, void 0, own.children),
1856
- modifiers
1857
- );
1858
- }
1859
- function Grid(props) {
1860
- const { own, modifiers } = splitProps(props);
1861
- return applyModifiers(
1862
- sb(
1863
- "grid",
1864
- { horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
1865
- void 0,
1866
- own.children
1867
- ),
1868
- modifiers
1869
- );
1870
- }
1871
- function GridRow(props) {
1872
- const { own, modifiers } = splitProps(props);
1873
- return applyModifiers(sb("gridrow", { alignment: own.alignment ?? null }, void 0, own.children), modifiers);
1874
2352
  }
1875
2353
  function runStyleOf(props, inherited, nested) {
1876
2354
  const style = { ...inherited };
@@ -2357,7 +2835,10 @@ function List(props) {
2357
2835
  useReportSplitSelection(split, selected, clearSelection);
2358
2836
  const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
2359
2837
  Object.assign(listProps, refresh.props);
2360
- const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, wrapRows(own.children)) });
2838
+ const ownSettings = takeScrollSettings(modifiers);
2839
+ const edgeEffect = edgeEffectProp(useScrollSettings(ownSettings));
2840
+ if (edgeEffect) listProps["edgeEffect"] = edgeEffect;
2841
+ const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, providingScrollSettings(ownSettings, wrapRows(own.children))) });
2361
2842
  return applyModifiers(
2362
2843
  selection ? /* @__PURE__ */ jsx(ListSelectionContext.Provider, { value: selection, children: element }) : element,
2363
2844
  modifiers
@@ -2543,11 +3024,11 @@ function Host(props) {
2543
3024
  if (typeof document === "undefined") return null;
2544
3025
  const element = document.createElement("div");
2545
3026
  element.className = "sb-host-content";
2546
- registerHostContent(key, element);
2547
3027
  return element;
2548
3028
  });
2549
3029
  const bridge = useContextBridge(own.contexts);
2550
3030
  const root = useRef(null);
3031
+ const mounted = useRef(false);
2551
3032
  const sizing = own.sizing ?? "content";
2552
3033
  const style = sizing === "fill" ? { height: "100%", ...own.style } : own.style;
2553
3034
  const tree = bridge(
@@ -2555,6 +3036,8 @@ function Host(props) {
2555
3036
  );
2556
3037
  useLayoutEffect(() => {
2557
3038
  if (!content) return;
3039
+ mounted.current = true;
3040
+ registerHostContent(key, content);
2558
3041
  root.current ??= createRoot(content);
2559
3042
  const current = root.current;
2560
3043
  queueMicrotask(() => {
@@ -2565,168 +3048,19 @@ function Host(props) {
2565
3048
  });
2566
3049
  useEffect(
2567
3050
  () => () => {
2568
- const current = root.current;
2569
- root.current = null;
3051
+ mounted.current = false;
2570
3052
  unregisterHostContent(key);
2571
- queueMicrotask(() => current?.unmount());
3053
+ queueMicrotask(() => {
3054
+ if (mounted.current) return;
3055
+ const current = root.current;
3056
+ root.current = null;
3057
+ current?.unmount();
3058
+ });
2572
3059
  },
2573
3060
  [key]
2574
3061
  );
2575
3062
  return applyModifiers(sb("host", { content: key, sizing }), modifiers);
2576
3063
  }
2577
- const NO_INSETS = { top: 0, leading: 0, bottom: 0, trailing: 0 };
2578
- function GeometryReader(props) {
2579
- const { own, modifiers } = splitProps(props);
2580
- const [reported, setReported] = useState({ size: { width: 0, height: 0 }, origin: null, safeArea: NO_INSETS });
2581
- const [needsFrame, setNeedsFrame] = useState(false);
2582
- const spaces = useCoordinateSpaces();
2583
- let readFrame = false;
2584
- const proxy = {
2585
- size: reported.size,
2586
- frame: (space = "local") => {
2587
- if (space === "local") return { x: 0, y: 0, ...reported.size };
2588
- readFrame = true;
2589
- const origin = reported.origin ?? { x: 0, y: 0 };
2590
- if (space === "global") return { ...origin, ...reported.size };
2591
- const named = spaces[space.named];
2592
- return { x: origin.x - (named?.x ?? 0), y: origin.y - (named?.y ?? 0), ...reported.size };
2593
- },
2594
- get safeAreaInsets() {
2595
- readFrame = true;
2596
- return reported.safeArea;
2597
- }
2598
- };
2599
- const content = own.children(proxy);
2600
- useEffect(() => {
2601
- if (readFrame && !needsFrame) setNeedsFrame(true);
2602
- });
2603
- return applyModifiers(
2604
- sb(
2605
- "geometry",
2606
- needsFrame ? { reportsFrame: true } : {},
2607
- {
2608
- geometry: (event) => {
2609
- const next = {
2610
- size: { width: event.width, height: event.height },
2611
- origin: event.x !== void 0 && event.y !== void 0 ? { x: event.x, y: event.y } : reported.origin,
2612
- safeArea: event.safeArea ?? reported.safeArea
2613
- };
2614
- if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
2615
- }
2616
- },
2617
- content
2618
- ),
2619
- modifiers
2620
- );
2621
- }
2622
- const DEFAULT_VIEW_SPACING = { distance: () => 8 };
2623
- function subviewTraits(children) {
2624
- return flattenChildren(children).map((element) => {
2625
- const props = element.props;
2626
- return { priority: props.layoutPriority ?? 0, values: props.layoutValue ?? {} };
2627
- });
2628
- }
2629
- const fromDimension = (value) => value === "infinity" ? Infinity : value;
2630
- const toDimension = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : "infinity";
2631
- const toSize = (size) => ({
2632
- width: fromDimension(size.width) ?? 0,
2633
- height: fromDimension(size.height) ?? 0
2634
- });
2635
- const GUIDES = ["leading", "horizontalCenter", "trailing", "top", "verticalCenter", "bottom", "firstTextBaseline", "lastTextBaseline"];
2636
- function clamp(value, min, max) {
2637
- return Math.min(Math.max(value, min), max);
2638
- }
2639
- function answerLayout(layout, record, traits = []) {
2640
- const frames = record.children.map(() => null);
2641
- const subviews = record.children.map((measurement, index) => {
2642
- const min = toSize(measurement.min);
2643
- const ideal = toSize(measurement.ideal);
2644
- const max = toSize(measurement.max);
2645
- const sizeThatFits = (proposal) => ({
2646
- width: proposal.width === null ? ideal.width : clamp(proposal.width, min.width, max.width),
2647
- height: proposal.height === null ? ideal.height : clamp(proposal.height, min.height, max.height)
2648
- });
2649
- return {
2650
- min,
2651
- ideal,
2652
- max,
2653
- priority: traits[index]?.priority ?? 0,
2654
- values: traits[index]?.values ?? {},
2655
- spacing: DEFAULT_VIEW_SPACING,
2656
- sizeThatFits,
2657
- place: ({ x, y, anchor, proposal }) => {
2658
- const size2 = sizeThatFits(proposal ?? { width: null, height: null });
2659
- const point = unitPoint(anchor ?? "topLeading");
2660
- frames[index] = { x: x - point.x * size2.width, y: y - point.y * size2.height, ...size2 };
2661
- }
2662
- };
2663
- });
2664
- const cache = layout.makeCache ? layout.makeCache(subviews) : void 0;
2665
- const measure = (proposal) => layout.sizeThatFits(proposal, subviews, cache);
2666
- const size = measure(record.proposal);
2667
- layout.placeSubviews({ x: 0, y: 0, ...size }, record.proposal, subviews, cache);
2668
- const placed = frames.map((frame2, index) => {
2669
- if (frame2) return frame2;
2670
- const own = subviews[index].sizeThatFits({ width: size.width, height: size.height });
2671
- return { x: (size.width - own.width) / 2, y: (size.height - own.height) / 2, ...own };
2672
- });
2673
- const guides = {};
2674
- if (layout.explicitAlignment) {
2675
- const bounds = { x: 0, y: 0, ...size };
2676
- for (const guide of GUIDES) {
2677
- const value = layout.explicitAlignment(guide, bounds, record.proposal, subviews, cache);
2678
- if (value !== null && value !== void 0 && Number.isFinite(value)) guides[guide] = value;
2679
- }
2680
- }
2681
- return {
2682
- size,
2683
- frames: placed,
2684
- guides,
2685
- sizes: {
2686
- min: measure({ width: 0, height: 0 }),
2687
- ideal: measure({ width: null, height: null }),
2688
- max: measure({ width: Infinity, height: Infinity })
2689
- }
2690
- };
2691
- }
2692
- function Layout(props) {
2693
- const { own, modifiers } = splitProps(props);
2694
- const [record, setRecord] = useState(null);
2695
- let layoutProps = { proposal: null, size: null, frames: null };
2696
- const guideModifiers = [];
2697
- if (record) {
2698
- const answer = answerLayout(own.layout, record, subviewTraits(own.children));
2699
- for (const [guide, value] of Object.entries(answer.guides)) guideModifiers.push(["alignmentGuide", { guide, value: () => value }]);
2700
- const encode = (size) => ({ width: toDimension(size.width), height: toDimension(size.height) });
2701
- const round = (value) => Math.round(value * 100) / 100;
2702
- layoutProps = {
2703
- proposal: {
2704
- width: record.proposal.width === null ? null : toDimension(record.proposal.width),
2705
- height: record.proposal.height === null ? null : toDimension(record.proposal.height)
2706
- },
2707
- size: { width: round(answer.size.width), height: round(answer.size.height) },
2708
- frames: answer.frames.map((frame2) => ({ x: round(frame2.x), y: round(frame2.y), width: round(frame2.width), height: round(frame2.height) })),
2709
- sizes: { min: encode(answer.sizes.min), ideal: encode(answer.sizes.ideal), max: encode(answer.sizes.max) }
2710
- };
2711
- }
2712
- return applyModifiers(
2713
- sb(
2714
- "layout",
2715
- layoutProps,
2716
- {
2717
- layout: (event) => {
2718
- const proposal = event.proposal;
2719
- setRecord({
2720
- proposal: { width: fromDimension(proposal.width), height: fromDimension(proposal.height) },
2721
- children: event.children
2722
- });
2723
- }
2724
- },
2725
- own.children
2726
- ),
2727
- [...guideModifiers, ...modifiers]
2728
- );
2729
- }
2730
3064
  function Menu(props) {
2731
3065
  const { own, modifiers } = splitProps(props);
2732
3066
  const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.label;
@@ -3006,9 +3340,9 @@ function Chart(props) {
3006
3340
  }
3007
3341
  const xScale = scaleFor(xValues, { domain: own.xScale?.domain });
3008
3342
  const yScale = scaleFor(yValues, { includesZero: own.yScale?.includesZero ?? true, domain: own.yScale?.domain });
3009
- const round = (n) => Math.round(n * 1e6) / 1e6;
3010
- const ux = (v) => round(xScale.unit(v));
3011
- const uy = (v) => round(1 - yScale.unit(v));
3343
+ const round2 = (n) => Math.round(n * 1e6) / 1e6;
3344
+ const ux = (v) => round2(xScale.unit(v));
3345
+ const uy = (v) => round2(1 - yScale.unit(v));
3012
3346
  let continuousBand = 1;
3013
3347
  if (xScale.kind !== "band") {
3014
3348
  const centers = [...new Set(marks.filter((m) => m.kind === "bar").map((m) => ux(m.props.x)))].sort((a, b) => a - b);
@@ -3054,15 +3388,15 @@ function Chart(props) {
3054
3388
  case "bar": {
3055
3389
  const style = common(mark);
3056
3390
  const [b0, b1] = xScale.kind === "band" ? xScale.band(p.x) : [ux(p.x) - continuousBand / 2, ux(p.x) + continuousBand / 2];
3057
- const center = round((b0 + b1) / 2);
3058
- const half = round((b1 - b0) * 0.8 / 2);
3391
+ const center = round2((b0 + b1) / 2);
3392
+ const half = round2((b1 - b0) * 0.8 / 2);
3059
3393
  const top = uy(Math.max(asNumber(p.y), p.yStart ?? 0));
3060
3394
  const bottom = uy(Math.min(asNumber(p.y), p.yStart ?? 0));
3061
3395
  const rect = {
3062
3396
  kind: "rect",
3063
3397
  ...style,
3064
- x0: p.width !== void 0 ? center : round(center - half),
3065
- x1: p.width !== void 0 ? center : round(center + half),
3398
+ x0: p.width !== void 0 ? center : round2(center - half),
3399
+ x1: p.width !== void 0 ? center : round2(center + half),
3066
3400
  y0: top,
3067
3401
  y1: bottom,
3068
3402
  cornerRadius: p.cornerRadius ?? 0,
@@ -3133,7 +3467,7 @@ function Chart(props) {
3133
3467
  }
3134
3468
  }
3135
3469
  const axis = (scale, position, flipY) => {
3136
- const flip = (u) => round(flipY ? 1 - u : u);
3470
+ const flip = (u) => round2(flipY ? 1 - u : u);
3137
3471
  return {
3138
3472
  position,
3139
3473
  gridLines: scale.gridLines.map(flip),
@@ -3948,6 +4282,7 @@ export {
3948
4282
  Label,
3949
4283
  LabeledContent,
3950
4284
  Layout,
4285
+ LazyHGrid,
3951
4286
  LazyHStack,
3952
4287
  LazyVGrid,
3953
4288
  LazyVStack,
@@ -3956,6 +4291,7 @@ export {
3956
4291
  Link,
3957
4292
  List,
3958
4293
  Menu,
4294
+ NO_GEOMETRY,
3959
4295
  NavigationLink,
3960
4296
  NavigationSplitView,
3961
4297
  NavigationStack,
@@ -3994,6 +4330,7 @@ export {
3994
4330
  VStack,
3995
4331
  VideoPlayer,
3996
4332
  ViewThatFits,
4333
+ VisualEffect,
3997
4334
  ZStack,
3998
4335
  answerLayout,
3999
4336
  color,
@@ -4001,22 +4338,26 @@ export {
4001
4338
  flattenChildren,
4002
4339
  font,
4003
4340
  frame,
4341
+ geometryProxy,
4004
4342
  gradient,
4005
4343
  hex,
4006
4344
  insets,
4007
4345
  keyframeValues,
4008
4346
  mount,
4009
4347
  moveItems,
4348
+ nextGeometry,
4010
4349
  niceStep,
4011
4350
  opacity,
4012
4351
  openURL,
4013
4352
  padding,
4014
4353
  placeholder,
4015
4354
  plainText,
4355
+ providingScrollSettings,
4016
4356
  readBinding,
4017
4357
  rgb,
4018
4358
  shapeStyle,
4019
4359
  system,
4360
+ takeScrollSettings,
4020
4361
  timeTicks,
4021
4362
  unitPoint,
4022
4363
  useAVPlayer,