@uniai-fe/uds-primitives 0.4.7 → 0.5.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 (36) hide show
  1. package/README.md +3 -0
  2. package/dist/styles.css +325 -138
  3. package/package.json +1 -1
  4. package/src/components/badge/index.tsx +1 -3
  5. package/src/components/badge/markup/Badge.tsx +26 -15
  6. package/src/components/badge/styles/badge.scss +244 -0
  7. package/src/components/badge/styles/index.scss +2 -187
  8. package/src/components/badge/styles/variables.scss +41 -0
  9. package/src/components/badge/types/index.ts +3 -77
  10. package/src/components/badge/types/options.ts +25 -0
  11. package/src/components/badge/types/props.ts +53 -0
  12. package/src/components/switch/index.scss +1 -0
  13. package/src/components/switch/index.tsx +10 -0
  14. package/src/components/switch/markup/Switch.tsx +76 -0
  15. package/src/components/switch/markup/index.ts +1 -0
  16. package/src/components/switch/styles/index.scss +2 -0
  17. package/src/components/switch/styles/switch.scss +63 -0
  18. package/src/components/switch/styles/variables.scss +21 -0
  19. package/src/components/switch/types/index.ts +1 -0
  20. package/src/components/switch/types/switch.ts +46 -0
  21. package/src/components/tab/index.tsx +1 -2
  22. package/src/components/tab/markup/Label.tsx +22 -0
  23. package/src/components/tab/markup/TabList.tsx +27 -29
  24. package/src/components/tab/markup/TabRoot.tsx +16 -71
  25. package/src/components/tab/markup/TabTrigger.tsx +2 -15
  26. package/src/components/tab/styles/index.scss +2 -198
  27. package/src/components/tab/styles/tab.scss +190 -0
  28. package/src/components/tab/styles/variables.scss +39 -0
  29. package/src/components/tab/types/index.ts +29 -6
  30. package/src/components/tab/utils/tab-context.ts +1 -6
  31. package/src/index.scss +1 -0
  32. package/src/index.tsx +1 -0
  33. package/src/components/badge/hooks/index.ts +0 -4
  34. package/src/components/badge/img/.gitkeep +0 -0
  35. package/src/components/badge/utils/index.ts +0 -21
  36. package/src/components/tab/hooks/index.ts +0 -4
