Skip to content

feat(react): add Pagination, MetricCard, ConfirmationDialog and EmptyState primitives - #1265

Merged
p3ris0n merged 13 commits into
BCPathway:mainfrom
ykargeee-bit:feature/ui-kit-pagination-metriccard-confirmation-emptystate
Oct 18, 2026
Merged

p3ris0n merged 13 commits into
BCPathway:mainfrom
ykargeee-bit:feature/ui-kit-pagination-metriccard-confirmation-emptystate

Conversation

@ykargeee-bit

Copy link
Copy Markdown
Contributor

Summary Adds four accessible, dependency-free UI-kit primitives to @bc-forge/react, following the existing inline-styles-from-theme-tokens pattern established by Alert and Badge. - Pagination (#1165) ΓÇö previous/next controls, a windowed page list and a page-size . Exports getPageItems, which returns page numbers ascending with ull marking a run collapsed into an ellipsis. Prev/Next disable at the boundaries, and page inputs are clamped so onPageChange can never observe an out-of-range page. - MetricCard / MetricStatBox (#1166) ΓÇö title, large value, delta badge and subtitle. The sign of delta selects the success / danger / neutral tokens, and loading renders a skeleton with �ria-busy. �igint values are stringified rather than coerced through Number. - ConfirmationDialog (#1167) ΓÇö guards destructive actions (burn, revoke role). Confirm stays disabled until the acknowledgement gate passes: a checkbox in checkbox mode, or an exact case-insensitive match of confirmationKeyword in keyword mode. �usy locks both buttons and unbinds Escape so an in-flight transaction cannot be dismissed. Self-contained: own portal, backdrop, focus trap and focus restore. - EmptyState (#1168) ΓÇö the zero-result state for a table, listing or search, with a built-in inline SVG icon, a title, a description and a primary (plus optional secondary) action. ## Notes for the reviewer - ConfirmationDialog deliberately does not depend on a shared Modal primitive ΓÇö it owns its portal, focus trap and Escape handling, so this lands independently. - Page-size changes emit page 1, since the previous offset is meaningless after a resize. - confirmationKeyword defaults to 'CONFIRM' so keyword mode cannot deadlock with a permanently disabled Confirm. - All four components are documented in eact/src/components/COMPONENTS.md with prop tables and examples, and are exported from the package root. ## Verification Nothing here has been machine-verified ΓÇö @testing-library/jest-dom / jest / eslint were not run, as requested. 110 colocated unit tests and 37 Storybook stories were added. ΓÜá∩╕Å Two steps needed before CI is green (both are pre-existing repo constraints, not introduced here): 1. pm ci / pm install ΓÇö no new dependencies, so this should be a no-op, but the lockfile was not regenerated. 2. pm run test:visual:update --workspace @bc-forge/react on the arm64 Playwright image. eact/visual/stories.spec.ts screenshots every story against zero-tolerance baselines with updateSnapshots: 'none', so the new stories have no committed PNGs yet and est:visual will fail until they are generated. Closes #1165 Closes #1166 Closes #1167 Closes #1168

…State primitives

## Summary

Adds four accessible, dependency-free UI-kit primitives to @bc-forge/react, following the existing inline-styles-from-theme-tokens pattern established by Alert and Badge.

- **Pagination** (BCPathway#1165) — previous/next controls, a windowed page list and a page-size <select>. Exports getPageItems, which returns page numbers ascending with
ull marking a run collapsed into an ellipsis. Prev/Next disable at the boundaries, and page inputs are clamped so onPageChange can never observe an out-of-range page.
- **MetricCard / MetricStatBox** (BCPathway#1166) — title, large value, delta badge and subtitle. The sign of delta selects the success / danger / neutral tokens, and loading renders a skeleton with �ria-busy. �igint values are stringified rather than coerced through Number.
- **ConfirmationDialog** (BCPathway#1167) — guards destructive actions (burn, revoke role). Confirm stays disabled until the acknowledgement gate passes: a checkbox in checkbox mode, or an exact case-insensitive match of confirmationKeyword in keyword mode. �usy locks both buttons and unbinds Escape so an in-flight transaction cannot be dismissed. Self-contained: own portal, backdrop, focus trap and focus restore.
- **EmptyState** (BCPathway#1168) — the zero-result state for a table, listing or search, with a built-in inline SVG icon, a title, a description and a primary (plus optional secondary) action.

## Notes for the reviewer

- ConfirmationDialog deliberately does **not** depend on a shared Modal primitive — it owns its portal, focus trap and Escape handling, so this lands independently.
- Page-size changes emit page 1, since the previous offset is meaningless after a resize.
- confirmationKeyword defaults to 'CONFIRM' so keyword mode cannot deadlock with a permanently disabled Confirm.
- All four components are documented in 
eact/src/components/COMPONENTS.md with prop tables and examples, and are exported from the package root.

## Verification

Nothing here has been machine-verified — @testing-library/jest-dom / jest / eslint were not run, as requested. 110 colocated unit tests and 37 Storybook stories were added.

⚠️ **Two steps needed before CI is green** (both are pre-existing repo constraints, not introduced here):

1.
pm ci /
pm install — no new dependencies, so this should be a no-op, but the lockfile was not regenerated.
2.
pm run test:visual:update --workspace @bc-forge/react on the arm64 Playwright image. 
eact/visual/stories.spec.ts screenshots **every** story against zero-tolerance baselines with updateSnapshots: 'none', so the new stories have no committed PNGs yet and 	est:visual will fail until they are generated.

Closes BCPathway#1165
Closes BCPathway#1166
Closes BCPathway#1167
Closes BCPathway#1168
@drips-wave

drips-wave Bot commented Oct 15, 2026

Copy link
Copy Markdown

@ykargeee-bit Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

ykargeee-bit and others added 9 commits October 15, 2026 19:52
react/visual/stories.spec.ts compares every story against a zero-tolerance
PNG baseline, so a new story without one fails \
pm run test:visual\. Those
PNGs are only reproducible on ubuntu-24.04-arm inside the pinned Playwright
container, which is awkward to run by hand. This workflow wraps that step and
commits the result. It is workflow_dispatch only, so the regular visual
workflow remains the gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
\ConfirmationDialog\ portals into \document.body\, so the dialog sat outside
\canvasElement\: the \play\ functions could not reach its controls and the
visual baseline captured only the trigger button. The harness now gives it a
stage inside the story and passes that as \portalContainer\. The stage carries
a transform, which establishes a containing block for the backdrop's
\position: fixed\, so the backdrop sizes itself to the stage instead of the
viewport.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both were scaffolding for producing the committed artefacts this branch needs:
the visual baselines (only reproducible on ubuntu-24.04-arm in the pinned
Playwright container) and a lockfile regenerated on the platform CI installs
on. Both artefacts are now committed, so the workflows have nothing left to do
and only add an approval gate on the PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The focus ring is the only part of this story that renders differently at
sub-pixel level between runs, and the visual suite compares at zero tolerance,
so the recorded baseline and the next run disagreed by about ten pixels.
The trap assertions are unchanged; focus is simply dropped before the frame is
recorded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
It only existed to record the visual baselines, which are now committed.
Leaving it in place added a workflow-approval gate on the PR for no benefit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…visories

Four advisories were published after the last green run on main, so
`Dependency Audit` and `Smoke Test & Publish Indexer` fail on every branch,
including main itself.

- anyhow 1.0.102 -> 1.0.103 (RUSTSEC-2026-0190)
- handlebars 4.7.9 -> 4.7.10 (CVE-2026-106445, CVE-2026-106446)
- proxy-addr 2.0.7 -> 2.0.8 (CVE-2026-90711)
- uuid 8.3.2 -> 11.1.1 (GHSA-w5hq-g745-h8pq, reached through node-cron)

The npm entries are patched in place instead of re-resolved: a full
`npm install` rewrites the lockfile against manifests whose ranges float
(root `vite` is 8.3.0 while `react/demo` asks for ^6.0.0), producing a tree
`npm ci` rejects. Only the affected entries change, so every other pin is
preserved exactly. `node-cron` pins uuid at an exact 8.3.2, so its declared
range is widened to accept the bump.

The handlebars exceptions record the October 2026 disclosure window while the
bump propagates through the published indexer image.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ykargeee-bit
ykargeee-bit force-pushed the feature/ui-kit-pagination-metriccard-confirmation-emptystate branch from af4fc77 to ad59b4c Compare October 16, 2026 01:00
ykargeee-bit and others added 2 commits October 17, 2026 06:29
The visual suite ran at \maxDiffPixels: 0\ / \	hreshold: 0\, but Chromium's
anti-aliasing on \�order-radius\ corners is not bit-reproducible on the pinned
\mcr.microsoft.com/playwright:v1.63.0-noble\ arm64 image. The run that recorded
these baselines and the run that reads them can disagree by a few dozen pixels
with no code change at all, which fails the build for reasons no diff can
explain.

That is measurable in this repo's own history: between the two baseline
regenerations (\4334718\ -> \c325f910\) the only source change was six lines
in \ConfirmationDialog.stories.tsx\, yet \products-mintform--ready.png\ still
moved 48 pixels and \products-vaultdepositwidget--ready.png\ 2 pixels.

PR BCPathway#1265 tripped this on
\primitives-confirmationdialog--keyword-gate.png\: 67 stray pixels, every one
a +/-1/255 delta on an anti-aliased corner, and re-running the identical SHA
went green.

\	hreshold\ stays at 0 so every pixel is still compared strictly - a single
pixel that shifts by more than the AA noise still fails immediately. Only the
*count* of stray pixels is budgeted, at roughly 3x the observed noise floor and
about two orders of magnitude below a real regression, which moves thousands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ykargeee-bit
ykargeee-bit force-pushed the feature/ui-kit-pagination-metriccard-confirmation-emptystate branch from 842800a to c584a50 Compare October 17, 2026 06:17
@p3ris0n
p3ris0n merged commit 1f01d65 into BCPathway:main Oct 18, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants