@jbpark/ui-kit 9.1.0 → 10.0.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 (114) hide show
  1. package/README.ko.md +18 -17
  2. package/README.md +18 -17
  3. package/dist/Button.d.mts +1 -1
  4. package/dist/Button.d.mts.map +1 -1
  5. package/dist/Button.mjs +4 -5
  6. package/dist/Button.mjs.map +1 -1
  7. package/dist/Tag.d.mts.map +1 -1
  8. package/dist/Tag.mjs.map +1 -1
  9. package/dist/components/atoms/checkbox/checkbox.mjs +1 -1
  10. package/dist/components/atoms/checkbox/checkbox.mjs.map +1 -1
  11. package/dist/components/atoms/option-group.mjs.map +1 -1
  12. package/dist/components/atoms/popover.d.mts +3 -1
  13. package/dist/components/atoms/popover.d.mts.map +1 -1
  14. package/dist/components/atoms/popover.mjs +10 -111
  15. package/dist/components/atoms/popover.mjs.map +1 -1
  16. package/dist/components/atoms/progress.mjs +3 -4
  17. package/dist/components/atoms/progress.mjs.map +1 -1
  18. package/dist/components/atoms/radio/context.mjs +2 -2
  19. package/dist/components/atoms/radio/context.mjs.map +1 -1
  20. package/dist/components/atoms/radio/group.d.mts.map +1 -1
  21. package/dist/components/atoms/radio/group.mjs +8 -6
  22. package/dist/components/atoms/radio/group.mjs.map +1 -1
  23. package/dist/components/atoms/radio/radio.d.mts +2 -5
  24. package/dist/components/atoms/radio/radio.d.mts.map +1 -1
  25. package/dist/components/atoms/radio/radio.mjs +0 -1
  26. package/dist/components/atoms/radio/radio.mjs.map +1 -1
  27. package/dist/components/atoms/rich-text-editor/content-classes.mjs +1 -1
  28. package/dist/components/atoms/rich-text-editor/content-classes.mjs.map +1 -1
  29. package/dist/components/atoms/rich-text-editor/rich-text-editor.mjs +1 -1
  30. package/dist/components/atoms/rich-text-editor/rich-text-editor.mjs.map +1 -1
  31. package/dist/components/atoms/rich-text-editor/toolbar-button.mjs.map +1 -1
  32. package/dist/components/atoms/rich-text-editor/toolbar-presets.mjs.map +1 -1
  33. package/dist/components/atoms/rich-text-editor/toolbar.mjs +1 -1
  34. package/dist/components/atoms/rich-text-editor/toolbar.mjs.map +1 -1
  35. package/dist/components/atoms/select.mjs +5 -1
  36. package/dist/components/atoms/select.mjs.map +1 -1
  37. package/dist/components/atoms/slider/slider.mjs.map +1 -1
  38. package/dist/components/atoms/switch.d.mts +1 -1
  39. package/dist/components/atoms/switch.d.mts.map +1 -1
  40. package/dist/components/atoms/switch.mjs +3 -3
  41. package/dist/components/atoms/switch.mjs.map +1 -1
  42. package/dist/components/molecules/collapse.mjs +3 -10
  43. package/dist/components/molecules/collapse.mjs.map +1 -1
  44. package/dist/components/organisms/drawer.d.mts +1 -2
  45. package/dist/components/organisms/drawer.d.mts.map +1 -1
  46. package/dist/components/organisms/drawer.mjs +5 -7
  47. package/dist/components/organisms/drawer.mjs.map +1 -1
  48. package/dist/components/organisms/modal.d.mts.map +1 -1
  49. package/dist/components/organisms/modal.mjs +1 -3
  50. package/dist/components/organisms/modal.mjs.map +1 -1
  51. package/dist/components/templates/container.d.mts +4 -3
  52. package/dist/components/templates/container.d.mts.map +1 -1
  53. package/dist/components/templates/container.mjs +10 -6
  54. package/dist/components/templates/container.mjs.map +1 -1
  55. package/dist/components/templates/index.d.mts +13 -0
  56. package/dist/components/templates/layout/content.d.mts +4 -3
  57. package/dist/components/templates/layout/content.d.mts.map +1 -1
  58. package/dist/components/templates/layout/content.mjs +14 -9
  59. package/dist/components/templates/layout/content.mjs.map +1 -1
  60. package/dist/core/accordion.d.mts +1 -1
  61. package/dist/core/accordion.mjs +12 -12
  62. package/dist/core/accordion.mjs.map +1 -1
  63. package/dist/core/badge.d.mts +4 -16
  64. package/dist/core/badge.d.mts.map +1 -1
  65. package/dist/core/badge.mjs +12 -21
  66. package/dist/core/badge.mjs.map +1 -1
  67. package/dist/core/button.d.mts +5 -4
  68. package/dist/core/button.d.mts.map +1 -1
  69. package/dist/core/button.mjs +4 -4
  70. package/dist/core/button.mjs.map +1 -1
  71. package/dist/core/calendar.mjs +2 -1
  72. package/dist/core/calendar.mjs.map +1 -1
  73. package/dist/core/checkbox.d.mts +1 -1
  74. package/dist/core/checkbox.mjs +14 -14
  75. package/dist/core/checkbox.mjs.map +1 -1
  76. package/dist/core/dialog.d.mts +1 -1
  77. package/dist/core/dialog.mjs +25 -33
  78. package/dist/core/dialog.mjs.map +1 -1
  79. package/dist/core/drawer.d.mts +1 -1
  80. package/dist/core/drawer.mjs +45 -46
  81. package/dist/core/drawer.mjs.map +1 -1
  82. package/dist/core/label.d.mts +1 -2
  83. package/dist/core/label.mjs +1 -3
  84. package/dist/core/label.mjs.map +1 -1
  85. package/dist/core/popover.d.mts +1 -1
  86. package/dist/core/popover.mjs +42 -37
  87. package/dist/core/popover.mjs.map +1 -1
  88. package/dist/core/progress.d.mts +1 -1
  89. package/dist/core/progress.mjs +7 -10
  90. package/dist/core/progress.mjs.map +1 -1
  91. package/dist/core/radio-group.d.mts +3 -7
  92. package/dist/core/radio-group.mjs +15 -20
  93. package/dist/core/radio-group.mjs.map +1 -1
  94. package/dist/core/select.d.mts +7 -3
  95. package/dist/core/select.d.mts.map +1 -1
  96. package/dist/core/select.mjs +60 -56
  97. package/dist/core/select.mjs.map +1 -1
  98. package/dist/core/separator.d.mts +1 -1
  99. package/dist/core/separator.mjs +6 -5
  100. package/dist/core/separator.mjs.map +1 -1
  101. package/dist/core/slider.d.mts +1 -1
  102. package/dist/core/slider.mjs +38 -27
  103. package/dist/core/slider.mjs.map +1 -1
  104. package/dist/core/switch.d.mts +1 -1
  105. package/dist/core/switch.mjs +15 -15
  106. package/dist/core/switch.mjs.map +1 -1
  107. package/dist/index.d.mts +1 -0
  108. package/dist/lib/z-layers.mjs +4 -6
  109. package/dist/lib/z-layers.mjs.map +1 -1
  110. package/dist/providers/config/config.mjs +2 -2
  111. package/dist/providers/config/config.mjs.map +1 -1
  112. package/dist/style.css +330 -455
  113. package/package.json +8 -20
  114. package/dist/core/radio-group.d.mts.map +0 -1
package/README.ko.md CHANGED
@@ -25,7 +25,7 @@ src/
25
25
  │ ├── molecules/ # 🔬 분자 - 원자들의 조합
26
26
  │ ├── organisms/ # 🦠 유기체 - 복잡한 UI 블록
27
27
  │ └── templates/ # 📄 템플릿 - 페이지 레이아웃
28
- ├── core/ # ⚙️ 핵심 UI 로직 (Radix UI 기반)
28
+ ├── core/ # ⚙️ 핵심 UI 로직 (Base UI 기반)
29
29
  ├── lib/
30
30
  │ ├── enums/ # 📋 열거형 타입
31
31
  │ └── utils/ # 🛠 유틸리티 함수
@@ -90,15 +90,15 @@ src/
90
90
 
91
91
  ### Core 모듈
92
92
 
93
- Radix UI 기반의 접근성 우선 핵심 컴포넌트들:
93
+ Base UI 기반의 접근성 우선 핵심 컴포넌트들:
94
94
 
95
- - `accordion.tsx` - 아코디언 컴포넌트 (Radix UI 기반)
95
+ - `accordion.tsx` - 아코디언 컴포넌트 (Base UI 기반)
96
96
  - `button.tsx` - 버튼 컴포넌트 (class-variance-authority로 variants 관리)
97
- - `dialog.tsx` - 다이얼로그 컴포넌트 (Radix UI 기반)
98
- - `drawer.tsx` - 드로어 컴포넌트 (Vaul 기반)
99
- - `progress.tsx` - 진행률 컴포넌트 (Radix UI 기반)
97
+ - `dialog.tsx` - 다이얼로그 컴포넌트 (Base UI 기반)
98
+ - `drawer.tsx` - 드로어 컴포넌트 (Base UI dialog 기반)
99
+ - `progress.tsx` - 진행률 컴포넌트 (Base UI 기반)
100
100
  - `skeleton.tsx` - 스켈레톤 컴포넌트
101
- - `switch.tsx` - 스위치 컴포넌트 (Radix UI 기반)
101
+ - `switch.tsx` - 스위치 컴포넌트 (Base UI 기반)
102
102
 
103
103
  ### 유틸리티
104
104
 
@@ -129,14 +129,20 @@ import '@jbpark/ui-kit/style.css';
129
129
 
130
130
  function App() {
131
131
  return (
132
- <Layout>
133
- <Typography.Title>안녕하세요!</Typography.Title>
134
- <Button variant="primary">클릭하세요</Button>
135
- </Layout>
132
+ <div data-ui-root>
133
+ <Layout>
134
+ <Typography.Title>안녕하세요!</Typography.Title>
135
+ <Button variant="primary">클릭하세요</Button>
136
+ </Layout>
137
+ </div>
136
138
  );
137
139
  }
138
140
  ```
139
141
 
142
+ 애플리케이션 레이아웃 루트에 `data-ui-root`를 지정하세요. 패키지 스타일시트가
143
+ 해당 요소에 `isolation: isolate`를 적용해 Base UI 포털이 앱 내부의 z-index와
144
+ 경쟁하지 않고 페이지 콘텐츠 위에 표시되도록 합니다.
145
+
140
146
  ### 개별 컴포넌트 import
141
147
 
142
148
  ```tsx
@@ -210,12 +216,7 @@ import '@jbpark/ui-kit/style.css';
210
216
 
211
217
  ### UI 라이브러리
212
218
 
213
- - **Radix UI** - 접근성 우선 헤드리스 UI 컴포넌트
214
- - `@radix-ui/react-accordion` (1.2.12)
215
- - `@radix-ui/react-dialog` (1.1.15)
216
- - `@radix-ui/react-progress` (1.1.7)
217
- - `@radix-ui/react-slot` (1.2.3)
218
- - `@radix-ui/react-switch` (1.2.6)
219
+ - **Base UI** - 접근성 우선 헤드리스 UI 컴포넌트
219
220
  - **Lucide React 0.542.0** - 아이콘 라이브러리
220
221
  - **Motion 12.23.12** - 애니메이션 라이브러리
221
222
  - **Swiper 11.2.10** - 터치 슬라이더
package/README.md CHANGED
@@ -25,7 +25,7 @@ src/
25
25
  │ ├── molecules/ # 🔬 Molecules - Combinations of atoms
26
26
  │ ├── organisms/ # 🦠 Organisms - Complex UI blocks
27
27
  │ └── templates/ # 📄 Templates - Page layouts
28
- ├── core/ # ⚙️ Core UI logic (Radix UI based)
28
+ ├── core/ # ⚙️ Core UI logic (Base UI based)
29
29
  ├── lib/
30
30
  │ ├── enums/ # 📋 Enumeration types
31
31
  │ └── utils/ # 🛠 Utility functions
