@barefootjs/vite 0.33.0 → 0.33.1

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.
Files changed (2) hide show
  1. package/dist/index.js +145 -40
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -5057,6 +5057,7 @@ var ErrorCodes = {
5057
5057
  MISSING_KEY_IN_LIST: "BF023",
5058
5058
  MISSING_KEY_IN_NESTED_LIST: "BF024",
5059
5059
  UNSUPPORTED_DESTRUCTURE_REST: "BF025",
5060
+ RETURN_VALUE_NOT_JSX: "BF027",
5060
5061
  PROPS_DESTRUCTURING: "BF043",
5061
5062
  SIGNAL_GETTER_NOT_CALLED: "BF044",
5062
5063
  JSX_IN_LOCAL_FUNCTION: "BF045",
@@ -5088,6 +5089,7 @@ var errorMessages = {
5088
5089
  [ErrorCodes.MISSING_KEY_IN_LIST]: "Missing key attribute in list rendering. Add a key prop for efficient updates",
5089
5090
  [ErrorCodes.MISSING_KEY_IN_NESTED_LIST]: "Nested .map() loop requires key attribute for event delegation. Add a key prop to elements in the inner loop",
5090
5091
  [ErrorCodes.UNSUPPORTED_DESTRUCTURE_REST]: "Computed property key in .map() callback destructure is not supported. Rewrite the callback to destructure explicit bindings (e.g., `({ a, b }) => ...`) so the compiler can rewrite references to per-item signal accessors.",
5092
+ [ErrorCodes.RETURN_VALUE_NOT_JSX]: "Component's return value is not recognized as JSX — return the JSX expression directly instead of binding it to a local variable first.",
5091
5093
  [ErrorCodes.PROPS_DESTRUCTURING]: "Props destructuring in function parameters breaks reactivity. Use props object directly.",
5092
5094
  [ErrorCodes.SIGNAL_GETTER_NOT_CALLED]: "Signal/memo getter passed without calling it. Use getter() to read the value.",
5093
5095
  [ErrorCodes.JSX_IN_LOCAL_FUNCTION]: "Local function returns JSX but cannot be inlined. Extract it as a top-level PascalCase component or use a single return statement.",
@@ -5730,6 +5732,14 @@ function visitComponentBody(node, ctx) {
5730
5732
  }
5731
5733
  }
5732
5734
  if (isTopLevel && (ts9.isTryStatement(node) || ts9.isSwitchStatement(node) || ts9.isForStatement(node) || ts9.isForInStatement(node) || ts9.isForOfStatement(node) || ts9.isWhileStatement(node) || ts9.isDoStatement(node) || ts9.isThrowStatement(node) || ts9.isBlock(node) && node.parent === ctx.componentBodyBlock)) {
5735
+ if (ts9.isBlock(node)) {
5736
+ const returnedLocal = findBlockBodyReturnedJsxLocalName(node);
5737
+ if (returnedLocal) {
5738
+ ctx.errors.push(createError(ErrorCodes.RETURN_VALUE_NOT_JSX, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
5739
+ message: `Component '${ctx.componentName ?? "(unknown)"}' return value is not recognized ` + `as JSX — return the JSX expression directly instead of binding it to a local ` + `variable first (\`return ${returnedLocal}\` after \`const ${returnedLocal} = ` + `<jsx/>\` is not resolved at return position).`
5740
+ }));
5741
+ }
5742
+ }
5733
5743
  collectInitStatement(node, ctx);
5734
5744
  return;
5735
5745
  }
@@ -5765,6 +5775,31 @@ function unwrapJsxTransparent(expr) {
5765
5775
  }
5766
5776
  return current;
5767
5777
  }
