Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export { MediaUpload } from './ui/MediaUpload';
export { NavBack } from './ui/NavBack';
export { Pagination } from './ui/Pagination';
export { Portal } from './ui/Portal';
export { ProgressBar } from './ui/ProgressBar';
export { Select, GroupingSelect } from './ui/Select';
export { Skeleton } from './ui/Skeleton';
export { Radio, RadioItem } from './ui/Radio';
Expand Down
3 changes: 3 additions & 0 deletions src/shared/lib/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const colors = {
purple: '#a855f7',
white: '#ffffff',
black: '#000000',
pink: '#FF507D',
};

export const COLORS = {
Expand All @@ -41,9 +42,11 @@ export const COLORS = {
green: colors['green'][300],
black: colors['black'],
white: colors['white'],
pink: colors['pink'],
};

export type Colors = keyof typeof colors;
export type IconColor = keyof typeof COLORS;
export type SwitchColor = keyof typeof COLORS;
export type ProgressBarColor = keyof typeof colors;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드래빗 리뷰 참고해주시면 좋을 것 같습니다.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

03f92ff 수정했습니다.

export const colorNames = Object.keys(colors) as Colors[];
39 changes: 39 additions & 0 deletions src/shared/ui/ProgressBar/ProgressBar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Meta, StoryObj } from '@storybook/react';

import { COLORS } from '@/shared/lib/colors';

import { ProgressBar } from './ProgressBar';

const meta = {
title: 'Components/ProgressBar',
component: ProgressBar,
tags: ['autodocs'],
parameters: {
docs: {
description: {
component: 'ProgressBar 컴포넌트는 진행 상황을 시각적으로 표시하는 컴포넌트입니다.',
},
},
},
} satisfies Meta<typeof ProgressBar>;

export default meta;

export const Basic: StoryObj<typeof ProgressBar> = {
args: {
percent: 60,
color: 'pink',
},
argTypes: {
percent: { control: { type: 'range', min: 0, max: 100, step: 1 } },
color: {
control: { type: 'select' },
table: {
type: { summary: 'Colors' },
defaultValue: { summary: 'primary' },
},
options: Object.keys(COLORS),
},
},
render: (args) => <ProgressBar {...args} />,
};
40 changes: 40 additions & 0 deletions src/shared/ui/ProgressBar/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { COLORS, colors } from '@/shared/lib/colors';
import { cn } from '@/shared/lib/core';
import { Flex } from '@/shared/ui/Flex';

type Props = {
/**
* defined in percentage (0-100).
*/
percent: number;
/**
* color of the switch.
* @default 'primary'
*/
color?: keyof typeof COLORS;
className?: string;
};

export function ProgressBar({ color = 'primary', percent, className }: Props) {
const clampedPercent = Math.min(100, Math.max(0, percent));
const barColor = COLORS[color];

return (
<Flex>
<div
className={cn('h-[0.625rem] w-[16.5rem] overflow-hidden rounded-full', className)}
style={{
backgroundColor: colors.gray[100],
}}
>
<div
className="h-full rounded-full transition-[width] duration-600 ease-in-out"
style={{
width: `${clampedPercent}%`,
backgroundColor: barColor,
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

접근성 속성(ARIA) 추가가 필요합니다.

진행 상태를 전달하는 컴포넌트인데 role="progressbar"aria-valuenow/min/max가 없어 스크린리더가 의미를 인지하기 어렵습니다.

♿ 제안 수정안
 type Props = {
   /**
    *   defined in percentage (0-100).
    */
   percent: number;
+  /**
+   * 접근성 라벨
+   */
+  ariaLabel?: string;
   /**
    * color of the switch.
    * `@default` 'primary'
    */
   color?: keyof typeof COLORS;
   className?: string;
 };
 
-export function ProgressBar({ color = 'primary', percent, className }: Props) {
+export function ProgressBar({
+  color = 'primary',
+  percent,
+  className,
+  ariaLabel = 'progress',
+}: Props) {
   const clampedPercent = Math.min(100, Math.max(0, percent));
   const barColor = COLORS[color];
 
   return (
     <Flex>
       <div
         className={cn('h-[0.625rem] w-[16.5rem] overflow-hidden rounded-full', className)}
+        role="progressbar"
+        aria-valuemin={0}
+        aria-valuemax={100}
+        aria-valuenow={clampedPercent}
+        aria-label={ariaLabel}
         style={{
           backgroundColor: colors.gray[100],
         }}
       >
🤖 Prompt for AI Agents
In `@src/shared/ui/ProgressBar/ProgressBar.tsx` around lines 5 - 35, The
ProgressBar component is missing ARIA attributes; update the rendered container
(the outer or the inner bar in ProgressBar) to include role="progressbar" and
set aria-valuenow to the clampedPercent (or a derived integer), and
aria-valuemin="0" and aria-valuemax="100"; ensure you use the clampedPercent
variable (from ProgressBar) for the value attributes and preserve existing
className/cn, COLORS and Flex usage so screen readers can announce the progress
correctly.

/>
</div>
</Flex>
);
}
1 change: 1 addition & 0 deletions src/shared/ui/ProgressBar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ProgressBar } from './ProgressBar';