@swiftbrowser/react 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
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, Children, useEffect, isValidElement, Fragment, useId, 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";
5
5
  import { Renderer } from "@swiftbrowser/web/src/renderer";
6
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
6
+ import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
7
7
  import { applyTypeSizeVariables } from "@swiftbrowser/web/src/typography";
8
8
  import { registerHostContent, notifyHostContentChange, unregisterHostContent } from "@swiftbrowser/web/src/hostContent";
9
9
  import { createRoot } from "react-dom/client";
@@ -534,6 +534,85 @@ 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
+ }
537
616
  const HIERARCHY = { primary: 1, secondary: 2, tertiary: 3, quaternary: 4 };
538
617
  function rgb(r2, g, b, a = 1) {
539
618
  return { r: r2, g, b, a };
@@ -680,369 +759,746 @@ function insets(edges, amount) {
680
759
  }
681
760
  return result;
682
761
  }
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);
701
- }
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
- }
762
+ const ScrollSettingsContext = createContext({});
763
+ function edgesOf(edges) {
764
+ const list = Array.isArray(edges) ? edges : [edges];
765
+ const all = list.some((edge) => edge === "all" || edge === "vertical");
766
+ return { top: all || list.includes("top"), bottom: all || list.includes("bottom") };
819
767
  }
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);
768
+ function edgeStyleSettings(value) {
769
+ const [style, edges] = Array.isArray(value) ? value : [value, "all"];
770
+ const on = edgesOf(edges);
771
+ const name = style === "automatic" ? void 0 : style;
772
+ const result = {};
773
+ if (on.top) result.topStyle = name;
774
+ if (on.bottom) result.bottomStyle = name;
775
+ return result;
826
776
  }
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
- );
777
+ function edgeHiddenSettings(value) {
778
+ const [hidden, edges] = Array.isArray(value) ? value : [value, "all"];
779
+ const on = edgesOf(edges);
780
+ const result = {};
781
+ if (on.top) result.topHidden = hidden;
782
+ if (on.bottom) result.bottomHidden = hidden;
783
+ return result;
842
784
  }
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;
785
+ function marginSettings(value) {
786
+ return { margins: padding(value) };
787
+ }
788
+ function mergeScrollSettings(outer, inner) {
789
+ const result = { ...outer };
790
+ for (const key of ["topStyle", "bottomStyle", "topHidden", "bottomHidden"]) {
791
+ if (key in inner) result[key] = inner[key];
853
792
  }
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;
793
+ if (inner.margins) result.margins = { ...outer.margins, ...inner.margins };
794
+ return result;
858
795
  }
859
- function DropDestination({ action, isTargeted, accepts, children }) {
796
+ function withScrollSettings(settings, children) {
797
+ return createElement(ScrollSettingsExtender, { settings }, children);
798
+ }
799
+ function ScrollSettingsExtender({ settings, children }) {
800
+ const outer = useContext(ScrollSettingsContext);
801
+ return createElement(ScrollSettingsContext.Provider, { value: mergeScrollSettings(outer, settings) }, children);
802
+ }
803
+ function useScrollSettings(own) {
804
+ return mergeScrollSettings(useContext(ScrollSettingsContext), own);
805
+ }
806
+ function edgeEffectProp(settings) {
807
+ const edges = {};
808
+ const top = settings.topHidden ? "hidden" : settings.topStyle;
809
+ const bottom = settings.bottomHidden ? "hidden" : settings.bottomStyle;
810
+ if (top) edges.top = top;
811
+ if (bottom) edges.bottom = bottom;
812
+ return top || bottom ? edges : void 0;
813
+ }
814
+ function marginedContent(children, margins, axis) {
815
+ if (!margins || Object.values(margins).every((value) => !value)) return children;
816
+ const list = Children.toArray(children);
817
+ const content = list.length === 1 ? list[0] : sb(axis === "horizontal" ? "hstack" : "vstack", { spacing: null, alignment: "center" }, void 0, children);
818
+ return sb("styled", { style: { padding: margins } }, void 0, content);
819
+ }
820
+ const ListSelectionContext = createContext(null);
821
+ function Row({ tag, onDelete, deletable, onMove, movable, index, containerIndex, children }) {
822
+ const selection = useContext(ListSelectionContext);
823
+ const selectable = selection !== null && tag !== void 0;
824
+ const canDelete = onDelete !== void 0 && deletable !== false;
825
+ const canMove = onMove !== void 0 && movable !== false;
826
+ if (!selectable && !canDelete && !canMove) return children;
827
+ const props = {};
828
+ if (selectable) {
829
+ props["selectable"] = true;
830
+ props["selected"] = selection.isSelected(tag);
831
+ }
832
+ if (canDelete) props["deletable"] = true;
833
+ if (canMove) props["movable"] = true;
860
834
  return sb(
861
- "dropdestination",
862
- { accepts: accepts ?? [] },
835
+ "listrow",
836
+ props,
863
837
  {
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 });
838
+ tap: () => selectable && selection.select(tag),
839
+ delete: () => onDelete?.(),
840
+ move: (event) => {
841
+ const start = (containerIndex ?? index ?? 0) - (index ?? 0);
842
+ onMove?.(Math.max(0, event.to - start));
875
843
  }
876
844
  },
877
845
  children
878
846
  );
879
847
  }
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?.();
848
+ const ScrollRequestContext = createContext(null);
849
+ let nextSerial = 1;
850
+ function ScrollViewReader({ children }) {
851
+ const [request, setRequest] = useState(null);
852
+ const proxy = {
853
+ scrollTo: (id, anchor) => setRequest({ id, anchor: anchor === void 0 ? null : unitPoint(anchor), serial: nextSerial++ })
886
854
  };
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");
855
+ return /* @__PURE__ */ jsx(ScrollRequestContext.Provider, { value: request, children: children(proxy) });
906
856
  }
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
- );
857
+ function ScrollTarget({ id, children }) {
858
+ const request = useContext(ScrollRequestContext);
859
+ if (request && request.id === id) return styled({ scrollID: true, scrollTo: { anchor: request.anchor, serial: request.serial } }, children);
860
+ return styled({ scrollID: true }, children);
923
861
  }
924
- function Lifecycle({ onAppear, onDisappear }) {
862
+ const LAZY_BATCH = 12;
863
+ const LazyContext = createContext(null);
864
+ function LazyGroup({ rows, start = 0, wrap: wrap2 }) {
865
+ const axis = useContext(LazyContext);
866
+ const request = useContext(ScrollRequestContext);
867
+ const [count, setCount] = useState(LAZY_BATCH);
868
+ const target = request ? rows.findIndex((row) => rowMatches(row, request.id)) : -1;
869
+ const needed = target >= 0 ? Math.ceil((target + 1) / LAZY_BATCH) * LAZY_BATCH : 0;
925
870
  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
- ]);
871
+ if (needed > count) setCount(needed);
872
+ }, [needed, count]);
873
+ const visible = Math.max(count, needed);
874
+ const shown = axis === null ? rows : rows.slice(0, visible);
875
+ const built = shown.map((row, index) => wrap2 ? wrap2(row, start + index) : row);
876
+ if (axis === null || shown.length >= rows.length) return built;
877
+ return [
878
+ ...built,
879
+ createElement(
880
+ LazySpacer,
881
+ { key: `lazy-${visible}`, axis, remaining: rows.length - shown.length, more: () => setCount(visible + LAZY_BATCH) }
882
+ )
883
+ ];
945
884
  }
946
- function InspectorPart({ children }) {
947
- return children;
885
+ function LazySpacer({ axis, remaining, more }) {
886
+ return sb("lazyspacer", { axis, remaining }, { lazy: more });
948
887
  }
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;
888
+ function rowMatches(row, id) {
889
+ if (row.key !== null && row.key === String(id)) return true;
890
+ let element = row;
891
+ for (let depth = 0; element && depth < 3; depth++) {
892
+ const props = element.props;
893
+ if (props.scrollID === id) return true;
894
+ element = isValidElement(props.children) ? props.children : null;
895
+ }
896
+ return false;
960
897
  }
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;
898
+ function VStack(props) {
899
+ const { own, modifiers } = splitProps(props);
900
+ const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
901
+ if (own.scrollTargetLayout) stack["scrollTarget"] = true;
902
+ return applyModifiers(sb("vstack", stack, void 0, own.children), modifiers);
979
903
  }
980
- const CoordinateSpacesContext = createContext({});
981
- function useCoordinateSpaces() {
982
- return useContext(CoordinateSpacesContext);
904
+ function HStack(props) {
905
+ const { own, modifiers } = splitProps(props);
906
+ const stack = { spacing: own.spacing ?? null, alignment: own.alignment ?? "center" };
907
+ if (own.scrollTargetLayout) stack["scrollTarget"] = true;
908
+ return applyModifiers(sb("hstack", stack, void 0, own.children), modifiers);
983
909
  }
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
- ) });
910
+ function ZStack(props) {
911
+ const { own, modifiers } = splitProps(props);
912
+ return applyModifiers(sb("zstack", { alignment: own.alignment ?? "center" }, void 0, own.children), modifiers);
998
913
  }
999
- function Hover({ action, children }) {
1000
- return sb("styled", { style: { hover: true } }, { hover: (event) => action(event.value) }, children);
914
+ function Spacer(props) {
915
+ const { own, modifiers } = splitProps(props);
916
+ return applyModifiers(sb("spacer", { minLength: own.minLength ?? null }), modifiers);
1001
917
  }
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;
918
+ function Divider(props) {
919
+ const { modifiers } = splitProps(props);
920
+ return applyModifiers(sb("divider", {}), modifiers);
1016
921
  }
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 };
922
+ function ScrollView(props) {
923
+ const { own, modifiers } = splitProps(props);
924
+ const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
925
+ const ownSettings = takeScrollSettings(modifiers);
926
+ const settings = useScrollSettings(ownSettings);
927
+ const axes = own.axes ?? "vertical";
928
+ const scroll = { axes, ...refresh.props };
929
+ if (own.scrollTargetBehavior) scroll["snap"] = own.scrollTargetBehavior;
930
+ if (own.scrollDismissesKeyboard) scroll["dismissesKeyboard"] = true;
931
+ const edgeEffect = edgeEffectProp(settings);
932
+ if (edgeEffect) scroll["edgeEffect"] = edgeEffect;
933
+ const content = marginedContent(own.children, settings.margins, axes === "horizontal" ? "horizontal" : "vertical");
934
+ return applyModifiers(sb("scrollview", scroll, refresh.handlers, providingScrollSettings(ownSettings, content)), modifiers);
935
+ }
936
+ function takeScrollSettings(modifiers) {
937
+ let settings = {};
938
+ const own = [];
939
+ for (const key of ["scrollEdgeEffectStyle", "scrollEdgeEffectHidden", "contentMargins"]) {
940
+ const value = takeModifier(modifiers, key);
941
+ if (value === void 0) continue;
942
+ if (key === "scrollEdgeEffectStyle") own.push(edgeStyleSettings(value));
943
+ else if (key === "scrollEdgeEffectHidden") own.push(edgeHiddenSettings(value));
944
+ else own.push(marginSettings(value));
1023
945
  }
1024
- if (!discrete && spec.isActive === false) return children;
1025
- const effect = { effect: spec.effect };
1026
- if (spec.direction) effect.direction = spec.direction;
1027
- if (spec.speed !== void 0) effect.speed = spec.speed;
1028
- if (spec.repeat !== void 0) effect.repeat = spec.repeat;
1029
- if (discrete) effect.trigger = serial.current.count;
1030
- return styled({ symbolEffect: effect }, children);
946
+ for (const each of own) settings = mergeScrollSettings(settings, each);
947
+ return settings;
1031
948
  }