5778
+ function findBlockBodyReturnedJsxLocalName(block) {
5779
+ const stmts = block.statements;
5780
+ const last = stmts[stmts.length - 1];
5781
+ if (!last || !ts9.isReturnStatement(last) || !last.expression)
5782
+ return null;
5783
+ const returned = unwrapJsxTransparent(last.expression);
5784
+ if (!ts9.isIdentifier(returned))
5785
+ return null;
5786
+ const name = returned.text;
5787
+ for (const stmt of stmts) {
5788
+ if (!ts9.isVariableStatement(stmt))
5789
+ continue;
5790
+ for (const decl of stmt.declarationList.declarations) {
5791
+ if (!ts9.isIdentifier(decl.name) || decl.name.text !== name || !decl.initializer)
5792
+ continue;
5793
+ let init = decl.initializer;
5794
+ while (ts9.isParenthesizedExpression(init))
5795
+ init = init.expression;
5796
+ if (ts9.isJsxElement(init) || ts9.isJsxSelfClosingElement(init) || ts9.isJsxFragment(init) || initializerShapeContainsJsx(init) || isMapLikeCallWithJsx(init)) {
5797
+ return name;
5798
+ }
5799
+ }
5800
+ }
5801
+ return null;
5802
+ }
5768
5803
  function extractJsxFromExpression(expr) {
5769
5804
  const inner = unwrapJsxTransparent(expr);
5770
5805
  if (ts9.isJsxElement(inner) || ts9.isJsxFragment(inner) || ts9.isJsxSelfClosingElement(inner)) {
@@ -10106,8 +10141,14 @@ function buildIRRoot(analyzer) {
10106
10141
  }
10107
10142
  ctx.isRoot = false;
10108
10143
  const ir = transformJsxExpression(jsxReturn, ctx);
10109
- if (ir === null)
10144
+ if (ir === null) {
10145
+ if (ts13.isIdentifier(jsxReturn) && (analyzer.jsxConstants.has(jsxReturn.text) || analyzer.inlineableJsxConsts.has(jsxReturn.text))) {
10146
+ analyzer.errors.push(createError(ErrorCodes.RETURN_VALUE_NOT_JSX, getSourceLocation(jsxReturn, analyzer.sourceFile, analyzer.filePath), {
10147
+ message: `Component '${analyzer.componentName ?? "(unknown)"}' return value is not recognized ` + `as JSX — return the JSX expression directly instead of binding it to a local variable ` + `first (\`return ${jsxReturn.text}\` after \`const ${jsxReturn.text} = <jsx/>\` is not ` + `resolved at return position).`
10148
+ }));
10149
+ }
10110
10150
  return null;
10151
+ }
10111
10152
  return wrapInScopeElement(ir);
10112
10153
  }
10113
10154
  function needsScopeWrapper(ir) {
@@ -13222,6 +13263,35 @@ function getStringValue(node) {
13222
13263
  }
13223
13264
  return null;
13224
13265
  }
13266
+ function unwrapTransparentTsWrappers(node) {
13267
+ let n = node;
13268
+ while (ts13.isParenthesizedExpression(n) || ts13.isAsExpression(n) || ts13.isSatisfiesExpression(n) || ts13.isNonNullExpression(n)) {
13269
+ n = n.expression;
13270
+ }
13271
+ return n;
13272
+ }
13273
+ function expressionWrapsJsx(node) {
13274
+ const n = unwrapTransparentTsWrappers(node);
13275
+ if (ts13.isJsxElement(n) || ts13.isJsxSelfClosingElement(n) || ts13.isJsxFragment(n))
13276
+ return true;
13277
+ if (ts13.isConditionalExpression(n)) {
13278
+ return expressionWrapsJsx(n.whenTrue) || expressionWrapsJsx(n.whenFalse);
13279
+ }
13280
+ if (ts13.isArrayLiteralExpression(n)) {
13281
+ return n.elements.some((el) => expressionWrapsJsx(ts13.isSpreadElement(el) ? el.expression : el));
13282
+ }
13283
+ return false;
13284
+ }
13285
+ function reportNakedJsxWrapperProp(ctx, attr, propName, jsxExpr) {
13286
+ const shape = ts13.isConditionalExpression(jsxExpr) ? "a ternary" : "an array literal";
13287
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(attr, ctx.sourceFile, ctx.filePath), {
13288
+ message: `Prop '${propName}' is ${shape} wrapping JSX (${jsxExpr.getText(ctx.sourceFile)}). ` + `This shape is not compiled — only a JSX element/fragment given DIRECTLY as the prop value is.`,
13289
+ suggestion: {
13290
+ message: `Move the conditional/array out of the prop position: compute it in a local ` + `const and pass it as the component's children instead of a named prop ` + `(e.g. const ${propName} = ${jsxExpr.getText(ctx.sourceFile)}; <Comp>{${propName}}</Comp>). ` + `Wrapping the ternary/array in a fragment at the prop position ` + `(${propName}={<>{${jsxExpr.getText(ctx.sourceFile)}}</>}) is NOT a safe escape here: it compiles, ` + `but the child's own reactive prop getter receives the branch's HTML unbranded and re-escapes it as ` + `text on the child's very next reactive run, corrupting the DOM (a narrower gap #2651's door ` + `inventory left open — tracked separately).`,
13291
+ escape: [{ kind: "rewrite" }]
13292
+ }
13293
+ }));
13294
+ }
13225
13295
  function processComponentProps(attributes, ctx) {
13226
13296
  const props = [];
13227
13297
  for (const attr of attributes.properties) {
@@ -13233,10 +13303,7 @@ function processComponentProps(attributes, ctx) {
13233
13303
  continue;
13234
13304
  const name = attr.name.getText(ctx.sourceFile);
13235
13305
  if (attr.initializer && ts13.isJsxExpression(attr.initializer) && attr.initializer.expression) {
13236
- let jsxExpr = attr.initializer.expression;
13237
- while (ts13.isParenthesizedExpression(jsxExpr)) {
13238
- jsxExpr = jsxExpr.expression;
13239
- }
13306
+ const jsxExpr = unwrapTransparentTsWrappers(attr.initializer.expression);
13240
13307
  if (ts13.isJsxElement(jsxExpr) || ts13.isJsxSelfClosingElement(jsxExpr) || ts13.isJsxFragment(jsxExpr)) {
13241
13308
  const prevInsideComponentChildren = ctx.insideComponentChildren;
13242
13309
  ctx.insideComponentChildren = true;
@@ -13251,6 +13318,10 @@ function processComponentProps(attributes, ctx) {
13251
13318
  continue;
13252
13319
  }
13253
13320
  }
13321
+ if ((ts13.isConditionalExpression(jsxExpr) || ts13.isArrayLiteralExpression(jsxExpr)) && expressionWrapsJsx(jsxExpr)) {
13322
+ reportNakedJsxWrapperProp(ctx, attr, name, jsxExpr);
13323
+ continue;
13324
+ }
13254
13325
  }
13255
13326
  let value = getAttributeValue(attr, ctx);
13256
13327
  if (value.kind === "template") {
@@ -14332,10 +14403,11 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
14332
14403
  const innerPreambleNames = preambleNamesOf(n);
14333
14404
  if (ctx) {
14334
14405
  for (const child of n.children) {
14335
- bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx, n.param, n.paramBindings, false, innerPreambleNames, n.index));
14336
- bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx, n.param, n.paramBindings, false, innerPreambleNames, n.index));
14406
+ bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx, n.param, n.paramBindings, true, innerPreambleNames, n.index));
14407
+ bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx, n.param, n.paramBindings, true, innerPreambleNames, n.index));
14337
14408
  bindings.refs.push(...collectLoopChildRefs(child));