@@ -90,15 +90,15 @@ Page layout templates
90
90
 
91
91
  ### Core Module
92
92
 
93
- Accessibility-first core components based on Radix UI:
93
+ Accessibility-first core components based on Base UI:
94
94
 
95
- - `accordion.tsx` - Accordion component (Radix UI based)
95
+ - `accordion.tsx` - Accordion component (Base UI based)
96
96
  - `button.tsx` - Button component (variants managed with class-variance-authority)
97
- - `dialog.tsx` - Dialog component (Radix UI based)
98
- - `drawer.tsx` - Drawer component (Vaul based)
99
- - `progress.tsx` - Progress component (Radix UI based)
97
+ - `dialog.tsx` - Dialog component (Base UI based)
98
+ - `drawer.tsx` - Drawer component (Base UI dialog based)
99
+ - `progress.tsx` - Progress component (Base UI based)
100
100
  - `skeleton.tsx` - Skeleton component
101
- - `switch.tsx` - Switch component (Radix UI based)
101
+ - `switch.tsx` - Switch component (Base UI based)
102
102
 
103
103
  ### Utilities
104
104
 
@@ -129,14 +129,20 @@ import '@jbpark/ui-kit/style.css';
129
129
 
130
130
  function App() {
131
131
  return (
132
- <Layout>
133
- <Typography.Title>Hello!</Typography.Title>
134
- <Button variant="primary">Click me</Button>
135
- </Layout>
132
+ <div data-ui-root>
133
+ <Layout>
134
+ <Typography.Title>Hello!</Typography.Title>
135
+ <Button variant="primary">Click me</Button>
136
+ </Layout>
137
+ </div>
136
138
  );
137
139
  }
138
140
  ```
139
141
 
142
+ Put `data-ui-root` on your application layout root. The included stylesheet
143
+ applies `isolation: isolate` there so Base UI portals render above page content
144
+ without competing with z-index values inside the app.
145
+
140
146
  ### Import Individual Components
141
147
 
142
148
  ```tsx
@@ -210,12 +216,7 @@ import '@jbpark/ui-kit/style.css';
210
216
 
211
217
  ### UI Libraries
212
218
 
213
- - **Radix UI** - Accessible headless UI components
214
- - `@radix-ui/react-accordion` (1.2.12)
215
- - `@radix-ui/react-dialog` (1.1.15)
216
- - `@radix-ui/react-progress` (1.1.7)
217
- - `@radix-ui/react-slot` (1.2.3)
218
- - `@radix-ui/react-switch` (1.2.6)
219
+ - **Base UI** - Accessible headless UI components
219
220
  - **Lucide React 0.542.0** - Icon library
220
221
  - **Motion 12.23.12** - Animation library
221
222
  - **Swiper 11.2.10** - Touch slider
package/dist/Button.d.mts CHANGED
@@ -90,7 +90,7 @@ interface Props extends Omit<React$1.ComponentProps<typeof Core>, 'size' | 'vari
90
90
  icon: React$1.ReactNode;
91
91
  };
92
92
  }
93
- declare const Button: ({ icon, className, type, variant, htmlType, size, color, shape, block, disabled, loading, danger, asChild, children, onMouseDown, ...props }: Props) => React$1.JSX.Element;
93
+ declare const Button: ({ icon, className, type, variant, htmlType, size, color, shape, block, disabled, loading, danger, nativeButton, children, onMouseDown, ...props }: Props) => React$1.JSX.Element;
94
94
  //#endregion
95
95
  export { Props, Button as default };
96
96
  //# sourceMappingURL=Button.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.mts","names":[],"sources":["../src/components/atoms/button.tsx"],"mappings":";;;;;cAaM,aAAI;;;;;;;;;;;;;KAcL;;;;;;;;KAUA;UAGY,cAAc,KAC7B,QAAM,sBAAsB;EAG5B,OAAO,QAAM;EACb;EACA;EACA;;;;;;;;EAQA,sCAAsC;;;;;;;;;;;;;;;;;;EAkBtC;;;;;;;;;;;;;;;;EAgBA,yEAOI;;;;;;EAMJ;EACA;;;;;;;EAOA,QAAQ;EACR;IAAsB,MAAM,QAAM;;;cAmH9B,WAAU,MAAA,WAAA,MAAA,SAAA,UAAA,MAAA,OAAA,OAAA,OAAA,UAAA,SAAA,QAAA,SAAA,UAAA,gBAAA,SAiBb,UAAK,QAAA,IAAA"}
1
+ {"version":3,"file":"Button.d.mts","names":[],"sources":["../src/components/atoms/button.tsx"],"mappings":";;;;;cAYM,aAAI;;;;;;;;;;;;;KAcL;;;;;;;;KAUA;UAGY,cAAc,KAC7B,QAAM,sBAAsB;EAG5B,OAAO,QAAM;EACb;EACA;EACA;;;;;;;;EAQA,sCAAsC;;;;;;;;;;;;;;;;;;EAkBtC;;;;;;;;;;;;;;;;EAgBA,yEAOI;;;;;;EAMJ;EACA;;;;;;;EAOA,QAAQ;EACR;IAAsB,MAAM,QAAM;;;cAmH9B,WAAU,MAAA,WAAA,MAAA,SAAA,UAAA,MAAA,OAAA,OAAA,OAAA,UAAA,SAAA,QAAA,cAAA,UAAA,gBAAA,SAiBb,UAAK,QAAA,IAAA"}
package/dist/Button.mjs CHANGED
@@ -3,7 +3,6 @@ import { cn } from "./utils.mjs";
3
3
  import { useConfig } from "./providers/config/context.mjs";
4
4
  import { Button as Button$1 } from "./core/button.mjs";
5
5
  import "react";
6
- import { Slottable } from "@radix-ui/react-slot";
7
6
  import { LoaderCircle } from "lucide-react";
8
7
  import { jsx, jsxs } from "react/jsx-runtime";
9
8
  //#region src/components/atoms/button.tsx
@@ -106,7 +105,7 @@ const shapesClasses = {
106
105
  circle: "rounded-full",
107
106
  round: "rounded-2xl"
108
107
  };
