@teamturing/react-kit 2.74.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.
Files changed (41) hide show
  1. package/dist/core/Datagrid/DatagridBody.d.ts +3 -3
  2. package/dist/core/Datagrid/DatagridCell.d.ts +8 -3
  3. package/dist/core/Datagrid/DatagridHeader.d.ts +2 -2
  4. package/dist/core/Datagrid/DatagridRow.d.ts +8 -3
  5. package/dist/core/Datagrid/DatagridRowList.d.ts +21 -0
  6. package/dist/core/Datagrid/index.d.ts +9 -5
  7. package/dist/core/Drawer/index.d.ts +3 -3
  8. package/dist/core/FormControl/index.d.ts +9 -2
  9. package/dist/core/Grid/index.d.ts +4 -4
  10. package/dist/core/Spinner/index.d.ts +12 -0
  11. package/dist/core/StyledIcon/index.d.ts +2 -2
  12. package/dist/core/Toast/index.d.ts +3 -3
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +251 -77
  15. package/dist/theme/index.d.ts +30 -0
  16. package/esm/core/ClickArea/index.js +20 -10
  17. package/esm/core/Datagrid/DatagridBody.js +2 -0
  18. package/esm/core/Datagrid/DatagridCell.js +3 -0
  19. package/esm/core/Datagrid/DatagridRow.js +13 -2
  20. package/esm/core/Datagrid/DatagridRowList.js +33 -0
  21. package/esm/core/Datagrid/index.js +26 -1
  22. package/esm/core/DescriptionList/index.js +5 -1
  23. package/esm/core/Dialog/index.js +1 -0
  24. package/esm/core/Drawer/index.js +7 -1
  25. package/esm/core/Flash/index.js +4 -1
  26. package/esm/core/FormControl/FormControlCaption.js +2 -2
  27. package/esm/core/FormControl/FormControlErrorMessage.js +3 -2
  28. package/esm/core/FormControl/FormControlSuccessMessage.js +3 -2
  29. package/esm/core/FormControl/index.js +29 -11
  30. package/esm/core/IconButton/index.js +8 -1
  31. package/esm/core/IconToggleButton/index.js +25 -15
  32. package/esm/core/Overlay/index.js +1 -1
  33. package/esm/core/SearchSelectInput/index.js +6 -1
  34. package/esm/core/Spinner/index.js +9 -0
  35. package/esm/core/StyledIcon/index.js +31 -15
  36. package/esm/core/Switch/index.js +1 -0
  37. package/esm/core/Tab/TabItem.js +1 -0
  38. package/esm/core/Tab/index.js +2 -0
  39. package/esm/core/Toast/index.js +7 -2
  40. package/esm/theme/index.js +10 -0
  41. package/package.json +2 -2
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"
@@ -5103,8 +5164,10 @@ const BaseCounterBadge = /*#__PURE__*/styled__default.default.span.withConfig({
5103
5164
  }), sx);
5104
5165
 
5105
5166
  const DatagridBody = ({
5167
+ role,
5106
5168
  ...props
5107
5169
  }) => /*#__PURE__*/jsxRuntime.jsx(BaseDatagridBody, {
5170
+ role: role ?? 'rowgroup',
5108
5171
  ...props
5109
5172
  });