14338
14409
  }
14410
+ bindings.conditionals.push(...collectLoopChildConditionals({ type: "fragment", children: n.children, loc: n.loc }, ctx, siblingOffsets, n.param, n.paramBindings, innerPreambleNames, n.index));
14339
14411
  }
14340
14412
  let childComponents;
14341
14413
  if (collectBindings) {
@@ -14359,9 +14431,6 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
14359
14431
  for (const child of n.children) {
14360
14432
  bindings.events.push(...collectLoopChildEventsWithNesting(child));
14361
14433
  }
14362
- if (ctx) {
14363
- bindings.conditionals.push(...collectLoopChildConditionals({ type: "fragment", children: n.children, loc: n.loc }, ctx, siblingOffsets, n.param, n.paramBindings, innerPreambleNames, n.index));
14364
- }
14365
14434
  }
14366
14435
  result.push({
14367
14436
  kind: "nested",
@@ -15497,6 +15566,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
15497
15566
  "mapArrayLazy",
15498
15567
  "patchLeaf",
15499
15568
  "createDisposableEffect",
15569
+ "findCondContainer",
15500
15570
  "createComponent",
15501
15571
  "renderChild",
15502
15572
  "registerComponent",
@@ -17354,7 +17424,8 @@ function emitProviderAndChildInits(lines, ctx) {
17354
17424
  lines.push(` upsertChild(__scope, '${registryName}', '${child.slotId}', ${child.propsExpr})`);
17355
17425
  continue;
17356
17426
  }
17357
- const scopeRef = child.slotId ? `_${varSlotId(child.slotId)}` : "__scope";
17427
+ const isCommentRoot = child.slotId !== null && child.slotId === ctx.commentScopeRootSlotId;
17428
+ const scopeRef = !child.slotId || isCommentRoot ? "__scope" : `_${varSlotId(child.slotId)}`;
17358
17429
  lines.push(` initChild('${registryName}', ${scopeRef}, ${child.propsExpr})`);
17359
17430
  }
17360
17431
  }