109
- const Button = ({ icon, className, type, variant, htmlType = "button", size, color, shape, block = false, disabled, loading, danger, asChild = false, children, onMouseDown, ...props }) => {
108
+ const Button = ({ icon, className, type, variant, htmlType = "button", size, color, shape, block = false, disabled, loading, danger, nativeButton = true, children, onMouseDown, ...props }) => {
110
109
  const { componentSize, defaultProps } = useConfig();
111
110
  const buttonDefaults = defaultProps?.button;
112
111
  const resolvedShape = shape ?? buttonDefaults?.shape ?? "default";
@@ -123,7 +122,7 @@ const Button = ({ icon, className, type, variant, htmlType = "button", size, col
123
122
  return /* @__PURE__ */ jsxs(Core, {
124
123
  variant: null,
125
124
  size: null,
126
- asChild,
125
+ nativeButton,
127
126
  "data-slot": "button",
128
127
  "data-variant": resolvedVariant,
129
128
  "data-size": resolvedSize,
@@ -134,7 +133,7 @@ const Button = ({ icon, className, type, variant, htmlType = "button", size, col
134
133
  "text-(--btn-fg)",
135
134
  "border-(--btn-border)"
136
135
  ] : ["text-(--btn-bg)", "border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]"]), className),
137
- type: htmlType,
136
+ type: nativeButton ? htmlType : void 0,
138
137
  disabled: disabled || isLoading,
139
138
  "aria-busy": isLoading,
140
139
  "data-color": computedColor,
@@ -142,7 +141,7 @@ const Button = ({ icon, className, type, variant, htmlType = "button", size, col
142
141
  onMouseDown?.(e);
143
142
  },
144
143
  ...props,
145
- children: [displayIcon, /* @__PURE__ */ jsx(Slottable, { children })]
144
+ children: [displayIcon, children]
146
145
  });
147
146
  };
148
147
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Button.mjs","names":["button.Button"],"sources":["../src/components/atoms/button.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { Slottable } from '@radix-ui/react-slot';\nimport { LoaderCircle } from 'lucide-react';\n\nimport { useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { button } from '../../core';\nimport { type PresetColor } from '../../lib/colors';\n\nconst Core = button.Button;\n\n/**\n * shadcn's own `variant` words, accepted on top of this component's own\n * vocabulary rather than replacing it. They are sugar in exactly the sense\n * `type` is: each expands to a `(color, variant)` pair, so a snippet copied\n * from the shadcn docs renders as the nearest thing on this library's scale\n * instead of erroring.\n *\n * `link` is deliberately absent: it already exists as one of this component's\n * own variants and already renders what shadcn's `link` renders, so mapping it\n * would change `variant=\"link\"`'s resolved colour from `default` to `primary`\n * for existing callers.\n */\ntype ShadcnVariant =\n 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost';\n\n/**\n * shadcn's `size` words. The `icon*` entries additionally force the icon-only\n * (square, unpadded) treatment, which this component otherwise infers from\n * `icon` being set with no children — without that, the shadcn idiom of\n * passing the icon as *children* (`<Button size=\"icon\"><Trash /></Button>`)\n * would render a normal padded button.\n */\ntype ShadcnSize =\n 'default' | 'xs' | 'sm' | 'lg' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg';\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'size' | 'variant' | 'type'\n> {\n icon?: React.ReactNode;\n block?: boolean;\n danger?: boolean;\n disabled?: boolean;\n /**\n * Size on this library's antd-style scale. shadcn's words are accepted too\n * and map onto that scale: `sm`/`xs` → `small`, `default` → `middle`,\n * `lg` → `large`. There is no separate `xs` step here, so `xs` renders as\n * `small`. The `icon*` entries pick the same sizes and additionally force\n * the icon-only treatment.\n */\n size?: 'small' | 'middle' | 'large' | ShadcnSize;\n /**\n * Syntactic sugar for a `(color, variant)` pair. **Will follow `variant` and\n * `color` if provided** — `type` only fills in the axes you leave unset.\n *\n * | `type` | equivalent to |\n * | --------- | -------------------------------------- |\n * | `primary` | `color=\"primary\" variant=\"solid\"` |\n * | `default` | `color=\"default\" variant=\"outlined\"` |\n * | `dashed` | `color=\"default\" variant=\"dashed\"` |\n * | `text` | `color=\"default\" variant=\"text\"` |\n * | `link` | `color=\"primary\" variant=\"link\"` |\n *\n * So `<Button type=\"primary\">` is the same as\n * `<Button color=\"primary\" variant=\"solid\">`, and\n * `<Button type=\"primary\" variant=\"filled\">` keeps the primary color but\n * renders filled. `danger` still overrides the resolved color.\n */\n type?: 'primary' | 'default' | 'dashed' | 'text' | 'link';\n /**\n * Visual fill style, independent of `color`. Defaults to `'outlined'`.\n * Takes precedence over whatever `type` would have supplied.\n *\n * shadcn's words are accepted here as well and expand to a `(color, variant)`\n * pair the same way `type` does — `destructive` ≡ `color=\"danger\"\n * variant=\"solid\"`, `outline` ≡ `outlined`, `secondary` ≡ `filled`,\n * `ghost` ≡ `text`, `default` ≡ `color=\"primary\" variant=\"solid\"`. An\n * explicit `color` still wins over the one the word implies.\n *\n * ⚠️ `variant=\"default\"` (shadcn: a filled primary button) and\n * `type=\"default\"` (antd: a plain outlined button) mean opposite things.\n * They are different props, so nothing collides at runtime, but don't read\n * one as the other.\n */\n variant?:\n | 'solid'\n | 'outlined'\n | 'dashed'\n | 'filled'\n | 'text'\n | 'link'\n | ShadcnVariant;\n /**\n * Native `<button>` `type` (`button`/`submit`/`reset`), kept separate\n * from the antd-style `type` above. Defaults to `'button'` so a Button\n * placed inside a `<form>` doesn't submit it unless explicitly opted in.\n */\n htmlType?: 'button' | 'submit' | 'reset';\n shape?: 'default' | 'circle' | 'round';\n /**\n * Color, independent of `variant`. Defaults to `'default'`, or to whatever\n * `type` maps to when `type` is set. `danger` overrides this.\n *\n * Preset hues use Tailwind's colour names (#342).\n */\n color?: PresetColor | 'default' | 'primary' | 'danger';\n loading?: boolean | { icon: React.ReactNode };\n}\n\n// Geometry, the focus/aria/disabled chassis and the svg sizing come from\n// `core/button` again (#278 ③ is reversed here — see the core membership rule\n// in CLAUDE.md). Unlike Tag, Button pins no core variant at all: it passes\n// `variant={null} size={null}`, which cva treats as \"skip this axis entirely\",\n// so the primitive contributes only its base string and the atom keeps full\n// ownership of every colour and size class below. That leaves nothing for the\n// `variant=\"…\"` smell check to flag.\n//\n// The base still carries `rounded-md` and `text-sm`; the `rounded-*` from\n// `shapesClasses` and the `text-*` from `sizesClasses` come later in the class\n// list and override them, exactly as they did when this was absorbed.\nconst BUTTON_BASE = cn(\n 'gap-2 whitespace-nowrap font-medium transition-all',\n 'has-[>svg]:px-3',\n);\n\nconst variantClasses: Record<string, string> = {\n // solid used to inherit its fill from core/button's default variant; carry it\n // explicitly now that the primitive is absorbed. A colored solid overrides\n // this with the --btn-* custom properties further down.\n solid: cn('bg-primary text-primary-foreground', 'hover:bg-primary/90'),\n outlined: cn(\n 'border border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n dashed: cn(\n 'border border-dashed border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n filled: cn('bg-muted text-foreground', 'hover:bg-muted/80'),\n text: cn('bg-transparent text-foreground', 'hover:bg-accent'),\n link: cn(\n 'bg-transparent text-primary',\n 'underline-offset-4 hover:underline',\n 'hover:bg-primary/10',\n ),\n};\n\n/**\n * antd-style syntactic sugar: each `type` expands to a `(color, variant)` pair.\n * Explicit `color`/`variant` props win over whatever the `type` maps to, so\n * `type` only fills in the axes the caller left unset.\n *\n * Mirrors antd: `<Button type=\"primary\">` ≡ `<Button color=\"primary\" variant=\"solid\">`.\n */\nconst typeToColorVariant: Record<\n NonNullable<Props['type']>,\n { color: NonNullable<Props['color']>; variant: NonNullable<Props['variant']> }\n> = {\n primary: { color: 'primary', variant: 'solid' },\n default: { color: 'default', variant: 'outlined' },\n dashed: { color: 'default', variant: 'dashed' },\n text: { color: 'default', variant: 'text' },\n link: { color: 'primary', variant: 'link' },\n};\n\n/** The half of `variant` that is this component's own vocabulary. */\ntype OwnVariant = Exclude<NonNullable<Props['variant']>, ShadcnVariant>;\n\ntype OwnSize = 'small' | 'middle' | 'large';\n\n/**\n * shadcn's variant words → the `(color, variant)` pair each stands for here.\n * Same contract as `typeToColorVariant` above: the word only fills axes the\n * caller left unset, so an explicit `color` still wins over the implied one.\n */\nconst shadcnVariantToColorVariant: Record<\n ShadcnVariant,\n { color: NonNullable<Props['color']>; variant: OwnVariant }\n> = {\n default: { color: 'primary', variant: 'solid' },\n destructive: { color: 'danger', variant: 'solid' },\n outline: { color: 'default', variant: 'outlined' },\n secondary: { color: 'default', variant: 'filled' },\n ghost: { color: 'default', variant: 'text' },\n};\n\n/** shadcn's size words → this library's scale. */\nconst shadcnSizeToSize: Record<ShadcnSize, OwnSize> = {\n default: 'middle',\n xs: 'small',\n sm: 'small',\n lg: 'large',\n icon: 'middle',\n 'icon-xs': 'small',\n 'icon-sm': 'small',\n 'icon-lg': 'large',\n};\n\n/** The `size` words that also mean \"render this icon-only\". */\nconst ICON_SIZES = new Set<string>(['icon', 'icon-xs', 'icon-sm', 'icon-lg']);\n\nconst sizesClasses: Record<string, string> = {\n small: 'h-6 px-3 text-sm',\n middle: 'h-8 px-4 text-base',\n large: 'h-10 px-5 text-lg',\n};\n\nconst iconClasses: Record<string, string> = {\n small: `size-6 [&_svg:not([class*='size-'])]:size-3`,\n middle: `size-8 [&_svg:not([class*='size-'])]:size-4`,\n large: `size-10 [&_svg:not([class*='size-'])]:size-5`,\n};\n\nconst shapesClasses = {\n default: 'rounded-sm',\n circle: 'rounded-full',\n round: 'rounded-2xl',\n};\n\nconst Button = ({\n icon,\n className,\n type,\n variant,\n htmlType = 'button',\n size,\n color,\n shape,\n block = false,\n disabled,\n loading,\n danger,\n asChild = false,\n children,\n onMouseDown,\n ...props\n}: Props) => {\n const { componentSize, defaultProps } = useConfig();\n const buttonDefaults = defaultProps?.button as\n Partial<Pick<Props, 'shape' | 'variant' | 'color'>> | undefined;\n const resolvedShape = shape ?? buttonDefaults?.shape ?? 'default';\n // Both `variant` and `size` accept this library's own words *and* shadcn's.\n // Translate the shadcn ones first so everything below reasons in one\n // vocabulary; a word this library already owns (`link`, `text`, `small`, …)\n // is passed through untouched.\n const variantAlias =\n variant && variant in shadcnVariantToColorVariant\n ? shadcnVariantToColorVariant[variant as ShadcnVariant]\n : undefined;\n const ownVariant =\n variantAlias?.variant ?? (variant as OwnVariant | undefined);\n const ownSize =\n size && size in shadcnSizeToSize\n ? shadcnSizeToSize[size as ShadcnSize]\n : (size as OwnSize | undefined);\n const resolvedSize = ownSize ?? componentSize ?? 'middle';\n // A shadcn `size=\"icon*\"` says \"icon-only\" explicitly; otherwise it is\n // inferred from an `icon` with no children, which is how this component has\n // always detected it.\n const iconOnly =\n (size != null && ICON_SIZES.has(size)) || !!(icon && !children);\n // `type` is syntactic sugar that expands to a (color, variant) pair; explicit\n // `color`/`variant` win over it, so `type` only fills the axes left unset.\n // A shadcn `variant` word carries an implied colour and sits between the two:\n // more specific than `type`, less than an explicit `color`.\n // A `Config` default sits below the call-site `type` (which is more specific)\n // but above the library built-in. `danger` still trumps everything, matching\n // antd. Defaults live here rather than on the parameters so `type` gets a\n // chance to supply them first.\n const typeDefaults = type ? typeToColorVariant[type] : undefined;\n const resolvedVariant =\n ownVariant ??\n typeDefaults?.variant ??\n buttonDefaults?.variant ??\n 'outlined';\n const computedColor = danger\n ? 'danger'\n : (color ??\n variantAlias?.color ??\n typeDefaults?.color ??\n buttonDefaults?.color ??\n 'default');\n const colored = computedColor !== 'default';\n const isLoading = !!loading;\n\n const displayIcon = loading ? (\n typeof loading === 'object' ? (\n loading.icon\n ) : (\n <LoaderCircle className=\"animate-spin\" />\n )\n ) : (\n icon\n );\n\n return (\n <Core\n // cva skips an axis entirely when it is passed `null`, so the primitive\n // contributes only its base string and this atom keeps ownership of\n // every colour/size class.\n variant={null}\n size={null}\n asChild={asChild}\n data-slot=\"button\"\n data-variant={resolvedVariant}\n data-size={resolvedSize}\n className={cn(\n BUTTON_BASE,\n 'inline-flex items-center justify-center gap-x-2',\n 'rounded-lg',\n 'cursor-pointer',\n 'h-auto py-0',\n 'transition-all',\n variantClasses[resolvedVariant],\n sizesClasses[resolvedSize],\n iconOnly && ['p-0', iconClasses[resolvedSize]],\n shapesClasses[resolvedShape],\n block && 'w-full',\n colored &&\n (resolvedVariant === 'solid'\n ? [\n 'bg-(--btn-bg)',\n 'hover:bg-(--btn-bg-hover)',\n 'active:bg-(--btn-bg-active)',\n 'text-(--btn-fg)',\n 'border-(--btn-border)',\n ]\n : [\n 'text-(--btn-bg)',\n 'border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n //\n ]),\n className,\n //\n )}\n type={htmlType}\n disabled={disabled || isLoading}\n aria-busy={isLoading}\n data-color={computedColor}\n onMouseDown={e => {\n onMouseDown?.(e);\n }}\n {...props}\n >\n {displayIcon}\n {/*\n A Button renders two children (the icon slot and the caller's content),\n but Radix's Slot accepts multiple children only when exactly one is\n marked `Slottable` — without this marker `asChild` threw\n \"Slot failed to slot onto its children\" for *every* call, icon or not.\n `Slottable` is a plain fragment when `asChild` is false, so the\n non-asChild markup is unchanged.\n */}\n <Slottable>{children}</Slottable>\n </Core>\n );\n};\n\nexport default Button;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Button.mjs","names":["button.Button"],"sources":["../src/components/atoms/button.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { LoaderCircle } from 'lucide-react';\n\nimport { useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { button } from '../../core';\nimport { type PresetColor } from '../../lib/colors';\n\nconst Core = button.Button;\n\n/**\n * shadcn's own `variant` words, accepted on top of this component's own\n * vocabulary rather than replacing it. They are sugar in exactly the sense\n * `type` is: each expands to a `(color, variant)` pair, so a snippet copied\n * from the shadcn docs renders as the nearest thing on this library's scale\n * instead of erroring.\n *\n * `link` is deliberately absent: it already exists as one of this component's\n * own variants and already renders what shadcn's `link` renders, so mapping it\n * would change `variant=\"link\"`'s resolved colour from `default` to `primary`\n * for existing callers.\n */\ntype ShadcnVariant =\n 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost';\n\n/**\n * shadcn's `size` words. The `icon*` entries additionally force the icon-only\n * (square, unpadded) treatment, which this component otherwise infers from\n * `icon` being set with no children — without that, the shadcn idiom of\n * passing the icon as *children* (`<Button size=\"icon\"><Trash /></Button>`)\n * would render a normal padded button.\n */\ntype ShadcnSize =\n 'default' | 'xs' | 'sm' | 'lg' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg';\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'size' | 'variant' | 'type'\n> {\n icon?: React.ReactNode;\n block?: boolean;\n danger?: boolean;\n disabled?: boolean;\n /**\n * Size on this library's antd-style scale. shadcn's words are accepted too\n * and map onto that scale: `sm`/`xs` → `small`, `default` → `middle`,\n * `lg` → `large`. There is no separate `xs` step here, so `xs` renders as\n * `small`. The `icon*` entries pick the same sizes and additionally force\n * the icon-only treatment.\n */\n size?: 'small' | 'middle' | 'large' | ShadcnSize;\n /**\n * Syntactic sugar for a `(color, variant)` pair. **Will follow `variant` and\n * `color` if provided** — `type` only fills in the axes you leave unset.\n *\n * | `type` | equivalent to |\n * | --------- | -------------------------------------- |\n * | `primary` | `color=\"primary\" variant=\"solid\"` |\n * | `default` | `color=\"default\" variant=\"outlined\"` |\n * | `dashed` | `color=\"default\" variant=\"dashed\"` |\n * | `text` | `color=\"default\" variant=\"text\"` |\n * | `link` | `color=\"primary\" variant=\"link\"` |\n *\n * So `<Button type=\"primary\">` is the same as\n * `<Button color=\"primary\" variant=\"solid\">`, and\n * `<Button type=\"primary\" variant=\"filled\">` keeps the primary color but\n * renders filled. `danger` still overrides the resolved color.\n */\n type?: 'primary' | 'default' | 'dashed' | 'text' | 'link';\n /**\n * Visual fill style, independent of `color`. Defaults to `'outlined'`.\n * Takes precedence over whatever `type` would have supplied.\n *\n * shadcn's words are accepted here as well and expand to a `(color, variant)`\n * pair the same way `type` does — `destructive` ≡ `color=\"danger\"\n * variant=\"solid\"`, `outline` ≡ `outlined`, `secondary` ≡ `filled`,\n * `ghost` ≡ `text`, `default` ≡ `color=\"primary\" variant=\"solid\"`. An\n * explicit `color` still wins over the one the word implies.\n *\n * ⚠️ `variant=\"default\"` (shadcn: a filled primary button) and\n * `type=\"default\"` (antd: a plain outlined button) mean opposite things.\n * They are different props, so nothing collides at runtime, but don't read\n * one as the other.\n */\n variant?:\n | 'solid'\n | 'outlined'\n | 'dashed'\n | 'filled'\n | 'text'\n | 'link'\n | ShadcnVariant;\n /**\n * Native `<button>` `type` (`button`/`submit`/`reset`), kept separate\n * from the antd-style `type` above. Defaults to `'button'` so a Button\n * placed inside a `<form>` doesn't submit it unless explicitly opted in.\n */\n htmlType?: 'button' | 'submit' | 'reset';\n shape?: 'default' | 'circle' | 'round';\n /**\n * Color, independent of `variant`. Defaults to `'default'`, or to whatever\n * `type` maps to when `type` is set. `danger` overrides this.\n *\n * Preset hues use Tailwind's colour names (#342).\n */\n color?: PresetColor | 'default' | 'primary' | 'danger';\n loading?: boolean | { icon: React.ReactNode };\n}\n\n// Geometry, the focus/aria/disabled chassis and the svg sizing come from\n// `core/button` again (#278 ③ is reversed here — see the core membership rule\n// in CLAUDE.md). Unlike Tag, Button pins no core variant at all: it passes\n// `variant={null} size={null}`, which cva treats as \"skip this axis entirely\",\n// so the primitive contributes only its base string and the atom keeps full\n// ownership of every colour and size class below. That leaves nothing for the\n// `variant=\"…\"` smell check to flag.\n//\n// The base still carries `rounded-md` and `text-sm`; the `rounded-*` from\n// `shapesClasses` and the `text-*` from `sizesClasses` come later in the class\n// list and override them, exactly as they did when this was absorbed.\nconst BUTTON_BASE = cn(\n 'gap-2 whitespace-nowrap font-medium transition-all',\n 'has-[>svg]:px-3',\n);\n\nconst variantClasses: Record<string, string> = {\n // solid used to inherit its fill from core/button's default variant; carry it\n // explicitly now that the primitive is absorbed. A colored solid overrides\n // this with the --btn-* custom properties further down.\n solid: cn('bg-primary text-primary-foreground', 'hover:bg-primary/90'),\n outlined: cn(\n 'border border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n dashed: cn(\n 'border border-dashed border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n 'bg-background text-foreground',\n 'hover:bg-accent',\n ),\n filled: cn('bg-muted text-foreground', 'hover:bg-muted/80'),\n text: cn('bg-transparent text-foreground', 'hover:bg-accent'),\n link: cn(\n 'bg-transparent text-primary',\n 'underline-offset-4 hover:underline',\n 'hover:bg-primary/10',\n ),\n};\n\n/**\n * antd-style syntactic sugar: each `type` expands to a `(color, variant)` pair.\n * Explicit `color`/`variant` props win over whatever the `type` maps to, so\n * `type` only fills in the axes the caller left unset.\n *\n * Mirrors antd: `<Button type=\"primary\">` ≡ `<Button color=\"primary\" variant=\"solid\">`.\n */\nconst typeToColorVariant: Record<\n NonNullable<Props['type']>,\n { color: NonNullable<Props['color']>; variant: NonNullable<Props['variant']> }\n> = {\n primary: { color: 'primary', variant: 'solid' },\n default: { color: 'default', variant: 'outlined' },\n dashed: { color: 'default', variant: 'dashed' },\n text: { color: 'default', variant: 'text' },\n link: { color: 'primary', variant: 'link' },\n};\n\n/** The half of `variant` that is this component's own vocabulary. */\ntype OwnVariant = Exclude<NonNullable<Props['variant']>, ShadcnVariant>;\n\ntype OwnSize = 'small' | 'middle' | 'large';\n\n/**\n * shadcn's variant words → the `(color, variant)` pair each stands for here.\n * Same contract as `typeToColorVariant` above: the word only fills axes the\n * caller left unset, so an explicit `color` still wins over the implied one.\n */\nconst shadcnVariantToColorVariant: Record<\n ShadcnVariant,\n { color: NonNullable<Props['color']>; variant: OwnVariant }\n> = {\n default: { color: 'primary', variant: 'solid' },\n destructive: { color: 'danger', variant: 'solid' },\n outline: { color: 'default', variant: 'outlined' },\n secondary: { color: 'default', variant: 'filled' },\n ghost: { color: 'default', variant: 'text' },\n};\n\n/** shadcn's size words → this library's scale. */\nconst shadcnSizeToSize: Record<ShadcnSize, OwnSize> = {\n default: 'middle',\n xs: 'small',\n sm: 'small',\n lg: 'large',\n icon: 'middle',\n 'icon-xs': 'small',\n 'icon-sm': 'small',\n 'icon-lg': 'large',\n};\n\n/** The `size` words that also mean \"render this icon-only\". */\nconst ICON_SIZES = new Set<string>(['icon', 'icon-xs', 'icon-sm', 'icon-lg']);\n\nconst sizesClasses: Record<string, string> = {\n small: 'h-6 px-3 text-sm',\n middle: 'h-8 px-4 text-base',\n large: 'h-10 px-5 text-lg',\n};\n\nconst iconClasses: Record<string, string> = {\n small: `size-6 [&_svg:not([class*='size-'])]:size-3`,\n middle: `size-8 [&_svg:not([class*='size-'])]:size-4`,\n large: `size-10 [&_svg:not([class*='size-'])]:size-5`,\n};\n\nconst shapesClasses = {\n default: 'rounded-sm',\n circle: 'rounded-full',\n round: 'rounded-2xl',\n};\n\nconst Button = ({\n icon,\n className,\n type,\n variant,\n htmlType = 'button',\n size,\n color,\n shape,\n block = false,\n disabled,\n loading,\n danger,\n nativeButton = true,\n children,\n onMouseDown,\n ...props\n}: Props) => {\n const { componentSize, defaultProps } = useConfig();\n const buttonDefaults = defaultProps?.button as\n Partial<Pick<Props, 'shape' | 'variant' | 'color'>> | undefined;\n const resolvedShape = shape ?? buttonDefaults?.shape ?? 'default';\n // Both `variant` and `size` accept this library's own words *and* shadcn's.\n // Translate the shadcn ones first so everything below reasons in one\n // vocabulary; a word this library already owns (`link`, `text`, `small`, …)\n // is passed through untouched.\n const variantAlias =\n variant && variant in shadcnVariantToColorVariant\n ? shadcnVariantToColorVariant[variant as ShadcnVariant]\n : undefined;\n const ownVariant =\n variantAlias?.variant ?? (variant as OwnVariant | undefined);\n const ownSize =\n size && size in shadcnSizeToSize\n ? shadcnSizeToSize[size as ShadcnSize]\n : (size as OwnSize | undefined);\n const resolvedSize = ownSize ?? componentSize ?? 'middle';\n // A shadcn `size=\"icon*\"` says \"icon-only\" explicitly; otherwise it is\n // inferred from an `icon` with no children, which is how this component has\n // always detected it.\n const iconOnly =\n (size != null && ICON_SIZES.has(size)) || !!(icon && !children);\n // `type` is syntactic sugar that expands to a (color, variant) pair; explicit\n // `color`/`variant` win over it, so `type` only fills the axes left unset.\n // A shadcn `variant` word carries an implied colour and sits between the two:\n // more specific than `type`, less than an explicit `color`.\n // A `Config` default sits below the call-site `type` (which is more specific)\n // but above the library built-in. `danger` still trumps everything, matching\n // antd. Defaults live here rather than on the parameters so `type` gets a\n // chance to supply them first.\n const typeDefaults = type ? typeToColorVariant[type] : undefined;\n const resolvedVariant =\n ownVariant ??\n typeDefaults?.variant ??\n buttonDefaults?.variant ??\n 'outlined';\n const computedColor = danger\n ? 'danger'\n : (color ??\n variantAlias?.color ??\n typeDefaults?.color ??\n buttonDefaults?.color ??\n 'default');\n const colored = computedColor !== 'default';\n const isLoading = !!loading;\n\n const displayIcon = loading ? (\n typeof loading === 'object' ? (\n loading.icon\n ) : (\n <LoaderCircle className=\"animate-spin\" />\n )\n ) : (\n icon\n );\n\n return (\n <Core\n // cva skips an axis entirely when it is passed `null`, so the primitive\n // contributes only its base string and this atom keeps ownership of\n // every colour/size class.\n variant={null}\n size={null}\n nativeButton={nativeButton}\n data-slot=\"button\"\n data-variant={resolvedVariant}\n data-size={resolvedSize}\n className={cn(\n BUTTON_BASE,\n 'inline-flex items-center justify-center gap-x-2',\n 'rounded-lg',\n 'cursor-pointer',\n 'h-auto py-0',\n 'transition-all',\n variantClasses[resolvedVariant],\n sizesClasses[resolvedSize],\n iconOnly && ['p-0', iconClasses[resolvedSize]],\n shapesClasses[resolvedShape],\n block && 'w-full',\n colored &&\n (resolvedVariant === 'solid'\n ? [\n 'bg-(--btn-bg)',\n 'hover:bg-(--btn-bg-hover)',\n 'active:bg-(--btn-bg-active)',\n 'text-(--btn-fg)',\n 'border-(--btn-border)',\n ]\n : [\n 'text-(--btn-bg)',\n 'border-[color-mix(in_oklch,var(--btn-border),transparent_50%)]',\n //\n ]),\n className,\n //\n )}\n type={nativeButton ? htmlType : undefined}\n disabled={disabled || isLoading}\n aria-busy={isLoading}\n data-color={computedColor}\n onMouseDown={e => {\n onMouseDown?.(e);\n }}\n {...props}\n >\n {displayIcon}\n {children}\n </Core>\n );\n};\n\nexport default Button;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tag.d.mts","names":[],"sources":["../src/components/atoms/tag.tsx"],"mappings":";;;;;cAUM,aAAI;UAEO,cAAc,KAC7B,QAAM,sBAAsB;;;;;;EAQ5B;;;;;;;;;;;;EAYA,mEAC6D;;cA0BzD,QAAO,WAAA,SAAA,OAAA,aAAA,SAAmD,UAAK,QAAA,IAAA"}
1
+ {"version":3,"file":"Tag.d.mts","names":[],"sources":["../src/components/atoms/tag.tsx"],"mappings":";;;;;cAUM,aAAI;UAEO,cAAc,KAC7B,QAAM,sBAAsB;;;;;;EAQ5B;;;;;;;;;;;;EAYA,mEAC6D;;cAuBzD,QAAO,WAAA,SAAA,OAAA,aAAA,SAAmD,UAAK,QAAA,IAAA"}
package/dist/Tag.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Tag.mjs","names":["badge.Badge"],"sources":["../src/components/atoms/tag.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { badge } from '../../core';\nimport { type PresetColor } from '../../lib/colors';\n\nconst Core = badge.Badge;\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'variant' | 'color'\n> {\n /**\n * Fill style, aligned with `Button`'s vocabulary (#320). The pre-7.0\n * `'default'` spelling was removed — use `'filled'`, which renders\n * identically.\n */\n variant?: 'filled' | 'outlined';\n /**\n * Colour. Every value — the semantic states (`primary`/`success`/`warning`/\n * `danger`) as well as the palette shared with `Button` (`blue`, `red`,\n * `amber`, …) — resolves through the same `data-color` + `--tag-*` system\n * (#320), so any of them can be re-themed the same way.\n *\n * `success`/`warning` have no `Button` counterpart on purpose: a Tag marks\n * state, which is why antd's Tag also carries them while its Button does not.\n *\n * Preset hues use Tailwind's colour names (#342).\n */\n color?:\n 'default' | 'primary' | 'success' | 'warning' | 'danger' | PresetColor;\n}\n\n// Geometry, the focus/aria chassis and the svg sizing all come from\n// `core/badge` now (#278 ③ is reversed here — see the core membership rule in\n// CLAUDE.md). Tag pins the core `outline` variant because it supplies exactly\n// the neutral base Tag wants — a border plus `text-foreground` and the `[a&]`\n// hover treatment — and then repaints border/text/fill from the `--tag-*`\n// custom properties below. Pinning one core variant is deliberate and is why\n// the membership rule had to change; the alternative (absorbing the primitive)\n// is what left `core/badge` orphaned and three upstream releases stale.\nconst CORE_VARIANT = 'outline';\n\n// Every colour — semantic states and shared presets alike — resolves from the\n// `--tag-*` custom properties that `globals.css` sets per `data-color` (#320).\n// Before 7.0 only the presets took this path while the states carried bespoke\n// Tailwind classes, which meant `[data-color]` hooks and `--tag-*` overrides\n// worked on some colours but silently not on others.\n//\n// --tag-bg the hue; the border in `outlined`\n// --tag-fg text colour (defaults to --tag-bg)\n// --tag-tint the fill behind `filled` (defaults to a 10% --tag-bg wash)\nconst fillClasses = cn('border-transparent bg-(--tag-tint) text-(--tag-fg)');\n\nconst outlinedClasses = cn('border-(--tag-bg) text-(--tag-fg)');\n\nconst Tag = ({ className, variant, color, children, ...props }: Props) => {\n const { defaultProps } = useConfig();\n const tagDefaults = defaultProps?.tag as\n Partial<Pick<Props, 'variant' | 'color'>> | undefined;\n // An explicit prop wins over a `Config` default, which wins over the built-in\n // — the same resolution order `Button` uses.\n const resolvedVariant = variant ?? tagDefaults?.variant ?? 'filled';\n const resolvedColor = color ?? tagDefaults?.color ?? 'default';\n const isOutlined = resolvedVariant === 'outlined';\n\n return (\n <Core\n variant={CORE_VARIANT}\n // Overrides the core primitive's own `data-slot=\"badge\"`. The slot now\n // matches the public component name, which frees `badge` for the\n // antd-style Badge (a count/dot decorator, a different component from\n // this chip — shadcn's Badge is what antd calls a Tag).\n data-slot=\"tag\"\n // Emitted for every colour, not just the presets, so consumers can hook\n // `[data-color]` / `[data-variant]` uniformly. `data-variant` is what\n // lets `globals.css` give `default` a different text colour when\n // outlined without reintroducing a second class path here; it also\n // replaces the core primitive's own `data-variant`, which would\n // otherwise report the pinned core variant rather than Tag's.\n data-color={resolvedColor}\n data-variant={resolvedVariant}\n className={cn(\n 'rounded-full px-2.5 py-1',\n isOutlined ? outlinedClasses : fillClasses,\n className,\n //\n )}\n {...props}\n >\n {children}\n </Core>\n );\n};\n\nexport default Tag;\n"],"mappings":";;;;;;;AAUA,MAAM,OAAOA;AAmCb,MAAM,eAAe;AAWrB,MAAM,cAAc,GAAG,oDAAoD;AAE3E,MAAM,kBAAkB,GAAG,mCAAmC;AAE9D,MAAM,OAAO,EAAE,WAAW,SAAS,OAAO,UAAU,GAAG,YAAmB;CACxE,MAAM,EAAE,iBAAiB,UAAU;CACnC,MAAM,cAAc,cAAc;CAIlC,MAAM,kBAAkB,WAAW,aAAa,WAAW;CAC3D,MAAM,gBAAgB,SAAS,aAAa,SAAS;CAGrD,OACE,oBAAC,MAAD;EACE,SAAS;EAKT,aAAU;EAOV,cAAY;EACZ,gBAAc;EACd,WAAW,GACT,4BAnBa,oBAAoB,aAoBpB,kBAAkB,aAC/B,SAEF;EACA,GAAI;EAEH;CACG,CAAA;AAEV"}
1
+ {"version":3,"file":"Tag.mjs","names":["badge.Badge"],"sources":["../src/components/atoms/tag.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { badge } from '../../core';\nimport { type PresetColor } from '../../lib/colors';\n\nconst Core = badge.Badge;\n\nexport interface Props extends Omit<\n React.ComponentProps<typeof Core>,\n 'variant' | 'color'\n> {\n /**\n * Fill style, aligned with `Button`'s vocabulary (#320). The pre-7.0\n * `'default'` spelling was removed — use `'filled'`, which renders\n * identically.\n */\n variant?: 'filled' | 'outlined';\n /**\n * Colour. Every value — the semantic states (`primary`/`success`/`warning`/\n * `danger`) as well as the palette shared with `Button` (`blue`, `red`,\n * `amber`, …) — resolves through the same `data-color` + `--tag-*` system\n * (#320), so any of them can be re-themed the same way.\n *\n * `success`/`warning` have no `Button` counterpart on purpose: a Tag marks\n * state, which is why antd's Tag also carries them while its Button does not.\n *\n * Preset hues use Tailwind's colour names (#342).\n */\n color?:\n 'default' | 'primary' | 'success' | 'warning' | 'danger' | PresetColor;\n}\n\n// Geometry, the focus/aria chassis and the svg sizing all come from the\n// repo-owned `core/badge`. Tag pins the core `outline` variant because it\n// supplies exactly the neutral base Tag wants — a border plus `text-foreground`\n// and the `[a&]` hover treatment — then repaints border/text/fill from the\n// `--tag-*` custom properties below.\nconst CORE_VARIANT = 'outline';\n\n// Every colour — semantic states and shared presets alike — resolves from the\n// `--tag-*` custom properties that `globals.css` sets per `data-color` (#320).\n// Before 7.0 only the presets took this path while the states carried bespoke\n// Tailwind classes, which meant `[data-color]` hooks and `--tag-*` overrides\n// worked on some colours but silently not on others.\n//\n// --tag-bg the hue; the border in `outlined`\n// --tag-fg text colour (defaults to --tag-bg)\n// --tag-tint the fill behind `filled` (defaults to a 10% --tag-bg wash)\nconst fillClasses = cn('border-transparent bg-(--tag-tint) text-(--tag-fg)');\n\nconst outlinedClasses = cn('border-(--tag-bg) text-(--tag-fg)');\n\nconst Tag = ({ className, variant, color, children, ...props }: Props) => {\n const { defaultProps } = useConfig();\n const tagDefaults = defaultProps?.tag as\n Partial<Pick<Props, 'variant' | 'color'>> | undefined;\n // An explicit prop wins over a `Config` default, which wins over the built-in\n // — the same resolution order `Button` uses.\n const resolvedVariant = variant ?? tagDefaults?.variant ?? 'filled';\n const resolvedColor = color ?? tagDefaults?.color ?? 'default';\n const isOutlined = resolvedVariant === 'outlined';\n\n return (\n <Core\n variant={CORE_VARIANT}\n // Overrides the core primitive's own `data-slot=\"badge\"`. The slot now\n // matches the public component name, which frees `badge` for the\n // antd-style Badge (a count/dot decorator, a different component from\n // this chip — shadcn's Badge is what antd calls a Tag).\n data-slot=\"tag\"\n // Emitted for every colour, not just the presets, so consumers can hook\n // `[data-color]` / `[data-variant]` uniformly. `data-variant` is what\n // lets `globals.css` give `default` a different text colour when\n // outlined without reintroducing a second class path here; it also\n // replaces the core primitive's own `data-variant`, which would\n // otherwise report the pinned core variant rather than Tag's.\n data-color={resolvedColor}\n data-variant={resolvedVariant}\n className={cn(\n 'rounded-full px-2.5 py-1',\n isOutlined ? outlinedClasses : fillClasses,\n className,\n //\n )}\n {...props}\n >\n {children}\n </Core>\n );\n};\n\nexport default Tag;\n"],"mappings":";;;;;;;AAUA,MAAM,OAAOA;AAgCb,MAAM,eAAe;AAWrB,MAAM,cAAc,GAAG,oDAAoD;AAE3E,MAAM,kBAAkB,GAAG,mCAAmC;AAE9D,MAAM,OAAO,EAAE,WAAW,SAAS,OAAO,UAAU,GAAG,YAAmB;CACxE,MAAM,EAAE,iBAAiB,UAAU;CACnC,MAAM,cAAc,cAAc;CAIlC,MAAM,kBAAkB,WAAW,aAAa,WAAW;CAC3D,MAAM,gBAAgB,SAAS,aAAa,SAAS;CAGrD,OACE,oBAAC,MAAD;EACE,SAAS;EAKT,aAAU;EAOV,cAAY;EACZ,gBAAc;EACd,WAAW,GACT,4BAnBa,oBAAoB,aAoBpB,kBAAkB,aAC/B,SAEF;EACA,GAAI;EAEH;CACG,CAAA;AAEV"}
@@ -66,7 +66,7 @@ const Checkbox = ({ placement = "left", value: _value = "", children, className,
66
66
  value: itemValue,
67
67
  checked,
68
68
  disabled,
69
- className: cn(cursorClassName),
69
+ className: cn("rounded-sm", cursorClassName),
70
70
  onCheckedChange: onChange
71
71
  }), children && /* @__PURE__ */ jsx(CoreLabel, {
72
72
  htmlFor: id,
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.mjs","names":["checkbox","label"],"sources":["../../../../src/components/atoms/checkbox/checkbox.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useRef } from 'react';\n\nimport { useControllableState, useKeyPress } from '@jbpark/use-hooks';\nimport { Square, SquareCheck } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { checkbox, label } from '../../../core';\nimport { type OptionValue } from './group';\n\nconst { Checkbox: CoreCheckbox } = checkbox;\nconst { Label: CoreLabel } = label;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'onChange'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n disabled?: boolean;\n icons?: Partial<{ checked: React.ReactNode; unchecked: React.ReactNode }>;\n children?: React.ReactNode;\n onChange?: (checked: boolean) => void;\n}\n\nconst Checkbox = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n name,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [checked, setChecked] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const id = useId();\n const itemValue = String(_value);\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n setChecked(next);\n };\n\n const iconTriggerRef = useRef<HTMLSpanElement>(null);\n\n useKeyPress(\n ['Enter', 'space'],\n event => {\n event.preventDefault();\n onChange(!checked);\n },\n { target: iconTriggerRef, enabled: !!icons && !disabled },\n );\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"checkbox\"\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n ref={iconTriggerRef}\n role=\"checkbox\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n onChange(!checked);\n }}\n >\n {checked\n ? (icons.checked ?? <SquareCheck />)\n : (icons.unchecked ?? <Square />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : (\n <>\n <CoreCheckbox\n id={id}\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n className={cn(cursorClassName)}\n onCheckedChange={onChange}\n />\n {children && (\n <CoreLabel htmlFor={id} className={cn(cursorClassName, 'text-left')}>\n {children}\n </CoreLabel>\n )}\n </>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center gap-x-2',\n placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;;;;;;AAYA,MAAM,EAAE,UAAU,iBAAiBA;AACnC,MAAM,EAAE,OAAO,cAAcC;AAkB7B,MAAM,YAAY,EAChB,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,MACA,UAAU,kBAAkB,CAAC,GAC7B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;CACZ,CAAC;CAED,MAAM,KAAK,MAAM;CACjB,MAAM,YAAY,OAAO,MAAM;CAE/B,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;EAClC,IAAI,UACF;EAGF,WAAW,IAAI;CACjB;CAEA,MAAM,iBAAiB,OAAwB,IAAI;CAEnD,YACE,CAAC,SAAS,OAAO,IACjB,UAAS;EACP,MAAM,eAAe;EACrB,SAAS,CAAC,OAAO;CACnB,GACA;EAAE,QAAQ;EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;CAAS,CAC1D;CAEA,MAAM,gBAAgB,QACpB,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,SAAD;GACM;GACJ,QAAA;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;IACb,SAAS,EAAE,OAAO,OAAO;GAC3B;EACD,CAAA;EACD,oBAAC,QAAD;GACE,KAAK;GACL,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,eAAe;IACb,SAAS,CAAC,OAAO;GACnB;GAEC,UAAA,UACI,MAAM,WAAW,oBAAC,aAAD,CAAc,CAAA,IAC/B,MAAM,aAAa,oBAAC,QAAD,CAAS,CAAA;EAC7B,CAAA;EACL,YACC,oBAAC,SAAD;GACE,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,SAAS;GAER;EACI,CAAA;CAET,EAAA,CAAA,IAEF,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EACM;EACE;EACN,OAAO;EACE;EACC;EACV,WAAW,GAAG,eAAe;EAC7B,iBAAiB;CAClB,CAAA,GACA,YACC,oBAAC,WAAD;EAAW,SAAS;EAAI,WAAW,GAAG,iBAAiB,WAAW;EAC/D;CACQ,CAAA,CAEb,EAAA,CAAA;CAGJ,OACE,oBAAC,OAAD;EACE,WAAW,GACT,6BACA,cAAc,WAAW,oBACzB,iBACA,SAEF;EACA,GAAI;EAEH,UAAA;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"checkbox.mjs","names":["checkbox","label"],"sources":["../../../../src/components/atoms/checkbox/checkbox.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useRef } from 'react';\n\nimport { useControllableState, useKeyPress } from '@jbpark/use-hooks';\nimport { Square, SquareCheck } from 'lucide-react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { checkbox, label } from '../../../core';\nimport { type OptionValue } from './group';\n\nconst { Checkbox: CoreCheckbox } = checkbox;\nconst { Label: CoreLabel } = label;\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'onChange'\n> {\n placement?: 'left' | 'right';\n defaultChecked?: boolean;\n checked?: boolean;\n value?: OptionValue;\n /** Native form field name — participates in `FormData` when set. */\n name?: string;\n disabled?: boolean;\n icons?: Partial<{ checked: React.ReactNode; unchecked: React.ReactNode }>;\n children?: React.ReactNode;\n onChange?: (checked: boolean) => void;\n}\n\nconst Checkbox = ({\n placement = 'left',\n value: _value = '',\n children,\n className,\n icons,\n disabled,\n defaultChecked,\n checked: _checked,\n name,\n onChange: _onChange = () => {},\n ...props\n}: Props) => {\n const [checked, setChecked] = useControllableState<boolean>({\n value: _checked,\n defaultValue: defaultChecked ?? false,\n onChange: _onChange,\n });\n\n const id = useId();\n const itemValue = String(_value);\n\n const cursorClassName = disabled ? 'cursor-not-allowed' : 'cursor-pointer';\n\n const onChange = (next: boolean) => {\n if (disabled) {\n return;\n }\n\n setChecked(next);\n };\n\n const iconTriggerRef = useRef<HTMLSpanElement>(null);\n\n useKeyPress(\n ['Enter', 'space'],\n event => {\n event.preventDefault();\n onChange(!checked);\n },\n { target: iconTriggerRef, enabled: !!icons && !disabled },\n );\n\n const renderContent = icons ? (\n <>\n <input\n id={id}\n hidden\n type=\"checkbox\"\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n onChange={e => {\n onChange(e.target.checked);\n }}\n />\n <span\n ref={iconTriggerRef}\n role=\"checkbox\"\n aria-checked={checked}\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cn(cursorClassName, disabled && 'opacity-50')}\n onClick={() => {\n onChange(!checked);\n }}\n >\n {checked\n ? (icons.checked ?? <SquareCheck />)\n : (icons.unchecked ?? <Square />)}\n </span>\n {children && (\n <label\n className={cn(cursorClassName, disabled && 'opacity-50')}\n htmlFor={id}\n >\n {children}\n </label>\n )}\n </>\n ) : (\n <>\n <CoreCheckbox\n id={id}\n name={name}\n value={itemValue}\n checked={checked}\n disabled={disabled}\n // Keep the atom's established 4px radius after the Base UI migration;\n // tailwind-merge lets this override the core primitive's radius (#361).\n className={cn('rounded-sm', cursorClassName)}\n onCheckedChange={onChange}\n />\n {children && (\n <CoreLabel htmlFor={id} className={cn(cursorClassName, 'text-left')}>\n {children}\n </CoreLabel>\n )}\n </>\n );\n\n return (\n <div\n className={cn(\n 'flex items-center gap-x-2',\n placement === 'right' && 'flex-row-reverse',\n cursorClassName,\n className,\n //\n )}\n {...props}\n >\n {renderContent}\n </div>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;;;;;;AAYA,MAAM,EAAE,UAAU,iBAAiBA;AACnC,MAAM,EAAE,OAAO,cAAcC;AAkB7B,MAAM,YAAY,EAChB,YAAY,QACZ,OAAO,SAAS,IAChB,UACA,WACA,OACA,UACA,gBACA,SAAS,UACT,MACA,UAAU,kBAAkB,CAAC,GAC7B,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,cAAc,qBAA8B;EAC1D,OAAO;EACP,cAAc,kBAAkB;EAChC,UAAU;CACZ,CAAC;CAED,MAAM,KAAK,MAAM;CACjB,MAAM,YAAY,OAAO,MAAM;CAE/B,MAAM,kBAAkB,WAAW,uBAAuB;CAE1D,MAAM,YAAY,SAAkB;EAClC,IAAI,UACF;EAGF,WAAW,IAAI;CACjB;CAEA,MAAM,iBAAiB,OAAwB,IAAI;CAEnD,YACE,CAAC,SAAS,OAAO,IACjB,UAAS;EACP,MAAM,eAAe;EACrB,SAAS,CAAC,OAAO;CACnB,GACA;EAAE,QAAQ;EAAgB,SAAS,CAAC,CAAC,SAAS,CAAC;CAAS,CAC1D;CAEA,MAAM,gBAAgB,QACpB,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,SAAD;GACM;GACJ,QAAA;GACA,MAAK;GACC;GACN,OAAO;GACE;GACC;GACV,WAAU,MAAK;IACb,SAAS,EAAE,OAAO,OAAO;GAC3B;EACD,CAAA;EACD,oBAAC,QAAD;GACE,KAAK;GACL,MAAK;GACL,gBAAc;GACd,iBAAe;GACf,UAAU,WAAW,KAAK;GAC1B,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,eAAe;IACb,SAAS,CAAC,OAAO;GACnB;GAEC,UAAA,UACI,MAAM,WAAW,oBAAC,aAAD,CAAc,CAAA,IAC/B,MAAM,aAAa,oBAAC,QAAD,CAAS,CAAA;EAC7B,CAAA;EACL,YACC,oBAAC,SAAD;GACE,WAAW,GAAG,iBAAiB,YAAY,YAAY;GACvD,SAAS;GAER;EACI,CAAA;CAET,EAAA,CAAA,IAEF,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EACM;EACE;EACN,OAAO;EACE;EACC;EAGV,WAAW,GAAG,cAAc,eAAe;EAC3C,iBAAiB;CAClB,CAAA,GACA,YACC,oBAAC,WAAD;EAAW,SAAS;EAAI,WAAW,GAAG,iBAAiB,WAAW;EAC/D;CACQ,CAAA,CAEb,EAAA,CAAA;CAGJ,OACE,oBAAC,OAAD;EACE,WAAW,GACT,6BACA,cAAc,WAAW,oBACzB,iBACA,SAEF;EACA,GAAI;EAEH,UAAA;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"option-group.mjs","names":[],"sources":["../../../src/components/atoms/option-group.ts"],"sourcesContent":["export type OptionValue = string | number | boolean;\n\nexport interface Option {\n label: string;\n value: OptionValue;\n disabled?: boolean;\n}\n\nexport type Options = string[] | number[] | boolean[] | Option[];\n\nexport interface OptionGroupClassNames {\n wrapper?: string;\n item?: string;\n}\n\nexport const normalizeOptions = (options: Options): Option[] =>\n options.map(item =>\n typeof item === 'object'\n ? item\n : {\n label: `${item}`,\n value: item,\n },\n );\n\n// Radio.Group/Checkbox.Group both key selection off `value` (Radix's\n// RadioGroup matches items by it, and Checkbox.Group tests membership via\n// `value.includes(...)`), so two options sharing a value aren't just a\n// React list-key collision — they become indistinguishable to the\n// component's own selection logic, e.g. both rendering aria-checked=true\n// together. A duplicate is virtually always a caller mistake (two radios\n// for the \"same\" value can't be meaningfully different choices), so warn\n// instead of silently accepting it.\nexport const warnOnDuplicateOptionValues = (\n options: Option[],\n componentName: string,\n) => {\n const nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } })\n .process?.env?.NODE_ENV;\n\n if (nodeEnv === 'production') {\n return;\n }\n\n const seen = new Set<OptionValue>();\n const duplicates = new Set<OptionValue>();\n\n for (const option of options) {\n if (seen.has(option.value)) {\n duplicates.add(option.value);\n }\n seen.add(option.value);\n }\n\n if (duplicates.size > 0) {\n console.warn(\n `${componentName}: duplicate option value(s) [${[...duplicates].map(v => JSON.stringify(v)).join(', ')}] — options sharing a value render as if selecting one selects all of them, since selection is matched by value.`,\n );\n }\n};\n"],"mappings":";AAeA,MAAa,oBAAoB,YAC/B,QAAQ,KAAI,SACV,OAAO,SAAS,WACZ,OACA;CACE,OAAO,GAAG;CACV,OAAO;AACT,CACN;AAUF,MAAa,+BACX,SACA,kBACG;CAIH,IAHiB,WACd,SAAS,KAAK,aAED,cACd;CAGF,MAAM,uBAAO,IAAI,IAAiB;CAClC,MAAM,6BAAa,IAAI,IAAiB;CAExC,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,KAAK,IAAI,OAAO,KAAK,GACvB,WAAW,IAAI,OAAO,KAAK;EAE7B,KAAK,IAAI,OAAO,KAAK;CACvB;CAEA,IAAI,WAAW,OAAO,GACpB,QAAQ,KACN,GAAG,cAAc,+BAA+B,CAAC,GAAG,UAAU,CAAC,CAAC,KAAI,MAAK,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,iHACzG;AAEJ"}
1
+ {"version":3,"file":"option-group.mjs","names":[],"sources":["../../../src/components/atoms/option-group.ts"],"sourcesContent":["export type OptionValue = string | number | boolean;\n\nexport interface Option {\n label: string;\n value: OptionValue;\n disabled?: boolean;\n}\n\nexport type Options = string[] | number[] | boolean[] | Option[];\n\nexport interface OptionGroupClassNames {\n wrapper?: string;\n item?: string;\n}\n\nexport const normalizeOptions = (options: Options): Option[] =>\n options.map(item =>\n typeof item === 'object'\n ? item\n : {\n label: `${item}`,\n value: item,\n },\n );\n\n// Radio.Group/Checkbox.Group both key selection off `value` (Base UI's\n// Radio.Group matches items by it, and Checkbox.Group tests membership via\n// `value.includes(...)`), so two options sharing a value aren't just a\n// React list-key collision — they become indistinguishable to the\n// component's own selection logic, e.g. both rendering aria-checked=true\n// together. A duplicate is virtually always a caller mistake (two radios\n// for the \"same\" value can't be meaningfully different choices), so warn\n// instead of silently accepting it.\nexport const warnOnDuplicateOptionValues = (\n options: Option[],\n componentName: string,\n) => {\n const nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } })\n .process?.env?.NODE_ENV;\n\n if (nodeEnv === 'production') {\n return;\n }\n\n const seen = new Set<OptionValue>();\n const duplicates = new Set<OptionValue>();\n\n for (const option of options) {\n if (seen.has(option.value)) {\n duplicates.add(option.value);\n }\n seen.add(option.value);\n }\n\n if (duplicates.size > 0) {\n console.warn(\n `${componentName}: duplicate option value(s) [${[...duplicates].map(v => JSON.stringify(v)).join(', ')}] — options sharing a value render as if selecting one selects all of them, since selection is matched by value.`,\n );\n }\n};\n"],"mappings":";AAeA,MAAa,oBAAoB,YAC/B,QAAQ,KAAI,SACV,OAAO,SAAS,WACZ,OACA;CACE,OAAO,GAAG;CACV,OAAO;AACT,CACN;AAUF,MAAa,+BACX,SACA,kBACG;CAIH,IAHiB,WACd,SAAS,KAAK,aAED,cACd;CAGF,MAAM,uBAAO,IAAI,IAAiB;CAClC,MAAM,6BAAa,IAAI,IAAiB;CAExC,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,KAAK,IAAI,OAAO,KAAK,GACvB,WAAW,IAAI,OAAO,KAAK;EAE7B,KAAK,IAAI,OAAO,KAAK;CACvB;CAEA,IAAI,WAAW,OAAO,GACpB,QAAQ,KACN,GAAG,cAAc,+BAA+B,CAAC,GAAG,UAAU,CAAC,CAAC,KAAI,MAAK,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,iHACzG;AAEJ"}
@@ -2,13 +2,15 @@
2
2
  type Placement = 'top' | 'left' | 'right' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom';
3
3
  interface Props extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title' | 'content'> {
4
4
  title?: React.ReactNode;
5
+ /** Set to false when a custom trigger component renders a non-button element. */
6
+ nativeButton?: boolean;
5
7
  placement?: Placement;
6
8
  content: React.ReactNode;
7
9
  open?: boolean;
8
10
  defaultOpen?: boolean;
9
11
  onOpenChange?: (open: boolean) => void;
10
12
  }
