@swiftbrowser/react 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,6 +103,14 @@ a React root of its own: the page's React state reaches it through props as
103
103
  usual, and its contexts through `contexts={[…]}` (see
104
104
  [Contexts across roots](#contexts-across-roots)).
105
105
 
106
+ There is no status bar in a page, so `safeArea` stands in for one. A
107
+ `fill` island keeps 10 points at the top, the way SwiftUI keeps a window's
108
+ bars off its edge. Navigation bars sit below that inset and their
109
+ background reaches up into it, and lists start below it. A `content`
110
+ island has no insets. Pass a number for the top inset (`safeArea={0}` puts
111
+ the bars flush with the edge) or an object such as
112
+ `safeArea={{ top: 24, bottom: 34 }}`.
113
+
106
114
  ### Try the demos
107
115
 
108
116
  ```sh
package/dist/index.js CHANGED
@@ -483,7 +483,11 @@ function useContextBridge(contexts = [], options = {}) {
483
483
  const values = all.map((context) => useContext(context));
484
484
  return (children) => all.reduceRight((inner, context, index) => createElement(context.Provider, { value: values[index] }, inner), children);
485
485
  }
486
- const NO_SAFE_AREA = { top: 0, leading: 0, bottom: 0, trailing: 0 };
486
+ const WINDOW_TOP_INSET = 10;
487
+ function insetsOf(safeArea, fit) {
488
+ const given = typeof safeArea === "number" ? { top: safeArea } : safeArea ?? { top: fit === "fill" ? WINDOW_TOP_INSET : 0 };
489
+ return { top: given.top ?? 0, leading: given.leading ?? 0, bottom: given.bottom ?? 0, trailing: given.trailing ?? 0 };
490
+ }
487
491
  function SwiftUIView({
488
492
  children,
489
493
  fit = "fill",
@@ -491,6 +495,7 @@ function SwiftUIView({
491
495
  dynamicTypeSize = "large",
492
496
  contexts,
493
497
  assets,
498
+ safeArea,
494
499
  className,
495
500
  style
496
501
  }) {
@@ -506,7 +511,7 @@ function SwiftUIView({
506
511
  const instance = mount(screen.current, latest.current, {
507
512
  colorScheme,
508
513
  dynamicTypeSize,
509
- safeArea: NO_SAFE_AREA,
514
+ safeArea: insetsOf(safeArea, fit),
510
515
  contentHeight: fit === "content",
511
516
  ...assets ? { assets } : {}
512
517
  });
@@ -519,6 +524,11 @@ function SwiftUIView({
519
524
  useLayoutEffect(() => {
520
525
  mounted.current?.root.render(tree);
521
526
  });
527
+ const insets2 = insetsOf(safeArea, fit);
528
+ const insetsKey = `${insets2.top},${insets2.leading},${insets2.bottom},${insets2.trailing}`;
529
+ useLayoutEffect(() => {
530
+ mounted.current?.renderer.setSafeArea(insets2);
531
+ }, [insetsKey]);
522
532
  useLayoutEffect(() => {
523
533
  if (device.current) applyTypeSizeVariables(device.current, dynamicTypeSize);
524
534
  mounted.current?.setEnvironment({ colorScheme, dynamicTypeSize });
@@ -1759,18 +1769,91 @@ function Searchable({ text, onChange, prompt }) {
1759
1769
  function applyModifiers(element, modifiers) {
1760
1770
  const sides = [];
1761
1771
  const node = wrap(element, modifiers, sides);
1762
- if (sides.length === 0) return node;
1763
1772
  return createElement(Fragment, null, node, ...sides);
1764
1773
  }
1765
1774
  function wrap(element, modifiers, sides) {
1766
1775
  let node = element;
1767
1776
  for (const [key, value] of modifiers) {
1768
- if (value === void 0) continue;
1769
- if (value === null && key !== "lineLimit" && key !== "badge") continue;
1770
- node = apply(key, value, node, sides);
1777
+ const inactive = value === void 0 || value === null && key !== "lineLimit" && key !== "badge";
1778
+ const next = inactive ? node : apply(key, value, node, sides);
1779
+ node = next === node ? neutral(key, node) : next;
1771
1780
  }
1772
1781
  return node;
1773
1782
  }
1783
+ const STYLED_KEYS = /* @__PURE__ */ new Set([
1784
+ "padding",
1785
+ "font",
1786
+ "fontWeight",
1787
+ "bold",
1788
+ "foregroundStyle",
1789
+ "background",
1790
+ "frame",
1791
+ "cornerRadius",
1792
+ "clipShape",
1793
+ "clipped",
1794
+ "opacity",
1795
+ "disabled",
1796
+ "hidden",
1797
+ "layoutPriority",
1798
+ "lineLimit",
1799
+ "multilineTextAlignment",
1800
+ "fixedSize",
1801
+ "offset",
1802
+ "rotationEffect",
1803
+ "scaleEffect",
1804
+ "shadow",
1805
+ "tint",
1806
+ "badge",
1807
+ "listRowInsets",
1808
+ "imageScale",
1809
+ "transition",
1810
+ "gridColumnAlignment",
1811
+ "gridCellColumns",
1812
+ "aspectRatio",
1813
+ "scaledToFit",
1814
+ "scaledToFill",
1815
+ "blur",
1816
+ "brightness",
1817
+ "contrast",
1818
+ "saturation",
1819
+ "grayscale",
1820
+ "hueRotation",
1821
+ "colorInvert",
1822
+ "colorMultiply",
1823
+ "blendMode",
1824
+ "mask",
1825
+ "position",
1826
+ "zIndex",
1827
+ "allowsHitTesting",
1828
+ "ignoresSafeArea",
1829
+ "rotation3DEffect",
1830
+ "gridCellAnchor",
1831
+ "alignmentGuide",
1832
+ "help",
1833
+ "pointerStyle",
1834
+ "matchedGeometryEffect",
1835
+ "containerRelativeFrame",
1836
+ "contentTransition"
1837
+ ]);
1838
+ const ENVIRONMENT_KEYS = /* @__PURE__ */ new Set([
1839
+ "buttonStyle",
1840
+ "controlSize",
1841
+ "pickerStyle",
1842
+ "labelsHidden",
1843
+ "refreshable",
1844
+ "submitLabel",
1845
+ "labelStyle",
1846
+ "redacted",
1847
+ "textCase"
1848
+ ]);
1849
+ const SCROLL_KEYS = /* @__PURE__ */ new Set(["scrollEdgeEffectStyle", "scrollEdgeEffectHidden", "contentMargins"]);
1850
+ function neutral(key, node) {
1851
+ if (key === "overlay") return decorated("overlay", "center", node, null);
1852
+ if (STYLED_KEYS.has(key)) return styled({}, node);
1853
+ if (ENVIRONMENT_KEYS.has(key)) return withEnvironment({}, node);
1854
+ if (SCROLL_KEYS.has(key)) return withScrollSettings({}, node);
1855
+ return node;
1856
+ }
1774
1857
  function apply(key, value, node, sides) {
1775
1858
  switch (key) {
1776
1859
  case "padding":