@freightos/freightwind 1.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/cjs/components/alert.js +33 -16
- package/dist/cjs/components/avatar.js +53 -58
- package/dist/cjs/components/badge.js +42 -18
- package/dist/cjs/components/button.js +35 -24
- package/dist/cjs/components/checkbox.js +21 -3
- package/dist/cjs/components/chip.js +67 -9
- package/dist/cjs/components/message.js +38 -0
- package/dist/cjs/components/pop-confirm.js +86 -0
- package/dist/cjs/components/radio-button-group.js +31 -35
- package/dist/cjs/components/radio-group.js +2 -1
- package/dist/cjs/components/slider.js +14 -6
- package/dist/cjs/components/switch.js +29 -10
- package/dist/cjs/components/tooltip.js +40 -11
- package/dist/cjs/index.js +38 -84
- package/dist/cjs/lib/icon-utils.js +5 -0
- package/dist/cjs/{components/aspect-ratio.js → lib/use-stable-id.js} +7 -4
- package/dist/cjs/lib/utils.js +18 -1
- package/dist/esm/components/alert.js +34 -17
- package/dist/esm/components/avatar.js +53 -22
- package/dist/esm/components/badge.js +45 -19
- package/dist/esm/components/button.js +36 -25
- package/dist/esm/components/checkbox.js +22 -4
- package/dist/esm/components/chip.js +34 -9
- package/dist/esm/components/message.js +34 -0
- package/dist/esm/components/pop-confirm.js +51 -0
- package/dist/esm/components/radio-button-group.js +31 -33
- package/dist/esm/components/radio-group.js +2 -1
- package/dist/esm/components/slider.js +14 -6
- package/dist/esm/components/switch.js +30 -11
- package/dist/esm/components/tooltip.js +40 -7
- package/dist/esm/index.js +18 -66
- package/dist/esm/lib/icon-utils.js +1 -0
- package/dist/esm/lib/use-stable-id.js +6 -0
- package/dist/esm/lib/utils.js +18 -1
- package/dist/types/components/alert.d.ts +5 -5
- package/dist/types/components/avatar.d.ts +14 -19
- package/dist/types/components/badge.d.ts +22 -8
- package/dist/types/components/button.d.ts +15 -9
- package/dist/types/components/checkbox.d.ts +8 -2
- package/dist/types/components/chip.d.ts +14 -8
- package/dist/types/components/message.d.ts +14 -0
- package/dist/types/components/pop-confirm.d.ts +28 -0
- package/dist/types/components/radio-button-group.d.ts +19 -14
- package/dist/types/components/slider.d.ts +10 -2
- package/dist/types/components/switch.d.ts +7 -6
- package/dist/types/components/tooltip.d.ts +9 -6
- package/dist/types/index.d.ts +25 -61
- package/dist/types/lib/icon-utils.d.ts +1 -0
- package/dist/types/lib/use-stable-id.d.ts +1 -0
- package/package.json +62 -54
- package/tokens.css +387 -0
- package/dist/cjs/components/accordion.js +0 -57
- package/dist/cjs/components/breadcrumb.js +0 -65
- package/dist/cjs/components/calendar.js +0 -106
- package/dist/cjs/components/card.js +0 -59
- package/dist/cjs/components/chart.js +0 -176
- package/dist/cjs/components/collapsible.js +0 -43
- package/dist/cjs/components/command.js +0 -73
- package/dist/cjs/components/context-menu.js +0 -83
- package/dist/cjs/components/country-select.js +0 -155
- package/dist/cjs/components/date-picker.js +0 -59
- package/dist/cjs/components/date-range-picker.js +0 -59
- package/dist/cjs/components/date-time-picker.js +0 -106
- package/dist/cjs/components/dialog.js +0 -70
- package/dist/cjs/components/drawer.js +0 -68
- package/dist/cjs/components/dropdown-menu.js +0 -85
- package/dist/cjs/components/empty.js +0 -42
- package/dist/cjs/components/file-preview.js +0 -73
- package/dist/cjs/components/form.js +0 -106
- package/dist/cjs/components/inline-edit.js +0 -83
- package/dist/cjs/components/input-group.js +0 -70
- package/dist/cjs/components/input-otp.js +0 -58
- package/dist/cjs/components/input.js +0 -57
- package/dist/cjs/components/label.js +0 -45
- package/dist/cjs/components/menubar.js +0 -96
- package/dist/cjs/components/navigation-menu.js +0 -68
- package/dist/cjs/components/pagination.js +0 -65
- package/dist/cjs/components/phone-input.js +0 -218
- package/dist/cjs/components/popover.js +0 -49
- package/dist/cjs/components/progress.js +0 -43
- package/dist/cjs/components/resizable.js +0 -47
- package/dist/cjs/components/rich-text-editor.js +0 -152
- package/dist/cjs/components/route.js +0 -47
- package/dist/cjs/components/scroll-area.js +0 -48
- package/dist/cjs/components/select.js +0 -71
- package/dist/cjs/components/separator.js +0 -43
- package/dist/cjs/components/sheet.js +0 -245
- package/dist/cjs/components/skeleton.js +0 -8
- package/dist/cjs/components/sonner.js +0 -25
- package/dist/cjs/components/spinner.js +0 -25
- package/dist/cjs/components/stepper.js +0 -99
- package/dist/cjs/components/steps.js +0 -127
- package/dist/cjs/components/table.js +0 -66
- package/dist/cjs/components/tabs.js +0 -51
- package/dist/cjs/components/textarea.js +0 -44
- package/dist/cjs/components/time-picker.js +0 -110
- package/dist/cjs/components/toast.js +0 -75
- package/dist/cjs/components/toaster.js +0 -12
- package/dist/cjs/components/toggle-group.js +0 -58
- package/dist/cjs/components/toggle.js +0 -62
- package/dist/cjs/hooks/use-toast.js +0 -166
- package/dist/cjs/lib/countryUtils.js +0 -93
- package/dist/esm/components/accordion.js +0 -18
- package/dist/esm/components/aspect-ratio.js +0 -3
- package/dist/esm/components/breadcrumb.js +0 -23
- package/dist/esm/components/calendar.js +0 -70
- package/dist/esm/components/card.js +0 -18
- package/dist/esm/components/chart.js +0 -135
- package/dist/esm/components/collapsible.js +0 -5
- package/dist/esm/components/command.js +0 -29
- package/dist/esm/components/context-menu.js +0 -33
- package/dist/esm/components/country-select.js +0 -118
- package/dist/esm/components/date-picker.js +0 -23
- package/dist/esm/components/date-range-picker.js +0 -23
- package/dist/esm/components/date-time-picker.js +0 -70
- package/dist/esm/components/dialog.js +0 -24
- package/dist/esm/components/drawer.js +0 -23
- package/dist/esm/components/dropdown-menu.js +0 -35
- package/dist/esm/components/empty.js +0 -6
- package/dist/esm/components/file-preview.js +0 -69
- package/dist/esm/components/form.js +0 -63
- package/dist/esm/components/inline-edit.js +0 -47
- package/dist/esm/components/input-group.js +0 -63
- package/dist/esm/components/input-otp.js +0 -19
- package/dist/esm/components/input.js +0 -21
- package/dist/esm/components/label.js +0 -9
- package/dist/esm/components/menubar.js +0 -45
- package/dist/esm/components/navigation-menu.js +0 -24
- package/dist/esm/components/pagination.js +0 -23
- package/dist/esm/components/phone-input.js +0 -181
- package/dist/esm/components/popover.js +0 -10
- package/dist/esm/components/progress.js +0 -7
- package/dist/esm/components/resizable.js +0 -9
- package/dist/esm/components/rich-text-editor.js +0 -145
- package/dist/esm/components/route.js +0 -11
- package/dist/esm/components/scroll-area.js +0 -11
- package/dist/esm/components/select.js +0 -26
- package/dist/esm/components/separator.js +0 -7
- package/dist/esm/components/sheet.js +0 -197
- package/dist/esm/components/skeleton.js +0 -6
- package/dist/esm/components/sonner.js +0 -22
- package/dist/esm/components/spinner.js +0 -21
- package/dist/esm/components/stepper.js +0 -57
- package/dist/esm/components/steps.js +0 -80
- package/dist/esm/components/table.js +0 -22
- package/dist/esm/components/tabs.js +0 -12
- package/dist/esm/components/textarea.js +0 -8
- package/dist/esm/components/time-picker.js +0 -74
- package/dist/esm/components/toast.js +0 -33
- package/dist/esm/components/toaster.js +0 -9
- package/dist/esm/components/toggle-group.js +0 -21
- package/dist/esm/components/toggle.js +0 -25
- package/dist/esm/hooks/use-toast.js +0 -128
- package/dist/esm/lib/countryUtils.js +0 -87
- package/dist/styles.css +0 -152
- package/dist/types/components/accordion.d.ts +0 -11
- package/dist/types/components/aspect-ratio.d.ts +0 -3
- package/dist/types/components/breadcrumb.d.ts +0 -19
- package/dist/types/components/calendar.d.ts +0 -7
- package/dist/types/components/card.d.ts +0 -11
- package/dist/types/components/chart.d.ts +0 -66
- package/dist/types/components/collapsible.d.ts +0 -5
- package/dist/types/components/command.d.ts +0 -80
- package/dist/types/components/context-menu.d.ts +0 -27
- package/dist/types/components/country-select.d.ts +0 -17
- package/dist/types/components/date-picker.d.ts +0 -9
- package/dist/types/components/date-range-picker.d.ts +0 -10
- package/dist/types/components/date-time-picker.d.ts +0 -10
- package/dist/types/components/dialog.d.ts +0 -23
- package/dist/types/components/drawer.d.ts +0 -22
- package/dist/types/components/dropdown-menu.d.ts +0 -27
- package/dist/types/components/empty.d.ts +0 -6
- package/dist/types/components/file-preview.d.ts +0 -9
- package/dist/types/components/form.d.ts +0 -23
- package/dist/types/components/inline-edit.d.ts +0 -10
- package/dist/types/components/input-group.d.ts +0 -16
- package/dist/types/components/input-otp.d.ts +0 -34
- package/dist/types/components/input.d.ts +0 -9
- package/dist/types/components/label.d.ts +0 -5
- package/dist/types/components/menubar.d.ts +0 -28
- package/dist/types/components/navigation-menu.d.ts +0 -12
- package/dist/types/components/pagination.d.ts +0 -29
- package/dist/types/components/phone-input.d.ts +0 -20
- package/dist/types/components/popover.d.ts +0 -9
- package/dist/types/components/progress.d.ts +0 -4
- package/dist/types/components/resizable.d.ts +0 -23
- package/dist/types/components/rich-text-editor.d.ts +0 -8
- package/dist/types/components/route.d.ts +0 -10
- package/dist/types/components/scroll-area.d.ts +0 -5
- package/dist/types/components/select.d.ts +0 -13
- package/dist/types/components/separator.d.ts +0 -4
- package/dist/types/components/sheet.d.ts +0 -49
- package/dist/types/components/skeleton.d.ts +0 -2
- package/dist/types/components/sonner.d.ts +0 -4
- package/dist/types/components/spinner.d.ts +0 -8
- package/dist/types/components/stepper.d.ts +0 -17
- package/dist/types/components/steps.d.ts +0 -64
- package/dist/types/components/table.d.ts +0 -14
- package/dist/types/components/tabs.d.ts +0 -7
- package/dist/types/components/textarea.d.ts +0 -3
- package/dist/types/components/time-picker.d.ts +0 -10
- package/dist/types/components/toast.d.ts +0 -15
- package/dist/types/components/toaster.d.ts +0 -1
- package/dist/types/components/toggle-group.d.ts +0 -12
- package/dist/types/components/toggle.d.ts +0 -12
- package/dist/types/hooks/use-toast.d.ts +0 -44
- package/dist/types/lib/countryUtils.d.ts +0 -20
- package/tailwind-preset.js +0 -70
|
@@ -1,37 +1,68 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
3
|
+
import { IconUser } from '@freightos/icons';
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
|
-
import
|
|
6
|
-
const
|
|
5
|
+
import { iconMap } from '../lib/icon-utils';
|
|
6
|
+
const FLAGS_BASE_URL = 'https://freightwind.freightos.com/flags/1x1';
|
|
7
|
+
// --- Component ---
|
|
8
|
+
const avatarVariants = cva('relative flex shrink-0 items-center justify-center overflow-hidden rounded-full', {
|
|
7
9
|
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-fds-purple-2 text-fds-purple-1',
|
|
12
|
+
info: 'bg-fds-blue-20 text-fds-blue-40',
|
|
13
|
+
secondary: 'bg-fds-blue-10 text-fds-blue-40',
|
|
14
|
+
warning: 'bg-fds-yellow-20 text-fds-yellow-50',
|
|
15
|
+
neutral: 'bg-fds-gray-20 text-fds-gray-80',
|
|
16
|
+
positive: 'bg-fds-green-20 text-fds-green-40',
|
|
17
|
+
filled: 'bg-white dark:bg-fds-gray-90 text-fds-gray-80',
|
|
18
|
+
ghost: 'bg-transparent text-fds-gray-80',
|
|
19
|
+
},
|
|
8
20
|
size: {
|
|
9
|
-
xs: 'h-[16px] w-[16px]',
|
|
10
|
-
sm: 'h-[24px] w-[24px]',
|
|
11
|
-
md: 'h-[32px] w-[32px]',
|
|
12
|
-
lg: 'h-[40px] w-[40px]',
|
|
13
|
-
xl: 'h-[58px] w-[58px]',
|
|
21
|
+
xs: 'h-[16px] w-[16px] text-fds-xs',
|
|
22
|
+
sm: 'h-[24px] w-[24px] text-fds-sm',
|
|
23
|
+
md: 'h-[32px] w-[32px] text-fds-base',
|
|
24
|
+
lg: 'h-[40px] w-[40px] text-fds-h6',
|
|
25
|
+
xl: 'h-[58px] w-[58px] text-fds-h4',
|
|
14
26
|
},
|
|
15
27
|
bordered: {
|
|
16
|
-
true: 'border
|
|
28
|
+
true: 'border border-fds-gray-20',
|
|
17
29
|
false: '',
|
|
18
30
|
},
|
|
19
31
|
},
|
|
20
32
|
defaultVariants: {
|
|
33
|
+
variant: 'default',
|
|
21
34
|
size: 'md',
|
|
22
35
|
bordered: false,
|
|
23
36
|
},
|
|
24
37
|
});
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
const iconSizeMap = {
|
|
39
|
+
xs: 10,
|
|
40
|
+
sm: 14,
|
|
41
|
+
md: 18,
|
|
42
|
+
lg: 22,
|
|
43
|
+
xl: 28,
|
|
44
|
+
};
|
|
45
|
+
function Avatar({ variant = 'default', size = 'md', bordered = false, icon, title, flag, src, alt, }) {
|
|
46
|
+
const classes = avatarVariants({ variant, size, bordered });
|
|
47
|
+
const iconSize = iconSizeMap[size];
|
|
48
|
+
// Content priority: src > flag > title > icon > default placeholder
|
|
49
|
+
if (src) {
|
|
50
|
+
return (_jsx("div", { className: classes, children: _jsx("img", { src: src, alt: alt ?? '', className: "h-full w-full object-cover" }) }));
|
|
29
51
|
}
|
|
30
|
-
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
if (flag) {
|
|
53
|
+
const flagUrl = `${FLAGS_BASE_URL}/${flag.trim().toLowerCase()}.svg`;
|
|
54
|
+
return (_jsx("div", { className: classes, children: _jsx("img", { src: flagUrl, alt: alt ?? flag.toUpperCase(), className: "h-full w-full object-cover" }) }));
|
|
55
|
+
}
|
|
56
|
+
if (title) {
|
|
57
|
+
return (_jsx("div", { className: classes, role: "img", "aria-label": alt ?? title, children: _jsx("span", { className: "font-fds-semibold leading-none", "aria-hidden": "true", children: title.charAt(0).toUpperCase() }) }));
|
|
58
|
+
}
|
|
59
|
+
if (icon) {
|
|
60
|
+
const IconComp = iconMap[icon];
|
|
61
|
+
if (IconComp) {
|
|
62
|
+
return (_jsx("div", { className: classes, role: "img", "aria-label": alt ?? icon, children: _jsx(IconComp, { size: iconSize }) }));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Default: user icon placeholder
|
|
66
|
+
return (_jsx("div", { className: classes, role: "img", "aria-label": alt ?? 'User avatar', children: _jsx(IconUser, { size: iconSize }) }));
|
|
67
|
+
}
|
|
68
|
+
export { Avatar };
|
|
@@ -1,20 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { cn } from
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../lib/utils';
|
|
4
|
+
const positionClasses = {
|
|
5
|
+
'top-end': '-top-1 -end-1',
|
|
6
|
+
'bottom-end': '-bottom-1 -end-1',
|
|
7
|
+
};
|
|
8
|
+
const statusDotColors = {
|
|
9
|
+
success: 'bg-fds-green-30',
|
|
10
|
+
error: 'bg-fds-red-30',
|
|
11
|
+
default: 'bg-fds-gray-40',
|
|
12
|
+
processing: 'bg-fds-blue-30',
|
|
13
|
+
warning: 'bg-fds-yellow-30',
|
|
14
|
+
};
|
|
15
|
+
const badgeSizeClasses = {
|
|
16
|
+
default: 'min-w-[16px] h-[16px] text-fds-sm px-[3px]',
|
|
17
|
+
large: 'min-w-[20px] h-[20px] text-fds-sm px-[4px]',
|
|
18
|
+
};
|
|
19
|
+
const variantClasses = {
|
|
20
|
+
default: 'bg-fds-red-30 text-white',
|
|
21
|
+
info: 'bg-fds-blue-30 text-white',
|
|
22
|
+
neutral: 'bg-white border border-fds-gray-20 text-fds-gray-80',
|
|
23
|
+
};
|
|
24
|
+
function Badge({ value, size = 'default', variant = 'default', position = 'top-end', status, text, children }) {
|
|
25
|
+
const badgeClasses = cn('inline-flex items-center justify-center rounded-full font-fds-semibold leading-none', badgeSizeClasses[size], variantClasses[variant]);
|
|
26
|
+
const display = typeof value === 'number'
|
|
27
|
+
? (value > 99 ? '99+' : String(value))
|
|
28
|
+
: value;
|
|
29
|
+
const showValue = typeof value === 'string' ? value.length > 0 : (value != null && value > 0);
|
|
30
|
+
// Badge wrapping a child (e.g. icon or button)
|
|
31
|
+
if (children != null && value != null) {
|
|
32
|
+
return (_jsxs("div", { className: "relative inline-flex", children: [children, showValue && (_jsx("span", { className: cn(badgeClasses, 'absolute', positionClasses[position]), children: display }))] }));
|
|
33
|
+
}
|
|
34
|
+
// Standalone badge
|
|
35
|
+
if (value != null) {
|
|
36
|
+
if (!showValue)
|
|
37
|
+
return null;
|
|
38
|
+
return (_jsx("span", { className: badgeClasses, children: display }));
|
|
39
|
+
}
|
|
40
|
+
// Status badge
|
|
41
|
+
if (status) {
|
|
42
|
+
return (_jsxs("span", { className: "inline-flex items-center gap-fds-sm", children: [_jsx("span", { className: cn('h-[6px] w-[6px] rounded-full', statusDotColors[status]) }), text && _jsx("span", { className: "text-fds-base text-fds-gray-80", children: text })] }));
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
19
45
|
}
|
|
20
|
-
export { Badge
|
|
46
|
+
export { Badge };
|
|
@@ -1,39 +1,50 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { cva } from 'class-variance-authority';
|
|
3
4
|
import * as React from 'react';
|
|
5
|
+
import { iconMap } from '../lib/icon-utils';
|
|
4
6
|
import { cn } from '../lib/utils';
|
|
5
|
-
|
|
7
|
+
import { Tooltip } from './tooltip';
|
|
8
|
+
const buttonVariants = cva('inline-flex w-fit items-center justify-center gap-fds-sm whitespace-nowrap rounded-fds-md cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0', {
|
|
6
9
|
variants: {
|
|
7
|
-
|
|
8
|
-
default: 'bg-fds-blue
|
|
9
|
-
secondary: 'bg-fds-white
|
|
10
|
-
tertiary: 'bg-
|
|
11
|
-
|
|
12
|
-
danger: 'bg-fds-red hover:bg-fds-red
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-fds-blue-30 text-fds-white hover:bg-fds-blue-40',
|
|
12
|
+
secondary: 'bg-fds-white border border-fds-blue-30 text-fds-blue-30 hover:bg-fds-blue-10',
|
|
13
|
+
tertiary: 'bg-transparent text-fds-blue-30 hover:bg-fds-blue-10',
|
|
14
|
+
link: 'bg-transparent text-fds-blue-30 hover:text-fds-blue-50',
|
|
15
|
+
danger: 'bg-fds-red-30 text-fds-white hover:bg-fds-red-40',
|
|
16
|
+
'danger-ghost': 'bg-fds-white border border-fds-red-30 text-fds-red-30 hover:bg-fds-red-10',
|
|
17
|
+
toggle: 'bg-fds-white border border-fds-gray-30 text-fds-gray-80 hover:border-fds-blue-30 hover:text-fds-blue-30',
|
|
13
18
|
},
|
|
14
19
|
size: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
padding: {
|
|
20
|
-
default: 'px-fds-lg',
|
|
21
|
-
small: 'px-fds-md',
|
|
22
|
-
large: 'px-fds-xl',
|
|
20
|
+
sm: 'h-[var(--fds-size-lg)] px-fds-md text-fds-sm [&_svg]:size-3',
|
|
21
|
+
md: 'h-[var(--fds-size-xl)] px-fds-lg text-fds-base [&_svg]:size-4',
|
|
22
|
+
lg: 'h-[var(--fds-size-xxl)] px-fds-xl text-fds-base [&_svg]:size-4',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
25
|
defaultVariants: {
|
|
26
|
-
|
|
27
|
-
size: '
|
|
28
|
-
padding: 'default',
|
|
26
|
+
variant: 'default',
|
|
27
|
+
size: 'md',
|
|
29
28
|
},
|
|
30
29
|
});
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
30
|
+
function LoadingSpinner() {
|
|
31
|
+
return (_jsx("svg", { className: "animate-spin", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M12 22c5.421 0 10-4.579 10-10h-2c0 4.337-3.663 8-8 8s-8-3.663-8-8c0-4.336 3.663-8 8-8V2C6.579 2 2 6.58 2 12c0 5.421 4.579 10 10 10z", fill: "currentColor" }) }));
|
|
32
|
+
}
|
|
33
|
+
const Button = React.forwardRef(({ variant = 'default', size = 'md', icon, loading = false, active, disabled, tooltip, fullWidth, children, ...props }, ref) => {
|
|
34
|
+
const iconOnly = !!icon && !children && !loading;
|
|
35
|
+
if (process.env.NODE_ENV !== 'production' && iconOnly && !tooltip) {
|
|
36
|
+
console.warn('Button: tooltip is required for icon-only buttons.');
|
|
37
|
+
}
|
|
38
|
+
const IconComp = icon ? iconMap[icon] : null;
|
|
39
|
+
// Icon sizes: with text (sm=12, md=16, lg=16), icon-only (sm=16, md=16, lg=24)
|
|
40
|
+
const iconSize = iconOnly
|
|
41
|
+
? size === 'lg' ? 24 : 16
|
|
42
|
+
: size === 'sm' ? 12 : 16;
|
|
43
|
+
const button = (_jsxs("button", { className: cn(buttonVariants({ variant, size }), variant === 'toggle' && active && 'border-fds-blue-30 text-fds-blue-30 bg-fds-blue-10', iconOnly && '!px-0', iconOnly && size === 'sm' && 'w-[var(--fds-size-lg)]', iconOnly && size === 'md' && 'w-[var(--fds-size-xl)]', iconOnly && size === 'lg' && 'w-[var(--fds-size-xxl)]', fullWidth && 'w-full'), ref: ref, disabled: disabled || loading, "aria-busy": loading || undefined, "aria-label": iconOnly ? tooltip : undefined, "aria-pressed": variant === 'toggle' ? active : undefined, ...props, children: [loading ? _jsx(LoadingSpinner, {}) : IconComp && _jsx(IconComp, { size: iconSize }), children] }));
|
|
44
|
+
if (tooltip) {
|
|
45
|
+
return _jsx(Tooltip, { message: tooltip, children: button });
|
|
46
|
+
}
|
|
47
|
+
return button;
|
|
37
48
|
});
|
|
38
49
|
Button.displayName = 'Button';
|
|
39
50
|
export { Button, buttonVariants };
|
|
@@ -1,8 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
3
4
|
import * as React from 'react';
|
|
4
|
-
import { IconCheck } from '@freightos/icons';
|
|
5
5
|
import { cn } from '../lib/utils';
|
|
6
|
-
|
|
7
|
-
Checkbox
|
|
6
|
+
import { useStableId } from '../lib/use-stable-id';
|
|
7
|
+
const Checkbox = React.forwardRef(({ checked, onCheckedChange, disabled, error, children, }, ref) => {
|
|
8
|
+
const checkboxId = useStableId();
|
|
9
|
+
const [internalChecked, setInternalChecked] = React.useState(false);
|
|
10
|
+
const resolvedChecked = checked !== undefined ? checked : internalChecked;
|
|
11
|
+
const handleCheckedChange = (val) => {
|
|
12
|
+
if (checked === undefined)
|
|
13
|
+
setInternalChecked(val);
|
|
14
|
+
onCheckedChange?.(val);
|
|
15
|
+
};
|
|
16
|
+
const box = (_jsx(CheckboxPrimitive.Root, { ref: ref, id: checkboxId, checked: resolvedChecked, onCheckedChange: handleCheckedChange, disabled: disabled, "aria-invalid": error || undefined, className: cn('peer size-4 shrink-0 rounded-fds-sm border cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', disabled
|
|
17
|
+
? 'cursor-not-allowed bg-fds-gray-10 border-fds-gray-20'
|
|
18
|
+
: error
|
|
19
|
+
? 'border-fds-red-30 bg-fds-red-10 data-[state=checked]:bg-fds-red-30'
|
|
20
|
+
: 'border-fds-gray-30 data-[state=checked]:bg-fds-blue-30 data-[state=checked]:border-fds-blue-30'), children: _jsx(CheckboxPrimitive.Indicator, { className: cn('flex items-center justify-center', disabled ? 'text-fds-gray-60' : error && resolvedChecked !== true ? 'text-fds-red-30' : 'text-fds-white'), children: resolvedChecked === 'indeterminate' ? (_jsx("span", { className: cn('block size-2 rounded-[1px]', disabled ? 'bg-fds-gray-60' : error ? 'bg-fds-red-30' : 'bg-fds-blue-30') })) : (_jsx("svg", { width: "11", height: "9", viewBox: "0 0 11 9", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M3.96757 5.24179L1.53586 2.81007L0 4.3378L3.96742 8.30523L10.7609 1.51176L9.21392 0L3.96757 5.24179Z", fill: "currentColor" }) })) }) }));
|
|
21
|
+
if (!children)
|
|
22
|
+
return box;
|
|
23
|
+
return (_jsxs("div", { className: "flex items-center gap-fds-sm", children: [box, _jsx("label", { htmlFor: checkboxId, className: cn('text-fds-base cursor-pointer select-none', disabled && 'cursor-not-allowed text-fds-gray-60', !disabled && error && 'text-fds-red-30', !disabled && !error && 'text-fds-gray-80 dark:text-fds-gray-10'), children: children })] }));
|
|
24
|
+
});
|
|
25
|
+
Checkbox.displayName = 'Checkbox';
|
|
8
26
|
export { Checkbox };
|
|
@@ -1,22 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { cva } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
3
5
|
import { IconClose } from '@freightos/icons';
|
|
6
|
+
import { iconMap } from '../lib/icon-utils';
|
|
4
7
|
import { cn } from '../lib/utils';
|
|
5
|
-
const chipVariants = cva('inline-flex items-center rounded-full h-5 px-
|
|
8
|
+
const chipVariants = cva('inline-flex items-center rounded-full h-5 px-fds-sm text-fds-sm font-fds-regular transition-colors', {
|
|
6
9
|
variants: {
|
|
7
|
-
|
|
8
|
-
default: 'bg-fds-purple-
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-fds-purple-2 text-fds-purple-1',
|
|
9
12
|
neutral: 'bg-fds-gray-20 text-fds-gray-80',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
info: 'bg-[rgba(225,245,249,1)] text-fds-blue-40',
|
|
14
|
+
highlight: 'bg-[rgba(172,232,240,1)] text-fds-blue-40',
|
|
15
|
+
warning: 'bg-fds-yellow-20 text-fds-yellow-50',
|
|
16
|
+
success: 'bg-fds-green-20 text-fds-green-40',
|
|
17
|
+
notice: 'bg-fds-red-10 text-fds-red-30',
|
|
18
|
+
error: 'bg-fds-red-20 text-fds-red-40',
|
|
13
19
|
},
|
|
14
20
|
},
|
|
15
21
|
defaultVariants: {
|
|
16
|
-
|
|
22
|
+
variant: 'default',
|
|
17
23
|
},
|
|
18
24
|
});
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
const badgeColors = {
|
|
26
|
+
default: 'bg-fds-purple-1 text-fds-white',
|
|
27
|
+
neutral: 'bg-fds-gray-80 text-fds-white',
|
|
28
|
+
info: 'bg-fds-blue-40 text-fds-white',
|
|
29
|
+
highlight: 'bg-fds-blue-40 text-fds-white',
|
|
30
|
+
warning: 'bg-fds-yellow-50 text-fds-white',
|
|
31
|
+
success: 'bg-fds-green-40 text-fds-white',
|
|
32
|
+
notice: 'bg-fds-red-30 text-fds-white',
|
|
33
|
+
error: 'bg-fds-red-40 text-fds-white',
|
|
34
|
+
};
|
|
35
|
+
function Chip({ variant = 'default', icon, closable, onClose, badge, children, }) {
|
|
36
|
+
const [visible, setVisible] = React.useState(true);
|
|
37
|
+
if (!visible)
|
|
38
|
+
return null;
|
|
39
|
+
const handleClose = () => {
|
|
40
|
+
setVisible(false);
|
|
41
|
+
onClose?.();
|
|
42
|
+
};
|
|
43
|
+
const IconComp = icon ? iconMap[icon] : null;
|
|
44
|
+
const iconOnly = !!icon && !children;
|
|
45
|
+
return (_jsxs("div", { className: cn(chipVariants({ variant }), iconOnly && 'justify-center', badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && '!pl-0.5'), children: [badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && (_jsx("span", { className: cn('mr-1 inline-flex items-center justify-center rounded-full min-w-[16px] h-4 px-1 text-[10px] font-fds-semibold leading-none', badgeColors[variant]), children: typeof badge === 'number' && badge > 99 ? '99+' : badge })), IconComp && _jsx(IconComp, { size: 12, className: children ? 'mr-fds-sm' : '' }), children, closable && (_jsx("button", { type: "button", onClick: handleClose, "aria-label": "Remove", className: "ml-fds-sm inline-flex cursor-pointer items-center hover:opacity-70", children: _jsx(IconClose, { size: 10 }) }))] }));
|
|
21
46
|
}
|
|
22
47
|
export { Chip, chipVariants };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { IconCheckCircled, IconInfoCircled, IconNegativeCircled, IconRisk } from "@freightos/icons";
|
|
4
|
+
import { toast, Toaster as Sonner } from "sonner";
|
|
5
|
+
const messageConfig = {
|
|
6
|
+
success: { icon: IconCheckCircled, bg: "bg-[rgba(71,169,110,1)]" },
|
|
7
|
+
info: { icon: IconInfoCircled, bg: "bg-[rgba(32,117,189,1)]" },
|
|
8
|
+
warning: { icon: IconRisk, bg: "bg-[rgba(237,175,7,1)]" },
|
|
9
|
+
error: { icon: IconNegativeCircled, bg: "bg-[rgba(216,39,30,1)]" },
|
|
10
|
+
};
|
|
11
|
+
function MessageToast({ variant, title, onClick, toastId, }) {
|
|
12
|
+
const config = messageConfig[variant];
|
|
13
|
+
const Icon = config.icon;
|
|
14
|
+
const dir = document.documentElement.getAttribute("dir") || "ltr";
|
|
15
|
+
return (_jsxs("div", { dir: dir, className: `mx-auto flex w-fit items-center gap-fds-sm rounded-fds-md p-fds-lg shadow-fds-md text-white font-[family-name:var(--font-open-sans)] ${config.bg} ${onClick ? "cursor-pointer" : ""}`, onClick: onClick ? () => {
|
|
16
|
+
onClick();
|
|
17
|
+
toast.dismiss(toastId);
|
|
18
|
+
} : undefined, children: [_jsx(Icon, { size: 16, className: "shrink-0" }), _jsx("span", { className: "text-fds-h6 font-fds-regular leading-fds-body", children: title })] }));
|
|
19
|
+
}
|
|
20
|
+
function showMessage(variant, title, options) {
|
|
21
|
+
return toast.custom((id) => (_jsx(MessageToast, { variant: variant, title: title, onClick: options?.onClick, toastId: id })), {
|
|
22
|
+
...(options?.duration !== undefined && { duration: options.duration }),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const message = {
|
|
26
|
+
success: (title, options) => showMessage("success", title, options),
|
|
27
|
+
info: (title, options) => showMessage("info", title, options),
|
|
28
|
+
warning: (title, options) => showMessage("warning", title, options),
|
|
29
|
+
error: (title, options) => showMessage("error", title, options),
|
|
30
|
+
};
|
|
31
|
+
const MessageProvider = ({ duration = 3000, ...props }) => {
|
|
32
|
+
return (_jsx(Sonner, { position: "top-center", duration: duration, gap: 8, toastOptions: { style: { left: 0, right: 0 } }, ...props }));
|
|
33
|
+
};
|
|
34
|
+
export { MessageProvider, message };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { Button } from './button';
|
|
6
|
+
import { iconMap } from '../lib/icon-utils';
|
|
7
|
+
function resolvePlacement(placement) {
|
|
8
|
+
const [sideRaw, alignRaw] = placement.split('-');
|
|
9
|
+
const align = alignRaw ?? 'center';
|
|
10
|
+
const isRtl = typeof document !== 'undefined' && document.documentElement.dir === 'rtl';
|
|
11
|
+
const resolveLogical = (value) => (value === 'start') !== isRtl ? 'left' : 'right';
|
|
12
|
+
const side = sideRaw === 'top' || sideRaw === 'bottom'
|
|
13
|
+
? sideRaw
|
|
14
|
+
: resolveLogical(sideRaw);
|
|
15
|
+
const radixAlign = align === 'center'
|
|
16
|
+
? 'center'
|
|
17
|
+
: isRtl
|
|
18
|
+
? align === 'start' ? 'end' : 'start'
|
|
19
|
+
: align;
|
|
20
|
+
return { side, align: radixAlign };
|
|
21
|
+
}
|
|
22
|
+
const ARROW_EDGE_INSET = 10;
|
|
23
|
+
function PopConfirm({ title, onConfirm, onCancel, placement = 'top', children, slotProps, }) {
|
|
24
|
+
const [open, setOpen] = React.useState(false);
|
|
25
|
+
const { side, align } = resolvePlacement(placement);
|
|
26
|
+
const triggerRef = React.useRef(null);
|
|
27
|
+
const [alignOffset, setAlignOffset] = React.useState(0);
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
if (align === 'center' || !triggerRef.current) {
|
|
30
|
+
setAlignOffset(0);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const isHorizontal = side === 'top' || side === 'bottom';
|
|
34
|
+
const triggerSize = isHorizontal
|
|
35
|
+
? triggerRef.current.offsetWidth
|
|
36
|
+
: triggerRef.current.offsetHeight;
|
|
37
|
+
setAlignOffset(ARROW_EDGE_INSET - triggerSize / 2);
|
|
38
|
+
}, [align, side]);
|
|
39
|
+
function handleConfirm() {
|
|
40
|
+
onConfirm();
|
|
41
|
+
setOpen(false);
|
|
42
|
+
}
|
|
43
|
+
function handleCancel() {
|
|
44
|
+
onCancel?.();
|
|
45
|
+
setOpen(false);
|
|
46
|
+
}
|
|
47
|
+
const iconName = slotProps?.icon?.name ?? 'risk';
|
|
48
|
+
const IconComp = iconMap[iconName];
|
|
49
|
+
return (_jsxs(PopoverPrimitive.Root, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, ref: triggerRef, children: children }), _jsx(PopoverPrimitive.Portal, { children: _jsxs(PopoverPrimitive.Content, { side: side, align: align, alignOffset: alignOffset, sideOffset: 8, className: "z-[1300] w-[246px] rounded-fds-lg bg-white p-fds-lg shadow-fds-md origin-[--radix-popover-content-transform-origin] animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", children: [_jsxs("div", { className: "flex gap-fds-xs", children: [IconComp && _jsx(IconComp, { size: 16, color: slotProps?.icon?.color ?? 'yellow-30', className: "mt-[2.5px] shrink-0" }), _jsx("p", { className: "text-fds-base text-fds-gray-100", children: title })] }), _jsxs("div", { className: "mt-[10px] flex justify-end gap-fds-sm", children: [_jsx(Button, { variant: slotProps?.cancelButton?.variant ?? 'secondary', size: "sm", onClick: handleCancel, children: slotProps?.cancelButton?.children ?? 'No' }), _jsx(Button, { variant: slotProps?.confirmButton?.variant ?? 'danger', size: "sm", onClick: handleConfirm, children: slotProps?.confirmButton?.children ?? 'Yes' })] }), _jsx(PopoverPrimitive.Arrow, { className: "fill-white", width: 16, height: 8 })] }) })] }));
|
|
50
|
+
}
|
|
51
|
+
export { PopConfirm };
|
|
@@ -1,47 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { cn } from '../lib/utils';
|
|
4
|
+
import { useStableId } from '../lib/use-stable-id';
|
|
3
5
|
import { cva } from 'class-variance-authority';
|
|
4
6
|
import * as React from 'react';
|
|
5
7
|
import { RadioGroup, RadioGroupItem } from './radio-group';
|
|
6
|
-
const
|
|
8
|
+
const itemVariants = cva('relative flex cursor-pointer items-center justify-center border bg-card transition-all has-[[data-state=checked]]:z-10', {
|
|
7
9
|
variants: {
|
|
8
10
|
size: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
variant: {
|
|
14
|
-
default: 'border-fds-gray-30 text-fds-gray-80 dark:border-fds-gray-60 dark:text-fds-gray-40 has-[[data-state=checked]]:border-fds-blue has-[[data-state=checked]]:bg-fds-blue-10 has-[[data-state=checked]]:text-fds-blue dark:has-[[data-state=checked]]:border-fds-blue-20 dark:has-[[data-state=checked]]:text-fds-blue',
|
|
15
|
-
custom: '', // No default checked styles, allows full customization
|
|
11
|
+
sm: 'h-[24px] text-fds-sm px-fds-md',
|
|
12
|
+
md: 'h-[32px] text-fds-base px-fds-lg',
|
|
13
|
+
lg: 'h-[40px] text-fds-h6 px-fds-xl',
|
|
16
14
|
},
|
|
17
15
|
},
|
|
18
16
|
defaultVariants: {
|
|
19
|
-
size: '
|
|
20
|
-
variant: 'default',
|
|
17
|
+
size: 'md',
|
|
21
18
|
},
|
|
22
19
|
});
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
const defaultColors = 'border-fds-gray-30 text-fds-gray-80 dark:border-fds-gray-60 dark:text-fds-gray-40 has-[[data-state=checked]]:border-fds-blue-30 has-[[data-state=checked]]:bg-fds-blue-10 has-[[data-state=checked]]:text-fds-blue-30 dark:has-[[data-state=checked]]:border-fds-blue-20 dark:has-[[data-state=checked]]:text-fds-blue-30';
|
|
21
|
+
const errorColors = 'border-fds-red-30 bg-fds-red-10 text-fds-red-30 has-[[data-state=checked]]:border-fds-red-30 has-[[data-state=checked]]:bg-fds-red-10 has-[[data-state=checked]]:text-fds-red-30';
|
|
22
|
+
const disabledColors = 'bg-fds-gray-10 border-fds-gray-20 text-fds-gray-60 has-[[data-state=checked]]:bg-fds-gray-20 has-[[data-state=checked]]:border-fds-gray-30 has-[[data-state=checked]]:text-fds-gray-60';
|
|
23
|
+
function RadioButtonGroup({ options, value, defaultValue, onValueChange, size = 'md', orientation = 'horizontal', disabled = false, error = false, }) {
|
|
24
|
+
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
25
|
+
const isControlled = value !== undefined;
|
|
26
|
+
const currentValue = isControlled ? value : internalValue;
|
|
27
|
+
const baseId = useStableId();
|
|
28
|
+
const handleValueChange = (v) => {
|
|
29
|
+
if (!isControlled)
|
|
30
|
+
setInternalValue(v);
|
|
31
|
+
onValueChange?.(v);
|
|
32
|
+
};
|
|
33
|
+
const isVertical = orientation === 'vertical';
|
|
34
|
+
const stateColors = disabled ? disabledColors : error ? errorColors : defaultColors;
|
|
35
|
+
return (_jsx(RadioGroup, { value: currentValue, onValueChange: handleValueChange, disabled: disabled, className: cn('flex', isVertical ? 'flex-col gap-fds-sm' : 'flex-row gap-0', disabled && 'opacity-50 cursor-not-allowed'), children: options.map((option, index) => {
|
|
27
36
|
const isFirst = index === 0;
|
|
28
|
-
const isLast = index ===
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
className: cn(childProps.className, isFirst && roundedStart, isLast && roundedEnd, !isFirst && '-ml-px') || undefined,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
return child;
|
|
39
|
-
});
|
|
40
|
-
return (_jsx(RadioGroup, { ref: ref, className: cn('flex gap-0', className), ...props, children: childrenWithProps }));
|
|
41
|
-
});
|
|
37
|
+
const isLast = index === options.length - 1;
|
|
38
|
+
const optionId = `${baseId}-${option.value}`;
|
|
39
|
+
return (_jsxs("div", { className: cn(itemVariants({ size }), stateColors, option.render && 'h-auto py-fds-sm', isVertical
|
|
40
|
+
? 'rounded-fds-md w-full'
|
|
41
|
+
: cn(isFirst && 'rounded-s-fds-md', isLast && 'rounded-e-fds-md', !isFirst && '-ml-px'), disabled && 'cursor-not-allowed'), children: [_jsx(RadioGroupItem, { id: optionId, value: option.value, className: "sr-only", disabled: disabled }), _jsx("label", { htmlFor: optionId, className: cn('whitespace-nowrap after:absolute after:inset-0', !option.render && 'font-medium', disabled ? 'cursor-not-allowed' : 'cursor-pointer'), style: { color: 'inherit', fontSize: 'inherit' }, children: option.render ? option.render() : option.label })] }, option.value));
|
|
42
|
+
}) }));
|
|
43
|
+
}
|
|
42
44
|
RadioButtonGroup.displayName = 'RadioButtonGroup';
|
|
43
|
-
|
|
44
|
-
return (_jsxs("div", { ref: ref, className: cn(radioButtonGroupItemVariants({ size, variant }), className), ...props, children: [_jsx(RadioGroupItem, { id: id, value: value, className: "sr-only" }), _jsx("label", { htmlFor: id, className: "cursor-pointer whitespace-nowrap font-medium after:absolute after:inset-0", style: { color: 'inherit', fontSize: 'inherit' }, children: children })] }));
|
|
45
|
-
});
|
|
46
|
-
RadioButtonGroupItem.displayName = 'RadioButtonGroupItem';
|
|
47
|
-
export { RadioButtonGroup, RadioButtonGroupItem };
|
|
45
|
+
export { RadioButtonGroup };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
3
4
|
import * as React from 'react';
|
|
@@ -7,7 +8,7 @@ const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
|
|
|
7
8
|
});
|
|
8
9
|
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
|
|
9
10
|
const RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => {
|
|
10
|
-
return (_jsx(RadioGroupPrimitive.Item, { ref: ref, className: cn('
|
|
11
|
+
return (_jsx(RadioGroupPrimitive.Item, { ref: ref, className: cn('h-[16px] w-[16px] cursor-pointer rounded-full border border-fds-gray-30 bg-white ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:border-fds-gray-20 disabled:bg-fds-gray-10 data-[state=checked]:border-fds-blue-30 data-[state=checked]:disabled:border-fds-gray-30', className), ...props, children: _jsx(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: _jsx("div", { className: "h-[8px] w-[8px] rounded-full bg-fds-blue-30 [[disabled]_&]:bg-fds-gray-30" }) }) }));
|
|
11
12
|
});
|
|
12
13
|
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
|
13
14
|
export { RadioGroup, RadioGroupItem };
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cn } from '../lib/utils';
|
|
3
3
|
import * as SliderPrimitive from '@radix-ui/react-slider';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
5
|
+
import { cn } from '../lib/utils';
|
|
6
|
+
const Slider = React.forwardRef(({ value, defaultValue, onValueChange, min = 0, max = 100, step = 1, disabled }, ref) => {
|
|
7
|
+
const [internalValue, setInternalValue] = React.useState(defaultValue ?? [min]);
|
|
8
|
+
const resolvedValue = value !== undefined ? value : internalValue;
|
|
9
|
+
const handleValueChange = (val) => {
|
|
10
|
+
if (value === undefined)
|
|
11
|
+
setInternalValue(val);
|
|
12
|
+
onValueChange?.(val);
|
|
13
|
+
};
|
|
14
|
+
return (_jsxs(SliderPrimitive.Root, { ref: ref, value: resolvedValue, onValueChange: handleValueChange, min: min, max: max, step: step, disabled: disabled, className: "relative flex w-full touch-none select-none items-center", children: [_jsx(SliderPrimitive.Track, { className: "relative h-1 w-full grow overflow-hidden rounded-full bg-fds-gray-20", children: _jsx(SliderPrimitive.Range, { className: cn('absolute h-full', disabled ? 'bg-fds-blue-05' : 'bg-fds-blue-30') }) }), resolvedValue.map((_, i) => (_jsx(SliderPrimitive.Thumb, { className: cn('block h-4 w-4 rounded-full border-2 bg-fds-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2', disabled
|
|
15
|
+
? 'border-fds-blue-05 cursor-not-allowed'
|
|
16
|
+
: 'border-fds-blue-30 focus-visible:ring-fds-blue-20 cursor-pointer') }, i)))] }));
|
|
9
17
|
});
|
|
10
|
-
Slider.displayName =
|
|
18
|
+
Slider.displayName = 'Slider';
|
|
11
19
|
export { Slider };
|
|
@@ -1,30 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as SwitchPrimitives from '@radix-ui/react-switch';
|
|
4
|
+
import * as React from 'react';
|
|
4
5
|
import { cva } from 'class-variance-authority';
|
|
5
6
|
import { cn } from '../lib/utils';
|
|
6
|
-
|
|
7
|
+
import { useStableId } from '../lib/use-stable-id';
|
|
8
|
+
const switchVariants = cva('peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50', {
|
|
7
9
|
variants: {
|
|
8
10
|
size: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
lg: 'h-5 w-9',
|
|
12
|
+
sm: 'h-4 w-8',
|
|
11
13
|
},
|
|
12
14
|
},
|
|
13
15
|
defaultVariants: {
|
|
14
|
-
size: '
|
|
16
|
+
size: 'lg',
|
|
15
17
|
},
|
|
16
18
|
});
|
|
17
19
|
const switchThumbVariants = cva('pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0', {
|
|
18
20
|
variants: {
|
|
19
21
|
size: {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
lg: 'size-4 data-[state=checked]:translate-x-4',
|
|
23
|
+
sm: 'size-3 data-[state=checked]:translate-x-4',
|
|
22
24
|
},
|
|
23
25
|
},
|
|
24
26
|
defaultVariants: {
|
|
25
|
-
size: '
|
|
27
|
+
size: 'lg',
|
|
26
28
|
},
|
|
27
29
|
});
|
|
28
|
-
const Switch = React.forwardRef(({
|
|
29
|
-
|
|
30
|
+
const Switch = React.forwardRef(({ checked, onCheckedChange, disabled, error, size = 'lg', children }, ref) => {
|
|
31
|
+
const switchId = useStableId();
|
|
32
|
+
const [internalChecked, setInternalChecked] = React.useState(false);
|
|
33
|
+
const resolvedChecked = checked !== undefined ? checked : internalChecked;
|
|
34
|
+
const handleCheckedChange = (val) => {
|
|
35
|
+
if (checked === undefined)
|
|
36
|
+
setInternalChecked(val);
|
|
37
|
+
onCheckedChange?.(val);
|
|
38
|
+
};
|
|
39
|
+
const track = (_jsx(SwitchPrimitives.Root, { ref: ref, id: switchId, checked: resolvedChecked, onCheckedChange: handleCheckedChange, disabled: disabled, "aria-invalid": error || undefined, className: cn(switchVariants({ size }), disabled
|
|
40
|
+
? 'data-[state=unchecked]:bg-fds-gray-20 data-[state=checked]:bg-fds-blue-05'
|
|
41
|
+
: error
|
|
42
|
+
? 'data-[state=unchecked]:bg-fds-gray-60 data-[state=checked]:bg-fds-red-30'
|
|
43
|
+
: 'data-[state=unchecked]:bg-fds-gray-60 data-[state=checked]:bg-fds-blue-30'), children: _jsx(SwitchPrimitives.Thumb, { className: cn(switchThumbVariants({ size })) }) }));
|
|
44
|
+
if (!children)
|
|
45
|
+
return track;
|
|
46
|
+
return (_jsxs("div", { className: "flex items-center gap-fds-sm", children: [track, _jsx("label", { htmlFor: switchId, className: cn('text-fds-base cursor-pointer select-none', disabled && 'cursor-not-allowed text-fds-gray-60', !disabled && error && resolvedChecked && 'text-fds-red-30', !disabled && !(error && resolvedChecked) && 'text-fds-gray-80 dark:text-fds-gray-10'), children: children })] }));
|
|
47
|
+
});
|
|
48
|
+
Switch.displayName = 'Switch';
|
|
30
49
|
export { Switch };
|