Skip to content

feat(quick): Add Card and Box container builder#1284

Open
RajSurajR wants to merge 6 commits into
Karanjot786:mainfrom
RajSurajR:feat/add-card-and-box-container-builder
Open

feat(quick): Add Card and Box container builder#1284
RajSurajR wants to merge 6 commits into
Karanjot786:mainfrom
RajSurajR:feat/add-card-and-box-container-builder

Conversation

@RajSurajR

@RajSurajR RajSurajR commented Jun 10, 2026

Copy link
Copy Markdown

Description

This PR introduces the card() and box() container builders to the @termuijs/quick package. The card() function generates a padded widget featuring a custom title embedded within its top border frame, whereas the box() function serves as a minimalist, thin-bordered utility wrapper for child layouts.

Related Issue

Closes #512

Which package(s)?

@termuijs/quick (packages/quick)

Type of Change

  • 🐛 Bug fix (type:bug)
  • ✨ Feature (type:feature)
  • 📝 Docs (type:docs)
  • 🧪 Tests (type:testing)
  • ♻️ Refactor (type:refactor)
  • 🎨 Design / UX (type:design)
  • ♿ Accessibility (type:accessibility)
  • ⚡ Performance (type:performance)
  • 🔧 DevOps / CI (type:devops)
  • 🔒 Security (type:security)

Checklist

  • ⭐ You starred the repo. The needs-star check blocks your merge otherwise.
  • Tests pass locally: bun vitest run
  • Build passes: bun run build
  • Typecheck passes: bun run typecheck
  • You read CONTRIBUTING.md.
  • Your PR title follows type: short description.
  • Widget state mutators call markDirty() (if your change affects rendering).
  • No new any types without an inline comment explaining why.
  • No unrelated refactors bundled into this PR.

GSSoC 2026 Participation

  • You are a GSSoC 2026 contributor.
  • Your GSSoC profile: https://gssoc.girlscript.org/profile/6c6b9500-52a8-4c78-84fb-97d5e17753e3

Screenshots / Recordings (UI changes)

Notes for the Reviewer

Summary by CodeRabbit

  • New Features

    • Added new card and box widget builders for simpler structured layout creation.
    • card supports an optional title; both widgets support optional border color customization (defaulting to brightBlack).
    • Updated the Quick public API to expose card/box and their option types (replacing the previous tabs/select shorthand exports).
  • Tests

    • Expanded rendering checks for card and box: export verification, child attachment, title rendering on card, and default border character styling.

@RajSurajR RajSurajR requested a review from Karanjot786 as a code owner June 10, 2026 13:35
@github-actions github-actions Bot added the type:testing +10 pts. Tests. label Jun 10, 2026
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds card() and box() shorthand builders to @termuijs/quick that wrap Card/Box with single borders (default brightBlack), attach provided children, export option types, update public exports, and add Vitest coverage for the new builders. Note: The PR currently contains unresolved merge-conflict markers in the index.ts export sections that must be resolved before merging.

Changes

Container Widget Builders

Layer / File(s) Summary
Core widget builders and types
packages/quick/src/widgets.ts
Imports Box and Card from @termuijs/widgets and adds QuickCardOptions (title?, borderColor?) and QuickBoxOptions (borderColor?) plus card(children, opts) and box(children, opts) that default borderColor to brightBlack and attach children via addChild. Card wraps internal _renderBorder to conditionally invoke _renderSelf with error swallowing.
Test validation for card and box
packages/quick/src/widgets.test.ts
Adds Screen import and new Vitest suites asserting card() and box() are exported functions, return Widget instances containing provided children, card forwards title into the border, and both default border color to brightBlack box-drawing characters when omitted.
Public API exports
packages/quick/src/index.ts
Re-exports card, box and the types QuickCardOptions, QuickBoxOptions from ./widgets.js. Current state contains unresolved merge-conflict markers (<<<<<<< HEAD / ======= / >>>>>>> upstream/main) in both export list sections.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Karanjot786/TermUI#716: Both PRs add/verify Card widget border rendering and title-related behavior (main PR via quick's card shorthand tests; retrieved PR via @termuijs/widgets Card.test.ts border/title assertions).

Suggested labels

gssoc:approved, level:intermediate

Suggested reviewers

  • Karanjot786

Poem