1032
- function useNamespace() {
1033
- return useId();
949
+ function providingScrollSettings(settings, children) {
950
+ return Object.keys(settings).length > 0 ? withScrollSettings(settings, children) : children;
1034
951
  }
1035
- const KEY_NAMES = {
1036
- return: "Enter",
1037
- escape: "Escape",
1038
- delete: "Backspace",
1039
- tab: "Tab",
1040
- space: " ",
1041
- upArrow: "ArrowUp",
1042
- downArrow: "ArrowDown",
1043
- leftArrow: "ArrowLeft",
1044
- rightArrow: "ArrowRight"
1045
- };
952
+ function useRefreshable(own) {
953
+ const environment = useViewEnvironment();
954
+ const refresh = own ?? environment.refresh;
955
+ const [refreshing, setRefreshing] = useState(false);
956
+ if (!refresh) return { props: {} };
957
+ return {
958
+ props: { refreshable: true, refreshing },
959
+ handlers: {
960
+ refresh: () => {
961
+ if (refreshing) return;
962
+ setRefreshing(true);
963
+ Promise.resolve().then(refresh).catch((error) => console.error(error)).finally(() => setRefreshing(false));
964
+ }
965
+ }
966
+ };
967
+ }
968
+ function Group(props) {
969
+ const { own, modifiers } = splitProps(props);
970
+ if (modifiers.length === 0) return own.children;
971
+ return Children.map(own.children, (child) => applyModifiers(child, modifiers));
972
+ }
973
+ function moveItems(items, offsets, to) {
974
+ const moving = new Set(offsets);
975
+ const picked = items.filter((_, index) => moving.has(index));
976
+ const rest = items.filter((_, index) => !moving.has(index));
977
+ const before = offsets.filter((offset) => offset < to).length;
978
+ const at = to - before;
979
+ return [...rest.slice(0, at), ...picked, ...rest.slice(at)];
980
+ }
981
+ function ForEach(props) {
982
+ const { own, modifiers } = splitProps(props);
983
+ const rows = own.data.map((element, index) => {
984
+ const key = own.id ? own.id(element, index) : keyOf(element, index);
985
+ const content = applyModifiers(own.children(element, index), modifiers);
986
+ if (!own.onDelete && !own.onMove) return createElement(Fragment, { key }, content);
987
+ const { onDelete, onMove } = own;
988
+ const row = { tag: key, index };
989
+ if (onDelete) {
990
+ row.onDelete = () => onDelete([index]);
991
+ row.deletable = !own.deleteDisabled?.(element, index);
992
+ }
993
+ if (onMove) {
994
+ row.onMove = (to) => onMove([index], to);
995
+ row.movable = !own.moveDisabled?.(element, index);
996
+ }
997
+ return createElement(Row, { key, ...row }, content);
998
+ });
999
+ return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
1000
+ }
1001
+ function keyOf(element, index) {
1002
+ if (typeof element === "string" || typeof element === "number") return element;
1003
+ if (typeof element === "object" && element !== null && "id" in element) {
1004
+ const id = element.id;
1005
+ if (typeof id === "string" || typeof id === "number") return id;
1006
+ }
1007
+ return index;
1008
+ }
1009
+ function flattenChildren(children, options = {}) {
1010
+ const result = [];
1011
+ const visit = (node) => {
1012
+ if (node === null || node === void 0 || typeof node === "boolean") return;
1013
+ if (Array.isArray(node)) {
1014
+ node.forEach(visit);
1015
+ return;
1016
+ }
1017
+ if (!isValidElement(node)) return;
1018
+ const element = node;
1019
+ if (element.type === Fragment) {
1020
+ const inner = element.props["children"];
1021
+ if (element.key !== null && isValidElement(inner) && inner.key === null && inner.type !== Fragment) {
1022
+ visit({ ...inner, key: element.key });
1023
+ return;
1024
+ }
1025
+ visit(inner);
1026
+ return;
1027
+ }
1028
+ if (element.type === ForEach) {
1029
+ visit(ForEach(element.props));
1030
+ return;
1031
+ }
1032
+ if (element.type === LazyGroup && !options.keepLazy) {
1033
+ visit(element.props.rows);
1034
+ return;
1035
+ }
1036
+ result.push(element);
1037
+ };
1038
+ visit(children);
1039
+ return result;
1040
+ }
1041
+ function GridItem(spec = {}) {
1042
+ const dimension = (n) => n === void 0 || n === Infinity ? "infinity" : n;
1043
+ let size;
1044
+ if (spec.size && "fixed" in spec.size) size = { kind: "fixed", value: spec.size.fixed };
1045
+ else if (spec.size && "adaptive" in spec.size) {
1046
+ size = { kind: "adaptive", minimum: spec.size.adaptive.minimum, maximum: dimension(spec.size.adaptive.maximum) };
1047
+ } else {
1048
+ const flexible = spec.size && "flexible" in spec.size ? spec.size.flexible : {};
1049
+ size = { kind: "flexible", minimum: flexible.minimum ?? 10, maximum: dimension(flexible.maximum) };
1050
+ }
1051
+ return { size, spacing: spec.spacing ?? null, alignment: spec.alignment ?? null };
1052
+ }
1053
+ GridItem.flexible = (options = {}) => GridItem({ size: { flexible: options }, spacing: options.spacing, alignment: options.alignment });
1054
+ GridItem.fixed = (value, options = {}) => GridItem({ size: { fixed: value }, spacing: options.spacing, alignment: options.alignment });
1055
+ GridItem.adaptive = (options) => GridItem({ size: { adaptive: options }, spacing: options.spacing, alignment: options.alignment });
1056
+ function LazyVGrid(props) {
1057
+ const { own, modifiers } = splitProps(props);
1058
+ return applyModifiers(
1059
+ sb("lazyvgrid", { columns: own.columns, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" }, void 0, own.children),
1060
+ modifiers
1061
+ );
1062
+ }
1063
+ function LazyHGrid(props) {
1064
+ const { own, modifiers } = splitProps(props);
1065
+ return applyModifiers(
1066
+ sb("lazyhgrid", { rows: own.rows, spacing: own.spacing ?? null, alignment: own.alignment ?? "center" }, void 0, own.children),
1067
+ modifiers
1068
+ );
1069
+ }
1070
+ function Grid(props) {
1071
+ const { own, modifiers } = splitProps(props);
1072
+ return applyModifiers(
1073
+ sb(
1074
+ "grid",
1075
+ { horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
1076
+ void 0,
1077
+ own.children
1078
+ ),
1079
+ modifiers
1080
+ );
1081
+ }
1082
+ function GridRow(props) {
1083
+ const { own, modifiers } = splitProps(props);
1084
+ return applyModifiers(sb("gridrow", { alignment: own.alignment ?? null }, void 0, own.children), modifiers);
1085
+ }
1086
+ function runStyleOf(props, inherited, nested) {
1087
+ const style = { ...inherited };
1088
+ if (props.italic) style.italic = true;
1089
+ if (props.underline) style.underline = typeof props.underline === "object" && props.underline.color ? { color: color(props.underline.color) } : {};
1090
+ if (props.strikethrough) {
1091
+ style.strikethrough = typeof props.strikethrough === "object" && props.strikethrough.color ? { color: color(props.strikethrough.color) } : {};
1092
+ }
1093
+ const kerning = props.tracking ?? props.kerning;
1094
+ if (kerning !== void 0) style.kerning = kerning;
1095
+ if (props.baselineOffset !== void 0) style.baselineOffset = props.baselineOffset;
1096
+ if (props.link) style.link = props.link;
1097
+ if (nested) {
1098
+ let runFont = props.font !== void 0 ? font(props.font) : void 0;
1099
+ if (props.bold) runFont = { ...runFont ?? {}, weight: "bold" };
1100
+ if (props.fontWeight) runFont = { ...runFont ?? {}, weight: props.fontWeight };
1101
+ if (runFont) style.font = { ...style.font ?? {}, ...runFont };
1102
+ if (props.foregroundStyle !== void 0) style.foreground = shapeStyle(props.foregroundStyle);
1103
+ }
1104
+ return style;
1105
+ }
1106
+ function segmentsOf(children, style, into) {
1107
+ const visit = (node) => {
1108
+ if (node === null || node === void 0 || typeof node === "boolean") return;
1109
+ if (typeof node === "string" || typeof node === "number") {
1110
+ const last = into[into.length - 1];
1111
+ if (last && "text" in last && last.style === style) last.text += String(node);
1112
+ else into.push({ text: String(node), style });
1113
+ return;
1114
+ }
1115
+ if (Array.isArray(node)) {
1116
+ node.forEach(visit);
1117
+ return;
1118
+ }
1119
+ if (!isValidElement(node)) return;
1120
+ const element = node;
1121
+ if (element.type === Fragment) {
1122
+ visit(element.props["children"]);
1123
+ return;
1124
+ }
1125
+ if (element.type === Text) {
1126
+ const props = element.props;
1127
+ segmentsOf(props.children, runStyleOf(props, style, true), into);
1128
+ return;
1129
+ }
1130
+ if (element.type === Image$1) {
1131
+ const props = element.props;
1132
+ into.push({ image: imageProps(props), style });
1133
+ return;
1134
+ }
1135
+ };
1136
+ visit(children);
1137
+ }
1138
+ function isPlainStyle(style) {
1139
+ return Object.keys(style).length === 0;
1140
+ }
1141
+ function Text(props) {
1142
+ const { own, modifiers } = splitProps(props);
1143
+ const environment = useViewEnvironment();
1144
+ const style = runStyleOf(props, {}, false);
1145
+ const segments = [];
1146
+ segmentsOf(own.children, style, segments);
1147
+ const textCase = takeModifier(modifiers, "textCase") ?? environment.textCase;
1148
+ if (textCase) {
1149
+ for (const segment of segments) {
1150
+ if ("text" in segment) segment.text = textCase === "uppercase" ? segment.text.toUpperCase() : segment.text.toLowerCase();
1151
+ }
1152
+ }
1153
+ const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
1154
+ const content = segments.map((segment) => "text" in segment ? segment.text : "").join("");
1155
+ const plain = segments.length <= 1 && (segments.length === 0 || "text" in segments[0] && isPlainStyle(segments[0].style));
1156
+ if (plain) return applyModifiers(placeholder(sb("text", { text: content }), redacted), modifiers);
1157
+ const runs = segments.map((segment) => {
1158
+ const run = { ...segment.style };
1159
+ if ("text" in segment) run["text"] = segment.text;
1160
+ else run["image"] = segment.image;
1161
+ return run;
1162
+ });
1163
+ const hasLinks = segments.some((segment) => segment.style.link);
1164
+ const handlers = hasLinks ? { link: (event) => openURL(event.value) } : void 0;
1165
+ return applyModifiers(placeholder(sb("text", { text: content, runs }, handlers), redacted), modifiers);
1166
+ }
1167
+ function placeholder(node, redacted) {
1168
+ if (!redacted) return node;
1169
+ return styled({ background: { hierarchical: 3 }, backgroundCornerRadius: 4 }, styled({ foreground: { name: "clear" } }, node));
1170
+ }
1171
+ function openURL(url) {
1172
+ if (typeof window !== "undefined") window.open(url, "_blank", "noopener");
1173
+ }
1174
+ function imageProps(props) {
1175
+ if (props.systemName !== void 0) return { systemName: props.systemName };
1176
+ if (props.url !== void 0) return { url: props.url, resizable: props.resizable ?? false, width: props.width ?? 0, height: props.height ?? 0 };
1177
+ return { name: props.name ?? "", resizable: props.resizable ?? false };
1178
+ }
1179
+ function Image$1(props) {
1180
+ const { modifiers } = splitProps(props);
1181
+ const environment = useViewEnvironment();
1182
+ const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
1183
+ return applyModifiers(placeholder(sb("image", imageProps(props)), redacted), modifiers);
1184
+ }
1185
+ function Label(props) {
1186
+ const { own, modifiers } = splitProps(props);
1187
+ const environment = useViewEnvironment();
1188
+ const style = takeModifier(modifiers, "labelStyle") ?? environment.labelStyle ?? "automatic";
1189
+ const icon = own.icon ?? (own.systemImage !== void 0 ? /* @__PURE__ */ jsx(Image$1, { systemName: own.systemImage }) : own.image !== void 0 ? /* @__PURE__ */ jsx(Image$1, { name: own.image }) : null);
1190
+ const title = typeof own.title === "string" || typeof own.title === "number" ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.title;
1191
+ if (style === "iconOnly") return applyModifiers(icon, modifiers);
1192
+ if (style === "titleOnly") return applyModifiers(title, modifiers);
1193
+ return applyModifiers(
1194
+ /* @__PURE__ */ jsxs(HStack, { spacing: 8, children: [
1195
+ styled({ labelIcon: true }, icon),
1196
+ title
1197
+ ] }),
1198
+ modifiers
1199
+ );
1200
+ }
1201
+ function LabeledContent(props) {
1202
+ const { own, modifiers } = splitProps(props);
1203
+ const label = typeof own.label === "string" || typeof own.label === "number" ? /* @__PURE__ */ jsx(Text, { children: own.label }) : own.label;
1204
+ const content = own.children ?? own.value;
1205
+ const value = typeof content === "string" || typeof content === "number" ? /* @__PURE__ */ jsx(Text, { children: content }) : content;
1206
+ return applyModifiers(
1207
+ /* @__PURE__ */ jsxs(HStack, { children: [
1208
+ label,
1209
+ sb("spacer", { minLength: null }),
1210
+ styled({ foreground: { hierarchical: 2 } }, value)
1211
+ ] }),
1212
+ modifiers
1213
+ );
1214
+ }
1215
+ function Link(props) {
1216
+ const { own, modifiers } = splitProps(props);
1217
+ const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
1218
+ return applyModifiers(sb("button", { role: null, style: "automatic" }, { tap: () => openURL(own.destination) }, label), modifiers);
1219
+ }
1220
+ const isPushedView = (value) => typeof value === "object" && value !== null && "view" in value && Object.keys(value).length === 1;
1221
+ function NavigationStack(props) {
1222
+ const enclosing = useNavigation();
1223
+ if (enclosing) return /* @__PURE__ */ jsx(FlattenedStack, { ...props });
1224
+ return /* @__PURE__ */ jsx(OwnStack, { ...props });
1225
+ }
1226
+ function FlattenedStack(props) {
1227
+ const { own, modifiers } = splitProps(props);
1228
+ return applyModifiers(
1229
+ /* @__PURE__ */ jsxs(Fragment$1, { children: [
1230
+ own.destination && /* @__PURE__ */ jsx(RegisterDestination, { destination: own.destination }),
1231
+ own.children
1232
+ ] }),
1233
+ modifiers
1234
+ );
1235
+ }
1236
+ function OwnStack(props) {
1237
+ const { own, modifiers } = splitProps(props);
1238
+ const [internalPath, setInternalPath] = useState([]);
1239
+ const [path, setPath] = own.path !== void 0 ? readBinding(own.path, own.onPathChange) : [internalPath, setInternalPath];
1240
+ const destination = useRef(null);
1241
+ destination.current = own.destination ?? null;
1242
+ const context = {
1243
+ push: (value) => setPath([...path, value]),
1244
+ pop: () => setPath(path.slice(0, -1)),
1245
+ registerDestination: (builder) => {
1246
+ destination.current = builder;
1247
+ }
1248
+ };
1249
+ const screens = [
1250
+ /* @__PURE__ */ jsx(Fragment, { children: sb("navscreen", { title: "", displayMode: "automatic", depth: 0 }, { tap: context.pop }, own.children) }, "root")
1251
+ ];
1252
+ path.forEach((value, index) => {
1253
+ const pop = () => setPath(path.slice(0, index));
1254
+ screens.push(
1255
+ /* @__PURE__ */ jsx(Fragment, { children: sb(
1256
+ "navscreen",
1257
+ { title: "", displayMode: "automatic", depth: index + 1 },
1258
+ { tap: pop },
1259
+ /* @__PURE__ */ jsx(DismissContext.Provider, { value: pop, children: /* @__PURE__ */ jsx(PathScreen, { value, destination }) })
1260
+ ) }, index + 1)
1261
+ );
1262
+ });
1263
+ return applyModifiers(
1264
+ sb("navstack", {}, void 0, /* @__PURE__ */ jsx(NavigationContext.Provider, { value: context, children: screens })),
1265
+ modifiers
1266
+ );
1267
+ }
1268
+ function PathScreen({ value, destination }) {
1269
+ if (isPushedView(value)) return value.view;
1270
+ return destination.current ? destination.current(value) : null;
1271
+ }
1272
+ function NavigationLink(props) {
1273
+ const { own, modifiers } = splitProps(props);
1274
+ const navigation = useNavigation();
1275
+ const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
1276
+ const tap = () => {
1277
+ if (!navigation) return;
1278
+ if (own.destination !== void 0) navigation.push({ view: own.destination });
1279
+ else navigation.push(own.value);
1280
+ };
1281
+ return applyModifiers(sb("navlink", {}, { tap }, label), modifiers);
1282
+ }
1283
+ const SplitSelectionContext = createContext(null);
1284
+ function NavigationSplitView(props) {
1285
+ const { own, modifiers } = splitProps(props);
1286
+ const sizeClass = useHorizontalSizeClass();
1287
+ const [selected, setSelected] = useState(false);
1288
+ const reporters = useRef(/* @__PURE__ */ new Map());
1289
+ const [report] = useState(() => {
1290
+ const settle = () => setSelected([...reporters.current.values()].some((entry) => entry.selected));
1291
+ return {
1292
+ report: (key, nowSelected, clear2) => {
1293
+ reporters.current.set(key, { selected: nowSelected, clear: clear2 });
1294
+ settle();
1295
+ },
1296
+ retract: (key) => {
1297
+ if (reporters.current.delete(key)) settle();
1298
+ }
1299
+ };
1300
+ });
1301
+ const clear = () => {
1302
+ for (const entry of reporters.current.values()) if (entry.selected) entry.clear();
1303
+ };
1304
+ const [internal, setInternal] = useState("automatic");
1305
+ const [visibility, setVisibility] = own.columnVisibility !== void 0 ? readBinding(own.columnVisibility, own.onColumnVisibilityChange) : [internal, setInternal];
1306
+ if (sizeClass === "compact") {
1307
+ return applyModifiers(
1308
+ /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children: /* @__PURE__ */ jsx(CompactSplit, { sidebar: own.sidebar, detail: own.detail, selected, clear }) }),
1309
+ modifiers
1310
+ );
1311
+ }
1312
+ const sidebarVisible = visibility !== "detailOnly";
1313
+ const toggle = () => withAnimation(() => setVisibility(sidebarVisible ? "detailOnly" : "all"));
1314
+ const detail = isValidElement(own.detail) && own.detail.type === NavigationStack ? own.detail : /* @__PURE__ */ jsx(NavigationStack, { children: own.detail });
1315
+ return applyModifiers(
1316
+ sb("navsplit", { sidebarVisible }, { tap: toggle }, [
1317
+ /* @__PURE__ */ jsx(SplitColumn, { report, children: /* @__PURE__ */ jsx(NavigationStack, { children: own.sidebar }) }, "sidebar"),
1318
+ /* @__PURE__ */ jsx(SplitColumn, { report: null, children: detail }, "detail")
1319
+ ]),
1320
+ modifiers
1321
+ );
1322
+ }
1323
+ function SplitColumn({ report, children }) {
1324
+ return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children }) });
1325
+ }
1326
+ function CompactSplit({ sidebar, detail, selected, clear }) {
1327
+ const [extra, setExtra] = useState([]);
1328
+ const base = selected ? [{ view: /* @__PURE__ */ jsx(DetailScope, { children: detail }) }] : [];
1329
+ const path = [...base, ...extra];
1330
+ const setPath = (next) => {
1331
+ if (selected && next.length === 0) {
1332
+ setExtra([]);
1333
+ clear();
1334
+ return;
1335
+ }
1336
+ setExtra(next.slice(base.length));
1337
+ };
1338
+ return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(NavigationStack, { path: [path, setPath], children: sidebar }) });
1339
+ }
1340
+ function DetailScope({ children }) {
1341
+ return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
1342
+ }
1343
+ function useReportSplitSelection(split, selected, clear, active2 = true) {
1344
+ const key = useRef({}).current;
1345
+ useLayoutEffect(() => {
1346
+ if (active2) split?.report(key, selected, clear);
1347
+ else split?.retract(key);
1348
+ });
1349
+ useLayoutEffect(() => () => split?.retract(key), [split, key]);
1350
+ }
1351
+ function OutsideSplit({ children }) {
1352
+ return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
1353
+ }
1354
+ function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
1355
+ const [presented, setPresented] = readBinding(isPresented);
1356
+ if (!presented) return null;
1357
+ const dismiss = () => {
1358
+ setPresented(false);
1359
+ onDismiss?.();
1360
+ };
1361
+ const detents = fullScreen ? ["full"] : ["large"];
1362
+ return sb(
1363
+ HOIST_KIND,
1364
+ void 0,
1365
+ void 0,
1366
+ sb(
1367
+ "sheet",
1368
+ { detents },
1369
+ { tap: dismiss },
1370
+ /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(OutsideSplit, { children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) }) })
1371
+ ),
1372
+ "root"
1373
+ );
1374
+ }
1375
+ function presentationDetents(detents) {
1376
+ const encoded = detents.map(
1377
+ (detent) => typeof detent === "string" ? detent : "height" in detent ? `height:${detent.height}` : `fraction:${detent.fraction}`
1378
+ );
1379
+ return sb(PREF_KIND, { detents: encoded }, void 0, void 0, "sheet");
1380
+ }
1381
+ function AlertPresenter({ title, isPresented, message, actions, style }) {
1382
+ const [presented, setPresented] = readBinding(isPresented);
1383
+ if (!presented) return null;
1384
+ const dismiss = () => setPresented(false);
1385
+ return sb(
1386
+ HOIST_KIND,
1387
+ void 0,
1388
+ void 0,
1389
+ sb(
1390
+ "alert",
1391
+ { title, message: message ?? null, style: style ?? "alert" },
1392
+ { tap: dismiss },
1393
+ withEnvironment({ dismissAlert: dismiss }, actions)
1394
+ ),
1395
+ "root"
1396
+ );
1397
+ }
1398
+ function Lifecycle({ onAppear, onDisappear }) {
1399
+ useEffect(() => {
1400
+ onAppear?.();
1401
+ return () => onDisappear?.();
1402
+ }, []);
1403
+ return null;
1404
+ }
1405
+ function Inspector({ isPresented, content, columnWidth, children }) {
1406
+ const sizeClass = useHorizontalSizeClass();
1407
+ const [presented, setPresented] = readBinding(isPresented);
1408
+ if (sizeClass === "compact") {
1409
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1410
+ children,
1411
+ /* @__PURE__ */ jsx(SheetPresenter, { isPresented: [presented, setPresented], content })
1412
+ ] });
1413
+ }
1414
+ const outside = /* @__PURE__ */ jsx(OutsideSplit, { children: content });
1415
+ const panelContent = columnWidth !== void 0 ? sb("styled", { style: { inspectorColumnWidth: columnWidth } }, void 0, outside) : outside;
1416
+ return sb("inspector", { presented }, void 0, [
1417
+ /* @__PURE__ */ jsx(InspectorPart, { children }, "content"),
1418
+ /* @__PURE__ */ jsx(InspectorPart, { children: sb("inspectorpanel", {}, void 0, panelContent) }, "panel")
1419
+ ]);
1420
+ }
1421
+ function InspectorPart({ children }) {
1422
+ return children;
1423
+ }
1424
+ function Task({ id, action }) {
1425
+ const latest = useRef(action);
1426
+ latest.current = action;
1427
+ useEffect(() => {
1428
+ const controller = new AbortController();
1429
+ Promise.resolve().then(() => latest.current(controller.signal)).catch((error) => {
1430
+ if (!controller.signal.aborted) console.error(error);
1431
+ });
1432
+ return () => controller.abort();
1433
+ }, [id]);
1434
+ return null;
1435
+ }
1436
+ function OnChange({
1437
+ value,
1438
+ action,
1439
+ initial
1440
+ }) {
1441
+ const previous = useRef(null);
1442
+ const latest = useRef(action);
1443
+ latest.current = action;
1444
+ useEffect(() => {
1445
+ const last = previous.current;
1446
+ previous.current = { value };
1447
+ if (last === null) {
1448
+ if (initial) latest.current(value, value);
1449
+ return;
1450
+ }
1451
+ if (!Object.is(last.value, value)) latest.current(last.value, value);
1452
+ }, [value, initial]);
1453
+ return null;
1454
+ }
1455
+ function Hover({ action, children }) {
1456
+ return sb("styled", { style: { hover: true } }, { hover: (event) => action(event.value) }, children);
1457
+ }
1458
+ const CURSORS = {
1459
+ link: "pointer",
1460
+ automatic: "auto",
1461
+ default: "default",
1462
+ text: "text",
1463
+ verticalText: "vertical-text",
1464
+ grabIdle: "grab",
1465
+ grabActive: "grabbing",
1466
+ rectSelection: "crosshair",
1467
+ columnResize: "col-resize",
1468
+ rowResize: "row-resize"
1469
+ };
1470
+ function cursorFor(style) {
1471
+ return CURSORS[style] ?? style;
1472
+ }
1473
+ function SymbolEffect({ spec, children }) {
1474
+ const serial = useRef(null);
1475
+ const discrete = "value" in spec;
1476
+ if (discrete) {
1477
+ if (!serial.current) serial.current = { value: spec.value, count: 0 };
1478
+ else if (!Object.is(serial.current.value, spec.value)) serial.current = { value: spec.value, count: serial.current.count + 1 };
1479
+ }
1480
+ if (!discrete && spec.isActive === false) return children;
1481
+ const effect = { effect: spec.effect };
1482
+ if (spec.direction) effect.direction = spec.direction;
1483
+ if (spec.speed !== void 0) effect.speed = spec.speed;
1484
+ if (spec.repeat !== void 0) effect.repeat = spec.repeat;
1485
+ if (discrete) effect.trigger = serial.current.count;
1486
+ return styled({ symbolEffect: effect }, children);
1487
+ }
1488
+ function useNamespace() {
1489
+ return useId();
1490
+ }
1491
+ const KEY_NAMES = {
1492
+ return: "Enter",
1493
+ escape: "Escape",
1494
+ delete: "Backspace",
1495
+ tab: "Tab",
1496
+ space: " ",
1497
+ upArrow: "ArrowUp",
1498
+ downArrow: "ArrowDown",
1499
+ leftArrow: "ArrowLeft",
1500
+ rightArrow: "ArrowRight"
1501
+ };
1046
1502
  const isApple = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
