@stacksjs/stx 0.2.174 → 0.2.175

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.
@@ -32,6 +32,7 @@ export function injectBrowserRuntime(template) {
32
32
  "clamp",
33
33
  "rand",
34
34
  "readableSize",
35
+ "useActiveElement",
35
36
  "useDocumentVisibility",
36
37
  "useIntervalFn"
37
38
  ].some((sym) => {
package/dist/signals.js CHANGED
@@ -1183,7 +1183,7 @@ else if (immediate) {
1183
1183
  var ownerScope = currentLifecycleScope() || componentScope;
1184
1184
  return {
1185
1185
  get current() {
1186
- return ownerScope.$refs ? ownerScope.$refs[name] : null;
1186
+ return (ownerScope.$refs && ownerScope.$refs[name]) || null;
1187
1187
  },
1188
1188
  get value() {
1189
1189
  return this.current;
@@ -4367,33 +4367,30 @@ catch (e2) {
4367
4367
  }
4368
4368
 
4369
4369
  // Helper to evaluate with captured scope (auto-unwraps signals).
4370
- // Mirrors bindStyle/bindShow/evalAttrExpr: first try the auto-unwrap
4371
- // proxy (so a bare-reference comparison like count > 5 reads the signal
4372
- // as a primitive), then retry with the raw scope so call-syntax
4373
- // expressions like count() === 0 or !recording() still work. The proxy
4374
- // unwraps signals to their values, which turns count() into 0() ->
4375
- // TypeError; pre-fix (stacksjs/stx#1733) the single catch swallowed
4376
- // that TypeError and returned '' (falsy), silently hiding the element
4377
- // for EVERY comparison/boolean expression. bindIf was the only
4378
- // directive missing this retry.
4370
+ // A with-scope resolves only identifiers the expression actually references,
4371
+ // so the conditional subscribes narrowly instead of reading every signal
4372
+ // in a component scope. That broad subscription made an unrelated ref
4373
+ // update re-enter structural removal while the real condition was already
4374
+ // removing the same subtree. First try the auto-unwrap proxy (so a bare
4375
+ // comparison like count > 5 reads the signal value), then retry with the
4376
+ // raw scope so call syntax like count() === 0 still works (#1733).
4379
4377
  const evalExpr = (expression) => {
4380
4378
  // Skip placeholder expressions like __TITLE__ (build-time placeholders)
4381
4379
  if (/^__[A-Z_]+__$/.test(expression.trim())) {
4382
4380
  return expression;
4383
4381
  }
4384
4382
  try {
4385
- // Use captured componentScope (with @for vars) merged with element scope
4386
4383
  const scope = { ...globalHelpers, ...capturedComponentScope, ...(capturedElementScope || {}) };
4387
4384
  const unwrapScope = createExpressionAutoUnwrapProxy(scope, expression);
4388
- const fn = new Function(...Object.keys(scope), 'return ' + expression);
4389
- return fn(...Object.values(unwrapScope));
4385
+ const fn = new Function('__scope__', 'with(__scope__) { return ' + expression + ' }');
4386
+ return fn(unwrapScope);
4390
4387
  }
4391
4388
  catch (e1) {
4392
4389
  try {
4393
4390
  // Retry without the unwrap proxy so call-syntax (signal()) works.
4394
4391
  const scope2 = { ...globalHelpers, ...capturedComponentScope, ...(capturedElementScope || {}) };
4395
- const fn2 = new Function(...Object.keys(scope2), 'return ' + expression);
4396
- return fn2(...Object.values(scope2));
4392
+ const fn2 = new Function('__scope__', 'with(__scope__) { return ' + expression + ' }');
4393
+ return fn2(scope2);
4397
4394
  }
4398
4395
  catch (e2) {
4399
4396
  if (!(e2 instanceof ReferenceError) && !(e2 instanceof TypeError)) console.warn('[STX] Expression error:', expression, e2);
@@ -4450,11 +4447,6 @@ catch (e2) {
4450
4447
  value = directSignal();
4451
4448
  console.log('[stx] bindIf effect (direct):', expr, '\u2192', value, 'isInserted:', isInserted);
4452
4449
  } else {
4453
- // Complex expression: read all signals first for tracking, then evaluate
4454
- for (var sk in fullScope) {
4455
- var sv = fullScope[sk];
4456
- if (sv && typeof sv === 'function' && (sv._isSignal || sv._isDerived)) sv();
4457
- }
4458
4450
  value = evalExpr(expr);
4459
4451
  }
4460
4452
 
@@ -4892,12 +4884,19 @@ else if (timer === null) {
4892
4884
  };
4893
4885
  }
4894
4886
 
4895
- // Queue work after the current synchronous signal/effect flush. This mirrors
4896
- // the Composition API nextTick contract and gives template refs a chance to
4897
- // resolve after a structural directive inserts their elements.
4887
+ // Queue work after the current synchronous signal/effect flush and after
4888
+ // structural directives finish their deferred subtree hydration. The
4889
+ // microtask schedules this timer only after every subscriber has run, so a
4890
+ // :if/:for timer created later in the same signal flush runs first and its
4891
+ // template refs are available to the callback.
4898
4892
  function nextTick(fn) {
4899
4893
  return Promise.resolve().then(function() {
4900
- if (fn) fn();
4894
+ return new Promise(function(resolve) {
4895
+ setTimeout(function() {
4896
+ if (fn) fn();
4897
+ resolve();
4898
+ }, 0);
4899
+ });
4901
4900
  });
4902
4901
  }
4903
4902