@telepix-lab/telepix-ui 0.7.0 → 0.7.1

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/dist/cjs/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
+ var locale = require('react-day-picker/locale');
5
6
 
6
7
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
7
8
 
@@ -3305,28 +3306,28 @@ function cn(...inputs) {
3305
3306
  const StateColorContainer = ({ groupName = "state", isInverted, className, }) => {
3306
3307
  const fillClassMap = {
3307
3308
  wrapper: {
3308
- normal: "group-hover/wrapper:bg-fill-hovered bg-fill-default group-active/wrapper:bg-fill-pressed group-aria-selected/wrapper:bg-fill-selected",
3309
- invert: "group-hover/wrapper:bg-fill-invert-hovered group-active/wrapper:bg-fill-invert-pressed bg-fill-invert-default group-aria-selected/wrapper:bg-fill-invert-selected",
3309
+ normal: "group-hover/wrapper:bg-fill-hovered bg-fill-default group-active/wrapper:bg-fill-pressed group-data-[focused=true]/wrapper:bg-fill-selected",
3310
+ invert: "group-hover/wrapper:bg-fill-invert-hovered group-active/wrapper:bg-fill-invert-pressed bg-fill-invert-default group-data-[focused=true]/wrapper:bg-fill-invert-selected",
3310
3311
  },
3311
3312
  item: {
3312
- normal: "group-hover/item:bg-fill-hovered bg-fill-default group-active/item:bg-fill-pressed group-aria-selected/item:bg-fill-selected",
3313
- invert: "group-hover/item:bg-fill-invert-hovered group-active/item:bg-fill-invert-pressed bg-fill-invert-default group-aria-selected/item:bg-fill-invert-selected",
3313
+ normal: "group-hover/item:bg-fill-hovered bg-fill-default group-active/item:bg-fill-pressed group-data-[focused=true]/item:bg-fill-selected",
3314
+ invert: "group-hover/item:bg-fill-invert-hovered group-active/item:bg-fill-invert-pressed bg-fill-invert-default group-data-[focused=true]/item:bg-fill-invert-selected",
3314
3315
  },
3315
3316
  option: {
3316
- normal: "group-hover/option:bg-fill-hovered bg-fill-default group-active/option:bg-fill-pressed group-aria-selected/option:bg-fill-selected",
3317
- invert: "group-hover/option:bg-fill-invert-hovered group-active/option:bg-fill-invert-pressed bg-fill-invert-default group-aria-selected/option:bg-fill-invert-selected",
3317
+ normal: "group-hover/option:bg-fill-hovered bg-fill-default group-active/option:bg-fill-pressed group-data-[focused=true]/option:bg-fill-selected",
3318
+ invert: "group-hover/option:bg-fill-invert-hovered group-active/option:bg-fill-invert-pressed bg-fill-invert-default group-data-[focused=true]/option:bg-fill-invert-selected",
3318
3319
  },
3319
3320
  tab: {
3320
- normal: "group-hover/tab:bg-fill-hovered bg-fill-default group-active/tab:bg-fill-pressed group-aria-selected/tab:bg-fill-selected",
3321
- invert: "group-hover/tab:bg-fill-invert-hovered group-active/tab:bg-fill-invert-pressed bg-fill-invert-default group-aria-selected/tab:bg-fill-invert-selected",
3321
+ normal: "group-hover/tab:bg-fill-hovered bg-fill-default group-active/tab:bg-fill-pressed group-data-[focused=true]/tab:bg-fill-selected",
3322
+ invert: "group-hover/tab:bg-fill-invert-hovered group-active/tab:bg-fill-invert-pressed bg-fill-invert-default group-data-[focused=true]/tab:bg-fill-invert-selected",
3322
3323
  },
3323
3324
  chip: {
3324
- normal: "group-hover/chip:bg-fill-hovered bg-fill-default group-active/chip:bg-fill-pressed group-aria-selected/chip:bg-fill-selected",
3325
- invert: "group-hover/chip:bg-fill-invert-hovered group-active/chip:bg-fill-invert-pressed bg-fill-invert-default group-aria-selected/chip:bg-fill-invert-selected",
3325
+ normal: "group-hover/chip:bg-fill-hovered bg-fill-default group-active/chip:bg-fill-pressed group-data-[focused=true]/chip:bg-fill-selected",
3326
+ invert: "group-hover/chip:bg-fill-invert-hovered group-active/chip:bg-fill-invert-pressed bg-fill-invert-default group-data-[focused=true]/chip:bg-fill-invert-selected",
3326
3327
  },
3327
3328
  state: {
3328
- normal: "group-hover/state:bg-fill-hovered bg-fill-default group-active/state:bg-fill-pressed group-aria-selected/state:bg-fill-selected",
3329
- invert: "group-hover/state:bg-fill-invert-hovered group-active/state:bg-fill-invert-pressed bg-fill-invert-default group-aria-selected/state:bg-fill-invert-selected",
3329
+ normal: "group-hover/state:bg-fill-hovered bg-fill-default group-active/state:bg-fill-pressed group-data-[focused=true]/state:bg-fill-selected",
3330
+ invert: "group-hover/state:bg-fill-invert-hovered group-active/state:bg-fill-invert-pressed bg-fill-invert-default group-data-[focused=true]/state:bg-fill-invert-selected",
3330
3331
  },
3331
3332
  };
3332
3333
  const group = groupName || "state";
@@ -3374,25 +3375,25 @@ const Button = react.forwardRef(({ variant = "accent", size = "regular", fullWid
3374
3375
  if (variant === BUTTON_VARIANTS.TEXT_DIM) {
3375
3376
  return [
3376
3377
  "h-auto py-0.5 px-0 text-body leading-body-compact gap-1.5",
3377
- "bg-page-l-null text-comp-mono-subtle-default hover:text-comp-mono-default aria-selected:text-comp-mono-default disabled:bg-page-l-null disabled:text-comp-disabled disabled:hover:text-comp-disabled",
3378
+ "bg-page-l-null text-comp-mono-subtle-default hover:text-comp-mono-default data-[focused=true]:text-comp-mono-default disabled:bg-page-l-null disabled:text-comp-disabled disabled:hover:text-comp-disabled",
3378
3379
  ];
3379
3380
  }
3380
3381
  const sizeClassName = {
3381
3382
  small: "h-7 py-0 px-1 text-label leading-label-compact gap-1",
3382
3383
  regular: "h-9 py-0 px-2 text-body leading-body-compact gap-1.5",
3383
- large: "h-12 py-0 px-3 text-body leading-body-compact gap-2",
3384
+ large: "h-12 py-0 px-3 text-base leading-base-compact gap-2",
3384
3385
  }[size];
3385
3386
  const variantClassName = {
3386
3387
  accent: "bg-page-accent-l0 disabled:bg-pure-transparent text-comp-accent-default disabled:text-comp-disabled",
3387
- outline: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled border border-border-bound disabled:border-pure-transparent aria-selected:border-border-selected",
3388
- outline_to_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled border border-border-bound disabled:border-pure-transparent aria-selected:border-border-selected aria-selected:bg-page-accent-l0 aria-selected:text-comp-accent-default",
3388
+ outline: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled border border-border-bound disabled:border-pure-transparent data-[focused=true]:border-border-selected",
3389
+ outline_to_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled border border-border-bound disabled:border-pure-transparent data-[focused=true]:border-border-selected data-[focused=true]:bg-page-accent-l0 data-[focused=true]:text-comp-accent-default",
3389
3390
  ghost: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled",
3390
3391
  thumbnail_ghost: "bg-page-l-null disabled:bg-fill-disabled text-comp-mono-default disabled:text-comp-disabled",
3391
- ghost_to_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled aria-selected:bg-page-accent-l0 aria-selected:text-comp-accent-default",
3392
- subtle_filled: "bg-page-l3 disabled:bg-fill-disabled text-comp-mono-subtle-default disabled:text-comp-disabled aria-selected:text-comp-mono-default",
3393
- outline_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-accent-default disabled:text-comp-disabled border border-border-accent-bound disabled:border-pure-transparent aria-selected:border-border-accent-selected",
3392
+ ghost_to_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-default disabled:text-comp-disabled data-[focused=true]:bg-page-accent-l0 data-[focused=true]:text-comp-accent-default",
3393
+ subtle_filled: "bg-page-l3 disabled:bg-fill-disabled text-comp-mono-subtle-default disabled:text-comp-disabled data-[focused=true]:text-comp-mono-default",
3394
+ outline_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-accent-default disabled:text-comp-disabled border border-border-accent-bound disabled:border-pure-transparent data-[focused=true]:border-border-accent-selected",
3394
3395
  ghost_accent: "bg-page-l-null disabled:bg-page-l-null text-comp-accent-default disabled:text-comp-disabled",
3395
- ghost_dim: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-subtle-default disabled:text-comp-disabled aria-selected:text-comp-mono-default",
3396
+ ghost_dim: "bg-page-l-null disabled:bg-page-l-null text-comp-mono-subtle-default disabled:text-comp-disabled data-[focused=true]:text-comp-mono-default",
3396
3397
  text_dim: "", // 위에서 처리되므로 여기서는 빈 문자열
3397
3398
  }[variant];
3398
3399
  return [sizeClassName, variantClassName];
@@ -3411,22 +3412,22 @@ const Button = react.forwardRef(({ variant = "accent", size = "regular", fullWid
3411
3412
  return "size-5";
3412
3413
  return "size-6"; // 기본값은 regular 크기
3413
3414
  };
3414
- return (jsxRuntime.jsxs("button", { ref: ref, disabled: disabled ?? isLoading, className: cn("flex group/state items-center justify-center relative box-border m-0 border-transparent outline-none cursor-pointer select-none align-middle appearance-none text-center transition-normal font-medium w-auto rounded-md overflow-hidden pointer-events-auto disabled:pointer-events-none disabled:cursor-not-allowed", ...getClassName(size, variant), fullWidth && "w-full", className), ...rest, children: [variant !== BUTTON_VARIANTS.TEXT_DIM && (jsxRuntime.jsx(StateColorContainer, { isInverted: variant === BUTTON_VARIANTS.ACCENT, className: stateContainerClassName })), isLoading && (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: cn("lucide lucide-loader-circle-icon lucide-loader-circle absolute animate-spin", size === BUTTON_SIZES.SMALL &&
3415
+ return (jsxRuntime.jsxs("button", { ref: ref, disabled: disabled ?? isLoading, "aria-busy": isLoading, "aria-disabled": disabled ?? isLoading, "aria-pressed": rest["aria-pressed"], className: cn("flex group/state items-center justify-center relative box-border m-0 border-transparent outline-none border cursor-pointer select-none align-middle appearance-none text-center transition-normal font-medium w-auto rounded-md pointer-events-auto disabled:pointer-events-none disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-border-focused", ...getClassName(size, variant), fullWidth && "w-full", className), ...rest, children: [variant !== BUTTON_VARIANTS.TEXT_DIM && (jsxRuntime.jsx(StateColorContainer, { isInverted: variant === BUTTON_VARIANTS.ACCENT, className: cn("-inset-px", stateContainerClassName) })), isLoading && (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: cn("lucide lucide-loader-circle-icon lucide-loader-circle absolute animate-spin", size === BUTTON_SIZES.SMALL &&
3415
3416
  "size-4 top-[calc(50%-8px)] left-[calc(50%-8px)]", size === BUTTON_SIZES.REGULAR &&
3416
3417
  "size-5 top-[calc(50%-10px)] left-[calc(50%-10px)]", size === BUTTON_SIZES.LARGE &&
3417
3418
  "size-6 top-[calc(50%-12px)] left-[calc(50%-12px)]"), children: jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) })), leftIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center relative", variant === BUTTON_VARIANTS.THUMBNAIL_GHOST &&
3418
- "aspect-square [&_img]:rounded-sm", getThumbnailSize(variant, size)), children: leftIcon })), children && (jsxRuntime.jsx("div", { className: "flex-1", style: { visibility: isLoading ? "hidden" : "visible" }, children: children })), rightIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center relative", getThumbnailSize(variant, size)), children: rightIcon }))] }));
3419
+ "aspect-square [&_img]:rounded-sm", getThumbnailSize(variant, size)), children: leftIcon })), children && (jsxRuntime.jsx("div", { className: "flex-1 truncate", style: { visibility: isLoading ? "hidden" : "visible" }, children: children })), rightIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center relative", getThumbnailSize(variant, size)), children: rightIcon }))] }));
3419
3420
  });
3420
3421
  Button.displayName = "Button";
3421
3422
  /**
3422
3423
  * Text Dim 스타일의 버튼 컴포넌트입니다.<br/>
3423
3424
  * 텍스트 중심의 보조 액션(secondary / subtle action)에 적합한 low-emphasis 스타일을 제공합니다.<br/>
3424
- * 기본적으로 낮은 명도의 텍스트를 사용하며, hover 시 명도가 상승하고 selected 시 accent 색상으로 강조됩니다.<br/>
3425
+ * 기본적으로 낮은 명도의 텍스트를 사용하며, hover 시 명도가 상승하고 focused 시 accent 색상으로 강조됩니다.<br/>
3425
3426
  * <br/>
3426
3427
  * ### 사용 예시
3427
3428
  * ```tsx
3428
3429
  * <ButtonTextDim>자세히 보기</ButtonTextDim>
3429
- * <ButtonTextDim aria-selected="true">선택됨</ButtonTextDim>
3430
+ * <ButtonTextDim data-focused="true">포커스됨</ButtonTextDim>
3430
3431
  * ```
3431
3432
  */
3432
3433
  const ButtonTextDim = react.forwardRef((props, ref) => {
@@ -3469,6 +3470,33 @@ const CardFooter = react.forwardRef(({ className, ...rest }, ref) => {
3469
3470
  return (jsxRuntime.jsx("div", { ...rest, ref: ref, className: cn("py-4 px-6", className), children: rest.children }));
3470
3471
  });
3471
3472
 
3473
+ /**
3474
+ * 전역 포커스 가시성 제어 훅
3475
+ *
3476
+ * - 마우스 클릭 시: body.using-mouse 추가 → outline 제거
3477
+ * - Tab 키로 이동 시: using-mouse 제거 → outline 정상 표시
3478
+ *
3479
+ * Telepix-UI의 focus-visible outline 정책을 보완하기 위해 사용.
3480
+ */
3481
+ function useFocusVisibleMode() {
3482
+ react.useEffect(() => {
3483
+ const handleMouseDown = () => {
3484
+ document.body.classList.add("using-mouse");
3485
+ };
3486
+ const handleKeyDown = (e) => {
3487
+ if (e.key === "Tab") {
3488
+ document.body.classList.remove("using-mouse");
3489
+ }
3490
+ };
3491
+ window.addEventListener("mousedown", handleMouseDown);
3492
+ window.addEventListener("keydown", handleKeyDown);
3493
+ return () => {
3494
+ window.removeEventListener("mousedown", handleMouseDown);
3495
+ window.removeEventListener("keydown", handleKeyDown);
3496
+ };
3497
+ }, []);
3498
+ }
3499
+
3472
3500
  const TEXT_SIZES = {
3473
3501
  XSMALL: "xsmall",
3474
3502
  LABEL: "label",
@@ -3744,22 +3772,27 @@ const Input = react.forwardRef(({ size = "regular", variant = "outlined", leftIc
3744
3772
  ref.current = node;
3745
3773
  innerRef.current = node;
3746
3774
  };
3747
- return (jsxRuntime.jsxs(react.Fragment, { children: [jsxRuntime.jsxs("div", { "aria-disabled": rest.disabled, className: cn("relative group/state flex items-center justify-center rounded-lg border bg-Page-l-null border-border-bound focus-within:border-border-focused has-[input:disabled]:border-transparent", variant === INPUT_VARIANTS.OUTLINED &&
3775
+ const generatedId = react.useId();
3776
+ const inputId = locale.id ?? `input-${generatedId}`;
3777
+ useFocusVisibleMode();
3778
+ return (jsxRuntime.jsxs(react.Fragment, { children: [jsxRuntime.jsxs("div", { "aria-disabled": rest.disabled, className: cn("relative group/state flex items-center justify-center rounded-lg border bg-Page-l-null border-border-bound has-[input:disabled]:border-transparent has-input-focus-visible", variant === INPUT_VARIANTS.OUTLINED &&
3748
3779
  "border border-border-bound focus-within:border-border-focused", variant === INPUT_VARIANTS.FILLED &&
3749
- "bg-page-l3 border-transparent focus-within:border-transparent", size === INPUT_SIZES.SMALL &&
3780
+ "bg-page-l3 border-transparent focus-within:border-border-focused", size === INPUT_SIZES.SMALL &&
3750
3781
  "py-1.5 px-2 text-label leading-label-compact font-medium gap-1", size === INPUT_SIZES.REGULAR &&
3751
3782
  "py-1.5 px-2 text-body leading-body-compact font-medium gap-2", size === INPUT_SIZES.LARGE &&
3752
3783
  "py-[11px] px-4 text-base leading-base-compact font-medium gap-3", isError &&
3753
- "border-comp-chroma-error focus-within:border-comp-chroma-error", wrapperClassName), onClick: () => {
3784
+ "border-comp-chroma-error focus-within:border-comp-chroma-error focus-within:outline-comp-chroma-error", wrapperClassName), onClick: () => {
3754
3785
  innerRef.current?.focus();
3755
- }, children: [jsxRuntime.jsx(StateColorContainer, { className: cn("group-focus-within/state:bg-page-l-null", (!useHoverStyle || rest.disabled) && "hover:bg-fill-default") }), leftIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center text-comp-mono-default", isError && "text-comp-chroma-error"), children: leftIcon })), jsxRuntime.jsx("input", { ref: mergedRef, className: cn("border-none outline-none p-0 flex-1 bg-transparent min-w-0 text-comp-mono-default placeholder:text-comp-mono-subtle-default focus:placeholder:text-comp-mono-subtle-selected disabled:text-comp-disabled disabled:placeholder:text-comp-disabled", useHoverStyle &&
3786
+ }, children: [jsxRuntime.jsx(StateColorContainer, { className: cn("group-focus-within/state:bg-page-l-null", (!useHoverStyle || rest.disabled) && "hover:bg-fill-default") }), leftIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center text-comp-mono-default", isError && "text-comp-chroma-error"), children: leftIcon })), jsxRuntime.jsx("input", { id: inputId.toString(), ref: mergedRef, "aria-invalid": isError, "aria-describedby": isError && errorMessage
3787
+ ? `${rest.id || "input"}-error`
3788
+ : undefined, className: cn("border-none outline-none p-0 flex-1 bg-transparent min-w-0 text-comp-mono-default placeholder:text-comp-mono-subtle-default focus:placeholder:text-comp-mono-subtle-selected disabled:text-comp-disabled disabled:placeholder:text-comp-disabled focus-visible:outline-none", useHoverStyle &&
3756
3789
  "hover:placeholder:text-comp-mono-subtle-hovered", size === INPUT_SIZES.SMALL &&
3757
3790
  "text-label leading-label-compact font-medium", size === INPUT_SIZES.REGULAR &&
3758
3791
  "text-body leading-body-compact font-medium", size === INPUT_SIZES.LARGE &&
3759
3792
  "text-base leading-base-compact font-medium", isError &&
3760
3793
  "placeholder:text-comp-chroma-error text-comp-chroma-error hover:placeholder:text-comp-error focus:placeholder:text-comp-error", rest.type === "number" &&
3761
3794
  !useIndicator &&
3762
- "[-moz-appearance:_textfield] [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none", rest.className), ...rest }), rightIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center text-comp-mono-default", isError && "text-comp-chroma-error"), children: rightIcon }))] }), errorMessage && (jsxRuntime.jsx(Text, { variant: "medLabelMedCompact", className: "text-comp-chroma-error mt-2", children: errorMessage }))] }));
3795
+ "[-moz-appearance:_textfield] [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none", rest.className), ...rest }), rightIcon && (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center text-comp-mono-default", isError && "text-comp-chroma-error"), children: rightIcon }))] }), errorMessage && (jsxRuntime.jsx(Text, { id: `${inputId}-error`, variant: "medLabelMedCompact", className: "text-comp-chroma-error mt-2", role: "alert", "aria-live": "polite", children: errorMessage }))] }));
3763
3796
  });
3764
3797
  Input.displayName = "Input";
3765
3798
 
@@ -3767,8 +3800,10 @@ const NOTIFY_ITEM_VARIANTS = {
3767
3800
  GHOST: "ghost",
3768
3801
  DYNAMIC_ACCENT: "dynamicAccent",
3769
3802
  };
3770
- const NotifyItem = react.forwardRef(({ title, description, timestamp, icon, actionIcon, variant = NOTIFY_ITEM_VARIANTS.GHOST, unread = false, disabled, className, ...rest }, ref) => {
3771
- return (jsxRuntime.jsxs("div", { ref: ref, "data-unread": unread, "data-disabled": disabled, className: cn("relative group/state inline-flex items-center min-h-9 w-full p-1.5 rounded cursor-pointer border border-transparent", variant === NOTIFY_ITEM_VARIANTS.GHOST && [
3803
+ const NotifyItem = react.forwardRef(({ title, description, timestamp, icon, actionIcon, variant = NOTIFY_ITEM_VARIANTS.GHOST, unread = false, disabled, className, onClick, ...rest }, ref) => {
3804
+ const ariaLabel = rest["aria-label"] ||
3805
+ `${title}. ${description}${unread ? ". 읽지 않음" : ". 읽음"}${timestamp ? `. ${timestamp}` : ""}`;
3806
+ return (jsxRuntime.jsxs("div", { ref: ref, role: onClick ? "button" : "article", tabIndex: onClick && !disabled ? 0 : undefined, "data-unread": unread, "data-disabled": disabled, "aria-label": ariaLabel, "aria-disabled": disabled, "aria-readonly": !onClick, "aria-live": unread ? "polite" : "off", className: cn("relative group/state inline-flex items-center min-h-9 w-full p-1.5 rounded cursor-pointer border border-transparent", variant === NOTIFY_ITEM_VARIANTS.GHOST && [
3772
3807
  !disabled && "bg-page-l-null *:text-comp-mono-subtle-default",
3773
3808
  "data-[unread=true]:border-border-bound data-[unread=true]:bg-page-l3 data-[unread=true]:*:text-comp-mono-default",
3774
3809
  ], variant === NOTIFY_ITEM_VARIANTS.DYNAMIC_ACCENT && [
@@ -3776,7 +3811,16 @@ const NotifyItem = react.forwardRef(({ title, description, timestamp, icon, acti
3776
3811
  "data-[unread=true]:bg-page-accent-l0 data-[unread=true]:*:text-comp-accent-default",
3777
3812
  ], disabled && [
3778
3813
  "cursor-not-allowed pointer-events-none bg-page-l-null *:text-comp-disabled",
3779
- ], className), ...rest, children: [icon && (jsxRuntime.jsx("div", { className: "size-9 flex justify-center items-center flex-shrink-0", children: icon })), jsxRuntime.jsxs("div", { className: "flex-1 self-stretch px-1.5 inline-flex flex-col justify-center items-start gap-1 min-w-0 text-inherit", children: [jsxRuntime.jsx(Text, { variant: "medBodyMedCompact", className: "text-inherit", children: title }), jsxRuntime.jsx(Text, { variant: "regularLabelCompact", className: cn("text-inherit", variant === NOTIFY_ITEM_VARIANTS.GHOST &&
3814
+ ], onClick &&
3815
+ !disabled &&
3816
+ "focus-visible:outline focus-visible:outline-offset-2 focus-visible:outline-border-focused focus-visible:outline-solid", className), onClick: disabled ? undefined : onClick, onKeyDown: onClick && !disabled
3817
+ ? (e) => {
3818
+ if (e.key === "Enter" || e.key === " ") {
3819
+ e.preventDefault();
3820
+ onClick(e);
3821
+ }
3822
+ }
3823
+ : undefined, ...rest, children: [icon && (jsxRuntime.jsx("div", { className: "size-9 flex justify-center items-center flex-shrink-0", children: icon })), jsxRuntime.jsxs("div", { className: "flex-1 self-stretch px-1.5 inline-flex flex-col justify-center items-start gap-1 min-w-0 text-inherit", children: [jsxRuntime.jsx(Text, { variant: "medBodyMedCompact", className: "text-inherit", children: title }), jsxRuntime.jsx(Text, { variant: "regularLabelCompact", className: cn("text-inherit", variant === NOTIFY_ITEM_VARIANTS.GHOST &&
3780
3824
  "group-data-[unread=true]/state:text-comp-mono-subtle-default", variant === NOTIFY_ITEM_VARIANTS.DYNAMIC_ACCENT &&
3781
3825
  !disabled &&
3782
3826
  "group-data-[unread=false]/state:text-comp-mono-subtle-default"), children: description })] }), timestamp && (jsxRuntime.jsx("div", { className: "h-9 flex justify-center items-center flex-shrink-0", children: jsxRuntime.jsx(Text, { variant: "medLabelMedCompact", className: cn("text-inherit", variant === NOTIFY_ITEM_VARIANTS.DYNAMIC_ACCENT &&
@@ -3955,7 +3999,10 @@ const PaginationItem = (props) => {
3955
3999
  return jsxRuntime.jsx("li", { "data-slot": "pagination-item", ...props });
3956
4000
  };
3957
4001
  const PaginationLink = ({ className, isActive, size = "regular", variant = "ghost", ...rest }) => {
3958
- return (jsxRuntime.jsx(Button, { "aria-current": isActive ? "page" : undefined, "data-slot": "pagination-link", "data-active": isActive, size: size, variant: variant, className: cn("h-9 min-h-9", isActive && "bg-fill-selected text-comp-mono-default", className), ...rest }));
4002
+ return (jsxRuntime.jsx(Button, { "aria-current": isActive ? "page" : undefined, "aria-label": rest["aria-label"] ||
4003
+ (isActive
4004
+ ? `현재 페이지, ${rest.children}`
4005
+ : `페이지 ${rest.children}로 이동`), "data-slot": "pagination-link", "data-active": isActive, size: size, variant: variant, className: cn("h-9 min-h-9", isActive && "bg-fill-selected text-comp-mono-default", className), ...rest }));
3959
4006
  };
3960
4007
  const PaginationPrevious = ({ className, ...rest }) => {
3961
4008
  return (jsxRuntime.jsx(PaginationLink, { "aria-label": "Go to previous page", className: cn("flex items-center justify-center mr-4", className), leftIcon: jsxRuntime.jsx(ChevronLeft, { size: 20 }), ...rest }));
@@ -3964,14 +4011,14 @@ const PaginationNext = ({ className, ...rest }) => {
3964
4011
  return (jsxRuntime.jsx(PaginationLink, { "aria-label": "Go to next page", className: cn("ml-4", className), leftIcon: jsxRuntime.jsx(ChevronRight, { size: 20 }), ...rest }));
3965
4012
  };
3966
4013
  const PaginationEllipsis = ({ className, ...rest }) => {
3967
- return (jsxRuntime.jsx("span", { "aria-hidden": true, "data-slot": "pagination-ellipsis", className: cn("flex items-center justify-center size-9 rounded-md hover:bg-fill-mono-hovered", className), ...rest, children: jsxRuntime.jsx(Ellipsis, { className: "size-4 stroke-comp-mono-subtle-default" }) }));
4014
+ return (jsxRuntime.jsx("span", { "aria-hidden": "true", role: "presentation", "data-slot": "pagination-ellipsis", className: cn("flex items-center justify-center size-9 rounded-md hover:bg-fill-mono-hovered", className), ...rest, children: jsxRuntime.jsx(Ellipsis, { className: "size-4 stroke-comp-mono-subtle-default", "aria-hidden": "true", focusable: false }) }));
3968
4015
  };
3969
4016
 
3970
4017
  const Tag = react.forwardRef(({ icon, value, variant = "filled", size = "regular", className, onDeleteClick, onClick, useSelectedStyle = false, ...props }, ref) => {
3971
- const [isSelected, setIsSelected] = react.useState(false);
4018
+ const [isFocused, setIsFocused] = react.useState(false);
3972
4019
  const handleClick = (event) => {
3973
4020
  if (useSelectedStyle)
3974
- setIsSelected((prev) => !prev);
4021
+ setIsFocused((prev) => !prev);
3975
4022
  onClick?.(event);
3976
4023
  };
3977
4024
  const handleDeleteClick = (event) => {
@@ -3982,7 +4029,9 @@ const Tag = react.forwardRef(({ icon, value, variant = "filled", size = "regular
3982
4029
  `bg-page-l4 text-comp-mono-subtle-default data-disabled:text-comp-disabled data-disabled:bg-page-l-null`, variant === "accent" &&
3983
4030
  `bg-page-accent-l0 text-comp-accent-default data-disabled:text-comp-disabled data-disabled:bg-page-l-null`, size === "regular" &&
3984
4031
  "text-body font-medium leading-body-compact px-2 py-1 gap-2", size === "small" &&
3985
- "text-label font-medium leading-label-compact px-1.5 py-0.5 gap-1.5", className), onClick: handleClick, "data-selected": isSelected, "aria-selected": isSelected, ...props, children: [icon && (jsxRuntime.jsx("span", { className: "flex items-center justify-center size-4 border-none bg-transparent outline-none p-0", children: icon })), jsxRuntime.jsx("span", { className: "flex-1 text-nowrap overflow-hidden text-ellipsis text-inherit text-size-inherit leading-inherit font-inherit", children: value.label }), onDeleteClick && (jsxRuntime.jsx("span", { className: "flex items-center justify-center size-4 border-none bg-transparent outline-none p-0 cursor-pointer text-comp-mono-default group-disabled/state:text-comp-disabled", onClick: handleDeleteClick, children: jsxRuntime.jsx(X, {}) })), jsxRuntime.jsx(StateColorContainer, { className: cn(useSelectedStyle
4032
+ "text-label font-medium leading-label-compact px-1.5 py-0.5 gap-1.5", className), onClick: handleClick, "data-focused": isFocused, ...props, children: [icon && (jsxRuntime.jsx("span", { className: "flex items-center justify-center size-4 border-none bg-transparent outline-none p-0", children: icon })), jsxRuntime.jsx("span", { className: cn("flex-1 truncate text-inherit text-size-inherit font-inherit", size === "small" &&
4033
+ "leading-[calc(var(--spacing-label-compact)+3px)]", size === "regular" &&
4034
+ "leading-[calc(var(--spacing-body-compact)+3px)]"), children: value.label }), onDeleteClick && (jsxRuntime.jsx("span", { className: "flex items-center justify-center size-4 border-none bg-transparent outline-none p-0 cursor-pointer text-inherit group-disabled/state:text-comp-disabled", onClick: handleDeleteClick, children: jsxRuntime.jsx(X, {}) })), jsxRuntime.jsx(StateColorContainer, { className: cn(useSelectedStyle
3986
4035
  ? ""
3987
4036
  : "group-active/state:bg-fill-default group-active/state:border-transparent group-disabled/state:bg-fill-default"), isInverted: variant === "accent" })] }));
3988
4037
  });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 전역 포커스 가시성 제어 훅
3
+ *
4
+ * - 마우스 클릭 시: body.using-mouse 추가 → outline 제거
5
+ * - Tab 키로 이동 시: using-mouse 제거 → outline 정상 표시
6
+ *
7
+ * Telepix-UI의 focus-visible outline 정책을 보완하기 위해 사용.
8
+ */
9
+ export declare function useFocusVisibleMode(): void;
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  interface InteractiveListItemProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
3
- isSelected?: boolean;
4
3
  disabled?: boolean;
4
+ isSelected?: boolean;
5
5
  showHoverActions?: boolean;
6
6
  }
7
7
  export declare const InteractiveListItem: React.ForwardRefExoticComponent<Omit<InteractiveListItemProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
@@ -7,6 +7,7 @@ interface NotifyItemProps extends React.HTMLAttributes<HTMLDivElement> {
7
7
  variant?: "ghost" | "dynamicAccent";
8
8
  unread?: boolean;
9
9
  disabled?: boolean;
10
+ onClick?: (e: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
10
11
  }
11
12
  export declare const NotifyItem: import("react").ForwardRefExoticComponent<NotifyItemProps & import("react").RefAttributes<HTMLDivElement>>;
12
13
  export {};
@@ -1,5 +1,5 @@
1
- import { ReactNode } from "react";
2
1
  import { RadioGroup as RadioGroupRadix } from "radix-ui";
2
+ import { ReactNode } from "react";
3
3
  import { RadioGroupOrientation } from "./types";
4
4
  interface RadioGroupProps extends RadioGroupRadix.RadioGroupProps {
5
5
  className?: string;
@@ -1,5 +1,5 @@
1
- import React from "react";
2
1
  import { Select as SelectRadix } from "radix-ui";
2
+ import React from "react";
3
3
  import { SelectTriggerSize, SelectTriggerVariant } from "./types";
4
4
  /**
5
5
  * Select 컴포넌트는 드롭다운 선택 상자를 생성하는 데 사용됩니다.<br/>
@@ -14,9 +14,9 @@ import { SelectTriggerSize, SelectTriggerVariant } from "./types";
14
14
  * <Select>
15
15
  * <SelectTrigger placeholder="Select an option" />
16
16
  * <SelectContent>
17
- * <SelectItem value="option1">Option 1</SelectItem>
18
- * <SelectItem value="option2">Option 2</SelectItem>
19
- * <SelectItem value="option3">Option 3</SelectItem>
17
+ * <SelectItem value="option1" textValue="Option 1"></SelectItem>
18
+ * <SelectItem value="option2" textValue="Option 2"></SelectItem>
19
+ * <SelectItem value="option3" textValue="Option 3"></SelectItem>
20
20
  * </SelectContent>
21
21
  * </Select>
22
22
  */
@@ -3,7 +3,7 @@ export declare const Table: React.ForwardRefExoticComponent<Omit<React.DetailedH
3
3
  export declare const TableHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>, "ref"> & React.RefAttributes<HTMLTableRowElement>>;
4
4
  export declare const TableBody: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & React.RefAttributes<HTMLTableSectionElement>>;
5
5
  interface TableRowProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement> {
6
- isSelected?: boolean;
6
+ isFocused?: boolean;
7
7
  shouldLastBorderRender?: boolean;
8
8
  }
9
9
  export declare const TableRow: React.ForwardRefExoticComponent<Omit<TableRowProps, "ref"> & React.RefAttributes<HTMLTableRowElement>>;
package/dist/client.d.ts CHANGED
@@ -132,9 +132,9 @@ type SelectTriggerSize = (typeof SELECT_TRIGGER_SIZES)[keyof typeof SELECT_TRIGG
132
132
  * <Select>
133
133
  * <SelectTrigger placeholder="Select an option" />
134
134
  * <SelectContent>
135
- * <SelectItem value="option1">Option 1</SelectItem>
136
- * <SelectItem value="option2">Option 2</SelectItem>
137
- * <SelectItem value="option3">Option 3</SelectItem>
135
+ * <SelectItem value="option1" textValue="Option 1"></SelectItem>
136
+ * <SelectItem value="option2" textValue="Option 2"></SelectItem>
137
+ * <SelectItem value="option3" textValue="Option 3"></SelectItem>
138
138
  * </SelectContent>
139
139
  * </Select>
140
140
  */
@@ -304,7 +304,7 @@ declare const Table: React__default.ForwardRefExoticComponent<Omit<React__defaul
304
304
  declare const TableHeader: React__default.ForwardRefExoticComponent<Omit<React__default.DetailedHTMLProps<React__default.TableHTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>, "ref"> & React__default.RefAttributes<HTMLTableRowElement>>;
305
305
  declare const TableBody: React__default.ForwardRefExoticComponent<Omit<React__default.DetailedHTMLProps<React__default.TableHTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & React__default.RefAttributes<HTMLTableSectionElement>>;
306
306
  interface TableRowProps extends React__default.DetailedHTMLProps<React__default.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement> {
307
- isSelected?: boolean;
307
+ isFocused?: boolean;
308
308
  shouldLastBorderRender?: boolean;
309
309
  }
310
310
  declare const TableRow: React__default.ForwardRefExoticComponent<Omit<TableRowProps, "ref"> & React__default.RefAttributes<HTMLTableRowElement>>;
@@ -352,8 +352,8 @@ interface DataTableProps<T> {
352
352
  declare const DataTable: <T extends object>({ config, data, emptyMessage, onRowClick, enableSelection, shouldLastBorderRender, classNames, refs, }: DataTableProps<T>) => react_jsx_runtime.JSX.Element;
353
353
 
354
354
  interface InteractiveListItemProps extends React__default.DetailedHTMLProps<React__default.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
355
- isSelected?: boolean;
356
355
  disabled?: boolean;
356
+ isSelected?: boolean;
357
357
  showHoverActions?: boolean;
358
358
  }
359
359
  declare const InteractiveListItem: React__default.ForwardRefExoticComponent<Omit<InteractiveListItemProps, "ref"> & React__default.RefAttributes<HTMLDivElement>>;
@@ -27,12 +27,12 @@ export declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "
27
27
  /**
28
28
  * Text Dim 스타일의 버튼 컴포넌트입니다.<br/>
29
29
  * 텍스트 중심의 보조 액션(secondary / subtle action)에 적합한 low-emphasis 스타일을 제공합니다.<br/>
30
- * 기본적으로 낮은 명도의 텍스트를 사용하며, hover 시 명도가 상승하고 selected 시 accent 색상으로 강조됩니다.<br/>
30
+ * 기본적으로 낮은 명도의 텍스트를 사용하며, hover 시 명도가 상승하고 focused 시 accent 색상으로 강조됩니다.<br/>
31
31
  * <br/>
32
32
  * ### 사용 예시
33
33
  * ```tsx
34
34
  * <ButtonTextDim>자세히 보기</ButtonTextDim>
35
- * <ButtonTextDim aria-selected="true">선택됨</ButtonTextDim>
35
+ * <ButtonTextDim data-focused="true">포커스됨</ButtonTextDim>
36
36
  * ```
37
37
  */
38
38
  export declare const ButtonTextDim: React.ForwardRefExoticComponent<Omit<Omit<ButtonProps, "variant">, "ref"> & React.RefAttributes<HTMLButtonElement>>;