1047
1503
  function matchesKey(event, key) {
1048
1504
  const name = KEY_NAMES[key] ?? key;
@@ -1128,10 +1584,31 @@ function toolbarPlacement(name) {
1128
1584
  return "principal";
1129
1585
  case "bottomBar":
1130
1586
  return "bottom";
1587
+ case "secondaryAction":
1588
+ return "secondary";
1131
1589
  default:
1132
1590
  return "trailing";
1133
1591
  }
1134
1592
  }
1593
+ function containerRelativeFrame(value) {
1594
+ const spec = typeof value === "string" ? { axes: value } : value;
1595
+ const horizontal = spec.axes !== "vertical";
1596
+ const vertical = spec.axes !== "horizontal";
1597
+ let a = 1;
1598
+ let b = 0;
1599
+ if (spec.length) {
1600
+ const axis = horizontal ? "horizontal" : "vertical";
1601
+ b = spec.length(0, axis);
1602
+ a = (spec.length(1e3, axis) - b) / 1e3;
1603
+ } else if (spec.count !== void 0) {
1604
+ const n = Math.max(spec.count, 1);
1605
+ const span = Math.max(spec.span ?? 1, 1);
1606
+ const spacing = spec.spacing ?? 0;
1607
+ a = span / n;
1608
+ b = -spacing * (n - 1) * span / n + spacing * (span - 1);
1609
+ }
1610
+ return { ...horizontal ? { horizontal: true } : {}, ...vertical ? { vertical: true } : {}, a, b, alignment: spec.alignment ?? "center" };
1611
+ }
1135
1612
  const MODIFIER_KEYS = /* @__PURE__ */ new Set([
1136
1613
  "padding",
1137
1614
  "font",
@@ -1169,6 +1646,7 @@ const MODIFIER_KEYS = /* @__PURE__ */ new Set([
1169
1646
  "labelsHidden",
1170
1647
  "navigationTitle",
1171
1648
  "navigationBarTitleDisplayMode",
1649
+ "toolbarRole",
1172
1650
  "toolbar",
1173
1651
  "searchable",
1174
1652
  "navigationDestination",
@@ -1230,7 +1708,13 @@ const MODIFIER_KEYS = /* @__PURE__ */ new Set([
1230
1708
  "sensoryFeedback",
1231
1709
  "textCase",
1232
1710
  "coordinateSpace",
1233
- "contentTransition"
1711
+ "contentTransition",
1712
+ "scrollEdgeEffectStyle",
1713
+ "scrollEdgeEffectHidden",
1714
+ "contentMargins",
1715
+ "containerRelativeFrame",
1716
+ "visualEffect",
1717
+ "scrollTransition"
1234
1718
  ]);
1235
1719
  function splitProps(props) {
1236
1720
  const own = {};
@@ -1253,8 +1737,8 @@ function styled(style, child) {
1253
1737
  }
1254
1738
  function decorated(role, alignment, content, decoration) {
1255
1739
  return sb("decorated", { role, alignment }, void 0, [
1256
- createElement(Fragment$1, { key: "content" }, content),
1257
- createElement(Fragment$1, { key: "decoration" }, decoration)
1740
+ createElement(Fragment, { key: "content" }, content),
1741
+ createElement(Fragment, { key: "decoration" }, decoration)
1258
1742
  ]);
1259
1743
  }
1260
1744
  function shapeSpecOf(element) {
@@ -1276,7 +1760,7 @@ function applyModifiers(element, modifiers) {
1276
1760
  const sides = [];
1277
1761
  const node = wrap(element, modifiers, sides);
1278
1762
  if (sides.length === 0) return node;
1279
- return createElement(Fragment$1, null, node, ...sides);
1763
+ return createElement(Fragment, null, node, ...sides);
1280
1764
  }
1281
1765
  function wrap(element, modifiers, sides) {
1282
1766
  let node = element;
@@ -1398,6 +1882,9 @@ function apply(key, value, node, sides) {
1398
1882
  case "navigationBarTitleDisplayMode":
1399
1883
  sides.push(sb(PREF_KIND, { displayMode: value }, void 0, void 0, "navscreen"));
1400
1884
  return node;
1885
+ case "toolbarRole":
1886
+ sides.push(sb(PREF_KIND, { toolbarRole: value }, void 0, void 0, "navscreen"));
1887
+ return node;
1401
1888
  case "toolbar":
1402
1889
  sides.push(sb(HOIST_KIND, void 0, void 0, value, "navscreen"));
1403
1890
  return node;
@@ -1454,7 +1941,7 @@ function apply(key, value, node, sides) {
1454
1941
  );
1455
1942
  }
1456
1943
  case "contextMenu":
1457
- return sb("contextmenu", {}, void 0, [createElement(Fragment$1, { key: "content" }, node), createElement(Fragment$1, { key: "items" }, value)]);
1944
+ return sb("contextmenu", {}, void 0, [createElement(Fragment, { key: "content" }, node), createElement(Fragment, { key: "items" }, value)]);
1458
1945
  case "swipeActions": {
1459
1946
  const specs = Array.isArray(value) ? value : [value];
1460
1947
  const trailing = [];
@@ -1475,7 +1962,7 @@ function apply(key, value, node, sides) {
1475
1962
  "swipeactions",
1476
1963
  { trailing: trailing.length, leading: leading.length, fullSwipeTrailing, fullSwipeLeading },
1477
1964
  void 0,
1478
- [createElement(Fragment$1, { key: "content" }, node), ...trailing, ...leading]
1965
+ [createElement(Fragment, { key: "content" }, node), ...trailing, ...leading]
1479
1966
  );
1480
1967
  }
1481
1968
  case "onAppear":
@@ -1535,7 +2022,7 @@ function apply(key, value, node, sides) {
1535
2022
  const spec = value;
1536
2023
  const at = (width, height) => spec.value({ width, height });
1537
2024
  const a = at(0, 0);
1538
- const round = (n) => Math.round(n * 1e6) / 1e6;
2025
+ const round2 = (n) => Math.round(n * 1e6) / 1e6;
1539
2026
  const vertical = ["top", "bottom", "verticalCenter", "firstTextBaseline", "lastTextBaseline"].includes(spec.guide);
1540
2027
  const name = spec.guide === "horizontalCenter" || spec.guide === "verticalCenter" ? "center" : spec.guide;
1541
2028
  return styled(
@@ -1543,7 +2030,7 @@ function apply(key, value, node, sides) {
1543
2030
  alignmentGuide: {
1544
2031
  axis: vertical ? "vertical" : "horizontal",
1545
2032
  name,
1546
- value: [round(a), round((at(100, 0) - a) / 100), round((at(0, 100) - a) / 100)]
2033
+ value: [round2(a), round2((at(100, 0) - a) / 100), round2((at(0, 100) - a) / 100)]
1547
2034
  }
1548
2035
  },
1549
2036
  node
@@ -1592,7 +2079,7 @@ function apply(key, value, node, sides) {
1592
2079
  const spec = value;
1593
2080
  const vertical = spec.edge === "top" || spec.edge === "bottom";
1594
2081
  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)];
2082
+ const children = before ? [createElement(Fragment, { key: "inset" }, spec.content), createElement(Fragment, { key: "content" }, node)] : [createElement(Fragment, { key: "content" }, node), createElement(Fragment, { key: "inset" }, spec.content)];
1596
2083
  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);
1597
2084
  }
1598
2085
  case "popover":
@@ -1605,406 +2092,538 @@ function apply(key, value, node, sides) {
1605
2092
  case "onKeyPress":
1606
2093
  sides.push(createElement(KeyPressListener, { spec: value }));
1607
2094
  return node;
1608
- case "sensoryFeedback": {
1609
- const spec = value;
1610
- sides.push(createElement(SensoryFeedbackPlayer, spec));
1611
- return node;
1612
- }
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);
1624
- }
1625
- case "modifiers": {
1626
- let result = node;
1627
- for (const extra of value) {
1628
- result = wrap(result, Object.entries(extra), sides);
1629
- }
1630
- return result;
1631
- }
1632
- default: {
1633
- const unknown = key;
1634
- throw new Error(`Unknown modifier ${String(unknown)}`);
1635
- }
1636
- }
1637
- }
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++ })
1644
- };
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);
1651
- }
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;
1666
- return sb(
1667
- "listrow",
1668
- props,
1669
- {
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));
1675
- }
1676
- },
1677
- children
1678
- );
1679
- }
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)];
1776
- }
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);
2095
+ case "sensoryFeedback": {
2096
+ const spec = value;
2097
+ sides.push(createElement(SensoryFeedbackPlayer, spec));
2098
+ return node;
1792
2099
  }
