@swiftbrowser/react 0.26.10 → 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/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";
@@ -63,153 +63,41 @@ function usePlatform() {
63
63
  function useRedacted() {
64
64
  return useContext(ViewEnvironmentContext).redacted === true;
65
65
  }
66
- let currentUpdatePriority = 0;
67
- function detach(parent, child) {
68
- const at = parent.children.indexOf(child);
69
- if (at >= 0) parent.children.splice(at, 1);
70
- }
71
- const hostConfig = {
72
- supportsMutation: true,
73
- supportsPersistence: false,
74
- supportsHydration: false,
75
- isPrimaryRenderer: true,
76
- noTimeout: -1,
77
- scheduleTimeout: setTimeout,
78
- cancelTimeout: clearTimeout,
79
- supportsMicrotasks: true,
80
- scheduleMicrotask: queueMicrotask,
81
- getRootHostContext: () => ({}),
82
- getChildHostContext: (parent) => parent,
83
- getPublicInstance: (instance) => instance,
84
- prepareForCommit: () => null,
85
- resetAfterCommit: (tree) => tree.commit(),
86
- preparePortalMount: () => {
87
- },
88
- shouldSetTextContent: () => false,
89
- createInstance: (type, props, tree) => {
90
- if (type !== "sb") throw new Error(`Unknown host element <${type}>: only SwiftUI components render here.`);
91
- return tree.createInstance(props);
92
- },
93
- createTextInstance: (text) => {
94
- throw new Error(`Text strings must be rendered within a <Text> component (got ${JSON.stringify(text)}).`);
95
- },
96
- appendInitialChild: (parent, child) => parent.children.push(child),
97
- finalizeInitialChildren: () => false,
98
- commitMount: () => {
99
- },
100
- commitUpdate: (instance, _type, _prev, next, handle) => {
101
- const tree = treeOf(handle);
102
- if (tree) tree.updateInstance(instance, next);
103
- else {
104
- instance.props = next.props ?? {};
105
- instance.on = next.on;
106
- instance.target = next.target;
107
- }
108
- },
109
- appendChild: (parent, child) => {
110
- detach(parent, child);
111
- parent.children.push(child);
112
- },
113
- appendChildToContainer: (tree, child) => {
114
- detach(tree.root, child);
115
- tree.root.children.push(child);
116
- },
117
- insertBefore: (parent, child, before) => {
118
- detach(parent, child);
119
- const at = parent.children.indexOf(before);
120
- parent.children.splice(at < 0 ? parent.children.length : at, 0, child);
121
- },
122
- insertInContainerBefore: (tree, child, before) => {
123
- detach(tree.root, child);
124
- const at = tree.root.children.indexOf(before);
125
- tree.root.children.splice(at < 0 ? tree.root.children.length : at, 0, child);
126
- },
127
- removeChild: (parent, child) => detach(parent, child),
128
- removeChildFromContainer: (tree, child) => detach(tree.root, child),
129
- clearContainer: (tree) => {
130
- tree.root.children = [];
131
- },
132
- resetTextContent: () => {
133
- },
134
- commitTextUpdate: () => {
135
- },
136
- hideInstance: (instance) => {
137
- instance.hidden = true;
138
- },
139
- unhideInstance: (instance) => {
140
- instance.hidden = false;
141
- },
142
- hideTextInstance: () => {
143
- },
144
- unhideTextInstance: () => {
145
- },
146
- detachDeletedInstance: () => {
147
- },
148
- getInstanceFromNode: () => null,
149
- beforeActiveInstanceBlur: () => {
150
- },
151
- afterActiveInstanceBlur: () => {
152
- },
153
- prepareScopeUpdate: () => {
154
- },
155
- getInstanceFromScope: () => null,
156
- setCurrentUpdatePriority: (priority) => {
157
- currentUpdatePriority = priority;
158
- },
159
- getCurrentUpdatePriority: () => currentUpdatePriority,
160
- resolveUpdatePriority: () => currentUpdatePriority !== 0 ? currentUpdatePriority : DefaultEventPriority,
161
- resetFormInstance: () => {
162
- },
163
- requestPostPaintCallback: () => {
164
- },
165
- shouldAttemptEagerTransition: () => false,
166
- trackSchedulerEvent: () => {
167
- },
168
- resolveEventType: () => null,
169
- resolveEventTimeStamp: () => -1.1,
170
- maySuspendCommit: () => false,
171
- maySuspendCommitOnUpdate: () => false,
172
- maySuspendCommitInSyncRender: () => false,
173
- suspendOnActiveViewTransition: () => {
174
- },
175
- getSuspendedCommitReason: () => null,
176
- bindToConsole: (methodName, args) => () => console[methodName]?.(...args),
177
- preloadInstance: () => true,
178
- startSuspendingCommit: () => null,
179
- suspendInstance: () => {
180
- },
181
- waitForCommitToBeReady: () => null,
182
- NotPendingTransition: null,
183
- HostTransitionContext: createContext(null),
184
- rendererVersion: "0.3.1",
185
- rendererPackageName: "@swiftbrowser/react",
186
- extraDevToolsConfig: null
187
- };
188
- function treeOf(handle) {
189
- let fiber = handle;
190
- while (fiber) {
191
- if (fiber.tag === 3) return fiber.stateNode.containerInfo;
192
- fiber = fiber.return;
193
- }
194
- return null;
195
- }
196
- const reconciler = Reconciler(hostConfig);
197
66
  const PREF_KIND = "$pref";
198
67
  const HOIST_KIND = "$hoist";
199
- function inheritTitleModes(screens, effective) {
68
+ function inheritTitleModes(screens) {
200
69
  let below = "large";
201
70
  for (const screen of screens) {
202
- const props = screen.kind === "navscreen" ? effective.get(screen)?.props : void 0;
203
- if (!props) continue;
204
- const depth = typeof props["depth"] === "number" ? props["depth"] : 0;
205
- let mode = typeof props["displayMode"] === "string" ? props["displayMode"] : "automatic";
71
+ const entry = screen.kind === "navscreen" ? screen.entry : null;
72
+ if (!entry) continue;
73
+ const base = entry.base;
74
+ const depth = typeof base["depth"] === "number" ? base["depth"] : 0;
75
+ let mode = typeof base["displayMode"] === "string" ? base["displayMode"] : "automatic";
206
76
  if (mode === "automatic") {
207
- if (depth > 0) props["displayMode"] = below;
77
+ if (depth > 0) {
78
+ if (entry.props["displayMode"] !== below) entry.props = { ...base, displayMode: below };
79
+ } else if (entry.props !== base) entry.props = base;
208
80
  mode = depth > 0 ? below : "large";
209
- }
81
+ } else if (entry.props !== base) entry.props = base;
210
82
  below = mode === "inline" ? "inline" : "large";
211
83
  }
212
84
  }
85
+ function markStale(node) {
86
+ for (let current = node; current && !current.stale; current = current.kind === "root" ? null : current.parent) current.stale = true;
87
+ }
88
+ function attach(parent, child, index) {
89
+ detach(parent, child);
90
+ if (index === void 0 || index < 0 || index > parent.children.length) parent.children.push(child);
91
+ else parent.children.splice(index, 0, child);
92
+ child.parent = parent;
93
+ markStale(parent);
94
+ }
95
+ function detach(parent, child) {
96
+ const at = parent.children.indexOf(child);
97
+ if (at >= 0) parent.children.splice(at, 1);
98
+ if (child.parent === parent) child.parent = null;
99
+ markStale(parent);
100
+ }
213
101
  class HostTree {
214
102
  constructor(sink, options = {}) {
215
103
  this.sink = sink;
@@ -217,13 +105,14 @@ class HostTree {
217
105
  }
218
106
  sink;
219
107
  options;
220
- root = { id: 0, kind: "root", children: [], committedChildren: [] };
108
+ root = { id: 0, kind: "root", children: [], committedChildren: [], parent: null, stale: true, entry: null };
221
109
  nextId = 1;
222
110
  /** Emitted elements by id, for event dispatch. */
223
111
  live = /* @__PURE__ */ new Map();
224
- committedLive = /* @__PURE__ */ new Set();
225
112
  /** Ids whose element changed kind: removed at the end of the next flush. */
226
113
  retired = [];
114
+ /** Which flush is under way; an instance resolved in it carries the number. */
115
+ generation = 0;
227
116
  /** `withAnimation`: stamped on the next `commit`. */
228
117
  pendingAnimation;
229
118
  /** `withAnimation(_:completionCriteria:_:completion:)`: stamped on the next `commit` with its serial; the callback waits in `completions`. */
@@ -249,7 +138,13 @@ class HostTree {
249
138
  created: false,
250
139
  committedProps: null,
251
140
  committedParent: null,
252
- committedChildren: []
141
+ committedChildren: [],
142
+ parent: null,
143
+ stale: true,
144
+ entry: null,
145
+ shown: false,
146
+ effectiveParent: null,
147
+ resolvedIn: 0
253
148
  };
254
149
  }
255
150
  updateInstance(instance, next) {
@@ -268,6 +163,12 @@ class HostTree {
268
163
  instance.props = next.props ?? {};
269
164
  instance.on = next.on;
270
165
  instance.target = next.target;
166
+ markStale(instance);
167
+ }
168
+ /** `node` is hidden or shown again (Suspense): it leaves or rejoins the emitted tree. */
169
+ setHidden(instance, hidden) {
170
+ instance.hidden = hidden;
171
+ markStale(instance);
271
172
  }
272
173
  /** Emit the ops for everything that changed since the last commit. */
273
174
  commit() {
@@ -279,68 +180,134 @@ class HostTree {
279
180
  this.pendingAnimation = void 0;
280
181
  const completion = this.pendingCompletion;
281
182
  this.pendingCompletion = void 0;
282
- const effective = /* @__PURE__ */ new Map();
283
- const rootEffective = { props: {}, children: [], hoisted: [] };
284
- effective.set(this.root, rootEffective);
285
- const visit = (child, sink, ctx) => {
183
+ const generation = ++this.generation;
184
+ const root = this.root;
185
+ const rootEntry = { props: {}, base: {}, children: [], hoisted: [], escaping: [] };
186
+ const previousRoot = root.entry;
187
+ root.entry = rootEntry;
188
+ const resolved = [];
189
+ const path = [];
190
+ const targetOf = (target, ctx, hoist) => {
191
+ if (target === "root" || target === void 0) return root;
192
+ return ctx[target] ?? (hoist || this.options.remote ? root : void 0);
193
+ };
194
+ const keep = (contribution, target) => {
195
+ for (let i = path.length - 1; i >= 0; i--) {
196
+ const node = path[i];
197
+ if (node === target) return;
198
+ node.entry.escaping.push(contribution);
199
+ }
200
+ };
201
+ const assign = (target, props) => {
202
+ const entry = target.entry;
203
+ if (target.kind !== "root" && entry.props === target.props) {
204
+ entry.props = { ...entry.props };
205
+ entry.base = entry.props;
206
+ }
207
+ Object.assign(entry.props, props);
208
+ if (entry.base !== entry.props) Object.assign(entry.base, props);
209
+ };
210
+ const contribute = (contribution, ctx) => {
211
+ if (contribution.kind === "pref") {
212
+ const target = targetOf(contribution.target, ctx, false);
213
+ if (target) assign(target, contribution.props);
214
+ keep(contribution, target);
215
+ } else {
216
+ const target = targetOf(contribution.target, ctx, true);
217
+ target.entry.hoisted.push(contribution.node);
218
+ contribution.node.effectiveParent = target;
219
+ keep(contribution, target);
220
+ }
221
+ };
222
+ const visit = (child, sink, owner, ctx, hoistedTo) => {
286
223
  if (child.hidden) return;
287
224
  if (child.kind === PREF_KIND) {
288
- const target = child.target === "root" || child.target === void 0 ? this.root : ctx[child.target] ?? (this.options.remote ? this.root : void 0);
289
- const entry2 = target ? effective.get(target) : void 0;
290
- if (entry2) Object.assign(entry2.props, child.props);
225
+ contribute({ kind: "pref", target: child.target, props: child.props }, ctx);
291
226
  return;
292
227
  }
293
228
  if (child.kind === HOIST_KIND) {
294
- const target = (child.target && child.target !== "root" ? ctx[child.target] : void 0) ?? this.root;
295
- const entry2 = effective.get(target);
296
- for (const grandchild of child.children) visit(grandchild, entry2.hoisted, ctx);
229
+ const target = targetOf(child.target, ctx, true);
230
+ for (const grandchild of child.children) visit(grandchild, target.entry.hoisted, target, ctx, child.target ?? "root");
297
231
  return;
298
232
  }
299
- const entry = { props: { ...child.props }, children: [], hoisted: [] };
300
- effective.set(child, entry);
233
+ if (hoistedTo !== void 0) {
234
+ child.effectiveParent = owner;
235
+ keep({ kind: "hoist", target: hoistedTo ?? void 0, node: child }, owner);
236
+ }
301
237
  sink.push(child);
238
+ if (!child.stale && child.entry) {
239
+ child.effectiveParent = owner;
240
+ child.shown = true;
241
+ for (const contribution of child.entry.escaping) contribute(contribution, ctx);
242
+ return;
243
+ }
244
+ const entry = { props: child.props, base: child.props, children: [], hoisted: [], escaping: [] };
245
+ resolved.push([child, child.entry]);
246
+ child.entry = entry;
247
+ child.stale = false;
248
+ child.shown = true;
249
+ child.effectiveParent = owner;
250
+ child.resolvedIn = generation;
302
251
  const next = child.kind === "navscreen" ? { ...ctx, navscreen: child } : child.kind === "sheet" ? { ...ctx, sheet: child } : ctx;
303
- for (const grandchild of child.children) visit(grandchild, entry.children, next);
252
+ path.push(child);
253
+ for (const grandchild of child.children) visit(grandchild, entry.children, child, next, void 0);
254
+ path.pop();
304
255
  };
305
- for (const child of this.root.children) visit(child, rootEffective.children, {});
306
- for (const entry of effective.values()) {
256
+ for (const child of root.children) visit(child, rootEntry.children, root, {}, void 0);
257
+ root.stale = false;
258
+ if (rootEntry.hoisted.length > 0) rootEntry.children.push(...rootEntry.hoisted);
259
+ for (const [node] of resolved) {
260
+ const entry = node.entry;
307
261
  if (entry.hoisted.length > 0) entry.children.push(...entry.hoisted);
308
262
  }
309
- for (const [node, entry] of effective) {
310
- if (node !== this.root && node.kind === "navstack") inheritTitleModes(entry.children, effective);
311
- }
312
- const live = /* @__PURE__ */ new Set();
313
- const parentOf = /* @__PURE__ */ new Map();
314
- for (const [node, entry] of effective) {
315
- for (const child of entry.children) {
316
- live.add(child);
317
- parentOf.set(child, node);
318
- }
263
+ for (const [node] of resolved) {
264
+ if (node.kind === "navstack") inheritTitleModes(node.entry.children);
319
265
  }
320
266
  const ops = [];
321
- const dead = /* @__PURE__ */ new Set();
322
- for (const instance of this.committedLive) if (!live.has(instance)) dead.add(instance);
323
- for (const instance of dead) {
324
- const parent = instance.committedParent;
325
- if (parent && parent !== this.root && dead.has(parent)) continue;
326
- ops.push({ op: "remove", id: instance.id });
327
- }
328
- for (const instance of dead) {
267
+ const left = [];
268
+ const arrived = /* @__PURE__ */ new Set();
269
+ const compare = (before, after) => {
270
+ if (!before) {
271
+ for (const child of after) arrived.add(child);
272
+ return;
273
+ }
274
+ let same = before.length === after.length;
275
+ for (let i = 0; same && i < after.length; i++) if (before[i] !== after[i]) same = false;
276
+ if (same) return;
277
+ const now = new Set(after);
278
+ for (const child of before) if (!now.has(child)) left.push(child);
279
+ const then = new Set(before);
280
+ for (const child of after) if (!then.has(child)) arrived.add(child);
281
+ };
282
+ compare(previousRoot?.children, rootEntry.children);
283
+ for (const [node, previous] of resolved) compare(previous?.children, node.entry.children);
284
+ const gone = (instance) => {
329
285
  this.live.delete(instance.id);
286
+ instance.shown = false;
330
287
  instance.created = false;
331
288
  instance.committedProps = null;
332
289
  instance.committedParent = null;
333
290
  instance.committedChildren = [];
291
+ instance.stale = true;
292
+ const entry = instance.entry;
293
+ if (entry) {
294
+ for (const child of entry.children) if (child.effectiveParent === instance) gone(child);
295
+ }
296
+ };
297
+ for (const instance of left) {
298
+ if (!instance.shown || arrived.has(instance)) continue;
299
+ ops.push({ op: "remove", id: instance.id });
300
+ gone(instance);
334
301
  }
335
302
  const emit = (parent, entry) => {
336
- const current = parent.committedChildren.filter((child) => live.has(child) && parentOf.get(child) === parent);
303
+ const current = parent.committedChildren.filter((child) => child.shown && child.effectiveParent === parent);
337
304
  entry.children.forEach((child, index) => {
338
- const childEntry = effective.get(child);
305
+ const childEntry = child.entry;
339
306
  if (!child.created) {
340
307
  ops.push({ op: "create", id: child.id, kind: child.kind, props: childEntry.props });
341
308
  child.created = true;
342
309
  this.live.set(child.id, child);
343
- } else if (!deepEqual(childEntry.props, child.committedProps)) {
310
+ } else if (childEntry.props !== child.committedProps && !deepEqual(childEntry.props, child.committedProps)) {
344
311
  ops.push({ op: "update", id: child.id, props: childEntry.props });
345
312
  }
346
313
  child.committedProps = childEntry.props;
@@ -351,21 +318,20 @@ class HostTree {
351
318
  current.splice(index, 0, child);
352
319
  }
353
320
  child.committedParent = parent;
354
- emit(child, childEntry);
321
+ if (child.resolvedIn === generation) emit(child, childEntry);
355
322
  });
356
323
  parent.committedChildren = entry.children;
357
324
  };
358
- emit(this.root, rootEffective);
325
+ emit(root, rootEntry);
359
326
  for (const id of this.retired) ops.push({ op: "remove", id });
360
327
  this.retired = [];
361
- this.committedLive = live;
362
328
  if (this.options.remote) {
363
- if (!deepEqual(rootEffective.props, this.committedRootProps)) {
364
- ops.push({ op: "update", id: 0, props: rootEffective.props });
365
- this.committedRootProps = rootEffective.props;
329
+ if (!deepEqual(rootEntry.props, this.committedRootProps)) {
330
+ ops.push({ op: "update", id: 0, props: rootEntry.props });
331
+ this.committedRootProps = rootEntry.props;
366
332
  }
367
333
  } else {
368
- const scheme = rootEffective.props["colorScheme"];
334
+ const scheme = rootEntry.props["colorScheme"];
369
335
  const next = scheme === void 0 ? this.committedColorScheme === void 0 ? void 0 : null : scheme;
370
336
  if (next !== void 0 && next !== this.committedColorScheme) {
371
337
  ops.push({ op: "update", id: 0, props: { colorScheme: next } });
@@ -422,6 +388,132 @@ function deepEqual(a, b) {
422
388
  if (keys.length !== Object.keys(right).length) return false;
423
389
  return keys.every((key) => key in right && deepEqual(left[key], right[key]));
424
390
  }
391
+ let currentUpdatePriority = 0;
392
+ const hostConfig = {
393
+ supportsMutation: true,
394
+ supportsPersistence: false,
395
+ supportsHydration: false,
396
+ isPrimaryRenderer: true,
397
+ noTimeout: -1,
398
+ scheduleTimeout: setTimeout,
399
+ cancelTimeout: clearTimeout,
400
+ supportsMicrotasks: true,
401
+ scheduleMicrotask: queueMicrotask,
402
+ getRootHostContext: () => ({}),
403
+ getChildHostContext: (parent) => parent,
404
+ getPublicInstance: (instance) => instance,
405
+ prepareForCommit: () => null,
406
+ resetAfterCommit: (tree) => tree.commit(),
407
+ preparePortalMount: () => {
408
+ },
409
+ shouldSetTextContent: () => false,
410
+ createInstance: (type, props, tree) => {
411
+ if (type !== "sb") throw new Error(`Unknown host element <${type}>: only SwiftUI components render here.`);
412
+ return tree.createInstance(props);
413
+ },
414
+ createTextInstance: (text) => {
415
+ throw new Error(`Text strings must be rendered within a <Text> component (got ${JSON.stringify(text)}).`);
416
+ },
417
+ appendInitialChild: (parent, child) => attach(parent, child),
418
+ finalizeInitialChildren: () => false,
419
+ commitMount: () => {
420
+ },
421
+ commitUpdate: (instance, _type, _prev, next, handle) => {
422
+ const tree = treeOf(handle);
423
+ if (tree) tree.updateInstance(instance, next);
424
+ else {
425
+ instance.props = next.props ?? {};
426
+ instance.on = next.on;
427
+ instance.target = next.target;
428
+ markStale(instance);
429
+ }
430
+ },
431
+ appendChild: (parent, child) => attach(parent, child),
432
+ appendChildToContainer: (tree, child) => attach(tree.root, child),
433
+ insertBefore: (parent, child, before) => {
434
+ detach(parent, child);
435
+ const at = parent.children.indexOf(before);
436
+ attach(parent, child, at < 0 ? parent.children.length : at);
437
+ },
438
+ insertInContainerBefore: (tree, child, before) => {
439
+ detach(tree.root, child);
440
+ const at = tree.root.children.indexOf(before);
441
+ attach(tree.root, child, at < 0 ? tree.root.children.length : at);
442
+ },
443
+ removeChild: (parent, child) => detach(parent, child),
444
+ removeChildFromContainer: (tree, child) => detach(tree.root, child),
445
+ clearContainer: (tree) => {
446
+ for (const child of tree.root.children) child.parent = null;
447
+ tree.root.children = [];
448
+ markStale(tree.root);
449
+ },
450
+ resetTextContent: () => {
451
+ },
452
+ commitTextUpdate: () => {
453
+ },
454
+ hideInstance: (instance) => {
455
+ instance.hidden = true;
456
+ markStale(instance);
457
+ },
458
+ unhideInstance: (instance) => {
459
+ instance.hidden = false;
460
+ markStale(instance);
461
+ },
462
+ hideTextInstance: () => {
463
+ },
464
+ unhideTextInstance: () => {
465
+ },
466
+ detachDeletedInstance: () => {
467
+ },
468
+ getInstanceFromNode: () => null,
469
+ beforeActiveInstanceBlur: () => {
470
+ },
471
+ afterActiveInstanceBlur: () => {
472
+ },
473
+ prepareScopeUpdate: () => {
474
+ },
475
+ getInstanceFromScope: () => null,
476
+ setCurrentUpdatePriority: (priority) => {
477
+ currentUpdatePriority = priority;
478
+ },
479
+ getCurrentUpdatePriority: () => currentUpdatePriority,
480
+ resolveUpdatePriority: () => currentUpdatePriority !== 0 ? currentUpdatePriority : DefaultEventPriority,
481
+ resetFormInstance: () => {
482
+ },
483
+ requestPostPaintCallback: () => {
484
+ },
485
+ shouldAttemptEagerTransition: () => false,
486
+ trackSchedulerEvent: () => {
487
+ },
488
+ resolveEventType: () => null,
489
+ resolveEventTimeStamp: () => -1.1,
490
+ maySuspendCommit: () => false,
491
+ maySuspendCommitOnUpdate: () => false,
492
+ maySuspendCommitInSyncRender: () => false,
493
+ suspendOnActiveViewTransition: () => {
494
+ },
495
+ getSuspendedCommitReason: () => null,
496
+ bindToConsole: (methodName, args) => () => console[methodName]?.(...args),
497
+ preloadInstance: () => true,
498
+ startSuspendingCommit: () => null,
499
+ suspendInstance: () => {
500
+ },
501
+ waitForCommitToBeReady: () => null,
502
+ NotPendingTransition: null,
503
+ HostTransitionContext: createContext(null),
504
+ rendererVersion: "0.3.1",
505
+ rendererPackageName: "@swiftbrowser/react",
506
+ extraDevToolsConfig: null
507
+ };
508
+ function treeOf(handle) {
509
+ let fiber = handle;
510
+ while (fiber) {
511
+ if (fiber.tag === 3) return fiber.stateNode.containerInfo;
512
+ fiber = fiber.return;
513
+ }
514
+ return null;
515
+ }
516
+ const reconciler = Reconciler(hostConfig);
425
517
  const DEFAULT_ENVIRONMENT = { colorScheme: "light", dynamicTypeSize: "large", horizontalSizeClass: "compact", scenePhase: "active", platform: "ios" };
426
518
  const roots = /* @__PURE__ */ new Set();
427
519
  const HostTreeContext = createContext(null);
@@ -654,6 +746,37 @@ function sb(kind, props, on, children, target) {
654
746
  if (target) hostProps.target = target;
655
747
  return children === void 0 ? createElement("sb", hostProps) : createElement("sb", hostProps, children);
656
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
+ }
657
780
  const NavigationContext = createContext(null);
658
781
  const ScreenDepthContext = createContext(0);
659
782
  function useScreenDepth() {
@@ -694,6 +817,10 @@ function renderNode(root, node, stack) {
694
817
  const children = node.children.length ? node.children.map((child) => renderNode(root, child, stack)) : void 0;
695
818
  return createElement(Fragment, { key: node.id }, sb(node.kind, node.props, root.handlersFor(node.id), children));
696
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
+ }
697
824
  function renderScreen(root, screen, stack) {
698
825
  const out = [screenPrefs(screen.props, "$screen")];
699
826
  for (const child of screen.children) {
@@ -712,6 +839,7 @@ function RemoteScreen({ root, id }) {
712
839
  function RemoteTree({ root, initialPath }) {
713
840
  useSyncExternalStore(root.subscribe, root.getVersion, root.getVersion);
714
841
  const environment = useContext(EnvironmentContext);
842
+ const inherited = useInheritedStyles();
715
843
  const tree = useContext(HostTreeContext);
716
844
  const navigation = useNavigation();
717
845
  const depth = useScreenDepth();
@@ -767,7 +895,7 @@ function RemoteTree({ root, initialPath }) {
767
895
  if ("colorScheme" in root.rootProps)
768
896
  out.push(createElement(Fragment, { key: "$scheme" }, sb(PREF_KIND, { colorScheme: root.rootProps["colorScheme"] }, void 0, void 0, "root")));
769
897
  for (const child of root.root.children) {
770
- const drawn = renderNode(root, child, stack);
898
+ const drawn = child.kind === "sheet" && inherited.length > 0 ? renderSheet(root, child, stack, inherited) : renderNode(root, child, stack);
771
899
  if (child.kind === "sheet" || child.kind === "alert") out.push(createElement(Fragment, { key: child.id }, sb(HOIST_KIND, void 0, void 0, drawn, "root")));
772
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")));
773
901
  else out.push(drawn);
@@ -960,6 +1088,7 @@ function mount(screen, element, options = {}) {
960
1088
  platform: options.platform === void 0 || options.platform === "auto" ? decidePlatform(width) : options.platform
961
1089
  };
962
1090
  renderer.contentHeight = options.contentHeight ?? false;
1091
+ if (options.sidebarTitleBar === false) renderer.sidebarTitleBar = false;
963
1092
  if (options.assets) renderer.setAssetCatalog(options.assets);
964
1093
  if (options.app) browserEnvironment.files?.setApp?.(options.app);
965
1094
  renderer.setEnvironment({ colorScheme: environment.colorScheme, dynamicTypeSize: environment.dynamicTypeSize, platform: environment.platform });
@@ -1268,6 +1397,7 @@ function SwiftUIView({
1268
1397
  safeArea,
1269
1398
  history = true,
1270
1399
  keyboard = fit === "fill",
1400
+ sidebarTitleBar = true,
1271
1401
  className,
1272
1402
  style
1273
1403
  }) {
@@ -1295,6 +1425,9 @@ function SwiftUIView({
1295
1425
  instance.unmount();
1296
1426
  };
1297
1427
  }, [fit, history, keyboard]);
1428
+ useLayoutEffect(() => {
1429
+ if (mounted.current) mounted.current.renderer.sidebarTitleBar = sidebarTitleBar;
1430
+ }, [sidebarTitleBar, fit, history, keyboard]);
1298
1431
  useLayoutEffect(() => {
1299
1432
  mounted.current?.root.render(tree);
1300
1433
  });
@@ -2196,7 +2329,7 @@ function NavigationSplitView(props) {
2196
2329
  const detail = isValidElement(own.detail) && own.detail.type === NavigationStack ? own.detail : /* @__PURE__ */ jsx(NavigationStack, { children: own.detail });
2197
2330
  const sidebar = own.sidebarWidth !== void 0 ? sb("styled", { style: { splitColumnWidth: splitColumnWidthHint(own.sidebarWidth) } }, void 0, own.sidebar) : own.sidebar;
2198
2331
  return applyModifiers(
2199
- sb("navsplit", { sidebarVisible }, { tap: toggle }, [
2332
+ sb("navsplit", { sidebarVisible }, { tap: toggle, columnwidth: (event) => own.onSidebarWidthChange?.(event.width) }, [
2200
2333
  /* @__PURE__ */ jsx(SplitColumn, { report, children: /* @__PURE__ */ jsx(NavigationStack, { children: sidebar }) }, "sidebar"),
2201
2334
  /* @__PURE__ */ jsx(SplitColumn, { report: null, children: detail }, "detail")
2202
2335
  ]),
@@ -2242,7 +2375,8 @@ function useReportSplitSelection(split, selected, clear, active2 = true) {
2242
2375
  function OutsideSplit({ children }) {
2243
2376
  return /* @__PURE__ */ jsx(SplitSelectionContext.Provider, { value: null, children });
2244
2377
  }
2245
- function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
2378
+ function SheetPresenter({ isPresented, onDismiss, content, fullScreen, inherited }) {
2379
+ const around = useInheritedStyles();
2246
2380
  const [presented, setPresented] = readBinding(isPresented);
2247
2381
  if (!presented) return null;
2248
2382
  const dismiss = () => {
@@ -2258,7 +2392,10 @@ function SheetPresenter({ isPresented, onDismiss, content, fullScreen }) {
2258
2392
  "sheet",
2259
2393
  { detents },
2260
2394
  { tap: dismiss },
2261
- /* @__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
+ )
2262
2399
  ),
2263
2400
  "root"
2264
2401
  );
@@ -2641,6 +2778,7 @@ const MODIFIER_KEYS = /* @__PURE__ */ new Set([
2641
2778
  "coordinateSpace",
2642
2779
  "contentTransition",
2643
2780
  "scrollDisabled",
2781
+ "defaultMinListRowHeight",
2644
2782
  "scrollEdgeEffectStyle",
2645
2783
  "scrollEdgeEffectHidden",
2646
2784
  "contentMargins",
@@ -2764,13 +2902,30 @@ function applyModifiers(element, modifiers) {
2764
2902
  const isPreference = (side) => isValidElement(side) && side.props.kind === PREF_KIND;
2765
2903
  function wrap(element, modifiers, sides) {
2766
2904
  let node = element;
2905
+ const holds = holdsViews(element);
2906
+ const presentations = [];
2767
2907
  for (const [key, value] of modifiers) {
2768
2908
  const inactive = value === void 0 || value === null && key !== "lineLimit" && key !== "badge";
2909
+ const before = sides.length;
2769
2910
  const next = inactive ? node : apply(key, value, node, sides);
2770
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() });
2771
2922
  }
2772
2923
  return node;
2773
2924
  }
2925
+ function holdsViews(element) {
2926
+ if (!isValidElement(element)) return false;
2927
+ return element.type !== "sb" || element.props.children !== void 0;
2928
+ }
2774
2929
  const STYLED_KEYS = /* @__PURE__ */ new Set([
2775
2930
  "padding",
2776
2931
  "font",
@@ -2830,7 +2985,8 @@ const STYLED_KEYS = /* @__PURE__ */ new Set([
2830
2985
  "containerRelativeFrame",
2831
2986
  "contentTransition",
2832
2987
  "scrollDisabled",
2833
- "textSelection"
2988
+ "textSelection",
2989
+ "defaultMinListRowHeight"
2834
2990
  ]);
2835
2991
  const ENVIRONMENT_KEYS = /* @__PURE__ */ new Set([
2836
2992
  "buttonStyle",
@@ -3254,6 +3410,8 @@ function apply(key, value, node, sides) {
3254
3410
  }
3255
3411
  case "scrollDisabled":
3256
3412
  return styled({ scrollDisabled: value === true }, node);
3413
+ case "defaultMinListRowHeight":
3414
+ return typeof value === "number" && Number.isFinite(value) ? styled({ defaultMinListRowHeight: Math.max(0, value) }, node) : styled({}, node);
3257
3415
  case "textSelection":
3258
3416
  return styled({ textSelection: value === "enabled" }, node);
3259
3417
  case "contentTransition": {
@@ -6231,7 +6389,7 @@ function Chart(props) {
6231
6389
  const key = mark.props.foregroundStyleBy;
6232
6390
  if (key !== void 0 && !series.includes(key)) series.push(key);
6233
6391
  }
6234
- const styleOf = (mark) => {
6392
+ const styleOf2 = (mark) => {
6235
6393
  if (mark.props.foregroundStyle !== void 0) return shapeStyle(mark.props.foregroundStyle);
6236
6394
  const key = mark.props.foregroundStyleBy;
6237
6395
  if (key !== void 0) return { name: PALETTE[series.indexOf(key) % PALETTE.length] };
@@ -6289,7 +6447,7 @@ function Chart(props) {
6289
6447
  );
6290
6448
  };
6291
6449
  const common = (mark) => {
6292
- const base = { style: styleOf(mark) };
6450
+ const base = { style: styleOf2(mark) };
6293
6451
  if (mark.props.opacity !== void 0) base.opacity = mark.props.opacity;
6294
6452
  return base;
6295
6453
  };