@bigtablet/design-system 1.19.2 โ†’ 1.19.4

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.
package/README.md CHANGED
@@ -7,11 +7,16 @@
7
7
  [![npm version](https://img.shields.io/npm/v/@bigtablet/design-system.svg)](https://www.npmjs.com/package/@bigtablet/design-system)
8
8
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
9
  [![Test Coverage](https://img.shields.io/badge/coverage-86%25-brightgreen.svg)](https://github.com/Bigtablet/bigtablet-design-system/actions)
10
+ [![CI](https://github.com/Bigtablet/bigtablet-design-system/actions/workflows/ci.yml/badge.svg)](https://github.com/Bigtablet/bigtablet-design-system/actions/workflows/ci.yml)
11
+ [![Storybook](https://img.shields.io/badge/Storybook-FF4785?logo=storybook&logoColor=white)](https://bigtablet.github.io/bigtablet-design-system)
10
12
 
11
13
  [๐Ÿ‡ฐ๐Ÿ‡ท ํ•œ๊ตญ์–ด](./README_KR.md) ยท ๐Ÿ‡บ๐Ÿ‡ธ English
12
14
 
13
15
  The official design system of Bigtablet โ€” a unified UI library composed of Foundation (design tokens) and UI Components.
14
16
 
17
+ > **Note**: This is Bigtablet's in-house design system, open-sourced for community reference.
18
+ > External use is welcome, but minor versions may include breaking changes without prior notice.
19
+
15
20
  [GitHub](https://github.com/Bigtablet/bigtablet-design-system) ยท [NPM](https://www.npmjs.com/package/@bigtablet/design-system) ยท [Storybook](https://bigtablet.github.io/bigtablet-design-system)
16
21
 
17
22
  </div>
@@ -30,6 +35,7 @@ The official design system of Bigtablet โ€” a unified UI library composed of Fou
30
35
  | โ™ฟ **Accessibility** | Keyboard navigation, screen reader support, full ARIA attributes |
31
36
  | ๐Ÿงช **86% Coverage** | Stable test coverage powered by Vitest |
32
37
  | ๐ŸŽญ **Storybook** | Interactive documentation for all components |
38
+ | ๐ŸŽฏ **Zero Dependencies** | No bundled runtime dependencies โ€” peer deps only |
33
39
 
34
40
  ---
35
41
 
@@ -49,15 +55,17 @@ pnpm add @bigtablet/design-system
49
55
  **Peer Dependencies**
50
56
 
51
57
  ```bash
52
- npm install react react-dom lucide-react
58
+ npm install react@^19 react-dom@^19 "lucide-react@>=0.552.0"
53
59
  ```
54
60
 
55
- > Recommended for use with **React 18+** and **Next.js 13+**.
61
+ > Requires **React 19** and **lucide-react โ‰ฅ 0.552.0**. Compatible with **Next.js 13+**.
56
62
 
57
63
  ---
58
64
 
59
65
  ## Quick Start
60
66
 
67
+ > โš ๏ธ **Alert** and **Toast** require Providers at the root of your app โ€” see [Provider Setup](#provider-setup) below.
68
+
61
69
  ### Pure React
62
70
 
63
71
  ```tsx
package/dist/index.d.ts CHANGED
@@ -99,6 +99,8 @@ interface ToastProviderProps {
99
99
  children: React.ReactNode;
100
100
  /** ์ตœ๋Œ€ ๋™์‹œ ํ‘œ์‹œ ํ† ์ŠคํŠธ ์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: 5) */
101
101
  maxCount?: number;
102
+ /** ํ† ์ŠคํŠธ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์˜ aria-label (๊ธฐ๋ณธ๊ฐ’: "Close") */
103
+ closeAriaLabel?: string;
102
104
  }
103
105
  /**
104
106
  * ํ† ์ŠคํŠธ ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” Provider๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.
@@ -106,7 +108,7 @@ interface ToastProviderProps {
106
108
  * @param props Provider ์†์„ฑ
107
109
  * @returns ๋ Œ๋”๋ง๋œ Provider์™€ ํ† ์ŠคํŠธ ์ปจํ…Œ์ด๋„ˆ
108
110
  */
109
- declare const ToastProvider: ({ children, maxCount }: ToastProviderProps) => react_jsx_runtime.JSX.Element;
111
+ declare const ToastProvider: ({ children, maxCount, closeAriaLabel }: ToastProviderProps) => react_jsx_runtime.JSX.Element;
110
112
 
111
113
  /**
112
114
  * ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ํ›….
@@ -326,6 +328,12 @@ interface DatePickerProps {
326
328
  * @deprecated `fullWidth` ์‚ฌ์šฉ ๋˜๋Š” CSS๋กœ ์ฒ˜๋ฆฌ
327
329
  */
328
330
  width?: number | string;
331
+ /** ์—ฐ๋„ select์˜ aria-label ๋ฐ ๋นˆ ์˜ต์…˜ ํ…์ŠคํŠธ (๊ธฐ๋ณธ๊ฐ’: "Year") */
332
+ yearLabel?: string;
333
+ /** ์›” select์˜ aria-label ๋ฐ ๋นˆ ์˜ต์…˜ ํ…์ŠคํŠธ (๊ธฐ๋ณธ๊ฐ’: "Month") */
334
+ monthLabel?: string;
335
+ /** ์ผ select์˜ aria-label ๋ฐ ๋นˆ ์˜ต์…˜ ํ…์ŠคํŠธ (๊ธฐ๋ณธ๊ฐ’: "Day") */
336
+ dayLabel?: string;
329
337
  }
330
338
  /**
331
339
  * ์—ฐ/์›”/์ผ ์„ ํƒํ˜• ๋ฐ์ดํŠธ ํ”ผ์ปค๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.
@@ -333,7 +341,7 @@ interface DatePickerProps {
333
341
  * @param props ๋ฐ์ดํŠธ ํ”ผ์ปค ์†์„ฑ
334
342
  * @returns ๋ Œ๋”๋ง๋œ ๋ฐ์ดํŠธ ํ”ผ์ปค UI
335
343
  */
336
- declare const DatePicker: ({ label, value, onChange, mode, startYear, endYear, minDate, selectableRange, disabled, fullWidth, width, }: DatePickerProps) => react_jsx_runtime.JSX.Element;
344
+ declare const DatePicker: ({ label, value, onChange, mode, startYear, endYear, minDate, selectableRange, disabled, fullWidth, width, yearLabel, monthLabel, dayLabel, }: DatePickerProps) => react_jsx_runtime.JSX.Element;
337
345
 
338
346
  interface PaginationProps {
339
347
  /** ํ˜„์žฌ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (1-based) */
@@ -342,6 +350,10 @@ interface PaginationProps {
342
350
  totalPages: number;
343
351
  /** ํŽ˜์ด์ง€ ๋ณ€๊ฒฝ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ */
344
352
  onChange: (page: number) => void;
353
+ /** ์ด์ „ ํŽ˜์ด์ง€ ๋ฒ„ํŠผ aria-label (๊ธฐ๋ณธ๊ฐ’: "Previous page") */
354
+ prevLabel?: string;
355
+ /** ๋‹ค์Œ ํŽ˜์ด์ง€ ๋ฒ„ํŠผ aria-label (๊ธฐ๋ณธ๊ฐ’: "Next page") */
356
+ nextLabel?: string;
345
357
  }
346
358
  /**
347
359
  * ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๋ Œ๋”๋งํ•œ๋‹ค.
@@ -349,7 +361,7 @@ interface PaginationProps {
349
361
  * @param props ํŽ˜์ด์ง€๋„ค์ด์…˜ ์†์„ฑ
350
362
  * @returns ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€๋„ค์ด์…˜ UI
351
363
  */
352
- declare const Pagination: ({ page, totalPages, onChange }: PaginationProps) => react_jsx_runtime.JSX.Element;
364
+ declare const Pagination: ({ page, totalPages, onChange, prevLabel, nextLabel }: PaginationProps) => react_jsx_runtime.JSX.Element;
353
365
 
354
366
  interface ModalProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
355
367
  /** ๋ชจ๋‹ฌ ์—ด๋ฆผ ์—ฌ๋ถ€ */
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import './index.css';
3
- import * as React6 from 'react';
3
+ import * as React7 from 'react';
4
4
  import { createContext, useContext, useState, useCallback } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
  import { createPortal } from 'react-dom';
@@ -37,8 +37,8 @@ var FOCUSABLE_SELECTORS = [
37
37
  '[tabindex]:not([tabindex="-1"])'
38
38
  ].join(", ");
39
39
  function useFocusTrap(containerRef, isActive) {
40
- const previousActiveElement = React6.useRef(null);
41
- React6.useEffect(() => {
40
+ const previousActiveElement = React7.useRef(null);
41
+ React7.useEffect(() => {
42
42
  if (!isActive) return;
43
43
  const container = containerRef.current;
44
44
  if (!container) return;
@@ -168,6 +168,8 @@ var AlertModal = ({
168
168
  onCancel,
169
169
  onClose
170
170
  }) => {
171
+ const panelRef = React7.useRef(null);
172
+ useFocusTrap(panelRef, true);
171
173
  const modalClassName = [
172
174
  "alert_modal",
173
175
  `alert_variant_${variant}`
@@ -176,41 +178,50 @@ var AlertModal = ({
176
178
  "alert_actions",
177
179
  `alert_actions_${actionsAlign}`
178
180
  ].filter(Boolean).join(" ");
179
- return /* @__PURE__ */ jsx("div", { className: "alert_overlay", onClick: onClose, children: /* @__PURE__ */ jsxs(
181
+ return /* @__PURE__ */ jsx(
180
182
  "div",
181
183
  {
182
- className: modalClassName,
183
- onClick: (e) => e.stopPropagation(),
184
- role: "alertdialog",
185
- "aria-modal": "true",
186
- "aria-labelledby": "alert_title",
187
- "aria-describedby": "alert_message",
188
- children: [
189
- title && /* @__PURE__ */ jsx("div", { className: "alert_title", id: "alert_title", children: title }),
190
- message && /* @__PURE__ */ jsx("div", { className: "alert_message", id: "alert_message", children: message }),
191
- /* @__PURE__ */ jsxs("div", { className: actionsClassName, children: [
192
- showCancel && /* @__PURE__ */ jsx(
193
- "button",
194
- {
195
- type: "button",
196
- className: "alert_button alert_button_cancel",
197
- onClick: onCancel,
198
- children: cancelText
199
- }
200
- ),
201
- /* @__PURE__ */ jsx(
202
- "button",
203
- {
204
- type: "button",
205
- className: "alert_button alert_button_confirm",
206
- onClick: onConfirm,
207
- children: confirmText
208
- }
209
- )
210
- ] })
211
- ]
184
+ className: "alert_overlay",
185
+ onClick: onClose,
186
+ onKeyDown: (e) => e.key === "Escape" && onClose(),
187
+ children: /* @__PURE__ */ jsxs(
188
+ "div",
189
+ {
190
+ ref: panelRef,
191
+ className: modalClassName,
192
+ onClick: (e) => e.stopPropagation(),
193
+ role: "alertdialog",
194
+ "aria-modal": "true",
195
+ "aria-labelledby": "alert_title",
196
+ "aria-describedby": "alert_message",
197
+ children: [
198
+ title && /* @__PURE__ */ jsx("div", { className: "alert_title", id: "alert_title", children: title }),
199
+ message && /* @__PURE__ */ jsx("div", { className: "alert_message", id: "alert_message", children: message }),
200
+ /* @__PURE__ */ jsxs("div", { className: actionsClassName, children: [
201
+ showCancel && /* @__PURE__ */ jsx(
202
+ "button",
203
+ {
204
+ type: "button",
205
+ className: "alert_button alert_button_cancel",
206
+ onClick: onCancel,
207
+ children: cancelText
208
+ }
209
+ ),
210
+ /* @__PURE__ */ jsx(
211
+ "button",
212
+ {
213
+ type: "button",
214
+ className: "alert_button alert_button_confirm",
215
+ onClick: onConfirm,
216
+ children: confirmText
217
+ }
218
+ )
219
+ ] })
220
+ ]
221
+ }
222
+ )
212
223
  }
213
- ) });
224
+ );
214
225
  };
215
226
  var Spinner = ({ size = 24, ariaLabel = "Loading" }) => {
216
227
  return /* @__PURE__ */ jsx(
@@ -258,7 +269,7 @@ var TopLoading = ({
258
269
  }
259
270
  );
260
271
  };
261
- var ToastContext = React6.createContext(null);
272
+ var ToastContext = React7.createContext(null);
262
273
  var VARIANT_ICONS = {
263
274
  success: /* @__PURE__ */ jsx(CheckCircle2, { size: 18 }),
264
275
  error: /* @__PURE__ */ jsx(XCircle, { size: 18 }),
@@ -266,10 +277,10 @@ var VARIANT_ICONS = {
266
277
  info: /* @__PURE__ */ jsx(Info, { size: 18 }),
267
278
  default: /* @__PURE__ */ jsx(Bell, { size: 18 })
268
279
  };
269
- var ToastItemComponent = ({ item, onRemove }) => {
270
- const [exiting, setExiting] = React6.useState(false);
271
- const closingRef = React6.useRef(false);
272
- const close = React6.useCallback(() => {
280
+ var ToastItemComponent = ({ item, onRemove, closeAriaLabel }) => {
281
+ const [exiting, setExiting] = React7.useState(false);
282
+ const closingRef = React7.useRef(false);
283
+ const close = React7.useCallback(() => {
273
284
  if (closingRef.current) return;
274
285
  closingRef.current = true;
275
286
  setExiting(true);
@@ -283,7 +294,7 @@ var ToastItemComponent = ({ item, onRemove }) => {
283
294
  "div",
284
295
  {
285
296
  className: itemClassName,
286
- role: "alert",
297
+ role: item.variant === "error" ? "alert" : "status",
287
298
  children: [
288
299
  /* @__PURE__ */ jsx("span", { className: `toast_icon toast_icon_${item.variant}`, "aria-hidden": "true", children: VARIANT_ICONS[item.variant] }),
289
300
  /* @__PURE__ */ jsx("span", { className: "toast_message", children: item.message }),
@@ -293,7 +304,7 @@ var ToastItemComponent = ({ item, onRemove }) => {
293
304
  type: "button",
294
305
  className: "toast_close",
295
306
  onClick: close,
296
- "aria-label": "\uB2EB\uAE30",
307
+ "aria-label": closeAriaLabel,
297
308
  children: /* @__PURE__ */ jsx(X, { size: 14 })
298
309
  }
299
310
  ),
@@ -310,33 +321,43 @@ var ToastItemComponent = ({ item, onRemove }) => {
310
321
  }
311
322
  );
312
323
  };
313
- var ToastProvider = ({ children, maxCount = 5 }) => {
314
- const [toasts, setToasts] = React6.useState([]);
315
- const [isMounted, setIsMounted] = React6.useState(false);
316
- React6.useEffect(() => {
324
+ var ToastProvider = ({ children, maxCount = 5, closeAriaLabel = "Close" }) => {
325
+ const [toasts, setToasts] = React7.useState([]);
326
+ const [isMounted, setIsMounted] = React7.useState(false);
327
+ React7.useEffect(() => {
317
328
  setIsMounted(true);
318
329
  }, []);
319
- const addToast = React6.useCallback(
330
+ const addToast = React7.useCallback(
320
331
  (message, variant, duration = 3e3) => {
321
332
  const id = crypto.randomUUID();
322
333
  setToasts((prev) => [{ id, message, variant, duration }, ...prev].slice(0, maxCount));
323
334
  },
324
335
  [maxCount]
325
336
  );
326
- const removeToast = React6.useCallback((id) => {
337
+ const removeToast = React7.useCallback((id) => {
327
338
  setToasts((prev) => prev.filter((t) => t.id !== id));
328
339
  }, []);
329
340
  return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { addToast }, children: [
330
341
  children,
331
342
  isMounted && createPortal(
332
- /* @__PURE__ */ jsx("div", { className: "toast_container", children: toasts.map((item) => /* @__PURE__ */ jsx(
333
- ToastItemComponent,
343
+ /* @__PURE__ */ jsx(
344
+ "div",
334
345
  {
335
- item,
336
- onRemove: removeToast
337
- },
338
- item.id
339
- )) }),
346
+ className: "toast_container",
347
+ "aria-live": "polite",
348
+ "aria-atomic": "false",
349
+ "aria-label": "Notifications",
350
+ children: toasts.map((item) => /* @__PURE__ */ jsx(
351
+ ToastItemComponent,
352
+ {
353
+ item,
354
+ onRemove: removeToast,
355
+ closeAriaLabel
356
+ },
357
+ item.id
358
+ ))
359
+ }
360
+ ),
340
361
  document.body
341
362
  )
342
363
  ] });
@@ -378,11 +399,11 @@ var Button = ({
378
399
  const buttonStyle = width ? { ...style, width } : style;
379
400
  return /* @__PURE__ */ jsx("button", { className: buttonClassName, style: buttonStyle, ...props });
380
401
  };
381
- var Checkbox = React6.forwardRef(
402
+ var Checkbox = React7.forwardRef(
382
403
  ({ label, size = "md", indeterminate, className, ...props }, ref) => {
383
- const inputRef = React6.useRef(null);
384
- React6.useImperativeHandle(ref, () => inputRef.current);
385
- React6.useEffect(() => {
404
+ const inputRef = React7.useRef(null);
405
+ React7.useImperativeHandle(ref, () => inputRef.current);
406
+ React7.useEffect(() => {
386
407
  if (!inputRef.current) return;
387
408
  inputRef.current.indeterminate = Boolean(indeterminate);
388
409
  }, [indeterminate]);
@@ -408,19 +429,19 @@ var Checkbox = React6.forwardRef(
408
429
  );
409
430
  Checkbox.displayName = "Checkbox";
410
431
  var FileInput = ({
411
- label = "\uD30C\uC77C \uC120\uD0DD",
432
+ label = "Choose file",
412
433
  onFiles,
413
434
  className,
414
435
  disabled,
415
436
  ...props
416
437
  }) => {
417
- const inputId = React6.useId();
438
+ const inputId = React7.useId();
418
439
  const rootClassName = [
419
440
  "file_input",
420
441
  disabled && "file_input_disabled",
421
442
  className ?? ""
422
443
  ].filter(Boolean).join(" ");
423
- return /* @__PURE__ */ jsxs("div", { style: { cursor: "pointer" }, className: rootClassName, children: [
444
+ return /* @__PURE__ */ jsxs("div", { className: rootClassName, children: [
424
445
  /* @__PURE__ */ jsx(
425
446
  "input",
426
447
  {
@@ -435,7 +456,7 @@ var FileInput = ({
435
456
  /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "file_input_label", children: label })
436
457
  ] });
437
458
  };
438
- var Radio = React6.forwardRef(
459
+ var Radio = React7.forwardRef(
439
460
  ({ label, size = "md", className, ...props }, ref) => {
440
461
  const rootClassName = cn(
441
462
  "radio",
@@ -465,21 +486,21 @@ var Select = ({
465
486
  className,
466
487
  textAlign = "left"
467
488
  }) => {
468
- const internalId = React6.useId();
489
+ const internalId = React7.useId();
469
490
  const selectId = id ?? internalId;
470
491
  const isControlled = value !== void 0;
471
- const [internalValue, setInternalValue] = React6.useState(defaultValue);
492
+ const [internalValue, setInternalValue] = React7.useState(defaultValue);
472
493
  const currentValue = isControlled ? value ?? null : internalValue;
473
- const [isOpen, setIsOpen] = React6.useState(false);
474
- const [activeIndex, setActiveIndex] = React6.useState(-1);
475
- const [dropUp, setDropUp] = React6.useState(false);
476
- const wrapperRef = React6.useRef(null);
477
- const controlRef = React6.useRef(null);
478
- const currentOption = React6.useMemo(
494
+ const [isOpen, setIsOpen] = React7.useState(false);
495
+ const [activeIndex, setActiveIndex] = React7.useState(-1);
496
+ const [dropUp, setDropUp] = React7.useState(false);
497
+ const wrapperRef = React7.useRef(null);
498
+ const controlRef = React7.useRef(null);
499
+ const currentOption = React7.useMemo(
479
500
  () => options.find((o) => o.value === currentValue) ?? null,
480
501
  [options, currentValue]
481
502
  );
482
- const setValue = React6.useCallback(
503
+ const setValue = React7.useCallback(
483
504
  (next) => {
484
505
  const option = options.find((o) => o.value === next) ?? null;
485
506
  if (!isControlled) setInternalValue(next);
@@ -487,12 +508,12 @@ var Select = ({
487
508
  },
488
509
  [isControlled, onChange, options]
489
510
  );
490
- const handleOutsideClick = React6.useEffectEvent((e) => {
511
+ const handleOutsideClick = React7.useEffectEvent((e) => {
491
512
  if (!wrapperRef.current?.contains(e.target)) {
492
513
  setIsOpen(false);
493
514
  }
494
515
  });
495
- React6.useEffect(() => {
516
+ React7.useEffect(() => {
496
517
  document.addEventListener("mousedown", handleOutsideClick);
497
518
  return () => document.removeEventListener("mousedown", handleOutsideClick);
498
519
  }, []);
@@ -557,12 +578,12 @@ var Select = ({
557
578
  break;
558
579
  }
559
580
  };
560
- React6.useEffect(() => {
581
+ React7.useEffect(() => {
561
582
  if (!isOpen) return;
562
583
  const idx = options.findIndex((o) => o.value === currentValue && !o.disabled);
563
584
  setActiveIndex(idx >= 0 ? idx : Math.max(0, options.findIndex((o) => !o.disabled)));
564
585
  }, [isOpen, options, currentValue]);
565
- React6.useLayoutEffect(() => {
586
+ React7.useLayoutEffect(() => {
566
587
  if (!isOpen || !controlRef.current) return;
567
588
  const rect = controlRef.current.getBoundingClientRect();
568
589
  const listHeight = Math.min(options.length * 40, 288);
@@ -644,7 +665,7 @@ var Select = ({
644
665
  )
645
666
  ] });
646
667
  };
647
- var Switch = React6.forwardRef(
668
+ var Switch = React7.forwardRef(
648
669
  ({
649
670
  checked,
650
671
  defaultChecked,
@@ -656,7 +677,7 @@ var Switch = React6.forwardRef(
656
677
  ...props
657
678
  }, ref) => {
658
679
  const isControlled = checked !== void 0;
659
- const [innerChecked, setInnerChecked] = React6.useState(!!defaultChecked);
680
+ const [innerChecked, setInnerChecked] = React7.useState(!!defaultChecked);
660
681
  const isOn = isControlled ? !!checked : innerChecked;
661
682
  const handleToggle = () => {
662
683
  if (disabled) return;
@@ -688,7 +709,7 @@ var Switch = React6.forwardRef(
688
709
  }
689
710
  );
690
711
  Switch.displayName = "Switch";
691
- var TextField = React6.forwardRef(
712
+ var TextField = React7.forwardRef(
692
713
  ({
693
714
  id,
694
715
  label,
@@ -707,15 +728,15 @@ var TextField = React6.forwardRef(
707
728
  transformValue,
708
729
  ...props
709
730
  }, ref) => {
710
- const inputId = id ?? React6.useId();
731
+ const inputId = id ?? React7.useId();
711
732
  const helperId = helperText ? `${inputId}-help` : void 0;
712
733
  const isControlled = value !== void 0;
713
734
  const applyTransform = (nextValue) => transformValue ? transformValue(nextValue) : nextValue;
714
- const [innerValue, setInnerValue] = React6.useState(
735
+ const [innerValue, setInnerValue] = React7.useState(
715
736
  () => applyTransform(value ?? defaultValue ?? "")
716
737
  );
717
- const isComposingRef = React6.useRef(false);
718
- React6.useEffect(() => {
738
+ const isComposingRef = React7.useRef(false);
739
+ React7.useEffect(() => {
719
740
  if (!isControlled) return;
720
741
  setInnerValue(applyTransform(value ?? ""));
721
742
  }, [isControlled, value, transformValue]);
@@ -799,8 +820,12 @@ var DatePicker = ({
799
820
  selectableRange = "all",
800
821
  disabled,
801
822
  fullWidth = true,
802
- width
823
+ width,
824
+ yearLabel = "Year",
825
+ monthLabel = "Month",
826
+ dayLabel = "Day"
803
827
  }) => {
828
+ const groupId = React7.useId();
804
829
  const today = /* @__PURE__ */ new Date();
805
830
  const todayYear = today.getFullYear();
806
831
  const todayMonth = today.getMonth() + 1;
@@ -828,56 +853,64 @@ var DatePicker = ({
828
853
  const containerStyle = width ? { width: normalizeWidth(width) } : void 0;
829
854
  const rootClassName = cn("date_picker", { date_picker_full_width: fullWidth && !width });
830
855
  return /* @__PURE__ */ jsxs("div", { className: rootClassName, style: containerStyle, children: [
831
- label && /* @__PURE__ */ jsx("label", { className: "date_picker_label", children: label }),
832
- /* @__PURE__ */ jsxs("div", { className: "date_picker_fields", children: [
833
- /* @__PURE__ */ jsxs(
834
- "select",
835
- {
836
- "aria-label": "\uC5F0\uB3C4",
837
- value: year,
838
- disabled,
839
- onChange: (e) => emit(Number(e.target.value), month || minMonth, day || minDay),
840
- children: [
841
- /* @__PURE__ */ jsx("option", { value: "", children: "\uC5F0\uB3C4" }),
842
- Array.from(
843
- { length: maxYear - startYear + 1 },
844
- (_, i) => startYear + i
845
- ).map((y2) => /* @__PURE__ */ jsx("option", { value: y2, children: y2 }, y2))
846
- ]
847
- }
848
- ),
849
- /* @__PURE__ */ jsxs(
850
- "select",
851
- {
852
- "aria-label": "\uC6D4",
853
- value: month,
854
- disabled: disabled || !year,
855
- onChange: (e) => emit(year, Number(e.target.value), day || minDay),
856
- children: [
857
- /* @__PURE__ */ jsx("option", { value: "", children: "\uC6D4" }),
858
- Array.from({ length: maxMonth - minMonth + 1 }, (_, i) => minMonth + i).map(
859
- (m2) => /* @__PURE__ */ jsx("option", { value: m2, children: pad(m2) }, m2)
860
- )
861
- ]
862
- }
863
- ),
864
- mode === "year-month-day" && /* @__PURE__ */ jsxs(
865
- "select",
866
- {
867
- "aria-label": "\uC77C",
868
- value: day,
869
- disabled: disabled || !month,
870
- onChange: (e) => emit(year, month, Number(e.target.value)),
871
- children: [
872
- /* @__PURE__ */ jsx("option", { value: "", children: "\uC77C" }),
873
- Array.from(
874
- { length: days - minDay + 1 },
875
- (_, i) => minDay + i
876
- ).map((d2) => /* @__PURE__ */ jsx("option", { value: d2, children: pad(d2) }, d2))
877
- ]
878
- }
879
- )
880
- ] })
856
+ label && /* @__PURE__ */ jsx("label", { className: "date_picker_label", id: groupId, children: label }),
857
+ /* @__PURE__ */ jsxs(
858
+ "div",
859
+ {
860
+ className: "date_picker_fields",
861
+ role: "group",
862
+ "aria-labelledby": label ? groupId : void 0,
863
+ children: [
864
+ /* @__PURE__ */ jsxs(
865
+ "select",
866
+ {
867
+ "aria-label": yearLabel,
868
+ value: year,
869
+ disabled,
870
+ onChange: (e) => emit(Number(e.target.value), month || minMonth, day || minDay),
871
+ children: [
872
+ /* @__PURE__ */ jsx("option", { value: "", children: yearLabel }),
873
+ Array.from(
874
+ { length: maxYear - startYear + 1 },
875
+ (_, i) => startYear + i
876
+ ).map((y2) => /* @__PURE__ */ jsx("option", { value: y2, children: y2 }, y2))
877
+ ]
878
+ }
879
+ ),
880
+ /* @__PURE__ */ jsxs(
881
+ "select",
882
+ {
883
+ "aria-label": monthLabel,
884
+ value: month,
885
+ disabled: disabled || !year,
886
+ onChange: (e) => emit(year, Number(e.target.value), day || minDay),
887
+ children: [
888
+ /* @__PURE__ */ jsx("option", { value: "", children: monthLabel }),
889
+ Array.from({ length: maxMonth - minMonth + 1 }, (_, i) => minMonth + i).map(
890
+ (m2) => /* @__PURE__ */ jsx("option", { value: m2, children: pad(m2) }, m2)
891
+ )
892
+ ]
893
+ }
894
+ ),
895
+ mode === "year-month-day" && /* @__PURE__ */ jsxs(
896
+ "select",
897
+ {
898
+ "aria-label": dayLabel,
899
+ value: day,
900
+ disabled: disabled || !month,
901
+ onChange: (e) => emit(year, month, Number(e.target.value)),
902
+ children: [
903
+ /* @__PURE__ */ jsx("option", { value: "", children: dayLabel }),
904
+ Array.from(
905
+ { length: days - minDay + 1 },
906
+ (_, i) => minDay + i
907
+ ).map((d2) => /* @__PURE__ */ jsx("option", { value: d2, children: pad(d2) }, d2))
908
+ ]
909
+ }
910
+ )
911
+ ]
912
+ }
913
+ )
881
914
  ] });
882
915
  };
883
916
  var range = (start, end) => {
@@ -909,10 +942,10 @@ var getPaginationItems = (page, totalPages) => {
909
942
  items.push(last);
910
943
  return items;
911
944
  };
912
- var Pagination = ({ page, totalPages, onChange }) => {
945
+ var Pagination = ({ page, totalPages, onChange, prevLabel = "Previous page", nextLabel = "Next page" }) => {
913
946
  const prevDisabled = page <= 1;
914
947
  const nextDisabled = page >= totalPages;
915
- const items = React6.useMemo(
948
+ const items = React7.useMemo(
916
949
  () => getPaginationItems(page, totalPages),
917
950
  [page, totalPages]
918
951
  );
@@ -923,7 +956,7 @@ var Pagination = ({ page, totalPages, onChange }) => {
923
956
  className: "pagination_item",
924
957
  onClick: () => onChange(page - 1),
925
958
  disabled: prevDisabled,
926
- "aria-label": "Previous page",
959
+ "aria-label": prevLabel,
927
960
  children: "\u2039"
928
961
  }
929
962
  ),
@@ -953,7 +986,7 @@ var Pagination = ({ page, totalPages, onChange }) => {
953
986
  className: "pagination_item",
954
987
  onClick: () => onChange(page + 1),
955
988
  disabled: nextDisabled,
956
- "aria-label": "Next page",
989
+ "aria-label": nextLabel,
957
990
  children: "\u203A"
958
991
  }
959
992
  )
@@ -970,18 +1003,18 @@ var Modal = ({
970
1003
  ariaLabel,
971
1004
  ...props
972
1005
  }) => {
973
- const panelRef = React6.useRef(null);
974
- const titleId = React6.useId();
1006
+ const panelRef = React7.useRef(null);
1007
+ const titleId = React7.useId();
975
1008
  useFocusTrap(panelRef, open);
976
- const handleEscape = React6.useEffectEvent((e) => {
1009
+ const handleEscape = React7.useEffectEvent((e) => {
977
1010
  if (e.key === "Escape") onClose?.();
978
1011
  });
979
- React6.useEffect(() => {
1012
+ React7.useEffect(() => {
980
1013
  if (!open) return;
981
1014
  document.addEventListener("keydown", handleEscape);
982
1015
  return () => document.removeEventListener("keydown", handleEscape);
983
1016
  }, [open]);
984
- React6.useEffect(() => {
1017
+ React7.useEffect(() => {
985
1018
  if (!open) return;
986
1019
  const body = document.body;
987
1020
  const openModals = parseInt(body.dataset.openModals || "0", 10);
package/dist/next.js CHANGED
@@ -75,7 +75,7 @@ var Sidebar = ({
75
75
  Image,
76
76
  {
77
77
  src: "/images/sidebar/arrow-close.svg",
78
- alt: "Close",
78
+ alt: "\uC0AC\uC774\uB4DC\uBC14 \uB2EB\uAE30",
79
79
  width: 24,
80
80
  height: 24
81
81
  }
@@ -83,7 +83,7 @@ var Sidebar = ({
83
83
  }
84
84
  )
85
85
  ] }),
86
- /* @__PURE__ */ jsx("nav", { className: "sidebar_nav", children: items.map((item) => {
86
+ /* @__PURE__ */ jsx("nav", { className: "sidebar_nav", "aria-label": "\uBA54\uC778 \uBA54\uB274", children: items.map((item) => {
87
87
  if (item.type === "group") {
88
88
  const open = openGroups.includes(item.id);
89
89
  const subClassName = [
@@ -130,6 +130,7 @@ var Sidebar = ({
130
130
  {
131
131
  href: child.href,
132
132
  className: subItemClassName,
133
+ "aria-current": active2 ? "page" : void 0,
133
134
  onClick: () => onItemSelect?.(
134
135
  child.href
135
136
  ),
@@ -158,6 +159,7 @@ var Sidebar = ({
158
159
  {
159
160
  href: item.href,
160
161
  className: itemClassName,
162
+ "aria-current": active ? "page" : void 0,
161
163
  onClick: () => onItemSelect?.(item.href),
162
164
  children: /* @__PURE__ */ jsxs("div", { className: "sidebar_item_left", children: [
163
165
  item.icon && /* @__PURE__ */ jsx("span", { className: "sidebar_icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(item.icon, { size: 16 }) }),
@@ -177,7 +179,7 @@ var Sidebar = ({
177
179
  Image,
178
180
  {
179
181
  src: "/images/sidebar/menu.svg",
180
- alt: "Open",
182
+ alt: "\uC0AC\uC774\uB4DC\uBC14 \uC5F4\uAE30",
181
183
  width: 24,
182
184
  height: 24
183
185
  }
@@ -40,6 +40,10 @@ $color_accent: #3B82F6;
40
40
  $color_accent_light: #60A5FA;
41
41
  $color_accent_dark: #2563EB;
42
42
 
43
+ /* Hover */
44
+ $color_hover_subtle: rgba(0, 0, 0, 0.03);
45
+ $color_hover_light: rgba(0, 0, 0, 0.05);
46
+
43
47
  /* Overlay */
44
48
  $color_overlay: rgba(0, 0, 0, 0.5);
45
49
  $color_overlay_light: rgba(0, 0, 0, 0.3);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigtablet/design-system",
3
- "version": "1.19.2",
3
+ "version": "1.19.4",
4
4
  "description": "Bigtablet Design System UI Components",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",