@teamturing/react-kit 2.75.0 → 2.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren, RefObject } from 'react';
1
+ import { HTMLAttributes, PropsWithChildren, RefObject } from 'react';
2
2
  import { SxProp } from '../../utils/styled-system';
3
3
  import { DrawerBodyProps } from './DrawerBody';
4
4
  import { DrawerFooterProps } from './DrawerFooter';
@@ -16,7 +16,7 @@ type Props = {
16
16
  size?: DrawerSizeType;
17
17
  direction?: DrawerDirectionType;
18
18
  initialFocusRef?: RefObject<HTMLElement>;
19
- } & SxProp;
19
+ } & Pick<HTMLAttributes<HTMLDivElement>, 'aria-label' | 'aria-labelledby'> & SxProp;
20
20
  declare const _default: import("react").ForwardRefExoticComponent<{
21
21
  isOpen?: boolean | undefined;
22
22
  onDismiss?: (() => void) | undefined;
@@ -24,7 +24,7 @@ declare const _default: import("react").ForwardRefExoticComponent<{
24
24
  size?: DrawerSizeType | undefined;
25
25
  direction?: DrawerDirectionType | undefined;
26
26
  initialFocusRef?: RefObject<HTMLElement> | undefined;
27
- } & SxProp & {
27
+ } & Pick<HTMLAttributes<HTMLDivElement>, "aria-label" | "aria-labelledby"> & SxProp & {
28
28
  children?: import("react").ReactNode;
29
29
  } & import("react").RefAttributes<HTMLDivElement>> & {
30
30
  UnstyledHeader: import("styled-components").IStyledComponent<"web", {
@@ -30,8 +30,15 @@ type FormControlFieldProps = {
30
30
  label: string;
31
31
  caption?: string;
32
32
  };
33
- type FormControlContextValue = {} & Omit<Props, 'additionalInputComponentCandidates'>;
34
- declare const FormControlContext: import("react").Context<Omit<Props, "additionalInputComponentCandidates">>;
33
+ type FormControlContextValue = {
34
+ /**
35
+ * `Caption`, `ErrorMessage`, `SuccessMessage`가 Input과 `aria-describedby`로 연결되기 위한 고유 ID입니다.
36
+ */
37
+ captionId?: string;
38
+ errorId?: string;
39
+ successId?: string;
40
+ } & Omit<Props, 'additionalInputComponentCandidates'>;
41
+ declare const FormControlContext: import("react").Context<FormControlContextValue>;
35
42
  declare const _default: import("react").ForwardRefExoticComponent<{
36
43
  /**
37
44
  * `FormControl`의 Input 요소를 컨트롤하기 위한 ID입니다. `Label`, `Caption`과 연결짓기 위해 사용합니다.
@@ -2,9 +2,21 @@ import { SVGProps } from 'react';
2
2
  type SpinnerVariantType = 'progress-gradient' | 'progress-line';
3
3
  type Props = {
4
4
  variant?: SpinnerVariantType;
5
+ /**
6
+ * 스크린 리더에 읽힐 로딩 상태 텍스트를 정의합니다.
7
+ * 빈 문자열(`''`)을 전달하면 장식용으로 간주되어 보조 기술에서 숨겨집니다.
8
+ * @default '로딩 중'
9
+ */
10
+ label?: string;
5
11
  } & Omit<SVGProps<SVGSVGElement>, 'ref'>;
6
12
  declare const Spinner: import("react").ForwardRefExoticComponent<{
7
13
  variant?: SpinnerVariantType | undefined;
14
+ /**
15
+ * 스크린 리더에 읽힐 로딩 상태 텍스트를 정의합니다.
16
+ * 빈 문자열(`''`)을 전달하면 장식용으로 간주되어 보조 기술에서 숨겨집니다.
17
+ * @default '로딩 중'
18
+ */
19
+ label?: string | undefined;
8
20
  } & Omit<SVGProps<SVGSVGElement>, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
9
21
  export default Spinner;
10
22
  export type { Props as SpinnerProps };
@@ -5,12 +5,12 @@ type Props = {
5
5
  * @teamturing/icons와 함께 사용
6
6
  */
7
7
  icon: ComponentType<SVGProps<SVGSVGElement>>;
8
- } & Pick<ViewProps, 'size' | 'color' | 'sx'> & Pick<HTMLAttributes<HTMLDivElement>, 'className'>;
8
+ } & Pick<ViewProps, 'size' | 'color' | 'sx'> & Pick<HTMLAttributes<HTMLDivElement>, 'className' | 'aria-label' | 'aria-hidden'>;
9
9
  declare const StyledIcon: import("react").ForwardRefExoticComponent<{
10
10
  /**
11
11
  * @teamturing/icons와 함께 사용
12
12
  */
13
13
  icon: ComponentType<SVGProps<SVGSVGElement>>;
14
- } & Pick<ViewProps, "color" | "size" | "sx"> & Pick<HTMLAttributes<HTMLDivElement>, "className"> & import("react").RefAttributes<HTMLDivElement>>;
14
+ } & Pick<ViewProps, "color" | "size" | "sx"> & Pick<HTMLAttributes<HTMLDivElement>, "className" | "aria-hidden" | "aria-label"> & import("react").RefAttributes<HTMLDivElement>>;
15
15
  export default StyledIcon;
16
16
  export type { Props as StyledIconProps };
@@ -1,4 +1,4 @@
1
- import { ComponentType, PropsWithChildren, SVGProps } from 'react';
1
+ import { ComponentType, HTMLAttributes, PropsWithChildren, SVGProps } from 'react';
2
2
  import { ResponsiveValue } from 'styled-system';
3
3
  type ToastVariantType = 'success' | 'warning';
4
4
  type Props = {
@@ -16,7 +16,7 @@ type Props = {
16
16
  * 반응형 디자인이 적용됩니다.
17
17
  */
18
18
  resizing?: ResponsiveValue<'hug' | 'fill'>;
19
- };
20
- declare const Toast: ({ variant, icon: Icon, resizing, children, }: PropsWithChildren<Props>) => import("react/jsx-runtime").JSX.Element;
19
+ } & HTMLAttributes<HTMLDivElement>;
20
+ declare const Toast: ({ variant, icon: Icon, resizing, children, ...props }: PropsWithChildren<Props>) => import("react/jsx-runtime").JSX.Element;
21
21
  export default Toast;
22
22
  export type { Props as ToastProps };
package/dist/index.js CHANGED
@@ -1916,10 +1916,10 @@ const Overlay = ({
1916
1916
  }, [isOpen, handleOutsideClick]);
1917
1917
  return isOpen ? /*#__PURE__*/jsxRuntime.jsx(BaseOverlay, {
1918
1918
  ref: overlayRef,
1919
+ role: 'dialog',
1919
1920
  size: size,
1920
1921
  maxHeight: maxHeight,
1921
1922
  ...props,
1922
- role: 'dialog',
1923
1923
  children: children
1924
1924
  }) : null;
1925
1925
  };
