Skip to content

feat(Board): render a body BoardItemTitle in the item header - #113

Merged
agatha197 merged 2 commits into
mainfrom
fix/gh-111-board-render-a-body-boarditemt
Oct 28, 2026
Merged

agatha197 merged 2 commits into
mainfrom
fix/gh-111-board-render-a-body-boarditemt

Conversation

@lablup-octodog

Copy link
Copy Markdown
Contributor

Resolves #111

Summary

  • Board renders each item's header row and description through a small BoardItemBody, which provides an item context (BoardItemContext, internal) to the description.
  • When an item has no title, the first BoardItemTitle inside its description claims the header row and renders there through a portal: same .uic-board-item__title slot, so the same layout and drag-handle alignment as a title node. Further BoardItemTitles stay in the body, and the next one takes over if the first unmounts.
  • New inline prop on BoardItemTitle keeps it in the body (e.g. a second section title).
  • An item with neither a title nor a body title still renders no header row, so the content keeps the board's top padding.
  • New export useIsInBoardItem(): true inside an item's description, false elsewhere (including the title node).
  • A body title renders nothing until its claim settles (layout effect), so it mounts once, directly in its final place; it is never injected into items, so onItemsChange reports only what the consumer passed.
  • Component docs (Board, BoardItemTitle), a TitleInDescription story and a CHANGELOG entry (### Added). No new strings.

Why

Consumers that build a dashboard card once (title row with help tooltip and actions, plus body) currently have to pass a placeholder title, portal their title row into it, hide an empty header with selectors on Board's private .uic-board-item__* classes, and strip the placeholder back out of onItemsChange. That CSS breaks silently whenever Board's DOM changes. With this change the card just renders a BoardItemTitle in its body and Board places it (#108). backend.ai-webui picks this up with the next @lablup/ui-common release and can then drop that workaround.

Test plan

  • src/components/Board/Board.test.tsx → "Board item context": the hook is true only in the description; a body title renders in the header of an untitled item (heading, actions, nothing left in the body); it stays in the body when the item has a title or it is inline; only the first moves and the next takes over; the header row goes away with the title (also under StrictMode); moving items keeps one row, mounted once.
  • src/components/BoardItemTitle/BoardItemTitle.test.tsx: renders in place outside a board, inline or not.
  • Storybook: Components/Board → Title In Description. Each card's title row is in the header, on the drag handle's line; the "Details" title stays in the body (inline); move and resize items and check the rows don't duplicate.

Verification

dist/components/Board/Board2.js                                    20.48 kB │ gzip: 6.60 kB │ map: 63.16 kB
dist/index.js                                                      32.14 kB │ gzip: 8.94 kB

✓ built in 6.21s

$ node scripts/check-pack.mjs
Packed artifact clean: @lablup/ui-common 1181 file(s), 169 export path(s) resolve; @lablup/ui-common-cli 52 file(s), bin and imports resolve.
$ node scripts/check-integration.mjs && astryx integration verify
check:integration: @lablup/ui-common@0.2.0-alpha.20 validates with 0 errors, 0 warnings (72 docs type-checked)
Integration package ready

[ok] @lablup/ui-common@0.2.0-alpha.20

1181 packed files; 144/144 required files present.

Content that draws its own title row had to pass a placeholder title,
portal itself into it and hide an empty header through Board's private
classes. A Board item now gives its description an item context: when
the item has no title, the first BoardItemTitle in it renders in the
header row (inline keeps one in the body), and useIsInBoardItem() tells
content it is padded by the board.
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

GitHub Pages may take up to a minute to hydrate after the deploy.

🧩 Changed Components

Component Changed Stories Open
Board source + stories 8 Storybook ↗
BoardItemTitle source 4 Storybook ↗
1 other changed file(s) in src/
  • src/index.ts

📦 Bundle Size

Group Gzip Δ Gzip vs base
components/Board 12.4 kB +0.4 kB
index.js 8.7 kB +0.0 kB
components/BoardItemTitle 0.8 kB +0.2 kB

Total gzip (JS + CSS): 197.8 kB (+0.7 kB vs origin/main)


Generated by the PR Preview workflow for c2a5532 · Storybook · CI run

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Preview published under the pr-113 dist-tag (npmjs): 0.2.0-alpha.20.pr-113-20261028080932-c2a55328f

pnpm add @lablup/ui-common@0.2.0-alpha.20.pr-113-20261028080932-c2a55328f
pnpm add -D @lablup/ui-common-cli@0.2.0-alpha.20.pr-113-20261028080932-c2a55328f

In backend.ai-webui: pnpm run ui-common:pin pr-113. A consumer PR pinned to a preview cannot merge; repin to canary after this PR merges.

Clear the item context around an item's title node, so a Board nested in another item's description keeps its items' titles in their own header rows instead of claiming the outer item's header. Adds a test.
@lablup-octodog

Copy link
Copy Markdown
Contributor Author

Ready gate review — round 1

Reviewed 22c6c2b against main. Copilot was not run.

# Tag File:line Finding Outcome
O1 Important src/components/Board/Board.tsx:1222 The header row's title node rendered inside the surrounding item context. When a Board is nested in another untitled item's description, a BoardItemTitle used as a nested item's title claimed the outer item's header and moved there through a portal, so the outer item showed two header rows and the nested item lost its title. It also made useIsInBoardItem() return true in that title node, though the docs say it is false there. fixed c2a5532: the title node now renders under BoardItemContext.Provider value={null}; new test "keeps a nested board's item title in its own item" (fails without the fix).

The fix landed after this review and was not re-reviewed (5 changed lines in Board.tsx, plus a test). pnpm run verify passes at c2a5532.

@lablup-octodog
lablup-octodog marked this pull request as ready for review October 28, 2026 08:09
github-actions Bot added a commit that referenced this pull request Oct 28, 2026
@agatha197
agatha197 merged commit e3c2624 into main Oct 28, 2026
10 checks passed
agatha197 added a commit to lablup/backend.ai-webui that referenced this pull request Oct 28, 2026
…ommon now covers

Pin @lablup/ui-common to 0.2.0-alpha.20.canary-20261028082256-e3c262420,
which carries lablup/ui-common#113 (a body BoardItemTitle renders in the
item header, useIsInBoardItem) and lablup/ui-common#116 (the DataGrid
page-size list flips above near the viewport bottom).

- BAIBoard passes data.content as the description only; the title-slot
  portal, its :empty header CSS and the title stripping in onItemsChange go.
- BAIBoardItemTitle renders ui-common BoardItemTitle as is; a second
  section title takes `inline` instead of BAIBoardItemInlineTitles.
- useIsInBAIBoardItem stays as an alias of ui-common useIsInBoardItem.
- BAITable.css, the page-size margin override, is deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
release — c2a55328 Deployed Oct 28, 2026 by lablup-octodog via npmjs #96
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Board: render a body BoardItemTitle in the item header and add useIsInBoardItem

2 participants