fix: header row spans work now - #6485
Conversation
|
View your CI Pipeline Execution β for commit 2e7d106
βοΈ Nx Cloud last updated this comment at |
π WalkthroughWalkthroughThe change implements placeholder-chain ChangesHeader row-span behavior
Spreadsheet header stability
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant TableColumns
participant HeaderGroupBuilder
participant FlexRender
participant FrameworkExample
TableColumns->>HeaderGroupBuilder: build grouped headers
HeaderGroupBuilder->>FrameworkExample: provide rowSpan and placeholder metadata
FrameworkExample->>FlexRender: render header context
FlexRender->>FrameworkExample: return configured header content
FrameworkExample->>FrameworkExample: omit zero-span headers and apply spans
Possibly related PRs
π₯ Pre-merge checks | β 4 | β 1β Failed checks (1 warning)
β Passed checks (4 passed)
β¨ Finishing Touches π‘ 1π Generate docstrings π‘
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (1)
packages/table-core/src/flex-render.ts (1)
83-91: ποΈ Data Integrity & Integration | π Major | ποΈ Heavy liftPlaceholder suppression moved from the adapters to the caller. All three sites remove the placeholder short-circuit so that a spanning placeholder can render its column's header content for
rowSpanmerging. The shared consequence is a public-API behavior change: any existing caller without anisPlaceholderguard now renders duplicated header or footer text.
packages/table-core/src/flex-render.ts#L83-L91: add a migration note for theheader/footerplaceholder behavior change, and confirm every call site in the repository guards onisPlaceholderorrowSpan.packages/ember-table/src/FlexRender.gts#L170-L178: confirm the Ember header-group example and integration tests wrapFlexRenderHeaderin{{#unlessheader.isPlaceholder}}where the empty-cell pattern is intended.packages/ember-table/src/FlexRender.gts#L245-L250: apply the same template guard forFlexRenderFooter, because footer groups render in reverse order and cannot use therowSpanpattern.π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/table-core/src/flex-render.ts` around lines 83 - 91, Document the public placeholder-rendering change in packages/table-core/src/flex-render.ts#L83-L91 with a migration note, and verify repository call sites guard rendering with isPlaceholder or rowSpan. In packages/ember-table/src/FlexRender.gts#L170-L178, ensure the header-group example and integration tests use an unless header.isPlaceholder guard where empty cells are intended. In packages/ember-table/src/FlexRender.gts#L245-L250, add the equivalent guard for FlexRenderFooter, preserving footer rendering order and preventing duplicated placeholder text.
π§Ή Nitpick comments (3)
examples/lit/header-groups/tests/e2e/smoke.spec.ts (1)
290-290: π Maintainability & Code Quality | π΅ Trivial | β‘ Quick winRename the row-span test, because it targets the fourth table. Each title says "in the second table", but the body uses
rowSpanTable, which ispage.locator('table').nth(3). The shared root cause is a copied title. Rename each title to name the row-span table, for example "spans shallow leaf headers across rows in the row-span table".
examples/lit/header-groups/tests/e2e/smoke.spec.ts#L290-L290: rename the title.examples/octane/header-groups/tests/e2e/smoke.spec.ts#L291-L291: rename the title.examples/preact/header-groups/tests/e2e/smoke.spec.ts#L291-L291: rename the title.examples/react/header-groups/tests/e2e/smoke.spec.ts#L291-L291: rename the title.examples/solid/header-groups/tests/e2e/smoke.spec.ts#L290-L290: rename the title.examples/svelte/header-groups/tests/e2e/smoke.spec.ts#L290-L290: rename the title.π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/lit/header-groups/tests/e2e/smoke.spec.ts` at line 290, Rename the row-span test title from βin the second tableβ to βin the row-span tableβ in the smoke.spec.ts files for Lit (line 290), Octane (line 291), Preact (line 291), React (line 291), Solid (line 290), and Svelte (line 290); update only the test descriptions, leaving the rowSpanTable test logic unchanged.examples/angular/header-groups/src/app/app.ts (1)
209-223: π Performance & Scalability | π΅ Trivial | π€ Low valueConsider
computed()for the derived template values.
basicFooterGroups()andstringifiedState()run on every change-detection cycle, andbasicFooterGroups()returns a new array identity each call. Acomputed()signal caches the result and keeps the identity stable between data changes.β»οΈ Proposed refactor
- stringifiedState() { - return JSON.stringify(this.table.store.get(), null, 2) - } + readonly stringifiedState = computed(() => + JSON.stringify(this.table.store.get(), null, 2), + ) // Only the leaf columns declare footers, so skip the group row instead of // rendering a blank one. - basicFooterGroups() { - return this.basicTable - .getFooterGroups() - .filter((footerGroup) => - footerGroup.headers.some( - (header) => !header.isPlaceholder && header.column.columnDef.footer, - ), - ) - } + readonly basicFooterGroups = computed(() => + this.basicTable + .getFooterGroups() + .filter((footerGroup) => + footerGroup.headers.some( + (header) => !header.isPlaceholder && header.column.columnDef.footer, + ), + ), + )This also requires updating the template call sites and importing
computedfrom@angular/core.π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/angular/header-groups/src/app/app.ts` around lines 209 - 223, Convert the derived template values in AppComponent, specifically stringifiedState() and basicFooterGroups(), to Angular computed signals so their results are cached and basicFooterGroups retains a stable array identity between data changes. Import computed from `@angular/core`, define the computed values from the existing table state, and update all template call sites to read the signals without invoking methods.examples/svelte/header-groups/src/App.svelte (1)
210-210: π Maintainability & Code Quality | π΅ Trivial | π€ Low valueUse lowercase HTML attributes for table col/row spans.
colSpanandrowSpanwork, but<th>is standard HTML markup, so use the canonical lowercasecolspanandrowspanatexamples/svelte/header-groups/src/App.svelte:210,236,255,283,307,327.π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/svelte/header-groups/src/App.svelte` at line 210, Update the table header markup in App.svelte to use lowercase colspan and rowspan attributes at all referenced <th> elements, replacing the camelCase colSpan and rowSpan forms while preserving their existing values and behavior.
π€ Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/octane/header-groups/tests/e2e/smoke.spec.ts`:
- Line 243: Reconcile the headerRow/footerRow expectations in the header-groups
smoke tests with the source examples, which use the first placeholder group as
header βNameβ with a footer. Update
examples/octane/header-groups/tests/e2e/smoke.spec.ts lines 243 and 285,
examples/preact/header-groups/tests/e2e/smoke.spec.ts lines 243 and 285,
examples/react/header-groups/tests/e2e/smoke.spec.ts lines 243 and 285, and
examples/lit/header-groups/tests/e2e/smoke.spec.ts,
examples/solid/header-groups/tests/e2e/smoke.spec.ts, and
examples/svelte/header-groups/tests/e2e/smoke.spec.ts at line 255 to expect the
actual Name/footer data, including any related comments; alternatively, update
the corresponding source examples consistently if the Hello/missing-footer
behavior is intended.
In `@packages/table-core/src/core/headers/buildHeaderGroups.ts`:
- Around line 197-226: Update all nine header-group examples that render
rowSpan={header.rowSpan} to skip rendering when header.rowSpan === 0, while
preserving the existing rowSpan value for visible headers. Use the established
example rendering pattern and leave the buildHeaderGroups chain calculation
unchanged.
---
Outside diff comments:
In `@packages/table-core/src/flex-render.ts`:
- Around line 83-91: Document the public placeholder-rendering change in
packages/table-core/src/flex-render.ts#L83-L91 with a migration note, and verify
repository call sites guard rendering with isPlaceholder or rowSpan. In
packages/ember-table/src/FlexRender.gts#L170-L178, ensure the header-group
example and integration tests use an unless header.isPlaceholder guard where
empty cells are intended. In packages/ember-table/src/FlexRender.gts#L245-L250,
add the equivalent guard for FlexRenderFooter, preserving footer rendering order
and preventing duplicated placeholder text.
---
Nitpick comments:
In `@examples/angular/header-groups/src/app/app.ts`:
- Around line 209-223: Convert the derived template values in AppComponent,
specifically stringifiedState() and basicFooterGroups(), to Angular computed
signals so their results are cached and basicFooterGroups retains a stable array
identity between data changes. Import computed from `@angular/core`, define the
computed values from the existing table state, and update all template call
sites to read the signals without invoking methods.
In `@examples/lit/header-groups/tests/e2e/smoke.spec.ts`:
- Line 290: Rename the row-span test title from βin the second tableβ to βin the
row-span tableβ in the smoke.spec.ts files for Lit (line 290), Octane (line
291), Preact (line 291), React (line 291), Solid (line 290), and Svelte (line
290); update only the test descriptions, leaving the rowSpanTable test logic
unchanged.
In `@examples/svelte/header-groups/src/App.svelte`:
- Line 210: Update the table header markup in App.svelte to use lowercase
colspan and rowspan attributes at all referenced <th> elements, replacing the
camelCase colSpan and rowSpan forms while preserving their existing values and
behavior.
πͺ Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
βΉοΈ Review info
βοΈ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: fe9faf56-edd0-4259-9830-5453337c1ed9
π Files selected for processing (40)
docs/guide/headers.mdexamples/alpine/header-groups/index.htmlexamples/alpine/header-groups/src/index.cssexamples/alpine/header-groups/src/main.tsexamples/alpine/header-groups/tests/e2e/smoke.spec.tsexamples/angular/header-groups/src/app/app.htmlexamples/angular/header-groups/src/app/app.tsexamples/angular/header-groups/src/styles.cssexamples/angular/header-groups/tests/e2e/smoke.spec.tsexamples/ember/header-groups/app/app.cssexamples/ember/header-groups/app/templates/application.gtsexamples/ember/header-groups/tests/e2e/smoke.spec.tsexamples/lit/header-groups/src/main.tsexamples/lit/header-groups/tests/e2e/smoke.spec.tsexamples/octane/header-groups/src/index.cssexamples/octane/header-groups/src/main.tsrxexamples/octane/header-groups/tests/e2e/smoke.spec.tsexamples/preact/header-groups/src/index.cssexamples/preact/header-groups/src/main.tsxexamples/preact/header-groups/tests/e2e/smoke.spec.tsexamples/react/header-groups/src/index.cssexamples/react/header-groups/src/main.tsxexamples/react/header-groups/tests/e2e/smoke.spec.tsexamples/solid/header-groups/src/App.tsxexamples/solid/header-groups/src/index.cssexamples/solid/header-groups/tests/e2e/smoke.spec.tsexamples/solid/spreadsheet/src/SpreadsheetGrid.tsxexamples/svelte/header-groups/src/App.svelteexamples/svelte/header-groups/src/index.cssexamples/svelte/header-groups/tests/e2e/smoke.spec.tsexamples/vue/header-groups/src/App.tsxexamples/vue/header-groups/src/index.cssexamples/vue/header-groups/tests/e2e/smoke.spec.tspackages/ember-table/src/FlexRender.gtspackages/ember-table/tests/integration/flex-render.test.gtspackages/table-core/src/core/headers/buildHeaderGroups.tspackages/table-core/src/core/headers/coreHeadersFeature.types.tspackages/table-core/src/flex-render.tspackages/table-core/tests/unit/core/headers/coreHeadersFeature.utils.test.tspackages/table-core/tests/unit/flex-render.test.ts
| await expect(table.locator('thead tr')).toHaveCount(3) | ||
|
|
||
| await expect(headerRow(page, 0)).toHaveText(['Hello', 'Info']) | ||
| await expect(headerRow(table, 0)).toHaveText(['Hello', 'Info']) |
There was a problem hiding this comment.
π― Functional Correctness | π‘ Minor | β‘ Quick win
π§© Analysis chain
π Script executed:
#!/bin/bash
# Description: Compare the first group header and footer labels in every header-groups example source.
set -euo pipefail
fd -t f -e ts -e tsx -e svelte -e gts -e html . examples --full-path 'header-groups' \
| rg -v '/tests/' | while IFS= read -r file; do
if rg -q "Hello|'Name'|\"Name\"|More Info" "$file"; then
echo "=== $file ==="
rg -n -C 3 "header:|footer:|Hello|More Info" "$file"
fi
doneRepository: TanStack/table
Length of output: 50371
π Script executed:
#!/bin/bash
set -euo pipefail
echo "=== header-groups example source first groups ==="
for base in examples/octane examples/preact examples/react examples/lit examples/solid examples/svelte; do
echo "--- $base/header-groups/src"
file="$(find "$base/header-groups/src" -maxdepth 1 -type f | sort | head -n 5 | tr '\n' ' ')"
rg -n -C 4 "group\\({|header:|footer:|defaultColumns|Hello|Name|Info|More Info" "$base/header-groups/src" || true
done
echo
echo "=== header-groups E2E expectations around first group/footer ==="
for f in examples/octane/header-groups/tests/e2e/smoke.spec.ts examples/preact/header-groups/tests/e2e/smoke.spec.ts examples/react/header-groups/tests/e2e/smoke.spec.ts; do
echo "--- $f"
sed -n '220,300p' "$f"
done
for f in examples/lit/header-groups/tests/e2e/smoke.spec.ts examples/solid/header-groups/tests/e2e/smoke.spec.ts examples/svelte/header-groups/tests/e2e/smoke.spec.ts; do
echo "--- $f"
sed -n '235,300p' "$f"
done
echo
echo "=== all header-groups example files containing placeholder tables ==="
rg -n "columns = columnHelper.columns|const columns|defaultColumns|Hello|footer:\\s*\\(" examples/octane/header-groups/src examples/preact/header-groups/src examples/react/header-groups/src examples/lit/header-groups/src examples/solid/header-groups/src examples/svelte/header-groups/srcRepository: TanStack/table
Length of output: 23641
Reconcile the header group expectations with each example. Most header-groups examples define the first placeholder group as header: 'Name' with a footer, so the "Hello"/missing-footer expectations in octane, preact, and react diverge from the current sources. Either update those source examples to match the tests, or update the expectations/comments to match the Name placeholder data.
π Affects 6 files
examples/octane/header-groups/tests/e2e/smoke.spec.ts#L243-L243(this comment)examples/octane/header-groups/tests/e2e/smoke.spec.ts#L285-L285examples/preact/header-groups/tests/e2e/smoke.spec.ts#L243-L243examples/preact/header-groups/tests/e2e/smoke.spec.ts#L285-L285examples/react/header-groups/tests/e2e/smoke.spec.ts#L243-L243examples/react/header-groups/tests/e2e/smoke.spec.ts#L285-L285examples/lit/header-groups/tests/e2e/smoke.spec.ts#L255-L255examples/solid/header-groups/tests/e2e/smoke.spec.ts#L255-L255examples/svelte/header-groups/tests/e2e/smoke.spec.ts#L255-L255
π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/octane/header-groups/tests/e2e/smoke.spec.ts` at line 243, Reconcile
the headerRow/footerRow expectations in the header-groups smoke tests with the
source examples, which use the first placeholder group as header βNameβ with a
footer. Update examples/octane/header-groups/tests/e2e/smoke.spec.ts lines 243
and 285, examples/preact/header-groups/tests/e2e/smoke.spec.ts lines 243 and
285, examples/react/header-groups/tests/e2e/smoke.spec.ts lines 243 and 285, and
examples/lit/header-groups/tests/e2e/smoke.spec.ts,
examples/solid/header-groups/tests/e2e/smoke.spec.ts, and
examples/svelte/header-groups/tests/e2e/smoke.spec.ts at line 255 to expect the
actual Name/footer data, including any related comments; alternatively, update
the corresponding source examples consistently if the Hello/missing-footer
behavior is intended.
|
|
||
| // A shallow leaf column produces a chain of same-column headers: the | ||
| // placeholder at the column's own depth, more placeholders below it, and | ||
| // the real leaf header in the bottom row. The top of the chain carries the | ||
| // full rowSpan and renders the column's header content when merging | ||
| // vertically; every header it covers gets a rowSpan of 0 so rowSpan-aware | ||
| // renderers can skip it. All other headers span a single row. | ||
| if ( | ||
| header.isPlaceholder && | ||
| header.subHeaders.length === 1 && | ||
| header.subHeaders[0]!.column === header.column | ||
| ) { | ||
| let rowSpan = 1 | ||
| let chainChild: Header<TFeatures, TData, TValue> | undefined = | ||
| header.subHeaders[0] | ||
| while (chainChild) { | ||
| chainChild.rowSpan = 0 | ||
| rowSpan++ | ||
| chainChild = | ||
| chainChild.subHeaders.length === 1 && | ||
| chainChild.subHeaders[0]!.column === header.column | ||
| ? chainChild.subHeaders[0] | ||
| : undefined | ||
| } | ||
| header.rowSpan = rowSpan | ||
| } else { | ||
| // Chain members are visited before their chain top, so this default is | ||
| // overwritten with 0 when the chain top claims them. | ||
| header.rowSpan = 1 | ||
| } |
There was a problem hiding this comment.
ποΈ Data Integrity & Integration | π‘ Minor | β‘ Quick win
π§© Analysis chain
π Script executed:
#!/bin/bash
# Find every site that renders a header rowSpan, then inspect for a `rowSpan === 0` guard.
set -uo pipefail
echo "=== JSX/HTML rowspan attribute bindings ==="
rg -nP -C5 '\browSpan\s*=\s*\{|rowspan\s*=\s*("\$\{|\{\{)' \
-g '!**/node_modules/**' -g '!**/dist/**' || true
echo "=== All reads of .rowSpan ==="
rg -nP -C3 '\.rowSpan\b' \
-g '!**/node_modules/**' -g '!**/dist/**' || trueRepository: TanStack/table
Length of output: 196
π Script executed:
#!/bin/bash
set -uo pipefail
echo "=== Candidate files containing rowSpan attribute/type usage ==="
rg -n -C3 '\browSpan\b|rowspan\b|headerSpan|header\.rowSpan' \
-g '!**/node_modules/**' -g '!**/dist/**' -g '!**/.vite/**' -g '!**/coverage/**' . || true
echo "=== Files likely related to header rendering in core/tests/packages ==="
git ls-files | rg '(^docs/|^examples/|^packages/.*core/.*header|^packages/.*core/.*thead|^packages/.*react/.*thead|^packages/.*vue/.*thead|^packages/.*svelte/.*thead|^packages/.*solid/.*thead|^packages/.*preact/.*thead)' || trueRepository: TanStack/table
Length of output: 50371
π Script executed:
#!/bin/bash
set -uo pipefail
echo "=== focused head/header matches in tracked TS/TSX/JS/JSX/MDX ==="
python3 - <<'PY'
import subprocess
out=subprocess.check_output(['git','ls-files'],encoding='utf8')
files=out.splitlines()
patterns=['*.*tsx','*.*ts','*.*js','*.*jsx','*.mdx']
def globmatch(path):
import fnmatch
return any(fnmatch.fnmatch(path.lower(), pat.lower()) for pat in patterns)
matches=[]
for path in files:
if not globmatch(path):
continue
try:
text=open(path,encoding='utf8',errors='ignore').read()
except Exception:
continue
if 'rowSpan' in text or 'rowspan' in text or 'columnGroupHeaderFn' in text or 'headerGroups' in text or 'thead' in text or 'TableHead' in text or 'Header' in text:
matches.append(path)
print('\n'.join(matches))
PY
echo "=== focused rowSpan and attribute-string cases ==="
rg -n -C2 'rowSpan\s*=\s*\{|rowspan\s*=\s*("\$\{|\{\{)|rowspan="0"|rowSpan={0}|\.rowSpan\b' \
-g '*.tsx' -g '*.ts' -g '*.jsx' -g '*.js' -g '*.mdx' \
-g '!**/node_modules/**' -g '!**/dist/**' . || trueRepository: TanStack/table
Length of output: 50370
π Script executed:
#!/bin/bash
set -eo pipefail
echo "=== files containing literal rowspan="0" or rowSpan={0}") ==="
python3 - <<'PY' \
-g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' -g '*.gts' -g '*.gjs' -iglob '*.gts' -iglob '*.gjs' -iglob '*.svelte' .
import subprocess, re
text=subprocess.check_output(['git','grep','-E','rowSpan=\{0\}|rowspan="0"|rowspan=\'0\''], encoding='utf8')
print(text if text else "NO MATCHES")
PY
echo "=== actual rowSpan attribute render lines in tracked examples/packages docs with attribute context ==="
python3 - <<'PY'
import subprocess, pathlib, fnmatch
files = subprocess.check_output(['git','ls-files'], text=True).splitlines()
pats = ['*.ts','*.tsx','*.js','*.jsx','*.gts','*.gjs','*.svelte','*.mdx','*.html','*.vue','*.astro']
needles = ['rowSpan=', 'rowspan=', 'header.rowSpan', 'rowSpan']
for p in files:
if not any(fnmatch.fnmatchcase(p.lower(), pp.lower()) for pp in pats):
continue
txt = pathlib.Path(p).read_text(errors='ignore')
if not any(n in txt for n in needles):
continue
for i,line in enumerate(txt.splitlines(),1):
if 'rowSpan=' in line or 'rowspan=' in line:
print(f"{p}:{i}: {line.strip()}")
PYRepository: TanStack/table
Length of output: 205
π Script executed:
#!/bin/bash
set -eo pipefail
echo "=== files containing literal rowspan="0" or rowSpan={0}") ==="
python3 - <<'PY'
import subprocess
try:
text=subprocess.check_output(['git','grep','-E','rowSpan=\{0\}|rowspan="0"|rowspan='\''0'\''''], encoding='utf8')
print(text if text else "NO MATCHES")
except subprocess.CalledProcessError as e:
print(f"NO_MATCHES_EXIT_CODE={e.returncode}")
PY
echo "=== actual rowSpan attribute render lines in tracked examples/packages/docs with attribute context ==="
python3 - <<'PY'
import subprocess, pathlib, fnmatch
files = subprocess.check_output(['git','ls-files'], text=True).splitlines()
pats = ['*.ts','*.tsx','*.js','*.jsx','*.gts','*.gjs','*.svelte','*.mdx','*.html','*.vue','*.astro']
for p in files:
if not any(fnmatch.fnmatchcase(p.lower(), pp.lower()) for pp in pats):
continue
txt = pathlib.Path(p).read_text(errors='ignore')
if 'rowSpan=' not in txt and 'rowspan=' not in txt:
continue
for i,line in enumerate(txt.splitlines(),1):
if 'rowSpan=' in line or 'rowspan=' in line:
print(f"{p}:{i}: {line.strip()}")
PYRepository: TanStack/table
Length of output: 205
π Script executed:
#!/bin/bash
set -eo pipefail
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
echo "=== write search script ==="
cat > "$tmp/search_rowspan.py" <<'PY'
import subprocess, pathlib, fnmatch
files = subprocess.check_output(['git', 'ls-files'], text=True).splitlines()
pats = ['*.ts','*.tsx','*.js','*.jsx','*.gts','*.gjs','*.svelte','*.mdx','*.html','*.vue','*.astro']
attrs = set()
literal_zero = []
for p in files:
if not any(fnmatch.fnmatchcase(p.lower(), pp.lower()) for pp in pats):
continue
txt = pathlib.Path(p).read_text(errors='ignore')
if 'rowSpan=' not in txt and 'rowspan=' not in txt:
continue
attrs.add(p)
for line in txt.splitlines():
if 'rowSpan=' in line or 'rowspan=' in line:
if 'rowSpan={0}' in line or 'rowspan="0"' in line or "rowspan='0'" in line:
literal_zero.append((p, line.strip()))
print(f"{p}: {line.strip()[:400]}")
print("ATTRIBUTE_FILES=", len(attrs))
print("LITERAL_ZERO_COUNT=", len(literal_zero))
for p,line in literal_zero:
print("LITERAL_ZERO:", p, line)
PY
python3 "$tmp/search_rowspan.py"Repository: TanStack/table
Length of output: 907
Add the rowSpan === 0 skip to the existing rowSpan={header.rowSpan} examples.
Nine header-group examples currently render rowSpan directly, so they will emit rowspan="0" for covered placeholder headers. Add the skip pattern there to keep example markup consistent with the new covered-header contract.
π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/table-core/src/core/headers/buildHeaderGroups.ts` around lines 197 -
226, Update all nine header-group examples that render rowSpan={header.rowSpan}
to skip rendering when header.rowSpan === 0, while preserving the existing
rowSpan value for visible headers. Use the established example rendering pattern
and leave the buildHeaderGroups chain calculation unchanged.
π― Changes
β Checklist
pnpm test:pr.Summary by CodeRabbit
New Features
Bug Fixes
Documentation