@versini/ui-button 11.3.3 → 11.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/188.js ADDED
@@ -0,0 +1,469 @@
1
+ /*!
2
+ @versini/ui-button v11.3.5
3
+ © 2026 gizmette.com
4
+ */
5
+
6
+ import clsx from "clsx";
7
+
8
+
9
+
10
+ const BUTTON_CLASSNAME = "av-button";
11
+
12
+
13
+
14
+ const TYPE_ICON = "icon";
15
+ const TYPE_BUTTON = "button";
16
+ const TYPE_LINK = "link";
17
+ // Text copy classes
18
+ const TEXT_COPY_DARK = "text-copy-dark";
19
+ const TEXT_COPY_LIGHT = "text-copy-light";
20
+ const TEXT_COPY_LIGHTER = "text-copy-lighter";
21
+ const DARK_TEXT_COPY_DARK = "dark:text-copy-dark";
22
+ const DARK_TEXT_COPY_LIGHT = "dark:text-copy-light";
23
+ const DARK_TEXT_COPY_LIGHTER = "dark:text-copy-lighter";
24
+ // Hover text classes
25
+ const HOVER_TEXT_DARK = "hover:text-copy-dark-hover";
26
+ const HOVER_TEXT_LIGHT = "hover:text-copy-light-hover";
27
+ const DARK_HOVER_TEXT_DARK = "dark:hover:text-copy-dark-hover";
28
+ const DARK_HOVER_TEXT_LIGHT = "dark:hover:text-copy-light-hover";
29
+ // Active text classes
30
+ const ACTIVE_TEXT_LIGHT = "active:text-copy-light-active";
31
+ const ACTIVE_TEXT_MEDIUM = "active:text-copy-medium-active";
32
+ const ACTIVE_TEXT_LIGHTER = "active:text-copy-lighter-active";
33
+ const DARK_ACTIVE_TEXT_LIGHT = "dark:active:text-copy-light-active";
34
+ const DARK_ACTIVE_TEXT_MEDIUM = "dark:active:text-copy-medium-active";
35
+ // Background classes
36
+ const BG_ACTION_LIGHT = "bg-action-light";
37
+ const BG_ACTION_DARK = "bg-action-dark";
38
+ const BG_DANGER_LIGHT = "bg-action-danger-light";
39
+ const BG_DANGER_DARK = "bg-action-danger-dark";
40
+ // System mode compound background classes
41
+ const BG_LIGHT_DARK_DARK = "bg-action-light dark:bg-action-dark";
42
+ const BG_DARK_DARK_LIGHT = "bg-action-dark dark:bg-action-light";
43
+ const BG_DANGER_DARK_DARK_LIGHT = "bg-action-danger-dark dark:bg-action-danger-light";
44
+ const BG_DANGER_LIGHT_DARK_DARK = "bg-action-danger-light dark:bg-action-danger-dark";
45
+ // Hover background classes
46
+ const HOVER_BG_LIGHT = "hover:bg-action-light-hover";
47
+ const HOVER_BG_DARK = "hover:bg-action-dark-hover";
48
+ const HOVER_BG_DANGER_LIGHT = "hover:bg-action-danger-light-hover";
49
+ const HOVER_BG_DANGER_DARK = "hover:bg-action-danger-dark-hover";
50
+ // System mode compound hover background classes
51
+ const HOVER_BG_LIGHT_DARK_DARK = "hover:bg-action-light-hover dark:hover:bg-action-dark-hover";
52
+ const HOVER_BG_DARK_DARK_LIGHT = "hover:bg-action-dark-hover dark:hover:bg-action-light-hover";
53
+ const HOVER_BG_DANGER_DARK_DARK_LIGHT = "hover:bg-action-danger-dark-hover dark:hover:bg-action-danger-light-hover";
54
+ const HOVER_BG_DANGER_LIGHT_DARK_DARK = "hover:bg-action-danger-light-hover dark:hover:bg-action-danger-dark-hover";
55
+ // Active background classes
56
+ const ACTIVE_BG_LIGHT = "active:bg-action-light-active";
57
+ const ACTIVE_BG_DARK = "active:bg-action-dark-active";
58
+ const ACTIVE_BG_DANGER_LIGHT = "active:bg-action-danger-light-active";
59
+ const ACTIVE_BG_DANGER_DARK = "active:bg-action-danger-dark-active";
60
+ // System mode compound active background classes
61
+ const ACTIVE_BG_LIGHT_DARK_DARK = "active:bg-action-light-active dark:active:bg-action-dark-active";
62
+ const ACTIVE_BG_DARK_DARK_LIGHT = "active:bg-action-dark-active dark:active:bg-action-light-active";
63
+ const ACTIVE_BG_DANGER_DARK_DARK_LIGHT = "active:bg-action-danger-dark-active dark:active:bg-action-danger-light-active";
64
+ const ACTIVE_BG_DANGER_LIGHT_DARK_DARK = "active:bg-action-danger-light-active dark:active:bg-action-danger-dark-active";
65
+ // Border classes
66
+ const BORDER_MEDIUM = "border-border-medium";
67
+ const BORDER_ACCENT = "border-border-accent";
68
+ const BORDER_DANGER_MEDIUM = "border-border-danger-medium";
69
+ const BORDER_DANGER_DARK = "border-border-danger-dark";
70
+ // System mode compound border classes
71
+ const BORDER_MEDIUM_DARK_ACCENT = "border-border-medium dark:border-border-accent";
72
+ const BORDER_ACCENT_DARK_MEDIUM = "border-border-accent dark:border-border-medium";
73
+ const BORDER_DANGER_DARK_DARK_MEDIUM = "border-border-danger-dark dark:border-border-danger-medium";
74
+ const BORDER_DANGER_MEDIUM_DARK_DARK = "border-border-danger-medium dark:border-border-danger-dark";
75
+ // Focus classes
76
+ const FOCUS_LIGHT = "focus:outline-focus-light";
77
+ const FOCUS_DARK = "focus:outline-focus-dark";
78
+ // System mode compound focus classes
79
+ const FOCUS_LIGHT_DARK_DARK = "focus:outline-focus-light dark:focus:outline-focus-dark";
80
+ const FOCUS_DARK_DARK_LIGHT = "focus:outline-focus-dark dark:focus:outline-focus-light";
81
+ // Common utility classes
82
+ const NOT_PROSE = "not-prose";
83
+ // Size classes
84
+ const SIZE_SMALL = "max-h-8 py-0 px-2";
85
+ const SIZE_MEDIUM = "max-h-9 h-8 px-3";
86
+ const SIZE_LARGE = "max-h-12 py-2 px-4";
87
+ // Font size classes
88
+ const FONT_SMALL = "text-sm font-medium";
89
+ const FONT_MEDIUM = "text-base font-medium";
90
+ const FONT_LARGE = "text-lg font-medium";
91
+ /**
92
+ * Helpers functions used more than once.
93
+ */ const isSmall = (size)=>size === "small";
94
+ const isMedium = (size)=>size === "medium";
95
+ const isLarge = (size)=>size === "large";
96
+ const isPrimary = (variant)=>variant === "primary";
97
+ const isSecondary = (variant)=>variant === "secondary";
98
+ const isDanger = (variant)=>variant === "danger";
99
+ const isSelected = (variant)=>variant === "selected";
100
+ const isLight = (mode)=>mode === "light";
101
+ const isDark = (mode)=>mode === "dark";
102
+ const isSystem = (mode)=>mode === "system";
103
+ const isAltSystem = (mode)=>mode === "alt-system";
104
+ const isDarkOrAltSystem = (mode)=>isDark(mode) || isAltSystem(mode);
105
+ const isLightOrSystem = (mode)=>isLight(mode) || isSystem(mode);
106
+ const getButtonSizesClasses = ({ type, size, labelRight, labelLeft, align, animated })=>{
107
+ const labelRightOrLeft = labelRight || labelLeft;
108
+ switch(type){
109
+ case TYPE_BUTTON:
110
+ case TYPE_LINK:
111
+ return clsx({
112
+ [SIZE_SMALL]: isSmall(size),
113
+ [SIZE_MEDIUM]: isMedium(size),
114
+ [SIZE_LARGE]: isLarge(size)
115
+ });
116
+ case TYPE_ICON:
117
+ return clsx("flex items-center", {
118
+ "justify-center": align === "center",
119
+ "justify-start": align === "left",
120
+ "justify-end": align === "right",
121
+ "h-6 w-6 p-0": isSmall(size) && !animated && !labelRightOrLeft,
122
+ "h-6 px-1 sm:px-2": isSmall(size) && !animated && labelRightOrLeft,
123
+ "h-8 w-8 p-1": isMedium(size) && !animated && !labelRightOrLeft,
124
+ "h-8 px-3": isMedium(size) && !animated && labelRightOrLeft,
125
+ "h-12 w-12 p-2": isLarge(size) && !animated && !labelRightOrLeft,
126
+ "h-12 px-4": isLarge(size) && !animated && labelRightOrLeft,
127
+ "h-6 py-0": isSmall(size) && animated && !labelRightOrLeft,
128
+ "h-6": isSmall(size) && animated && labelRightOrLeft,
129
+ "h-8 py-1": isMedium(size) && animated && !labelRightOrLeft,
130
+ "h-8": isMedium(size) && animated && labelRightOrLeft,
131
+ "h-12 py-2": isLarge(size) && animated && !labelRightOrLeft,
132
+ "h-12": isLarge(size) && animated && labelRightOrLeft
133
+ });
134
+ }
135
+ };
136
+ const getButtonFontClasses = ({ type, size, labelRight, labelLeft })=>{
137
+ switch(type){
138
+ case TYPE_BUTTON:
139
+ case TYPE_LINK:
140
+ return clsx({
141
+ "text-center": type === TYPE_LINK,
142
+ [FONT_SMALL]: isSmall(size),
143
+ [FONT_MEDIUM]: isMedium(size),
144
+ [FONT_LARGE]: isLarge(size)
145
+ });
146
+ case TYPE_ICON:
147
+ return clsx({
148
+ [FONT_SMALL]: isSmall(size) && (labelRight || labelLeft),
149
+ [FONT_MEDIUM]: isMedium(size) && (labelRight || labelLeft),
150
+ [FONT_LARGE]: isLarge(size) && (labelRight || labelLeft)
151
+ });
152
+ }
153
+ };
154
+ const getButtonTextCopyClasses = ({ mode, noBackground, truncate, variant })=>{
155
+ if (noBackground) {
156
+ return NOT_PROSE;
157
+ }
158
+ const truncateClass = {
159
+ truncate: truncate
160
+ };
161
+ if (isPrimary(variant)) {
162
+ return clsx(NOT_PROSE, {
163
+ ...truncateClass,
164
+ [TEXT_COPY_DARK]: isLightOrSystem(mode),
165
+ [TEXT_COPY_LIGHT]: isDarkOrAltSystem(mode),
166
+ [DARK_TEXT_COPY_LIGHT]: isSystem(mode),
167
+ [DARK_TEXT_COPY_DARK]: isAltSystem(mode)
168
+ });
169
+ }
170
+ if (isSecondary(variant)) {
171
+ return clsx(NOT_PROSE, {
172
+ ...truncateClass,
173
+ [TEXT_COPY_LIGHT]: isLightOrSystem(mode),
174
+ [TEXT_COPY_DARK]: isDarkOrAltSystem(mode),
175
+ [DARK_TEXT_COPY_DARK]: isSystem(mode),
176
+ [DARK_TEXT_COPY_LIGHT]: isAltSystem(mode)
177
+ });
178
+ }
179
+ if (isDanger(variant)) {
180
+ return clsx(NOT_PROSE, {
181
+ ...truncateClass,
182
+ [TEXT_COPY_LIGHT]: isDarkOrAltSystem(mode),
183
+ [TEXT_COPY_LIGHTER]: mode === "light" || mode === "alt-system",
184
+ [DARK_TEXT_COPY_LIGHTER]: isSystem(mode),
185
+ [DARK_TEXT_COPY_LIGHT]: isAltSystem(mode)
186
+ });
187
+ }
188
+ /* v8 ignore start - selected variant edge case */ if (isSelected(variant)) {
189
+ return clsx(NOT_PROSE, TEXT_COPY_LIGHTER, truncateClass);
190
+ }
191
+ /* v8 ignore stop */ };
192
+ const getButtonBackgroundClasses = ({ mode, noBackground, variant })=>{
193
+ if (noBackground) {
194
+ return;
195
+ }
196
+ if (isPrimary(variant)) {
197
+ return clsx({
198
+ [BG_ACTION_LIGHT]: isLight(mode),
199
+ [BG_ACTION_DARK]: isDark(mode),
200
+ [BG_LIGHT_DARK_DARK]: isSystem(mode),
201
+ [BG_DARK_DARK_LIGHT]: isAltSystem(mode)
202
+ });
203
+ }
204
+ if (isSecondary(variant)) {
205
+ return clsx({
206
+ [BG_ACTION_DARK]: isLight(mode),
207
+ [BG_ACTION_LIGHT]: isDark(mode),
208
+ [BG_DARK_DARK_LIGHT]: isSystem(mode),
209
+ [BG_LIGHT_DARK_DARK]: isAltSystem(mode)
210
+ });
211
+ }
212
+ if (isDanger(variant)) {
213
+ return clsx({
214
+ [BG_DANGER_DARK]: isDark(mode),
215
+ [BG_DANGER_LIGHT]: isLight(mode),
216
+ [BG_DANGER_DARK_DARK_LIGHT]: isSystem(mode),
217
+ [BG_DANGER_LIGHT_DARK_DARK]: isAltSystem(mode)
218
+ });
219
+ }
220
+ /* v8 ignore start - selected variant edge case */ if (isSelected(variant)) {
221
+ return "bg-action-selected-dark";
222
+ }
223
+ /* v8 ignore stop */ };
224
+ const getButtonRadiusClasses = ({ radius })=>{
225
+ return clsx({
226
+ "rounded-full": radius === "large",
227
+ "rounded-md": radius === "medium",
228
+ "rounded-xs": radius === "small"
229
+ });
230
+ };
231
+ const getButtonHoverClasses = ({ mode, disabled, variant })=>{
232
+ if (disabled) {
233
+ return "";
234
+ }
235
+ if (isPrimary(variant)) {
236
+ return clsx({
237
+ [HOVER_TEXT_DARK]: isLightOrSystem(mode),
238
+ [HOVER_TEXT_LIGHT]: isDarkOrAltSystem(mode),
239
+ [DARK_HOVER_TEXT_LIGHT]: isSystem(mode),
240
+ [DARK_HOVER_TEXT_DARK]: isAltSystem(mode),
241
+ [HOVER_BG_LIGHT]: isLight(mode),
242
+ [HOVER_BG_DARK]: isDark(mode),
243
+ [HOVER_BG_LIGHT_DARK_DARK]: isSystem(mode),
244
+ [HOVER_BG_DARK_DARK_LIGHT]: isAltSystem(mode)
245
+ });
246
+ }
247
+ if (isSecondary(variant)) {
248
+ return clsx({
249
+ [HOVER_TEXT_LIGHT]: isLightOrSystem(mode),
250
+ [HOVER_TEXT_DARK]: isDarkOrAltSystem(mode),
251
+ [DARK_HOVER_TEXT_DARK]: isSystem(mode),
252
+ [DARK_HOVER_TEXT_LIGHT]: isAltSystem(mode),
253
+ [HOVER_BG_DARK]: isLight(mode),
254
+ [HOVER_BG_LIGHT]: isDark(mode),
255
+ [HOVER_BG_DARK_DARK_LIGHT]: isSystem(mode),
256
+ [HOVER_BG_LIGHT_DARK_DARK]: isAltSystem(mode)
257
+ });
258
+ }
259
+ if (isDanger(variant)) {
260
+ return clsx(HOVER_TEXT_LIGHT, {
261
+ [HOVER_BG_DANGER_DARK]: isDark(mode),
262
+ [HOVER_BG_DANGER_LIGHT]: isLight(mode),
263
+ [HOVER_BG_DANGER_DARK_DARK_LIGHT]: isSystem(mode),
264
+ [HOVER_BG_DANGER_LIGHT_DARK_DARK]: isAltSystem(mode)
265
+ });
266
+ }
267
+ /* v8 ignore start - selected variant edge case */ if (isSelected(variant)) {
268
+ return "hover:text-copy-light-hover hover:bg-action-selected-dark-hover";
269
+ }
270
+ /* v8 ignore stop */ };
271
+ const getButtonActiveClasses = ({ mode, disabled, variant })=>{
272
+ if (disabled) {
273
+ return "";
274
+ }
275
+ if (isPrimary(variant)) {
276
+ return clsx({
277
+ [ACTIVE_TEXT_LIGHT]: isLightOrSystem(mode),
278
+ [ACTIVE_TEXT_MEDIUM]: isDarkOrAltSystem(mode),
279
+ [DARK_ACTIVE_TEXT_MEDIUM]: isSystem(mode),
280
+ [DARK_ACTIVE_TEXT_LIGHT]: isAltSystem(mode),
281
+ [ACTIVE_BG_LIGHT]: isLight(mode),
282
+ [ACTIVE_BG_DARK]: isDark(mode),
283
+ [ACTIVE_BG_LIGHT_DARK_DARK]: isSystem(mode),
284
+ [ACTIVE_BG_DARK_DARK_LIGHT]: isAltSystem(mode)
285
+ });
286
+ }
287
+ if (isSecondary(variant)) {
288
+ return clsx({
289
+ [ACTIVE_TEXT_MEDIUM]: isLightOrSystem(mode),
290
+ [ACTIVE_TEXT_LIGHT]: isDarkOrAltSystem(mode),
291
+ [DARK_ACTIVE_TEXT_LIGHT]: isSystem(mode),
292
+ [DARK_ACTIVE_TEXT_MEDIUM]: isAltSystem(mode),
293
+ [ACTIVE_BG_DARK]: isLight(mode),
294
+ [ACTIVE_BG_LIGHT]: isDark(mode),
295
+ [ACTIVE_BG_DARK_DARK_LIGHT]: isSystem(mode),
296
+ [ACTIVE_BG_LIGHT_DARK_DARK]: isAltSystem(mode)
297
+ });
298
+ }
299
+ if (isDanger(variant)) {
300
+ return clsx(ACTIVE_TEXT_LIGHTER, {
301
+ [ACTIVE_BG_DANGER_DARK]: isDark(mode),
302
+ [ACTIVE_BG_DANGER_LIGHT]: isLight(mode),
303
+ [ACTIVE_BG_DANGER_DARK_DARK_LIGHT]: isSystem(mode),
304
+ [ACTIVE_BG_DANGER_LIGHT_DARK_DARK]: isAltSystem(mode)
305
+ });
306
+ }
307
+ /* v8 ignore start - selected variant edge case */ if (isSelected(variant)) {
308
+ return "active:text-copy-lighter-active active:bg-action-selected-dark-active";
309
+ }
310
+ /* v8 ignore stop */ };
311
+ const getButtonBorderClasses = ({ mode, noBorder, variant })=>{
312
+ if (noBorder) {
313
+ return "border border-transparent";
314
+ }
315
+ if (isPrimary(variant)) {
316
+ return clsx("border", {
317
+ [BORDER_MEDIUM]: isLight(mode),
318
+ [BORDER_ACCENT]: isDark(mode),
319
+ [BORDER_MEDIUM_DARK_ACCENT]: isSystem(mode),
320
+ [BORDER_ACCENT_DARK_MEDIUM]: isAltSystem(mode)
321
+ });
322
+ }
323
+ if (isSecondary(variant)) {
324
+ return clsx("border", {
325
+ [BORDER_ACCENT]: isLight(mode),
326
+ [BORDER_MEDIUM]: isDark(mode),
327
+ [BORDER_ACCENT_DARK_MEDIUM]: isSystem(mode),
328
+ [BORDER_MEDIUM_DARK_ACCENT]: isAltSystem(mode)
329
+ });
330
+ }
331
+ if (isDanger(variant)) {
332
+ return clsx("border", {
333
+ [BORDER_DANGER_DARK]: isDark(mode),
334
+ [BORDER_DANGER_MEDIUM]: isLight(mode),
335
+ [BORDER_DANGER_DARK_DARK_MEDIUM]: isSystem(mode),
336
+ [BORDER_DANGER_MEDIUM_DARK_DARK]: isAltSystem(mode)
337
+ });
338
+ }
339
+ /* v8 ignore start - selected variant edge case */ if (isSelected(variant)) {
340
+ return "border border-border-selected-dark";
341
+ }
342
+ /* v8 ignore stop */ };
343
+ const getButtonFocusClasses = ({ focusMode })=>{
344
+ return clsx("focus:outline-2 focus:outline-offset-2", {
345
+ [FOCUS_DARK]: isDark(focusMode),
346
+ [FOCUS_LIGHT]: isLight(focusMode),
347
+ [FOCUS_LIGHT_DARK_DARK]: isAltSystem(focusMode),
348
+ [FOCUS_DARK_DARK_LIGHT]: isSystem(focusMode)
349
+ });
350
+ };
351
+ const getIconClasses = ({ mode, raw, iconClassName, variant = "primary" })=>{
352
+ if (raw) {
353
+ return "";
354
+ }
355
+ let textColorClasses = {};
356
+ if (isPrimary(variant)) {
357
+ textColorClasses = {
358
+ [TEXT_COPY_DARK]: isLightOrSystem(mode),
359
+ [TEXT_COPY_LIGHT]: isDarkOrAltSystem(mode),
360
+ [DARK_TEXT_COPY_LIGHT]: isSystem(mode),
361
+ [DARK_TEXT_COPY_DARK]: isAltSystem(mode)
362
+ };
363
+ } else if (isSecondary(variant)) {
364
+ textColorClasses = {
365
+ [TEXT_COPY_LIGHT]: isLightOrSystem(mode),
366
+ [TEXT_COPY_DARK]: isDarkOrAltSystem(mode),
367
+ [DARK_TEXT_COPY_DARK]: isSystem(mode),
368
+ [DARK_TEXT_COPY_LIGHT]: isAltSystem(mode)
369
+ };
370
+ } else if (isDanger(variant)) {
371
+ textColorClasses = {
372
+ [TEXT_COPY_LIGHT]: mode === "dark" || mode === "system",
373
+ [TEXT_COPY_LIGHTER]: mode === "light" || mode === "alt-system",
374
+ [DARK_TEXT_COPY_LIGHTER]: isSystem(mode),
375
+ [DARK_TEXT_COPY_LIGHT]: isAltSystem(mode)
376
+ };
377
+ }
378
+ /* v8 ignore start - selected variant edge case */ if (isSelected(variant)) {
379
+ textColorClasses = {
380
+ [TEXT_COPY_LIGHTER]: true
381
+ };
382
+ }
383
+ /* v8 ignore stop */ return clsx(textColorClasses, iconClassName);
384
+ };
385
+ const getButtonIconLabelClasses = ({ animated })=>{
386
+ return clsx({
387
+ "transition-opacity duration-300 ease-in-out": animated
388
+ });
389
+ };
390
+ const getBadgeClasses = ({ size, badge })=>{
391
+ if (badge === undefined || badge === false || badge === 0) {
392
+ return null;
393
+ }
394
+ const isNumber = typeof badge === "number";
395
+ const displayValue = isNumber ? badge > 99 ? "99+" : String(badge) : null;
396
+ const baseClasses = clsx("absolute inline-flex items-center justify-center", "border border-border-white", "rounded-full", TEXT_COPY_LIGHTER, "bg-copy-error-dark", "pointer-events-none");
397
+ const sizeClasses = clsx({
398
+ "size-2 -top-0.5 right-0": !isNumber && isSmall(size),
399
+ "size-2.5 -top-0.5 right-0": !isNumber && isMedium(size),
400
+ "size-3 -top-0.5 right-1": !isNumber && isLarge(size),
401
+ "min-w-3 h-3 text-[8px] px-1 -top-1.5 -right-1.5": isNumber && isSmall(size) && badge < 10,
402
+ "min-w-3 h-3 text-[8px] px-1 -top-1.5 -right-2": isNumber && isSmall(size) && badge >= 10 && badge <= 99,
403
+ "min-w-3 h-3 text-[8px] px-1 -top-1.5 -right-3": isNumber && isSmall(size) && badge > 99,
404
+ "min-w-4 h-4 text-[10px] px-1 -top-1.5 -right-0.5": isNumber && isMedium(size) && badge < 10,
405
+ "min-w-4 h-4 text-[10px] px-1 -top-1.5 -right-2": isNumber && isMedium(size) && badge >= 10 && badge <= 99,
406
+ "min-w-4 h-4 text-[10px] px-1 -top-1.5 -right-3": isNumber && isMedium(size) && badge > 99,
407
+ "min-w-5 h-5 text-xs px-1 -top-1 -right-1": isNumber && isLarge(size) && badge < 10,
408
+ "min-w-5 h-5 text-xs px-1 -top-1 -right-2": isNumber && isLarge(size) && badge >= 10 && badge <= 99,
409
+ "min-w-5 h-5 text-xs px-1 -top-1 -right-3": isNumber && isLarge(size) && badge > 99
410
+ });
411
+ return {
412
+ className: clsx(baseClasses, sizeClasses),
413
+ displayValue
414
+ };
415
+ };
416
+ const getButtonClasses = ({ type, className, raw, mode, focusMode, disabled, fullWidth, size, noBorder, labelRight, labelLeft, noBackground, variant, truncate, align, radius, animated, badge })=>{
417
+ if (!variant) {
418
+ variant = "primary";
419
+ }
420
+ const hasBadge = badge !== undefined && badge !== false && badge !== 0;
421
+ return raw ? clsx(BUTTON_CLASSNAME, className) : clsx(BUTTON_CLASSNAME, getButtonTextCopyClasses({
422
+ mode,
423
+ variant,
424
+ noBackground,
425
+ truncate
426
+ }), getButtonBackgroundClasses({
427
+ mode,
428
+ noBackground,
429
+ variant
430
+ }), getButtonRadiusClasses({
431
+ radius
432
+ }), getButtonSizesClasses({
433
+ type,
434
+ size,
435
+ labelRight,
436
+ labelLeft,
437
+ align,
438
+ animated
439
+ }), getButtonFontClasses({
440
+ type,
441
+ size,
442
+ labelRight,
443
+ labelLeft
444
+ }), getButtonBorderClasses({
445
+ mode,
446
+ variant,
447
+ noBorder
448
+ }), getButtonFocusClasses({
449
+ focusMode
450
+ }), getButtonHoverClasses({
451
+ mode,
452
+ variant,
453
+ disabled
454
+ }), getButtonActiveClasses({
455
+ mode,
456
+ variant,
457
+ disabled
458
+ }), {
459
+ "w-full": fullWidth,
460
+ "disabled:cursor-not-allowed disabled:opacity-50": disabled,
461
+ "cursor-pointer": !disabled,
462
+ relative: hasBadge
463
+ }, clsx({
464
+ "transition-[width] duration-300 ease-in": type === TYPE_ICON && animated
465
+ }), className);
466
+ };
467
+
468
+ export { TYPE_BUTTON, TYPE_ICON, TYPE_LINK, clsx, getBadgeClasses, getButtonClasses, getButtonIconLabelClasses, getIconClasses };
469
+ export { jsx, jsxs } from "react/jsx-runtime";
package/dist/370.js ADDED
@@ -0,0 +1,219 @@
1
+ /*!
2
+ @versini/ui-button v11.3.5
3
+ © 2026 gizmette.com
4
+ */
5
+
6
+ import { useMergeRefs } from "@versini/ui-hooks/use-merge-refs";
7
+ import { useResizeObserver } from "@versini/ui-hooks/use-resize-observer";
8
+ import { jsxs, getButtonClasses, getIconClasses, getButtonIconLabelClasses, TYPE_ICON, getBadgeClasses, jsx } from "./188.js";
9
+ import { useLayoutEffect, useRef, useEffect, BaseButton_private } from "./795.js";
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+ const WIDTH = {
20
+ small: 24,
21
+ medium: 32,
22
+ large: 48
23
+ };
24
+ const PADDINGS = {
25
+ small: 8 * 2,
26
+ medium: 12 * 2,
27
+ large: 16 * 2
28
+ };
29
+ const BORDERS = 2; // border x 2
30
+ const ANIMATION_DURATION = 300; // ms - should match the CSS transition duration
31
+ function ButtonIcon({ children, disabled = false, mode = "system", focusMode = "system", fullWidth = false, className, type = "button", raw = false, noBorder = false, "aria-label": ariaLabel, label, size = "medium", labelRight, labelLeft, noBackground = false, align = "center", radius = "large", variant = "secondary", iconClassName, animated = false, badge, ref, ...otherProps }) {
32
+ const buttonClass = getButtonClasses({
33
+ type: TYPE_ICON,
34
+ mode,
35
+ focusMode,
36
+ fullWidth,
37
+ disabled,
38
+ raw,
39
+ className,
40
+ noBorder,
41
+ size,
42
+ labelRight,
43
+ labelLeft,
44
+ noBackground,
45
+ align,
46
+ radius,
47
+ variant,
48
+ animated,
49
+ badge
50
+ });
51
+ const iconClass = getIconClasses({
52
+ mode,
53
+ raw,
54
+ iconClassName,
55
+ variant
56
+ });
57
+ const labelClass = getButtonIconLabelClasses({
58
+ animated
59
+ });
60
+ // Create a combined class for the button content wrapper
61
+ const contentWrapperClass = "flex items-center justify-center relative w-full h-full overflow-hidden";
62
+ const [labelRightRef, rectR] = useResizeObserver();
63
+ const [labelLeftRef, rectL] = useResizeObserver();
64
+ const [iconRef, rectIcon] = useResizeObserver();
65
+ const bufferRef = useRef(0);
66
+ const buttonRef = useRef(null);
67
+ const timeoutRef = useRef(null);
68
+ const mergedRef = useMergeRefs([
69
+ ref,
70
+ buttonRef
71
+ ]);
72
+ /**
73
+ * Effect to calculate the buffer to add to the width of the button to
74
+ * account for the icon, paddings and borders.
75
+ */ useLayoutEffect(()=>{
76
+ /* v8 ignore start */ if (iconRef && iconRef.current && animated) {
77
+ bufferRef.current = rectIcon.width + PADDINGS[size] + (noBorder ? 0 : BORDERS);
78
+ // Set initial button width if it hasn't been set yet
79
+ if (buttonRef.current && !buttonRef.current.style.width) {
80
+ buttonRef.current.style.width = `${WIDTH[size]}px`;
81
+ }
82
+ }
83
+ /* v8 ignore stop */ }, [
84
+ rectIcon,
85
+ iconRef,
86
+ size,
87
+ noBorder,
88
+ animated
89
+ ]);
90
+ /**
91
+ * Effect to update the width of the button based on the visibility of
92
+ * the right and left labels.
93
+ */ useLayoutEffect(()=>{
94
+ /* v8 ignore start */ if (buttonRef && buttonRef.current && animated) {
95
+ // Calculate the target width first
96
+ let newWidth = WIDTH[size];
97
+ if (labelRight && labelRightRef && rectR.width > 0) {
98
+ newWidth = rectR.width + bufferRef.current;
99
+ } else if (labelLeft && labelLeftRef && rectL.width > 0) {
100
+ newWidth = rectL.width + bufferRef.current;
101
+ }
102
+ // Clear any existing timeout to prevent race conditions
103
+ if (timeoutRef.current) {
104
+ clearTimeout(timeoutRef.current);
105
+ }
106
+ // Start transition - expand button first
107
+ if (newWidth !== parseInt(buttonRef.current.style.width || "0", 10)) {
108
+ // Make sure labels are hidden during width transition
109
+ if (labelRightRef.current) {
110
+ labelRightRef.current.style.opacity = "0";
111
+ }
112
+ if (labelLeftRef.current) {
113
+ labelLeftRef.current.style.opacity = "0";
114
+ }
115
+ // Set the width to trigger the transition
116
+ buttonRef.current.style.width = `${newWidth}px`;
117
+ // After button width transition completes, show the label
118
+ if (newWidth > WIDTH[size]) {
119
+ timeoutRef.current = setTimeout(()=>{
120
+ if (labelRightRef.current && labelRight) {
121
+ labelRightRef.current.style.opacity = "1";
122
+ }
123
+ if (labelLeftRef.current && labelLeft) {
124
+ labelLeftRef.current.style.opacity = "1";
125
+ }
126
+ timeoutRef.current = null;
127
+ }, ANIMATION_DURATION * 0.8); // Wait for most of the width transition to complete
128
+ }
129
+ }
130
+ // If transitioning to icon-only state, hide labels immediately
131
+ if (newWidth === WIDTH[size]) {
132
+ if (labelRightRef.current) {
133
+ labelRightRef.current.style.opacity = "0";
134
+ }
135
+ if (labelLeftRef.current) {
136
+ labelLeftRef.current.style.opacity = "0";
137
+ }
138
+ }
139
+ }
140
+ /* v8 ignore stop */ }, [
141
+ rectR,
142
+ labelRight,
143
+ labelRightRef,
144
+ rectL,
145
+ labelLeft,
146
+ labelLeftRef,
147
+ size,
148
+ animated
149
+ ]);
150
+ // Clean up timeout on unmount
151
+ /* v8 ignore start */ useEffect(()=>{
152
+ return ()=>{
153
+ if (timeoutRef.current) {
154
+ clearTimeout(timeoutRef.current);
155
+ }
156
+ };
157
+ }, []);
158
+ /* v8 ignore stop */ const badgeInfo = getBadgeClasses({
159
+ size,
160
+ badge
161
+ });
162
+ return /*#__PURE__*/ jsxs(BaseButton_private, {
163
+ ref: mergedRef,
164
+ className: buttonClass,
165
+ disabled: disabled,
166
+ type: type,
167
+ "aria-label": ariaLabel || label,
168
+ ...otherProps,
169
+ children: [
170
+ /*#__PURE__*/ jsxs("div", {
171
+ className: contentWrapperClass,
172
+ children: [
173
+ /*#__PURE__*/ jsx(ButtonLabel, {
174
+ label: labelLeft,
175
+ labelRef: labelLeftRef,
176
+ labelClass: labelClass,
177
+ labelInnerClass: "pr-2",
178
+ initiallyHidden: animated
179
+ }),
180
+ /*#__PURE__*/ jsx("span", {
181
+ ref: iconRef,
182
+ className: iconClass,
183
+ children: children
184
+ }),
185
+ /*#__PURE__*/ jsx(ButtonLabel, {
186
+ label: labelRight,
187
+ labelRef: labelRightRef,
188
+ labelClass: labelClass,
189
+ labelInnerClass: "pl-2",
190
+ initiallyHidden: animated
191
+ })
192
+ ]
193
+ }),
194
+ badgeInfo && /*#__PURE__*/ jsx("span", {
195
+ className: badgeInfo.className,
196
+ "aria-hidden": "true",
197
+ children: badgeInfo.displayValue
198
+ })
199
+ ]
200
+ });
201
+ }
202
+ const ButtonLabel = ({ labelRef, labelClass, label, labelInnerClass, initiallyHidden = false })=>{
203
+ if (!label && !initiallyHidden) {
204
+ return null;
205
+ }
206
+ return /*#__PURE__*/ jsx("span", {
207
+ ref: labelRef,
208
+ className: labelClass,
209
+ style: initiallyHidden ? {
210
+ opacity: 0
211
+ } : undefined,
212
+ children: label && /*#__PURE__*/ jsx("span", {
213
+ className: labelInnerClass,
214
+ children: label
215
+ })
216
+ });
217
+ };
218
+
219
+ export { ButtonIcon };