sh-ui-cli 0.45.2 → 0.46.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 (98) hide show
  1. package/data/changelog/versions.json +26 -0
  2. package/data/registry/react/components/accordion/index.tailwind.tsx +5 -7
  3. package/data/registry/react/components/accordion/index.tsx +5 -7
  4. package/data/registry/react/components/avatar/index.tailwind.tsx +4 -6
  5. package/data/registry/react/components/avatar/index.tsx +4 -6
  6. package/data/registry/react/components/badge/index.tailwind.tsx +2 -4
  7. package/data/registry/react/components/badge/index.tsx +2 -4
  8. package/data/registry/react/components/breadcrumb/index.tailwind.tsx +8 -10
  9. package/data/registry/react/components/breadcrumb/index.tsx +8 -10
  10. package/data/registry/react/components/button/index.module.tsx +45 -0
  11. package/data/registry/react/components/button/index.tailwind.tsx +2 -1
  12. package/data/registry/react/components/button/index.tsx +3 -4
  13. package/data/registry/react/components/button/styles.module.css +92 -0
  14. package/data/registry/react/components/calendar/index.tailwind.tsx +10 -12
  15. package/data/registry/react/components/calendar/index.tsx +9 -11
  16. package/data/registry/react/components/card/index.module.tsx +63 -0
  17. package/data/registry/react/components/card/index.tailwind.tsx +8 -10
  18. package/data/registry/react/components/card/index.tsx +8 -10
  19. package/data/registry/react/components/card/styles.module.css +73 -0
  20. package/data/registry/react/components/carousel/index.tailwind.tsx +7 -9
  21. package/data/registry/react/components/carousel/index.tsx +7 -9
  22. package/data/registry/react/components/checkbox/index.tailwind.tsx +3 -5
  23. package/data/registry/react/components/checkbox/index.tsx +3 -5
  24. package/data/registry/react/components/code-editor/index.tailwind.tsx +2 -4
  25. package/data/registry/react/components/code-editor/index.tsx +2 -4
  26. package/data/registry/react/components/code-panel/index.tailwind.tsx +5 -7
  27. package/data/registry/react/components/code-panel/index.tsx +5 -7
  28. package/data/registry/react/components/color-picker/index.tailwind.tsx +7 -6
  29. package/data/registry/react/components/color-picker/index.tsx +7 -6
  30. package/data/registry/react/components/combobox/index.tailwind.tsx +8 -10
  31. package/data/registry/react/components/combobox/index.tsx +8 -10
  32. package/data/registry/react/components/context-menu/index.tailwind.tsx +10 -12
  33. package/data/registry/react/components/context-menu/index.tsx +10 -12
  34. package/data/registry/react/components/date-picker/index.tailwind.tsx +7 -9
  35. package/data/registry/react/components/date-picker/index.tsx +7 -9
  36. package/data/registry/react/components/dialog/index.tailwind.tsx +6 -8
  37. package/data/registry/react/components/dialog/index.tsx +6 -8
  38. package/data/registry/react/components/dropdown-menu/index.tailwind.tsx +10 -12
  39. package/data/registry/react/components/dropdown-menu/index.tsx +10 -12
  40. package/data/registry/react/components/file-upload/index.tailwind.tsx +6 -8
  41. package/data/registry/react/components/file-upload/index.tsx +6 -8
  42. package/data/registry/react/components/form/field.tailwind.tsx +2 -1
  43. package/data/registry/react/components/form/field.tsx +2 -3
  44. package/data/registry/react/components/header/index.tailwind.tsx +17 -19
  45. package/data/registry/react/components/header/index.tsx +17 -19
  46. package/data/registry/react/components/input/index.module.tsx +486 -0
  47. package/data/registry/react/components/input/index.tailwind.tsx +4 -6
  48. package/data/registry/react/components/input/index.tsx +4 -6
  49. package/data/registry/react/components/input/styles.module.css +200 -0
  50. package/data/registry/react/components/label/index.tailwind.tsx +6 -8
  51. package/data/registry/react/components/label/index.tsx +6 -8
  52. package/data/registry/react/components/markdown-editor/index.tailwind.tsx +2 -4
  53. package/data/registry/react/components/markdown-editor/index.tsx +2 -4
  54. package/data/registry/react/components/menubar/index.tailwind.tsx +2 -4
  55. package/data/registry/react/components/menubar/index.tsx +2 -4
  56. package/data/registry/react/components/numeric-input/index.tailwind.tsx +2 -4
  57. package/data/registry/react/components/numeric-input/index.tsx +2 -4
  58. package/data/registry/react/components/page-toc/index.tailwind.tsx +3 -2
  59. package/data/registry/react/components/page-toc/index.tsx +2 -3
  60. package/data/registry/react/components/pagination/index.tailwind.tsx +8 -10
  61. package/data/registry/react/components/pagination/index.tsx +8 -10
  62. package/data/registry/react/components/popover/index.tailwind.tsx +4 -6
  63. package/data/registry/react/components/popover/index.tsx +4 -6
  64. package/data/registry/react/components/progress/index.tailwind.tsx +3 -5
  65. package/data/registry/react/components/progress/index.tsx +2 -4
  66. package/data/registry/react/components/radio/index.tailwind.tsx +3 -5
  67. package/data/registry/react/components/radio/index.tsx +3 -5
  68. package/data/registry/react/components/rich-text-editor/index.tailwind.tsx +3 -5
  69. package/data/registry/react/components/rich-text-editor/index.tsx +3 -5
  70. package/data/registry/react/components/select/index.tailwind.tsx +8 -10
  71. package/data/registry/react/components/select/index.tsx +8 -10
  72. package/data/registry/react/components/separator/index.tailwind.tsx +2 -4
  73. package/data/registry/react/components/separator/index.tsx +2 -4
  74. package/data/registry/react/components/sidebar/index.tailwind.tsx +32 -43
  75. package/data/registry/react/components/sidebar/index.tsx +29 -46
  76. package/data/registry/react/components/skeleton/index.tailwind.tsx +2 -4
  77. package/data/registry/react/components/skeleton/index.tsx +2 -4
  78. package/data/registry/react/components/slider/index.tailwind.tsx +5 -7
  79. package/data/registry/react/components/slider/index.tsx +5 -7
  80. package/data/registry/react/components/spinner/index.tailwind.tsx +3 -5
  81. package/data/registry/react/components/spinner/index.tsx +2 -4
  82. package/data/registry/react/components/switch/index.tailwind.tsx +3 -5
  83. package/data/registry/react/components/switch/index.tsx +2 -4
  84. package/data/registry/react/components/tabs/index.tailwind.tsx +6 -8
  85. package/data/registry/react/components/tabs/index.tsx +6 -8
  86. package/data/registry/react/components/textarea/index.tailwind.tsx +2 -4
  87. package/data/registry/react/components/textarea/index.tsx +2 -4
  88. package/data/registry/react/components/toggle/index.tailwind.tsx +4 -6
  89. package/data/registry/react/components/toggle/index.tsx +4 -6
  90. package/data/registry/react/components/tooltip/index.tailwind.tsx +2 -4
  91. package/data/registry/react/components/tooltip/index.tsx +2 -4
  92. package/data/registry/react/lib/cn.tailwind.ts +17 -0
  93. package/data/registry/react/peer-versions.json +3 -1
  94. package/data/registry/react/registry.json +202 -43
  95. package/data/tokens/build.mjs +4 -0
  96. package/package.json +1 -1
  97. package/src/add.mjs +37 -13
  98. package/templates/ui-app-template/sh-ui.config.json +5 -0