5110
5173
  const BaseDatagridBody = /*#__PURE__*/styled__default.default.div.withConfig({
@@ -5116,8 +5179,11 @@ const BaseDatagridBody = /*#__PURE__*/styled__default.default.div.withConfig({
5116
5179
 
5117
5180
  const DatagridCell = ({
5118
5181
  children,
5182
+ columnHeader = false,
5183
+ role,
5119
5184
  ...props
5120
5185
  }) => /*#__PURE__*/jsxRuntime.jsx(BaseDatagridCell, {
5186
+ role: role ?? (columnHeader ? 'columnheader' : 'cell'),
5121
5187
  ...props,
5122
5188
  children: children
5123
5189
  });
@@ -5154,21 +5220,69 @@ const DatagridRow = ({
5154
5220
  gapX = 2,
5155
5221
  alignItems,
5156
5222
  justifyContent,
5223
+ columnHeader = false,
5224
+ role,
5157
5225
  children,
5158
5226
  ...props
5159
- }) => /*#__PURE__*/jsxRuntime.jsx(DatagridRowWrapper, {
5227
+ }) =>
5228
+ /*#__PURE__*/
5229
+ // 외부 wrapper가 `rowgroup`의 직접 자식이 되도록 여기에 role="row"를 부여하고,
5230
+ // 셀을 직접 감싸는 내부 Grid는 presentation 처리하여 row가 cell을 직접 소유하도록 한다.
5231
+ jsxRuntime.jsx(DatagridRowWrapper, {
5232
+ role: role ?? 'row',
5160
5233
  ...props,
5161
5234
  children: /*#__PURE__*/jsxRuntime.jsx(BaseDatagridRow, {
5235
+ role: 'presentation',
5162
5236
  wrap: false,
5163
5237
  gapX: gapX,
5164
5238
  alignItems: alignItems,
5165
5239
  justifyContent: justifyContent,
5166
- children: children
5240
+ children: columnHeader ? React.Children.map(children, child => /*#__PURE__*/React.isValidElement(child) ? /*#__PURE__*/React.cloneElement(child, {
5241
+ columnHeader: child.props.columnHeader ?? true
5242
+ }) : child) : children
5167
5243
  })
5168
5244
  });
5169
5245
  const BaseDatagridRow = Grid$1;
5170
5246
  const DatagridRowWrapper = Space;
5171
5247
 
5248
+ const ItemList = ({
5249
+ items,
5250
+ renderItem,
5251
+ renderItemWrapper = children => children,
5252
+ emptyState = null
5253
+ }) => {
5254
+ if (items.length === 0) return emptyState;
5255
+ return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
5256
+ children: items.map((item, i) => renderItemWrapper(renderItem(item, i), item, i))
5257
+ });
5258
+ };
5259
+
5260
+ const DatagridRowList = ({
5261
+ rows,
5262
+ columns,
5263
+ rowProps = {
5264
+ alignItems: 'center'
5265
+ },
5266
+ renderItemWrapper,
5267
+ emptyState,
5268
+ columnsTransformer = columns => columns
5269
+ }) => /*#__PURE__*/jsxRuntime.jsx(ItemList, {
5270
+ items: rows,
5271
+ renderItem: (row, i) => /*#__PURE__*/jsxRuntime.jsx(DatagridRow, {
5272
+ ...rowProps,
5273
+ children: columnsTransformer(columns).filter(column => !utils.isNullable(column)).map(({
5274
+ field,
5275
+ renderValue,
5276
+ size
5277
+ }) => /*#__PURE__*/jsxRuntime.jsx(DatagridCell, {
5278
+ size: size,
5279
+ children: renderValue(row, i)
5280
+ }, field))
5281
+ }, row.id),
5282
+ renderItemWrapper: renderItemWrapper,
5283
+ emptyState: emptyState
5284
+ });
5285
+
5172
5286
  const DatagridSubheader = ({
5173
5287
  ...props
5174
5288
  }) => /*#__PURE__*/jsxRuntime.jsx(DataGridSubheaderWrapper, {
@@ -5188,6 +5302,9 @@ const DataGridSubheaderWrapper = /*#__PURE__*/styled__default.default.div.withCo
5188
5302
  const Datagrid = ({
5189
5303
  children,
5190
5304
  sx,
5305
+ role = 'table',
5306
+ 'aria-label': ariaLabel,
5307
+ 'aria-labelledby': ariaLabelledby,
5191
5308
  ...props
5192
5309
  }) => {
5193
5310
  const [relocatableComponentsObject, restConmponents] = useRelocation({
@@ -5197,9 +5314,28 @@ const Datagrid = ({
5197
5314
  subHeader: DatagridSubheader
5198
5315
  }
5199
5316
  });
5317
+
5318
+ // Header가 있고 별도 라벨이 지정되지 않은 경우, Header를 표의 접근 가능한 이름으로 연결한다.
5319
+ const generatedHeaderId = React.useId();
5320
+ const {
5321
+ header: rawHeader,
5322
+ subHeader
5323
+ } = relocatableComponentsObject;
5324
+ let headerNode = rawHeader;
5325
+ let resolvedLabelledby = ariaLabelledby;
5326
+ if (!ariaLabel && !ariaLabelledby && /*#__PURE__*/React.isValidElement(rawHeader)) {
5327
+ const headerId = rawHeader.props.id ?? generatedHeaderId;
5328
+ headerNode = /*#__PURE__*/React.cloneElement(rawHeader, {
5329
+ id: headerId
5330
+ });
5331
+ resolvedLabelledby = headerId;
5332
+ }
5200
5333
  return /*#__PURE__*/jsxRuntime.jsxs(DatagridWrapper, {
5201
5334
  sx: sx,
5202
- children: [relocatableComponentsObject.header, relocatableComponentsObject.subHeader, /*#__PURE__*/jsxRuntime.jsx(BaseDatagrid, {
5335
+ children: [headerNode, subHeader, /*#__PURE__*/jsxRuntime.jsx(BaseDatagrid, {
5336
+ role: role,
5337
+ "aria-label": ariaLabel,
5338
+ "aria-labelledby": resolvedLabelledby,
5203
5339
  ...props,
5204
5340
  children: restConmponents
5205
5341
  })]
@@ -5222,21 +5358,10 @@ var index$9 = Object.assign(Datagrid, {
5222
5358
  Subheader: DatagridSubheader,
5223
5359
  Body: DatagridBody,
5224
5360
  Row: DatagridRow,
5361
+ RowList: DatagridRowList,
5225
5362
  Cell: DatagridCell
5226
5363
  });
5227
5364
 
5228
- const ItemList = ({
5229
- items,
5230
- renderItem,
5231
- renderItemWrapper = children => children,
5232
- emptyState = null
5233
- }) => {
5234
- if (items.length === 0) return emptyState;
5235
- return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
5236
- children: items.map((item, i) => renderItemWrapper(renderItem(item, i), item, i))
5237
- });
5238
- };
5239
-
5240
5365
  const DescriptionList = ({
5241
5366
  item,
5242
5367
  itemDescriptions,
@@ -5271,6 +5396,7 @@ const DescriptionList = ({
5271
5396
  children: [/*#__PURE__*/jsxRuntime.jsx(Grid$1.Unit, {
5272
5397
  size: titleUnitSize,
5273
5398
  children: /*#__PURE__*/jsxRuntime.jsxs(View, {
5399
+ role: 'term',
5274
5400
  display: 'flex',
5275
5401
  alignItems: 'center',
5276
5402
  flexWrap: 'nowrap',
@@ -5285,7 +5411,10 @@ const DescriptionList = ({
5285
5411
  })
5286
5412
  }), /*#__PURE__*/jsxRuntime.jsx(Grid$1.Unit, {
5287
5413
  size: descriptionUnitSize,
5288
- children: renderDescription(!utils.isNullable(description) ? description : '-')
5414
+ children: /*#__PURE__*/jsxRuntime.jsx(View, {
5415
+ role: 'definition',
5416
+ children: renderDescription(!utils.isNullable(description) ? description : '-')
5417
+ })
5289
5418
  })]
5290
5419
  });
5291
5420
  },
@@ -5306,6 +5435,13 @@ const IconButton = /*#__PURE__*/React.forwardRef(({
5306
5435
  loading = false,
5307
5436
  ...props
5308
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]);
5309
5445
  return /*#__PURE__*/jsxRuntime.jsx(BaseIconButton, {
5310
5446
  ref: ref,
5311
5447
  icon: Icon,
@@ -5800,6 +5936,7 @@ const Dialog = ({
5800
5936
  icon: icons.CloseIcon,
5801
5937
  variant: 'plain-bold',
5802
5938
  size: 'm',
5939
+ "aria-label": theme.locales?.Dialog?.closeButtonLabel ?? '닫기',
5803
5940
  onClick: handleDismiss
5804
5941
  })
5805
5942
  }), /*#__PURE__*/jsxRuntime.jsx(DialogContext.Provider, {
@@ -5945,6 +6082,8 @@ const Drawer = ({
5945
6082
  size = 'm',
5946
6083
  direction = 'right',
5947
6084
  initialFocusRef,
6085
+ 'aria-label': ariaLabel,
6086
+ 'aria-labelledby': ariaLabelledby,
5948
6087
  sx
5949
6088
  }, ref) => {
5950
6089
  const theme = styled.useTheme();
@@ -5969,7 +6108,8 @@ const Drawer = ({
5969
6108
  useFocusTrap({
5970
6109
  containerRef: drawerRef,
5971
6110
  initialFocusRef: initialFocusRef || closeButtonRef,
5972
- disabled: !isOpen
6111
+ disabled: !isOpen,
6112
+ restoreFocusOnCleanUp: true
5973
6113
  });
5974
6114
  React.useEffect(() => {
5975
6115
  if (isOpen && isOutsideClickDismissable) {
@@ -6052,6 +6192,8 @@ const Drawer = ({
6052
6192
  className: `trk-drawer--${size} trk-drawer--${direction}`,
6053
6193
  ref: drawerRef,
6054
6194
  "aria-modal": 'true',
6195
+ "aria-label": ariaLabel,
6196
+ "aria-labelledby": ariaLabelledby,
6055
6197
  role: 'dialog',
6056
6198
  tabIndex: -1,
6057
6199
  size: size,
@@ -6070,6 +6212,7 @@ const Drawer = ({
6070
6212
  icon: icons.CloseIcon,
6071
6213
  variant: 'plain-bold',
6072
6214
  size: 'm',
6215
+ "aria-label": theme.locales?.Drawer?.closeButtonLabel ?? '닫기',
6073
6216
  onClick: handleDismiss
6074
6217
  })
6075
6218
  }), children]
@@ -6515,9 +6658,12 @@ const Flash = ({
6515
6658
  return /*#__PURE__*/jsxRuntime.jsxs(BaseFlash, {
6516
6659
  ref: ref,
6517
6660
  variant: variant,
6661
+ role: variant === 'danger' ? 'alert' : 'status',
6662
+ "aria-live": variant === 'danger' ? 'assertive' : 'polite',
6518
6663
  ...props,
6519
6664
  children: [/*#__PURE__*/jsxRuntime.jsx(Icon, {
6520
- className: 'flash__leading_icon'
6665
+ className: 'flash__leading_icon',
6666
+ "aria-hidden": true
6521
6667
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6522
6668
  className: 'flash__content',
6523
6669
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
@@ -6622,20 +6768,30 @@ const IconToggleButton = ({
6622
6768
  disabled = false,
6623
6769
  sx,
6624
6770
  ...props
6625
- }, ref) => /*#__PURE__*/jsxRuntime.jsx(BaseIconToggleButton, {
6626
- ref: ref,
6627
- icon: Icon,
6628
- size: size,
6629
- shape: shape,
6630
- variant: variant,
6631
- selected: selected,
6632
- type: 'button',
6633
- disabled: disabled,
6634
- $disabled: disabled,
6635
- sx: sx,
6636
- ...props,
6637
- children: /*#__PURE__*/jsxRuntime.jsx(Icon, {})
6638
- });
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
+ };
6639
6795
  const BaseIconToggleButton = /*#__PURE__*/styled__default.default(UnstyledButton).withConfig({
6640
6796
  displayName: "IconToggleButton__BaseIconToggleButton",
6641
6797
  componentId: "sc-1y68w0-0"
@@ -7243,6 +7399,7 @@ const TabItem = ({
7243
7399
  className: 'trk-tab_item',
7244
7400
  type: 'button',
7245
7401
  role: 'tab',
7402
+ "aria-selected": selected,
7246
7403
  ref: ref,
7247
7404
  variant: variant,
7248
7405
  size: size,
@@ -7523,6 +7680,7 @@ const Tab = ({
7523
7680
  size: 's',
7524
7681
  variant: 'plain-bold',
7525
7682
  icon: icons.ChevronLeftIcon,
7683
+ "aria-label": theme.locales?.Tab?.scrollLeftLabel ?? '왼쪽으로 스크롤',
7526
7684
  onClick: handleLeftButtonClick
7527
7685
  })
7528
7686
  })]
@@ -7554,6 +7712,7 @@ const Tab = ({
7554
7712
  size: 's',
7555
7713
  variant: 'plain-bold',
7556
7714
  icon: icons.ChevronRightIcon,
7715
+ "aria-label": theme.locales?.Tab?.scrollRightLabel ?? '오른쪽으로 스크롤',
7557
7716
  onClick: handleRightButtonClick
7558
7717
  })
7559
7718
  })]
@@ -7596,6 +7755,16 @@ const theme = {
7596
7755
  UploadInput: {
7597
7756
  placeholder: '파일을 끌어다 놓으세요',
7598
7757
  selectFile: '파일 선택'
7758
+ },
7759
+ Dialog: {
7760
+ closeButtonLabel: '닫기'
7761
+ },
7762
+ Drawer: {
7763
+ closeButtonLabel: '닫기'
7764
+ },
7765
+ Tab: {
7766
+ scrollLeftLabel: '왼쪽으로 스크롤',
7767
+ scrollRightLabel: '오른쪽으로 스크롤'
7599
7768
  }
7600
7769
  }
7601
7770
  };
@@ -7633,13 +7802,18 @@ const Toast = ({
7633
7802
  variant = 'success',
7634
7803
  icon: Icon = variant === 'success' ? icons.CheckInCircleIcon : icons.ExclamationPointInCircleIcon,
7635
7804
  resizing = 'hug',
7636
- children
7805
+ children,
7806
+ ...props
7637
7807
  }) => {
7638
7808
  return /*#__PURE__*/jsxRuntime.jsxs(BaseToast, {
7639
7809
  variant: variant,
7640
7810
  resizing: resizing,
7811
+ role: variant === 'warning' ? 'alert' : 'status',
7812
+ "aria-live": variant === 'warning' ? 'assertive' : 'polite',
7813
+ ...props,
7641
7814
  children: [/*#__PURE__*/jsxRuntime.jsx(Icon, {
7642
- className: 'toast__leading_icon'
7815
+ className: 'toast__leading_icon',
7816
+ "aria-hidden": true
7643
7817
  }), children]
7644
7818
  });
7645
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"