🐇
I hopped to the code with a grin,
Bordered boxes and cards tucked in,
Title on top, children inside,
BrightBlack borders softly applied,
Tests now guard my cozy win!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR contains unresolved merge conflict markers in packages/quick/src/index.ts that indicate incomplete conflict resolution, which is a blocking issue requiring resolution before merge. Resolve the merge conflicts in packages/quick/src/index.ts by removing the conflict markers (<<<<<<< HEAD, =======, >>>>>>> upstream/main) and selecting the correct final state for the exports.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(quick): Add Card and Box container builder' clearly summarizes the main change - adding two new container builder functions to the quick package.
Description check ✅ Passed The PR description follows the template with all required sections filled: Description, Related Issue (#512), Which package (@termuijs/quick), Type of Change (Feature), completed Checklist, GSSoC 2026 participation, and PR title format verified.
Linked Issues check ✅ Passed The PR implements the card() and box() functions with correct signatures, interfaces (QuickCardOptions, QuickBoxOptions), default brightBlack border color, and exports as specified in issue #512, with tests added verifying functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Thanks for your first PR to TermUI, @RajSurajR.

Before your PR merges:

  1. Star the repo. Required. The star-check job blocks your merge otherwise.
  2. ✅ All checks green: build, test, typecheck.
  3. 🏷 PR title follows type: short description. Example: fix: handle empty list.
  4. 🔗 Link your closing issue in the description.

GSSoC 2026 points come from labels after merge:

  • gssoc:approved. +50 base points.
  • level:beginner / intermediate / advanced / critical. +20 / +35 / +55 / +80.
  • quality:clean / exceptional. x 1.2 / x 1.5.
  • type:*. Stackable bonus.

Your reviewer responds within 48 hours. Ping @Karanjot786 on Discord for urgent help.

🚀 Welcome to the cohort.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/quick/src/widgets.ts (1)

501-515: 💤 Low value

Consider using property shorthand.

Line 507 uses borderColor: borderColor which can be shortened to just borderColor using ES6 property shorthand.

♻️ Suggested simplification
     const container = new Box({
         border: 'single',
-        borderColor: borderColor,
+        borderColor,
     });
🤖 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/quick/src/widgets.ts` around lines 501 - 515, The object passed to
the Box constructor uses the redundant key/value pair borderColor: borderColor;
update the box function to use ES6 property shorthand by replacing that pair
with just borderColor. Locate the box function (export function box) where a new
Box({ border: 'single', borderColor: borderColor }) is constructed and change it
to new Box({ border: 'single', borderColor }) so the variable declared above
(borderColor) is used via shorthand; no other behavior changes needed.
🤖 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 `@packages/quick/src/widgets.test.ts`:
- Around line 82-127: The tests in widgets.test.ts are asserting private fields
(_title, _borderColor, _style) instead of rendering and checking visible output;
update each spec that references card, box or text to import Screen from
`@termuijs/core`, create a Screen instance with appropriate width/height, call
widget.updateRect({x,y,width,height}) and widget.render(screen), then assert
observable output from the screen buffer (e.g., screen.getLine(lineIndex)
contains the title text or border characters and child text) rather than
inspecting internal properties; ensure you keep references to the same symbols
(card, box, text, Screen, updateRect, render, getLine) so tests remain focused
on rendered behavior.

---

Nitpick comments:
In `@packages/quick/src/widgets.ts`:
- Around line 501-515: The object passed to the Box constructor uses the
redundant key/value pair borderColor: borderColor; update the box function to
use ES6 property shorthand by replacing that pair with just borderColor. Locate
the box function (export function box) where a new Box({ border: 'single',
borderColor: borderColor }) is constructed and change it to new Box({ border:
'single', borderColor }) so the variable declared above (borderColor) is used
via shorthand; no other behavior changes needed.
🪄 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: 01cef2a5-b3f2-40b1-99a0-a128b2242b58

📥 Commits

Reviewing files that changed from the base of the PR and between 6baf572 and c700000.

📒 Files selected for processing (3)
  • packages/quick/src/index.ts
  • packages/quick/src/widgets.test.ts
  • packages/quick/src/widgets.ts

Comment thread packages/quick/src/widgets.test.ts
@RajSurajR RajSurajR changed the title Add Card and Box container builder feat: Add Card and Box container builder Jun 10, 2026
@github-actions github-actions Bot added the type:feature +10 pts. New feature. label Jun 10, 2026

@Karanjot786 Karanjot786 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review complete — CI is awaiting maintainer approval to run (fork workflow gate). Reviewing code only per policy.

Code looks good:

  • card() and box() builders follow the existing quick-widget pattern exactly
  • Both correctly delegate to Card and Box from @termuijs/widgets with proper constructor signatures
  • borderColor defaults to { type: 'named', name: 'brightBlack' } — consistent with the Color object type used across the codebase (not a string)
  • Both are exported from packages/quick/src/index.ts with their option types
  • Tests cover: instanceof Widget, children presence, title forwarding, and borderColor default — good coverage
  • No console.log, no new as any on public surface

Waiting on: CI green before merge. Once the workflow approval is granted and CI passes, this is ready to squash-merge.

@RajSurajR RajSurajR requested a review from Karanjot786 June 10, 2026 18:50
@RajSurajR

Copy link
Copy Markdown
Author

Hey @Karanjot786 PR #1284 is Open . is any problem in this PR.

@RajSurajR

Copy link
Copy Markdown
Author

Hey @Karanjot786 .
What happened ? Is there a problem with this PR #1284?
If any changes are required please let me know.

@Karanjot786 Karanjot786 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. There are issues to fix before this merges.

Issues:

  1. (widget as any)._field access in tests
    File: packages/quick/src/widgets.test.ts, lines 106, 112, 113, 126
    Problem: The tests access (w as any)._title and (w as any)._borderColor / (w as any)._style?.borderColor, which casts widget internals through any. This pattern is explicitly disallowed — it couples tests to private fields and will silently pass even if the implementation changes. The card() and box() builder tests should assert on observable behaviour (rendered output, children contents, or public style accessors) rather than private state.
    Fix: Drive assertions through the public API. For example, add a title getter to Card (it already stores the value for rendering) or assert that the rendered screen output contains the title string. For border colour, check the rendered cell attributes on a small screen rather than reading a private field.

  2. Missing build-and-test CI check
    The build-and-test and bench workflows did not run for this PR. This typically happens when the branch is too far behind main. Please rebase onto the latest main and push to trigger a full CI run before this can be reviewed further.
    Fix: git fetch origin && git rebase origin/main && git push --force-with-lease

Checklist:

  • Fix applied
  • Tests pass (bun vitest run)
  • PR title: type(scope): description

@Karanjot786 Karanjot786 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. There are issues to fix before this merges.

Issues:

  1. (widget as any)._field access in test file
    File: packages/quick/src/widgets.test.ts, lines ~104, ~109-110, ~125
    Problem: Tests access private widget internals via (w as any)._title, (w as any)._borderColor, and (w as any)._style casts. This is a project-level blocking rule — tests must not pierce widget encapsulation with as any to read private fields. It couples tests to implementation details that can change without notice.
    Fix: Assert behaviour through the public API instead. For the title, verify it appears in the rendered output (e.g. instance.toString() via @termuijs/testing). For border colour, expose a read-only public getter on Card/Box if the property needs to be observable, or simply trust that the style is applied by checking the rendered border character colour.

  2. CI is missing the build-and-test and bench workflow runs
    Problem: Only 4 checks ran (CodeRabbit, path-labels, star-check, title-labels). The build-and-test and bench jobs did not execute, which means the build and full test suite have not been validated against this branch.
    Fix: Push a new commit (even a no-op chore: trigger CI) to re-trigger all workflow runs and confirm the build passes.

Checklist:

  • Fix applied
  • Tests pass (bun vitest run)
  • PR title: type(scope): description

@RajSurajR RajSurajR changed the title feat: Add Card and Box container builder feat(quick): Add Card and Box container builder Jun 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@packages/quick/src/widgets.ts`:
- Around line 499-510: The monkey-patch code in the block starting with
origRenderBorder has three issues to fix. First, import the Screen type from
'`@termuijs/core`' if not already imported, and replace the screen parameter type
annotation of any with Screen type. Second, add explanatory comments for each
any cast on lines 500, 502, and 505 following the project's guidelines that
require comments explaining why any is necessary. Third, replace the silent
catch (_e) block that swallows all errors without logging or re-throwing with
proper error handling that at least logs the error to aid debugging, rather than
silently ignoring failures in _renderSelf. This ensures guideline compliance
while maintaining visibility into runtime issues.
🪄 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: 4d9a0c9d-d1e1-44ea-93d8-2ed8bcaef1e1

📥 Commits

Reviewing files that changed from the base of the PR and between 00c74a8 and d0151eb.

📒 Files selected for processing (2)
  • packages/quick/src/widgets.test.ts
  • packages/quick/src/widgets.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/quick/src/widgets.test.ts

Comment thread packages/quick/src/widgets.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@packages/quick/src/index.ts`:
- Around line 35-41: In packages/quick/src/index.ts, resolve two merge conflicts
by removing the git conflict markers and retaining all exports from both sides.
At lines 35-41, remove the conflict markers (<<<<<<< HEAD, =======, >>>>>>>
upstream/main) and keep all four widget shorthand exports: card, box, tabs, and
select. At lines 68-74, similarly remove the conflict markers and keep all four
type exports: QuickCardOptions, QuickBoxOptions, QuickTabsOptions, and
QuickSelectOptions. This will allow TypeScript to compile by merging both the
new exports from this PR and the existing upstream exports rather than choosing
one side or the other.
🪄 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: e6b86a63-b8f3-4a9b-9fd0-38048d14835e

📥 Commits

Reviewing files that changed from the base of the PR and between d0151eb and 4138760.

📒 Files selected for processing (3)
  • packages/quick/src/index.ts
  • packages/quick/src/widgets.test.ts
  • packages/quick/src/widgets.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/quick/src/widgets.ts
  • packages/quick/src/widgets.test.ts

Comment thread packages/quick/src/index.ts Outdated
@RajSurajR RajSurajR requested a review from Karanjot786 June 14, 2026 14:01

@Karanjot786 Karanjot786 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. There are issues to fix before this merges.

Issues:

  1. Private field access via as any in card() — monkey-patching _renderBorder and _renderSelf
    File: packages/quick/src/widgets.ts, lines ~467–479
    Problem: The block after c.addChild() reads and overwrites (c as any)._renderBorder and calls (c as any)._renderSelf, which are private internals of the Card widget. Accessing private fields through as any casts is a hard rule violation in this repo: it couples the builder tightly to implementation details that can change without notice, silently breaks if those methods are renamed/removed, and bypasses TypeScript's access guarantees. The swallowed catch (_e) {} also hides real rendering errors.
    Fix: Remove the entire monkey-patch block (the const origRenderBorder = ... through the closing }). If the Card widget requires additional configuration to render its title correctly, pass all needed options through the constructor arguments (already done above: { title: opts?.title, borderColor }) and let Card handle its own rendering. If Card's public API is insufficient, open a separate issue/PR to extend it rather than patching internals here.

  2. screen: any parameter in the monkey-patch closure
    File: packages/quick/src/widgets.ts, line ~472
    Problem: The anonymous function function (screen: any) inside the monkey-patch uses an untyped any parameter on what is effectively a public render method. Even if the surrounding block is removed (see #1), explicit any on method parameters in non-test source files is a BLOCKING violation.
    Fix: Resolved automatically by removing the monkey-patch block per issue #1.

Checklist before re-requesting review:

  • Remove the _renderBorder / _renderSelf monkey-patch block from card() entirely
  • Verify title still renders correctly in the test (bun vitest run packages/quick)
  • PR title follows format: type(scope): description

@Karanjot786 Karanjot786 added the quality:needs-work Needs changes before merge. label Jun 19, 2026
@Karanjot786

Copy link
Copy Markdown
Owner

Thanks for the contribution. There are issues to fix before this merges.

Issues:

  1. card() accesses and monkey-patches private methods _renderBorder and _renderSelf via (c as any) casts in production source (packages/quick/src/widgets.ts). No inline comment explains why, violating the project rule that as any on public methods requires justification. This also constitutes private field access bypassing the public API.
    File: packages/quick/src/widgets.ts
    Fix: Remove the _renderBorder monkey-patch entirely — it calls _renderSelf inside _renderBorder which would cause double-rendering and is architecturally wrong. If Card needs additional render logic, subclass Card or open a public hook in @termuijs/widgets instead. At minimum, if as any is kept for a workaround, add an inline comment per the project convention (e.g. // as any: Card has no public render hook; tracked in #XXX).

  2. The inner function assigned to (c as any)._renderBorder types its screen parameter as any (screen: any) without an inline justification comment.
    File: packages/quick/src/widgets.ts
    Fix: Import and use the Screen type from @termuijs/core instead of any, or add an inline justification comment if the type truly cannot be imported.

Checklist before re-requesting review:

  • All blocking issues fixed
  • Tests pass locally: bun vitest run
  • PR title follows: type(scope): description

@Karanjot786

Copy link
Copy Markdown
Owner

Two blocking issues:

  1. Private method monkey-patching: (c as any)._renderBorder in production code (packages/quick/src/widgets.ts)
    Fix: Extend the Widget class with class Card extends Widget { protected _renderBorder(screen: Screen) { ... } } instead of monkey-patching.

  2. screen: any parameter: Type the screen parameter as Screen from @termuijs/core.

Checklist:

  • Use class extension instead of (as any) monkey-patching
  • Type screen parameter properly
  • Tests pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

quality:needs-work Needs changes before merge. type:feature +10 pts. New feature. type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(quick): add card and box container builders

2 participants