@@ -18004,6 +18075,7 @@ function buildBranchInnerLoopsPlan(args) {
18004
18075
  const {
18005
18076
  innerLoops,
18006
18077
  scopeVar,
18078
+ condSlotId,
18007
18079
  outerLoopParam,
18008
18080
  outerLoopParamBindings,
18009
18081
  wrapOuter
@@ -18018,7 +18090,7 @@ function buildBranchInnerLoopsPlan(args) {
18018
18090
  const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
18019
18091
  const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
18020
18092
  const csl = inner.containerSlotId;
18021
- const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST}="\${__scopeId}"][${BF_AT}="${csl}"]\`) ?? ${scopeVar})` : scopeVar;
18093
+ const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST}="\${__scopeId}"][${BF_AT}="${csl}"]\`) ?? ${scopeVar})` : `findCondContainer(${scopeVar}, '${condSlotId}')`;
18022
18094
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
18023
18095
  const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
18024
18096
  const wrapIRNode = (node) => {
@@ -18102,13 +18174,15 @@ function buildLoopChildConditionalsPlan(args) {
18102
18174
  branch: cond.whenTrue,
18103
18175
  wrap,
18104
18176
  loopParam,
18105
- loopParamBindings
18177
+ loopParamBindings,
18178
+ condId: cond.slotId
18106
18179
  }),
18107
18180
  whenFalseArm: buildLoopChildArmPlan({
18108
18181
  branch: cond.whenFalse,
18109
18182
  wrap,
18110
18183
  loopParam,
18111
- loopParamBindings
18184
+ loopParamBindings,
18185
+ condId: cond.slotId
18112
18186
  })
18113
18187
  });
18114
18188
  }
@@ -18148,7 +18222,7 @@ function buildArmTextsPlan(texts, wrap) {
18148
18222
  }));
18149
18223
  }
