Repository navigation
feat: implement spinner component - #59
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
Primitive component overrides are accepted by the type but ignored by RenderPropsWrapper, causing the default SVG to render.
Pull request overview
Adds a reusable, accessible Spinner component with size variants, animation support, overrides, exports, tests, and Storybook examples.
Changes:
- Added Spinner component and SVG icon.
- Added public exports and type definitions.
- Added tests and Storybook documentation.
File summaries
| File | Summary |
|---|---|
src/stories/components/Spinner/Spinner.stories.tsx |
Storybook examples |
src/index.ts |
Public exports |
src/components/spinner.tsx |
Spinner implementation and API |
src/assets/icons/SpinnerIcon.tsx |
Spinner SVG icon |
spec/components/Spinner/Spinner.test.tsx |
Component behavior tests |
Review details
Suppressed comments (1)
src/components/spinner.tsx:49
reactNodeis typed asReactNode, so this accepts primitive overrides such as a string, number, orfalse, butRenderPropsWrapperonly recognizes function/object values (src/utils/RenderPropsWrapper.tsx:24-34). Passing one of those valid overrides toSpinnertherefore silently renders the default SVG instead. Update the shared wrapper to treat any explicitly defined override as an override, or narrow the override type consistently.
<RenderPropsWrapper props={renderProps} override={componentOverrides?.reactNode}>
- Files reviewed: 5/5 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| import SpinnerIcon from '@/assets/icons/SpinnerIcon'; | ||
|
|
||
| const spinnerVariants = cva( | ||
| 'cio-components cio-spinner cio:block cio:shrink-0 cio:animate-spin cio:motion-reduce:animate-none', |
There was a problem hiding this comment.
It looks like the ticket's "Verified in PLP UI" step isn't mentioned here, so I asked Claude to run this test: packed this branch, installed it into a PLP checkout and rendered <Spinner size='lg' /> inside PLP's .cio-plp-loading wrapper, the spot where CioPlpGrid renders spinner || <Spinner />. The API side is fine: the types compile against PLP's React 18 types, and the spinner is centred and spins. One thing to be aware of, though: the hook class cio-spinner is the same one PLP's legacy .cio-spinner rule styles for the four-ring spinner. That rule is unlayered, while our utilities are emitted into a cascade layer (layer(utilities)), so at equal specificity PLP's rule wins. With PLP's stylesheet loaded the svg comes out 70px wide, inline-block and position: relative. At lg inside the absolute wrapper it still looks right, because the arc keeps its aspect ratio, but sm and md sit in a 70px-wide box (the spacing in the first screenshot), and any customer CSS written against .cio-spinner lands on the svg too.
I don't think anything needs to change here, since cio-spinner follows the cio-badge / cio-chip naming. How about we note on CDX-630 that PLP has to drop its .cio-spinner rules in the same change?
| export type SpinnerOverrides = ComponentOverrideProps<SpinnerProps>; | ||
|
|
||
| export interface SpinnerProps | ||
| extends React.ComponentProps<'svg'>, |
There was a problem hiding this comment.
Nitpick: children is part of SpinnerProps through React.ComponentProps<'svg'>, but whatever a consumer passes is dropped, because SpinnerIcon renders its own arc path as the only child. So <Spinner>Loading…</Spinner> type-checks and renders without the text. I know the ticket's contract has the wider type, so this is a tweak to it: ChipProps already does this with Omit<React.ComponentProps<'div'>, 'children'>. What do you think about doing the same here, so the type says what the component does?
| extends React.ComponentProps<'svg'>, | |
| extends Omit<React.ComponentProps<'svg'>, 'children'>, |
[CDX-525] Create Spinner in Shared Components UI
Adds a shared
SpinnerChanges
src/components/spinner.tsx- shadcn single-arc spinner adapted to library conventionssrc/assets/icons/SpinnerIcon.tsx- hand-rolled SVG, like the other iconssrc/index.ts;componentOverridessupportedspec/components/Spinner/) and a Storybook story incl. a "centre it yourself" exampleAPI
role="status", colour viacurrentColor, respectsprefers-reduced-motion. No positioning inside the component — consumers centre it themselves.Pull Request Checklist
Before you submit a pull request, please make sure you have to following:
PR Type
What kind of change does this PR introduce?