11
- declare const Popover: ({ title, placement, className, content, children, open: _open, defaultOpen, onOpenChange, ...props }: Props) => import("react").JSX.Element;
13
+ declare const Popover: ({ title, nativeButton, placement, className, content, children, open: _open, defaultOpen, onOpenChange, ...props }: Props) => import("react").JSX.Element;
12
14
  //#endregion
13
15
  export { Props, Popover as default };
14
16
  //# sourceMappingURL=popover.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"popover.d.mts","names":[],"sources":["../../../src/components/atoms/popover.tsx"],"mappings":";KASK;UAcY,cAAc,KAC7B,MAAM;EAGN,QAAQ,MAAM;EACd,YAAY;EACZ,SAAS,MAAM;EACf;EACA;EACA,gBAAgB;;cA6JZ,YAAW,OAAA,WAAA,WAAA,SAAA,UAAA,MAAA,OAAA,aAAA,iBAAA,SAUd,0BAAK,IAAA"}
1
+ {"version":3,"file":"popover.d.mts","names":[],"sources":["../../../src/components/atoms/popover.tsx"],"mappings":";KAmBK;UAcY,cAAc,KAC7B,MAAM;EAGN,QAAQ,MAAM;;EAEd;EACA,YAAY;EACZ,SAAS,MAAM;EACf;EACA;EACA,gBAAgB;;cAqBZ,YAAW,OAAA,cAAA,WAAA,WAAA,SAAA,UAAA,MAAA,OAAA,aAAA,iBAAA,SAWd,0BAAK,IAAA"}
@@ -1,10 +1,12 @@
1
+ "use client";
1
2
  import { cn, renderConditional } from "../../utils.mjs";