@@ -2602,6 +2602,7 @@ const Spinner = /*#__PURE__*/React.forwardRef(({
2602
2602
  variant: propsVariant,
2603
2603
  width = 32,
2604
2604
  height = 32,
2605
+ label = '로딩 중',
2605
2606
  ...props
2606
2607
  }, ref) => {
2607
2608
  const theme = styled.useTheme();
@@ -2610,10 +2611,18 @@ const Spinner = /*#__PURE__*/React.forwardRef(({
2610
2611
  'progress-gradient': ProgressGradientSpinner,
2611
2612
  'progress-line': ProgressLineSpinner
2612
2613
  }[variant];
2614
+ const a11yProps = label ? {
2615
+ 'role': 'status',
2616
+ 'aria-label': label,
2617
+ 'aria-busy': true
2618
+ } : {
2619
+ 'aria-hidden': true
2620
+ };
2613
2621
  return /*#__PURE__*/jsxRuntime.jsx(SpinnerComponent, {
2614
2622
  ref: ref,
2615
2623
  width: width,
2616
2624
  height: height,
2625
+ ...a11yProps,
2617
2626
  ...props
2618
2627
  });
2619
2628
  });
@@ -3277,25 +3286,41 @@ const BaseHorizontalDivider = /*#__PURE__*/styled__default.default.hr.withConfig
3277
3286
  })(["display:block;margin:0;padding:0;border:none;width:100%;", " ", ""], border, sx);
3278
3287
 
3279
3288
  const StyledIcon = /*#__PURE__*/React.forwardRef(({
3280
- icon: Icon,
3289
+ 'icon': Icon,
3281
3290
  sx,
3282
3291
  className,
3292
+ 'aria-label': ariaLabel,
3293
+ 'aria-hidden': ariaHidden,
3283
3294
  ...props
3284
- }, ref) => /*#__PURE__*/jsxRuntime.jsx(View, {
3285
- ref: ref,
3286
- ...props,
3287
- className: `trk-styled_icon__wrapper ${className}`,
3288
- color: props.color,
3289
- sx: {
3290
- '& svg': {
3291
- display: 'inline-flex',
3292
- width: '100%',
3293
- height: '100%'
3295
+ }, ref) => {
3296
+ /**
3297
+ * 기본적으로 장식용 아이콘으로 간주해 `aria-hidden`을 부여합니다.
3298
+ * 의미 있는 아이콘이라면 `aria-label`을 전달하세요. (`role="img"`로 노출됩니다.)
3299
+ */
3300
+ const a11yProps = ariaLabel ? {
3301
+ 'role': 'img',
3302
+ 'aria-label': ariaLabel,
3303
+ 'aria-hidden': ariaHidden
3304
+ } : {
3305
+ 'aria-hidden': ariaHidden ?? true
3306
+ };
3307
+ return /*#__PURE__*/jsxRuntime.jsx(View, {
3308
+ ref: ref,
3309
+ ...props,
3310
+ ...a11yProps,
3311
+ className: `trk-styled_icon__wrapper ${className}`,
3312
+ color: props.color,
3313
+ sx: {
3314
+ '& svg': {
3315
+ display: 'inline-flex',
3316
+ width: '100%',
3317
+ height: '100%'
3318
+ },
3319
+ ...sx
3294
3320
  },
3295
- ...sx
3296
- },
3297
- children: /*#__PURE__*/jsxRuntime.jsx(Icon, {})
3298
- }));
3321
+ children: /*#__PURE__*/jsxRuntime.jsx(Icon, {})
3322
+ });
3323
+ });
3299
3324
 
3300
3325
  const TextInputTrailingAction = ({
3301
3326
  icon: Icon,
@@ -3635,7 +3660,9 @@ const SearchSelectInput = ({
3635
3660
  }, overlayHandler)
3636
3661
  })]
3637
3662
  }),
