@swiftbrowser/react 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -304,6 +304,16 @@ title="Rename" action={rename} /></> }}`);
304
304
  `presentationDetents` inside a sheet sets its detents. `useDismiss()` inside
305
305
  a pushed screen or a sheet pops or dismisses it.
306
306
 
307
+ A sheet, a full-screen cover or a popover inherits the environment of the
308
+ view that presents it, as SwiftUI's presentations do, though it is drawn at
309
+ the root: a `defaultMinListRowHeight`, `font`, `fontWeight`, `bold`,
310
+ `monospacedDigit`, `tint`, `lineLimit`, `multilineTextAlignment` or
311
+ `imageScale` set around the presenter reaches the sheet's lists and text,
312
+ and so does one set on the presenting view itself when written after the
313
+ `sheet` (around it, as SwiftUI orders modifiers). An app drawn through
314
+ `RemoteTree` has its sheets inherit the host's environment around the tree
315
+ too.
316
+
307
317
  Navigation is mirrored in the browser's history by default: pushing a
308
318
  screen or presenting a sheet adds an entry, and the browser's back (a
309
319
  phone's edge swipe, Android's back gesture, the toolbar button) pops or
@@ -448,6 +458,12 @@ dragged the sidebar to on a Mac, once the drag ends; keep it (in
448
458
  `useAppStorage`, say) and pass it back as `ideal` to start there next time, as
449
459
  a Mac app restores its columns.
450
460
 
461
+ On a Mac the sidebar panel's top 44 points are the window's color, where
462
+ macOS draws the title bar behind the window's buttons. A page has no window
463
+ buttons there; `<SwiftUIView sidebarTitleBar={false}>` (or `mount(...,
464
+ { sidebarTitleBar: false })`, `renderer.sidebarTitleBar = false`) keeps the
465
+ panel's sidebar fill to its top. Web only: a native app is in a real window.
466
+
451
467
  ### Platform
452
468
 
453
469
  `usePlatform()` is `ios` or `macos`: the platform the app is drawn as. A
@@ -1 +1 @@
1
- {"version":3,"file":"remoteTree.d.ts","sourceRoot":"","sources":["../../src/components/remoteTree.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAsF,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG3H,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAK7D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAClC;AA0DD;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,eAAe,GAAG,SAAS,CA2E5E"}
1
+ {"version":3,"file":"remoteTree.d.ts","sourceRoot":"","sources":["../../src/components/remoteTree.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAsF,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG3H,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAM7D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAClC;AAgED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,eAAe,GAAG,SAAS,CA6E5E"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, createElement, useSyncExternalStore, useLayoutEffect, useRef, Fragment, useState, Children, useEffect, isValidElement, useId, cloneElement, useCallback } from "react";
1
+ import { createContext, useContext, createElement, isValidElement, useMemo, useSyncExternalStore, useLayoutEffect, useRef, Fragment, useState, Children, useEffect, useId, cloneElement, useCallback } from "react";
2
2
  import { DefaultEventPriority, ConcurrentRoot } from "react-reconciler/constants";
3
3
  import Reconciler from "react-reconciler";
4
4
  import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
@@ -746,6 +746,37 @@ function sb(kind, props, on, children, target) {
746
746
  if (target) hostProps.target = target;
747
747
  return children === void 0 ? createElement("sb", hostProps) : createElement("sb", hostProps, children);
748
748
  }
749
+ const INHERITED_STYLE_KEYS = /* @__PURE__ */ new Set([
750
+ "font",
751
+ "fontWeight",
752
+ "bold",
753
+ "monospacedDigit",
754
+ "tint",
755
+ "lineLimit",
756
+ "multilineTextAlignment",
757
+ "imageScale",
758
+ "defaultMinListRowHeight"
759
+ ]);
760
+ const PRESENTATION_KEYS = /* @__PURE__ */ new Set(["sheet", "fullScreenCover", "popover"]);
761
+ const InheritedStylesContext = createContext([]);
762
+ function useInheritedStyles() {
763
+ return useContext(InheritedStylesContext);
764
+ }
765
+ function styleOf(node) {
766
+ if (!isValidElement(node) || node.props.kind !== "styled") return {};
767
+ return node.props.props?.style ?? {};
768
+ }
769
+ function InheritStyle({ style, children }) {
770
+ const parent = useContext(InheritedStylesContext);
771
+ const key = JSON.stringify(style);
772
+ const value = useMemo(() => key === "{}" ? parent : [...parent, style], [parent, key]);
773
+ return createElement(InheritedStylesContext.Provider, { value }, children);
774
+ }
775
+ function replayStyles(styles, content) {
776
+ if (styles.length === 0) return content;
777
+ const provided = createElement(InheritedStylesContext.Provider, { value: styles }, content);
778
+ return styles.reduceRight((child, style) => sb("styled", { style }, void 0, child), provided);
779
+ }
749
780
  const NavigationContext = createContext(null);
750
781
  const ScreenDepthContext = createContext(0);
751
782
  function useScreenDepth() {
@@ -786,6 +817,10 @@ function renderNode(root, node, stack) {
786
817
  const children = node.children.length ? node.children.map((child) => renderNode(root, child, stack)) : void 0;
787
818
  return createElement(Fragment, { key: node.id }, sb(node.kind, node.props, root.handlersFor(node.id), children));
788
819
  }
820
+ function renderSheet(root, node, stack, inherited) {
821
+ const children = node.children.map((child) => renderNode(root, child, stack));
822
+ return createElement(Fragment, { key: node.id }, sb(node.kind, node.props, root.handlersFor(node.id), replayStyles(inherited, children)));
823
+ }
789
824
  function renderScreen(root, screen, stack) {
790
825
  const out = [screenPrefs(screen.props, "$screen")];
791
826
  for (const child of screen.children) {
@@ -804,6 +839,7 @@ function RemoteScreen({ root, id }) {
804
839
  function RemoteTree({ root, initialPath }) {
805
840
  useSyncExternalStore(root.subscribe, root.getVersion, root.getVersion);
806
841
  const environment = useContext(EnvironmentContext);
842
+ const inherited = useInheritedStyles();
807
843
  const tree = useContext(HostTreeContext);
808
844
  const navigation = useNavigation();
809
845
  const depth = useScreenDepth();
@@ -859,7 +895,7 @@ function RemoteTree({ root, initialPath }) {
859
895
  if ("colorScheme" in root.rootProps)
860
896
  out.push(createElement(Fragment, { key: "$scheme" }, sb(PREF_KIND, { colorScheme: root.rootProps["colorScheme"] }, void 0, void 0, "root")));
861
897
  for (const child of root.root.children) {
862
- const drawn = renderNode(root, child, stack);
898
+ const drawn = child.kind === "sheet" && inherited.length > 0 ? renderSheet(root, child, stack, inherited) : renderNode(root, child, stack);
863
899
  if (child.kind === "sheet" || child.kind === "alert") out.push(createElement(Fragment, { key: child.id }, sb(HOIST_KIND, void 0, void 0, drawn, "root")));
864
900
  else if (child.kind === "toolbar" || child.kind === "searchfield") out.push(createElement(Fragment, { key: child.id }, sb(HOIST_KIND, void 0, void 0, drawn, "navscreen")));
865
901
  else out.push(drawn);
@@ -1052,6 +1088,7 @@ function mount(screen, element, options = {}) {
1052
1088
  platform: options.platform === void 0 || options.platform === "auto" ? decidePlatform(width) : options.platform
1053
1089
  };
1054
1090
  renderer.contentHeight = options.contentHeight ?? false;
1091
+ if (options.sidebarTitleBar === false) renderer.sidebarTitleBar = false;
1055
1092
  if (options.assets) renderer.setAssetCatalog(options.assets);
1056
1093
  if (options.app) browserEnvironment.files?.setApp?.(options.app);
1057
1094
  renderer.setEnvironment({ colorScheme: environment.colorScheme, dynamicTypeSize: environment.dynamicTypeSize, platform: environment.platform });
@@ -1360,6 +1397,7 @@ function SwiftUIView({
1360
1397
  safeArea,
1361
1398
  history = true,
1362
1399
  keyboard = fit === "fill",
1400
+ sidebarTitleBar = true,
1363
1401
  className,
1364
1402
  style
1365
1403
  }) {
@@ -1387,6 +1425,9 @@ function SwiftUIView({
1387
1425
  instance.unmount();
1388
1426
  };
1389
1427
  }, [fit, history, keyboard]);
1428
+ useLayoutEffect(() => {
1429
+ if (mounted.current) mounted.current.renderer.sidebarTitleBar = sidebarTitleBar;
1430
+ }, [sidebarTitleBar, fit, history, keyboard]);
1390
1431
  useLayoutEffect(() => {
1391
1432
  mounted.current?.root.render(tree);
1392
1433
  });
@@ -2334,7 +2375,8 @@ function useReportSplitSelection(split, selected, clear, active2 = true) {
2334
2375
  function OutsideSplit({ children }) {
2335
2376
  return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
2336
2377
  }
2337
- function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
2378
+ function SheetPresenter({ isPresented, onDismiss, content, fullScreen, inherited }) {
2379
+ const around = useInheritedStyles();
2338
2380
  const [presented, setPresented] = readBinding(isPresented);
2339
2381
  if (!presented) return null;
2340
2382
  const dismiss = () => {
@@ -2350,7 +2392,10 @@ function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
2350
2392
  "sheet",
2351
2393
  { detents },
2352
2394
  { tap: dismiss },
2353
- /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(OutsideSplit, { children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) }) })
2395
+ replayStyles(
2396
+ inherited && inherited.length > 0 ? [...around, ...inherited] : around,
2397
+ /* @__PURE__ */ jsx(NavigationContext.Provider, { value: null, children: /* @__PURE__ */ jsx(OutsideSplit, { children: /* @__PURE__ */ jsx(DismissContext.Provider, { value: dismiss, children: content }) }) })
2398
+ )
2354
2399
  ),
2355
2400
  "root"
2356
2401
  );
@@ -2857,13 +2902,30 @@ function applyModifiers(element, modifiers) {
2857
2902
  const isPreference = (side) => isValidElement(side) && side.props.kind === PREF_KIND;
2858
2903
  function wrap(element, modifiers, sides) {
2859
2904
  let node = element;
2905
+ const holds = holdsViews(element);
2906
+ const presentations = [];
2860
2907
  for (const [key, value] of modifiers) {
2861
2908
  const inactive = value === void 0 || value === null && key !== "lineLimit" && key !== "badge";
2909
+ const before = sides.length;
2862
2910
  const next = inactive ? node : apply(key, value, node, sides);
2863
2911
  node = next === node ? neutral(key, node) : next;
2912
+ if (INHERITED_STYLE_KEYS.has(key)) {
2913
+ const style = styleOf(node);
2914
+ if (Object.keys(style).length > 0) for (const presentation of presentations) presentation.after.push(style);
2915
+ if (holds) node = createElement(InheritStyle, { style }, node);
2916
+ }
2917
+ if (PRESENTATION_KEYS.has(key) && sides.length > before) presentations.push({ at: before, after: [] });
2918
+ }
2919
+ for (const { at, after } of presentations) {
2920
+ const side = sides[at];
2921
+ if (after.length > 0 && isValidElement(side)) sides[at] = cloneElement(side, { inherited: after.reverse() });
2864
2922
  }
2865
2923
  return node;
2866
2924
  }
2925
+ function holdsViews(element) {
2926
+ if (!isValidElement(element)) return false;
2927
+ return element.type !== "sb" || element.props.children !== void 0;
2928
+ }
2867
2929
  const STYLED_KEYS = /* @__PURE__ */ new Set([
2868
2930
  "padding",
2869
2931
  "font",
@@ -6327,7 +6389,7 @@ function Chart(props) {
6327
6389
  const key = mark.props.foregroundStyleBy;
6328
6390
  if (key !== void 0 && !series.includes(key)) series.push(key);
6329
6391
  }
6330
- const styleOf = (mark) => {
6392
+ const styleOf2 = (mark) => {
6331
6393
  if (mark.props.foregroundStyle !== void 0) return shapeStyle(mark.props.foregroundStyle);
6332
6394
  const key = mark.props.foregroundStyleBy;
6333
6395
  if (key !== void 0) return { name: PALETTE[series.indexOf(key) % PALETTE.length] };
@@ -6385,7 +6447,7 @@ function Chart(props) {
6385
6447
  );
6386
6448
  };
6387
6449
  const common = (mark) => {
6388
- const base = { style: styleOf(mark) };
6450
+ const base = { style: styleOf2(mark) };
6389
6451
  if (mark.props.opacity !== void 0) base.opacity = mark.props.opacity;
6390
6452
  return base;
6391
6453
  };