@@ -0,0 +1,53 @@
1
+ import type { CSSProperties, ComponentPropsWithoutRef, ReactNode } from "react";
2
+ import type { BadgePreset, BadgeSize, BadgeStyle } from "./options";
3
+
4
+ type NativeFigureProps = Omit<ComponentPropsWithoutRef<"figure">, "style">;
5
+
6
+ /**
7
+ * Badge Props; status/info label badge public props
8
+ * @property {ReactNode} [children] 표시할 라벨이다. 생략하면 dot만 렌더링한다.
9
+ * @property {"xsmall" | "small" | "medium"} [size] Figma size 축이다.
10
+ * @property {"fill" | "outlined" | "dot" | "count"} [style] badge 시각 스타일 축이다.
11
+ * @property {"primary" | "secondary" | "tertiary" | "gray" | "green" | "yellow" | "orange" | "red"} [preset] style에 대응하는 semantic 색상 preset이다.
12
+ * @property {string} [textColor] 라벨 텍스트 색상 CSS 값 또는 토큰 참조 문자열이다.
13
+ * @property {string} [backgroundColor] 배경 또는 dot 색상 CSS 값 또는 토큰 참조 문자열이다.
14
+ * @property {string} [borderColor] 외곽선 색상 CSS 값 또는 토큰 참조 문자열이다.
15
+ * @property {CSSProperties} [inlineStyle] 원본 figure 요소에 적용할 inline style이다.
16
+ */
17
+ export interface BadgeProps extends Omit<NativeFigureProps, "children"> {
18
+ /**
19
+ * 표시할 라벨. 생략하면 dot 스타일만 렌더링된다.
20
+ */
21
+ children?: ReactNode;
22
+ /**
23
+ * Figma size 축 (xsmall/small/medium)
24
+ */
25
+ size?: BadgeSize;
26
+ /**
27
+ * style 축 (fill/outlined/dot/count)
28
+ */
29
+ style?: BadgeStyle;
30
+ /**
31
+ * style에 대응하는 semantic 색상 preset이다.
32
+ */
33
+ preset?: BadgePreset;
34
+ /**
35
+ * 라벨 텍스트 색상 CSS 값 또는 토큰 참조 문자열이다.
36
+ * 예: `var(--color-common-100)`
37
+ */
38
+ textColor?: string;
39
+ /**
40
+ * 배경 또는 dot 색상 CSS 값 또는 토큰 참조 문자열이다.
41
+ * 예: `var(--color-primary-default)`
42
+ */
43
+ backgroundColor?: string;
44
+ /**
45
+ * 외곽선 색상 CSS 값 또는 토큰 참조 문자열이다.
46
+ * 예: `var(--color-border-assistive)`
47
+ */
48
+ borderColor?: string;
49
+ /**
50
+ * 원본 figure 요소에 적용할 인라인 스타일.
51
+ */
52
+ inlineStyle?: CSSProperties;
53
+ }
@@ -0,0 +1 @@
1
+ @use "./styles/index.scss";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Switch; standard toggle leaf 카테고리 배럴
3
+ * @desc
4
+ * - `Switch`: on/off 전환만 담당하는 leaf switch 컴포넌트다.
5
+ * - `SwitchProps`, `SwitchSize`: public 계약 타입이다.
6
+ */
7
+ import "./index.scss";
8
+
9
+ export * from "./markup";
10
+ export type * from "./types";
@@ -0,0 +1,76 @@
1
+ import clsx from "clsx";
2
+ import { forwardRef, useState } from "react";
3
+ import type { MouseEvent } from "react";
4
+ import type { SwitchProps } from "../types";
5
+
6
+ /**
7
+ * Switch; standard on/off toggle leaf 컴포넌트
8
+ * @component
9
+ * @param {SwitchProps} props
10
+ * @param {"small" | "medium"} [props.size="small"] Figma size 축이다.
11
+ * @param {boolean} [props.checked] 제어형 checked 상태다.
12
+ * @param {boolean} [props.defaultChecked=false] 비제어 초기 checked 상태다.
13
+ * @param {(checked: boolean, event: MouseEvent<HTMLButtonElement>) => void} [props.onCheckedChange]
14
+ * checked 상태 변경 핸들러다.
15
+ * @param {boolean} [props.disabled] 비활성 여부다.
16
+ * @param {string} [props.className] button root className override다.
17
+ * @example
18
+ * <Switch aria-label="알림 수신" defaultChecked />
19
+ */
20
+ const Switch = forwardRef<HTMLButtonElement, SwitchProps>(function Switch(
21
+ {
22
+ size = "small",
23
+ checked,
24
+ defaultChecked = false,
25
+ disabled = false,
26
+ className,
27
+ onCheckedChange,
28
+ onClick,
29
+ ...restProps
30
+ },
31
+ ref,
32
+ ) {
33
+ const [uncontrolledChecked, setUncontrolledChecked] =
34
+ useState(defaultChecked);
35
+ const isControlled = typeof checked === "boolean";
36
+ const isChecked = isControlled ? checked : uncontrolledChecked;
37
+
38
+ const onToggle = (event: MouseEvent<HTMLButtonElement>) => {
39
+ // 변경: 소비자가 defaultPrevented로 토글을 막을 수 있도록 onClick을 먼저 실행한다.
40
+ onClick?.(event);
41
+
42
+ if (event.defaultPrevented || disabled) {
43
+ return;
44
+ }
45
+
46
+ const nextChecked = !isChecked;
47
+
48
+ if (!isControlled) {
49
+ setUncontrolledChecked(nextChecked);
50
+ }
51
+
52
+ onCheckedChange?.(nextChecked, event);
53
+ };
54
+
55
+ return (
56
+ <button
57
+ {...restProps}
58
+ ref={ref}
59
+ type="button"
60
+ role="switch"
61
+ aria-checked={isChecked}
62
+ disabled={disabled}
63
+ className={clsx("switch", className)}
64
+ data-size={size}
65
+ data-state={isChecked ? "checked" : "unchecked"}
66
+ onClick={onToggle}
67
+ >
68
+ {/* 변경: standard variant는 handle만 렌더링하고, with text는 후속 확장 범위로 보류한다. */}
69
+ <span className="switch-handle" aria-hidden="true" />
70
+ </button>
71
+ );
72
+ });
73
+
74
+ Switch.displayName = "Switch";
75
+
76
+ export { Switch };
@@ -0,0 +1 @@
1
+ export { Switch } from "./Switch";
@@ -0,0 +1,2 @@
1
+ @use "./variables.scss";
2
+ @use "./switch.scss";
@@ -0,0 +1,63 @@
1
+ .switch {
2
+ --switch-track-width: var(--switch-track-width-small);
3
+ --switch-track-height: var(--switch-track-height-small);
4
+ --switch-track-padding: var(--switch-track-padding-small);
5
+ --switch-handle-size: var(--switch-handle-size-small);
6
+ display: flex;
7
+ align-items: center;
8
+ justify-content: flex-start;
9
+ width: var(--switch-track-width);
10
+ min-width: var(--switch-track-width);
11
+ height: var(--switch-track-height);
12
+ padding: var(--switch-track-padding);
13
+ border: none;
14
+ border-radius: 999px;
15
+ background-color: var(--switch-track-background-unchecked);
16
+ cursor: pointer;
17
+ transition:
18
+ background-color 0.2s ease,
19
+ box-shadow 0.2s ease,
20
+ opacity 0.2s ease;
21
+ }
22
+
23
+ .switch:where([data-size="medium"]) {
24
+ --switch-track-width: var(--switch-track-width-medium);
25
+ --switch-track-height: var(--switch-track-height-medium);
26
+ --switch-track-padding: var(--switch-track-padding-medium);
27
+ --switch-handle-size: var(--switch-handle-size-medium);
28
+ }
29
+
30
+ .switch:where([data-state="checked"]) {
31
+ background-color: var(--switch-track-background-checked);
32
+ }
33
+
34
+ .switch:where(:focus-visible) {
35
+ box-shadow: 0 0 0 2px var(--switch-focus-ring);
36
+ }
37
+
38
+ .switch:where(:disabled) {
39
+ cursor: not-allowed;
40
+ opacity: var(--switch-disabled-opacity);
41
+ }
42
+
43
+ .switch-handle {
44
+ display: flex;
45
+ width: var(--switch-handle-size);
46
+ min-width: var(--switch-handle-size);
47
+ height: var(--switch-handle-size);
48
+ border-radius: 999px;
49
+ background-color: var(--switch-thumb-background);
50
+ box-shadow: var(--switch-thumb-shadow-unchecked);
51
+ transition: transform 0.2s ease;
52
+ }
53
+
54
+ .switch:where([data-state="checked"]) .switch-handle {
55
+ /* 변경: handle 이동 거리는 frame width - handle size - 양쪽 padding 합으로 고정한다. */
56
+ box-shadow: var(--switch-thumb-shadow-checked);
57
+ transform: translateX(
58
+ calc(
59
+ var(--switch-track-width) - var(--switch-handle-size) -
60
+ (var(--switch-track-padding) * 2)
61
+ )
62
+ );
63
+ }
@@ -0,0 +1,21 @@
1
+ :root {
2
+ --switch-track-width-small: 48px;
3
+ --switch-track-height-small: 24px;
4
+ --switch-track-padding-small: 3px;
5
+ --switch-handle-size-small: 18px;
6
+
7
+ --switch-track-width-medium: 68px;
8
+ --switch-track-height-medium: 34px;
9
+ --switch-track-padding-medium: 2px;
10
+ --switch-handle-size-medium: 30px;
11
+
12
+ --switch-track-background-unchecked: var(--color-surface-strong);
13
+ --switch-track-background-checked: var(--color-primary-standard);
14
+ --switch-thumb-background: var(--color-surface-static-white);
15
+ --switch-thumb-shadow-unchecked:
16
+ 0px 2px 8px rgba(0, 0, 0, 0.04), 0px 0px 4px rgba(0, 0, 0, 0.08);
17
+ --switch-thumb-shadow-checked:
18
+ 0px 2px 8px rgba(0, 0, 0, 0.08), 0px 0px 4px rgba(0, 0, 0, 0.12);
19
+ --switch-focus-ring: var(--color-primary-focus);
20
+ --switch-disabled-opacity: 0.4;
21
+ }
@@ -0,0 +1 @@
1
+ export type * from "./switch";
@@ -0,0 +1,46 @@
1
+ import type { ComponentPropsWithoutRef, MouseEvent } from "react";
2
+
3
+ type NativeButtonProps = Omit<
4
+ ComponentPropsWithoutRef<"button">,
5
+ "aria-checked" | "children" | "onChange" | "role" | "type"
6
+ >;
7
+
8
+ /**
9
+ * Switch size; standard switch size 축
10
+ * @typedef {"small" | "medium"} SwitchSize
11
+ */
12
+ export type SwitchSize = "small" | "medium";
13
+
14
+ /**
15
+ * Switch props; standard toggle leaf public props
16
+ * @property {"small" | "medium"} [size] Figma size 축이다.
17
+ * @property {boolean} [checked] 제어형 checked 상태다.
18
+ * @property {boolean} [defaultChecked] 비제어 초기 checked 상태다.
19
+ * @property {(checked: boolean, event: MouseEvent<HTMLButtonElement>) => void} [onCheckedChange] checked 상태 변경 핸들러다.
20
+ * @property {boolean} [disabled] 비활성 여부다.
21
+ */
22
+ export interface SwitchProps extends NativeButtonProps {
23
+ /**
24
+ * Figma size 축이다.
25
+ */
26
+ size?: SwitchSize;
27
+ /**
28
+ * 제어형 checked 상태다.
29
+ */
30
+ checked?: boolean;
31
+ /**
32
+ * 비제어 초기 checked 상태다.
33
+ */
34
+ defaultChecked?: boolean;
35
+ /**
36
+ * checked 상태 변경 핸들러다.
37
+ */
38
+ onCheckedChange?: (
39
+ checked: boolean,
40
+ event: MouseEvent<HTMLButtonElement>,
41
+ ) => void;
42
+ /**
43
+ * 비활성 여부다.
44
+ */
45
+ disabled?: boolean;
46
+ }
@@ -3,11 +3,10 @@
3
3
  * @desc
