feat: SW-2547 Export Progress and Snippet from the barrel, fix Progress value forwarding - #198
feat: SW-2547 Export Progress and Snippet from the barrel, fix Progress value forwarding#198owilliams-tetrascience wants to merge 6 commits into
Conversation
Progress destructured `value` out of its props but never passed it to ProgressPrimitive.Root — it was only used to compute the indicator's inline translateX. Radix therefore never received a value, so every bar rendered with data-state="indeterminate" and no aria-valuenow no matter what the consumer passed. The bar still *looked* right because the style transform drives it independently of Radix state, which is why this went unnoticed. Screen readers and any consumer reading data-state saw an indeterminate bar. Adds a 7-story Storybook file whose play tests assert aria-valuenow and data-state; reverting the one-line fix fails 4 of the 7. Note for consumers: role="progressbar" requires an accessible name and the component cannot invent one, so each story passes its own aria-label. Documented in DESIGN.md in the follow-up commit.
Both components are fully built and story-tested in this kit but were
absent from src/index.ts, so `import { Progress } from
"@tetrascience-npm/tetrascience-react-ui"` resolved to undefined. This
blocked a consumer's conformance meter (Progress) and output-path copy
button (Snippet).
The barrel line is the whole fix. scripts/build/component-entries.ts
derives the per-component subpath entries by parsing the
`export * from "@/..."` lines in src/index.ts, so a component missing
from the barrel gets no build entry and the existing `./ui/*` exports
wildcard has nothing to resolve to. Verified post-build that all six
resolution targets now exist for each component:
dist/ui/<name>.{js,cjs} and dist/components/ui/<name>.d.ts. Both are
single files in ui/, that category's dominant shape, so no package.json
change was needed.
Also retitles the Snippet story from "AI Elements/Snippet" to
"Components/Data Display/Snippet". The component lives in
components/ui/ and is a read-only input-group field with a copy button —
nothing AI-specific; the misfiled title was inherited from upstream
ai-elements. Existing zephyr testCaseId values are untouched.
DESIGN.md: adds the Progress and Snippet inventory rows, and documents
that Progress requires a consumer-supplied aria-label because
role="progressbar" must be named and the component cannot name itself.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
✅ No issues found
About Unblocked
Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.
📖 Documentation — Learn more in our docs.
💬 Ask questions — Mention @unblocked to request a review or summary, or ask follow-up questions.
👍 Give feedback — React to comments with 👍 or 👎 to help us improve.
⚙️ Customize — Adjust settings in your preferences.
There was a problem hiding this comment.
Pull request overview
This PR makes Progress and Snippet available to consumers via the library barrel export (src/index.ts) and fixes Progress’s accessibility/state wiring by forwarding the value prop to the Radix root. It also adds/updates Storybook coverage and documentation to reflect the components’ intended taxonomy and accessibility requirements.
Changes:
- Export
ProgressandSnippetfromsrc/index.tsso consumers can import them from the package root. - Fix
Progressto forwardvaluetoProgressPrimitive.Root(restoring correctaria-valuenow/data-statebehavior). - Add
Progressstories with play assertions, retitleSnippetstory, and documentProgress’s accessible-name requirement inDESIGN.md.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/index.ts | Adds barrel exports for Progress and Snippet so they’re available to consumers. |
| src/components/ui/progress.tsx | Forwards value to the Radix progress root to fix ARIA/state behavior. |
| src/components/ui/progress.stories.tsx | Adds Storybook coverage + play tests for determinate/indeterminate behavior and labeling. |
| src/components/ui/snippet.stories.tsx | Retitles story to the Components/Data Display taxonomy. |
| DESIGN.md | Adds Progress/Snippet to the inventory and documents the accessible-name requirement for Progress. |
Suppressed comments (1)
src/components/ui/progress.stories.tsx:134
- Avoid hard-coded Tailwind palette colors in stories; use semantic tokens (e.g.
bg-warning) so the example remains consistent with the design system and dark mode.
className="bg-orange-500/20 [&_[data-slot=progress-indicator]]:bg-orange-500"
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The story hard-coded bg-green-500 / bg-orange-500 instead of the kit's semantic tokens. Those Tailwind palette colors are not redefined under .dark, so the story rendered the same washed-out greens/oranges in dark mode, while --positive / --warning / --destructive are defined for both themes with documented AA contrast ratios. Switches to bg-positive / bg-warning, matching the existing in-repo precedent for exactly this pattern in src/components/ai/context.tsx, which styles a Progress indicator via the same [&_[data-slot=progress-indicator]] selector. The destructive row already used the token. Raised by Copilot on the PR.
Resolves a DESIGN.md §3 inventory conflict. SW-2526 (Text) and SW-2540 (Tree) both landed on main and appended rows to the Data Display block in the same position as this branch's Snippet row. Kept both sides — the two changes are independent and purely additive — ordering Snippet before Text after Kbd. src/index.ts auto-merged; verified progress and snippet are still in their alphabetical positions and that the two pre-existing out-of-alphabetical trailing entries (code-editor, tetrascience-icon) are unchanged from main rather than introduced here.
SW-2305 (#197) landed and rewrote the whole DESIGN.md §3 inventory table to the 7-category taxonomy, conflicting with this branch's added rows — the conflict this branch anticipated. Resolved by taking main's rewritten table wholesale and re-adding only the Progress row, now under "Feedback & Status" (alphabetically between Banner and Skeleton) rather than the old "Feedback". The Snippet row was not re-added: #197's rewrite already includes one, so keeping main's version avoids a duplicate. No story retitling was needed. This branch deliberately authored both stories in #197's target taxonomy ahead of it landing, and both now match exactly — DESIGN.md's new "Storybook title" guidance even names `Components/Data Display/Snippet` as the correct title for Snippet, which is what this branch had already changed it to. Verified after merge: lint, typecheck, test:all (180 files / 1738 tests) all clean; the §4 accessibility note added by this branch survived intact; and all six per-component subpath resolution targets still build.
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||
Summary
ProgressandSnippetare fully built and story-tested in this kit, but neitherwas listed in
src/index.ts. Consumers importing them gotundefined— whichblocked a conformance meter (
Progress) and an output-path copy button(
Snippet). This adds both to the barrel.While writing the
Progressstory I found a real accessibility defect in thecomponent and fixed it — details in the aside below.
Closes SW-2547 (epic SW-2301,
React UI Kit v1.1.0).
The exports mechanism — correcting the ticket
The ticket states "the exports map has no subpaths". That isn't accurate as
written:
package.json'sexportsalready has./ui/*,./composed/*,./charts/*,./ai/*,./utils/*and./lib/*wildcards from SW-2007.The real mechanism is that
scripts/build/component-entries.tsderivesper-component build entries by parsing the
export * from "@/..."lines insrc/index.ts. A component absent from that barrel gets no entry generated,so the wildcard has nothing to resolve to. Net effect matches the ticket
(unreachable for consumers), but the fix is the barrel line — no
package.jsonchange was needed.
Both components are single files in
ui/, that category's dominant file shape, sothe wildcard resolves types as well as runtime. Verified against a real build
rather than assumed, since a shape mismatch fails silently for types while runtime
imports keep working:
progresssnippetdist/ui/<name>.js(import)dist/ui/<name>.cjs(require)dist/components/ui/<name>.d.ts(types)Snippet was also miscategorised
Its story was titled
"AI Elements/Snippet"while the component lives insrc/components/ui/. It's a read-only input-group field with a copy button —nothing AI-specific; the title was inherited from upstream
ai-elements, andsrc/components/ai/in this kit is otherwise entirely chat/LLM primitives.Retitled to
Components/Data Display/Snippet. The component stays inui/—no file move, so no subpath churn and no break for anyone already deep-importing
./ui/snippet. Existing ZephyrtestCaseIdvalues are untouched.🐛 Aside: the Progress defect (found while writing its story)
src/components/ui/progress.tsxdestructuredvalueout of its props but neverforwarded it to
ProgressPrimitive.Root— it was only used to compute theindicator's inline
translateX:Radix therefore never received a value. Every bar rendered
data-state="indeterminate"with noaria-valuenow, regardless of what theconsumer passed.
aria-valuenow"60"data-stateatvalue={60}indeterminateloadingdata-stateatvalue={100}indeterminatecompleteThe bar looked right because the style transform drives it independently of
Radix state — which is exactly why this went unnoticed. But screen readers, and
any consumer branching on
data-state, saw a permanently indeterminate bar. Thismatters directly for the conformance meter this ticket unblocks: it would have
been visually correct but unreadable to assistive tech.
Fix is one line (
value={value}). It is load-bearing, not speculative — deletingit fails 4 of the 7 new play tests with
aria-valuenow === null.Consumer requirement worth flagging:
role="progressbar"must have anaccessible name and the component cannot invent one, so every call site needs its
own
aria-label(oraria-labelledby). Storybook's axe check(
a11y: { test: "error" }) fails a story that omits it. Now documented inDESIGN.md §4.
Notes for the reviewer
Two deliberate, opposite calls on the SW-2305 / #197 taxonomy. That PR
(#197) is still open, so there was nothing to rebase onto:
Components/Feedback & Status/Progress,Components/Data Display/Snippet) rather than main's current flatComponents/<Name>. refactor: SW-2305 Regroup Storybook into logical categories (Components, AI Elements, Composed) #197 can't retitle a file it doesn't know about, soauthoring in the target shape means zero follow-up once it lands. Cost: a lone
sidebar group until then.
Feedback,Data Display). refactor: SW-2305 Regroup Storybook into logical categories (Components, AI Elements, Composed) #197 rewrites all 79 rows of that table, so a conflict there isguaranteed either way; internal consistency of this diff wins. On conflict
resolution,
Progressshould becomeFeedback & Status.Snippetwas missing from the DESIGN.md inventory table too, so it's added thereas well.
Split into two commits so the fix is revertable independently of the exports:
fix:for the Progress value forwarding,feat:for the barrel additions.Type of Change
Progress/SnippetexportsProgressnever forwardedvalueto RadixChecklist
yarn lintpassesyarn buildpassesyarn test:allpasses — 171 files, 1616 testsProgressstories;Snippetretitledprogress.tsxat 100%Testing
yarn lint,yarn typecheck,yarn buildandyarn test:allall clean locally(171 files / 1616 tests). Coverage on the one changed source file,
progress.tsx: 100% statements / branches / functions / lines.The 7 new
Progressstories (Default, Empty, Complete, Indeterminate, WithLabel,Sizes, SemanticColors) have play tests asserting
aria-valuenowanddata-state.Zephyr test cases:
Snippet— existing, unchanged: SW-T4731, SW-T4732, SW-T4733, SW-T4734Progress— new, IDs not yet generated. Per repo conventiontestCaseIdisleft absent; needs the
zephyr_synclabel applied to this PR to generate the 7IDs and commit them back to the branch.
Verification
Screenshots
Not applicable — the
Progressfix changes only the ARIA/data-stateattributesRadix emits. There is no visual change: the bar's rendered position was already
correct via the inline style transform, which is what masked the bug.
🤖 Generated with Claude Code