@olundot/ui 0.18.0 → 0.19.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.
- package/CHANGELOG.md +30 -0
- package/dist/index.d.ts +120 -36
- package/dist/index.js +189 -36
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @olundot/ui
|
|
2
2
|
|
|
3
|
+
## 0.19.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 42d2650: `Button`·`IconButton`에 새 축 `appearance`(`filled`·`outline`·`ghost`) × `tone`(`primary`·`neutral`·`danger`)을 추가했습니다. 옛 `variant`는 0.18과 똑같이 그려지고, 사용 중단 예정으로 표시됩니다. 0.20에서 삭제합니다.
|
|
8
|
+
|
|
9
|
+
- **쓸 수 있는 조합 다섯 개** — `filled` × `primary`·`neutral`·`danger`, `outline` × `neutral`, `ghost` × `neutral`. 나머지 네 조합은 타입 오류입니다. 새 축과 `variant`를 함께 줘도 타입 오류입니다.
|
|
10
|
+
- **두 컴포넌트가 같은 모양** — 같은 조합이면 `Button`과 `IconButton`의 색·테두리·hover가 같습니다. 크기는 아래 "크기 단계 하나"를 따릅니다.
|
|
11
|
+
- **기본값** — 아무것도 주지 않으면 지금과 같습니다(`Button` = `filled` + `primary`, `IconButton` = `ghost` + `neutral`). 한쪽만 주면 나머지를 채웁니다. `tone`이 없으면 `filled`는 `primary`, `outline`·`ghost`는 `neutral`입니다.
|
|
12
|
+
- **`IconButton` 글자** — `label="추가"` 또는 children으로 글자를 넣습니다. 둘을 함께 주면 타입 오류입니다. 글자가 있으면 `aria-label`은 필수가 아니고, 폭은 글자에 맞춥니다. 아이콘 위치는 `iconPosition="start" | "end"`(기본 `start`)입니다. 아이콘만일 때는 지금처럼 정사각형이고 누르는 영역은 44px입니다.
|
|
13
|
+
- **크기 단계 하나** — `appearance`나 `tone`을 준 `IconButton`은 `size`를 `Button`과 같은 5단계로 읽습니다: `xs` 28 · `sm` 30 · `md` 32 · `lg` 36 · `xl` 40(기본 `md`). 같은 `size`면 `Button`·글자 포함 `IconButton`·아이콘만 `IconButton`의 높이와 아이콘 크기·선 굵기가 같습니다(`xs` 14/1.75, `sm`·`md` 16/2, `lg`·`xl` 18/2). 아이콘만은 정사각형이고 누르는 영역은 사방 44px입니다.
|
|
14
|
+
- **옛 크기** — 축을 주지 않은 `IconButton`은 지금처럼 3단계 `sm` 28 · `md` 32 · `lg` 40으로 읽고 출력도 0.18과 같습니다. 새 축으로 옮길 때 `sm` → `xs`, `lg` → `xl`로 바꿉니다(`md`는 그대로). 축 없이 `xs`·`xl`을 주면 타입 오류입니다. 축 없이 글자를 넣으면 높이는 같은 높이의 `Button`(`xs`·`md`·`xl`)을 따릅니다.
|
|
15
|
+
- **옛 값 → 새 값**
|
|
16
|
+
- `Button` `variant`: `primary`·`default` → `filled` + `primary` / `secondary`·`outline`·`subtle` → `outline` + `neutral` / `ghost` → `ghost` + `neutral` / `danger`·`destructive`·`emergency` → `filled` + `danger` / `link` → 대체 없음(링크 컴포넌트 예정)
|
|
17
|
+
- `Button` `size="icon"`·`"icon-xs"` → 새 축 `IconButton` `lg`·`md`(36·32, 높이 그대로), `leadingIcon`·`trailingIcon` → 글자 포함 `IconButton`
|
|
18
|
+
- `IconButton` `variant`: `ghost` → `ghost` + `neutral` / `outline` → `outline` + `neutral` / `subtle` → `filled` + `neutral` / `danger` → `filled` + `danger`. `size`는 `sm` → `xs`, `lg` → `xl`
|
|
19
|
+
- **옮길 때 모양이 바뀌는 곳** — `IconButton` `variant="danger"`(연한 빨강)는 `filled` + `danger`(진한 빨강 채움)로 바뀝니다. `IconButton` `variant="outline"`은 `outline` + `neutral`로 옮기면 아이콘 색이 `text-secondary`에서 `foreground`로, hover 테두리가 `--border-strong`에서 `--border`로 바뀝니다(`Button` `secondary`와 같은 모양). 옛 값을 그대로 쓰는 동안에는 바뀌지 않습니다.
|
|
20
|
+
- `ButtonProps`는 interface에서 type(union)으로 바뀌었습니다. `interface X extends ButtonProps`로 확장하던 곳은 `type X = ButtonProps & { … }`로 바꿔야 합니다.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- 2e965c7: OlunSymbol now has two optical sizes. Above 32px it follows the brand concept sheet (thicker ring, smaller dot clearly apart from the ring); at 32px and below it keeps the current icon geometry.
|
|
25
|
+
|
|
26
|
+
OlunLogo drops the wordmark period when the symbol is shown, so the lime orbit dot is not repeated. The wordmark alone still reads `OLUN.`.
|
|
27
|
+
|
|
28
|
+
- 11d8450: Tabs: 세로 탭 활성 표시가 구분선 위에 겹치도록 수정하고, `sm` 미만에서는 가로 탭 규칙으로 표시합니다. line 탭의 focus-visible ring이 목록 overflow에 잘리지 않도록 ring을 안쪽으로 그립니다.
|
|
29
|
+
- Updated dependencies [89a385a]
|
|
30
|
+
- Updated dependencies [2fa68e9]
|
|
31
|
+
- @olundot/tokens@0.17.0
|
|
32
|
+
|
|
3
33
|
## 0.18.0
|
|
4
34
|
|
|
5
35
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -31,26 +31,60 @@ declare function useOlunTheme(): UseOlunThemeValue;
|
|
|
31
31
|
|
|
32
32
|
type SurfaceLevel = "surface" | "canvas" | "raised";
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
type ActionAppearance = 'filled' | 'outline' | 'ghost';
|
|
35
|
+
type ActionTone = 'primary' | 'neutral' | 'danger';
|
|
36
|
+
type FilledDefaultActionStyle = {
|
|
37
|
+
appearance?: 'filled';
|
|
38
|
+
tone?: ActionTone;
|
|
39
|
+
} | {
|
|
40
|
+
appearance: 'outline' | 'ghost';
|
|
41
|
+
tone?: 'neutral';
|
|
42
|
+
};
|
|
43
|
+
type GhostDefaultActionStyle = {
|
|
44
|
+
appearance: 'filled';
|
|
45
|
+
tone?: ActionTone;
|
|
46
|
+
} | {
|
|
47
|
+
appearance: 'outline' | 'ghost';
|
|
48
|
+
tone?: 'neutral';
|
|
49
|
+
} | {
|
|
50
|
+
appearance?: never;
|
|
51
|
+
tone: 'neutral';
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare const buttonCva: (props?: ({
|
|
55
|
+
size?: "default" | "md" | "xs" | "sm" | "lg" | "xl" | "icon" | "icon-xs" | null | undefined;
|
|
56
|
+
appearance?: "filled" | "outline" | "ghost" | null | undefined;
|
|
57
|
+
tone?: "primary" | "neutral" | "danger" | null | undefined;
|
|
58
|
+
variant?: "default" | "outline" | "ghost" | "primary" | "danger" | "emergency" | "subtle" | "destructive" | "secondary" | "link" | null | undefined;
|
|
37
59
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
60
|
+
type ButtonVariantsOptions = Parameters<typeof buttonCva>[0];
|
|
61
|
+
declare function buttonVariants(options?: ButtonVariantsOptions): string;
|
|
38
62
|
type ButtonVariant = NonNullable<VariantProps<typeof buttonVariants>['variant']>;
|
|
39
63
|
type ButtonSize = NonNullable<VariantProps<typeof buttonVariants>['size']>;
|
|
40
|
-
|
|
64
|
+
type ButtonStyleProps = (FilledDefaultActionStyle & {
|
|
41
65
|
/**
|
|
42
|
-
*
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
* @deprecated Use `appearance` × `tone` instead. Removed in 0.20.
|
|
67
|
+
*/
|
|
68
|
+
variant?: never;
|
|
69
|
+
}) | {
|
|
70
|
+
/**
|
|
71
|
+
* @deprecated Use `appearance` × `tone`: `primary`/`default` → filled + primary ·
|
|
72
|
+
* `secondary`/`outline`/`subtle` → outline + neutral · `ghost` → ghost + neutral ·
|
|
73
|
+
* `danger`/`destructive`/`emergency` → filled + danger · `link` → no Button replacement
|
|
74
|
+
* (a link component is planned). Removed in 0.20.
|
|
47
75
|
*/
|
|
48
|
-
variant?:
|
|
76
|
+
variant?: ButtonVariant | null;
|
|
77
|
+
};
|
|
78
|
+
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & ButtonStyleProps & {
|
|
79
|
+
/** `icon`·`icon-xs` are deprecated — use IconButton (`lg`·`md`). */
|
|
80
|
+
size?: ButtonSize | null;
|
|
49
81
|
asChild?: boolean;
|
|
82
|
+
/** @deprecated Use IconButton with `label` (or children). Removed in 0.20. */
|
|
50
83
|
leadingIcon?: LucideIcon;
|
|
84
|
+
/** @deprecated Use IconButton with `label` and `iconPosition="end"`. Removed in 0.20. */
|
|
51
85
|
trailingIcon?: LucideIcon;
|
|
52
86
|
loading?: boolean;
|
|
53
|
-
}
|
|
87
|
+
};
|
|
54
88
|
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
55
89
|
|
|
56
90
|
type CopyButtonProps = Omit<ButtonProps, 'children' | 'leadingIcon' | 'loading' | 'size' | 'trailingIcon' | 'variant'> & {
|
|
@@ -62,7 +96,7 @@ type CopyButtonProps = Omit<ButtonProps, 'children' | 'leadingIcon' | 'loading'
|
|
|
62
96
|
variant?: ButtonVariant;
|
|
63
97
|
duration?: number;
|
|
64
98
|
};
|
|
65
|
-
declare const CopyButton: React.ForwardRefExoticComponent<Omit<ButtonProps, "size" | "variant" | "
|
|
99
|
+
declare const CopyButton: React.ForwardRefExoticComponent<Omit<ButtonProps, "size" | "variant" | "children" | "leadingIcon" | "trailingIcon" | "loading"> & {
|
|
66
100
|
value: string;
|
|
67
101
|
label?: React.ReactNode;
|
|
68
102
|
copiedLabel?: React.ReactNode;
|
|
@@ -73,13 +107,13 @@ declare const CopyButton: React.ForwardRefExoticComponent<Omit<ButtonProps, "siz
|
|
|
73
107
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
74
108
|
|
|
75
109
|
declare const inputVariants: (props?: ({
|
|
76
|
-
size?: "
|
|
110
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
77
111
|
fullWidth?: boolean | null | undefined;
|
|
78
112
|
surface?: SurfaceLevel | null | undefined;
|
|
79
113
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
80
114
|
declare const inputMessageVariants: (props?: ({
|
|
81
115
|
state?: "default" | "error" | "success" | null | undefined;
|
|
82
|
-
size?: "
|
|
116
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
83
117
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
84
118
|
type InputState = NonNullable<VariantProps<typeof inputMessageVariants>["state"]>;
|
|
85
119
|
/** Canonical size type (0.2.0+). Use `size` prop with these values. */
|
|
@@ -169,7 +203,7 @@ interface InlineAlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'childre
|
|
|
169
203
|
declare const InlineAlert: React.ForwardRefExoticComponent<InlineAlertProps & React.RefAttributes<HTMLDivElement>>;
|
|
170
204
|
|
|
171
205
|
declare const textareaVariants: (props?: ({
|
|
172
|
-
size?: "
|
|
206
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
173
207
|
fullWidth?: boolean | null | undefined;
|
|
174
208
|
surface?: SurfaceLevel | null | undefined;
|
|
175
209
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -223,14 +257,14 @@ interface TextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaEl
|
|
|
223
257
|
declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
224
258
|
|
|
225
259
|
declare const selectVariants: (props?: ({
|
|
226
|
-
size?: "
|
|
260
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
227
261
|
fullWidth?: boolean | null | undefined;
|
|
228
262
|
appearance?: "inline" | "field" | null | undefined;
|
|
229
263
|
surface?: SurfaceLevel | null | undefined;
|
|
230
264
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
231
265
|
declare const selectMessageVariants: (props?: ({
|
|
232
266
|
state?: "default" | "error" | "success" | null | undefined;
|
|
233
|
-
size?: "
|
|
267
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
234
268
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
235
269
|
type SelectState = NonNullable<VariantProps<typeof selectMessageVariants>["state"]>;
|
|
236
270
|
/** Canonical size type (0.2.0+). Use `size` prop with these values. */
|
|
@@ -1168,7 +1202,7 @@ interface StatusBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
1168
1202
|
declare const StatusBadge: React.ForwardRefExoticComponent<StatusBadgeProps & React.RefAttributes<HTMLSpanElement>>;
|
|
1169
1203
|
|
|
1170
1204
|
declare const notificationBadgeVariants: (props?: ({
|
|
1171
|
-
size?: "
|
|
1205
|
+
size?: "md" | "sm" | null | undefined;
|
|
1172
1206
|
placement?: "none" | "inline" | "corner" | null | undefined;
|
|
1173
1207
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1174
1208
|
type NotificationBadgeSize = NonNullable<VariantProps<typeof notificationBadgeVariants>['size']>;
|
|
@@ -1181,13 +1215,13 @@ declare const NotificationBadge: React.ForwardRefExoticComponent<NotificationBad
|
|
|
1181
1215
|
|
|
1182
1216
|
declare const chipVariants: (props?: ({
|
|
1183
1217
|
variant?: "filter" | "choice" | "removable" | "status-filter" | null | undefined;
|
|
1184
|
-
tone?: "accent" | "
|
|
1185
|
-
size?: "
|
|
1218
|
+
tone?: "accent" | "neutral" | "danger" | "success" | "warning" | "muted" | null | undefined;
|
|
1219
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1186
1220
|
pressed?: boolean | null | undefined;
|
|
1187
1221
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1188
1222
|
declare const chipCountVariants: (props?: ({
|
|
1189
|
-
tone?: "accent" | "
|
|
1190
|
-
size?: "
|
|
1223
|
+
tone?: "accent" | "neutral" | "danger" | "success" | "warning" | "muted" | null | undefined;
|
|
1224
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1191
1225
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1192
1226
|
type ChipVariant = NonNullable<VariantProps<typeof chipVariants>["variant"]>;
|
|
1193
1227
|
type ChipTone = NonNullable<VariantProps<typeof chipVariants>["tone"]>;
|
|
@@ -1201,7 +1235,7 @@ interface ChipProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
1201
1235
|
declare const Chip: React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLButtonElement>>;
|
|
1202
1236
|
|
|
1203
1237
|
declare const emptyStateBaseVariants: (props?: ({
|
|
1204
|
-
size?: "
|
|
1238
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1205
1239
|
bordered?: boolean | null | undefined;
|
|
1206
1240
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1207
1241
|
type EmptyStateTone = "neutral" | "muted" | "raised";
|
|
@@ -1212,7 +1246,7 @@ interface EmptyStateVariantOptions extends VariantProps<typeof emptyStateBaseVar
|
|
|
1212
1246
|
}
|
|
1213
1247
|
declare function emptyStateVariants({ size, tone, surface, bordered, className, }?: EmptyStateVariantOptions): string;
|
|
1214
1248
|
declare const emptyStateIconVariants: (props?: ({
|
|
1215
|
-
size?: "
|
|
1249
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1216
1250
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1217
1251
|
type EmptyStateSize = NonNullable<VariantProps<typeof emptyStateBaseVariants>["size"]>;
|
|
1218
1252
|
interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof emptyStateBaseVariants> {
|
|
@@ -1231,7 +1265,7 @@ interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "ti
|
|
|
1231
1265
|
declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
|
|
1232
1266
|
|
|
1233
1267
|
declare const errorStateVariants: (props?: ({
|
|
1234
|
-
size?: "
|
|
1268
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1235
1269
|
surface?: SurfaceLevel | null | undefined;
|
|
1236
1270
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1237
1271
|
interface ErrorStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof errorStateVariants> {
|
|
@@ -1251,7 +1285,7 @@ declare const skeletonVariants: (props?: ({
|
|
|
1251
1285
|
shape?: "text" | "block" | "circle" | null | undefined;
|
|
1252
1286
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1253
1287
|
declare const spinnerVariants: (props?: ({
|
|
1254
|
-
size?: "
|
|
1288
|
+
size?: "md" | "sm" | "lg" | 16 | 24 | 32 | null | undefined;
|
|
1255
1289
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1256
1290
|
interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof skeletonVariants> {
|
|
1257
1291
|
}
|
|
@@ -1283,16 +1317,29 @@ interface SpinnerProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
1283
1317
|
}
|
|
1284
1318
|
declare const Spinner: React.ForwardRefExoticComponent<SpinnerProps & React.RefAttributes<HTMLSpanElement>>;
|
|
1285
1319
|
|
|
1286
|
-
declare const
|
|
1287
|
-
|
|
1288
|
-
size?: "sm" | "md" | "lg" | null | undefined;
|
|
1320
|
+
declare const iconButtonCva: (props?: ({
|
|
1321
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1289
1322
|
pressed?: boolean | null | undefined;
|
|
1323
|
+
appearance?: "filled" | "outline" | "ghost" | null | undefined;
|
|
1324
|
+
tone?: "primary" | "neutral" | "danger" | null | undefined;
|
|
1325
|
+
variant?: "outline" | "ghost" | "danger" | "subtle" | null | undefined;
|
|
1290
1326
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1327
|
+
type IconButtonAxisSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
1328
|
+
type IconButtonCvaOptions = NonNullable<Parameters<typeof iconButtonCva>[0]>;
|
|
1329
|
+
type IconButtonVariantsOptions = (IconButtonCvaOptions & {
|
|
1330
|
+
appearance?: null;
|
|
1331
|
+
tone?: null;
|
|
1332
|
+
}) | (Omit<IconButtonCvaOptions, "size"> & {
|
|
1333
|
+
appearance?: ActionAppearance | null;
|
|
1334
|
+
tone?: ActionTone | null;
|
|
1335
|
+
size?: IconButtonAxisSize | null;
|
|
1336
|
+
});
|
|
1337
|
+
declare function iconButtonVariants(options?: IconButtonVariantsOptions): string;
|
|
1291
1338
|
declare const iconButtonBadgeVariants: (props?: ({
|
|
1292
1339
|
tone?: "error" | "info" | null | undefined;
|
|
1293
1340
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1294
|
-
type IconButtonVariant = NonNullable<VariantProps<typeof
|
|
1295
|
-
type IconButtonSize = NonNullable<VariantProps<typeof
|
|
1341
|
+
type IconButtonVariant = NonNullable<VariantProps<typeof iconButtonCva>["variant"]>;
|
|
1342
|
+
type IconButtonSize = NonNullable<VariantProps<typeof iconButtonCva>["size"]>;
|
|
1296
1343
|
type IconButtonBadgeTone = NonNullable<VariantProps<typeof iconButtonBadgeVariants>["tone"]>;
|
|
1297
1344
|
type IconButtonIcon = React.ComponentType<React.SVGProps<SVGSVGElement> & {
|
|
1298
1345
|
size?: number | string;
|
|
@@ -1305,11 +1352,47 @@ type IconButtonAccessibleName = {
|
|
|
1305
1352
|
"aria-label"?: string;
|
|
1306
1353
|
"aria-labelledby": string;
|
|
1307
1354
|
};
|
|
1308
|
-
type
|
|
1355
|
+
type IconButtonOptionalName = {
|
|
1356
|
+
"aria-label"?: string;
|
|
1357
|
+
"aria-labelledby"?: string;
|
|
1358
|
+
};
|
|
1359
|
+
type IconButtonContent = (IconButtonAccessibleName & {
|
|
1360
|
+
label?: never;
|
|
1361
|
+
children?: never;
|
|
1362
|
+
}) | (IconButtonOptionalName & {
|
|
1363
|
+
label: React.ReactNode;
|
|
1364
|
+
children?: never;
|
|
1365
|
+
}) | (IconButtonOptionalName & {
|
|
1366
|
+
children: React.ReactNode;
|
|
1367
|
+
label?: never;
|
|
1368
|
+
});
|
|
1369
|
+
type IconButtonStyleProps = (GhostDefaultActionStyle & {
|
|
1370
|
+
/**
|
|
1371
|
+
* @deprecated Use `appearance` × `tone` instead. Removed in 0.20.
|
|
1372
|
+
*/
|
|
1373
|
+
variant?: never;
|
|
1374
|
+
/** Button's scale: `xs` 28 · `sm` 30 · `md` 32 · `lg` 36 · `xl` 40. */
|
|
1375
|
+
size?: IconButtonAxisSize | null;
|
|
1376
|
+
}) | {
|
|
1377
|
+
/**
|
|
1378
|
+
* @deprecated Use `appearance` × `tone`: `ghost` → ghost + neutral · `outline` →
|
|
1379
|
+
* outline + neutral · `subtle` → filled + neutral · `danger` → filled + danger
|
|
1380
|
+
* (solid red; `danger` keeps its light red until removal). When moving to the new axes,
|
|
1381
|
+
* `size` follows Button's scale: `sm` → `xs`, `lg` → `xl` (`md` stays). Removed in 0.20.
|
|
1382
|
+
*/
|
|
1383
|
+
variant?: IconButtonVariant | null;
|
|
1384
|
+
appearance?: never;
|
|
1385
|
+
tone?: never;
|
|
1386
|
+
/** Legacy scale without `appearance`/`tone`: `sm` 28 · `md` 32 · `lg` 40. */
|
|
1387
|
+
size?: IconButtonSize | null;
|
|
1388
|
+
};
|
|
1389
|
+
type IconButtonProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "aria-label" | "aria-labelledby" | "children" | "color"> & IconButtonStyleProps & IconButtonContent & {
|
|
1309
1390
|
icon: IconButtonIcon;
|
|
1310
1391
|
pressed?: boolean;
|
|
1311
1392
|
badge?: React.ReactNode;
|
|
1312
1393
|
badgeTone?: IconButtonBadgeTone;
|
|
1394
|
+
/** Icon side when the button has text. */
|
|
1395
|
+
iconPosition?: "start" | "end";
|
|
1313
1396
|
};
|
|
1314
1397
|
declare const IconButton: React.ForwardRefExoticComponent<IconButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
1315
1398
|
|
|
@@ -1518,10 +1601,10 @@ interface OTPFieldProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetEl
|
|
|
1518
1601
|
declare const OTPField: React.ForwardRefExoticComponent<OTPFieldProps & React.RefAttributes<HTMLFieldSetElement>>;
|
|
1519
1602
|
|
|
1520
1603
|
declare const searchFieldVariants: (props?: ({
|
|
1521
|
-
size?: "
|
|
1604
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1522
1605
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1523
1606
|
declare const searchFieldInputVariants: (props?: ({
|
|
1524
|
-
size?: "
|
|
1607
|
+
size?: "md" | "sm" | "lg" | null | undefined;
|
|
1525
1608
|
hasClear?: boolean | null | undefined;
|
|
1526
1609
|
surface?: SurfaceLevel | null | undefined;
|
|
1527
1610
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -1545,7 +1628,7 @@ declare const checkboxVariants: (props?: ({
|
|
|
1545
1628
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1546
1629
|
declare const checkboxRootVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
|
|
1547
1630
|
declare const checkboxBoxVariants: (props?: ({
|
|
1548
|
-
size?: "
|
|
1631
|
+
size?: "md" | "sm" | null | undefined;
|
|
1549
1632
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1550
1633
|
declare const checkboxGroupItemVariants: (props?: ({
|
|
1551
1634
|
appearance?: "plain" | "card" | null | undefined;
|
|
@@ -1699,8 +1782,9 @@ declare function TreeView<T extends TreeNode>({ nodes, selectedId, selectionAria
|
|
|
1699
1782
|
/**
|
|
1700
1783
|
* OLUN 브랜드 로고.
|
|
1701
1784
|
*
|
|
1702
|
-
* - symbol: O 원형 테두리 + 우하단 accent-pop 작은 circle
|
|
1785
|
+
* - symbol: O 원형 테두리 + 우하단 accent-pop 작은 circle (32px 초과/이하 두 비율)
|
|
1703
1786
|
* - wordmark: "OLUN" + 마지막 "." 은 accent 색상
|
|
1787
|
+
* - 조합: symbol과 함께 쓰면 wordmark의 "."를 뺀다. 궤도 점은 symbol이 맡는다(점 두 개 경쟁 방지).
|
|
1704
1788
|
*
|
|
1705
1789
|
* 레퍼런스: apps/web/docs/wireframes/ref/shell-wireframe.html Topbar 브랜드 영역.
|
|
1706
1790
|
*/
|
package/dist/index.js
CHANGED
|
@@ -186,8 +186,61 @@ import * as React from "react";
|
|
|
186
186
|
import { cva } from "class-variance-authority";
|
|
187
187
|
import { Loader2 } from "lucide-react";
|
|
188
188
|
import { Slot } from "radix-ui";
|
|
189
|
+
|
|
190
|
+
// src/components/ui/action-variants.ts
|
|
191
|
+
var actionPaint = {
|
|
192
|
+
// = Button `primary`
|
|
193
|
+
filledPrimary: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
|
|
194
|
+
// = IconButton `subtle`; the transparent 1px border keeps Button's box model
|
|
195
|
+
filledNeutral: "border-transparent bg-[var(--bg-inset)] text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
196
|
+
// = Button `danger`
|
|
197
|
+
filledDanger: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
|
|
198
|
+
// = Button `secondary`
|
|
199
|
+
outlineNeutral: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
|
|
200
|
+
// = Button and IconButton `ghost`
|
|
201
|
+
ghostNeutral: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground"
|
|
202
|
+
};
|
|
203
|
+
var actionAxisVariants = {
|
|
204
|
+
appearance: { filled: "", outline: "", ghost: "" },
|
|
205
|
+
tone: { primary: "", neutral: "", danger: "" }
|
|
206
|
+
};
|
|
207
|
+
var actionCompoundVariants = [
|
|
208
|
+
{ appearance: "filled", tone: "primary", className: actionPaint.filledPrimary },
|
|
209
|
+
{ appearance: "filled", tone: "neutral", className: actionPaint.filledNeutral },
|
|
210
|
+
{ appearance: "filled", tone: "danger", className: actionPaint.filledDanger },
|
|
211
|
+
{ appearance: "outline", tone: "neutral", className: actionPaint.outlineNeutral },
|
|
212
|
+
{ appearance: "ghost", tone: "neutral", className: actionPaint.ghostNeutral }
|
|
213
|
+
];
|
|
214
|
+
function resolveActionStyle(appearance, tone, fallback) {
|
|
215
|
+
const resolvedAppearance = appearance ?? fallback;
|
|
216
|
+
return {
|
|
217
|
+
appearance: resolvedAppearance,
|
|
218
|
+
tone: tone ?? (resolvedAppearance === "filled" ? "primary" : "neutral")
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/components/ui/button.tsx
|
|
189
223
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
190
|
-
var
|
|
224
|
+
var buttonSizeMd = "h-[32px] gap-[6px] px-pad-default-x text-body-sm [&_svg]:size-[16px]";
|
|
225
|
+
var buttonSizes = {
|
|
226
|
+
// Cross-control height map: Button sm/md/lg match field controls sm/md/lg (30/32/36px).
|
|
227
|
+
// Height comes from h-* alone — no vertical padding (py-12 inside h-32 left a 6px content box).
|
|
228
|
+
// xs/sm: invisible ::before stretches the hit area to 44px tall (#69), vertically only so
|
|
229
|
+
// side-by-side buttons never overlap. Its inset is measured from the padding box, inside
|
|
230
|
+
// the 1px border every variant carries: inset = (44 - (height - 2 × 1px)) / 2.
|
|
231
|
+
// IconButton with text reuses these through `buttonSizeClassName`.
|
|
232
|
+
xs: "relative h-[28px] gap-[6px] px-pad-compact-x text-[12px] before:absolute before:inset-x-0 before:-inset-y-[9px] before:content-[''] [&_svg]:size-[14px] [&_svg]:stroke-[1.75]",
|
|
233
|
+
sm: "relative h-[30px] gap-[6px] px-pad-compact-x text-body-sm before:absolute before:inset-x-0 before:-inset-y-[8px] before:content-[''] [&_svg]:size-[16px]",
|
|
234
|
+
md: buttonSizeMd,
|
|
235
|
+
lg: "h-[36px] gap-[var(--space-2)] px-pad-default-x text-[15px] [&_svg]:size-[18px]",
|
|
236
|
+
xl: "h-[40px] gap-[var(--space-2)] px-5 text-[15px] [&_svg]:size-[18px]",
|
|
237
|
+
default: buttonSizeMd,
|
|
238
|
+
/** @deprecated Use IconButton `size="lg"`. */
|
|
239
|
+
icon: "size-[36px] p-0 [&_svg]:size-[18px]",
|
|
240
|
+
/** @deprecated Use IconButton `size="md"`. */
|
|
241
|
+
"icon-xs": "size-[32px] p-0 [&_svg]:size-[14px] [&_svg]:stroke-[1.75]"
|
|
242
|
+
};
|
|
243
|
+
var buttonCva = cva(
|
|
191
244
|
[
|
|
192
245
|
"inline-flex cursor-pointer items-center justify-center whitespace-nowrap rounded-[var(--radius-md)] border font-medium",
|
|
193
246
|
"transition-[background-color,border-color,color,box-shadow,transform] motion-reduce:transition-none",
|
|
@@ -199,42 +252,49 @@ var buttonVariants = cva(
|
|
|
199
252
|
].join(" "),
|
|
200
253
|
{
|
|
201
254
|
variants: {
|
|
255
|
+
// Legacy single axis, deprecated in 0.19 for `appearance` × `tone` and removed in 0.20.
|
|
256
|
+
// Frozen at 0.18; button-appearance.test.tsx keeps each value equal to its new pair.
|
|
202
257
|
variant: {
|
|
258
|
+
/** @deprecated Use `appearance="filled" tone="primary"`. */
|
|
203
259
|
primary: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
|
|
204
|
-
/** @deprecated Use `
|
|
260
|
+
/** @deprecated Use `appearance="outline" tone="neutral"`. */
|
|
205
261
|
outline: "border-[var(--border)] bg-transparent text-foreground hover:border-[var(--border-strong)] hover:bg-[var(--action-hover)]",
|
|
262
|
+
/** @deprecated Use `appearance="ghost" tone="neutral"`. */
|
|
206
263
|
ghost: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
264
|
+
/** @deprecated Use `appearance="filled" tone="danger"`. */
|
|
207
265
|
danger: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
|
|
266
|
+
/** @deprecated Use `appearance="filled" tone="danger"`. */
|
|
208
267
|
emergency: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
|
|
209
|
-
/** @deprecated Use `
|
|
268
|
+
/** @deprecated Use `appearance="outline" tone="neutral"`. */
|
|
210
269
|
subtle: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
|
|
270
|
+
/** @deprecated Use `appearance="filled" tone="primary"`. */
|
|
211
271
|
default: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
|
|
272
|
+
/** @deprecated Use `appearance="filled" tone="danger"`. */
|
|
212
273
|
destructive: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
|
|
274
|
+
/** @deprecated Use `appearance="outline" tone="neutral"`. */
|
|
213
275
|
secondary: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
|
|
276
|
+
/** @deprecated No replacement on Button; a link component is planned. */
|
|
214
277
|
link: "border-transparent bg-transparent px-0 text-[var(--accent)] underline-offset-4 hover:underline"
|
|
215
278
|
},
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// Height comes from h-* alone — no vertical padding (py-12 inside h-32 left a 6px content box).
|
|
219
|
-
// xs/sm: invisible ::before stretches the hit area to 44px tall (#69), vertically only so
|
|
220
|
-
// side-by-side buttons never overlap. Its inset is measured from the padding box, inside
|
|
221
|
-
// the 1px border every variant carries: inset = (44 - (height - 2 × 1px)) / 2.
|
|
222
|
-
xs: "relative h-[28px] gap-[6px] px-pad-compact-x text-[12px] before:absolute before:inset-x-0 before:-inset-y-[9px] before:content-[''] [&_svg]:size-[14px] [&_svg]:stroke-[1.75]",
|
|
223
|
-
sm: "relative h-[30px] gap-[6px] px-pad-compact-x text-body-sm before:absolute before:inset-x-0 before:-inset-y-[8px] before:content-[''] [&_svg]:size-[16px]",
|
|
224
|
-
md: "h-[32px] gap-[6px] px-pad-default-x text-body-sm [&_svg]:size-[16px]",
|
|
225
|
-
lg: "h-[36px] gap-[var(--space-2)] px-pad-default-x text-[15px] [&_svg]:size-[18px]",
|
|
226
|
-
xl: "h-[40px] gap-[var(--space-2)] px-5 text-[15px] [&_svg]:size-[18px]",
|
|
227
|
-
default: "h-[32px] gap-[6px] px-pad-default-x text-body-sm [&_svg]:size-[16px]",
|
|
228
|
-
icon: "size-[36px] p-0 [&_svg]:size-[18px]",
|
|
229
|
-
"icon-xs": "size-[32px] p-0 [&_svg]:size-[14px] [&_svg]:stroke-[1.75]"
|
|
230
|
-
}
|
|
279
|
+
...actionAxisVariants,
|
|
280
|
+
size: buttonSizes
|
|
231
281
|
},
|
|
282
|
+
compoundVariants: [...actionCompoundVariants],
|
|
232
283
|
defaultVariants: {
|
|
233
284
|
variant: "primary",
|
|
234
285
|
size: "md"
|
|
235
286
|
}
|
|
236
287
|
}
|
|
237
288
|
);
|
|
289
|
+
function buttonVariants(options) {
|
|
290
|
+
if (options?.appearance == null && options?.tone == null) return buttonCva(options);
|
|
291
|
+
return buttonCva({
|
|
292
|
+
...options,
|
|
293
|
+
...resolveActionStyle(options.appearance, options.tone, "filled"),
|
|
294
|
+
variant: null
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
var buttonSizeClassName = (size) => buttonSizes[size];
|
|
238
298
|
var footerButtonHitAreaClassName = "relative before:absolute before:inset-x-0 before:-inset-y-[5px] before:content-['']";
|
|
239
299
|
var Button = React.forwardRef(
|
|
240
300
|
({
|
|
@@ -247,6 +307,8 @@ var Button = React.forwardRef(
|
|
|
247
307
|
trailingIcon: TrailingIcon,
|
|
248
308
|
type = "button",
|
|
249
309
|
variant,
|
|
310
|
+
appearance,
|
|
311
|
+
tone,
|
|
250
312
|
size,
|
|
251
313
|
style,
|
|
252
314
|
...props
|
|
@@ -281,7 +343,7 @@ var Button = React.forwardRef(
|
|
|
281
343
|
"aria-disabled": isDisabled ? true : void 0,
|
|
282
344
|
disabled: !asChild ? isDisabled : void 0,
|
|
283
345
|
type: !asChild ? type : void 0,
|
|
284
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
346
|
+
className: cn(buttonVariants({ variant, appearance, tone, size, className })),
|
|
285
347
|
style: frozenStyle ? { ...frozenStyle, ...style } : style,
|
|
286
348
|
...props,
|
|
287
349
|
children: [
|
|
@@ -2963,7 +3025,7 @@ var tabsListVariants = cva8(
|
|
|
2963
3025
|
{
|
|
2964
3026
|
variant: "line",
|
|
2965
3027
|
orientation: "vertical",
|
|
2966
|
-
className: "border-r border-[var(--border-subtle)] gap-[var(--space-2)] pr-[var(--space-4)]"
|
|
3028
|
+
className: "border-r border-[var(--border-subtle)] gap-[var(--space-2)] pr-[var(--space-4)] max-sm:flex-row max-sm:gap-[var(--space-6)] max-sm:overflow-x-auto max-sm:overflow-y-hidden max-sm:border-r-0 max-sm:border-b max-sm:pr-0"
|
|
2967
3029
|
},
|
|
2968
3030
|
{
|
|
2969
3031
|
variant: "contained",
|
|
@@ -3006,9 +3068,24 @@ var tabsTriggerVariants = cva8(
|
|
|
3006
3068
|
},
|
|
3007
3069
|
orientation: {
|
|
3008
3070
|
horizontal: "",
|
|
3009
|
-
vertical: "w-full justify-start data-[state=active]:after:bottom-0 data-[state=active]:after:left-auto data-[state=active]:after:right-[-1px] data-[state=active]:after:top-0 data-[state=active]:after:h-auto data-[state=active]:after:w-[2px]"
|
|
3071
|
+
vertical: "sm:w-full sm:justify-start sm:data-[state=active]:after:bottom-0 sm:data-[state=active]:after:left-auto sm:data-[state=active]:after:right-[calc(-1*(var(--space-4)+1px))] sm:data-[state=active]:after:top-0 sm:data-[state=active]:after:h-auto sm:data-[state=active]:after:w-[2px]"
|
|
3010
3072
|
}
|
|
3011
3073
|
},
|
|
3074
|
+
compoundVariants: [
|
|
3075
|
+
// 가로 line 목록은 overflow-y-hidden이라 바깥 ring이 잘린다. 2px 안쪽 여백을 두고 inset-ring으로 안쪽에 그린다.
|
|
3076
|
+
// ring-inset은 쓰지 않는다: 토큰 테마의 --color-inset(bg-inset) 때문에 ring 색이 배경색으로 덮인다.
|
|
3077
|
+
// 트리거 사이는 -mx로 보정해 텍스트 간격은 그대로 두고, 양 끝 트리거는 안쪽 여백을 유지해 ring이 목록 안에 남는다.
|
|
3078
|
+
{
|
|
3079
|
+
variant: "line",
|
|
3080
|
+
orientation: "horizontal",
|
|
3081
|
+
className: "mx-[-2px] px-[2px] first:ml-0 last:mr-0 focus-visible:ring-0 focus-visible:inset-ring-2 focus-visible:inset-ring-[var(--focus-ring)]"
|
|
3082
|
+
},
|
|
3083
|
+
{
|
|
3084
|
+
variant: "line",
|
|
3085
|
+
orientation: "vertical",
|
|
3086
|
+
className: "max-sm:mx-[-2px] max-sm:px-[2px] max-sm:first:ml-0 max-sm:last:mr-0 max-sm:focus-visible:ring-0 max-sm:focus-visible:inset-ring-2 max-sm:focus-visible:inset-ring-[var(--focus-ring)]"
|
|
3087
|
+
}
|
|
3088
|
+
],
|
|
3012
3089
|
defaultVariants: {
|
|
3013
3090
|
variant: "line",
|
|
3014
3091
|
orientation: "horizontal"
|
|
@@ -4254,7 +4331,7 @@ Chip.displayName = "Chip";
|
|
|
4254
4331
|
import * as React24 from "react";
|
|
4255
4332
|
import { cva as cva10 } from "class-variance-authority";
|
|
4256
4333
|
import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
4257
|
-
var
|
|
4334
|
+
var iconButtonCva = cva10(
|
|
4258
4335
|
[
|
|
4259
4336
|
"olun-icon-button relative inline-flex cursor-pointer shrink-0 items-center justify-center before:absolute before:content-['']",
|
|
4260
4337
|
"rounded-[var(--radius-md)] border font-medium",
|
|
@@ -4265,12 +4342,21 @@ var iconButtonVariants = cva10(
|
|
|
4265
4342
|
].join(" "),
|
|
4266
4343
|
{
|
|
4267
4344
|
variants: {
|
|
4345
|
+
// Legacy single axis, deprecated in 0.19 for `appearance` × `tone` and removed in 0.20.
|
|
4346
|
+
// Frozen at 0.18; button-appearance.test.tsx keeps ghost and subtle equal to their new
|
|
4347
|
+
// pair. `outline` and `danger` differ from the pair they migrate to (outline + neutral =
|
|
4348
|
+
// Button secondary, filled + danger = solid red).
|
|
4268
4349
|
variant: {
|
|
4350
|
+
/** @deprecated Use `appearance="ghost" tone="neutral"` (the default). */
|
|
4269
4351
|
ghost: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
4352
|
+
/** @deprecated Use `appearance="outline" tone="neutral"`. */
|
|
4270
4353
|
outline: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-text-secondary hover:border-[var(--border-strong)] hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
4354
|
+
/** @deprecated Use `appearance="filled" tone="neutral"`. */
|
|
4271
4355
|
subtle: "border-transparent bg-[var(--bg-inset)] text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
4356
|
+
/** @deprecated Use `appearance="filled" tone="danger"` (solid red, like Button). */
|
|
4272
4357
|
danger: "border-transparent bg-[var(--error-bg)] text-[var(--error)] hover:bg-[var(--action-hover)]"
|
|
4273
4358
|
},
|
|
4359
|
+
...actionAxisVariants,
|
|
4274
4360
|
// Hit area = 44px on every size. The ::before is absolutely positioned, so its
|
|
4275
4361
|
// inset is measured from the padding box — inside the 1px border every variant
|
|
4276
4362
|
// carries (transparent or not). Inset = (44 - (size - 2 × 1px border)) / 2.
|
|
@@ -4285,6 +4371,7 @@ var iconButtonVariants = cva10(
|
|
|
4285
4371
|
}
|
|
4286
4372
|
},
|
|
4287
4373
|
compoundVariants: [
|
|
4374
|
+
...actionCompoundVariants,
|
|
4288
4375
|
{
|
|
4289
4376
|
pressed: true,
|
|
4290
4377
|
variant: ["ghost", "outline", "subtle"],
|
|
@@ -4294,6 +4381,11 @@ var iconButtonVariants = cva10(
|
|
|
4294
4381
|
pressed: true,
|
|
4295
4382
|
variant: "danger",
|
|
4296
4383
|
className: "border-[var(--error)] bg-[var(--error-bg)] text-[var(--error)]"
|
|
4384
|
+
},
|
|
4385
|
+
{
|
|
4386
|
+
pressed: true,
|
|
4387
|
+
tone: "neutral",
|
|
4388
|
+
className: "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground"
|
|
4297
4389
|
}
|
|
4298
4390
|
],
|
|
4299
4391
|
// ghost is the intended default, not a fallback: ghost is reserved for icon-only
|
|
@@ -4306,6 +4398,33 @@ var iconButtonVariants = cva10(
|
|
|
4306
4398
|
}
|
|
4307
4399
|
}
|
|
4308
4400
|
);
|
|
4401
|
+
var axisSizeClassName = {
|
|
4402
|
+
xs: "size-[28px] before:-inset-[9px]",
|
|
4403
|
+
sm: "size-[30px] before:-inset-[8px]",
|
|
4404
|
+
md: "size-[32px] before:-inset-[7px]",
|
|
4405
|
+
lg: "size-[36px] before:-inset-[5px]",
|
|
4406
|
+
xl: "size-[40px] before:-inset-[3px]"
|
|
4407
|
+
};
|
|
4408
|
+
var axisIcon = {
|
|
4409
|
+
xs: { size: 14, strokeWidth: 1.75 },
|
|
4410
|
+
sm: { size: 16, strokeWidth: 2 },
|
|
4411
|
+
md: { size: 16, strokeWidth: 2 },
|
|
4412
|
+
lg: { size: 18, strokeWidth: 2 },
|
|
4413
|
+
xl: { size: 18, strokeWidth: 2 }
|
|
4414
|
+
};
|
|
4415
|
+
function iconButtonVariants(options) {
|
|
4416
|
+
if (options?.appearance == null && options?.tone == null) {
|
|
4417
|
+
return iconButtonCva(options);
|
|
4418
|
+
}
|
|
4419
|
+
const { size, ...rest } = options;
|
|
4420
|
+
const paint = iconButtonCva({
|
|
4421
|
+
...rest,
|
|
4422
|
+
...resolveActionStyle(options.appearance, options.tone, "ghost"),
|
|
4423
|
+
variant: null,
|
|
4424
|
+
size: null
|
|
4425
|
+
});
|
|
4426
|
+
return size === null ? paint : `${paint} ${axisSizeClassName[size ?? "md"]}`;
|
|
4427
|
+
}
|
|
4309
4428
|
var iconButtonBadgeVariants = cva10(
|
|
4310
4429
|
[
|
|
4311
4430
|
"pointer-events-none absolute right-0 top-0 inline-flex",
|
|
@@ -4332,6 +4451,11 @@ var iconSize2 = {
|
|
|
4332
4451
|
md: 16,
|
|
4333
4452
|
lg: 18
|
|
4334
4453
|
};
|
|
4454
|
+
var textButtonSize = {
|
|
4455
|
+
sm: "xs",
|
|
4456
|
+
md: "md",
|
|
4457
|
+
lg: "xl"
|
|
4458
|
+
};
|
|
4335
4459
|
var iconStrokeWidth = {
|
|
4336
4460
|
sm: 2.25,
|
|
4337
4461
|
md: 2.25,
|
|
@@ -4341,6 +4465,8 @@ var IconButton = React24.forwardRef(
|
|
|
4341
4465
|
({
|
|
4342
4466
|
className,
|
|
4343
4467
|
variant = "ghost",
|
|
4468
|
+
appearance,
|
|
4469
|
+
tone,
|
|
4344
4470
|
size = "md",
|
|
4345
4471
|
pressed = void 0,
|
|
4346
4472
|
icon: Icon,
|
|
@@ -4350,39 +4476,63 @@ var IconButton = React24.forwardRef(
|
|
|
4350
4476
|
title,
|
|
4351
4477
|
"aria-label": ariaLabel,
|
|
4352
4478
|
"aria-labelledby": ariaLabelledBy,
|
|
4479
|
+
iconPosition = "start",
|
|
4480
|
+
label,
|
|
4481
|
+
children,
|
|
4353
4482
|
...props
|
|
4354
4483
|
}, ref) => {
|
|
4355
4484
|
const resolvedSize = size ?? "md";
|
|
4485
|
+
const usesAxes = appearance != null || tone != null;
|
|
4356
4486
|
const isToggle = pressed !== void 0;
|
|
4357
4487
|
const isPressed = pressed === true;
|
|
4358
4488
|
const hoverTitle = title ?? (typeof ariaLabel === "string" ? ariaLabel : void 0);
|
|
4489
|
+
const text = label ?? children;
|
|
4490
|
+
const hasText = text !== void 0 && text !== null && text !== false;
|
|
4491
|
+
const style = usesAxes ? resolveActionStyle(appearance, tone, "ghost") : void 0;
|
|
4492
|
+
const axisSize = usesAxes ? resolvedSize : void 0;
|
|
4493
|
+
const legacySize = resolvedSize;
|
|
4494
|
+
const textBoxSize = axisSize ?? textButtonSize[legacySize];
|
|
4495
|
+
const icon = /* @__PURE__ */ jsx26(
|
|
4496
|
+
Icon,
|
|
4497
|
+
{
|
|
4498
|
+
"aria-hidden": "true",
|
|
4499
|
+
"data-slot": "icon-button-icon",
|
|
4500
|
+
size: axisSize ? axisIcon[axisSize].size : iconSize2[legacySize],
|
|
4501
|
+
strokeWidth: axisSize ? axisIcon[axisSize].strokeWidth : hasText ? void 0 : iconStrokeWidth[legacySize]
|
|
4502
|
+
}
|
|
4503
|
+
);
|
|
4359
4504
|
return /* @__PURE__ */ jsxs25(
|
|
4360
4505
|
"button",
|
|
4361
4506
|
{
|
|
4362
4507
|
ref,
|
|
4363
4508
|
...props,
|
|
4364
4509
|
"data-slot": "icon-button",
|
|
4365
|
-
"data-variant": variant,
|
|
4510
|
+
"data-variant": usesAxes ? void 0 : variant,
|
|
4511
|
+
"data-appearance": style?.appearance,
|
|
4512
|
+
"data-tone": style?.tone,
|
|
4366
4513
|
"data-size": resolvedSize,
|
|
4514
|
+
"data-icon-position": hasText ? iconPosition : void 0,
|
|
4367
4515
|
"data-pressed": isToggle ? String(isPressed) : void 0,
|
|
4368
4516
|
"aria-label": ariaLabel,
|
|
4369
4517
|
"aria-labelledby": ariaLabelledBy,
|
|
4370
4518
|
"aria-pressed": isToggle ? isPressed : void 0,
|
|
4371
4519
|
title: hoverTitle,
|
|
4372
4520
|
className: cn(
|
|
4373
|
-
iconButtonVariants({
|
|
4521
|
+
iconButtonVariants({
|
|
4522
|
+
variant,
|
|
4523
|
+
appearance,
|
|
4524
|
+
tone,
|
|
4525
|
+
size: hasText ? null : size,
|
|
4526
|
+
pressed: isPressed
|
|
4527
|
+
}),
|
|
4528
|
+
hasText && ["whitespace-nowrap", buttonSizeClassName(textBoxSize)],
|
|
4529
|
+
className
|
|
4374
4530
|
),
|
|
4375
4531
|
type: type ?? "button",
|
|
4376
4532
|
children: [
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
"aria-hidden": "true",
|
|
4381
|
-
"data-slot": "icon-button-icon",
|
|
4382
|
-
size: iconSize2[resolvedSize],
|
|
4383
|
-
strokeWidth: iconStrokeWidth[resolvedSize]
|
|
4384
|
-
}
|
|
4385
|
-
),
|
|
4533
|
+
hasText && iconPosition === "end" ? null : icon,
|
|
4534
|
+
hasText ? text : null,
|
|
4535
|
+
hasText && iconPosition === "end" ? icon : null,
|
|
4386
4536
|
badge !== void 0 ? /* @__PURE__ */ jsx26(
|
|
4387
4537
|
"span",
|
|
4388
4538
|
{
|
|
@@ -9722,7 +9872,10 @@ function TreeView({
|
|
|
9722
9872
|
|
|
9723
9873
|
// src/components/branding/olun-logo.tsx
|
|
9724
9874
|
import { jsx as jsx58, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
9875
|
+
var SYMBOL_LARGE = { stroke: 24, dotX: 184, dotY: 180, dotR: 13 };
|
|
9876
|
+
var SYMBOL_SMALL = { stroke: 18, dotX: 185, dotY: 175, dotR: 22 };
|
|
9725
9877
|
function OlunSymbol({ size = 28, className }) {
|
|
9878
|
+
const g = size > 32 ? SYMBOL_LARGE : SYMBOL_SMALL;
|
|
9726
9879
|
return /* @__PURE__ */ jsxs51(
|
|
9727
9880
|
"svg",
|
|
9728
9881
|
{
|
|
@@ -9741,12 +9894,12 @@ function OlunSymbol({ size = 28, className }) {
|
|
|
9741
9894
|
cy: "120",
|
|
9742
9895
|
r: "60",
|
|
9743
9896
|
stroke: "currentColor",
|
|
9744
|
-
strokeWidth:
|
|
9897
|
+
strokeWidth: g.stroke,
|
|
9745
9898
|
fill: "none",
|
|
9746
9899
|
style: { color: "var(--text-primary)" }
|
|
9747
9900
|
}
|
|
9748
9901
|
),
|
|
9749
|
-
/* @__PURE__ */ jsx58("circle", { cx:
|
|
9902
|
+
/* @__PURE__ */ jsx58("circle", { cx: g.dotX, cy: g.dotY, r: g.dotR, fill: "var(--accent-pop)" })
|
|
9750
9903
|
]
|
|
9751
9904
|
}
|
|
9752
9905
|
);
|
|
@@ -9780,7 +9933,7 @@ function OlunLogo({
|
|
|
9780
9933
|
},
|
|
9781
9934
|
children: [
|
|
9782
9935
|
"OLUN",
|
|
9783
|
-
/* @__PURE__ */ jsx58("span", { style: { color: "var(--accent)" }, children: "." })
|
|
9936
|
+
!showSymbol && /* @__PURE__ */ jsx58("span", { style: { color: "var(--accent)" }, children: "." })
|
|
9784
9937
|
]
|
|
9785
9938
|
}
|
|
9786
9939
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olundot/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "OLUN. shared React UI components built on OLUN design tokens",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"lucide-react": "^1.8.0",
|
|
45
45
|
"radix-ui": "^1.4.3",
|
|
46
46
|
"tailwind-merge": "^3.5.0",
|
|
47
|
-
"@olundot/tokens": "^0.
|
|
47
|
+
"@olundot/tokens": "^0.17.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"react": ">=18",
|