-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: new studio component StudioIconCard #14844
Conversation
📝 WalkthroughWalkthroughThis pull request introduces a new Changes
Suggested labels
Suggested reviewers
Warning There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure. 🔧 ESLint
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.cssOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-storybook". (The package "eslint-plugin-storybook" was not found when loaded as a Node module from the directory "/frontend/libs/studio-components".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-storybook" was referenced from the config file in "frontend/libs/studio-components/.eslintrc.js". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsxOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-storybook". (The package "eslint-plugin-storybook" was not found when loaded as a Node module from the directory "/frontend/libs/studio-components".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-storybook" was referenced from the config file in "frontend/libs/studio-components/.eslintrc.js". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsxOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the plugin "eslint-plugin-storybook". (The package "eslint-plugin-storybook" was not found when loaded as a Node module from the directory "/frontend/libs/studio-components".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-storybook" was referenced from the config file in "frontend/libs/studio-components/.eslintrc.js". If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. ✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
10-18
: Consider exporting theStudioIconCardProps
type.The component exports
StudioIconCardIconColors
but not the mainStudioIconCardProps
type. If other components need to reference this type for composition or extension, exporting it would be helpful.-type StudioIconCardProps = { +export type StudioIconCardProps = { icon: ReactElement; iconColor?: StudioIconCardIconColors; linkHref?: string; header?: string; headerOptions?: HeadingProps; description?: string; descriptionOptions?: ParagraphProps; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Build environment and run e2e test
🔇 Additional comments (5)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (5)
1-7
: Imports look good and well-organized.The imports are cleanly organized and include all necessary dependencies for the component.
8-8
: Type definition for icon colors is clear and well-constrained.The exported type
StudioIconCardIconColors
provides a good set of color options and makes the component API clear to users.
20-28
: Component props structure looks good.The component definition with destructured props and default values for
iconColor
is clean and follows React best practices.
51-51
: Overall implementation is clean and well-structured.The component follows a good pattern for a reusable UI element, with appropriate props, styling integration, and component composition. With the suggested improvements for conditional rendering and accessibility, this will be a robust addition to the component library.
36-36
: Make sure icon color classes exist in the CSS module.The component relies on CSS classes that match the color names in
StudioIconCardIconColors
. Ensure that the CSS module includes corresponding classes for each color ('blue', 'red', 'green', 'grey', 'yellow').#!/bin/bash # Check that all required color classes exist in the CSS module cat frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css | grep -E "\.(blue|red|green|grey|yellow)\s*\{"
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
Outdated
Show resolved
Hide resolved
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
Outdated
Show resolved
Hide resolved
27cb4ca
to
95b26fd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
55-57
: 🛠️ Refactor suggestionAdd conditional rendering for header.
The component always renders a
StudioHeading
even whenheader
might be undefined. This could lead to unnecessary empty elements in the DOM.- <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )}
🧹 Nitpick comments (8)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (2)
9-17
: Remove unnecessary async keyword.The test doesn't contain any asynchronous operations, so the async keyword is unnecessary.
- it('should render children as content', async () => { + it('should render children as content', () => {
19-27
: Remove unnecessary async keyword.This test doesn't contain any asynchronous operations, so the async keyword is unnecessary.
- it('should render icon prop', async () => { + it('should render icon prop', () => {frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css (4)
14-21
: Verify if hover styles should be commented out.The hover styles are commented out. Is this intentional or should these be active? If they should remain commented out, consider removing them entirely or adding a comment explaining why they're preserved for future reference.
Would you like me to uncomment these styles or help you decide which hover styles to keep?
68-73
: Use CSS variables for color values instead of hardcoded hex codes.Hardcoded color values (
#4b5563
) are used instead of CSS variables. This may be inconsistent with the design system approach. Consider using semantic color variables for better maintainability..iconBackground svg, .iconBackground img { transform: rotate(-45deg); font-size: var(--fds-sizing-9); - color: #4b5563; + color: var(--fds-semantic-text-neutral-default); }
75-98
: Use CSS variables for color values in color classes.All color classes use hardcoded hex code (
#23262a
) for text color. Consider using semantic color variables for better maintainability and consistency with the design system..blue { background-color: var(--fds-colors-blue-100); - color: #23262a; + color: var(--fds-semantic-text-neutral-default); } .red { background-color: var(--fds-colors-red-100); - color: #23262a; + color: var(--fds-semantic-text-neutral-default); } .green { background-color: var(--fds-colors-green-200); - color: #23262a; + color: var(--fds-semantic-text-neutral-default); } .grey { background-color: var(--fds-colors-grey-200); - color: #23262a; + color: var(--fds-semantic-text-neutral-default); } .yellow { background-color: var(--fds-colors-yellow-200); - color: #23262a; + color: var(--fds-semantic-text-neutral-default); }
1-12
: Consider adding responsiveness to card dimensions.The card has fixed dimensions (244px) which might limit its flexibility on different screen sizes. Consider adding responsive behavior or allowing dynamic sizing based on content.
You could use relative units or media queries to make the card more responsive:
.card { - height: 244px; - width: 244px; - min-width: 244px; + height: 244px; + width: 244px; + min-width: 244px; + @media (max-width: 768px) { + height: 200px; + width: 200px; + min-width: 200px; + } transition: 0.2s transform, 0.2s box-shadow; background-color: var(--fds-semantic-background-default); box-shadow: none; }frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (2)
15-24
: Consider adding additional props for flexibility.The component could benefit from additional props to enhance its flexibility, such as an optional onClick handler for the card itself or the ability to customize the icon size.
export type StudioIconCardProps = { icon: ReactElement; iconColor?: StudioIconCardIconColors; header?: string; headerOptions?: HeadingProps; contextButtons?: ReactNode; children: ReactNode; + onClick?: React.MouseEventHandler<HTMLDivElement>; + className?: string; };
26-33
: Enhance component with spread props pattern.The component could benefit from the spread props pattern to allow passing additional HTML attributes to the root element.
export const StudioIconCard = ({ icon, iconColor = 'grey', header, headerOptions, contextButtons, children, + className, + ...rest }: StudioIconCardProps) => {Then update the return statement:
return ( - <StudioCard className={classes.card}> + <StudioCard className={cn(classes.card, className)} {...rest}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: Testing
- GitHub Check: CodeQL
🔇 Additional comments (2)
frontend/testing/testids.js (1)
19-19
: LGTM: Test ID constant follows naming convention.The newly added test ID constant follows the established naming convention and is descriptive for its purpose of identifying the popover trigger in the StudioIconCard component.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (1)
29-40
: Test is correctly checking popover functionality.The test properly checks that clicking the popover trigger displays the context button. The use of async/await is appropriate here because it involves user interaction.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
Outdated
Show resolved
Hide resolved
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
Show resolved
Hide resolved
95b26fd
to
9de1874
Compare
c4665ec
to
d11ac82
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (2)
54-58
: Add conditional rendering for the header.The component currently renders the
StudioHeading
element regardless of whether a header prop is provided. This could lead to an empty heading element in the DOM when no header is specified.<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
50-52
: Consider accessibility of icon element.The icon element is rendered without any accessibility attributes. If the icon conveys important information, it should have appropriate accessibility attributes.
<div className={classes.iconContainer}> - <div className={cn(classes.iconBackground, classes[iconColor])}>{icon}</div> + <div className={cn(classes.iconBackground, classes[iconColor])} aria-hidden="true">{icon}</div> </div>If the icon represents important content that should be announced to screen readers, consider adding
aria-label
instead ofaria-hidden="true"
.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: CodeQL
- GitHub Check: Testing
🔇 Additional comments (6)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (6)
1-14
: Well-structured imports with clear organization.The imports are well-organized, separating React core imports, component imports, utility libraries, and constants. This follows good practices for import organization.
15-15
: Good type definition for icon colors.The
StudioIconCardIconColors
type provides a clear set of allowed color options that matches the design system palette. This helps enforce consistent styling across the application.
17-24
: Props interface is well-designed with appropriate optionality.The props interface is clear and properly typed, with good use of optionality for non-required props. The use of React's built-in types (
ReactElement
andReactNode
) is appropriate for the different prop requirements.
26-33
: Component signature follows best practices.The component declaration and props destructuring with default values follows React best practices. Setting a default value for
iconColor
ensures the component always has a valid appearance.
37-44
: Add accessibility attributes to the popover trigger.The popover trigger lacks accessibility attributes. Since this represents an action, it should have an accessible label for screen readers.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
34-60
:❓ Verification inconclusive
Verify keyboard navigation and focus handling.
The component includes interactive elements like the popover trigger, but it's not clear if proper keyboard navigation and focus management is implemented. Ensure the component is fully accessible via keyboard.
🏁 Script executed:
#!/bin/bash # Check if the StudioPopoverTrigger and related components properly handle keyboard focus # Check if StudioPopoverTrigger implements keyboard accessibility rg -A 3 -B 3 "StudioPopoverTrigger" --glob "*.tsx" | grep -E "(onKeyDown|onKeyPress|tabIndex|role|aria-)" || echo "No keyboard event handlers found in StudioPopoverTrigger components" # Check StudioPopover implementation for accessibility features rg -A 10 "export const StudioPopover" --glob "*.tsx"Length of output: 305
Accessibility: Verify Keyboard Navigation and Focus Handling
Based on the executed script, no explicit keyboard-related event handlers (e.g. onKeyDown, onKeyPress, tabIndex, aria- attributes) were found in the
StudioPopoverTrigger
component. This raises a concern regarding keyboard accessibility for interactive elements such as the popover trigger. Please confirm whether:
- The component either renders with a native element (e.g., a
<button>
) that inherently supports keyboard navigation,- Or if explicit keyboard event handlers and appropriate ARIA attributes are implemented elsewhere in the component hierarchy to manage focus and keyboard interactions.
If neither is the case, consider adding the necessary accessibility attributes and testing keyboard navigation to ensure the component is fully compliant. Manual verification of these aspects is recommended to avoid accessibility regressions.
d11ac82
to
cecbab7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
56-59
: 🛠️ Refactor suggestionAdd conditional rendering for the header.
The component currently renders the StudioHeading component even when the header prop is undefined, which results in an empty heading element in the DOM. This can lead to unnecessary elements and potential accessibility issues.
<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
🧹 Nitpick comments (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (4)
15-15
: Consider adding more color options to align with design system.The current color options are limited to 'blue', 'red', 'green', 'grey', and 'yellow'. Consider expanding this to include other colors that might be needed for various form elements or status indicators, such as 'purple', 'orange', or 'teal', if they're part of your design system.
17-24
: Add documentation comments to the props interface.Adding JSDoc comments to the props interface would improve developer experience by providing clear descriptions of each prop when consuming the component.
export type StudioIconCardProps = { + /** The icon to display in the card */ icon: ReactElement; + /** The background color of the icon (defaults to 'grey') */ iconColor?: StudioIconCardIconColors; + /** The header text to display */ header?: string; + /** Additional props to pass to the StudioHeading component */ headerOptions?: HeadingProps; + /** Content to display in the context menu popover */ contextButtons?: ReactNode; + /** Content to display in the card body */ children: ReactNode; };
1-13
: Organize imports for better maintainability.Consider organizing imports into groups: React imports, internal components, types, utilities, and constants. This will improve readability and maintainability as the codebase grows.
import React, { type ReactElement, type ReactNode } from 'react'; import { StudioCard, StudioHeading, StudioPopover, StudioPopoverContent, StudioPopoverTrigger, } from '@studio/components'; + import { MenuElipsisVerticalIcon } from '@studio/icons'; + import type { HeadingProps } from '@digdir/designsystemet-react'; + + import { studioIconCardPopoverTrigger } from '@studio/testing/testids'; + import cn from 'classnames'; import classes from './StudioIconCard.module.css'; - import cn from 'classnames'; - import type { HeadingProps } from '@digdir/designsystemet-react'; - import { MenuElipsisVerticalIcon } from '@studio/icons'; - import { studioIconCardPopoverTrigger } from '@studio/testing/testids';
38-43
: Consider adding a reference to the popover content for better accessibility.To improve accessibility, it's recommended to create a relationship between the trigger and the content it controls using
aria-controls
.<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" + aria-controls="icon-card-popover-content" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger> - <StudioPopoverContent className={classes.popoverContent}> + <StudioPopoverContent id="icon-card-popover-content" className={classes.popoverContent}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: Testing
- GitHub Check: CodeQL
🔇 Additional comments (2)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (2)
37-44
: Add accessibility attributes to the popover trigger.The popover trigger currently lacks accessibility attributes. Since this represents an action, it should have an accessible label for screen readers.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
26-64
: The component implementation looks clean and well-structured.The overall implementation of the
StudioIconCard
component follows good React practices:
- Props are properly destructured
- Default values are provided where appropriate
- Conditional rendering is used for optional elements
- CSS modules are used for styling
- Proper ARIA attributes are applied to decorative elements
cecbab7
to
0c6e880
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
38-44
: 🛠️ Refactor suggestionAdd accessibility attributes to the popover trigger.
The popover trigger lacks accessibility attributes that would help screen reader users understand its purpose.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
🧹 Nitpick comments (7)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (4)
9-17
: Remove unnecessary async modifier.This test function is marked as async but doesn't use any await operations, making the async modifier unnecessary.
- it('should render children as content', async () => { + it('should render children as content', () => {
19-27
: Remove unnecessary async modifier.Similar to the previous test, this test function is marked as async but doesn't contain any await operations.
- it('should render icon prop', async () => { + it('should render icon prop', () => {
22-26
: Enhance test by verifying icon color application.The test verifies that the icon renders but doesn't check if the 'red' iconColor prop is correctly applied to the icon container.
render( <StudioIconCard icon={<ClipboardIcon data-testid={iconTestId} />} iconColor='red'> <div></div> </StudioIconCard>, ); expect(screen.getByTestId(iconTestId)).toBeInTheDocument(); + const iconBackground = screen.getByTestId(iconTestId).closest('div').parentElement; + expect(iconBackground).toHaveClass('red');
29-40
: Verify initial popover state before clicking.The test should verify that the context buttons are not visible initially, then check they appear after clicking the trigger. This ensures the popover behavior works correctly.
render( <StudioIconCard contextButtons={contextButtons} icon={<ClipboardIcon />}> <div></div> </StudioIconCard>, ); + // Verify button is not initially visible + expect(screen.queryByRole('button', { name: buttonText })).not.toBeInTheDocument(); + await user.click(screen.getByTestId(studioIconCardPopoverTrigger)); expect(screen.getByRole('button', { name: buttonText })).toBeInTheDocument();frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (3)
50-53
: Consider moving aria-hidden to the icon itself.If the icon is purely decorative, it's better to apply aria-hidden to the icon itself rather than its container.
<div className={classes.iconContainer}> - <div className={cn(classes.iconBackground, classes[iconColor])} aria-hidden={true}> - {icon} + <div className={cn(classes.iconBackground, classes[iconColor])}> + {React.cloneElement(icon, { 'aria-hidden': true })} </div> </div>
56-60
: Add conditional rendering for the header.The component always renders the StudioHeading element even when no header text is provided, which can result in empty heading elements in the DOM. Consider conditionally rendering the heading only when header text is available.
<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
26-33
: Add className prop for better component composition.The component doesn't expose a way to add additional CSS classes at the root level. Consider adding a className prop to allow consumers to customize the component's appearance.
export type StudioIconCardProps = { icon: ReactElement; iconColor?: StudioIconCardIconColors; header?: string; headerOptions?: HeadingProps; contextButtons?: ReactNode; children: ReactNode; + className?: string; }; export const StudioIconCard = ({ icon, iconColor = 'grey', header, headerOptions, contextButtons, children, + className, }: StudioIconCardProps) => { return ( - <StudioCard className={classes.card}> + <StudioCard className={cn(classes.card, className)}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: Build environment and run e2e test
- GitHub Check: Typechecking and linting
- GitHub Check: Testing
- GitHub Check: CodeQL
🔇 Additional comments (2)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (1)
8-8
: Properly named test suite.The test suite is correctly named to match the component being tested, which follows best practices for test suite naming.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
15-24
: Well-defined type definitions.The type definitions for the component are clear, strongly typed, and provide good documentation for the component's API.
ddd9024
to
ca5b007
Compare
There was a problem hiding this comment.
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 (3)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (3)
9-17
: Remove unnecessary async declaration in non-asynchronous test.This test doesn't contain any asynchronous operations (no
await
statements), so theasync
keyword is unnecessary.- it('should render children as content', async () => { + it('should render children as content', () => {
19-27
: Remove unnecessary async and test the iconColor prop.Two improvements for this test:
- The
async
keyword is unnecessary as there are noawait
statements- The test passes
iconColor='red'
but doesn't verify that the color is actually applied- it('should render icon prop', async () => { + it('should render icon prop with correct color', () => { const iconTestId = 'icon-test-id'; render( <StudioIconCard icon={<ClipboardIcon data-testid={iconTestId} />} iconColor='red'> <div></div> </StudioIconCard>, ); expect(screen.getByTestId(iconTestId)).toBeInTheDocument(); + const iconElement = screen.getByTestId(iconTestId); + // Check that the icon has the red color class applied + expect(iconElement.closest('[class*="red"]')).not.toBeNull(); });
29-40
: Consider adding test for popover interaction behavior.The test verifies that clicking the popover trigger displays the button, but it doesn't test the behavior of clicking outside to close the popover or pressing escape key to close it, which are common expectations for popover components.
You could expand this test or add another one to verify these common popover behaviors:
it('should close popover when clicking outside', async () => { const user = userEvent.setup(); const buttonText = 'button-text'; const contextButtons = <button>{buttonText}</button>; render( <> <div data-testid="outside-element">Outside</div> <StudioIconCard contextButtons={contextButtons} icon={<ClipboardIcon />}> <div>Content</div> </StudioIconCard> </> ); // Open popover await user.click(screen.getByTestId(studioIconCardPopoverTrigger)); expect(screen.getByRole('button', { name: buttonText })).toBeInTheDocument(); // Click outside await user.click(screen.getByTestId('outside-element')); // Verify popover is closed (button is no longer visible) expect(screen.queryByRole('button', { name: buttonText })).not.toBeInTheDocument(); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
🔇 Additional comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (1)
8-8
: Test suite named correctly.The test suite is properly named to match the component name, which aligns with best practices for test organization and readability.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
Show resolved
Hide resolved
ca5b007
to
9914b16
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (1)
1-41
: 🛠️ Refactor suggestionAdd tests for header and headerOptions props.
The component accepts
header
andheaderOptions
props, but there are no tests to verify these are rendered correctly. This was mentioned in a previous review but hasn't been addressed yet.Add a new test case to verify the header rendering functionality:
it('should render header with custom options', async () => { const headerText = 'Test Header'; const customClassName = 'custom-header-class'; render( <StudioIconCard icon={<ClipboardIcon />} header={headerText} headerOptions={{ className: customClassName }} > <div>Content</div> </StudioIconCard>, ); const header = screen.getByText(headerText); expect(header).toBeInTheDocument(); expect(header).toHaveClass(customClassName); });frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
37-44
: 🛠️ Refactor suggestionAdd accessibility attributes to the popover trigger.
The popover trigger lacks accessibility attributes. Since it represents an action, it should have an accessible label for screen readers.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
🧹 Nitpick comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (1)
19-27
: Good test for icon rendering.This test properly verifies that the icon prop is rendered within the component. It also implicitly tests that the iconColor prop is accepted, though it doesn't verify the actual color application.
Consider adding a specific test for the iconColor classes to verify that the correct CSS class is applied based on the iconColor prop value. This would ensure that the color styling works as expected.
it('should render icon prop', async () => { const iconTestId = 'icon-test-id'; + const iconColor = 'red'; render( - <StudioIconCard icon={<ClipboardIcon data-testid={iconTestId} />} iconColor='red'> + <StudioIconCard icon={<ClipboardIcon data-testid={iconTestId} />} iconColor={iconColor}> <div></div> </StudioIconCard>, ); expect(screen.getByTestId(iconTestId)).toBeInTheDocument(); + // Verify the color class is applied to the icon background + const iconBackground = screen.getByTestId(iconTestId).closest('div')?.parentElement; + expect(iconBackground).toHaveClass(`red`); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: Build environment and run e2e test
- GitHub Check: Testing
- GitHub Check: Typechecking and linting
- GitHub Check: CodeQL
🔇 Additional comments (5)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (2)
8-17
: Good implementation of basic functionality test.This test correctly validates that the children passed to the StudioIconCard component are properly rendered within the document.
29-40
: Effective test for context button functionality.This test correctly verifies the interactive behavior of the popover trigger for context buttons. Good use of userEvent to simulate clicking and then checking that the button becomes visible.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (3)
15-24
: Well-defined type definitions.The type definitions are clear and properly structured. The use of TypeScript for prop types enhances type safety and developer experience.
56-61
: Add conditional rendering for the header element.The component always renders the
<StudioHeading>
element even ifheader
is undefined or empty, which could lead to unnecessary empty elements in the DOM.Apply this improvement to conditionally render the header:
<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
50-53
: Good use of aria-hidden attribute.The aria-hidden attribute on the icon background is a positive accessibility practice, as it prevents screen readers from trying to announce purely decorative elements.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
Show resolved
Hide resolved
9914b16
to
9a3732c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
37-44
: 🛠️ Refactor suggestionAdd accessibility attributes to the popover trigger.
The popover trigger lacks accessibility attributes for screen readers to understand its purpose.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
🧹 Nitpick comments (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (3)
9-17
: Simplify test by removing unnecessary async.This test doesn't contain any asynchronous operations, so the async keyword isn't needed.
- it('should render children as content', async () => { + it('should render children as content', () => {
19-27
: Simplify test by removing unnecessary async.Similar to the previous test, there are no asynchronous operations here, so the async keyword can be removed.
- it('should render icon prop', async () => { + it('should render icon prop', () => {
29-41
: Missing test cases for additional props.The tests cover basic functionality but don't test the
header
andheaderOptions
props as suggested in a previous review comment.Consider adding a test case for the header functionality:
it('should render header with provided options', () => { const header = 'Test Header'; const headerClassName = 'custom-header-class'; render( <StudioIconCard icon={<ClipboardIcon />} header={header} headerOptions={{ className: headerClassName }} > <div></div> </StudioIconCard>, ); const headerElement = screen.getByText(header); expect(headerElement).toBeInTheDocument(); expect(headerElement).toHaveClass(headerClassName); });frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
56-61
: Add conditional rendering for header.The header is currently always rendered even if it's undefined or empty, which could lead to unnecessary elements in the DOM.
<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
- frontend/testing/testids.js
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: CodeQL
- GitHub Check: Testing
🔇 Additional comments (7)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (2)
1-7
: Clean and clear imports.The necessary imports are correctly included, including React, testing libraries, and the component under test.
8-8
: Appropriate describe block naming.The describe block is named 'StudioIconCard', which properly matches the component name.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (5)
1-14
: Well-organized imports with clear component dependencies.The imports are well-structured, grouped appropriately, and correctly reference needed components and utilities.
15-24
: Clear type definitions with appropriate optionals.The types are well-defined with appropriate optional flags for props that aren't required. The
StudioIconCardIconColors
type provides a clear set of allowed values.
26-33
: Clean component declaration with sensible defaults.The component declaration is clean with proper destructuring and a sensible default for the
iconColor
prop.
50-54
: Appropriate aria-hidden attribute on decorative icon.The icon container correctly uses
aria-hidden={true}
to indicate that it's decorative and should be ignored by screen readers.
34-63
: Consider adding keyboard navigation support.The component lacks explicit keyboard navigation support for the popover trigger, which is important for accessibility.
As noted in a previous review, there are no explicit styles defined for focus states. Make sure the CSS module includes appropriate styles for
:focus
and:focus-visible
to provide visual feedback when the component is navigated using a keyboard.In the CSS file, add rules similar to:
.editIcon:focus-visible { outline: 2px solid var(--focus-color); outline-offset: 2px; }
12077fe
to
0e76757
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (3)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css (1)
29-31
: 🛠️ Refactor suggestionAdd focus states for accessibility.
The CSS only handles hover state for the edit icon visibility, but for proper keyboard navigation accessibility, focus states should also be included.
.card:not(:hover) .editIcon { display: none; } +.card:focus-within .editIcon, +.card:focus .editIcon { + display: block; +}frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (2)
37-44
: 🛠️ Refactor suggestionAdd accessibility attributes to the popover trigger.
The popover trigger currently lacks accessibility attributes. Since this represents an action, it should have an accessible label for screen readers.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
56-61
: 🛠️ Refactor suggestionAdd conditional rendering for header.
The component should conditionally render the header element only when a header value is provided.
<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
🧹 Nitpick comments (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css (2)
5-10
: Consider making card dimensions responsive.The current implementation uses fixed dimensions (250px) for both height and width, which could limit responsiveness on different screen sizes.
.card { - height: 250px; - width: 250px; - min-width: 250px; + height: var(--card-height, 250px); + width: var(--card-width, 250px); + min-width: var(--card-min-width, 250px); background-color: var(--fds-semantic-background-default); }
104-106
: Consider adding hover/active states for buttons.The button styling should include hover and active states for better user feedback.
.content button { width: 100%; + transition: background-color 0.2s ease; +} + +.content button:hover { + background-color: var(--fds-semantic-background-hover); +} + +.content button:active { + background-color: var(--fds-semantic-background-active); }frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (2)
42-50
: Add test for empty header case.Since I recommended adding conditional rendering for the header, it would be good to add a test for the case where no header is provided.
it('should not render header when not provided', async () => { render( <StudioIconCard icon={<ClipboardIcon />}> <div>Content</div> </StudioIconCard>, ); // Assuming there's only one heading from the children content expect(screen.queryByRole('heading')).not.toBeInTheDocument(); });
1-51
: Add test for different iconColor values.The component supports multiple iconColor values, but the tests only check one case ('red'). Consider adding tests for other color variations.
it('should apply the correct iconColor class', async () => { const { rerender } = render( <StudioIconCard icon={<ClipboardIcon />} iconColor='blue'> <div>Content</div> </StudioIconCard>, ); // Using a more specific selector to find the element with the blue class const blueIconBg = document.querySelector('[class*="iconBackground"][class*="blue"]'); expect(blueIconBg).toBeInTheDocument(); // Test another color rerender( <StudioIconCard icon={<ClipboardIcon />} iconColor='yellow'> <div>Content</div> </StudioIconCard>, ); const yellowIconBg = document.querySelector('[class*="iconBackground"][class*="yellow"]'); expect(yellowIconBg).toBeInTheDocument(); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/testing/testids.js
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: Testing
- GitHub Check: CodeQL
🔇 Additional comments (10)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css (5)
1-3
: Good use of CSS custom properties.The use of CSS variables for defining icon font color is a good practice for maintainability and future theming.
41-55
: LGTM! Good implementation of the icon container.The icon container implementation properly centers icon content vertically, which is important for consistent UI presentation.
64-87
: Good use of color utility classes.The color utility classes provide a clean way to apply different background colors based on the iconColor prop.
94-102
: Good use of flex layout.The flex layout for content spacing and alignment is well-implemented, providing good visual hierarchy.
57-62
:❓ Verification inconclusive
Ensure SVG accessibility.
When rotating SVGs, ensure they remain accessible. Adding appropriate ARIA attributes can help screen readers properly interpret the content.
🏁 Script executed:
#!/bin/bash # Check if any SVG icons being used have proper accessibility attributes # Look for SVG components in the imports echo "Checking for SVG icon imports and their accessibility attributes:" grep -r "import.*Icon" --include="*.tsx" frontend/libs/studio-components/src/ | head -n 10 # Check if there are any aria-label or role attributes used with icons echo -e "\nChecking for aria attributes with icons:" grep -r "aria-label" --include="*.tsx" frontend/libs/studio-components/src/ | head -n 10Length of output: 3677
Ensure SVG Accessibility in StudioIconCard
It appears that many components in the project already include ARIA attributes for icons. However, the CSS in
StudioIconCard.module.css
rotates SVGs, and it’s unclear if the corresponding TSX component sets the necessary accessibility attributes. Please confirm that in theStudioIconCard
component (likelyfrontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
):
- If the SVG icons are decorative, add
aria-hidden="true"
.- If they convey meaning, include
role="img"
along with an appropriatearia-label
.This will ensure that the visual transformation doesn’t hinder accessibility for assistive technologies.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (2)
15-24
: Well-defined and exported types.The exported types are well-defined and provide good type safety for the component props.
50-54
: Good use of aria-hidden for decorative icon container.The aria-hidden attribute on the icon background is good for accessibility, as it hides decorative elements from screen readers.
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (3)
8-17
: Good test coverage for rendering children.The test properly verifies that children are rendered as content within the component.
19-27
: Good test for icon rendering.The test correctly verifies that the icon is rendered in the component with the specified iconColor.
29-40
: Good test for popover functionality.The test correctly verifies that the popover trigger is clickable and shows the context buttons when clicked.
0e76757
to
0a919c4
Compare
0a919c4
to
680d1b9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
56-60
: Conditionally render the header to avoid empty headings.The
header
prop is optional, but the component always renders aStudioHeading
component even when no header is provided. This can result in an empty heading element, which isn't ideal for accessibility and semantic HTML.<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx (2)
8-50
: Enhance test coverage for component variations.The test suite covers the basic functionality well but misses a few important test cases:
- Testing what happens when
header
is not provided- Testing different
iconColor
values to ensure correct styling- Testing the component when
contextButtons
is not providedConsider adding these additional test cases to ensure comprehensive coverage:
it('should not render header when not provided', () => { render( <StudioIconCard icon={<ClipboardIcon />}> <div>Content</div> </StudioIconCard>, ); expect(screen.queryByRole('heading')).not.toBeInTheDocument(); }); it('should apply the correct color class based on iconColor', () => { const { container } = render( <StudioIconCard icon={<ClipboardIcon />} iconColor="blue"> <div>Content</div> </StudioIconCard>, ); // This would need to be adapted based on your actual CSS class implementation const iconBackground = container.querySelector('[class*="iconBackground"]'); expect(iconBackground).toHaveClass('blue'); });
9-17
: Remove unnecessary async declarations from tests without await operations.Several test functions are declared as
async
but don't use anyawait
operations, which is unnecessary and potentially misleading.- it('should render children as content', async () => { + it('should render children as content', () => {- it('should render icon prop', async () => { + it('should render icon prop', () => {- it('should apply headerOptions to header studioheading', async () => { + it('should apply headerOptions to header studioheading', () => {Also applies to: 19-27, 42-50
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: Testing
- GitHub Check: CodeQL
🔇 Additional comments (1)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (1)
37-44
: Add accessibility attributes to the popover trigger.The popover trigger lacks an
aria-label
, which is essential for screen readers to understand the purpose of this interactive element.<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍
Component that displays a card with an icon, description and optional ellipsis menu. Created to be used on the new navigation page for Form Designer. commit-id:fe161544
680d1b9
to
1bbf422
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (2)
56-59
: Consider conditional rendering for the header.The header element is always rendered even when the
header
prop is undefined or empty, which can result in an empty heading element in the DOM. This might cause accessibility or layout issues.<div className={classes.content}> - <StudioHeading className={classes.title} size='2xs' {...headerOptions}> - {header} - </StudioHeading> + {header && ( + <StudioHeading className={classes.title} size='2xs' {...headerOptions}> + {header} + </StudioHeading> + )} {children} </div>
17-24
: Enhance component API with additional descriptive props.The current implementation allows children but doesn't provide a dedicated prop for description text, which was mentioned in the PR objectives. This could make the component API less intuitive.
export type StudioIconCardProps = { icon: ReactElement; iconColor?: StudioIconCardIconColors; header?: string; headerOptions?: HeadingProps; contextButtons?: ReactNode; + description?: string; + descriptionOptions?: React.HTMLAttributes<HTMLParagraphElement>; children: ReactNode; };This enhancement would make the component more aligned with the PR objectives which mentioned a card with "icon, description, and an optional ellipsis menu".
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
(1 hunks)frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx
(1 hunks)frontend/testing/testids.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/testing/testids.js
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.module.css
- frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Build environment and run e2e test
- GitHub Check: CodeQL
- GitHub Check: Testing
🔇 Additional comments (4)
frontend/libs/studio-components/src/components/StudioIconCard/StudioIconCard.tsx (4)
37-44
: Add accessibility attributes to the popover trigger.The popover trigger lacks an aria-label, which is essential for screen reader users to understand its purpose. Since this represents an action, it should have an accessible name.
<StudioPopoverTrigger data-testid={studioIconCardPopoverTrigger} variant='tertiary' className={classes.editIcon} + aria-label="Open menu" > <MenuElipsisVerticalIcon /> </StudioPopoverTrigger>
1-13
: The import section is clean and well-organized.All necessary imports are included with a logical grouping. The component correctly imports from the design system and local modules.
15-15
: Clear and well-defined type for icon colors.The type definition for
StudioIconCardIconColors
is clear and follows the naming conventions used in the codebase.
50-53
: Good accessibility practice with aria-hidden attribute.Setting
aria-hidden={true}
on the icon container is a good practice as it prevents screen readers from attempting to announce decorative elements.
Component that displays a card with an icon, description and optional
ellipsis menu.
Created to be used on the new navigation page for Form Designer.
Stack:
Summary by CodeRabbit