octane 0.1.41 → 0.1.42

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
@@ -36,6 +36,9 @@ For the full story, see the
36
36
 
37
37
  ## Browser compatibility
38
38
 
39
+ See the [browser support guide](https://octanejs.dev/docs/browser-support) for
40
+ recommended targets, required browser APIs, and optional fallbacks.
41
+
39
42
  Configure your application's build target for the browser engines you support.
40
43
  The Rsbuild integration's `modules` target includes Chromium 87 and Samsung
41
44
  Internet 14; Samsung Internet can also be selected directly with targets such as
@@ -475,18 +475,19 @@ function stagedTransitionValue(slot) {
475
475
  function stageTransitionValue(slot, block, operation, value, forceRender = false) {
476
476
  const batch = transitionActionBatchForUpdate();
477
477
  if (batch === null) return false;
478
+ const replay = typeof operation === "function" ? operation : () => operation;
478
479
  const current = batch.updates.get(slot);
479
480
  if (current === void 0) {
480
481
  batch.updates.set(slot, {
481
482
  slot,
482
483
  block,
483
- operations: [operation],
484
+ operations: [replay],
484
485
  baseValue: slot.value,
485
486
  value,
486
487
  forceRender
487
488
  });
488
489
  } else {
489
- current.operations.push(operation);
490
+ current.operations.push(replay);
490
491
  current.value = value;
491
492
  current.forceRender ||= forceRender;
492
493
  }
@@ -1457,12 +1458,21 @@ function flush() {
1457
1458
  }
1458
1459
  return;
1459
1460
  }
1461
+ if (!hasPendingWork() && refDetachQueue.length === 0 && refAttachQueue.length === 0 && activeFragments.size === 0 && FLUSHED_TRANSITION_UPDATES.length === 0 && VIEW_TRANSITION_DRIVER === null) {
1462
+ if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__)
1463
+ (0, import_devtools_hook.__devtoolsNotifyFlush)();
1464
+ return;
1465
+ }
1460
1466
  if (VIEW_TRANSITION_DRIVER?.routeFlush() === true) return;
1461
1467
  flushWork();
1462
1468
  }