3638
- children: popperProps => /*#__PURE__*/jsxRuntime.jsxs(TextInputWrapper, {
3663
+ children: (popperProps, {
3664
+ isOpen
3665
+ }) => /*#__PURE__*/jsxRuntime.jsxs(TextInputWrapper, {
3639
3666
  ...(disabled ? {} : {
3640
3667
  ...popperProps,
3641
3668
  onClick: e => {
@@ -3686,6 +3713,9 @@ const SearchSelectInput = ({
3686
3713
  }) : null, /*#__PURE__*/jsxRuntime.jsx(BaseInput, {
3687
3714
  id: id,
3688
3715
  ref: labelInputRef,
3716
+ role: 'combobox',
3717
+ "aria-haspopup": 'listbox',
3718
+ "aria-expanded": isOpen,
3689
3719
  readOnly: true,
3690
3720
  onChange: utils.noop,
3691
3721
  autoComplete: 'off',
@@ -3973,6 +4003,7 @@ const Switch = ({
3973
4003
  const checkboxRef = useProvidedOrCreatedRef(ref);
3974
4004
  return /*#__PURE__*/jsxRuntime.jsx(BaseSwitch, {
3975
4005
  ref: checkboxRef,
4006
+ role: 'switch',
3976
4007
  checked: checked,
3977
4008
  validationStatus: validationStatus,
3978
4009
  ...props
@@ -4140,11 +4171,11 @@ const FormControlCaption = ({
4140
4171
  children
4141
4172
  }) => {
4142
4173
  const {
4143
- id
4174
+ captionId
4144
4175
  } = React.useContext(FormControlContext);
4145
4176
  return /*#__PURE__*/jsxRuntime.jsx(Text, {
4146
4177
  as: 'span',
4147
- id: id,
4178
+ id: captionId,
4148
4179
  typography: 'xxs',
4149
4180
  color: 'text/neutral/subtlest',
4150
4181
  children: children
@@ -4155,10 +4186,11 @@ const FormControlErrorMessage = ({
4155
4186
  children
4156
4187
  }) => {
4157
4188
  const {
4158
- id
4189
+ errorId
4159
4190
  } = React.useContext(FormControlContext);
4160
4191
  return /*#__PURE__*/jsxRuntime.jsx(StyledText$3, {
4161
- id: id,
4192
+ id: errorId,
4193
+ role: 'alert',
4162
4194
  typography: 'xxs',
4163
4195
  color: 'text/danger',
4164
4196
  children: children
@@ -4252,10 +4284,11 @@ const FormControlSuccessMessage = ({
4252
4284
  children
4253
4285
  }) => {
4254
4286
  const {
4255
- id
4287
+ successId
4256
4288
  } = React.useContext(FormControlContext);
4257
4289
  return /*#__PURE__*/jsxRuntime.jsx(StyledText$2, {
4258
- id: id,
4290
+ id: successId,
4291
+ role: 'status',
4259
4292
  typography: 'xxs',
4260
4293
  color: 'text/success',
4261
4294
  children: children
@@ -4318,11 +4351,35 @@ const FormControl = ({
4318
4351
  const inputComponentCandidates = [TextInput$1, Textarea, Select$1, SearchSelectInput$1, Checkbox$1, Radio$1, Switch$1, ...additionalInputComponentCandidates];
4319
4352
  const InputComponent = restComponents.find(component => inputComponentCandidates.some(candidate => /*#__PURE__*/React.isValidElement(component) && component.type === candidate));
4320
4353
  const isHorizontalLayoutNeeded = /*#__PURE__*/React.isValidElement(InputComponent) && (InputComponent.type === Checkbox$1 || InputComponent.type === Radio$1 || InputComponent.type === Switch$1);
4354
+ const reactId = React.useId();
4355
+ const resolvedId = id ?? reactId;
4356
+ const captionId = `${resolvedId}-caption`;
4357
+ const errorId = `${resolvedId}-error`;
4358
+ const successId = `${resolvedId}-success`;
4359
+ const hasCaption = Boolean(relocatableComponentsObject.caption);
4360
+ const hasError = Boolean(relocatableComponentsObject.errorMessage);
4361
+ const hasSuccess = Boolean(relocatableComponentsObject.successMessage);
4362
+
4363
+ /**
4364
+ * 소비자가 Input에 직접 전달한 aria 값을 보존하기 위해 기존 props와 병합합니다.
4365
+ */
4366
+ const inputProps = /*#__PURE__*/React.isValidElement(InputComponent) ? InputComponent.props : {};
4367
+ const describedBy = [inputProps['aria-describedby'], hasCaption && captionId, hasError && errorId, hasSuccess && successId].filter(Boolean).join(' ') || undefined;
4368
+ const inputA11yProps = {
4369
+ 'id': resolvedId,
4370
+ disabled,
4371
+ 'aria-invalid': hasError ? true : inputProps['aria-invalid'],
4372
+ 'aria-required': required ? true : inputProps['aria-required'],
4373
+ 'aria-describedby': describedBy
4374
+ };
4321
4375
  return /*#__PURE__*/jsxRuntime.jsx(FormControlContext.Provider, {
4322
4376
  value: {
4323
- id,
4377
+ id: resolvedId,
4324
4378
  disabled,
4325
- required
4379
+ required,
4380
+ captionId,
4381
+ errorId,
4382
+ successId
4326
4383
  },
4327
4384
  children: isHorizontalLayoutNeeded ? /*#__PURE__*/jsxRuntime.jsxs(View, {
4328
4385
  ref: ref,
@@ -4334,10 +4391,7 @@ const FormControl = ({
4334
4391
  ...props,
4335
4392
  children: [/*#__PURE__*/jsxRuntime.jsx(View, {
4336
4393
  display: 'inline-flex',
4337
- children: /*#__PURE__*/React.cloneElement(InputComponent, {
4338
- id,
4339
- disabled
4340
- })
4394
+ children: /*#__PURE__*/React.cloneElement(InputComponent, inputA11yProps)
4341
4395
  }), /*#__PURE__*/jsxRuntime.jsxs(View, {
4342
4396
  sx: {
4343
4397
  '& > span': {
@@ -4376,10 +4430,7 @@ const FormControl = ({
4376
4430
  columnGap: 1
4377
4431
  },
4378
4432
  children: [relocatableComponentsObject.label, relocatableComponentsObject.tooltipIcon]
4379
- }), /*#__PURE__*/React.cloneElement(InputComponent, {
4380
- id,
4381
- disabled
4382
- }), relocatableComponentsObject.caption, relocatableComponentsObject.errorMessage, relocatableComponentsObject.successMessage]
4433
+ }), /*#__PURE__*/React.cloneElement(InputComponent, inputA11yProps), relocatableComponentsObject.caption, relocatableComponentsObject.errorMessage, relocatableComponentsObject.successMessage]
4383
4434
  })
4384
4435
  });
4385
4436
  };
@@ -5040,16 +5091,26 @@ const ClickArea = ({
5040
5091
  disabled,
5041
5092
  onClick,
5042
5093
  ...props
5043
- }, ref) => /*#__PURE__*/jsxRuntime.jsx(BaseClickArea, {
5044
- ref: ref,
5045
- ...props,
5046
- role: 'button',
5047
- "aria-disabled": disabled,
5048
- disabled: disabled,
5049
- ...(!disabled ? {
5050
- onClick
5051
- } : {})
5052
- });
5094
+ }, ref) => {
5095
+ const handleKeyDown = e => {
5096
+ if (e.key === 'Enter' || e.key === ' ') {
5097
+ e.preventDefault();
5098
+ e.currentTarget.click();
5099
+ }
5100
+ };
5101
+ return /*#__PURE__*/jsxRuntime.jsx(BaseClickArea, {
5102
+ ref: ref,
5103
+ ...props,
5104
+ role: 'button',
5105
+ tabIndex: disabled ? -1 : 0,
5106
+ "aria-disabled": disabled,
5107
+ disabled: disabled,
5108
+ ...(!disabled ? {
5109
+ onClick,
5110
+ onKeyDown: handleKeyDown
5111
+ } : {})
5112
+ });
5113
+ };
5053
5114
  const BaseClickArea = /*#__PURE__*/styled__default.default(View).withConfig({
5054
5115
  displayName: "ClickArea__BaseClickArea",
5055
5116
  componentId: "sc-1pd8ned-0"
@@ -5335,6 +5396,7 @@ const DescriptionList = ({
5335
5396
  children: [/*#__PURE__*/jsxRuntime.jsx(Grid$1.Unit, {
5336
5397
  size: titleUnitSize,
5337
5398
  children: /*#__PURE__*/jsxRuntime.jsxs(View, {
5399
+ role: 'term',
5338
5400
  display: 'flex',
5339
5401
  alignItems: 'center',
5340
5402
  flexWrap: 'nowrap',
@@ -5349,7 +5411,10 @@ const DescriptionList = ({
5349
5411
  })
5350
5412
  }), /*#__PURE__*/jsxRuntime.jsx(Grid$1.Unit, {
5351
5413
  size: descriptionUnitSize,
5352
- children: renderDescription(!utils.isNullable(description) ? description : '-')
5414
+ children: /*#__PURE__*/jsxRuntime.jsx(View, {
5415
+ role: 'definition',
5416
+ children: renderDescription(!utils.isNullable(description) ? description : '-')
5417
+ })
5353
5418
  })]
5354
5419
  });
5355
5420
  },
@@ -5370,6 +5435,13 @@ const IconButton = /*#__PURE__*/React.forwardRef(({
5370
5435
  loading = false,
5371
5436
  ...props
5372
5437
  }, ref) => {
5438
+ const hasAccessibleName = Boolean(props['aria-label'] || props['aria-labelledby'] || props['title']);
5439
+ React.useEffect(() => {
5440
+ if (process.env.NODE_ENV !== 'production' && !hasAccessibleName) {
5441
+ // eslint-disable-next-line no-console
5442
+ console.warn('IconButton: An icon-only button should provide an accessible name via `aria-label`, `aria-labelledby`, or `title` so that assistive technologies can identify it.');
5443
+ }
5444
+ }, [hasAccessibleName]);
5373
5445
  return /*#__PURE__*/jsxRuntime.jsx(BaseIconButton, {
5374
5446
  ref: ref,
5375
5447
  icon: Icon,
@@ -5864,6 +5936,7 @@ const Dialog = ({
5864
5936
  icon: icons.CloseIcon,
5865
5937
  variant: 'plain-bold',
5866
5938
  size: 'm',
5939
+ "aria-label": theme.locales?.Dialog?.closeButtonLabel ?? '닫기',
5867
5940
  onClick: handleDismiss
5868
5941
  })
5869
5942
  }), /*#__PURE__*/jsxRuntime.jsx(DialogContext.Provider, {
@@ -6009,6 +6082,8 @@ const Drawer = ({
6009
6082
  size = 'm',
6010
6083
  direction = 'right',
6011
6084
  initialFocusRef,
6085
+ 'aria-label': ariaLabel,
6086
+ 'aria-labelledby': ariaLabelledby,
6012
6087
  sx
6013
6088
  }, ref) => {
6014
6089
  const theme = styled.useTheme();
@@ -6033,7 +6108,8 @@ const Drawer = ({
6033
6108
  useFocusTrap({
6034
6109
  containerRef: drawerRef,
6035
6110
  initialFocusRef: initialFocusRef || closeButtonRef,
6036
- disabled: !isOpen
6111
+ disabled: !isOpen,
6112
+ restoreFocusOnCleanUp: true
6037
6113
  });
6038
6114
  React.useEffect(() => {
6039
6115
  if (isOpen && isOutsideClickDismissable) {
@@ -6116,6 +6192,8 @@ const Drawer = ({
6116
6192
  className: `trk-drawer--${size} trk-drawer--${direction}`,
6117
6193
  ref: drawerRef,
6118
6194
  "aria-modal": 'true',
6195
+ "aria-label": ariaLabel,
6196
+ "aria-labelledby": ariaLabelledby,
6119
6197
  role: 'dialog',
6120
6198
  tabIndex: -1,
6121
6199
  size: size,
@@ -6134,6 +6212,7 @@ const Drawer = ({
6134
6212
  icon: icons.CloseIcon,
6135
6213
  variant: 'plain-bold',
6136
6214
  size: 'm',
6215
+ "aria-label": theme.locales?.Drawer?.closeButtonLabel ?? '닫기',
6137
6216
  onClick: handleDismiss
6138
6217
  })
6139
6218
  }), children]
@@ -6579,9 +6658,12 @@ const Flash = ({
6579
6658
  return /*#__PURE__*/jsxRuntime.jsxs(BaseFlash, {
6580
6659
  ref: ref,
6581
6660
  variant: variant,
6661
+ role: variant === 'danger' ? 'alert' : 'status',
6662
+ "aria-live": variant === 'danger' ? 'assertive' : 'polite',
6582
6663
  ...props,
6583
6664
  children: [/*#__PURE__*/jsxRuntime.jsx(Icon, {
6584
- className: 'flash__leading_icon'
6665
+ className: 'flash__leading_icon',
6666
+ "aria-hidden": true
6585
6667
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6586
6668
  className: 'flash__content',
6587
6669
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
@@ -6686,20 +6768,30 @@ const IconToggleButton = ({
6686
6768
  disabled = false,
6687
6769
  sx,
6688
6770
  ...props
6689
- }, ref) => /*#__PURE__*/jsxRuntime.jsx(BaseIconToggleButton, {
6690
- ref: ref,
6691
- icon: Icon,
6692
- size: size,
6693
- shape: shape,
6694
- variant: variant,
6695
- selected: selected,
6696
- type: 'button',
6697
- disabled: disabled,
6698
- $disabled: disabled,
6699
- sx: sx,
6700
- ...props,
6701
- children: /*#__PURE__*/jsxRuntime.jsx(Icon, {})
6702
- });
6771
+ }, ref) => {
6772
+ const hasAccessibleName = Boolean(props['aria-label'] || props['aria-labelledby'] || props['title']);
6773
+ React.useEffect(() => {
6774
+ if (process.env.NODE_ENV !== 'production' && !hasAccessibleName) {
6775
+ // eslint-disable-next-line no-console
6776
+ console.warn('IconToggleButton: An icon-only button should provide an accessible name via `aria-label`, `aria-labelledby`, or `title` so that assistive technologies can identify it.');
6777
+ }
6778
+ }, [hasAccessibleName]);
6779
+ return /*#__PURE__*/jsxRuntime.jsx(BaseIconToggleButton, {
6780
+ ref: ref,
6781
+ icon: Icon,
6782
+ size: size,
6783
+ shape: shape,
6784
+ variant: variant,
6785
+ selected: selected,
6786
+ "aria-pressed": selected,
6787
+ type: 'button',
6788
+ disabled: disabled,
6789
+ $disabled: disabled,
6790
+ sx: sx,
6791
+ ...props,
6792
+ children: /*#__PURE__*/jsxRuntime.jsx(Icon, {})
6793
+ });
6794
+ };
6703
6795
  const BaseIconToggleButton = /*#__PURE__*/styled__default.default(UnstyledButton).withConfig({
6704
6796
  displayName: "IconToggleButton__BaseIconToggleButton",
6705
6797
  componentId: "sc-1y68w0-0"
@@ -7307,6 +7399,7 @@ const TabItem = ({
7307
7399
  className: 'trk-tab_item',
7308
7400
  type: 'button',
7309
7401
  role: 'tab',
7402
+ "aria-selected": selected,
7310
7403
  ref: ref,
7311
7404
  variant: variant,
7312
7405
  size: size,
@@ -7587,6 +7680,7 @@ const Tab = ({
7587
7680
  size: 's',
7588
7681
  variant: 'plain-bold',
7589
7682
  icon: icons.ChevronLeftIcon,
7683
+ "aria-label": theme.locales?.Tab?.scrollLeftLabel ?? '왼쪽으로 스크롤',
7590
7684
  onClick: handleLeftButtonClick
7591
7685
  })
7592
7686
  })]
@@ -7618,6 +7712,7 @@ const Tab = ({
7618
7712
  size: 's',
7619
7713
  variant: 'plain-bold',
7620
7714
  icon: icons.ChevronRightIcon,
7715
+ "aria-label": theme.locales?.Tab?.scrollRightLabel ?? '오른쪽으로 스크롤',
7621
7716
  onClick: handleRightButtonClick
7622
7717
  })
7623
7718
  })]
@@ -7660,6 +7755,16 @@ const theme = {
7660
7755
  UploadInput: {
7661
7756
  placeholder: '파일을 끌어다 놓으세요',
7662
7757
  selectFile: '파일 선택'
7758
+ },
7759
+ Dialog: {
7760
+ closeButtonLabel: '닫기'
7761
+ },
7762
+ Drawer: {
7763
+ closeButtonLabel: '닫기'
7764
+ },
7765
+ Tab: {
7766
+ scrollLeftLabel: '왼쪽으로 스크롤',
7767
+ scrollRightLabel: '오른쪽으로 스크롤'
7663
7768
  }
7664
7769
  }
7665
7770
  };
@@ -7697,13 +7802,18 @@ const Toast = ({
7697
7802
  variant = 'success',
7698
7803
  icon: Icon = variant === 'success' ? icons.CheckInCircleIcon : icons.ExclamationPointInCircleIcon,
7699
7804
  resizing = 'hug',
7700
- children
7805
+ children,
7806
+ ...props
7701
7807
  }) => {
7702
7808
  return /*#__PURE__*/jsxRuntime.jsxs(BaseToast, {
7703
7809
  variant: variant,
7704
7810
  resizing: resizing,
7811
+ role: variant === 'warning' ? 'alert' : 'status',
7812
+ "aria-live": variant === 'warning' ? 'assertive' : 'polite',
7813
+ ...props,
7705
7814
  children: [/*#__PURE__*/jsxRuntime.jsx(Icon, {
7706
- className: 'toast__leading_icon'
7815
+ className: 'toast__leading_icon',
7816
+ "aria-hidden": true
7707
7817
  }), children]
7708
7818
  });
7709
7819
  };
@@ -330,6 +330,16 @@ declare const theme: {
330
330
  placeholder: string;
331
331
  selectFile: string;
332
332
  };
333
+ Dialog: {
334
+ closeButtonLabel: string;
335
+ };
336
+ Drawer: {
337
+ closeButtonLabel: string;
338
+ };
339
+ Tab: {
340
+ scrollLeftLabel: string;
341
+ scrollRightLabel: string;
342
+ };
333
343
  };
334
344
  };
335
345
  declare const gpaiLightTheme: {
@@ -664,6 +674,16 @@ declare const gpaiLightTheme: {
664
674
  placeholder: string;
665
675
  selectFile: string;
666
676
  };
677
+ Dialog: {
678
+ closeButtonLabel: string;
679
+ };
680
+ Drawer: {
681
+ closeButtonLabel: string;
682
+ };
683
+ Tab: {
684
+ scrollLeftLabel: string;
685
+ scrollRightLabel: string;
686
+ };
667
687
  };
668
688
  };
669
689
  declare const gpaiDarkTheme: {
@@ -998,6 +1018,16 @@ declare const gpaiDarkTheme: {
998
1018
  placeholder: string;
999
1019
  selectFile: string;
1000
1020
  };
1021
+ Dialog: {
1022
+ closeButtonLabel: string;
1023
+ };
1024
+ Drawer: {
1025
+ closeButtonLabel: string;
1026
+ };
1027
+ Tab: {
1028
+ scrollLeftLabel: string;
1029
+ scrollRightLabel: string;
1030
+ };
1001
1031
  };
1002
1032
  };
1003
1033
  export default theme;
@@ -7,16 +7,26 @@ const ClickArea = ({
7
7
  disabled,
8
8
  onClick,
9
9
  ...props
10
- }, ref) => /*#__PURE__*/jsx(BaseClickArea, {
11
- ref: ref,
12
- ...props,
13
- role: 'button',
14
- "aria-disabled": disabled,
15
- disabled: disabled,
16
- ...(!disabled ? {
17
- onClick
18
- } : {})
19
- });
10
+ }, ref) => {
11
+ const handleKeyDown = e => {
12
+ if (e.key === 'Enter' || e.key === ' ') {
13
+ e.preventDefault();
14
+ e.currentTarget.click();
15
+ }
16
+ };
17
+ return /*#__PURE__*/jsx(BaseClickArea, {
18
+ ref: ref,
19
+ ...props,
20
+ role: 'button',
21
+ tabIndex: disabled ? -1 : 0,
22
+ "aria-disabled": disabled,
23
+ disabled: disabled,
24
+ ...(!disabled ? {
25
+ onClick,
26
+ onKeyDown: handleKeyDown
27
+ } : {})
28
+ });
29
+ };
20
30
  const BaseClickArea = /*#__PURE__*/styled(View).withConfig({
21
31
  displayName: "ClickArea__BaseClickArea",
22
32
  componentId: "sc-1pd8ned-0"
@@ -40,6 +40,7 @@ const DescriptionList = ({
40
40
  children: [/*#__PURE__*/jsx(Grid.Unit, {
41
41
  size: titleUnitSize,
42
42
  children: /*#__PURE__*/jsxs(View, {
43
+ role: 'term',
43
44
  display: 'flex',
44
45
  alignItems: 'center',
45
46
  flexWrap: 'nowrap',
@@ -54,7 +55,10 @@ const DescriptionList = ({
54
55
  })
55
56
  }), /*#__PURE__*/jsx(Grid.Unit, {
56
57
  size: descriptionUnitSize,
57
- children: renderDescription(!isNullable(description) ? description : '-')
58
+ children: /*#__PURE__*/jsx(View, {
59
+ role: 'definition',
60
+ children: renderDescription(!isNullable(description) ? description : '-')
61
+ })
58
62
  })]
59
63
  });
60
64
  },
@@ -191,6 +191,7 @@ const Dialog = ({
191
191
  icon: CloseIcon,
192
192
  variant: 'plain-bold',
193
193
  size: 'm',
194
+ "aria-label": theme.locales?.Dialog?.closeButtonLabel ?? '닫기',
194
195
  onClick: handleDismiss
195
196
  })
196
197
  }), /*#__PURE__*/jsx(DialogContext.Provider, {
@@ -27,6 +27,8 @@ const Drawer = ({
27
27
  size = 'm',
28
28
  direction = 'right',
29
29
  initialFocusRef,
30
+ 'aria-label': ariaLabel,
31
+ 'aria-labelledby': ariaLabelledby,
30
32
  sx
31
33
  }, ref) => {
32
34
  const theme = useTheme();
@@ -51,7 +53,8 @@ const Drawer = ({
51
53
  useFocusTrap({
52
54
  containerRef: drawerRef,
53
55
  initialFocusRef: initialFocusRef || closeButtonRef,
54
- disabled: !isOpen
56
+ disabled: !isOpen,
57
+ restoreFocusOnCleanUp: true
55
58
  });
56
59
  useEffect(() => {
57
60
  if (isOpen && isOutsideClickDismissable) {
@@ -134,6 +137,8 @@ const Drawer = ({
134
137
  className: `trk-drawer--${size} trk-drawer--${direction}`,
135
138
  ref: drawerRef,
136
139
  "aria-modal": 'true',
140
+ "aria-label": ariaLabel,
141
+ "aria-labelledby": ariaLabelledby,
137
142
  role: 'dialog',
138
143
  tabIndex: -1,
139
144
  size: size,
@@ -152,6 +157,7 @@ const Drawer = ({
152
157
  icon: CloseIcon,
153
158
  variant: 'plain-bold',
154
159
  size: 'm',
160
+ "aria-label": theme.locales?.Drawer?.closeButtonLabel ?? '닫기',
155
161
  onClick: handleDismiss
156
162
  })
157
163
  }), children]
@@ -20,9 +20,12 @@ const Flash = ({
20
20
  return /*#__PURE__*/jsxs(BaseFlash, {
21
21
  ref: ref,
22
22
  variant: variant,
23
+ role: variant === 'danger' ? 'alert' : 'status',
24
+ "aria-live": variant === 'danger' ? 'assertive' : 'polite',
23
25
  ...props,
24
26
  children: [/*#__PURE__*/jsx(Icon, {
25
- className: 'flash__leading_icon'
27
+ className: 'flash__leading_icon',
28
+ "aria-hidden": true
26
29
  }), /*#__PURE__*/jsxs("div", {
27
30
  className: 'flash__content',
28
31
  children: [/*#__PURE__*/jsx("span", {
@@ -7,11 +7,11 @@ const FormControlCaption = ({
7
7
  children
8
8
  }) => {
9
9
  const {
10
- id
10
+ captionId
11
11
  } = useContext(FormControlContext);
12
12
  return /*#__PURE__*/jsx(Text, {
13
13
  as: 'span',
14
- id: id,
14
+ id: captionId,
15
15
  typography: 'xxs',
16
16
  color: 'text/neutral/subtlest',
17
17
  children: children
@@ -8,10 +8,11 @@ const FormControlErrorMessage = ({
8
8
  children
9
9
  }) => {
10
10
  const {
11
- id
11
+ errorId
12
12
  } = useContext(FormControlContext);
13
13
  return /*#__PURE__*/jsx(StyledText, {
14
- id: id,
14
+ id: errorId,
15
+ role: 'alert',
15
16
  typography: 'xxs',
16
17
  color: 'text/danger',
17
18
  children: children
@@ -8,10 +8,11 @@ const FormControlSuccessMessage = ({
8
8
  children
9
9
  }) => {
10
10
  const {
11
- id
11
+ successId
12
12
  } = useContext(FormControlContext);
13
13
  return /*#__PURE__*/jsx(StyledText, {
14
- id: id,
14
+ id: successId,
15
+ role: 'status',
15
16
  typography: 'xxs',
16
17
  color: 'text/success',
17
18
  children: children
@@ -1,4 +1,4 @@
1
- import { forwardRef, createContext, isValidElement, cloneElement } from 'react';
1
+ import { forwardRef, createContext, isValidElement, useId, cloneElement } from 'react';
2
2
  import useRelocation from '../../hook/useRelocation.js';
3
3
  import Checkbox from '../Checkbox/index.js';
4
4
  import Radio from '../Radio/index.js';
@@ -38,11 +38,35 @@ const FormControl = ({
38
38
  const inputComponentCandidates = [TextInput, Textarea, Select, SearchSelectInput, Checkbox, Radio, Switch, ...additionalInputComponentCandidates];
39
39
  const InputComponent = restComponents.find(component => inputComponentCandidates.some(candidate => /*#__PURE__*/isValidElement(component) && component.type === candidate));
40
40
  const isHorizontalLayoutNeeded = /*#__PURE__*/isValidElement(InputComponent) && (InputComponent.type === Checkbox || InputComponent.type === Radio || InputComponent.type === Switch);
41
+ const reactId = useId();
42
+ const resolvedId = id ?? reactId;
43
+ const captionId = `${resolvedId}-caption`;
44
+ const errorId = `${resolvedId}-error`;
45
+ const successId = `${resolvedId}-success`;
46
+ const hasCaption = Boolean(relocatableComponentsObject.caption);
47
+ const hasError = Boolean(relocatableComponentsObject.errorMessage);
48
+ const hasSuccess = Boolean(relocatableComponentsObject.successMessage);
49
+
50
+ /**
51
+ * 소비자가 Input에 직접 전달한 aria 값을 보존하기 위해 기존 props와 병합합니다.
52
+ */
53
+ const inputProps = /*#__PURE__*/isValidElement(InputComponent) ? InputComponent.props : {};
54
+ const describedBy = [inputProps['aria-describedby'], hasCaption && captionId, hasError && errorId, hasSuccess && successId].filter(Boolean).join(' ') || undefined;
55
+ const inputA11yProps = {
56
+ 'id': resolvedId,
57
+ disabled,
58
+ 'aria-invalid': hasError ? true : inputProps['aria-invalid'],
59
+ 'aria-required': required ? true : inputProps['aria-required'],
60
+ 'aria-describedby': describedBy
61
+ };
41
62
  return /*#__PURE__*/jsx(FormControlContext.Provider, {
42
63
  value: {
43
- id,
64
+ id: resolvedId,
44
65
  disabled,
45
- required
66
+ required,
67
+ captionId,
68
+ errorId,
69
+ successId
46
70
  },
47
71
  children: isHorizontalLayoutNeeded ? /*#__PURE__*/jsxs(View, {
48
72
  ref: ref,
@@ -54,10 +78,7 @@ const FormControl = ({
54
78
  ...props,
55
79
  children: [/*#__PURE__*/jsx(View, {
56
80
  display: 'inline-flex',
57
- children: /*#__PURE__*/cloneElement(InputComponent, {
58
- id,
59
- disabled
60
- })
81
+ children: /*#__PURE__*/cloneElement(InputComponent, inputA11yProps)
61
82
  }), /*#__PURE__*/jsxs(View, {
62
83
  sx: {
63
84
  '& > span': {
@@ -96,10 +117,7 @@ const FormControl = ({
96
117
  columnGap: 1
97
118
  },
98
119
  children: [relocatableComponentsObject.label, relocatableComponentsObject.tooltipIcon]
99
- }), /*#__PURE__*/cloneElement(InputComponent, {
100
- id,
101
- disabled
102
- }), relocatableComponentsObject.caption, relocatableComponentsObject.errorMessage, relocatableComponentsObject.successMessage]
120
+ }), /*#__PURE__*/cloneElement(InputComponent, inputA11yProps), relocatableComponentsObject.caption, relocatableComponentsObject.errorMessage, relocatableComponentsObject.successMessage]
103
121
  })
104
122
  });
105
123
  };
@@ -1,4 +1,4 @@
1
- import { forwardRef } from 'react';
1
+ import { forwardRef, useEffect } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import '../../node_modules/styled-system/dist/index.esm.js';
4
4
  import Spinner from '../Spinner/index.js';
@@ -14,6 +14,13 @@ const IconButton = /*#__PURE__*/forwardRef(({
14
14
  loading = false,
15
15
  ...props
16
16
  }, ref) => {
17
+ const hasAccessibleName = Boolean(props['aria-label'] || props['aria-labelledby'] || props['title']);
18
+ useEffect(() => {
19
+ if (process.env.NODE_ENV !== 'production' && !hasAccessibleName) {
20
+ // eslint-disable-next-line no-console
21
+ console.warn('IconButton: An icon-only button should provide an accessible name via `aria-label`, `aria-labelledby`, or `title` so that assistive technologies can identify it.');
22
+ }
23
+ }, [hasAccessibleName]);
17
24
  return /*#__PURE__*/jsx(BaseIconButton, {
18
25
  ref: ref,
19
26
  icon: Icon,
@@ -1,4 +1,4 @@
1
- import { forwardRef } from 'react';
1
+ import { forwardRef, useEffect } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import '../../node_modules/styled-system/dist/index.esm.js';
4
4
  import { sx } from '../../utils/styled-system/index.js';
@@ -15,20 +15,30 @@ const IconToggleButton = ({
15
15
  disabled = false,
16
16
  sx,
17
17
  ...props
18
- }, ref) => /*#__PURE__*/jsx(BaseIconToggleButton, {
19
- ref: ref,
20
- icon: Icon,
21
- size: size,
22
- shape: shape,
23
- variant: variant,
24
- selected: selected,
25
- type: 'button',
26
- disabled: disabled,
27
- $disabled: disabled,
28
- sx: sx,
29
- ...props,
30
- children: /*#__PURE__*/jsx(Icon, {})
31
- });
18
+ }, ref) => {
19
+ const hasAccessibleName = Boolean(props['aria-label'] || props['aria-labelledby'] || props['title']);
20
+ useEffect(() => {
21
+ if (process.env.NODE_ENV !== 'production' && !hasAccessibleName) {
22
+ // eslint-disable-next-line no-console
23
+ console.warn('IconToggleButton: An icon-only button should provide an accessible name via `aria-label`, `aria-labelledby`, or `title` so that assistive technologies can identify it.');
24
+ }
25
+ }, [hasAccessibleName]);
26
+ return /*#__PURE__*/jsx(BaseIconToggleButton, {
27
+ ref: ref,
28
+ icon: Icon,
29
+ size: size,
30
+ shape: shape,
31
+ variant: variant,
32
+ selected: selected,
33
+ "aria-pressed": selected,
34
+ type: 'button',
35
+ disabled: disabled,
36
+ $disabled: disabled,
37
+ sx: sx,
38
+ ...props,
39
+ children: /*#__PURE__*/jsx(Icon, {})
40
+ });
41
+ };
32
42
  const BaseIconToggleButton = /*#__PURE__*/styled(UnstyledButton).withConfig({
33
43
  displayName: "IconToggleButton__BaseIconToggleButton",
34
44
  componentId: "sc-1y68w0-0"
@@ -71,10 +71,10 @@ const Overlay = ({
71
71
  }, [isOpen, handleOutsideClick]);
72
72
  return isOpen ? /*#__PURE__*/jsx(BaseOverlay, {
73
73
  ref: overlayRef,
74
+ role: 'dialog',
74
75
  size: size,
75
76
  maxHeight: maxHeight,
76
77
  ...props,
77
- role: 'dialog',
78
78
  children: children
79
79
  }) : null;
80
80
  };
@@ -163,7 +163,9 @@ const SearchSelectInput = ({
163
163
  }, overlayHandler)
164
164
  })]
165
165
  }),
166
- children: popperProps => /*#__PURE__*/jsxs(TextInputWrapper, {
166
+ children: (popperProps, {
167
+ isOpen
168
+ }) => /*#__PURE__*/jsxs(TextInputWrapper, {
167
169
  ...(disabled ? {} : {
168
170
  ...popperProps,
169
171
  onClick: e => {
@@ -214,6 +216,9 @@ const SearchSelectInput = ({
214
216
  }) : null, /*#__PURE__*/jsx(BaseInput, {
215
217
  id: id,
216
218
  ref: labelInputRef,
219
+ role: 'combobox',
220
+ "aria-haspopup": 'listbox',
221
+ "aria-expanded": isOpen,
217
222
  readOnly: true,
218
223
  onChange: noop,
219
224
  autoComplete: 'off',
@@ -27,6 +27,7 @@ const Spinner = /*#__PURE__*/forwardRef(({
27
27
  variant: propsVariant,
28
28
  width = 32,
29
29
  height = 32,
30
+ label = '로딩 중',
30
31
  ...props
31
32
  }, ref) => {
32
33
  const theme = useTheme();
@@ -35,10 +36,18 @@ const Spinner = /*#__PURE__*/forwardRef(({
35
36
  'progress-gradient': ProgressGradientSpinner,
36
37
  'progress-line': ProgressLineSpinner
37
38
  }[variant];
39
+ const a11yProps = label ? {
40
+ 'role': 'status',
41
+ 'aria-label': label,
42
+ 'aria-busy': true
43
+ } : {
44
+ 'aria-hidden': true
45
+ };
38
46
  return /*#__PURE__*/jsx(SpinnerComponent, {
39
47
  ref: ref,
40
48
  width: width,
41
49
  height: height,
50
+ ...a11yProps,
42
51
  ...props
43
52
  });
44
53
  });
@@ -3,24 +3,40 @@ import View from '../View/index.js';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
5
5
  const StyledIcon = /*#__PURE__*/forwardRef(({
6
- icon: Icon,
6
+ 'icon': Icon,
7
7
  sx,
8
8
  className,
9
+ 'aria-label': ariaLabel,
10
+ 'aria-hidden': ariaHidden,
9
11
  ...props
10
- }, ref) => /*#__PURE__*/jsx(View, {
11
- ref: ref,
12
- ...props,
13
- className: `trk-styled_icon__wrapper ${className}`,
14
- color: props.color,
15
- sx: {
16
- '& svg': {
17
- display: 'inline-flex',
18
- width: '100%',
19
- height: '100%'
12
+ }, ref) => {
13
+ /**
14
+ * 기본적으로 장식용 아이콘으로 간주해 `aria-hidden`을 부여합니다.
15
+ * 의미 있는 아이콘이라면 `aria-label`을 전달하세요. (`role="img"`로 노출됩니다.)
16
+ */
17
+ const a11yProps = ariaLabel ? {
18
+ 'role': 'img',
19
+ 'aria-label': ariaLabel,
20
+ 'aria-hidden': ariaHidden
21
+ } : {
22
+ 'aria-hidden': ariaHidden ?? true
23
+ };
24
+ return /*#__PURE__*/jsx(View, {
25
+ ref: ref,
26
+ ...props,
27
+ ...a11yProps,
28
+ className: `trk-styled_icon__wrapper ${className}`,
29
+ color: props.color,
30
+ sx: {
31
+ '& svg': {
32
+ display: 'inline-flex',
33
+ width: '100%',
34
+ height: '100%'
35
+ },
36
+ ...sx
20
37
  },
21
- ...sx
22
- },
23
- children: /*#__PURE__*/jsx(Icon, {})
24
- }));
38
+ children: /*#__PURE__*/jsx(Icon, {})
39
+ });
40
+ });
25
41
 
26
42
  export { StyledIcon as default };
@@ -13,6 +13,7 @@ const Switch = ({
13
13
  const checkboxRef = useProvidedOrCreatedRef(ref);
14
14
  return /*#__PURE__*/jsx(BaseSwitch, {
15
15
  ref: checkboxRef,
16
+ role: 'switch',
16
17
  checked: checked,
17
18
  validationStatus: validationStatus,
18
19
  ...props
@@ -41,6 +41,7 @@ const TabItem = ({
41
41
  className: 'trk-tab_item',
42
42
  type: 'button',
43
43
  role: 'tab',
44
+ "aria-selected": selected,
44
45
  ref: ref,
45
46
  variant: variant,
46
47
  size: size,
@@ -108,6 +108,7 @@ const Tab = ({
108
108
  size: 's',
109
109
  variant: 'plain-bold',
110
110
  icon: ChevronLeftIcon,
111
+ "aria-label": theme.locales?.Tab?.scrollLeftLabel ?? '왼쪽으로 스크롤',
111
112
  onClick: handleLeftButtonClick
112
113
  })
113
114
  })]
@@ -139,6 +140,7 @@ const Tab = ({
139
140
  size: 's',
140
141
  variant: 'plain-bold',
141
142
  icon: ChevronRightIcon,
143
+ "aria-label": theme.locales?.Tab?.scrollRightLabel ?? '오른쪽으로 스크롤',
142
144
  onClick: handleRightButtonClick
143
145
  })
144
146
  })]
@@ -8,13 +8,18 @@ const Toast = ({
8
8
  variant = 'success',
9
9
  icon: Icon = variant === 'success' ? CheckInCircleIcon : ExclamationPointInCircleIcon,
10
10
  resizing = 'hug',
11
- children
11
+ children,
12
+ ...props
12
13
  }) => {
13
14
  return /*#__PURE__*/jsxs(BaseToast, {
14
15
  variant: variant,
15
16
  resizing: resizing,
17
+ role: variant === 'warning' ? 'alert' : 'status',
18
+ "aria-live": variant === 'warning' ? 'assertive' : 'polite',
19
+ ...props,
16
20
  children: [/*#__PURE__*/jsx(Icon, {
17
- className: 'toast__leading_icon'
21
+ className: 'toast__leading_icon',
22
+ "aria-hidden": true
18
23
  }), children]
19
24
  });
20
25
  };
@@ -30,6 +30,16 @@ const theme = {
30
30
  UploadInput: {
31
31
  placeholder: '파일을 끌어다 놓으세요',
32
32
  selectFile: '파일 선택'
33
+ },
34
+ Dialog: {
35
+ closeButtonLabel: '닫기'
36
+ },
37
+ Drawer: {
38
+ closeButtonLabel: '닫기'
39
+ },
40
+ Tab: {
41
+ scrollLeftLabel: '왼쪽으로 스크롤',
42
+ scrollRightLabel: '오른쪽으로 스크롤'
33
43
  }
34
44
  }
35
45
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamturing/react-kit",
3
- "version": "2.75.0",
3
+ "version": "2.76.0",
4
4
  "description": "React components, hooks for create teamturing web application",
5
5
  "author": "Sungchang Park <psch300@gmail.com> (https://github.com/psch300)",
6
6
  "homepage": "https://github.com/weareteamturing/bombe#readme",
@@ -65,5 +65,5 @@
65
65
  "react-textarea-autosize": "^8.5.3",
66
66
  "styled-system": "^5.1.5"
67
67
  },
68
- "gitHead": "dfe41b5bceb6209a01bc7fe08d2cb52ac8447a4e"
68
+ "gitHead": "786f4e6ff9bd2f7324b536c7872cf06eb4b0b3b6"
69
69
  }