4
4
  * - `TabRoot`: tabs value 상태를 관리하는 루트다.
5
5
  * - `TabList`, `TabTrigger`, `TabContent`: tabs anatomy 도구다.
6
- * - `TabContext`, `useTabContext`: tab 스타일 context util이다.
6
+ * - `TabContext`, `useTabContext`: tab 스타일 공유 context util이다.
7
7
  */
8
8
  import "./index.scss";
9
9
 
10
10
  export * from "./markup";
11
- export * from "./hooks";
12
11
  export type * from "./types";
13
12
  export * from "./utils";
@@ -0,0 +1,22 @@
1
+ import clsx from "clsx";
2
+ import { Slot } from "../../slot";
3
+ import type { TabLabelProps } from "../types";
4
+
5
+ /**
6
+ * Tab Label; trigger label className 고정 텍스트 슬롯
7
+ * @component
8
+ * @param {TabLabelProps} props
9
+ * @param {React.ElementType} [props.as] 렌더링할 요소. 기본값은 span.
10
+ * @param {React.ReactNode} [props.children] 라벨 콘텐츠.
11
+ * @param {string} [props.className] 라벨 className.
12
+ */
13
+ const TabLabel = ({ className, ...restProps }: TabLabelProps) => {
14
+ return (
15
+ <Slot.Text
16
+ className={clsx("tab-trigger-label", className)}
17
+ {...restProps}
18
+ />
19
+ );
20
+ };
21
+
22
+ export { TabLabel };
@@ -1,9 +1,9 @@
1
1
  import * as TabsPrimitive from "@radix-ui/react-tabs";