1463
1469
  function activeElementForDocument(doc) {
1464
1470
  try {
1465
1471
  let focused = doc.activeElement;
1472
+ if (focused === doc.body) {
1473
+ focused = focused?.shadowRoot?.activeElement ?? null;
1474
+ if (focused === null) return null;
1475
+ }
1466
1476
  while (focused !== null) {
1467
1477
  if (focused.localName === "iframe") {
1468
1478
  let nested;
@@ -3118,10 +3128,9 @@ function useState(initial, slot) {
3118
3128
  value: initVal,
3119
3129
  setter: (next) => {
3120
3130
  const previous = stagedTransitionValue(s);
3121
- const operation = typeof next === "function" ? next : () => next;
3122
- const computed = operation(previous);
3131
+ const computed = typeof next === "function" ? next(previous) : next;
3123
3132
  if (Object.is(computed, previous)) return;
3124
- if (stageTransitionValue(s, block, operation, computed)) {
3133
+ if (stageTransitionValue(s, block, next, computed)) {
3125
3134
  if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__) {
3126
3135
  const update = s.pendingActionBatch?.updates.get(s);
3127
3136
  if (update !== void 0) {
@@ -4638,6 +4647,10 @@ function activateHydrateBoundary(state) {
4638
4647
  renderBlock(block);
4639
4648
  drainHydrationRenderPhaseUpdates(block);
4640
4649
  if (state.hydrated) {
4650
+ const adoptedSlot = block.slots[0];
4651
+ if (adoptedSlot?.__kind === "trySlotSlot") {
4652
+ hydration.claimRootRemainder(adoptedSlot.end.nextSibling);
4653
+ }
4641
4654
  hydration.flushClassWrites();
4642
4655
  hydration.flushTextWarnings();
4643
4656
  hydration.finishRoot();
@@ -14982,7 +14995,7 @@ function forBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flag
14982
14995
  hydration.node = state.end.nextSibling;
14983
14996
  }
14984
14997
  }
14985
- function keyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd) {
14998
+ function keyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd, selectionBody) {
14986
14999
  const state = parentScope.slots[slotKey];
14987
15000
  if (TRANSITION_JOURNAL !== null) {
14988
15001
  if (state !== void 0) {
@@ -14990,7 +15003,15 @@ function keyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody,
14990
15003
  state.selectionItems = void 0;
14991
15004
  }
14992
15005
  flags &= ~4;
14993
- } else if (state !== void 0 && activeHydration() === null && state.cachedDeps !== null && tryUpdateKeyedSelection(state, items, itemBody, state.cachedDeps, deps, flags >>> 6)) {
15006
+ } else if (state !== void 0 && activeHydration() === null && state.cachedDeps !== null && tryUpdateKeyedSelection(
15007
+ state,
15008
+ items,
15009
+ itemBody,
15010
+ state.cachedDeps,
15011
+ deps,
15012
+ flags >>> 6,
15013
+ selectionBody
15014
+ )) {
14994
15015
  return;
14995
15016
  }
14996
15017
  forBlock(
@@ -15114,7 +15135,7 @@ function fastForBlock(parentScope, slotKey, domParent, items, getKey, itemBody,
15114
15135
  }
15115
15136
  mountFastHostItems(parentScope, state, parent, items, getKey, itemBody, flags, deps, false);
15116
15137
  }
15117
- function fastKeyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd) {
15138
+ function fastKeyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd, selectionBody) {
15118
15139
  const state = parentScope.slots[slotKey];
15119
15140
  const parent = fastHostListParent(state, items, flags);
15120
15141
  if (parent === null) {
@@ -15129,7 +15150,8 @@ function fastKeyedForBlock(parentScope, slotKey, domParent, items, getKey, itemB
15129
15150
  deps,
15130
15151
  emptyBody,
15131
15152
  anchor,
15132
- ownEnd
15153
+ ownEnd,
15154
+ selectionBody
15133
15155
  );
15134
15156
  return;
15135
15157
  }
@@ -15201,7 +15223,7 @@ function depsEqual(a, b) {
15201
15223
  }
15202
15224
  return true;
15203
15225
  }
15204
- function tryUpdateKeyedSelection(state, items, itemBody, previousDeps, deps, selectionIndex) {
15226
+ function tryUpdateKeyedSelection(state, items, itemBody, previousDeps, deps, selectionIndex, selectionBody) {
15205
15227
  if (state.selectionItems !== items || state.size !== items.length || state.items.size !== state.size || previousDeps.length !== deps.length || selectionIndex >= deps.length) {
15206
15228
  return false;
15207
15229
  }
@@ -15224,12 +15246,20 @@ function tryUpdateKeyedSelection(state, items, itemBody, previousDeps, deps, sel
15224
15246
  if (first !== void 0) {
15225
15247
  first.body = itemBody;
15226
15248
  first.extra = deps;
15227
- itemBody(first.props, first, deps);
15249
+ if (selectionBody !== void 0 && first._slots === null) {
15250
+ selectionBody(first.props, first, deps);
15251
+ } else {
15252
+ itemBody(first.props, first, deps);
15253
+ }
15228
15254
  }
15229
15255
  if (second !== void 0) {
15230
15256
  second.body = itemBody;
15231
15257
  second.extra = deps;
15232
- itemBody(second.props, second, deps);
15258
+ if (selectionBody !== void 0 && second._slots === null) {
15259
+ selectionBody(second.props, second, deps);
15260
+ } else {
15261
+ itemBody(second.props, second, deps);
15262
+ }
15233
15263
  }
15234
15264
  return true;
15235
15265
  }
@@ -21,7 +21,7 @@ __export(version_exports, {
21
21
  version: () => version
22
22
  });
23
23
  module.exports = __toCommonJS(version_exports);
24
- const version = "0.1.41";
24
+ const version = "0.1.42";
25
25
  // Annotate the CommonJS export names for ESM import in node:
26
26
  0 && (module.exports = {
27
27
  version
@@ -8188,6 +8188,7 @@ function compileInternal(
8188
8188
  !hmrEnabled &&
8189
8189
  !devEnabled &&
8190
8190
  !profileEnabled &&
8191
+ options?.__universal == null &&
8191
8192
  !((source.includes('eval') || source.includes('\\u')) && hasInlineMemoDirectEval(ast));
8192
8193
  // Same production-only gate as the tiers above, and for the same reason: a
8193
8194
  // lifted callback has left the component, which dev tooling, HMR boundaries,
@@ -13480,7 +13481,16 @@ function compileFunctionBody(node, ctx, name, parentNs = 'html', cssHash = null,
13480
13481
  cssHash,
13481
13482
  );
13482
13483
  } else {
13483
- plan = planJsx(jsxNodes, ctx, name, inlinedSubs, parentNs, cssHash, mountCallbackSinks);
13484
+ plan = planJsx(
13485
+ jsxNodes,
13486
+ ctx,
13487
+ name,
13488
+ inlinedSubs,
13489
+ parentNs,
13490
+ cssHash,
13491
+ mountCallbackSinks,
13492
+ options?.keyedSelection ?? null,
13493
+ );
13484
13494
  }
13485
13495
  ctx.currentInvariantLocals = prevInvariantLocals;
13486
13496
  ctx.currentEventInvariantLocals = prevEventInvariantLocals;
@@ -17421,6 +17431,11 @@ function extractFragment(node, ctx, holeProps, parentNs = 'html') {
17421
17431
  const bodyHole = `h${holeProps.length}`;
17422
17432
  holeProps.push(objectProp(bodyHole, b.id(rec.bodyHelper)));
17423
17433
  rec.bodyHelper = `props.${bodyHole}`;
17434
+ if (rec.selectionHelper != null) {
17435
+ const selectionHole = `h${holeProps.length}`;
17436
+ holeProps.push(objectProp(selectionHole, b.id(rec.selectionHelper)));
17437
+ rec.selectionHelper = `props.${selectionHole}`;
17438
+ }
17424
17439
  }
17425
17440
  if (mapCall) {
17426
17441
  const methodHole = `h${holeProps.length}`;
@@ -20439,6 +20454,7 @@ function planJsx(
20439
20454
  parentNs = 'html',
20440
20455
  cssHash = null,
20441
20456
  mountCallbackSinks = null,
20457
+ keyedSelection = null,
20442
20458
  ) {
20443
20459
  // DEV ONLY: per-element source-location map for THIS body (path-key → [line, col]),
20444
20460
  // populated at the top of emitElementHtml and read in the binding mount loop to emit
@@ -20712,6 +20728,15 @@ function planJsx(
20712
20728
  resolvedFrag = tplNs !== 'opaque';
20713
20729
  }
20714
20730
  }
20731
+ // Binding planning precedes the final template namespace. An inherited
20732
+ // opaque namespace can now use the same concrete namespace as clone(),
20733
+ // including HTML's faster className property. Preserve explicit foreign
20734
+ // content and leave genuinely opaque/mixed templates destination-aware.
20735
+ if (tplNs !== 'opaque') {
20736
+ for (const binding of elementBindings) {
20737
+ if (binding.ns === 'opaque') binding.ns = tplNs;
20738
+ }
20739
+ }
20715
20740
  const flag = nsFlag(tplNs);
20716
20741
  const fragArg = !single && (flag !== 0 || resolvedFrag) ? 1 : 0;
20717
20742
  let template = rootTemplate;
@@ -21234,6 +21259,24 @@ function planJsx(
21234
21259
  if (b.deferred) everyRenderLines.push(updateEmit);
21235
21260
  else updateLines.push(updateEmit);
21236
21261
  }
21262
+ if (keyedSelection !== null && single && !noTemplate) {
21263
+ // Reuse the ordinary root-class write and its exact bag fields. Updating
21264
+ // only the DOM would leave the normal row diff's previous value stale.
21265
+ const classes = elementBindings.filter(
21266
+ (binding) => binding.kind === 'class' && binding.path.length === 0,
21267
+ );
21268
+ if (
21269
+ classes.length === 1 &&
21270
+ !classes[0].fresh &&
21271
+ !classes[0].mountOnly &&
21272
+ collectFreeIdentifiers(classes[0].expr, [
21273
+ keyedSelection.itemName,
21274
+ keyedSelection.selectedName,
21275
+ ]).size === 0
21276
+ ) {
21277
+ keyedSelection.update = emitBindingUpdate(classes[0], bag);
21278
+ }
21279
+ }
21237
21280
 
21238
21281
  // After (forBlock + ifBlock calls run on every render — they reconcile).
21239
21282
  //
@@ -21342,6 +21385,7 @@ function planJsx(
21342
21385
  rtAlias(forHelper),
21343
21386
  fc.keyHelper,
21344
21387
  fc.bodyHelper,
21388
+ fc.selectionHelper,
21345
21389
  fc.emptyHelper,
21346
21390
  ]);
21347
21391
  registerClauseOrigin(ctx, fc.emptyKeyword, [fc.emptyHelper]);
@@ -21366,7 +21410,8 @@ function planJsx(
21366
21410
  (fc.requiresScope ? 32 : 0) |
21367
21411
  (fc.keyedSelectionIndex >= 0 ? fc.keyedSelectionIndex << 6 : 0);
21368
21412
  // Arg layout: forBlock(__s, slot, host, items, keyFn, body, flags?, deps?,
21369
- // emptyBody?, anchor?, ownEnd?).
21413
+ // emptyBody?, anchor?, ownEnd?, selectionBody?). The final argument is
21414
+ // emitted only for a certified keyed-selection call.
21370
21415
  // Optional args backfill positionally: `flags`/`deps` placeholders
21371
21416
  // (`0`/`undefined`) when only `emptyHelper` (`null` when no `@empty`
21372
21417
  // branch) or the anchor is present, and a `null` empty-body placeholder
@@ -21418,6 +21463,12 @@ function planJsx(
21418
21463
  // list's trailing boundary. Let forBlock reuse it as its end marker instead
21419
21464
  // of retaining it beside a newly-created `/for` comment.
21420
21465
  if (fc.anchorVar) tailArgs.push(b.literal(true));
21466
+ if (fc.selectionHelper != null) {
21467
+ // tailArgs starts at argument 5; preserve the optional positions through
21468
+ // ownEnd before supplying the selection updater as argument 12.
21469
+ while (tailArgs.length < 7) tailArgs.push(undefinedNode());
21470
+ tailArgs.push(helperRefNode(fc.selectionHelper));
21471
+ }
21421
21472
  if (isMappedList) {
21422
21473
  const nativeName = allocCompilerName(ctx, '__mapNative');
21423
21474
  if (fc.autoMemoDeps !== null) {
@@ -24999,6 +25050,7 @@ function hoistBodyHelper(
24999
25050
  cssHash,
25000
25051
  envNames,
25001
25052
  idOrigin = null,
25053
+ keyedSelection = null,
25002
25054
  ) {
25003
25055
  const helperName = `${prefix}$${ctx.nextHelperId++}`;
25004
25056
  const ownEnvNames = envNames === null ? null : helperCaptures(ctx, stmts, params);
@@ -25066,7 +25118,14 @@ function hoistBodyHelper(
25066
25118
  );
25067
25119
  let helperFn;
25068
25120
  try {
25069
- helperFn = compileFunctionBody(fake, ctx, helperName, parentNs, cssHash);
25121
+ helperFn = compileFunctionBody(
25122
+ fake,
25123
+ ctx,
25124
+ helperName,
25125
+ parentNs,
25126
+ cssHash,
25127
+ keyedSelection === null ? null : { keyedSelection },
25128
+ );
25070
25129
  } finally {
25071
25130
  ctx.currentComponentLocals = prevLocals;
25072
25131
  ctx.currentInvariantLocals = prevInvariantLocals;
@@ -25075,6 +25134,35 @@ function hoistBodyHelper(
25075
25134
  // Module-scope placement: the compiled helper joins the module AST as a
25076
25135
  // hoisted statement node (M2 AST emit).
25077
25136
  ctx.hoistedHelpers.push(helperFn);
25137
+ if (keyedSelection?.update != null) {
25138
+ const selectionName = allocCompilerName(ctx, `__select$${ctx.nextHelperId++}`);
25139
+ const origin = keyedSelection.update;
25140
+ const selectionBody = [
25141
+ inheritOriginLoc(
25142
+ b.const(
25143
+ keyedSelection.selectedName,
25144
+ b.member(b.id('__extra'), b.literal(keyedSelection.selectedIndex), true),
25145
+ ),
25146
+ origin,
25147
+ ),
25148
+ inheritOriginLoc(
25149
+ b.const('_b', b.member(b.member(b.id('__s'), 'slots'), b.literal(0), true)),
25150
+ origin,
25151
+ ),
25152
+ keyedSelection.update,
25153
+ ];
25154
+ ctx.hoistedHelpers.push(
25155
+ inheritOriginLoc(
25156
+ b.function_declaration(
25157
+ b.id(selectionName, idOrigin ?? fakeOrigin ?? undefined),
25158
+ [...params, b.id('__s'), b.id('__extra')],
25159
+ b.block(selectionBody),
25160
+ ),
25161
+ fakeOrigin,
25162
+ ),
25163
+ );
25164
+ keyedSelection.helper = selectionName;
25165
+ }
25078
25166
  return helperName;
25079
25167
  }
25080
25168
 
@@ -25984,14 +26072,17 @@ function makeSwitchCall(node, ctx, inlinedSubs, parentNs = 'html', cssHash = nul
25984
26072
  * snapshot remain unchanged.
25985
26073
  *
25986
26074
  * This recognizes `selected === item.id` (or its reverse) under `key item.id`,
25987
- * and the same proof for any other explicit, noncomputed item property.
26075
+ * optionally through one preceding `const id = item.id`, and the same proof
26076
+ * for any other explicit, noncomputed item property. The authored declaration
26077
+ * stays in the full item body, preserving its read position and event captures.
25988
26078
  * Dynamic ternary arms, extra references to
25989
26079
  * `selected` anywhere in the row (including deferred event callbacks), spreads,
25990
26080
  * and anything other than one direct host root all fail closed.
25991
26081
  */
25992
26082
  function keyedSelectionDepIndex(itemName, keyBody, subStmts, runtimeDepNames, ctx) {
25993
- if (subStmts.length !== 1 || !isPlainHostRoot(subStmts[0])) return -1;
25994
- const root = subStmts[0];
26083
+ if (subStmts.length !== 1 && subStmts.length !== 2) return -1;
26084
+ const root = subStmts[subStmts.length - 1];
26085
+ if (!isPlainHostRoot(root)) return -1;
25995
26086
  const attrs = root.attributes || root.openingElement?.attributes || [];
25996
26087
  if (attrs.some((attr) => attr.type !== 'Attribute' && attr.type !== 'JSXAttribute')) {
25997
26088
  return -1;
@@ -26043,12 +26134,33 @@ function keyedSelectionDepIndex(itemName, keyBody, subStmts, runtimeDepNames, ct
26043
26134
  member.property.name === keyProperty
26044
26135
  );
26045
26136
  };
26137
+ let keyAlias = null;
26138
+ if (subStmts.length === 2) {
26139
+ const declaration = subStmts[0];
26140
+ const binding = declaration.declarations?.[0];
26141
+ if (
26142
+ declaration.type !== 'VariableDeclaration' ||
26143
+ declaration.kind !== 'const' ||
26144
+ declaration.declare === true ||
26145
+ declaration.declarations?.length !== 1 ||
26146
+ binding?.id?.type !== 'Identifier' ||
26147
+ binding.id.name === itemName ||
26148
+ !isItemKey(binding.init)
26149
+ ) {
26150
+ return -1;
26151
+ }
26152
+ keyAlias = binding.id.name;
26153
+ }
26154
+ const isComparedKey = (expression) =>
26155
+ isItemKey(expression) ||
26156
+ (keyAlias !== null && expression?.type === 'Identifier' && expression.name === keyAlias);
26046
26157
  const left = unwrapTsExpr(test.left);
26047
26158
  const right = unwrapTsExpr(test.right);
26048
- const selected = isItemKey(left) ? right : isItemKey(right) ? left : null;
26159
+ const selected = isComparedKey(left) ? right : isComparedKey(right) ? left : null;
26049
26160
  if (
26050
26161
  selected?.type !== 'Identifier' ||
26051
26162
  selected.name === itemName ||
26163
+ selected.name === keyAlias ||
26052
26164
  !ctx.currentComponentLocals?.has(selected.name)
26053
26165
  ) {
26054
26166
  return -1;
@@ -26493,18 +26605,6 @@ function makeForCall(node, ctx, inlinedSubs, parentNs = 'html', cssHash = null)
26493
26605
  node.emptyKeyword ?? null,
26494
26606
  );
26495
26607
  }
26496
- const itemHelperName = hoistBodyHelper(
26497
- ctx,
26498
- inlinedSubs,
26499
- '__item',
26500
- itemAllStmts,
26501
- itemParams,
26502
- parentNs,
26503
- cssHash,
26504
- envNames,
26505
- directiveKeywordOrigin(ctx, node),
26506
- );
26507
-
26508
26608
  // Single-root detection: when the body emits exactly one Element root and
26509
26609
  // no other JSX siblings (no Fragment, no Component, no top-level if/for/try),
26510
26610
  // the runtime can skip per-item Comment markers and use the row element
@@ -26576,6 +26676,31 @@ function makeForCall(node, ctx, inlinedSubs, parentNs = 'html', cssHash = null)
26576
26676
  !containsRenderCall(subStmts) &&
26577
26677
  !containsAutoMemoUnsafeStructure(subStmts) &&
26578
26678
  isHostMountSafeTree(subStmts[0]);
26679
+ // Class-only updates need the stricter host-lifecycle proof as well as the
26680
+ // existing equality proof. The item planner fills this compiler-owned result
26681
+ // only when the root class survives as one ordinary cached binding.
26682
+ const keyedSelection =
26683
+ hostMountSafe && keyedSelectionIndex >= 0 && envNames !== null
26684
+ ? {
26685
+ itemName,
26686
+ selectedName: runtimeDepNames[keyedSelectionIndex],
26687
+ selectedIndex: keyedSelectionIndex,
26688
+ update: null,
26689
+ helper: null,
26690
+ }
26691
+ : null;
26692
+ const itemHelperName = hoistBodyHelper(
26693
+ ctx,
26694
+ inlinedSubs,
26695
+ '__item',
26696
+ itemAllStmts,
26697
+ itemParams,
26698
+ parentNs,
26699
+ cssHash,
26700
+ envNames,
26701
+ directiveKeywordOrigin(ctx, node),
26702
+ keyedSelection,
26703
+ );
26579
26704
 
26580
26705
  const mapCall = node.nativeArrayMap || null;
26581
26706
  return {
@@ -26606,6 +26731,7 @@ function makeForCall(node, ctx, inlinedSubs, parentNs = 'html', cssHash = null)
26606
26731
  keyHelper,
26607
26732
  inlineKey: inlineKey ? keyFn : null,
26608
26733
  bodyHelper: itemHelperName,
26734
+ selectionHelper: keyedSelection?.helper ?? null,
26609
26735
  hasPerItemEventClosure,
26610
26736
  pure,
26611
26737
  singleRoot,
package/dist/runtime.d.ts CHANGED
@@ -1480,11 +1480,11 @@ export declare function forBlock<T>(parentScope: Scope, slotKey: number, domPare
1480
1480
  * forBlock lets applications without a proven selection tree-shake its cost.
1481
1481
  * This entry point identifies the proof; bits 6+ hold its dependency index.
1482
1482
  */
1483
- export declare function keyedForBlock<T>(parentScope: Scope, slotKey: number, domParent: Node, items: ArrayLike<T>, getKey: (item: T, index: number) => any, itemBody: (item: T, scope: Scope) => void, flags: number, deps: any[], emptyBody?: ComponentBody | null, anchor?: Node | null, ownEnd?: boolean): void;
1483
+ export declare function keyedForBlock<T>(parentScope: Scope, slotKey: number, domParent: Node, items: ArrayLike<T>, getKey: (item: T, index: number) => any, itemBody: (item: T, scope: Scope) => void, flags: number, deps: any[], emptyBody?: ComponentBody | null, anchor?: Node | null, ownEnd?: boolean, selectionBody?: ComponentBody<T, any[]>): void;
1484
1484
  /** Compiler-only direct host-row entry; ordinary list bundles do not retain it. */
1485
1485
  export declare function fastForBlock<T>(parentScope: Scope, slotKey: number, domParent: Node, items: ArrayLike<T>, getKey: (item: T, index: number) => any, itemBody: (item: T, scope: Scope) => void, flags?: number, deps?: any[], emptyBody?: ComponentBody | null, anchor?: Node | null, ownEnd?: boolean): void;
1486
1486
  /** Direct host-row mounts composed with the independent keyed-selection proof. */
1487
- export declare function fastKeyedForBlock<T>(parentScope: Scope, slotKey: number, domParent: Node, items: ArrayLike<T>, getKey: (item: T, index: number) => any, itemBody: (item: T, scope: Scope) => void, flags: number, deps: any[], emptyBody?: ComponentBody | null, anchor?: Node | null, ownEnd?: boolean): void;
1487
+ export declare function fastKeyedForBlock<T>(parentScope: Scope, slotKey: number, domParent: Node, items: ArrayLike<T>, getKey: (item: T, index: number) => any, itemBody: (item: T, scope: Scope) => void, flags: number, deps: any[], emptyBody?: ComponentBody | null, anchor?: Node | null, ownEnd?: boolean, selectionBody?: ComponentBody<T, any[]>): void;
1488
1488
  /** Direct host-row mounts for compiler-proven, guarded native JSX map rows. */
1489
1489
  export declare function fastMapSlot(scopeOrItems: any, slotOrMethod: any, domParent?: Node, items?: any, method?: any, native?: boolean | ((...args: any[]) => any), callback?: (...args: any[]) => any, getKey?: (item: any, index: number) => any, itemBody?: (item: any, scope: Scope) => void, flags?: number, deps?: any[], anchor?: Node | null, ownEnd?: boolean | 1): boolean | void;
1490
1490
  export interface Root {
package/dist/runtime.js CHANGED
@@ -325,18 +325,19 @@ function stagedTransitionValue(slot) {
325
325
  function stageTransitionValue(slot, block, operation, value, forceRender = false) {
326
326
  const batch = transitionActionBatchForUpdate();
327
327
  if (batch === null) return false;
328
+ const replay = typeof operation === "function" ? operation : () => operation;
328
329
  const current = batch.updates.get(slot);
329
330
  if (current === void 0) {
330
331
  batch.updates.set(slot, {
331
332
  slot,
332
333
  block,
333
- operations: [operation],
334
+ operations: [replay],
334
335
  baseValue: slot.value,
335
336
  value,
336
337
  forceRender
337
338
  });
338
339
  } else {
339
- current.operations.push(operation);
340
+ current.operations.push(replay);
340
341
  current.value = value;
341
342
  current.forceRender ||= forceRender;
342
343
  }
@@ -1307,12 +1308,21 @@ function flush() {
1307
1308
  }
1308
1309
  return;
1309
1310
  }
1311
+ if (!hasPendingWork() && refDetachQueue.length === 0 && refAttachQueue.length === 0 && activeFragments.size === 0 && FLUSHED_TRANSITION_UPDATES.length === 0 && VIEW_TRANSITION_DRIVER === null) {
1312
+ if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__)
1313
+ __devtoolsNotifyFlush();
1314
+ return;
1315
+ }
1310
1316
  if (VIEW_TRANSITION_DRIVER?.routeFlush() === true) return;
1311
1317
  flushWork();
1312
1318
  }
1313
1319
  function activeElementForDocument(doc) {
1314
1320
  try {
1315
1321
  let focused = doc.activeElement;
1322
+ if (focused === doc.body) {
1323
+ focused = focused?.shadowRoot?.activeElement ?? null;
1324
+ if (focused === null) return null;
1325
+ }
1316
1326
  while (focused !== null) {
1317
1327
  if (focused.localName === "iframe") {
1318
1328
  let nested;
@@ -2968,10 +2978,9 @@ function useState(initial, slot) {
2968
2978
  value: initVal,
2969
2979
  setter: (next) => {
2970
2980
  const previous = stagedTransitionValue(s);
2971
- const operation = typeof next === "function" ? next : () => next;
2972
- const computed = operation(previous);
2981
+ const computed = typeof next === "function" ? next(previous) : next;
2973
2982
  if (Object.is(computed, previous)) return;
2974
- if (stageTransitionValue(s, block, operation, computed)) {
2983
+ if (stageTransitionValue(s, block, next, computed)) {
2975
2984
  if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__) {
2976
2985
  const update = s.pendingActionBatch?.updates.get(s);
2977
2986
  if (update !== void 0) {
@@ -4488,6 +4497,10 @@ function activateHydrateBoundary(state) {
4488
4497
  renderBlock(block);
4489
4498
  drainHydrationRenderPhaseUpdates(block);
4490
4499
  if (state.hydrated) {
4500
+ const adoptedSlot = block.slots[0];
4501
+ if (adoptedSlot?.__kind === "trySlotSlot") {
4502
+ hydration.claimRootRemainder(adoptedSlot.end.nextSibling);
4503
+ }
4491
4504
  hydration.flushClassWrites();
4492
4505
  hydration.flushTextWarnings();
4493
4506
  hydration.finishRoot();
@@ -14833,7 +14846,7 @@ function forBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flag
14833
14846
  hydration.node = state.end.nextSibling;
14834
14847
  }
14835
14848
  }
14836
- function keyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd) {
14849
+ function keyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd, selectionBody) {
14837
14850
  const state = parentScope.slots[slotKey];
14838
14851
  if (TRANSITION_JOURNAL !== null) {
14839
14852
  if (state !== void 0) {
@@ -14841,7 +14854,15 @@ function keyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody,
14841
14854
  state.selectionItems = void 0;
14842
14855
  }
14843
14856
  flags &= ~4;
14844
- } else if (state !== void 0 && activeHydration() === null && state.cachedDeps !== null && tryUpdateKeyedSelection(state, items, itemBody, state.cachedDeps, deps, flags >>> 6)) {
14857
+ } else if (state !== void 0 && activeHydration() === null && state.cachedDeps !== null && tryUpdateKeyedSelection(
14858
+ state,
14859
+ items,
14860
+ itemBody,
14861
+ state.cachedDeps,
14862
+ deps,
14863
+ flags >>> 6,
14864
+ selectionBody
14865
+ )) {
14845
14866
  return;
14846
14867
  }
14847
14868
  forBlock(
@@ -14965,7 +14986,7 @@ function fastForBlock(parentScope, slotKey, domParent, items, getKey, itemBody,
14965
14986
  }
14966
14987
  mountFastHostItems(parentScope, state, parent, items, getKey, itemBody, flags, deps, false);
14967
14988
  }
14968
- function fastKeyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd) {
14989
+ function fastKeyedForBlock(parentScope, slotKey, domParent, items, getKey, itemBody, flags, deps, emptyBody, anchor, ownEnd, selectionBody) {
14969
14990
  const state = parentScope.slots[slotKey];
14970
14991
  const parent = fastHostListParent(state, items, flags);
14971
14992
  if (parent === null) {
@@ -14980,7 +15001,8 @@ function fastKeyedForBlock(parentScope, slotKey, domParent, items, getKey, itemB
14980
15001
  deps,
14981
15002
  emptyBody,
14982
15003
  anchor,
14983
- ownEnd
15004
+ ownEnd,
15005
+ selectionBody
14984
15006
  );
14985
15007
  return;
14986
15008
  }
@@ -15052,7 +15074,7 @@ function depsEqual(a, b) {
15052
15074
  }
15053
15075
  return true;
15054
15076
  }
15055
- function tryUpdateKeyedSelection(state, items, itemBody, previousDeps, deps, selectionIndex) {
15077
+ function tryUpdateKeyedSelection(state, items, itemBody, previousDeps, deps, selectionIndex, selectionBody) {
15056
15078
  if (state.selectionItems !== items || state.size !== items.length || state.items.size !== state.size || previousDeps.length !== deps.length || selectionIndex >= deps.length) {
15057
15079
  return false;
15058
15080
  }
@@ -15075,12 +15097,20 @@ function tryUpdateKeyedSelection(state, items, itemBody, previousDeps, deps, sel
15075
15097
  if (first !== void 0) {
15076
15098
  first.body = itemBody;
15077
15099
  first.extra = deps;
15078
- itemBody(first.props, first, deps);
15100
+ if (selectionBody !== void 0 && first._slots === null) {
15101
+ selectionBody(first.props, first, deps);
15102
+ } else {
15103
+ itemBody(first.props, first, deps);
15104
+ }
15079
15105
  }
15080
15106
  if (second !== void 0) {
15081
15107
  second.body = itemBody;
15082
15108
  second.extra = deps;
15083
- itemBody(second.props, second, deps);
15109
+ if (selectionBody !== void 0 && second._slots === null) {
15110
+ selectionBody(second.props, second, deps);
15111
+ } else {
15112
+ itemBody(second.props, second, deps);
15113
+ }
15084
15114
  }
15085
15115
  return true;
15086
15116
  }
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
- const version = "0.1.41";
1
+ const version = "0.1.42";
2
2
  export {
3
3
  version
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "octane",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": [