feat(vertical-stepper,card-stepper): new TEDI-Ready components #172 - #690
feat(vertical-stepper,card-stepper): new TEDI-Ready components #172#690airikej wants to merge 16 commits into
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds ChangesStepper navigation migration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant VerticalStepper
participant VerticalStepperItem
participant VerticalStepperSubItem
participant User
VerticalStepper->>VerticalStepperItem: clone with index and compact context
User->>VerticalStepperItem: toggle expandable step
VerticalStepperItem->>VerticalStepperSubItem: render nested sub-items
User->>VerticalStepperSubItem: activate link or button
sequenceDiagram
participant User
participant CardStepper
participant Sheet
participant VerticalStepper
User->>CardStepper: open step list
CardStepper->>Sheet: open bottom sheet
CardStepper->>VerticalStepper: render step rows
User->>VerticalStepper: select navigable step
VerticalStepper->>CardStepper: invoke step selection
CardStepper->>Sheet: close sheet
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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 `@src/tedi/components/navigation/card-stepper/card-stepper.spec.tsx`:
- Around line 1-13: The modal mock in CardStepperSpec uses any for its props,
which violates the TypeScript guidance; replace the untyped Modal,
Modal.Content, Modal.Header, and Modal.Body props with explicit interfaces or
shared prop types. Update the jest.mock for modal in card-stepper.spec.tsx so
the mock components are properly typed while preserving the current
open/children behavior.
In `@src/tedi/components/navigation/card-stepper/card-stepper.stories.tsx`:
- Around line 26-31: The story meta in card-stepper.stories.tsx is missing the
required Storybook status metadata in meta.parameters. Update the default export
metadata alongside the existing design block to include status, and keep the
pattern consistent with the storybook metadata used in other stories. If needed,
verify the default story and other visual variants remain defined under the same
CardStepper story module.
In `@src/tedi/components/navigation/vertical-stepper/vertical-stepper-item.tsx`:
- Around line 49-50: VerticalStepperItem currently exposes an `as` prop but is
still a plain function component; refactor it to the repository’s polymorphic
`forwardRef` pattern. Update the `VerticalStepperItem` component in
`vertical-stepper-item.tsx` to use `React.forwardRef` with generic typing (`<C
extends React.ElementType>`), and thread the ref through the rendered element
while preserving the existing `as` behavior and props typing. Use the existing
`VerticalStepperItem` symbol and its polymorphic props definitions as the place
to apply the change.
In
`@src/tedi/components/navigation/vertical-stepper/vertical-stepper-sub-item.tsx`:
- Around line 42-53: The VerticalStepperSubItem component is using a fixed
element switch instead of the required polymorphic ref-forwarding pattern.
Refactor VerticalStepperSubItemProps and VerticalStepperSubItem to use a generic
`<C extends React.ElementType = 'div'>` with `forwardRef`, so the `as` prop
drives the rendered element type and the ref is forwarded correctly. Update the
current `Element` selection logic inside VerticalStepperSubItem to derive from
`as` dynamically and preserve existing interactive/non-interactive behavior
while passing the ref to the rendered element.
In `@src/tedi/components/navigation/vertical-stepper/vertical-stepper.spec.tsx`:
- Around line 40-43: The vertical stepper spec is using non-semantic DOM access
via querySelector for the current step assertion. Update the test in the
vertical stepper spec to use semantic RTL queries such as getByRole or
getByLabelText to locate the active step, and keep the assertions against the
returned element instead of querying the DOM directly. If you need to verify
there is only one current step, use a semantic query pattern consistent with the
existing VerticalStepper test setup rather than selector-based matching.
In
`@src/tedi/components/navigation/vertical-stepper/vertical-stepper.stories.tsx`:
- Around line 27-32: The story metadata in the vertical stepper stories
currently includes design details but is missing the required status entry in
meta.parameters. Update the default export in vertical-stepper.stories.tsx to
include status alongside the existing design metadata, and verify the story file
still follows the project convention with a Default story and any key visual
variants.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 70676b51-291f-4046-be6f-1c8db6246bb1
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (22)
package.jsonskills/tedi-react/references/components.mdsrc/community/components/vertical-stepper/step-item/step-item.tsxsrc/community/components/vertical-stepper/sub-item/sub-item.tsxsrc/community/components/vertical-stepper/vertical-stepper.stories.tsxsrc/community/components/vertical-stepper/vertical-stepper.tsxsrc/tedi/components/navigation/card-stepper/card-stepper-step.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.module.scsssrc/tedi/components/navigation/card-stepper/card-stepper.spec.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.stories.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.tsxsrc/tedi/components/navigation/card-stepper/index.tssrc/tedi/components/navigation/vertical-stepper/index.tssrc/tedi/components/navigation/vertical-stepper/vertical-stepper-context.tssrc/tedi/components/navigation/vertical-stepper/vertical-stepper-item.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper-sub-item.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper.module.scsssrc/tedi/components/navigation/vertical-stepper/vertical-stepper.spec.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper.stories.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper.tsxsrc/tedi/index.tssrc/tedi/providers/label-provider/labels-map.ts
| justify-content: center; | ||
| width: 1.75rem; | ||
| height: 1.75rem; | ||
| font-size: var(--body-small-size); |
There was a problem hiding this comment.
--body-small-size is not defined - pls check
| border-radius: 50%; | ||
| } | ||
|
|
||
| .tedi-vertical-stepper__number { |
There was a problem hiding this comment.
in Figma, font-weight is bold
font-weight: var(--body-bold-weight, 700);
| state="completed" | ||
| href="#i1" | ||
| info={ | ||
| <StatusBadge color="success" variant="filled"> |
There was a problem hiding this comment.
use bordered badge to match figma
| ), | ||
| }; | ||
|
|
||
| export const Compact: Story = { |
| @@ -0,0 +1,111 @@ | |||
| .tedi-card-stepper { | |||
There was a problem hiding this comment.
when looking at Figma design, there is no padding nor border at the bottom of the stepper
|
|
||
| .tedi-card-stepper__counter { | ||
| flex-shrink: 0; | ||
| font-size: var(--body-extra-small-size); |
There was a problem hiding this comment.
figma uses --body-small-regular
font-size: var(--body-small-regular-size, 14px);
font-weight: var(--body-small-regular-weight, 400);
line-height: var(--body-small-regular-line-height, 20px); /* 142.857% */
| render: () => ( | ||
| <VerticalSpacing size={1}> | ||
| <Row alignItems="center"> | ||
| <Col xs={12} md={2} /> |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/tedi/components/navigation/vertical-stepper/vertical-stepper.spec.tsx (1)
253-260: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAvoid reintroducing selector-based assertions here.
container.querySelector('.tedi-vertical-stepper__number')couples this test to CSS implementation details again. Please scope the check to the rendered list item and assert the absence of the number via Testing Library queries so the test survives classname/markup refactors.Suggested change
- const { container } = render( + render( <VerticalStepper compact> <VerticalStepper.Item title="Plain" /> </VerticalStepper> ); - expect(container.querySelector('.tedi-vertical-stepper__number')).not.toBeInTheDocument(); + expect(within(screen.getByRole('listitem')).queryByText('1')).not.toBeInTheDocument(); expect(screen.queryByRole('img')).not.toBeInTheDocument();As per coding guidelines, "Use semantic queries in tests (
getByRole,getByLabelText) instead of non-semantic queries"; as per path instructions, TEDI tests should "use semantic queries in tests (avoidgetByTestIdunless necessary)."🤖 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 `@src/tedi/components/navigation/vertical-stepper/vertical-stepper.spec.tsx` around lines 253 - 260, The VerticalStepper compact-mode test is using a CSS selector via container.querySelector for the step number, which reintroduces implementation coupling. Update the assertion in the VerticalStepper.Item test to scope within the rendered list item and use Testing Library semantic queries to verify the number is absent, keeping only role-based checks like the existing queryByRole('img') where appropriate.Sources: Coding guidelines, Path instructions
🤖 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.
Duplicate comments:
In `@src/tedi/components/navigation/vertical-stepper/vertical-stepper.spec.tsx`:
- Around line 253-260: The VerticalStepper compact-mode test is using a CSS
selector via container.querySelector for the step number, which reintroduces
implementation coupling. Update the assertion in the VerticalStepper.Item test
to scope within the rendered list item and use Testing Library semantic queries
to verify the number is absent, keeping only role-based checks like the existing
queryByRole('img') where appropriate.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c52be5af-5c1c-4356-914f-df3931df2066
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (16)
package.jsonskills/tedi-react/references/components.mdsrc/community/components/vertical-stepper/vertical-stepper.stories.tsxsrc/tedi/components/buttons/card-button/card-button.module.scsssrc/tedi/components/navigation/card-stepper/card-stepper-step.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.module.scsssrc/tedi/components/navigation/card-stepper/card-stepper.spec.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.stories.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper-item.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper-sub-item.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper.module.scsssrc/tedi/components/navigation/vertical-stepper/vertical-stepper.spec.tsxsrc/tedi/components/navigation/vertical-stepper/vertical-stepper.stories.tsxsrc/tedi/index.tssrc/tedi/providers/label-provider/labels-map.ts
🚧 Files skipped from review as they are similar to previous changes (11)
- src/tedi/index.ts
- src/community/components/vertical-stepper/vertical-stepper.stories.tsx
- src/tedi/providers/label-provider/labels-map.ts
- package.json
- src/tedi/components/navigation/card-stepper/card-stepper.module.scss
- src/tedi/components/navigation/vertical-stepper/vertical-stepper.stories.tsx
- src/tedi/components/navigation/card-stepper/card-stepper.spec.tsx
- src/tedi/components/navigation/card-stepper/card-stepper.stories.tsx
- src/tedi/components/navigation/vertical-stepper/vertical-stepper-item.tsx
- src/tedi/components/navigation/vertical-stepper/vertical-stepper-sub-item.tsx
- src/tedi/components/navigation/card-stepper/card-stepper.tsx
| * Per-instance label overrides. When omitted, each label comes from the | ||
| * `LabelProvider` (`stepper.previous`, `stepper.next`, `stepper.open-steps`, | ||
| * `stepper.steps`, `stepper.status`). | ||
| */ |
There was a problem hiding this comment.
Please add Figma link.
| import { VerticalStepperSubItem, VerticalStepperSubItemProps } from './vertical-stepper-sub-item'; | ||
|
|
||
| /** | ||
| * <a href="https://www.figma.com/design/jWiRIXhHRxwVdMSimKX2FF/TEDI-READY-2.54.75?node-id=4375-57530&m=dev" target="_blank">Figma ↗</a><br/> |
There was a problem hiding this comment.
Please add Zeroheight link as well: https://www.tedi.ee/1ee8444b7/p/25a440-stepper-vertical.
| <> | ||
| <div className={styles['tedi-vertical-stepper__toggle']}> | ||
| {interactiveTitle} | ||
| <Collapse |
There was a problem hiding this comment.
Replace with CollapseButton?
| <VerticalStepper.Item title="Kutse" state="completed" href="#k1" /> | ||
| <VerticalStepper.Item | ||
| title="Tahteavaldus" | ||
| description="Ülevaatamine võib võtta kuni 30 tööpäeva" |
| /> | ||
| <VerticalStepper.Item title="Üldandmed" state="completed" href="#i2" /> | ||
| <VerticalStepper.Item title="Terviseandmed" state="completed" href="#i3" /> | ||
| <VerticalStepper.Item title="Vastus" current href="#i4" info={<Text color="tertiary">Täidab ametnik</Text>} /> |
There was a problem hiding this comment.
Add modifiers="small" if we want to match Figma.
| parameters: { pseudo: { hover: ['.vs-hover a', '.vs-hover button'] } }, | ||
| render: () => ( | ||
| <VerticalSpacing size={2}> | ||
| <StateMatrix states={ITEM_STATES} renderCell={(props) => itemCell(false, props)} /> |
There was a problem hiding this comment.
Maybe add a subheading for each row here so it would be easier to understand what is presented here (Default, Compact, Has subitems)?
| } | ||
|
|
||
| .tedi-vertical-stepper__item--default:has(.tedi-vertical-stepper__link:hover) .tedi-vertical-stepper__indicator { | ||
| border-color: var(--stepper-step-default-border-hover); |
There was a problem hiding this comment.
Completed and Has error states should have hover color on indicator as well:
background: var(--stepper-step-completed-bg-hover);
background: var(--stepper-step-danger-bg-hover);
| { label: 'Default', props: {} }, | ||
| { label: 'Selected', props: { current: true } }, | ||
| { label: 'Disabled', props: { state: 'disabled' }, noHover: true }, | ||
| { label: 'Informative', props: { state: 'informative' }, noHover: true }, |
| .tedi-card-stepper__trail { | ||
| display: flex; | ||
| grid-column: 3; | ||
| gap: var(--layout-grid-gutters-08); |
There was a problem hiding this comment.
Is this gap added here because otherwise the focus ring would be overflowing the step number?
| minWidth: 0, | ||
| }} | ||
| > | ||
| <Text element="span" modifiers="bold"> |
There was a problem hiding this comment.
In Figma, this title is not in bold.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@src/tedi/components/overlays/sheet/sheet.tsx`:
- Around line 71-72: Update SheetProps and the Sheet component’s accessibility
behavior so callers cannot omit both title and ariaLabel: require ariaLabel when
no title is provided, while preserving title-based labeling when a title exists.
Add or update accessibility checks covering the dialog/sheet role and accessible
name for both title and ariaLabel paths.
- Around line 9-13: Update SheetProps to add optional defaultOpen and make open
and onToggle optional, then update the Sheet component’s Modal usage to forward
defaultOpen while preserving controlled behavior when open/onToggle are
provided. Ensure Sheet supports both controlled and uncontrolled state modes.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c3090959-12cc-4b43-bffb-deaebbd158cf
📒 Files selected for processing (9)
src/tedi/components/navigation/card-stepper/card-stepper.spec.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.stories.tsxsrc/tedi/components/navigation/card-stepper/card-stepper.tsxsrc/tedi/components/navigation/table-of-contents/components/table-of-contents-collapsible/table-of-contents-collapsible.tsxsrc/tedi/components/navigation/table-of-contents/table-of-contents.module.scsssrc/tedi/components/navigation/vertical-stepper/vertical-stepper.module.scsssrc/tedi/components/navigation/vertical-stepper/vertical-stepper.stories.tsxsrc/tedi/components/overlays/sheet/sheet.module.scsssrc/tedi/components/overlays/sheet/sheet.tsx
💤 Files with no reviewable changes (1)
- src/tedi/components/navigation/table-of-contents/table-of-contents.module.scss
🚧 Files skipped from review as they are similar to previous changes (5)
- src/tedi/components/navigation/vertical-stepper/vertical-stepper.stories.tsx
- src/tedi/components/navigation/card-stepper/card-stepper.tsx
- src/tedi/components/navigation/card-stepper/card-stepper.spec.tsx
- src/tedi/components/navigation/vertical-stepper/vertical-stepper.module.scss
- src/tedi/components/navigation/card-stepper/card-stepper.stories.tsx
| export interface SheetProps { | ||
| /** Controlled open state. */ | ||
| open: boolean; | ||
| /** Called when the sheet opens or closes. */ | ||
| onToggle: (open: boolean) => void; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Support uncontrolled Sheet state.
Sheet requires open and onToggle, even though its underlying Modal supports uncontrolled state. Add optional defaultOpen, make open/onToggle optional, and forward defaultOpen to Modal.
Proposed change
export interface SheetProps {
- /** Controlled open state. */
- open: boolean;
+ /** Initial open state for uncontrolled usage. */
+ defaultOpen?: boolean;
+ /** Controlled open state. */
+ open?: boolean;
/** Called when the sheet opens or closes. */
- onToggle: (open: boolean) => void;
+ onToggle?: (open: boolean) => void; export const Sheet = ({
+ defaultOpen,
open,
onToggle,
...
}: SheetProps): JSX.Element => {
...
- <Modal open={open} onToggle={onToggle}>
+ <Modal defaultOpen={defaultOpen} open={open} onToggle={onToggle}>As per path instructions, “always support controlled + uncontrolled modes.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export interface SheetProps { | |
| /** Controlled open state. */ | |
| open: boolean; | |
| /** Called when the sheet opens or closes. */ | |
| onToggle: (open: boolean) => void; | |
| export interface SheetProps { | |
| /** Initial open state for uncontrolled usage. */ | |
| defaultOpen?: boolean; | |
| /** Controlled open state. */ | |
| open?: boolean; | |
| /** Called when the sheet opens or closes. */ | |
| onToggle?: (open: boolean) => void; | |
| } |
🤖 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 `@src/tedi/components/overlays/sheet/sheet.tsx` around lines 9 - 13, Update
SheetProps to add optional defaultOpen and make open and onToggle optional, then
update the Sheet component’s Modal usage to forward defaultOpen while preserving
controlled behavior when open/onToggle are provided. Ensure Sheet supports both
controlled and uncontrolled state modes.
Source: Path instructions
| aria-label={ariaLabel} | ||
| aria-labelledby={!header && title !== undefined && title !== null ? titleId : undefined} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Prevent unnamed dialogs.
SheetProps allows callers to omit both title and ariaLabel; this leaves both accessible-name attributes unset. Model valid prop combinations so a label is required when no title is rendered.
As per path instructions, include accessibility checks for “role/name behavior.”
🤖 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 `@src/tedi/components/overlays/sheet/sheet.tsx` around lines 71 - 72, Update
SheetProps and the Sheet component’s accessibility behavior so callers cannot
omit both title and ariaLabel: require ariaLabel when no title is provided,
while preserving title-based labeling when a title exists. Add or update
accessibility checks covering the dialog/sheet role and accessible name for both
title and ariaLabel paths.
Source: Path instructions






https://storybook.tedi.ee/react/feat/172-verticalstepper-new-tedi-ready-component/?path=/docs/tedi-ready-components-navigation-verticalstepper--docs
https://storybook.tedi.ee/react/feat/172-verticalstepper-new-tedi-ready-component/?path=/docs/tedi-ready-components-navigation-cardstepper--docs
Summary by CodeRabbit