1793
- return createElement(Row, { key, ...row }, content);
1794
- });
1795
- return rows.length > LAZY_BATCH ? createElement(LazyGroup, { rows }) : rows;
1796
- }
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;
1802
- }
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;
2100
+ case "textCase":
2101
+ return withEnvironment({ textCase: value }, node);
2102
+ case "coordinateSpace":
2103
+ return createElement(CoordinateSpace, { name: value }, node);
2104
+ case "scrollEdgeEffectStyle":
2105
+ return withScrollSettings(edgeStyleSettings(value), node);
2106
+ case "scrollEdgeEffectHidden":
2107
+ return withScrollSettings(edgeHiddenSettings(value), node);
2108
+ case "contentMargins":
2109
+ return withScrollSettings(marginSettings(value), node);
2110
+ case "containerRelativeFrame":
2111
+ return styled({ containerRelativeFrame: containerRelativeFrame(value) }, node);
2112
+ case "visualEffect":
2113
+ return createElement(VisualEffectView, { effect: value }, node);
2114
+ case "scrollTransition": {
2115
+ const spec = typeof value === "function" ? { transition: value } : value;
2116
+ return createElement(ScrollTransitionView, { spec }, node);
1812
2117
  }
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;
2118
+ case "contentTransition": {
2119
+ if (value === "identity") return node;
2120
+ if (typeof value === "object") {
2121
+ const countsDown = value.numericText.countsDown;
2122
+ return styled({ contentTransition: { kind: "numericText", ...countsDown !== void 0 ? { countsDown } : {} } }, node);
1820
2123
  }
1821
- visit(inner);
1822
- return;
2124
+ return styled({ contentTransition: { kind: value } }, node);
1823
2125
  }
1824
- if (element.type === ForEach) {
1825
- visit(ForEach(element.props));
1826
- return;
2126
+ case "modifiers": {
2127
+ let result = node;
2128
+ for (const extra of value) {
2129
+ result = wrap(result, Object.entries(extra), sides);
2130
+ }
2131
+ return result;
1827
2132
  }
1828
- if (element.type === LazyGroup && !options.keepLazy) {
1829
- visit(element.props.rows);
1830
- return;
2133
+ default: {
2134
+ const unknown = key;
2135
+ throw new Error(`Unknown modifier ${String(unknown)}`);
1831
2136
  }
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) };
1846
2137
  }
1847
- return { size, spacing: spec.spacing ?? null, alignment: spec.alignment ?? null };
1848
2138
  }
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
- );
2139
+ const NO_INSETS = { top: 0, leading: 0, bottom: 0, trailing: 0 };
2140
+ const NO_GEOMETRY = { size: { width: 0, height: 0 }, origin: null, safeArea: NO_INSETS, scrollView: null };
2141
+ function nextGeometry(event, reported) {
2142
+ const hasOrigin = event.x !== void 0 && event.y !== void 0;
2143
+ return {
2144
+ size: { width: event.width, height: event.height },
2145
+ origin: hasOrigin ? { x: event.x, y: event.y } : reported.origin,
2146
+ safeArea: event.safeArea ?? reported.safeArea,
2147
+ // A frame report without a scroll view means the reader is in none.
2148
+ scrollView: hasOrigin ? event.scrollView ?? null : reported.scrollView
2149
+ };
1858
2150
  }