2
2
  import clsx from "clsx";
3
- import { forwardRef, useEffect, useMemo } from "react";
3
+ import { forwardRef } from "react";
4
4
  import type { CSSProperties } from "react";
5
5
  import type { TabListProps } from "../types";
6
- import { useTabContext, DEFAULT_TAB_CONTEXT_VALUE } from "../utils";
6
+ import { DEFAULT_TAB_CONTEXT_VALUE, TabContext, useTabContext } from "../utils";
7
7
 
8
8
  /**
9
9
  * TabList: Tab trigger container with variant/tone propagation.
@@ -38,36 +38,34 @@ const TabList = forwardRef<HTMLDivElement, TabListProps>(
38
38
  scale ?? parentContext.scale ?? DEFAULT_TAB_CONTEXT_VALUE.scale;
39
39
  const resolvedColor =
40
40
  color ?? parentContext.color ?? DEFAULT_TAB_CONTEXT_VALUE.color;
41
-
42
- useEffect(() => {
43
- parentContext.setSharedConfig?.(
44
- resolvedVariant,
45
- resolvedColor,
46
- resolvedScale,
47
- );
48
- }, [parentContext, resolvedVariant, resolvedColor, resolvedScale]);
49
-
50
- const listStyle = useMemo<CSSProperties>(
51
- () => ({
52
- ...(style ?? {}),
53
- "--tab-color-active": resolvedColor,
54
- }),
55
- [style, resolvedColor],
56
- );
41
+ // 변경: List-local override는 nearest provider로만 전달해 Root state 역주입을 제거한다.
42
+ const listStyle = color
43
+ ? ({
44
+ ...(style ?? {}),
45
+ "--tab-color-active": resolvedColor,
46
+ } as CSSProperties)
47
+ : style;
57
48
 
58
49
  return (
59
- <TabsPrimitive.List
60
- {...restProps}
61
- ref={forwardedRef}
62
- className={clsx("tab-list", className)}
63
- data-variant={resolvedVariant}
64
- data-scale={resolvedScale}
65
- data-full-width={fullWidth ? "true" : undefined}
66
- data-color={resolvedColor}
67
- style={listStyle}
50
+ <TabContext.Provider
51
+ value={{
52
+ variant: resolvedVariant,
53
+ color: resolvedColor,
54
+ scale: resolvedScale,
55
+ }}
68
56
  >
69
- {children}
70
- </TabsPrimitive.List>
57
+ <TabsPrimitive.List
58
+ {...restProps}
59
+ ref={forwardedRef}
60
+ className={clsx("tab-list", className)}
61
+ data-variant={resolvedVariant}
62
+ data-scale={resolvedScale}
63
+ data-full-width={fullWidth ? "true" : undefined}
64
+ style={listStyle}
65
+ >
66
+ {children}
67
+ </TabsPrimitive.List>
68
+ </TabContext.Provider>
71
69
  );
72
70
  },
73
71
  );
@@ -1,31 +1,10 @@
1
1
  import * as TabsPrimitive from "@radix-ui/react-tabs";
2
2
  import clsx from "clsx";
3
- import { forwardRef, useEffect, useMemo, useState } from "react";
3
+ import { forwardRef } from "react";
4
4
  import type { CSSProperties } from "react";
5
- import type { TabRootProps, TabScale } from "../types";
5
+ import type { TabRootProps } from "../types";
6
6
  import { TabContext, DEFAULT_TAB_CONTEXT_VALUE } from "../utils";
7
7
 
8
- const TAB_SCALE_STYLES: Record<TabScale, Record<string, string>> = {
9
- small: {
10
- "--tab-label-font-size": "var(--font-heading-xxsmall-size, 15px)",
11
- "--tab-label-font-weight": "var(--font-heading-xxsmall-weight, 600)",
12
- "--tab-height": "40px",
13
- "--tab-padding-x": "var(--spacing-padding-4, 8px)",
14
- },
15
- medium: {
16
- "--tab-label-font-size": "var(--font-heading-xsmall-size, 17px)",
17
- "--tab-label-font-weight": "var(--font-heading-xsmall-weight, 600)",
18
- "--tab-height": "48px",
19
- "--tab-padding-x": "var(--spacing-padding-8, 24px)",
20
- },
21
- large: {
22
- "--tab-label-font-size": "var(--font-heading-small-size, 19px)",
23
- "--tab-label-font-weight": "var(--font-heading-small-weight, 600)",
24
- "--tab-height": "56px",
25
- "--tab-padding-x": "var(--spacing-padding-8, 24px)",
26
- },
27
- };
28
-
29
8
  /**
30
9
  * TabRoot: TabsPrimitive.Root thin wrapper with tab data context.
31
10
  * @component
@@ -43,9 +22,9 @@ const TAB_SCALE_STYLES: Record<TabScale, Record<string, string>> = {
43
22
  const TabRoot = forwardRef<HTMLDivElement, TabRootProps>(
44
23
  (
45
24
  {
46
- variant: variantProp = DEFAULT_TAB_CONTEXT_VALUE.variant,
47
- scale: scaleProp = DEFAULT_TAB_CONTEXT_VALUE.scale,
48
- color: colorProp = DEFAULT_TAB_CONTEXT_VALUE.color,
25
+ variant: variantProp,
26
+ scale: scaleProp,
27
+ color: colorProp,
49
28
  className,
50
29
  children,
51
30
  style,
@@ -53,53 +32,19 @@ const TabRoot = forwardRef<HTMLDivElement, TabRootProps>(
53
32
  },
54
33
  forwardedRef,
55
34
  ) => {
56
- const [variant, setVariant] = useState(variantProp);
57
- const [color, setColor] = useState(colorProp);
58
- const [scale, setScale] = useState(scaleProp);
59
-
60
- useEffect(() => {
61
- setVariant(variantProp);
62
- }, [variantProp]);
63
-
64
- useEffect(() => {
65
- setColor(colorProp);
66
- }, [colorProp]);
67
-
68
- useEffect(() => {
69
- setScale(scaleProp);
70
- }, [scaleProp]);
71
-
72
- const contextValue = useMemo(
73
- () => ({
74
- variant,
75
- color,
76
- scale,
77
- setSharedConfig: (
78
- nextVariant: typeof variant,
79
- nextColor: typeof color,
80
- nextScale: typeof scale,
81
- ) => {
82
- setVariant(nextVariant);
83
- setColor(nextColor);
84
- setScale(nextScale);
85
- },
86
- }),
87
- [variant, color, scale],
88
- );
89
-
90
- const resolvedScaleStyle =
91
- TAB_SCALE_STYLES[scale] ?? TAB_SCALE_STYLES.medium;
92
- const rootStyle = useMemo<CSSProperties>(
93
- () => ({
94
- ...(style ?? {}),
95
- "--tab-color-active": color,
96
- ...resolvedScaleStyle,
97
- }),
98
- [style, color, resolvedScaleStyle],
99
- );
35
+ const variant = variantProp ?? DEFAULT_TAB_CONTEXT_VALUE.variant;
36
+ const scale = scaleProp ?? DEFAULT_TAB_CONTEXT_VALUE.scale;
37
+ const color = colorProp ?? DEFAULT_TAB_CONTEXT_VALUE.color;
38
+ // 변경: runtime color prop만 CSS 변수로 주입하고, size 토큰은 styles/variables.scss에서 관리한다.
39
+ const rootStyle = colorProp
40
+ ? ({
41
+ ...(style ?? {}),
42
+ "--tab-color-active": colorProp,
43
+ } as CSSProperties)
44
+ : style;
100
45
 
101
46
  return (
102
- <TabContext.Provider value={contextValue}>
47
+ <TabContext.Provider value={{ variant, color, scale }}>
103
48
  <TabsPrimitive.Root
104
49
  {...restProps}
105
50
  ref={forwardedRef}
@@ -1,21 +1,9 @@
1
1
  import * as TabsPrimitive from "@radix-ui/react-tabs";
2
2
  import clsx from "clsx";
3
3
  import { forwardRef } from "react";
4
- import type { ReactNode } from "react";
5
4
  import type { TabTriggerProps } from "../types";
6
5
  import { useTabContext } from "../utils";
7
-
8
- const wrapLabel = (children: ReactNode) => {
9
- if (children === null || children === undefined) {
10
- return null;
11
- }
12
-
13
- if (typeof children === "string" || typeof children === "number") {
14
- return <span className="tab-trigger-label">{children}</span>;
15
- }
16
-
17
- return children;
18
- };
6
+ import { TabLabel } from "./Label";
19
7
 
20
8
  /**
21
9
  * TabTrigger: 개별 탭 버튼. icon slot을 지원한다.
@@ -31,7 +19,6 @@ const TabTrigger = forwardRef<HTMLButtonElement, TabTriggerProps>(
31
19
  ({ icon, children, className, ...restProps }, forwardedRef) => {
32
20
  const { variant, scale } = useTabContext();
33
21
  const hasIcon = Boolean(icon);
34
- const normalizedChildren = wrapLabel(children);
35
22
 
36
23
  return (
37
24
  <TabsPrimitive.Trigger
@@ -44,7 +31,7 @@ const TabTrigger = forwardRef<HTMLButtonElement, TabTriggerProps>(
44
31
  data-disabled={restProps.disabled ? "true" : undefined}
45
32
  >
46
33
  {icon ? <span className="tab-trigger-icon">{icon}</span> : null}
47
- {normalizedChildren}
34
+ <TabLabel>{children}</TabLabel>
48
35
  </TabsPrimitive.Trigger>
49
36
  );
50
37
  },