18150
18224
  function buildLoopChildArmPlan(args) {
18151
- const { branch, wrap, loopParam, loopParamBindings } = args;
18225
+ const { branch, wrap, loopParam, loopParamBindings, condId } = args;
18152
18226
  return {
18153
18227
  events: buildBranchEventBindingsPlan({
18154
18228
  events: branch.events,
@@ -18161,6 +18235,7 @@ function buildLoopChildArmPlan(args) {
18161
18235
  innerLoops: buildBranchInnerLoopsPlan({
18162
18236
  innerLoops: branch.innerLoops,
18163
18237
  scopeVar: "__branchScope",
18238
+ condSlotId: condId,
18164
18239
  outerLoopParam: loopParam,
18165
18240
  outerLoopParamBindings: loopParamBindings,
18166
18241
  wrapOuter: wrap
@@ -18214,8 +18289,8 @@ function buildReactiveEffectsPlan(args) {
18214
18289
  wrappedCondition: wrap(cond.condition),
18215
18290
  whenTrueTemplateHtml: addCondAttrToTemplate(wrap(cond.whenTrueHtml), cond.slotId),
18216
18291
  whenFalseTemplateHtml: addCondAttrToTemplate(wrap(cond.whenFalseHtml), cond.slotId),
18217
- whenTrueArm: buildOuterArm(cond.whenTrue, wrap, loopParam, loopParamBindings, profileComponentName),
18218
- whenFalseArm: buildOuterArm(cond.whenFalse, wrap, loopParam, loopParamBindings, profileComponentName),
18292
+ whenTrueArm: buildOuterArm(cond.whenTrue, wrap, loopParam, loopParamBindings, cond.slotId, profileComponentName),
18293
+ whenFalseArm: buildOuterArm(cond.whenFalse, wrap, loopParam, loopParamBindings, cond.slotId, profileComponentName),
18219
18294
  ...cond.readsPreamble && { readsPreamble: true }
18220
18295
  });
18221
18296
  }
@@ -18227,7 +18302,7 @@ function buildReactiveEffectsPlan(args) {
18227
18302
  profileComponentName
18228
18303
  };
18229
18304
  }
18230
- function buildOuterArm(branch, wrap, loopParam, loopParamBindings, profileComponentName) {
18305
+ function buildOuterArm(branch, wrap, loopParam, loopParamBindings, condSlotId, profileComponentName) {
18231
18306
  return {
18232
18307
  events: buildBranchEventBindingsPlan({
18233
18308
  events: branch.events,
@@ -18241,6 +18316,7 @@ function buildOuterArm(branch, wrap, loopParam, loopParamBindings, profileCompon
18241
18316
  innerLoops: buildBranchInnerLoopsPlan({
18242
18317
  innerLoops: branch.innerLoops,
18243
18318
  scopeVar: "__branchScope",
18319
+ condSlotId,
18244
18320
  outerLoopParam: loopParam,
18245
18321
  outerLoopParamBindings: loopParamBindings,
18246
18322
  wrapOuter: wrap
@@ -18342,6 +18418,7 @@ function buildInnerLoopsPlan(args) {
18342
18418
  }
18343
18419
  function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, outerLoopParamBindings) {
18344
18420
  const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
18421
+ const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
18345
18422
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
18346
18423
  const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
18347
18424
  const wrapIRNode = (node) => {
@@ -18403,6 +18480,13 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
18403
18480
  }));
18404
18481
  }
18405
18482
  const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings);
18483
+ const conditionals = buildLoopChildConditionalsPlan({
18484
+ conditionals: inner.bindings.conditionals,
18485
+ scopeVar: `__innerEl${uidSuffix}`,
18486
+ wrap: wrapBoth,
18487
+ loopParam: inner.param,
18488
+ loopParamBindings: inner.paramBindings
18489
+ });
18406
18490
  return {
18407
18491
  mode: "reactive",
18408
18492
  keyFn: loopKeyFn(inner),
@@ -18415,6 +18499,7 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
18415
18499
  events,
18416
18500
  reactiveTexts,
18417
18501
  reactiveAttrs,
18502
+ conditionals,
18418
18503
  childRefs
18419
18504
  };
18420
18505
  }
@@ -19367,6 +19452,17 @@ function bindingIdArg(ctx, slotId) {
19367
19452
  return "";
19368
19453
  return `, ${JSON.stringify(`${ctx.componentName}#binding:${slotId}`)}`;
19369
19454
  }
19455
+ function emitValueUpdateStatements(target, expression) {
19456
+ return [
19457
+ `const __val = String(${expression})`,
19458
+ `if ('value' in ${target}) { if (${target}.value !== __val) ${target}.value = __val } else { ${target}.setAttribute('value', __val) }`
19459
+ ];
19460
+ }
19461
+ function emitChildValueMirrorStatements(target, expression) {
19462
+ return [
19463
+ `if ('value' in ${target}) { const __val = String(${expression}); if (${target}.value !== __val) ${target}.value = __val }`
19464
+ ];
19465
+ }
19370
19466
  function emitAttrUpdate(target, attrName, expression, meta) {
19371
19467
  const htmlName = toHTMLAttrName(attrName);
19372
19468
  if (attrName === "dangerouslySetInnerHTML" || htmlName === "dangerouslySetInnerHTML") {
@@ -19385,10 +19481,7 @@ function emitAttrUpdate(target, attrName, expression, meta) {
19385
19481
  ];
19386
19482
  }
19387
19483
  if (htmlName === "value") {
19388
- return [
19389
- `const __val = String(${expression})`,
19390
- `if (${target}.value !== __val) ${target}.value = __val`
19391
- ];
19484
+ return emitValueUpdateStatements(target, expression);
19392
19485
  }
19393
19486
  if (isBooleanAttr(htmlName)) {
19394
19487
  return [`${target}.${htmlName} = !!(${expression})`];
@@ -19636,30 +19729,30 @@ function emitReactivePropBindings(lines, ctx) {
19636
19729
  propsBySlot.get(prop.slotId).push(prop);
19637
19730
  }
19638
19731
  for (const [slotId, props] of propsBySlot) {
19639
- const v = varSlotId(slotId);
19640
- lines.push(` if (_${v}) {`);
19732
+ const ref = slotId === ctx.commentScopeRootSlotId ? "__scope" : `_${varSlotId(slotId)}`;
19733
+ lines.push(` if (${ref}) {`);
19641
19734
  for (const prop of props) {
19642
19735
  const value = `${prop.expression}()`;
19643
19736
  if (prop.propName === "selected") {
19644
19737
  if (prop.componentName === "TabsContent") {
19645
- lines.push(` _${v}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
19738
+ lines.push(` ${ref}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
19646
19739
  lines.push(` if (${value}) {`);
19647
- lines.push(` _${v}.classList.remove('hidden')`);
19740
+ lines.push(` ${ref}.classList.remove('hidden')`);
19648
19741
  lines.push(` } else {`);
19649
- lines.push(` _${v}.classList.add('hidden')`);
19742
+ lines.push(` ${ref}.classList.add('hidden')`);
19650
19743
  lines.push(` }`);
19651
19744
  } else {
19652
- lines.push(` _${v}.setAttribute('aria-selected', String(${value}))`);
19653
- lines.push(` _${v}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
19654
- lines.push(` _${v}.setAttribute('tabindex', ${value} ? '0' : '-1')`);
19745
+ lines.push(` ${ref}.setAttribute('aria-selected', String(${value}))`);
19746
+ lines.push(` ${ref}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
19747
+ lines.push(` ${ref}.setAttribute('tabindex', ${value} ? '0' : '-1')`);
19655
19748
  }
19656
19749
  } else if (prop.propName === "value") {
19657
- lines.push(` const __val = String(${value})`);
19658
- lines.push(` if (_${v}.value !== __val) _${v}.value = __val`);
19750
+ for (const stmt of emitChildValueMirrorStatements(ref, value))
19751
+ lines.push(` ${stmt}`);
19659
19752
  } else if (isBooleanAttr(prop.propName)) {
19660
- lines.push(` _${v}.${prop.propName} = !!(${value})`);
19753
+ lines.push(` ${ref}.${prop.propName} = !!(${value})`);
19661
19754
  } else {
19662
- lines.push(` _${v}.setAttribute('${prop.propName}', String(${value}))`);
19755
+ lines.push(` ${ref}.setAttribute('${prop.propName}', String(${value}))`);
19663
19756
  }
19664
19757
  }
19665
19758
  lines.push(` }`);
@@ -19682,13 +19775,17 @@ function emitReactiveChildProps(lines, ctx) {
19682
19775
  }
19683
19776
  for (const [, props] of propsByComponent) {
19684
19777
  const first = props[0];
19778
+ const isCommentRoot = first.slotId !== null && first.slotId === ctx.commentScopeRootSlotId;
19685
19779
  const varSuffix = first.slotId ? varSlotId(first.slotId).replace(/-/g, "_") : first.componentName;
19686
- const varName = `__${first.componentName}_${varSuffix}El`;
19687
- const selectorArg = first.slotId ? first.slotId : first.componentName;
19688
- lines.push(` const [${varName}] = $c(__scope, '${selectorArg}')`);
19780
+ const varName = isCommentRoot ? "__scope" : `__${first.componentName}_${varSuffix}El`;
19781
+ if (!isCommentRoot) {
19782
+ const selectorArg = first.slotId ? first.slotId : first.componentName;
19783
+ lines.push(` const [${varName}] = $c(__scope, '${selectorArg}')`);
19784
+ }
19689
19785
  lines.push(` if (${varName}) {`);
19690
19786
  for (const prop of props) {
19691
- for (const stmt of emitAttrUpdate(varName, prop.attrName, prop.expression, prop)) {
19787
+ const stmts = toHTMLAttrName(prop.attrName) === "value" ? emitChildValueMirrorStatements(varName, prop.expression) : emitAttrUpdate(varName, prop.attrName, prop.expression, prop);
19788
+ for (const stmt of stmts) {
19692
19789
  lines.push(` ${stmt}`);
19693
19790
  }
19694
19791
  }
@@ -20249,8 +20346,9 @@ function seedDiffersExpr(target, a) {
20249
20346
  return `${target}.getAttribute('style') !== styleToCss(__x)`;
20250
20347
  if (html === "class")
20251
20348
  return `${target}.getAttribute('class') !== (__x != null ? String(__x) : null)`;
20252
- if (html === "value")
20253
- return `${target}.value !== String(__x)`;
20349
+ if (html === "value") {
20350
+ return `('value' in ${target} ? ${target}.value !== String(__x) : ${target}.getAttribute('value') !== String(__x))`;
20351
+ }
20254
20352
  if (isBooleanAttr(html))
20255
20353
  return `${target}.${html} !== !!(__x)`;
20256
20354
  if (a.meta.presenceOrUndefined) {
@@ -20608,6 +20706,9 @@ function emitReactive(lines, inner, indent, pc) {
20608
20706
  }
20609
20707
  lines.push(`${indent} }${profileBindingId(pc, attr.slotId)}) }`);
20610
20708
  }
20709
+ if (emit.conditionals.length > 0) {
20710
+ stringifyLoopChildConditionals(lines, emit.conditionals, `${indent} `, pc);
20711
+ }
20611
20712
  emitLoopChildRefs(lines, emit.childRefs, {
20612
20713
  indent: `${indent} `,
20613
20714
  elVar: `__innerEl${uid}`,
@@ -21371,6 +21472,9 @@ function generateElementRefs(ctx) {
21371
21472
  for (const slotId of componentSlots) {
21372
21473
  regularSlots.delete(slotId);
21373
21474
  }
21475
+ if (ctx.commentScopeRootSlotId) {
21476
+ componentSlots.delete(ctx.commentScopeRootSlotId);
21477
+ }
21374
21478
  if (regularSlots.size === 0 && componentSlots.size === 0)
21375
21479
  return "";
21376
21480
  const refLines = [];
@@ -21856,6 +21960,7 @@ function createContext(ir, scope, adapterCapabilities, profile) {
21856
21960
  refElements: [],
21857
21961
  childInits: [],
21858
21962
  deferredChildSlots: new Set,
21963
+ commentScopeRootSlotId: ir.root.type === "component" ? ir.root.slotId : null,
21859
21964
  reactiveProps: [],
21860
21965
  reactiveChildProps: [],
21861
21966
  reactiveAttrs: [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/vite",
3
- "version": "0.33.0",
3
+ "version": "0.33.1",
4
4
  "description": "Vite plugin for BarefootJS: Vite/Rollup owns bundling, hashing, chunking, tree-shaking and minification of client assets, BarefootJS keeps only the JSX to (template, client JS) compile",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,17 +38,17 @@
38
38
  "directory": "packages/vite"
39
39
  },
40
40
  "dependencies": {
41
- "@barefootjs/shared": "0.33.0"
41
+ "@barefootjs/shared": "0.33.1"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@barefootjs/jsx": ">=0.2.0",
45
45
  "vite": "^6.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@barefootjs/client": "0.33.0",
49
- "@barefootjs/go-template": "0.33.0",
50
- "@barefootjs/hono": "0.33.0",
51
- "@barefootjs/jsx": "0.33.0",
48
+ "@barefootjs/client": "0.33.1",
49
+ "@barefootjs/go-template": "0.33.1",
50
+ "@barefootjs/hono": "0.33.1",
51
+ "@barefootjs/jsx": "0.33.1",
52
52
  "typescript": "^5.0.0",
53
53
  "vite": "^6.0.0"
54
54
  }