@@ -2,10 +2,8 @@ import { codeToHtml } from "shiki";
2
2
  import { CodePanelCopyButton } from "./copy";
3
3
  import "./styles.css";
4
4
 
5
- function cx(...args: (string | undefined | false | null)[]) {
6
- return args.filter(Boolean).join(" ");
7
- }
8
5
 
6
+ import { cn } from "@SH_UI_UTILS@";
9
7
  export interface CodePanelProps
10
8
  extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
11
9
  /** 하이라이팅할 코드 문자열. children을 제공하지 않을 때 필수. */
@@ -56,7 +54,7 @@ export async function CodePanel({
56
54
  children,
57
55
  ...rest
58
56
  }: CodePanelProps) {
59
- const classes = cx("sh-ui-code", className);
57
+ const classes = cn("sh-ui-code", className);
60
58
 
61
59
  if (children !== undefined) {
62
60
  return (
@@ -104,7 +102,7 @@ export function CodePanelHeader({
104
102
  ...props
105
103
  }: React.HTMLAttributes<HTMLDivElement>) {
106
104
  return (
107
- <div className={cx("sh-ui-code__header", className)} {...props}>
105
+ <div className={cn("sh-ui-code__header", className)} {...props}>
108
106
  {children}
109
107
  </div>
110
108
  );
@@ -119,7 +117,7 @@ export function CodePanelFilename({
119
117
  ...props
120
118
  }: React.HTMLAttributes<HTMLSpanElement>) {
121
119
  return (
122
- <span className={cx("sh-ui-code__filename", className)} {...props}>
120
+ <span className={cn("sh-ui-code__filename", className)} {...props}>
123
121
  {children}
124
122
  </span>
125
123
  );
@@ -182,7 +180,7 @@ export async function CodePanelBody({
182
180
 
183
181
  return (
184
182
  <div
185
- className={cx("sh-ui-code__body", className)}
183
+ className={cn("sh-ui-code__body", className)}
186
184
  data-line-numbers={showLineNumbers || undefined}
187
185
  dangerouslySetInnerHTML={{ __html: html }}
188
186
  {...rest}
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as React from "react";
4
4
 
5
+ import { cn } from "@SH_UI_UTILS@";
5
6
  interface HSV { h: number; s: number; v: number; }
6
7
  interface HSVA extends HSV { a: number; }
7
8
 
@@ -136,7 +137,7 @@ export function ColorPicker({
136
137
 
137
138
  return (
138
139
  <ColorPickerContext.Provider value={ctx}>
139
- <div className={["flex flex-col gap-2.5 w-full select-none", className].filter(Boolean).join(" ")} {...rest}>
140
+ <div className={cn("flex flex-col gap-2.5 w-full select-none", className)} {...rest}>
140
141
  {children ?? (<><ColorPickerSaturation /><ColorPickerHue /><ColorPickerHex /></>)}
141
142
  </div>
142
143
  </ColorPickerContext.Provider>
@@ -157,7 +158,7 @@ export function ColorPickerSaturation({ className, style, ...rest }: ColorPicker
157
158
  <div
158
159
  ref={drag.ref}
159
160
  onPointerDown={drag.onPointerDown}
160
- className={["relative w-full aspect-[4/3] rounded-[var(--radius)] cursor-crosshair overflow-hidden touch-none", className].filter(Boolean).join(" ")}
161
+ className={cn("relative w-full aspect-[4/3] rounded-[var(--radius)] cursor-crosshair overflow-hidden touch-none", className)}
161
162
  style={{ background: pureHueHex, ...style }}
162
163
  role="slider"
163
164
  aria-label="채도/명도"
@@ -187,7 +188,7 @@ export function ColorPickerHue({ className, ...rest }: ColorPickerHueProps) {
187
188
  <div
188
189
  ref={drag.ref}
189
190
  onPointerDown={drag.onPointerDown}
190
- className={["relative w-full h-3.5 rounded-full cursor-pointer touch-none bg-[linear-gradient(to_right,#f00_0%,#ff0_16.66%,#0f0_33.33%,#0ff_50%,#00f_66.66%,#f0f_83.33%,#f00_100%)]", className].filter(Boolean).join(" ")}
191
+ className={cn("relative w-full h-3.5 rounded-full cursor-pointer touch-none bg-[linear-gradient(to_right,#f00_0%,#ff0_16.66%,#0f0_33.33%,#0ff_50%,#00f_66.66%,#f0f_83.33%,#f00_100%)]", className)}
191
192
  role="slider"
192
193
  aria-label="색조"
193
194
  aria-valuemin={0} aria-valuemax={360} aria-valuenow={Math.round(hsva.h)}
@@ -215,7 +216,7 @@ export function ColorPickerAlpha({ className, style, ...rest }: ColorPickerAlpha
215
216
  <div
216
217
  ref={drag.ref}
217
218
  onPointerDown={drag.onPointerDown}
218
- className={["relative w-full h-3.5 rounded-full cursor-pointer touch-none overflow-hidden bg-white bg-[length:8px_8px] bg-[position:0_0,0_4px,4px_-4px,-4px_0] [background-image:linear-gradient(45deg,#ccc_25%,transparent_25%),linear-gradient(-45deg,#ccc_25%,transparent_25%),linear-gradient(45deg,transparent_75%,#ccc_75%),linear-gradient(-45deg,transparent_75%,#ccc_75%)]", className].filter(Boolean).join(" ")}
219
+ className={cn("relative w-full h-3.5 rounded-full cursor-pointer touch-none overflow-hidden bg-white bg-[length:8px_8px] bg-[position:0_0,0_4px,4px_-4px,-4px_0] [background-image:linear-gradient(45deg,#ccc_25%,transparent_25%),linear-gradient(-45deg,#ccc_25%,transparent_25%),linear-gradient(45deg,transparent_75%,#ccc_75%),linear-gradient(-45deg,transparent_75%,#ccc_75%)]", className)}
219
220
  role="slider"
220
221
  aria-label="투명도"
221
222
  aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(hsva.a * 100)}
@@ -248,7 +249,7 @@ export function ColorPickerHex({ className, showSwatch = true, ...rest }: ColorP
248
249
 
249
250
  return (
250
251
  <div
251
- className={["flex items-center gap-[var(--space-2)]", className].filter(Boolean).join(" ")}
252
+ className={cn("flex items-center gap-[var(--space-2)]", className)}
252
253
  {...rest}
253
254
  >
254
255
  {showSwatch && (
@@ -285,7 +286,7 @@ export function ColorPickerSwatches({ className, colors, ...rest }: ColorPickerS
285
286
  <div
286
287
  role="group"
287
288
  aria-label="미리 준비된 색상"
288
- className={["flex flex-wrap gap-1.5", className].filter(Boolean).join(" ")}
289
+ className={cn("flex flex-wrap gap-1.5", className)}
289
290
  {...rest}
290
291
  >
291
292
  {colors.map((c) => {
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
+ import { cn } from "@SH_UI_UTILS@";
4
5
  import "./styles.css";
5
6
 
6
7
  /* ───────────── types ───────────── */
@@ -234,7 +235,7 @@ export function ColorPicker({
234
235
  return (
235
236
  <ColorPickerContext.Provider value={ctx}>
236
237
  <div
237
- className={["sh-ui-color-picker", className].filter(Boolean).join(" ")}
238
+ className={cn("sh-ui-color-picker", className)}
238
239
  {...rest}
239
240
  >
240
241
  {children ?? (
@@ -271,7 +272,7 @@ export function ColorPickerSaturation({
271
272
  <div
272
273
  ref={drag.ref}
273
274
  onPointerDown={drag.onPointerDown}
274
- className={["sh-ui-color-picker__sv", className].filter(Boolean).join(" ")}
275
+ className={cn("sh-ui-color-picker__sv", className)}
275
276
  style={{ background: pureHueHex, ...style }}
276
277
  role="slider"
277
278
  aria-label="채도/명도"
@@ -309,7 +310,7 @@ export function ColorPickerHue({ className, ...rest }: ColorPickerHueProps) {
309
310
  <div
310
311
  ref={drag.ref}
311
312
  onPointerDown={drag.onPointerDown}
312
- className={["sh-ui-color-picker__hue", className].filter(Boolean).join(" ")}
313
+ className={cn("sh-ui-color-picker__hue", className)}
313
314
  role="slider"
314
315
  aria-label="색조"
315
316
  aria-valuemin={0}
@@ -341,7 +342,7 @@ export function ColorPickerAlpha({ className, style, ...rest }: ColorPickerAlpha
341
342
  <div
342
343
  ref={drag.ref}
343
344
  onPointerDown={drag.onPointerDown}
344
- className={["sh-ui-color-picker__alpha", className].filter(Boolean).join(" ")}
345
+ className={cn("sh-ui-color-picker__alpha", className)}
345
346
  role="slider"
346
347
  aria-label="투명도"
347
348
  aria-valuemin={0}
@@ -392,7 +393,7 @@ export function ColorPickerHex({
392
393
 
393
394
  return (
394
395
  <div
395
- className={["sh-ui-color-picker__row", className].filter(Boolean).join(" ")}
396
+ className={cn("sh-ui-color-picker__row", className)}
396
397
  {...rest}
397
398
  >
398
399
  {showSwatch && (
@@ -442,7 +443,7 @@ export function ColorPickerSwatches({
442
443
  <div
443
444
  role="group"
444
445
  aria-label="미리 준비된 색상"
445
- className={["sh-ui-color-picker__swatches", className].filter(Boolean).join(" ")}
446
+ className={cn("sh-ui-color-picker__swatches", className)}
446
447
  {...rest}
447
448
  >
448
449
  {colors.map((c) => {
@@ -3,11 +3,9 @@
3
3
  import * as React from "react";
4
4
  import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
5
5
 
6
+ import { cn } from "@SH_UI_UTILS@";
6
7
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
7
8
 
8
- function cx(...args: (string | undefined | false)[]) {
9
- return args.filter(Boolean).join(" ");
10
- }
11
9
 
12
10
  export const Combobox = BaseCombobox.Root;
13
11
  export const ComboboxIcon = BaseCombobox.Icon;
@@ -24,7 +22,7 @@ export const ComboboxInput = React.forwardRef<
24
22
  return (
25
23
  <BaseCombobox.Input
26
24
  ref={ref}
27
- className={cx(
25
+ className={cn(
28
26
  "inline-flex w-full min-w-40 h-[var(--control-md)] px-[var(--space-3)] bg-background text-foreground border border-border rounded-[var(--radius)] text-[length:var(--text-sm)] leading-none outline-none transition-[border-color] duration-[var(--duration-fast)] placeholder:text-foreground-subtle hover:not-disabled:border-border-strong focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 disabled:opacity-[var(--opacity-disabled)] disabled:pointer-events-none",
29
27
  className,
30
28
  )}
@@ -49,7 +47,7 @@ export const ComboboxContent = React.forwardRef<
49
47
  >
50
48
  <BaseCombobox.Popup
51
49
  ref={ref}
52
- className={cx(
50
+ className={cn(
53
51
  "max-h-[min(20rem,var(--available-height))] overflow-y-auto p-[var(--space-1)] bg-background text-foreground border border-border rounded-[var(--radius)] shadow-[0_8px_24px_rgba(0,0,0,0.08)] outline-none origin-[var(--transform-origin)] transition-[opacity,transform] duration-[140ms] ease-out motion-reduce:transition-none data-[starting-style]:opacity-0 data-[starting-style]:scale-[0.97] data-[ending-style]:opacity-0 data-[ending-style]:scale-[0.97]",
54
52
  className,
55
53
  )}
@@ -71,7 +69,7 @@ export const ComboboxItem = React.forwardRef<
71
69
  return (
72
70
  <BaseCombobox.Item
73
71
  ref={ref}
74
- className={cx(
72
+ className={cn(
75
73
  "flex items-center gap-[var(--space-2)] py-1.5 px-3 text-[length:var(--text-sm)] leading-snug rounded-[calc(var(--radius)-2px)] cursor-pointer select-none outline-none data-[highlighted]:bg-background-muted hover:bg-background-muted data-[selected]:text-foreground data-[selected]:font-medium data-[disabled]:opacity-[var(--opacity-disabled)] data-[disabled]:pointer-events-none",
76
74
  className,
77
75
  )}
@@ -92,7 +90,7 @@ export const ComboboxEmpty = React.forwardRef<
92
90
  return (
93
91
  <BaseCombobox.Empty
94
92
  ref={ref}
95
- className={cx(
93
+ className={cn(
96
94
  "py-[var(--space-3)] px-[var(--space-2)] text-center text-[0.8125rem] text-foreground-muted",
97
95
  className,
98
96
  )}
@@ -108,7 +106,7 @@ export const ComboboxGroupLabel = React.forwardRef<
108
106
  return (
109
107
  <BaseCombobox.GroupLabel
110
108
  ref={ref}
111
- className={cx(
109
+ className={cn(
112
110
  "py-1.5 px-[var(--space-2)] pb-[var(--space-1)] text-[length:var(--text-xs)] font-semibold text-foreground-muted uppercase tracking-[0.04em]",
113
111
  className,
114
112
  )}
@@ -124,7 +122,7 @@ export const ComboboxChip = React.forwardRef<
124
122
  return (
125
123
  <BaseCombobox.Chip
126
124
  ref={ref}
127
- className={cx(
125
+ className={cn(
128
126
  "inline-flex items-center gap-[var(--space-1)] py-0.5 pr-1.5 pl-[var(--space-2)] mr-[var(--space-1)] text-[length:var(--text-xs)] leading-5 bg-background-muted rounded-[calc(var(--radius)-2px)] whitespace-nowrap",
129
127
  className,
130
128
  )}
@@ -140,7 +138,7 @@ export const ComboboxChipRemove = React.forwardRef<
140
138
  return (
141
139
  <BaseCombobox.ChipRemove
142
140
  ref={ref}
143
- className={cx(
141
+ className={cn(
144
142
  "inline-flex items-center justify-center w-4 h-4 p-0 border-0 rounded-full bg-transparent text-foreground-muted text-[length:var(--text-sm)] leading-none cursor-pointer transition-[background-color,color] duration-[var(--duration-fast)] hover:bg-background hover:text-foreground motion-reduce:transition-none",
145
143
  className,
146
144
  )}
@@ -4,11 +4,9 @@ import * as React from "react";
4
4
  import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
5
5
  import "./styles.css";
6
6
 
7
+ import { cn } from "@SH_UI_UTILS@";
7
8
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
8
9
 
9
- function cx(...args: (string | undefined | false)[]) {
10
- return args.filter(Boolean).join(" ");
11
- }
12
10
 
13
11
  /**
14
12
  * Select + Input의 결합 — 타이핑으로 목록이 자동 필터링된다.
@@ -40,7 +38,7 @@ export const ComboboxInput = React.forwardRef<
40
38
  return (
41
39
  <BaseCombobox.Input
42
40
  ref={ref}
43
- className={cx("sh-ui-combobox__input", className)}
41
+ className={cn("sh-ui-combobox__input", className)}
44
42
  {...props}
45
43
  />
46
44
  );
@@ -66,7 +64,7 @@ export const ComboboxContent = React.forwardRef<
66
64
  >
67
65
  <BaseCombobox.Popup
68
66
  ref={ref}
69
- className={cx("sh-ui-combobox__content", className)}
67
+ className={cn("sh-ui-combobox__content", className)}
70
68
  {...props}
71
69
  >
72
70
  {children}
@@ -85,7 +83,7 @@ export const ComboboxItem = React.forwardRef<
85
83
  return (
86
84
  <BaseCombobox.Item
87
85
  ref={ref}
88
- className={cx("sh-ui-combobox__item", className)}
86
+ className={cn("sh-ui-combobox__item", className)}
89
87
  {...props}
90
88
  >
91
89
  <BaseCombobox.ItemIndicator className="sh-ui-combobox__item-indicator">
@@ -103,7 +101,7 @@ export const ComboboxEmpty = React.forwardRef<
103
101
  return (
104
102
  <BaseCombobox.Empty
105
103
  ref={ref}
106
- className={cx("sh-ui-combobox__empty", className)}
104
+ className={cn("sh-ui-combobox__empty", className)}
107
105
  {...props}
108
106
  />
109
107
  );
@@ -116,7 +114,7 @@ export const ComboboxGroupLabel = React.forwardRef<
116
114
  return (
117
115
  <BaseCombobox.GroupLabel
118
116
  ref={ref}
119
- className={cx("sh-ui-combobox__group-label", className)}
117
+ className={cn("sh-ui-combobox__group-label", className)}
120
118
  {...props}
121
119
  />
122
120
  );
@@ -130,7 +128,7 @@ export const ComboboxChip = React.forwardRef<
130
128
  return (
131
129
  <BaseCombobox.Chip
132
130
  ref={ref}
133
- className={cx("sh-ui-combobox__chip", className)}
131
+ className={cn("sh-ui-combobox__chip", className)}
134
132
  {...props}
135
133
  />
136
134
  );
@@ -144,7 +142,7 @@ export const ComboboxChipRemove = React.forwardRef<
144
142
  return (
145
143
  <BaseCombobox.ChipRemove
146
144
  ref={ref}
147
- className={cx("sh-ui-combobox__chip-remove", className)}
145
+ className={cn("sh-ui-combobox__chip-remove", className)}
148
146
  {...props}
149
147
  >
150
148
  {children ?? "×"}
@@ -1,11 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
3
3
 
4
+ import { cn } from "@SH_UI_UTILS@";
4
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
5
6
 
6
- function cx(...args: (string | undefined | false | null)[]) {
7
- return args.filter(Boolean).join(" ");
8
- }
9
7
 
10
8
  const itemBase =
11
9
  "relative flex items-center gap-[var(--space-2)] py-2 px-3 rounded-[calc(var(--radius)-2px)] cursor-pointer outline-none select-none transition-colors duration-[80ms] data-[highlighted]:bg-background-muted hover:bg-background-muted data-[disabled]:opacity-[var(--opacity-disabled)] data-[disabled]:pointer-events-none motion-reduce:transition-none";
@@ -19,7 +17,7 @@ export const ContextMenuTrigger = React.forwardRef<
19
17
  HTMLDivElement,
20
18
  WithStringClassName<React.ComponentPropsWithoutRef<typeof BaseContextMenu.Trigger>>
21
19
  >(function ContextMenuTrigger({ className, ...props }, ref) {
22
- return <BaseContextMenu.Trigger ref={ref} className={cx("contents", className)} {...props} />;
20
+ return <BaseContextMenu.Trigger ref={ref} className={cn("contents", className)} {...props} />;
23
21
  });
24
22
 
25
23
  export interface ContextMenuContentProps
@@ -32,7 +30,7 @@ export const ContextMenuContent = React.forwardRef<HTMLDivElement, ContextMenuCo
32
30
  return (
33
31
  <BaseContextMenu.Portal container={container}>
34
32
  <BaseContextMenu.Positioner className="outline-none z-[var(--z-dropdown)]">
35
- <BaseContextMenu.Popup ref={ref} className={cx(contentClasses, className)} {...props}>
33
+ <BaseContextMenu.Popup ref={ref} className={cn(contentClasses, className)} {...props}>
36
34
  {children}
37
35
  </BaseContextMenu.Popup>
38
36
  </BaseContextMenu.Positioner>
@@ -45,7 +43,7 @@ export const ContextMenuItem = React.forwardRef<
45
43
  HTMLDivElement,
46
44
  WithStringClassName<React.ComponentPropsWithoutRef<typeof BaseContextMenu.Item>>
47
45
  >(function ContextMenuItem({ className, ...props }, ref) {
48
- return <BaseContextMenu.Item ref={ref} className={cx(itemBase, className)} {...props} />;
46
+ return <BaseContextMenu.Item ref={ref} className={cn(itemBase, className)} {...props} />;
49
47
  });
50
48
 
51
49
  export const ContextMenuCheckboxItem = React.forwardRef<
@@ -53,7 +51,7 @@ export const ContextMenuCheckboxItem = React.forwardRef<
53
51
  WithStringClassName<React.ComponentPropsWithoutRef<typeof BaseContextMenu.CheckboxItem>>
54
52
  >(function ContextMenuCheckboxItem({ className, children, ...props }, ref) {
55
53
  return (
56
- <BaseContextMenu.CheckboxItem ref={ref} className={cx(itemBase, itemCheck, className)} {...props}>
54
+ <BaseContextMenu.CheckboxItem ref={ref} className={cn(itemBase, itemCheck, className)} {...props}>
57
55
  <span className="absolute left-2 inline-flex items-center justify-center w-4 h-4 text-foreground" aria-hidden>
58
56
  <BaseContextMenu.CheckboxItemIndicator>
59
57
  <CheckIcon />
@@ -71,7 +69,7 @@ export const ContextMenuRadioItem = React.forwardRef<
71
69
  WithStringClassName<React.ComponentPropsWithoutRef<typeof BaseContextMenu.RadioItem>>
72
70
  >(function ContextMenuRadioItem({ className, children, ...props }, ref) {
73
71
  return (
74
- <BaseContextMenu.RadioItem ref={ref} className={cx(itemBase, itemCheck, className)} {...props}>
72
+ <BaseContextMenu.RadioItem ref={ref} className={cn(itemBase, itemCheck, className)} {...props}>
75
73
  <span className="absolute left-2 inline-flex items-center justify-center w-4 h-4 text-foreground" aria-hidden>
76
74
  <BaseContextMenu.RadioItemIndicator>
77
75
  <DotIcon />
@@ -86,7 +84,7 @@ export const ContextMenuGroup = React.forwardRef<
86
84
  HTMLDivElement,
87
85
  WithStringClassName<React.ComponentPropsWithoutRef<typeof BaseContextMenu.Group>>
88
86
  >(function ContextMenuGroup({ className, ...props }, ref) {
89
- return <BaseContextMenu.Group ref={ref} className={cx("p-0", className)} {...props} />;
87
+ return <BaseContextMenu.Group ref={ref} className={cn("p-0", className)} {...props} />;
90
88
  });
91
89
 
92
90
  export const ContextMenuLabel = React.forwardRef<
@@ -96,7 +94,7 @@ export const ContextMenuLabel = React.forwardRef<
96
94
  return (
97
95
  <BaseContextMenu.GroupLabel
98
96
  ref={ref}
99
- className={cx(
97
+ className={cn(
100
98
  "py-[var(--space-2)] px-[var(--space-2)] pb-[var(--space-1)] text-[length:var(--text-xs)] font-semibold text-foreground-muted uppercase tracking-[0.04em]",
101
99
  className,
102
100
  )}
@@ -112,7 +110,7 @@ export const ContextMenuSeparator = React.forwardRef<HTMLDivElement, React.HTMLA
112
110
  ref={ref}
113
111
  role="separator"
114
112
  aria-orientation="horizontal"
115
- className={cx("h-px bg-border my-[var(--space-1)]", className)}
113
+ className={cn("h-px bg-border my-[var(--space-1)]", className)}
116
114
  {...props}
117
115
  />
118
116
  );
@@ -128,7 +126,7 @@ export const ContextMenuSubTrigger = React.forwardRef<
128
126
  return (
129
127
  <BaseContextMenu.SubmenuTrigger
130
128
  ref={ref}
131
- className={cx(itemBase, "data-[popup-open]:bg-background-muted", className)}
129
+ className={cn(itemBase, "data-[popup-open]:bg-background-muted", className)}
132
130
  {...props}
133
131
  >
134
132
  <span className="flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap">{children}</span>
@@ -2,11 +2,9 @@ import * as React from "react";
2
2
  import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
3
3
  import "./styles.css";
4
4
 
5
+ import { cn } from "@SH_UI_UTILS@";
5
6
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
6
7
 
7
- function cx(...args: (string | undefined | false | null)[]) {
8
- return args.filter(Boolean).join(" ");
9
- }
10
8
 
11
9
  /* ───────── Root ───────── */
12
10
 
@@ -29,7 +27,7 @@ export const ContextMenuTrigger = React.forwardRef<
29
27
  return (
30
28
  <BaseContextMenu.Trigger
31
29
  ref={ref}
32
- className={cx("sh-ui-cm__trigger", className)}
30
+ className={cn("sh-ui-cm__trigger", className)}
33
31
  {...props}
34
32
  />
35
33
  );
@@ -60,7 +58,7 @@ export const ContextMenuContent = React.forwardRef<
60
58
  <BaseContextMenu.Positioner className="sh-ui-cm__positioner">
61
59
  <BaseContextMenu.Popup
62
60
  ref={ref}
63
- className={cx("sh-ui-cm__content", className)}
61
+ className={cn("sh-ui-cm__content", className)}
64
62
  {...props}
65
63
  >
66
64
  {children}
@@ -80,7 +78,7 @@ export const ContextMenuItem = React.forwardRef<
80
78
  return (
81
79
  <BaseContextMenu.Item
82
80
  ref={ref}
83
- className={cx("sh-ui-cm__item", className)}
81
+ className={cn("sh-ui-cm__item", className)}
84
82
  {...props}
85
83
  />
86
84
  );
@@ -98,7 +96,7 @@ export const ContextMenuCheckboxItem = React.forwardRef<
98
96
  return (
99
97
  <BaseContextMenu.CheckboxItem
100
98
  ref={ref}
101
- className={cx("sh-ui-cm__item", "sh-ui-cm__item--check", className)}
99
+ className={cn("sh-ui-cm__item", "sh-ui-cm__item--check", className)}
102
100
  {...props}
103
101
  >
104
102
  <span className="sh-ui-cm__item-indicator" aria-hidden>
@@ -124,7 +122,7 @@ export const ContextMenuRadioItem = React.forwardRef<
124
122
  return (
125
123
  <BaseContextMenu.RadioItem
126
124
  ref={ref}
127
- className={cx("sh-ui-cm__item", "sh-ui-cm__item--check", className)}
125
+ className={cn("sh-ui-cm__item", "sh-ui-cm__item--check", className)}
128
126
  {...props}
129
127
  >
130
128
  <span className="sh-ui-cm__item-indicator" aria-hidden>
@@ -147,7 +145,7 @@ export const ContextMenuGroup = React.forwardRef<
147
145
  return (
148
146
  <BaseContextMenu.Group
149
147
  ref={ref}
150
- className={cx("sh-ui-cm__group", className)}
148
+ className={cn("sh-ui-cm__group", className)}
151
149
  {...props}
152
150
  />
153
151
  );
@@ -163,7 +161,7 @@ export const ContextMenuLabel = React.forwardRef<
163
161
  return (
164
162
  <BaseContextMenu.GroupLabel
165
163
  ref={ref}
166
- className={cx("sh-ui-cm__label", className)}
164
+ className={cn("sh-ui-cm__label", className)}
167
165
  {...props}
168
166
  />
169
167
  );
@@ -179,7 +177,7 @@ export const ContextMenuSeparator = React.forwardRef<
179
177
  ref={ref}
180
178
  role="separator"
181
179
  aria-orientation="horizontal"
182
- className={cx("sh-ui-cm__separator", className)}
180
+ className={cn("sh-ui-cm__separator", className)}
183
181
  {...props}
184
182
  />
185
183
  );
@@ -200,7 +198,7 @@ export const ContextMenuSubTrigger = React.forwardRef<
200
198
  return (
201
199
  <BaseContextMenu.SubmenuTrigger
202
200
  ref={ref}
203
- className={cx("sh-ui-cm__item", "sh-ui-cm__sub-trigger", className)}
201
+ className={cn("sh-ui-cm__item", "sh-ui-cm__sub-trigger", className)}
204
202
  {...props}
205
203
  >
206
204
  <span className="sh-ui-cm__item-text">{children}</span>
@@ -4,11 +4,9 @@ import * as React from "react";
4
4
  import { Popover as BasePopover } from "@base-ui/react/popover";
5
5
  import { Calendar, type DateRange } from "../calendar";
6
6
 
7
+ import { cn } from "@SH_UI_UTILS@";
7
8
  export type { DateRange };
8
9
 
9
- function cx(...args: (string | undefined | false)[]) {
10
- return args.filter(Boolean).join(" ");
11
- }
12
10
 
13
11
  const formatDefault = (d: Date) =>
14
12
  `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
@@ -121,7 +119,7 @@ export const DatePickerTrigger = React.forwardRef<HTMLButtonElement, DatePickerT
121
119
  if (children !== undefined) return children;
122
120
  return (
123
121
  <>
124
- <span className={cx("overflow-hidden text-ellipsis whitespace-nowrap", !displayText && "text-foreground-subtle")}>
122
+ <span className={cn("overflow-hidden text-ellipsis whitespace-nowrap", !displayText && "text-foreground-subtle")}>
125
123
  {displayText ?? ctx.placeholder}
126
124
  </span>
127
125
  <span className="shrink-0 inline-flex text-foreground-muted ml-[var(--space-2)]" aria-hidden>
@@ -133,7 +131,7 @@ export const DatePickerTrigger = React.forwardRef<HTMLButtonElement, DatePickerT
133
131
  return (
134
132
  <BasePopover.Trigger
135
133
  ref={ref}
136
- className={cx(triggerClasses, className)}
134
+ className={cn(triggerClasses, className)}
137
135
  disabled={ctx.disabled}
138
136
  aria-invalid={ctx.ariaInvalid}
139
137
  aria-haspopup="dialog"
@@ -165,7 +163,7 @@ export const DatePickerContent = React.forwardRef<HTMLDivElement, DatePickerCont
165
163
  return (
166
164
  <BasePopover.Portal container={container}>
167
165
  <BasePopover.Positioner className="z-[var(--z-popover)] outline-none" sideOffset={sideOffset} side={side} align={align}>
168
- <BasePopover.Popup ref={ref} className={cx(popupClasses, className)} {...props}>
166
+ <BasePopover.Popup ref={ref} className={cn(popupClasses, className)} {...props}>
169
167
  {children}
170
168
  </BasePopover.Popup>
171
169
  </BasePopover.Positioner>
@@ -199,7 +197,7 @@ export const DatePickerFooter = React.forwardRef<HTMLDivElement, DatePickerFoote
199
197
  return (
200
198
  <div
201
199
  ref={ref}
202
- className={cx(
200
+ className={cn(
203
201
  "flex items-center justify-end gap-[var(--space-2)] mt-[var(--space-2)] pt-[var(--space-2)] border-t border-border",
204
202
  className,
205
203
  )}
@@ -257,13 +255,13 @@ export const DateRangePicker = React.forwardRef<HTMLButtonElement, DateRangePick
257
255
  <BasePopover.Root open={open} onOpenChange={setOpen}>
258
256
  <BasePopover.Trigger
259
257
  ref={ref}
260
- className={cx(triggerClasses, className)}
258
+ className={cn(triggerClasses, className)}
261
259
  disabled={disabled}
262
260
  aria-invalid={ariaInvalid}
263
261
  aria-haspopup="dialog"
264
262
  onClick={(e) => { if (readOnly) e.preventDefault(); }}
265
263
  >
266
- <span className={cx("overflow-hidden text-ellipsis whitespace-nowrap", !displayText && "text-foreground-subtle")}>
264
+ <span className={cn("overflow-hidden text-ellipsis whitespace-nowrap", !displayText && "text-foreground-subtle")}>
267
265
  {displayText ?? placeholder}
268
266
  </span>
269
267
  <span className="shrink-0 inline-flex text-foreground-muted ml-[var(--space-2)]" aria-hidden>
@@ -5,13 +5,11 @@ import { Popover as BasePopover } from "@base-ui/react/popover";
5
5
  import { Calendar, type DateRange } from "../calendar";
6
6
  import "./styles.css";
7
7
 
8
+ import { cn } from "@SH_UI_UTILS@";
8
9
  export type { DateRange };
9
10
 
10
11
  /* ───────── Helpers ───────── */
11
12
 
12
- function cx(...args: (string | undefined | false)[]) {
13
- return args.filter(Boolean).join(" ");
14
- }
15
13
 
16
14
  const formatDefault = (d: Date) =>
17
15
  `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
@@ -247,7 +245,7 @@ export const DatePickerTrigger = React.forwardRef<HTMLButtonElement, DatePickerT
247
245
  return (
248
246
  <>
249
247
  <span
250
- className={cx(
248
+ className={cn(
251
249
  "sh-ui-date-picker__value",
252
250
  !displayText && "sh-ui-date-picker__placeholder",
253
251
  )}
@@ -264,7 +262,7 @@ export const DatePickerTrigger = React.forwardRef<HTMLButtonElement, DatePickerT
264
262
  return (
265
263
  <BasePopover.Trigger
266
264
  ref={ref}
267
- className={cx("sh-ui-date-picker__trigger", className)}
265
+ className={cn("sh-ui-date-picker__trigger", className)}
268
266
  disabled={ctx.disabled}
269
267
  aria-invalid={ctx.ariaInvalid}
270
268
  aria-haspopup="dialog"
@@ -326,7 +324,7 @@ export const DatePickerContent = React.forwardRef<HTMLDivElement, DatePickerCont
326
324
  >
327
325
  <BasePopover.Popup
328
326
  ref={ref}
329
- className={cx("sh-ui-date-picker__popup", className)}
327
+ className={cn("sh-ui-date-picker__popup", className)}
330
328
  {...props}
331
329
  >
332
330
  {children}
@@ -371,7 +369,7 @@ export const DatePickerFooter = React.forwardRef<HTMLDivElement, DatePickerFoote
371
369
  return (
372
370
  <div
373
371
  ref={ref}
374
- className={cx("sh-ui-date-picker__footer", className)}
372
+ className={cn("sh-ui-date-picker__footer", className)}
375
373
  {...props}
376
374
  />
377
375
  );
@@ -478,7 +476,7 @@ export const DateRangePicker = React.forwardRef<HTMLButtonElement, DateRangePick
478
476
  <BasePopover.Root open={open} onOpenChange={setOpen}>
479
477
  <BasePopover.Trigger
480
478
  ref={ref}
481
- className={cx("sh-ui-date-picker__trigger", className)}
479
+ className={cn("sh-ui-date-picker__trigger", className)}
482
480
  disabled={disabled}
483
481
  aria-invalid={ariaInvalid}
484
482
  aria-haspopup="dialog"
@@ -486,7 +484,7 @@ export const DateRangePicker = React.forwardRef<HTMLButtonElement, DateRangePick
486
484
  if (readOnly) e.preventDefault();
487
485
  }}
488
486
  >
489
- <span className={cx("sh-ui-date-picker__value", !displayText && "sh-ui-date-picker__placeholder")}>
487
+ <span className={cn("sh-ui-date-picker__value", !displayText && "sh-ui-date-picker__placeholder")}>
490
488
  {displayText ?? placeholder}
491
489
  </span>
492
490
  <span className="sh-ui-date-picker__icon" aria-hidden>