1859
- function Grid(props) {
2151
+ function geometryProxy(reported, spaces, onReadFrame) {
2152
+ return {
2153
+ size: reported.size,
2154
+ frame: (space = "local") => {
2155
+ if (space === "local") return { x: 0, y: 0, ...reported.size };
2156
+ onReadFrame();
2157
+ const origin = reported.origin ?? { x: 0, y: 0 };
2158
+ if (space === "global") return { ...origin, ...reported.size };
2159
+ const named = spaces[space.named];
2160
+ return { x: origin.x - (named?.x ?? 0), y: origin.y - (named?.y ?? 0), ...reported.size };
2161
+ },
2162
+ bounds: () => {
2163
+ onReadFrame();
2164
+ const view = reported.scrollView;
2165
+ if (!view || !reported.origin) return null;
2166
+ return { x: view.x - reported.origin.x, y: view.y - reported.origin.y, width: view.width, height: view.height };
2167
+ },
2168
+ get safeAreaInsets() {
2169
+ onReadFrame();
2170
+ return reported.safeArea;
2171
+ }
2172
+ };
2173
+ }
2174
+ function GeometryReader(props) {
1860
2175
  const { own, modifiers } = splitProps(props);
2176
+ const [reported, setReported] = useState(NO_GEOMETRY);
2177
+ const [needsFrame, setNeedsFrame] = useState(false);
2178
+ let readFrame = false;
2179
+ const proxy = geometryProxy(reported, useCoordinateSpaces(), () => {
2180
+ readFrame = true;
2181
+ });
2182
+ const content = own.children(proxy);
2183
+ useEffect(() => {
2184
+ if (readFrame && !needsFrame) setNeedsFrame(true);
2185
+ });
1861
2186
  return applyModifiers(
1862
2187
  sb(
1863
- "grid",
1864
- { horizontalSpacing: own.horizontalSpacing ?? null, verticalSpacing: own.verticalSpacing ?? null, alignment: own.alignment ?? "center" },
1865
- void 0,
1866
- own.children
2188
+ "geometry",
2189
+ needsFrame ? { reportsFrame: true } : {},
2190
+ {
2191
+ geometry: (event) => {
2192
+ const next = nextGeometry(event, reported);
2193
+ if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
2194
+ }
2195
+ },
2196
+ content
1867
2197
  ),
1868
2198
  modifiers
1869
2199
  );
1870
2200
  }
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
- }
1875
- function runStyleOf(props, inherited, nested) {
1876
- const style = { ...inherited };
1877
- if (props.italic) style.italic = true;
1878
- if (props.underline) style.underline = typeof props.underline === "object" && props.underline.color ? { color: color(props.underline.color) } : {};
1879
- if (props.strikethrough) {
1880
- style.strikethrough = typeof props.strikethrough === "object" && props.strikethrough.color ? { color: color(props.strikethrough.color) } : {};
1881
- }
1882
- const kerning = props.tracking ?? props.kerning;
1883
- if (kerning !== void 0) style.kerning = kerning;
1884
- if (props.baselineOffset !== void 0) style.baselineOffset = props.baselineOffset;
1885
- if (props.link) style.link = props.link;
1886
- if (nested) {
1887
- let runFont = props.font !== void 0 ? font(props.font) : void 0;
1888
- if (props.bold) runFont = { ...runFont ?? {}, weight: "bold" };
1889
- if (props.fontWeight) runFont = { ...runFont ?? {}, weight: props.fontWeight };
1890
- if (runFont) style.font = { ...style.font ?? {}, ...runFont };
1891
- if (props.foregroundStyle !== void 0) style.foreground = shapeStyle(props.foregroundStyle);
1892
- }
1893
- return style;
1894
- }
1895
- function segmentsOf(children, style, into) {
1896
- const visit = (node) => {
1897
- if (node === null || node === void 0 || typeof node === "boolean") return;
1898
- if (typeof node === "string" || typeof node === "number") {
1899
- const last = into[into.length - 1];
1900
- if (last && "text" in last && last.style === style) last.text += String(node);
1901
- else into.push({ text: String(node), style });
1902
- return;
1903
- }
1904
- if (Array.isArray(node)) {
1905
- node.forEach(visit);
1906
- return;
1907
- }
1908
- if (!isValidElement(node)) return;
1909
- const element = node;
1910
- if (element.type === Fragment$1) {
1911
- visit(element.props["children"]);
1912
- return;
1913
- }
1914
- if (element.type === Text) {
1915
- const props = element.props;
1916
- segmentsOf(props.children, runStyleOf(props, style, true), into);
1917
- return;
1918
- }
1919
- if (element.type === Image$1) {
1920
- const props = element.props;
1921
- into.push({ image: imageProps(props), style });
1922
- return;
1923
- }
1924
- };
1925
- visit(children);
2201
+ const DEFAULT_VIEW_SPACING = { distance: () => 8 };
2202
+ function subviewTraits(children) {
2203
+ return flattenChildren(children).map((element) => {
2204
+ const props = element.props;
2205
+ return { priority: props.layoutPriority ?? 0, values: props.layoutValue ?? {} };
2206
+ });
1926
2207
  }
1927
- function isPlainStyle(style) {
1928
- return Object.keys(style).length === 0;
2208
+ const fromDimension = (value) => value === "infinity" ? Infinity : value;
2209
+ const toDimension = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : "infinity";
2210
+ const toSize = (size) => ({
2211
+ width: fromDimension(size.width) ?? 0,
2212
+ height: fromDimension(size.height) ?? 0
2213
+ });
2214
+ const GUIDES = ["leading", "horizontalCenter", "trailing", "top", "verticalCenter", "bottom", "firstTextBaseline", "lastTextBaseline"];
2215
+ function clamp(value, min, max) {
2216
+ return Math.min(Math.max(value, min), max);
1929
2217
  }
1930
- function Text(props) {
1931
- const { own, modifiers } = splitProps(props);
1932
- const environment = useViewEnvironment();
1933
- const style = runStyleOf(props, {}, false);
1934
- const segments = [];
1935
- segmentsOf(own.children, style, segments);
1936
- const textCase = takeModifier(modifiers, "textCase") ?? environment.textCase;
1937
- if (textCase) {
1938
- for (const segment of segments) {
1939
- if ("text" in segment) segment.text = textCase === "uppercase" ? segment.text.toUpperCase() : segment.text.toLowerCase();
2218
+ function answerLayout(layout, record, traits = []) {
2219
+ const frames = record.children.map(() => null);
2220
+ const subviews = record.children.map((measurement, index) => {
2221
+ const min = toSize(measurement.min);
2222
+ const ideal = toSize(measurement.ideal);
2223
+ const max = toSize(measurement.max);
2224
+ const sizeThatFits = (proposal) => ({
2225
+ width: proposal.width === null ? ideal.width : clamp(proposal.width, min.width, max.width),
2226
+ height: proposal.height === null ? ideal.height : clamp(proposal.height, min.height, max.height)
2227
+ });
2228
+ return {
2229
+ min,
2230
+ ideal,
2231
+ max,
2232
+ priority: traits[index]?.priority ?? 0,
2233
+ values: traits[index]?.values ?? {},
2234
+ spacing: DEFAULT_VIEW_SPACING,
2235
+ sizeThatFits,
2236
+ place: ({ x, y, anchor, proposal }) => {
2237
+ const size2 = sizeThatFits(proposal ?? { width: null, height: null });
2238
+ const point = unitPoint(anchor ?? "topLeading");
2239
+ frames[index] = { x: x - point.x * size2.width, y: y - point.y * size2.height, ...size2 };
2240
+ }
2241
+ };
2242
+ });
2243
+ const cache = layout.makeCache ? layout.makeCache(subviews) : void 0;
2244
+ const measure = (proposal) => layout.sizeThatFits(proposal, subviews, cache);
2245
+ const size = measure(record.proposal);
2246
+ layout.placeSubviews({ x: 0, y: 0, ...size }, record.proposal, subviews, cache);
2247
+ const placed = frames.map((frame2, index) => {
2248
+ if (frame2) return frame2;
2249
+ const own = subviews[index].sizeThatFits({ width: size.width, height: size.height });
2250
+ return { x: (size.width - own.width) / 2, y: (size.height - own.height) / 2, ...own };
2251
+ });
2252
+ const guides = {};
2253
+ if (layout.explicitAlignment) {
2254
+ const bounds = { x: 0, y: 0, ...size };
2255
+ for (const guide of GUIDES) {
2256
+ const value = layout.explicitAlignment(guide, bounds, record.proposal, subviews, cache);
2257
+ if (value !== null && value !== void 0 && Number.isFinite(value)) guides[guide] = value;
1940
2258
  }
1941
2259
  }
1942
- const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
1943
- const content = segments.map((segment) => "text" in segment ? segment.text : "").join("");
1944
- const plain = segments.length <= 1 && (segments.length === 0 || "text" in segments[0] && isPlainStyle(segments[0].style));
1945
- if (plain) return applyModifiers(placeholder(sb("text", { text: content }), redacted), modifiers);
1946
- const runs = segments.map((segment) => {
1947
- const run = { ...segment.style };
1948
- if ("text" in segment) run["text"] = segment.text;
1949
- else run["image"] = segment.image;
1950
- return run;
1951
- });
1952
- const hasLinks = segments.some((segment) => segment.style.link);
1953
- const handlers = hasLinks ? { link: (event) => openURL(event.value) } : void 0;
1954
- return applyModifiers(placeholder(sb("text", { text: content, runs }, handlers), redacted), modifiers);
2260
+ return {
2261
+ size,
2262
+ frames: placed,
2263
+ guides,
2264
+ sizes: {
2265
+ min: measure({ width: 0, height: 0 }),
2266
+ ideal: measure({ width: null, height: null }),
2267
+ max: measure({ width: Infinity, height: Infinity })
2268
+ }
2269
+ };
1955
2270
  }
1956
- function placeholder(node, redacted) {
1957
- if (!redacted) return node;
1958
- return styled({ background: { hierarchical: 3 }, backgroundCornerRadius: 4 }, styled({ foreground: { name: "clear" } }, node));
2271
+ function Layout(props) {
2272
+ const { own, modifiers } = splitProps(props);
2273
+ const [record, setRecord] = useState(null);
2274
+ let layoutProps = { proposal: null, size: null, frames: null };
2275
+ const guideModifiers = [];
2276
+ if (record) {
2277
+ const answer = answerLayout(own.layout, record, subviewTraits(own.children));
2278
+ for (const [guide, value] of Object.entries(answer.guides)) guideModifiers.push(["alignmentGuide", { guide, value: () => value }]);
2279
+ const encode = (size) => ({ width: toDimension(size.width), height: toDimension(size.height) });
2280
+ const round2 = (value) => Math.round(value * 100) / 100;
2281
+ layoutProps = {
2282
+ proposal: {
2283
+ width: record.proposal.width === null ? null : toDimension(record.proposal.width),
2284
+ height: record.proposal.height === null ? null : toDimension(record.proposal.height)
2285
+ },
2286
+ size: { width: round2(answer.size.width), height: round2(answer.size.height) },
2287
+ frames: answer.frames.map((frame2) => ({ x: round2(frame2.x), y: round2(frame2.y), width: round2(frame2.width), height: round2(frame2.height) })),
2288
+ sizes: { min: encode(answer.sizes.min), ideal: encode(answer.sizes.ideal), max: encode(answer.sizes.max) }
2289
+ };
2290
+ }
2291
+ return applyModifiers(
2292
+ sb(
2293
+ "layout",
2294
+ layoutProps,
2295
+ {
2296
+ layout: (event) => {
2297
+ const proposal = event.proposal;
2298
+ setRecord({
2299
+ proposal: { width: fromDimension(proposal.width), height: fromDimension(proposal.height) },
2300
+ children: event.children
2301
+ });
2302
+ }
2303
+ },
2304
+ own.children
2305
+ ),
2306
+ [...guideModifiers, ...modifiers]
2307
+ );
1959
2308
  }
1960
- function openURL(url) {
1961
- if (typeof window !== "undefined") window.open(url, "_blank", "noopener");
2309
+ const IDENTITY$1 = {
2310
+ offsetX: 0,
2311
+ offsetY: 0,
2312
+ scaleX: 1,
2313
+ scaleY: 1,
2314
+ rotation: 0,
2315
+ opacity: 1,
2316
+ blur: 0,
2317
+ brightness: 0,
2318
+ contrast: 1,
2319
+ saturation: 1,
2320
+ grayscale: 0,
2321
+ hueRotation: 0
2322
+ };
2323
+ class VisualEffect {
2324
+ /** @internal */
2325
+ constructor(values = IDENTITY$1) {
2326
+ this.values = values;
2327
+ }
2328
+ values;
2329
+ with(patch) {
2330
+ return new VisualEffect({ ...this.values, ...patch });
2331
+ }
2332
+ offset(offset) {
2333
+ return this.with({ offsetX: this.values.offsetX + (offset.x ?? 0), offsetY: this.values.offsetY + (offset.y ?? 0) });
2334
+ }
2335
+ scaleEffect(scale, anchor) {
2336
+ const x = typeof scale === "number" ? scale : scale.x ?? 1;
2337
+ const y = typeof scale === "number" ? scale : scale.y ?? 1;
2338
+ return this.with({ scaleX: this.values.scaleX * x, scaleY: this.values.scaleY * y, ...anchor !== void 0 ? { scaleAnchor: unitPoint(anchor) } : {} });
2339
+ }
2340
+ /** Degrees. */
2341
+ rotationEffect(degrees, anchor) {
2342
+ return this.with({ rotation: this.values.rotation + degrees, ...anchor !== void 0 ? { rotationAnchor: unitPoint(anchor) } : {} });
2343
+ }
2344
+ rotation3DEffect(spec) {
2345
+ const rotation = { angle: spec.angle, axis: spec.axis };
2346
+ if (spec.anchor !== void 0) rotation.anchor = unitPoint(spec.anchor);
2347
+ if (spec.perspective !== void 0) rotation.perspective = spec.perspective;
2348
+ return this.with({ rotation3D: rotation });
2349
+ }
2350
+ opacity(opacity2) {
2351
+ return this.with({ opacity: this.values.opacity * opacity2 });
2352
+ }
2353
+ blur(radius) {
2354
+ return this.with({ blur: this.values.blur + radius });
2355
+ }
2356
+ brightness(amount) {
2357
+ return this.with({ brightness: this.values.brightness + amount });
2358
+ }
2359
+ contrast(amount) {
2360
+ return this.with({ contrast: this.values.contrast * amount });
2361
+ }
2362
+ saturation(amount) {
2363
+ return this.with({ saturation: this.values.saturation * amount });
2364
+ }
2365
+ grayscale(amount) {
2366
+ return this.with({ grayscale: Math.min(1, this.values.grayscale + amount) });
2367
+ }
2368
+ /** Degrees. */
2369
+ hueRotation(degrees) {
2370
+ return this.with({ hueRotation: this.values.hueRotation + degrees });
2371
+ }
1962
2372
  }
1963
- function imageProps(props) {
1964
- if (props.systemName !== void 0) return { systemName: props.systemName };
1965
- if (props.url !== void 0) return { url: props.url, resizable: props.resizable ?? false, width: props.width ?? 0, height: props.height ?? 0 };
1966
- return { name: props.name ?? "", resizable: props.resizable ?? false };
2373
+ const EMPTY_EFFECT = new VisualEffect();
2374
+ const round = (value) => Math.round(value * 1e3) / 1e3;
2375
+ function effectStyle(values) {
2376
+ const style = {};
2377
+ if (values.offsetX !== 0 || values.offsetY !== 0) style.offset = { x: round(values.offsetX), y: round(values.offsetY) };
2378
+ if (values.scaleX !== 1 || values.scaleY !== 1) {
2379
+ style.scale = { x: round(values.scaleX), y: round(values.scaleY) };
2380
+ if (values.scaleAnchor) style.scaleAnchor = values.scaleAnchor;
2381
+ }
2382
+ if (values.rotation !== 0) {
2383
+ style.rotation = round(values.rotation);
2384
+ if (values.rotationAnchor) style.rotationAnchor = values.rotationAnchor;
2385
+ }
2386
+ if (values.rotation3D && values.rotation3D.angle !== 0) style.rotation3D = { ...values.rotation3D, angle: round(values.rotation3D.angle) };
2387
+ if (values.opacity !== 1) style.opacity = round(values.opacity);
2388
+ if (values.blur !== 0) style.blur = round(values.blur);
2389
+ if (values.brightness !== 0) style.brightness = round(values.brightness);
2390
+ if (values.contrast !== 1) style.contrast = round(values.contrast);
2391
+ if (values.saturation !== 1) style.saturation = round(values.saturation);
2392
+ if (values.grayscale !== 0) style.grayscale = round(values.grayscale);
2393
+ if (values.hueRotation !== 0) style.hueRotation = round(values.hueRotation);
2394
+ return style;
1967
2395
  }
1968
- function Image$1(props) {
1969
- const { modifiers } = splitProps(props);
1970
- const environment = useViewEnvironment();
1971
- const redacted = takeModifier(modifiers, "redacted") ?? environment.redacted;
1972
- return applyModifiers(placeholder(sb("image", imageProps(props)), redacted), modifiers);
2396
+ function interpolateEffects(from, to, t) {
2397
+ const mix = (a, b) => a + (b - a) * t;
2398
+ const result = {
2399
+ offsetX: mix(from.offsetX, to.offsetX),
2400
+ offsetY: mix(from.offsetY, to.offsetY),
2401
+ scaleX: mix(from.scaleX, to.scaleX),
2402
+ scaleY: mix(from.scaleY, to.scaleY),
2403
+ rotation: mix(from.rotation, to.rotation),
2404
+ opacity: mix(from.opacity, to.opacity),
2405
+ blur: mix(from.blur, to.blur),
2406
+ brightness: mix(from.brightness, to.brightness),
2407
+ contrast: mix(from.contrast, to.contrast),
2408
+ saturation: mix(from.saturation, to.saturation),
2409
+ grayscale: mix(from.grayscale, to.grayscale),
2410
+ hueRotation: mix(from.hueRotation, to.hueRotation)
2411
+ };
2412
+ const scaleAnchor = to.scaleAnchor ?? from.scaleAnchor;
2413
+ if (scaleAnchor) result.scaleAnchor = scaleAnchor;
2414
+ const rotationAnchor = to.rotationAnchor ?? from.rotationAnchor;
2415
+ if (rotationAnchor) result.rotationAnchor = rotationAnchor;
2416
+ const rotation3D = to.rotation3D ?? from.rotation3D;
2417
+ if (rotation3D) result.rotation3D = { ...rotation3D, angle: mix(from.rotation3D?.angle ?? 0, to.rotation3D?.angle ?? 0) };
2418
+ return result;
1973
2419
  }
1974
- function Label(props) {
1975
- const { own, modifiers } = splitProps(props);
1976
- const environment = useViewEnvironment();
1977
- const style = takeModifier(modifiers, "labelStyle") ?? environment.labelStyle ?? "automatic";
1978
- const icon = own.icon ?? (own.systemImage !== void 0 ? /* @__PURE__ */ jsx(Image$1, { systemName: own.systemImage }) : own.image !== void 0 ? /* @__PURE__ */ jsx(Image$1, { name: own.image }) : null);
1979
- const title = typeof own.title === "string" || typeof own.title === "number" ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.title;
1980
- if (style === "iconOnly") return applyModifiers(icon, modifiers);
1981
- if (style === "titleOnly") return applyModifiers(title, modifiers);
1982
- return applyModifiers(
1983
- /* @__PURE__ */ jsxs(HStack, { spacing: 8, children: [
1984
- styled({ labelIcon: true }, icon),
1985
- title
1986
- ] }),
1987
- modifiers
2420
+ function EffectBox({
2421
+ render,
2422
+ alwaysFrame,
2423
+ animationToken,
2424
+ children
2425
+ }) {
2426
+ const [reported, setReported] = useState(NO_GEOMETRY);
2427
+ const [needsFrame, setNeedsFrame] = useState(alwaysFrame);
2428
+ let readFrame = false;
2429
+ const style = render(reported, () => {
2430
+ readFrame = true;
2431
+ });
2432
+ useEffect(() => {
2433
+ if (readFrame && !needsFrame) setNeedsFrame(true);
2434
+ });
2435
+ let content = Object.keys(style).length > 0 ? sb("styled", { style }, void 0, children) : children;
2436
+ if (animationToken) content = sb("styled", { style: { animation: { type: "default" }, animationToken: animationToken(reported) } }, void 0, content);
2437
+ return sb(
2438
+ "zstack",
2439
+ { alignment: "center", reportsSize: true, ...needsFrame ? { reportsFrame: true } : {} },
2440
+ {
2441
+ geometry: (event) => {
2442
+ const next = nextGeometry(event, reported);
2443
+ if (JSON.stringify(next) !== JSON.stringify(reported)) setReported(next);
2444
+ }
2445
+ },
2446
+ content
1988
2447
  );
1989
2448
  }
1990
- function LabeledContent(props) {
1991
- const { own, modifiers } = splitProps(props);
1992
- const label = typeof own.label === "string" || typeof own.label === "number" ? /* @__PURE__ */ jsx(Text, { children: own.label }) : own.label;
1993
- const content = own.children ?? own.value;
1994
- const value = typeof content === "string" || typeof content === "number" ? /* @__PURE__ */ jsx(Text, { children: content }) : content;
1995
- return applyModifiers(
1996
- /* @__PURE__ */ jsxs(HStack, { children: [
1997
- label,
1998
- sb("spacer", { minLength: null }),
1999
- styled({ foreground: { hierarchical: 2 } }, value)
2000
- ] }),
2001
- modifiers
2449
+ function VisualEffectView({ effect, children }) {
2450
+ const spaces = useCoordinateSpaces();
2451
+ return /* @__PURE__ */ jsx(EffectBox, { alwaysFrame: false, render: (reported, markRead) => effectStyle(effect(EMPTY_EFFECT, geometryProxy(reported, spaces, markRead)).values), children });
2452
+ }
2453
+ const PHASES = {
2454
+ topLeading: { phase: "topLeading", value: -1, isIdentity: false },
2455
+ identity: { phase: "identity", value: 0, isIdentity: true },
2456
+ bottomTrailing: { phase: "bottomTrailing", value: 1, isIdentity: false }
2457
+ };
2458
+ function scrollProgress(reported, axis) {
2459
+ const view = reported.scrollView;
2460
+ const origin = reported.origin;
2461
+ if (!view || !origin) return 0;
2462
+ const horizontal = (axis ?? view.axis) === "horizontal";
2463
+ const start = horizontal ? origin.x : origin.y;
2464
+ const length = horizontal ? reported.size.width : reported.size.height;
2465
+ const viewStart = horizontal ? view.x : view.y;
2466
+ const viewEnd = viewStart + (horizontal ? view.width : view.height);
2467
+ if (length <= 0) return 0;
2468
+ if (start < viewStart) return -Math.min(1, (viewStart - start) / length);
2469
+ if (start + length > viewEnd) return Math.min(1, (start + length - viewEnd) / length);
2470
+ return 0;
2471
+ }
2472
+ function scrollTransitionValues(spec, progress) {
2473
+ const identity = spec.transition(EMPTY_EFFECT, PHASES.identity).values;
2474
+ const configuration = spec.configuration ?? "interactive";
2475
+ if (configuration === "identity" || progress === 0) return identity;
2476
+ const edge = spec.transition(EMPTY_EFFECT, progress < 0 ? PHASES.topLeading : PHASES.bottomTrailing).values;
2477
+ if (configuration === "animated") return edge;
2478
+ return interpolateEffects(identity, edge, Math.abs(progress));
2479
+ }
2480
+ function ScrollTransitionView({ spec, children }) {
2481
+ return /* @__PURE__ */ jsx(
2482
+ EffectBox,
2483
+ {
2484
+ alwaysFrame: true,
2485
+ render: (reported) => effectStyle(scrollTransitionValues(spec, scrollProgress(reported, spec.axis))),
2486
+ ...spec.configuration === "animated" ? { animationToken: (reported) => Math.sign(scrollProgress(reported, spec.axis)) + 1 } : {},
2487
+ children
2488
+ }
2002
2489
  );
2003
2490
  }
2004
- function Link(props) {
2005
- const { own, modifiers } = splitProps(props);
2006
- const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
2007
- return applyModifiers(sb("button", { role: null, style: "automatic" }, { tap: () => openURL(own.destination) }, label), modifiers);
2491
+ const r = (n) => {
2492
+ const v = Math.round(n * 100) / 100;
2493
+ return Object.is(v, -0) ? "0" : String(v);
2494
+ };
2495
+ class Path {
2496
+ parts = [];
2497
+ current = null;
2498
+ start = null;
2499
+ constructor(build) {
2500
+ build?.(this);
2501
+ }
2502
+ /** `Path(rect)` */
2503
+ static rect(rect) {
2504
+ return new Path().addRect(rect);
2505
+ }
2506
+ /** `Path(roundedRect:cornerRadius:)` */
2507
+ static roundedRect(rect, cornerRadius) {
2508
+ return new Path().addRoundedRect(rect, cornerRadius);
2509
+ }
2510
+ /** `Path(ellipseIn:)` */
2511
+ static ellipse(rect) {
2512
+ return new Path().addEllipse(rect);
2513
+ }
2514
+ move(to) {
2515
+ this.parts.push(`M${r(to.x)} ${r(to.y)}`);
2516
+ this.current = to;
2517
+ this.start = to;
2518
+ return this;
2519
+ }
2520
+ addLine(to) {
2521
+ if (!this.current) return this.move(to);
2522
+ this.parts.push(`L${r(to.x)} ${r(to.y)}`);
2523
+ this.current = to;
2524
+ return this;
2525
+ }
2526
+ addLines(points) {
2527
+ points.forEach((point, index) => index === 0 ? this.move(point) : this.addLine(point));
2528
+ return this;
2529
+ }
2530
+ addQuadCurve(to, control) {
2531
+ if (!this.current) this.move(control);
2532
+ this.parts.push(`Q${r(control.x)} ${r(control.y)} ${r(to.x)} ${r(to.y)}`);
2533
+ this.current = to;
2534
+ return this;
2535
+ }
2536
+ addCurve(to, control1, control2) {
2537
+ if (!this.current) this.move(control1);
2538
+ this.parts.push(`C${r(control1.x)} ${r(control1.y)} ${r(control2.x)} ${r(control2.y)} ${r(to.x)} ${r(to.y)}`);
2539
+ this.current = to;
2540
+ return this;
2541
+ }
2542
+ /**
2543
+ * `addArc(center:radius:startAngle:endAngle:clockwise:)`, angles in
2544
+ * degrees. As in SwiftUI's flipped coordinates, `clockwise: false` draws
2545
+ * clockwise on screen.
2546
+ */
2547
+ addArc(center, radius, startAngle, endAngle, clockwise) {
2548
+ const rad = (deg) => deg * Math.PI / 180;
2549
+ const point = (deg) => ({ x: center.x + radius * Math.cos(rad(deg)), y: center.y + radius * Math.sin(rad(deg)) });
2550
+ const from = point(startAngle);
2551
+ if (this.current) this.addLine(from);
2552
+ else this.move(from);
2553
+ const sweepPositive = !clockwise;
2554
+ let delta = endAngle - startAngle;
2555
+ if (sweepPositive) while (delta < 0) delta += 360;
2556
+ else while (delta > 0) delta -= 360;
2557
+ if (Math.abs(delta) >= 360) {
2558
+ const half = point(startAngle + (sweepPositive ? 180 : -180));
2559
+ const flag = sweepPositive ? 1 : 0;
2560
+ this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(half.x)} ${r(half.y)}`);
2561
+ this.parts.push(`A${r(radius)} ${r(radius)} 0 0 ${flag} ${r(from.x)} ${r(from.y)}`);
2562
+ this.current = from;
2563
+ return this;
2564
+ }
2565
+ const to = point(startAngle + delta);
2566
+ const large = Math.abs(delta) > 180 ? 1 : 0;
2567
+ this.parts.push(`A${r(radius)} ${r(radius)} 0 ${large} ${sweepPositive ? 1 : 0} ${r(to.x)} ${r(to.y)}`);
2568
+ this.current = to;
2569
+ return this;
2570
+ }
2571
+ addRect(rect) {
2572
+ this.move({ x: rect.x, y: rect.y });
2573
+ this.addLine({ x: rect.x + rect.width, y: rect.y });
2574
+ this.addLine({ x: rect.x + rect.width, y: rect.y + rect.height });
2575
+ this.addLine({ x: rect.x, y: rect.y + rect.height });
2576
+ return this.closeSubpath();
2577
+ }
2578
+ addRoundedRect(rect, cornerRadius) {
2579
+ const c = Math.max(0, Math.min(cornerRadius, rect.width / 2, rect.height / 2));
2580
+ if (c === 0) return this.addRect(rect);
2581
+ const { x, y, width: w, height: h } = rect;
2582
+ this.move({ x: x + c, y });
2583
+ this.addLine({ x: x + w - c, y });
2584
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w)} ${r(y + c)}`);
2585
+ this.current = { x: x + w, y: y + c };
2586
+ this.addLine({ x: x + w, y: y + h - c });
2587
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + w - c)} ${r(y + h)}`);
2588
+ this.current = { x: x + w - c, y: y + h };
2589
+ this.addLine({ x: x + c, y: y + h });
2590
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x)} ${r(y + h - c)}`);
2591
+ this.current = { x, y: y + h - c };
2592
+ this.addLine({ x, y: y + c });
2593
+ this.parts.push(`A${r(c)} ${r(c)} 0 0 1 ${r(x + c)} ${r(y)}`);
2594
+ this.current = { x: x + c, y };
2595
+ return this.closeSubpath();
2596
+ }
2597
+ addEllipse(rect) {
2598
+ const rx = rect.width / 2;
2599
+ const ry = rect.height / 2;
2600
+ const cx = rect.x + rx;
2601
+ const cy = rect.y + ry;
2602
+ this.move({ x: cx + rx, y: cy });
2603
+ this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx - rx)} ${r(cy)}`);
2604
+ this.parts.push(`A${r(rx)} ${r(ry)} 0 0 1 ${r(cx + rx)} ${r(cy)}`);
2605
+ this.current = { x: cx + rx, y: cy };
2606
+ return this.closeSubpath();
2607
+ }
2608
+ addPath(path) {
2609
+ this.parts.push(path.svg());
2610
+ return this;
2611
+ }
2612
+ closeSubpath() {
2613
+ this.parts.push("Z");
2614
+ this.current = this.start;
2615
+ return this;
2616
+ }
2617
+ get isEmpty() {
2618
+ return this.parts.length === 0;
2619
+ }
2620
+ /** The SVG path data. */
2621
+ svg() {
2622
+ return this.parts.join("");
2623
+ }
2624
+ toString() {
2625
+ return this.svg();
2626
+ }
2008
2627
  }
2009
2628
  function Button(props) {
2010
2629
  const { own, modifiers } = splitProps(props);
@@ -2076,7 +2695,7 @@ function collectText(node) {
2076
2695
  if (Array.isArray(node)) return node.map(collectText).join("");
2077
2696
  if (typeof node === "object" && "props" in node) {
2078
2697
  const element = node;
2079
- if (element.type === Fragment$1 || element.type === Text) return collectText(element.props.children);
2698
+ if (element.type === Fragment || element.type === Text) return collectText(element.props.children);
2080
2699
  }
2081
2700
  return "";
2082
2701
  }
@@ -2089,11 +2708,11 @@ function Slider(props) {
2089
2708
  const children = [];
2090
2709
  if (own.label !== void 0 && !environment.labelsHidden) {
2091
2710
  labels.push("label");
2092
- children.push(/* @__PURE__ */ jsx(Fragment$1, { children: own.label }, "label"));
2711
+ children.push(/* @__PURE__ */ jsx(Fragment, { children: own.label }, "label"));
2093
2712
  }
2094
2713
  if (own.minimumValueLabel !== void 0 || own.maximumValueLabel !== void 0) {
2095
2714
  labels.push("min", "max");
2096
- children.push(/* @__PURE__ */ jsx(Fragment$1, { children: own.minimumValueLabel }, "min"), /* @__PURE__ */ jsx(Fragment$1, { children: own.maximumValueLabel }, "max"));
2715
+ children.push(/* @__PURE__ */ jsx(Fragment, { children: own.minimumValueLabel }, "min"), /* @__PURE__ */ jsx(Fragment, { children: own.maximumValueLabel }, "max"));
2097
2716
  }
2098
2717
  return applyModifiers(
2099
2718
  sb("slider", { value, min, max, step: own.step ?? null, labels }, { slide: (event) => setValue(event.value) }, children.length ? children : void 0),
@@ -2155,9 +2774,9 @@ function ProgressView(props) {
2155
2774
  }
2156
2775
  const label = own.label ?? own.children;
2157
2776
  const children = [];
2158
- if (label !== void 0 && label !== null) children.push(/* @__PURE__ */ jsx(Fragment$1, { children: label }, "label"));
2777
+ if (label !== void 0 && label !== null) children.push(/* @__PURE__ */ jsx(Fragment, { children: label }, "label"));
2159
2778
  if (own.currentValueLabel !== void 0 && own.currentValueLabel !== null) {
2160
- children.push(/* @__PURE__ */ jsx(Fragment$1, { children: styled({ foreground: { hierarchical: 2 } }, own.currentValueLabel) }, "current"));
2779
+ children.push(/* @__PURE__ */ jsx(Fragment, { children: styled({ foreground: { hierarchical: 2 } }, own.currentValueLabel) }, "current"));
2161
2780
  }
2162
2781
  return applyModifiers(
2163
2782
  sb(
@@ -2203,127 +2822,6 @@ function TextEditor(props) {
2203
2822
  function buttonDisabled(modifiers) {
2204
2823
  return modifiers.some(([key, value]) => key === "disabled" && value === true);
2205
2824
  }
2206
- const isPushedView = (value) => typeof value === "object" && value !== null && "view" in value && Object.keys(value).length === 1;
2207
- function NavigationStack(props) {
2208
- const enclosing = useNavigation();
2209
- if (enclosing) return /* @__PURE__ */ jsx(FlattenedStack, { ...props });
2210
- return /* @__PURE__ */ jsx(OwnStack, { ...props });
2211
- }
2212
- function FlattenedStack(props) {
2213
- const { own, modifiers } = splitProps(props);
2214
- return applyModifiers(
2215
- /* @__PURE__ */ jsxs(Fragment, { children: [
2216
- own.destination && /* @__PURE__ */ jsx(RegisterDestination, { destination: own.destination }),
2217
- own.children
2218
- ] }),
2219
- modifiers
2220
- );
2221
- }
2222
- function OwnStack(props) {
2223
- const { own, modifiers } = splitProps(props);
2224
- const [internalPath, setInternalPath] = useState([]);
2225
- const [path, setPath] = own.path !== void 0 ? readBinding(own.path, own.onPathChange) : [internalPath, setInternalPath];
2226
- const destination = useRef(null);
2227
- destination.current = own.destination ?? null;
2228
- const context = {
2229
- push: (value) => setPath([...path, value]),
2230
- pop: () => setPath(path.slice(0, -1)),
2231
- registerDestination: (builder) => {
2232
- destination.current = builder;
2233
- }
2234
- };
2235
- const screens = [
2236
- /* @__PURE__ */ jsx(Fragment$1, { children: sb("navscreen", { title: "", displayMode: "automatic", depth: 0 }, { tap: context.pop }, own.children) }, "root")
2237
- ];
2238
- path.forEach((value, index) => {
2239
- const pop = () => setPath(path.slice(0, index));
2240
- screens.push(
2241
- /* @__PURE__ */ jsx(Fragment$1, { children: sb(
2242
- "navscreen",
2243
- { title: "", displayMode: "automatic", depth: index + 1 },
2244
- { tap: pop },
2245
- /* @__PURE__ */ jsx(DismissContext.Provider, { value: pop, children: /* @__PURE__ */ jsx(PathScreen, { value, destination }) })
2246
- ) }, index + 1)
2247
- );
2248
- });
2249
- return applyModifiers(
2250
- sb("navstack", {}, void 0, /* @__PURE__ */ jsx(NavigationContext.Provider, { value: context, children: screens })),
2251
- modifiers
2252
- );
2253
- }
2254
- function PathScreen({ value, destination }) {
2255
- if (isPushedView(value)) return value.view;
2256
- return destination.current ? destination.current(value) : null;
2257
- }
2258
- function NavigationLink(props) {
2259
- const { own, modifiers } = splitProps(props);
2260
- const navigation = useNavigation();
2261
- const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.children;
2262
- const tap = () => {
2263
- if (!navigation) return;
2264
- if (own.destination !== void 0) navigation.push({ view: own.destination });
2265
- else navigation.push(own.value);
2266
- };
2267
- return applyModifiers(sb("navlink", {}, { tap }, label), modifiers);
2268
- }
2269
- const SplitSelectionContext = createContext(null);
2270
- function NavigationSplitView(props) {
2271
- const { own, modifiers } = splitProps(props);
2272
- const sizeClass = useHorizontalSizeClass();
2273
- const [selected, setSelected] = useState(false);
2274
- const clearRef = useRef(() => {
2275
- });
2276
- const report = {
2277
- report: (nowSelected, clear2) => {
2278
- clearRef.current = clear2;
2279
- if (nowSelected !== selected) setSelected(nowSelected);
2280
- }
2281
- };
2282
- const clear = () => clearRef.current();
2283
- const [internal, setInternal] = useState("automatic");
2284
- const [visibility, setVisibility] = own.columnVisibility !== void 0 ? readBinding(own.columnVisibility, own.onColumnVisibilityChange) : [internal, setInternal];
2285
- if (sizeClass === "compact") {
2286
- return applyModifiers(
2287
- /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children: /* @__PURE__ */ jsx(CompactSplit, { sidebar: own.sidebar, detail: own.detail, selected, clear }) }),
2288
- modifiers
2289
- );
2290
- }
2291
- const sidebarVisible = visibility !== "detailOnly";
2292
- const toggle = () => withAnimation(() => setVisibility(sidebarVisible ? "detailOnly" : "all"));
2293
- const detail = isValidElement(own.detail) && own.detail.type === NavigationStack ? own.detail : /* @__PURE__ */ jsx(NavigationStack, { children: own.detail });
2294
- return applyModifiers(
2295
- sb("navsplit", { sidebarVisible }, { tap: toggle }, [
2296
- /* @__PURE__ */ jsx(SplitColumn, { report, children: /* @__PURE__ */ jsx(NavigationStack, { children: own.sidebar }) }, "sidebar"),
2297
- /* @__PURE__ */ jsx(SplitColumn, { report: null, children: detail }, "detail")
2298
- ]),
2299
- modifiers
2300
- );
2301
- }
2302
- function SplitColumn({ report, children }) {
2303
- return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: report, children }) });
2304
- }
2305
- function CompactSplit({ sidebar, detail, selected, clear }) {
2306
- const [extra, setExtra] = useState([]);
2307
- const base = selected ? [{ view: /* @__PURE__ */ jsx(DetailScope, { children: detail }) }] : [];
2308
- const path = [...base, ...extra];
2309
- const setPath = (next) => {
2310
- if (selected && next.length === 0) {
2311
- setExtra([]);
2312
- clear();
2313
- return;
2314
- }
2315
- setExtra(next.slice(base.length));
2316
- };
2317
- return /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(NavigationStack, { path: [path, setPath], children: sidebar }) });
2318
- }
2319
- function DetailScope({ children }) {
2320
- return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
2321
- }
2322
- function useReportSplitSelection(split, selected, clear) {
2323
- useLayoutEffect(() => {
2324
- split?.report(selected, clear);
2325
- });
2326
- }
2327
2825
  const NO_CLEAR = () => {
2328
2826
  };
2329
2827
  function List(props) {
@@ -2354,10 +2852,13 @@ function List(props) {
2354
2852
  }
2355
2853
  };
2356
2854
  }
2357
- useReportSplitSelection(split, selected, clearSelection);
2855
+ useReportSplitSelection(split, selected, clearSelection, own.selection !== void 0);
2358
2856
  const refresh = useRefreshable(takeModifier(modifiers, "refreshable"));
2359
2857
  Object.assign(listProps, refresh.props);
2360
- const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, wrapRows(own.children)) });
2858
+ const ownSettings = takeScrollSettings(modifiers);
2859
+ const edgeEffect = edgeEffectProp(useScrollSettings(ownSettings));
2860
+ if (edgeEffect) listProps["edgeEffect"] = edgeEffect;
2861
+ const element = /* @__PURE__ */ jsx(LazyContext.Provider, { value: "vertical", children: sb("list", listProps, refresh.handlers, providingScrollSettings(ownSettings, wrapRows(own.children))) });
2361
2862
  return applyModifiers(
2362
2863
  selection ? /* @__PURE__ */ jsx(ListSelectionContext.Provider, { value: selection, children: element }) : element,
2363
2864
  modifiers
@@ -2543,11 +3044,11 @@ function Host(props) {
2543
3044
  if (typeof document === "undefined") return null;
2544
3045
  const element = document.createElement("div");
2545
3046
  element.className = "sb-host-content";
2546
- registerHostContent(key, element);
2547
3047
  return element;
2548
3048
  });
2549
3049
  const bridge = useContextBridge(own.contexts);
2550
3050
  const root = useRef(null);
3051
+ const mounted = useRef(false);
2551
3052
  const sizing = own.sizing ?? "content";
2552
3053
  const style = sizing === "fill" ? { height: "100%", ...own.style } : own.style;
2553
3054
  const tree = bridge(
@@ -2555,6 +3056,8 @@ function Host(props) {
2555
3056
  );
2556
3057
  useLayoutEffect(() => {
2557
3058
  if (!content) return;
3059
+ mounted.current = true;
3060
+ registerHostContent(key, content);
2558
3061
  root.current ??= createRoot(content);
2559
3062
  const current = root.current;
2560
3063
  queueMicrotask(() => {
@@ -2565,175 +3068,26 @@ function Host(props) {
2565
3068
  });
2566
3069
  useEffect(
2567
3070
  () => () => {
2568
- const current = root.current;
2569
- root.current = null;
3071
+ mounted.current = false;
2570
3072
  unregisterHostContent(key);
2571
- queueMicrotask(() => current?.unmount());
3073
+ queueMicrotask(() => {
3074
+ if (mounted.current) return;
3075
+ const current = root.current;
3076
+ root.current = null;
3077
+ current?.unmount();
3078
+ });
2572
3079
  },
2573
3080
  [key]
2574
3081
  );
2575
3082
  return applyModifiers(sb("host", { content: key, sizing }), modifiers);
2576
3083
  }
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
3084
  function Menu(props) {
2731
3085
  const { own, modifiers } = splitProps(props);
2732
3086
  const label = own.title !== void 0 ? /* @__PURE__ */ jsx(Text, { children: own.title }) : own.label;
2733
3087
  return applyModifiers(
2734
3088
  sb("menu", {}, void 0, [
2735
- /* @__PURE__ */ jsx(Fragment$1, { children: sb("zstack", { alignment: "center" }, void 0, label) }, "label"),
2736
- /* @__PURE__ */ jsx(Fragment$1, { children: own.children }, "items")
3089
+ /* @__PURE__ */ jsx(Fragment, { children: sb("zstack", { alignment: "center" }, void 0, label) }, "label"),
3090
+ /* @__PURE__ */ jsx(Fragment, { children: own.children }, "items")
2737
3091
  ]),
2738
3092
  modifiers
2739
3093
  );
@@ -3006,9 +3360,9 @@ function Chart(props) {
3006
3360
  }
3007
3361
  const xScale = scaleFor(xValues, { domain: own.xScale?.domain });
3008
3362
  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));
3363
+ const round2 = (n) => Math.round(n * 1e6) / 1e6;
3364
+ const ux = (v) => round2(xScale.unit(v));
3365
+ const uy = (v) => round2(1 - yScale.unit(v));
3012
3366
  let continuousBand = 1;
3013
3367
  if (xScale.kind !== "band") {
3014
3368
  const centers = [...new Set(marks.filter((m) => m.kind === "bar").map((m) => ux(m.props.x)))].sort((a, b) => a - b);
@@ -3020,7 +3374,7 @@ function Chart(props) {
3020
3374
  const annotation = mark.props.annotation;
3021
3375
  if (!annotation) return;
3022
3376
  items.push(
3023
- /* @__PURE__ */ jsx(Fragment$1, { children: sb(
3377
+ /* @__PURE__ */ jsx(Fragment, { children: sb(
3024
3378
  "chartitem",
3025
3379
  {
3026
3380
  role: "annotation",
@@ -3054,15 +3408,15 @@ function Chart(props) {
3054
3408
  case "bar": {
3055
3409
  const style = common(mark);
3056
3410
  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);
3411
+ const center = round2((b0 + b1) / 2);
3412
+ const half = round2((b1 - b0) * 0.8 / 2);
3059
3413
  const top = uy(Math.max(asNumber(p.y), p.yStart ?? 0));
3060
3414
  const bottom = uy(Math.min(asNumber(p.y), p.yStart ?? 0));
3061
3415
  const rect = {
3062
3416
  kind: "rect",
3063
3417
  ...style,
3064
- x0: p.width !== void 0 ? center : round(center - half),
3065
- x1: p.width !== void 0 ? center : round(center + half),
3418
+ x0: p.width !== void 0 ? center : round2(center - half),
3419
+ x1: p.width !== void 0 ? center : round2(center + half),
3066
3420
  y0: top,
3067
3421
  y1: bottom,
3068
3422
  cornerRadius: p.cornerRadius ?? 0,
@@ -3133,7 +3487,7 @@ function Chart(props) {
3133
3487
  }
3134
3488
  }
3135
3489
  const axis = (scale, position, flipY) => {
3136
- const flip = (u) => round(flipY ? 1 - u : u);
3490
+ const flip = (u) => round2(flipY ? 1 - u : u);
3137
3491
  return {
3138
3492
  position,
3139
3493
  gridLines: scale.gridLines.map(flip),
@@ -3158,8 +3512,8 @@ function Gauge(props) {
3158
3512
  const value = (own.value - min) / (max - min || 1);
3159
3513
  const children = [];
3160
3514
  const asView = (node) => typeof node === "string" || typeof node === "number" ? /* @__PURE__ */ jsx(Text, { children: node }) : node;
3161
- if (own.label !== void 0) children.push(/* @__PURE__ */ jsx(Fragment$1, { children: asView(own.label) }, "label"));
3162
- if (own.currentValueLabel !== void 0) children.push(/* @__PURE__ */ jsx(Fragment$1, { children: asView(own.currentValueLabel) }, "current"));
3515
+ if (own.label !== void 0) children.push(/* @__PURE__ */ jsx(Fragment, { children: asView(own.label) }, "label"));
3516
+ if (own.currentValueLabel !== void 0) children.push(/* @__PURE__ */ jsx(Fragment, { children: asView(own.currentValueLabel) }, "current"));
3163
3517
  return applyModifiers(
3164
3518
  sb(
3165
3519
  "gauge",
@@ -3233,7 +3587,7 @@ function GroupBox(props) {
3233
3587
  }
3234
3588
  function ControlGroup(props) {
3235
3589
  const { own, modifiers } = splitProps(props);
3236
- return modifiers.length ? applyModifiers(/* @__PURE__ */ jsx(Fragment, { children: own.children }), modifiers) : own.children;
3590
+ return modifiers.length ? applyModifiers(/* @__PURE__ */ jsx(Fragment$1, { children: own.children }), modifiers) : own.children;
3237
3591
  }
3238
3592
  function DisclosureGroup(props) {
3239
3593
  const { own, modifiers } = splitProps(props);
@@ -3567,10 +3921,10 @@ function Canvas(props) {
3567
3921
  if (draw.scale.x !== 1 || draw.scale.y !== 1) view = styled({ scale: draw.scale }, view);
3568
3922
  if (Math.abs(draw.rotation) > 1e-6) view = styled({ rotation: draw.rotation }, view);
3569
3923
  if (draw.opacity !== 1) view = styled({ opacity: draw.opacity }, view);
3570
- return /* @__PURE__ */ jsx(Fragment$1, { children: styled({ position: { x: draw.x, y: draw.y } }, view) }, index);
3924
+ return /* @__PURE__ */ jsx(Fragment, { children: styled({ position: { x: draw.x, y: draw.y } }, view) }, index);
3571
3925
  });
3572
3926
  return applyModifiers(
3573
- sb("zstack", { alignment: "topLeading" }, void 0, [/* @__PURE__ */ jsx(Fragment$1, { children: reader }, "canvas"), ...symbols]),
3927
+ sb("zstack", { alignment: "topLeading" }, void 0, [/* @__PURE__ */ jsx(Fragment, { children: reader }, "canvas"), ...symbols]),
3574
3928
  modifiers
3575
3929
  );
3576
3930
  }
@@ -3788,7 +4142,7 @@ function VideoPlayer(props) {
3788
4142
  );
3789
4143
  if (own.videoOverlay === void 0) return applyModifiers(video, modifiers);
3790
4144
  return applyModifiers(
3791
- sb("zstack", { alignment: "center" }, void 0, [/* @__PURE__ */ jsx(Fragment$1, { children: video }, "video"), /* @__PURE__ */ jsx(Fragment$1, { children: own.videoOverlay }, "overlay")]),
4145
+ sb("zstack", { alignment: "center" }, void 0, [/* @__PURE__ */ jsx(Fragment, { children: video }, "video"), /* @__PURE__ */ jsx(Fragment, { children: own.videoOverlay }, "overlay")]),
3792
4146
  modifiers
3793
4147
  );
3794
4148
  }
@@ -3948,6 +4302,7 @@ export {
3948
4302
  Label,
3949
4303
  LabeledContent,
3950
4304
  Layout,
4305
+ LazyHGrid,
3951
4306
  LazyHStack,
3952
4307
  LazyVGrid,
3953
4308
  LazyVStack,
@@ -3956,9 +4311,11 @@ export {
3956
4311
  Link,
3957
4312
  List,
3958
4313
  Menu,
4314
+ NO_GEOMETRY,
3959
4315
  NavigationLink,
3960
4316
  NavigationSplitView,
3961
4317
  NavigationStack,
4318
+ OutsideSplit,
3962
4319
  Path,
3963
4320
  PhaseAnimator,
3964
4321
  Picker,
@@ -3994,6 +4351,7 @@ export {
3994
4351
  VStack,
3995
4352
  VideoPlayer,
3996
4353
  ViewThatFits,
4354
+ VisualEffect,
3997
4355
  ZStack,
3998
4356
  answerLayout,
3999
4357
  color,
@@ -4001,22 +4359,26 @@ export {
4001
4359
  flattenChildren,
4002
4360
  font,
4003
4361
  frame,
4362
+ geometryProxy,
4004
4363
  gradient,
4005
4364
  hex,
4006
4365
  insets,
4007
4366
  keyframeValues,
4008
4367
  mount,
4009
4368
  moveItems,
4369
+ nextGeometry,
4010
4370
  niceStep,
4011
4371
  opacity,
4012
4372
  openURL,
4013
4373
  padding,
4014
4374
  placeholder,
4015
4375
  plainText,
4376
+ providingScrollSettings,
4016
4377
  readBinding,
4017
4378
  rgb,
4018
4379
  shapeStyle,
4019
4380
  system,
4381
+ takeScrollSettings,
4020
4382
  timeTicks,
4021
4383
  unitPoint,
4022
4384
  useAVPlayer,