2
3
  import { popover_exports } from "../../core/popover.mjs";
3
4
  import Typography from "../../Typography.mjs";
5
+ import { Children } from "react";
4
6
  import { jsx, jsxs } from "react/jsx-runtime";
5
7
  import { useControllableState } from "@jbpark/use-hooks";
6
8
  //#region src/components/atoms/popover.tsx
7
- const { Popover: CorePopover, PopoverContent, PopoverTrigger } = popover_exports;
9
+ const { Popover: CorePopover, PopoverContent, PopoverTrigger, PopoverArrow, PopoverTitle } = popover_exports;
8
10
  const placementMap = {
9
11
  top: {
10
12
  side: "top",
@@ -55,123 +57,20 @@ const placementMap = {
55
57
  align: "end"
56
58
  }
57
59
  };
58
- const beforeBase = "before:content-[\"\"] before:absolute before:h-0 before:w-0";
59
- const afterBase = "after:content-[\"\"] after:absolute after:h-0 after:w-0";
60
- const vBorderShape = "before:border-l-[9px] before:border-r-[9px] before:border-l-transparent before:border-r-transparent";
61
- const hBorderShape = "before:border-t-[9px] before:border-b-[9px] before:border-t-transparent before:border-b-transparent";
62
- const vFillShape = "after:border-l-8 after:border-r-8 after:border-l-transparent after:border-r-transparent";
63
- const hFillShape = "after:border-t-8 after:border-b-8 after:border-t-transparent after:border-b-transparent";
64
- const borderShapeBySide = {
65
- top: vBorderShape,
66
- bottom: vBorderShape,
67
- left: hBorderShape,
68
- right: hBorderShape
69
- };
70
- const fillShapeBySide = {
71
- top: vFillShape,
72
- bottom: vFillShape,
73
- left: hFillShape,
74
- right: hFillShape
75
- };
76
- const borderColorBySide = {
77
- top: "before:border-t-[9px] before:border-t-border",
78
- bottom: "before:border-b-[9px] before:border-b-border",
79
- left: "before:border-l-[9px] before:border-l-border",
80
- right: "before:border-r-[9px] before:border-r-border"
81
- };
82
- const fillColorBySide = {
83
- top: "after:border-t-8 after:border-t-popover",
84
- bottom: "after:border-b-8 after:border-b-popover",
85
- left: "after:border-l-8 after:border-l-popover",
86
- right: "after:border-r-8 after:border-r-popover"
87
- };
88
- const POSITION_CLASSES = {
89
- top: {
90
- start: {
91
- wrapper: "top-full left-4",
92
- before: "before:top-0 before:left-0",
93
- after: "after:-top-px after:left-px"
94
- },
95
- center: {
96
- wrapper: "top-full left-1/2 -translate-x-1/2",
97
- before: "before:top-0 before:left-1/2 before:-translate-x-1/2",
98
- after: "after:-top-px after:left-1/2 after:-translate-x-1/2"
99
- },
100
- end: {
101
- wrapper: "top-full right-4",
102
- before: "before:top-0 before:right-0",
103
- after: "after:-top-px after:right-px"
104
- }
105
- },
106
- bottom: {
107
- start: {
108
- wrapper: "bottom-full left-4",
109
- before: "before:bottom-0 before:left-0",
110
- after: "after:-bottom-px after:left-px"
111
- },
112
- center: {
113
- wrapper: "bottom-full left-1/2 -translate-x-1/2",
114
- before: "before:bottom-0 before:left-1/2 before:-translate-x-1/2",
115
- after: "after:-bottom-px after:left-1/2 after:-translate-x-1/2"
116
- },
117
- end: {
118
- wrapper: "bottom-full right-4",
119
- before: "before:bottom-0 before:right-0",
120
- after: "after:-bottom-px after:right-px"
121
- }
122
- },
123
- left: {
124
- start: {
125
- wrapper: "left-full top-4",
126
- before: "before:left-0 before:top-0",
127
- after: "after:-left-px after:top-px"
128
- },
129
- center: {
130
- wrapper: "left-full top-1/2 -translate-y-1/2",
131
- before: "before:left-0 before:top-1/2 before:-translate-y-1/2",
132
- after: "after:-left-px after:top-1/2 after:-translate-y-1/2"
133
- },
134
- end: {
135
- wrapper: "left-full bottom-4",
136
- before: "before:left-0 before:bottom-0",
137
- after: "after:-left-px after:bottom-px"
138
- }
139
- },
140
- right: {
141
- start: {
142
- wrapper: "right-full top-4",
143
- before: "before:right-0 before:top-0",
144
- after: "after:-right-px after:top-px"
145
- },
146
- center: {
147
- wrapper: "right-full top-1/2 -translate-y-1/2",
148
- before: "before:right-0 before:top-1/2 before:-translate-y-1/2",
149
- after: "after:-right-px after:top-1/2 after:-translate-y-1/2"
150
- },
151
- end: {
152
- wrapper: "right-full bottom-4",
153
- before: "before:right-0 before:bottom-0",
154
- after: "after:-right-px after:bottom-px"
155
- }
156
- }
157
- };
158
- const getArrowClassName = (side, align) => {
159
- const { wrapper, before, after } = POSITION_CLASSES[side][align];
160
- return cn("absolute", wrapper, beforeBase, before, borderShapeBySide[side], borderColorBySide[side], afterBase, after, fillShapeBySide[side], fillColorBySide[side]);
161
- };
162
- const Popover = ({ title, placement = "top", className, content, children, open: _open, defaultOpen, onOpenChange, ...props }) => {
60
+ const Popover = ({ title, nativeButton, placement = "top", className, content, children, open: _open, defaultOpen, onOpenChange, ...props }) => {
163
61
  const [open, setOpen] = useControllableState({
164
62
  value: _open,
165
63
  defaultValue: defaultOpen ?? false,
166
64
  onChange: onOpenChange
167
65
  });
168
66
  const { side, align } = placementMap[placement];
67
+ const trigger = Children.only(children);
169
68
  return /* @__PURE__ */ jsxs(CorePopover, {
170
69
  open,
171
70
  onOpenChange: setOpen,
172
71
  children: [/* @__PURE__ */ jsx(PopoverTrigger, {
173
- asChild: true,
174
- children
72
+ render: trigger,
73
+ nativeButton: nativeButton ?? (typeof trigger.type !== "string" || trigger.type === "button")
175
74
  }), /* @__PURE__ */ jsxs(PopoverContent, {
176
75
  ...props,
177
76
  align,
@@ -179,12 +78,12 @@ const Popover = ({ title, placement = "top", className, content, children, open:
179
78
  sideOffset: 16,
180
79
  className: cn("relative w-auto", className),
181
80
  children: [
182
- renderConditional(title, (v) => /* @__PURE__ */ jsx(Typography.Title, {
183
- level: 6,
81
+ renderConditional(title, (v) => /* @__PURE__ */ jsx(PopoverTitle, {
82
+ render: /* @__PURE__ */ jsx(Typography.Title, { level: 6 }),
184
83
  children: v
185
84
  })),
186
85
  content,
187
- /* @__PURE__ */ jsx("div", { className: getArrowClassName(side, align) })
86
+ /* @__PURE__ */ jsx(PopoverArrow, {})
188
87
  ]
189
88
  })]
190
89
  });
@@ -1 +1 @@
1
- {"version":3,"file":"popover.mjs","names":["popover"],"sources":["../../../src/components/atoms/popover.tsx"],"sourcesContent":["import { useControllableState } from '@jbpark/use-hooks';\n\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport { popover } from '../../core';\nimport Typography from './typography';\n\nconst { Popover: CorePopover, PopoverContent, PopoverTrigger } = popover;\n\ntype Placement =\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title' | 'content'\n> {\n title?: React.ReactNode;\n placement?: Placement;\n content: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\n\nconst placementMap: Record<Placement, { side: Side; align: Align }> = {\n top: { side: 'top', align: 'center' },\n left: { side: 'left', align: 'center' },\n right: { side: 'right', align: 'center' },\n bottom: { side: 'bottom', align: 'center' },\n topLeft: { side: 'top', align: 'start' },\n topRight: { side: 'top', align: 'end' },\n bottomLeft: { side: 'bottom', align: 'start' },\n bottomRight: { side: 'bottom', align: 'end' },\n leftTop: { side: 'left', align: 'start' },\n leftBottom: { side: 'left', align: 'end' },\n rightTop: { side: 'right', align: 'start' },\n rightBottom: { side: 'right', align: 'end' },\n};\n\nconst beforeBase = 'before:content-[\"\"] before:absolute before:h-0 before:w-0';\nconst afterBase = 'after:content-[\"\"] after:absolute after:h-0 after:w-0';\n\nconst vBorderShape =\n 'before:border-l-[9px] before:border-r-[9px] before:border-l-transparent before:border-r-transparent';\nconst hBorderShape =\n 'before:border-t-[9px] before:border-b-[9px] before:border-t-transparent before:border-b-transparent';\nconst vFillShape =\n 'after:border-l-8 after:border-r-8 after:border-l-transparent after:border-r-transparent';\nconst hFillShape =\n 'after:border-t-8 after:border-b-8 after:border-t-transparent after:border-b-transparent';\n\n// Top/bottom placements draw a vertical-edge triangle (border-l/border-r) —\n// the arrow points up/down, so its left/right edges form the point. Left/\n// right placements draw the horizontal-edge equivalent.\nconst borderShapeBySide: Record<Side, string> = {\n top: vBorderShape,\n bottom: vBorderShape,\n left: hBorderShape,\n right: hBorderShape,\n};\nconst fillShapeBySide: Record<Side, string> = {\n top: vFillShape,\n bottom: vFillShape,\n left: hFillShape,\n right: hFillShape,\n};\nconst borderColorBySide: Record<Side, string> = {\n top: 'before:border-t-[9px] before:border-t-border',\n bottom: 'before:border-b-[9px] before:border-b-border',\n left: 'before:border-l-[9px] before:border-l-border',\n right: 'before:border-r-[9px] before:border-r-border',\n};\nconst fillColorBySide: Record<Side, string> = {\n top: 'after:border-t-8 after:border-t-popover',\n bottom: 'after:border-b-8 after:border-b-popover',\n left: 'after:border-l-8 after:border-l-popover',\n right: 'after:border-r-8 after:border-r-popover',\n};\n\n// Tailwind v4 only extracts class candidates that appear as *literal*\n// strings in source — none of these ever do if built via\n// `` `${side}-full` `` style interpolation, so they'd silently never make\n// it into the generated CSS. This table exists purely so every class the\n// arrow can need appears literally somewhere in this file.\nconst POSITION_CLASSES: Record<\n Side,\n Record<Align, { wrapper: string; before: string; after: string }>\n> = {\n top: {\n start: {\n wrapper: 'top-full left-4',\n before: 'before:top-0 before:left-0',\n after: 'after:-top-px after:left-px',\n },\n center: {\n wrapper: 'top-full left-1/2 -translate-x-1/2',\n before: 'before:top-0 before:left-1/2 before:-translate-x-1/2',\n after: 'after:-top-px after:left-1/2 after:-translate-x-1/2',\n },\n end: {\n wrapper: 'top-full right-4',\n before: 'before:top-0 before:right-0',\n after: 'after:-top-px after:right-px',\n },\n },\n bottom: {\n start: {\n wrapper: 'bottom-full left-4',\n before: 'before:bottom-0 before:left-0',\n after: 'after:-bottom-px after:left-px',\n },\n center: {\n wrapper: 'bottom-full left-1/2 -translate-x-1/2',\n before: 'before:bottom-0 before:left-1/2 before:-translate-x-1/2',\n after: 'after:-bottom-px after:left-1/2 after:-translate-x-1/2',\n },\n end: {\n wrapper: 'bottom-full right-4',\n before: 'before:bottom-0 before:right-0',\n after: 'after:-bottom-px after:right-px',\n },\n },\n left: {\n start: {\n wrapper: 'left-full top-4',\n before: 'before:left-0 before:top-0',\n after: 'after:-left-px after:top-px',\n },\n center: {\n wrapper: 'left-full top-1/2 -translate-y-1/2',\n before: 'before:left-0 before:top-1/2 before:-translate-y-1/2',\n after: 'after:-left-px after:top-1/2 after:-translate-y-1/2',\n },\n end: {\n wrapper: 'left-full bottom-4',\n before: 'before:left-0 before:bottom-0',\n after: 'after:-left-px after:bottom-px',\n },\n },\n right: {\n start: {\n wrapper: 'right-full top-4',\n before: 'before:right-0 before:top-0',\n after: 'after:-right-px after:top-px',\n },\n center: {\n wrapper: 'right-full top-1/2 -translate-y-1/2',\n before: 'before:right-0 before:top-1/2 before:-translate-y-1/2',\n after: 'after:-right-px after:top-1/2 after:-translate-y-1/2',\n },\n end: {\n wrapper: 'right-full bottom-4',\n before: 'before:right-0 before:bottom-0',\n after: 'after:-right-px after:bottom-px',\n },\n },\n};\n\nconst getArrowClassName = (side: Side, align: Align) => {\n const { wrapper, before, after } = POSITION_CLASSES[side][align];\n\n return cn(\n 'absolute',\n wrapper,\n beforeBase,\n before,\n borderShapeBySide[side],\n borderColorBySide[side],\n afterBase,\n after,\n fillShapeBySide[side],\n fillColorBySide[side],\n );\n};\n\nconst Popover = ({\n title,\n placement = 'top',\n className,\n content,\n children,\n open: _open,\n defaultOpen,\n onOpenChange,\n ...props\n}: Props) => {\n const [open, setOpen] = useControllableState<boolean>({\n value: _open,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n const { side, align } = placementMap[placement];\n\n return (\n <CorePopover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n {...props}\n align={align}\n side={side}\n sideOffset={16}\n className={cn('relative w-auto', className)}\n >\n {renderConditional(title, v => (\n <Typography.Title level={6}>{v}</Typography.Title>\n ))}\n {content}\n <div className={getArrowClassName(side, align)} />\n </PopoverContent>\n </CorePopover>\n );\n};\n\nexport default Popover;\n"],"mappings":"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"}
1
+ {"version":3,"file":"popover.mjs","names":["popover"],"sources":["../../../src/components/atoms/popover.tsx"],"sourcesContent":["'use client';\n\nimport { Children, type ReactElement } from 'react';\n\nimport { useControllableState } from '@jbpark/use-hooks';\n\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport { popover } from '../../core';\nimport Typography from './typography';\n\nconst {\n Popover: CorePopover,\n PopoverContent,\n PopoverTrigger,\n PopoverArrow,\n PopoverTitle,\n} = popover;\n\ntype Placement =\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n\nexport interface Props extends Omit<\n React.ComponentPropsWithoutRef<'div'>,\n 'title' | 'content'\n> {\n title?: React.ReactNode;\n /** Set to false when a custom trigger component renders a non-button element. */\n nativeButton?: boolean;\n placement?: Placement;\n content: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\n\nconst placementMap: Record<Placement, { side: Side; align: Align }> = {\n top: { side: 'top', align: 'center' },\n left: { side: 'left', align: 'center' },\n right: { side: 'right', align: 'center' },\n bottom: { side: 'bottom', align: 'center' },\n topLeft: { side: 'top', align: 'start' },\n topRight: { side: 'top', align: 'end' },\n bottomLeft: { side: 'bottom', align: 'start' },\n bottomRight: { side: 'bottom', align: 'end' },\n leftTop: { side: 'left', align: 'start' },\n leftBottom: { side: 'left', align: 'end' },\n rightTop: { side: 'right', align: 'start' },\n rightBottom: { side: 'right', align: 'end' },\n};\n\nconst Popover = ({\n title,\n nativeButton,\n placement = 'top',\n className,\n content,\n children,\n open: _open,\n defaultOpen,\n onOpenChange,\n ...props\n}: Props) => {\n const [open, setOpen] = useControllableState<boolean>({\n value: _open,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n const { side, align } = placementMap[placement];\n\n const trigger = Children.only(children) as ReactElement;\n\n return (\n <CorePopover open={open} onOpenChange={setOpen}>\n {/* Deliberately no `data-slot` here: Base UI merges the trigger's own\n props over the rendered element's, so a `data-slot` set here replaces\n the child's. A `Button` trigger would lose `data-slot=\"button\"` and\n with it every `--btn-*` token rule in globals.css. */}\n <PopoverTrigger\n render={trigger}\n nativeButton={\n nativeButton ??\n (typeof trigger.type !== 'string' || trigger.type === 'button')\n }\n />\n <PopoverContent\n {...props}\n align={align}\n side={side}\n sideOffset={16}\n className={cn('relative w-auto', className)}\n >\n {renderConditional(title, v => (\n <PopoverTitle render={<Typography.Title level={6} />}>\n {v}\n </PopoverTitle>\n ))}\n {content}\n <PopoverArrow />\n </PopoverContent>\n </CorePopover>\n );\n};\n\nexport default Popover;\n"],"mappings":";;;;;;;;AAWA,MAAM,EACJ,SAAS,aACT,gBACA,gBACA,cACA,iBACEA;AAiCJ,MAAM,eAAgE;CACpE,KAAK;EAAE,MAAM;EAAO,OAAO;CAAS;CACpC,MAAM;EAAE,MAAM;EAAQ,OAAO;CAAS;CACtC,OAAO;EAAE,MAAM;EAAS,OAAO;CAAS;CACxC,QAAQ;EAAE,MAAM;EAAU,OAAO;CAAS;CAC1C,SAAS;EAAE,MAAM;EAAO,OAAO;CAAQ;CACvC,UAAU;EAAE,MAAM;EAAO,OAAO;CAAM;CACtC,YAAY;EAAE,MAAM;EAAU,OAAO;CAAQ;CAC7C,aAAa;EAAE,MAAM;EAAU,OAAO;CAAM;CAC5C,SAAS;EAAE,MAAM;EAAQ,OAAO;CAAQ;CACxC,YAAY;EAAE,MAAM;EAAQ,OAAO;CAAM;CACzC,UAAU;EAAE,MAAM;EAAS,OAAO;CAAQ;CAC1C,aAAa;EAAE,MAAM;EAAS,OAAO;CAAM;AAC7C;AAEA,MAAM,WAAW,EACf,OACA,cACA,YAAY,OACZ,WACA,SACA,UACA,MAAM,OACN,aACA,cACA,GAAG,YACQ;CACX,MAAM,CAAC,MAAM,WAAW,qBAA8B;EACpD,OAAO;EACP,cAAc,eAAe;EAC7B,UAAU;CACZ,CAAC;CAED,MAAM,EAAE,MAAM,UAAU,aAAa;CAErC,MAAM,UAAU,SAAS,KAAK,QAAQ;CAEtC,OACE,qBAAC,aAAD;EAAmB;EAAM,cAAc;EAAvC,UAAA,CAKE,oBAAC,gBAAD;GACE,QAAQ;GACR,cACE,iBACC,OAAO,QAAQ,SAAS,YAAY,QAAQ,SAAS;EAEzD,CAAA,GACD,qBAAC,gBAAD;GACE,GAAI;GACG;GACD;GACN,YAAY;GACZ,WAAW,GAAG,mBAAmB,SAAS;GAL5C,UAAA;IAOG,kBAAkB,QAAO,MACxB,oBAAC,cAAD;KAAc,QAAQ,oBAAC,WAAW,OAAZ,EAAkB,OAAO,EAAI,CAAA;KAChD,UAAA;IACW,CAAA,CACf;IACA;IACD,oBAAC,cAAD,CAAe,CAAA;GACD;EACL,CAAA,CAAA;;AAEjB"}
@@ -5,16 +5,15 @@ import { jsx } from "react/jsx-runtime";
5
5
  const { Progress: Core } = progress_exports;
6
6
  const Progress = ({ value, className, direction = "horizontal", classNames, ...props }) => {
7
7
  const isHorizontal = direction === "horizontal";
8
- const dimension = isHorizontal ? "width" : "height";
9
8
  const normalizedValue = Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : 0;
10
9
  return /* @__PURE__ */ jsx(Core, {
11
10
  ...props,
12
11
  value: normalizedValue,
13
12
  className: cn(isHorizontal ? "h-4 w-full" : "flex h-full w-4 flex-col justify-end", className, classNames?.background),
14
13
  barClassName: cn("flex-none", classNames?.bar),
15
- barStyle: {
16
- transform: "none",
17
- [dimension]: `${normalizedValue}%`
14
+ barStyle: isHorizontal ? { width: `${normalizedValue}%` } : {
15
+ width: "100%",
16
+ height: `${normalizedValue}%`
18
17
  }
19
18
  });
20
19
  };