@freightos/freightwind 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/dist/cjs/components/accordion.js +57 -0
  2. package/dist/cjs/components/alert.js +76 -0
  3. package/dist/cjs/components/aspect-ratio.js +39 -0
  4. package/dist/cjs/components/avatar.js +75 -0
  5. package/dist/cjs/components/badge.js +24 -0
  6. package/dist/cjs/components/breadcrumb.js +65 -0
  7. package/dist/cjs/components/button.js +76 -0
  8. package/dist/cjs/components/calendar.js +106 -0
  9. package/dist/cjs/components/card.js +59 -0
  10. package/dist/cjs/components/chart.js +176 -0
  11. package/dist/cjs/components/checkbox.js +44 -0
  12. package/dist/cjs/components/chip.js +26 -0
  13. package/dist/cjs/components/collapsible.js +43 -0
  14. package/dist/cjs/components/command.js +73 -0
  15. package/dist/cjs/components/context-menu.js +83 -0
  16. package/dist/cjs/components/country-select.js +155 -0
  17. package/dist/cjs/components/date-picker.js +59 -0
  18. package/dist/cjs/components/date-range-picker.js +59 -0
  19. package/dist/cjs/components/date-time-picker.js +106 -0
  20. package/dist/cjs/components/dialog.js +70 -0
  21. package/dist/cjs/components/drawer.js +68 -0
  22. package/dist/cjs/components/dropdown-menu.js +85 -0
  23. package/dist/cjs/components/empty.js +42 -0
  24. package/dist/cjs/components/file-preview.js +73 -0
  25. package/dist/cjs/components/form.js +106 -0
  26. package/dist/cjs/components/inline-edit.js +83 -0
  27. package/dist/cjs/components/input-group.js +70 -0
  28. package/dist/cjs/components/input-otp.js +58 -0
  29. package/dist/cjs/components/input.js +57 -0
  30. package/dist/cjs/components/label.js +45 -0
  31. package/dist/cjs/components/menubar.js +96 -0
  32. package/dist/cjs/components/navigation-menu.js +68 -0
  33. package/dist/cjs/components/pagination.js +65 -0
  34. package/dist/cjs/components/phone-input.js +218 -0
  35. package/dist/cjs/components/popover.js +49 -0
  36. package/dist/cjs/components/progress.js +43 -0
  37. package/dist/cjs/components/radio-button-group.js +84 -0
  38. package/dist/cjs/components/radio-group.js +50 -0
  39. package/dist/cjs/components/resizable.js +47 -0
  40. package/dist/cjs/components/rich-text-editor.js +152 -0
  41. package/dist/cjs/components/route.js +47 -0
  42. package/dist/cjs/components/scroll-area.js +48 -0
  43. package/dist/cjs/components/select.js +71 -0
  44. package/dist/cjs/components/separator.js +43 -0
  45. package/dist/cjs/components/sheet.js +245 -0
  46. package/dist/cjs/components/skeleton.js +8 -0
  47. package/dist/cjs/components/slider.js +47 -0
  48. package/dist/cjs/components/sonner.js +25 -0
  49. package/dist/cjs/components/spinner.js +25 -0
  50. package/dist/cjs/components/stepper.js +99 -0
  51. package/dist/cjs/components/steps.js +127 -0
  52. package/dist/cjs/components/switch.js +66 -0
  53. package/dist/cjs/components/table.js +66 -0
  54. package/dist/cjs/components/tabs.js +51 -0
  55. package/dist/cjs/components/textarea.js +44 -0
  56. package/dist/cjs/components/time-picker.js +110 -0
  57. package/dist/cjs/components/toast.js +75 -0
  58. package/dist/cjs/components/toaster.js +12 -0
  59. package/dist/cjs/components/toggle-group.js +58 -0
  60. package/dist/cjs/components/toggle.js +62 -0
  61. package/dist/cjs/components/tooltip.js +49 -0
  62. package/dist/cjs/hooks/use-toast.js +166 -0
  63. package/dist/cjs/index.js +88 -0
  64. package/dist/cjs/lib/countryUtils.js +93 -0
  65. package/dist/cjs/lib/utils.js +8 -0
  66. package/dist/esm/components/accordion.js +18 -0
  67. package/dist/esm/components/alert.js +39 -0
  68. package/dist/esm/components/aspect-ratio.js +3 -0
  69. package/dist/esm/components/avatar.js +37 -0
  70. package/dist/esm/components/badge.js +20 -0
  71. package/dist/esm/components/breadcrumb.js +23 -0
  72. package/dist/esm/components/button.js +39 -0
  73. package/dist/esm/components/calendar.js +70 -0
  74. package/dist/esm/components/card.js +18 -0
  75. package/dist/esm/components/chart.js +135 -0
  76. package/dist/esm/components/checkbox.js +8 -0
  77. package/dist/esm/components/chip.js +22 -0
  78. package/dist/esm/components/collapsible.js +5 -0
  79. package/dist/esm/components/command.js +29 -0
  80. package/dist/esm/components/context-menu.js +33 -0
  81. package/dist/esm/components/country-select.js +118 -0
  82. package/dist/esm/components/date-picker.js +23 -0
  83. package/dist/esm/components/date-range-picker.js +23 -0
  84. package/dist/esm/components/date-time-picker.js +70 -0
  85. package/dist/esm/components/dialog.js +24 -0
  86. package/dist/esm/components/drawer.js +23 -0
  87. package/dist/esm/components/dropdown-menu.js +35 -0
  88. package/dist/esm/components/empty.js +6 -0
  89. package/dist/esm/components/file-preview.js +69 -0
  90. package/dist/esm/components/form.js +63 -0
  91. package/dist/esm/components/inline-edit.js +47 -0
  92. package/dist/esm/components/input-group.js +63 -0
  93. package/dist/esm/components/input-otp.js +19 -0
  94. package/dist/esm/components/input.js +21 -0
  95. package/dist/esm/components/label.js +9 -0
  96. package/dist/esm/components/menubar.js +45 -0
  97. package/dist/esm/components/navigation-menu.js +24 -0
  98. package/dist/esm/components/pagination.js +23 -0
  99. package/dist/esm/components/phone-input.js +181 -0
  100. package/dist/esm/components/popover.js +10 -0
  101. package/dist/esm/components/progress.js +7 -0
  102. package/dist/esm/components/radio-button-group.js +47 -0
  103. package/dist/esm/components/radio-group.js +13 -0
  104. package/dist/esm/components/resizable.js +9 -0
  105. package/dist/esm/components/rich-text-editor.js +145 -0
  106. package/dist/esm/components/route.js +11 -0
  107. package/dist/esm/components/scroll-area.js +11 -0
  108. package/dist/esm/components/select.js +26 -0
  109. package/dist/esm/components/separator.js +7 -0
  110. package/dist/esm/components/sheet.js +197 -0
  111. package/dist/esm/components/skeleton.js +6 -0
  112. package/dist/esm/components/slider.js +11 -0
  113. package/dist/esm/components/sonner.js +22 -0
  114. package/dist/esm/components/spinner.js +21 -0
  115. package/dist/esm/components/stepper.js +57 -0
  116. package/dist/esm/components/steps.js +80 -0
  117. package/dist/esm/components/switch.js +30 -0
  118. package/dist/esm/components/table.js +22 -0
  119. package/dist/esm/components/tabs.js +12 -0
  120. package/dist/esm/components/textarea.js +8 -0
  121. package/dist/esm/components/time-picker.js +74 -0
  122. package/dist/esm/components/toast.js +33 -0
  123. package/dist/esm/components/toaster.js +9 -0
  124. package/dist/esm/components/toggle-group.js +21 -0
  125. package/dist/esm/components/toggle.js +25 -0
  126. package/dist/esm/components/tooltip.js +10 -0
  127. package/dist/esm/hooks/use-toast.js +128 -0
  128. package/dist/esm/index.js +67 -0
  129. package/dist/esm/lib/countryUtils.js +87 -0
  130. package/dist/esm/lib/utils.js +5 -0
  131. package/dist/styles.css +152 -0
  132. package/dist/types/components/accordion.d.ts +11 -0
  133. package/dist/types/components/alert.d.ts +12 -0
  134. package/dist/types/components/aspect-ratio.d.ts +3 -0
  135. package/dist/types/components/avatar.d.ts +19 -0
  136. package/dist/types/components/badge.d.ts +9 -0
  137. package/dist/types/components/breadcrumb.d.ts +19 -0
  138. package/dist/types/components/button.d.ts +14 -0
  139. package/dist/types/components/calendar.d.ts +7 -0
  140. package/dist/types/components/card.d.ts +11 -0
  141. package/dist/types/components/chart.d.ts +66 -0
  142. package/dist/types/components/checkbox.d.ts +4 -0
  143. package/dist/types/components/chip.d.ts +10 -0
  144. package/dist/types/components/collapsible.d.ts +5 -0
  145. package/dist/types/components/command.d.ts +80 -0
  146. package/dist/types/components/context-menu.d.ts +27 -0
  147. package/dist/types/components/country-select.d.ts +17 -0
  148. package/dist/types/components/date-picker.d.ts +9 -0
  149. package/dist/types/components/date-range-picker.d.ts +10 -0
  150. package/dist/types/components/date-time-picker.d.ts +10 -0
  151. package/dist/types/components/dialog.d.ts +23 -0
  152. package/dist/types/components/drawer.d.ts +22 -0
  153. package/dist/types/components/dropdown-menu.d.ts +27 -0
  154. package/dist/types/components/empty.d.ts +6 -0
  155. package/dist/types/components/file-preview.d.ts +9 -0
  156. package/dist/types/components/form.d.ts +23 -0
  157. package/dist/types/components/inline-edit.d.ts +10 -0
  158. package/dist/types/components/input-group.d.ts +16 -0
  159. package/dist/types/components/input-otp.d.ts +34 -0
  160. package/dist/types/components/input.d.ts +9 -0
  161. package/dist/types/components/label.d.ts +5 -0
  162. package/dist/types/components/menubar.d.ts +28 -0
  163. package/dist/types/components/navigation-menu.d.ts +12 -0
  164. package/dist/types/components/pagination.d.ts +29 -0
  165. package/dist/types/components/phone-input.d.ts +20 -0
  166. package/dist/types/components/popover.d.ts +9 -0
  167. package/dist/types/components/progress.d.ts +4 -0
  168. package/dist/types/components/radio-button-group.d.ts +17 -0
  169. package/dist/types/components/radio-group.d.ts +5 -0
  170. package/dist/types/components/resizable.d.ts +23 -0
  171. package/dist/types/components/rich-text-editor.d.ts +8 -0
  172. package/dist/types/components/route.d.ts +10 -0
  173. package/dist/types/components/scroll-area.d.ts +5 -0
  174. package/dist/types/components/select.d.ts +13 -0
  175. package/dist/types/components/separator.d.ts +4 -0
  176. package/dist/types/components/sheet.d.ts +49 -0
  177. package/dist/types/components/skeleton.d.ts +2 -0
  178. package/dist/types/components/slider.d.ts +4 -0
  179. package/dist/types/components/sonner.d.ts +4 -0
  180. package/dist/types/components/spinner.d.ts +8 -0
  181. package/dist/types/components/stepper.d.ts +17 -0
  182. package/dist/types/components/steps.d.ts +64 -0
  183. package/dist/types/components/switch.d.ts +10 -0
  184. package/dist/types/components/table.d.ts +14 -0
  185. package/dist/types/components/tabs.d.ts +7 -0
  186. package/dist/types/components/textarea.d.ts +3 -0
  187. package/dist/types/components/time-picker.d.ts +10 -0
  188. package/dist/types/components/toast.d.ts +15 -0
  189. package/dist/types/components/toaster.d.ts +1 -0
  190. package/dist/types/components/toggle-group.d.ts +12 -0
  191. package/dist/types/components/toggle.d.ts +12 -0
  192. package/dist/types/components/tooltip.d.ts +7 -0
  193. package/dist/types/hooks/use-toast.d.ts +44 -0
  194. package/dist/types/index.d.ts +62 -0
  195. package/dist/types/lib/countryUtils.d.ts +20 -0
  196. package/dist/types/lib/utils.d.ts +2 -0
  197. package/package.json +84 -0
  198. package/tailwind-preset.js +70 -0
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import * as SwitchPrimitives from '@radix-ui/react-switch';
4
+ import { cva } from 'class-variance-authority';
5
+ import { cn } from '../lib/utils';
6
+ 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 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-fds-blue data-[state=unchecked]:bg-fds-gray-30', {
7
+ variants: {
8
+ size: {
9
+ default: 'h-5 w-9',
10
+ small: 'h-4 w-7',
11
+ },
12
+ },
13
+ defaultVariants: {
14
+ size: 'default',
15
+ },
16
+ });
17
+ const switchThumbVariants = cva('pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0', {
18
+ variants: {
19
+ size: {
20
+ default: 'h-4 w-4 data-[state=checked]:translate-x-4',
21
+ small: 'h-3 w-3 data-[state=checked]:translate-x-3',
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ size: 'default',
26
+ },
27
+ });
28
+ const Switch = React.forwardRef(({ className, size, ...props }, ref) => (_jsx(SwitchPrimitives.Root, { className: cn(switchVariants({ size }), className), ...props, ref: ref, children: _jsx(SwitchPrimitives.Thumb, { className: cn(switchThumbVariants({ size })) }) })));
29
+ Switch.displayName = SwitchPrimitives.Root.displayName;
30
+ export { Switch };
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import { cn } from '../lib/utils';
4
+ const Table = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { className: "relative w-full overflow-auto", children: _jsx("table", { ref: ref, className: cn('w-full caption-bottom text-sm', className), ...props }) })));
5
+ Table.displayName = 'Table';
6
+ const TableHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("thead", { ref: ref, className: cn('[&_tr]:border-b [&_tr]:border-fds-gray-20', className), ...props })));
7
+ TableHeader.displayName = 'TableHeader';
8
+ const TableBody = React.forwardRef(({ className, ...props }, ref) => (_jsx("tbody", { ref: ref, className: cn('[&_tr:last-child]:border-0', className), ...props })));
9
+ TableBody.displayName = 'TableBody';
10
+ const TableFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("tfoot", { ref: ref, className: cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className), ...props })));
11
+ TableFooter.displayName = 'TableFooter';
12
+ const TableRow = React.forwardRef(({ className, ...props }, ref) => (_jsx("tr", { ref: ref, className: cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', className), ...props })));
13
+ TableRow.displayName = 'TableRow';
14
+ const TableHead = React.forwardRef(({ className, ...props }, ref) => (_jsx("th", { ref: ref, className: cn('px-fds-md text-left align-middle font-fds-semibold text-foreground [&:has([role=checkbox])]:pr-0', className), ...props })));
15
+ TableHead.displayName = 'TableHead';
16
+ const TableCell = React.forwardRef(({ className, ...props }, ref) => (_jsx("td", { ref: ref, className: cn('px-4 align-middle [&:has([role=checkbox])]:pr-0', className), ...props })));
17
+ TableCell.displayName = 'TableCell';
18
+ const TableCaption = React.forwardRef(({ className, ...props }, ref) => (_jsx("caption", { ref: ref, className: cn('mt-4 text-sm text-muted-foreground', className), ...props })));
19
+ TableCaption.displayName = 'TableCaption';
20
+ const TableEmpty = React.forwardRef(({ className, colSpan, message = 'No data', ...props }, ref) => (_jsx("tr", { ref: ref, className: className, ...props, children: _jsx("td", { colSpan: colSpan, className: "text-center", children: _jsxs("div", { className: "flex flex-col items-center justify-center py-fds-xxl", children: [_jsx("svg", { width: "64", height: "41", viewBox: "0 0 64 41", xmlns: "http://www.w3.org/2000/svg", children: _jsxs("g", { transform: "translate(0 1)", fill: "none", fillRule: "evenodd", children: [_jsx("ellipse", { className: "fill-fds-gray-10 dark:fill-fds-gray-80", cx: "32", cy: "33", rx: "32", ry: "7" }), _jsxs("g", { fillRule: "nonzero", className: "stroke-fds-gray-30 dark:stroke-fds-gray-60", children: [_jsx("path", { d: "M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z" }), _jsx("path", { d: "M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z", className: "fill-fds-gray-5 dark:fill-fds-gray-90" })] })] }) }), _jsx("span", { className: "mt-fds-sm text-fds-sm text-fds-gray-50", children: message })] }) }) })));
21
+ TableEmpty.displayName = 'TableEmpty';
22
+ export { Table, TableBody, TableCaption, TableCell, TableEmpty, TableFooter, TableHead, TableHeader, TableRow, };
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
4
+ import { cn } from '../lib/utils';
5
+ const Tabs = TabsPrimitive.Root;
6
+ const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.List, { ref: ref, className: cn('inline-flex h-auto w-full items-center justify-start overflow-x-auto border-b border-fds-gray-20 dark:border-fds-gray-80', className), ...props })));
7
+ TabsList.displayName = TabsPrimitive.List.displayName;
8
+ const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn('inline-flex items-center justify-center whitespace-nowrap border-b-2 border-transparent px-fds-lg py-fds-xs text-[16px] text-foreground transition-all focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50', 'hover:text-fds-gray-80 dark:hover:text-fds-gray-20', 'data-[state=active]:border-fds-blue data-[state=active]:text-fds-blue', 'dark:data-[state=active]:border-fds-blue-20 dark:data-[state=active]:text-fds-blue-20', className), ...props })));
9
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
10
+ const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn('mt-fds-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue focus-visible:ring-offset-2', className), ...props })));
11
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
12
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../lib/utils";
4
+ const Textarea = React.forwardRef(({ className, ...props }, ref) => {
5
+ return (_jsx("textarea", { className: cn("flex min-h-[80px] w-full rounded-md border border-input-border bg-input px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className), ref: ref, ...props }));
6
+ });
7
+ Textarea.displayName = "Textarea";
8
+ export { Textarea };
@@ -0,0 +1,74 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { IconClearCircledSolid, IconClock } from '@freightos/icons';
5
+ import { cn } from '../lib/utils';
6
+ import { Button } from './button';
7
+ import { Popover, PopoverContent, PopoverTrigger, } from './popover';
8
+ import { ScrollArea, ScrollBar, } from './scroll-area';
9
+ export function TimePicker({ value, onChange, placeholder = 'Select time', disabled = false, className, use24Hour = true, }) {
10
+ const [open, setOpen] = React.useState(false);
11
+ const [isHovered, setIsHovered] = React.useState(false);
12
+ const hours = use24Hour
13
+ ? Array.from({ length: 24 }, (_, i) => i)
14
+ : Array.from({ length: 12 }, (_, i) => i + 1);
15
+ // Parse value to get hour and minute
16
+ const parsedHour = value ? parseInt(value.split(':')[0], 10) : undefined;
17
+ const parsedMinute = value ? parseInt(value.split(':')[1], 10) : undefined;
18
+ const handleTimeChange = (type, val) => {
19
+ const currentHour = parsedHour ?? 0;
20
+ const currentMinute = parsedMinute ?? 0;
21
+ let newHour = currentHour;
22
+ let newMinute = currentMinute;
23
+ if (type === 'hour') {
24
+ if (use24Hour) {
25
+ newHour = parseInt(val);
26
+ }
27
+ else {
28
+ const isPM = currentHour >= 12;
29
+ newHour = (parseInt(val) % 12) + (isPM ? 12 : 0);
30
+ }
31
+ }
32
+ else if (type === 'minute') {
33
+ newMinute = parseInt(val);
34
+ }
35
+ else if (type === 'ampm') {
36
+ if (val === 'PM' && currentHour < 12) {
37
+ newHour = currentHour + 12;
38
+ }
39
+ else if (val === 'AM' && currentHour >= 12) {
40
+ newHour = currentHour - 12;
41
+ }
42
+ }
43
+ const timeString = `${newHour.toString().padStart(2, '0')}:${newMinute.toString().padStart(2, '0')}`;
44
+ onChange?.(timeString);
45
+ };
46
+ const handleClear = (e) => {
47
+ e.stopPropagation();
48
+ onChange?.(undefined);
49
+ };
50
+ const formatDisplayTime = (timeValue) => {
51
+ if (!timeValue)
52
+ return undefined;
53
+ const [h, m] = timeValue.split(':').map(Number);
54
+ if (use24Hour) {
55
+ return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
56
+ }
57
+ const hour12 = h % 12 || 12;
58
+ const ampm = h >= 12 ? 'PM' : 'AM';
59
+ return `${hour12}:${m.toString().padStart(2, '0')} ${ampm}`;
60
+ };
61
+ const showClearIcon = isHovered && value;
62
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", disabled: disabled, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), className: cn('flex h-[32px] w-full items-center justify-between gap-2 rounded-fds-md border border-input-border bg-input py-2 pl-3 pr-2 text-sm transition-[color,box-shadow]', 'focus:outline-none focus:border-[#2075bd] focus:shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)]', 'disabled:cursor-not-allowed disabled:opacity-50', open && 'border-[#2075bd] shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)]', !value && 'text-muted-foreground', className), children: [_jsx("span", { className: "truncate", children: value ? formatDisplayTime(value) : placeholder }), showClearIcon ? (_jsx(IconClearCircledSolid, { size: 16, className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground", onClick: handleClear })) : (_jsx(IconClock, { size: 16, className: "shrink-0 text-muted-foreground" }))] }) }), _jsx(PopoverContent, { className: "w-auto p-0", children: _jsxs("div", { className: "flex divide-x sm:h-[300px]", children: [_jsxs(ScrollArea, { className: "w-auto", children: [_jsx("div", { className: "flex flex-col p-2", children: hours.map((hour) => (_jsx(Button, { size: "small", htmlType: "button", type: parsedHour !== undefined &&
63
+ (use24Hour
64
+ ? parsedHour === hour
65
+ : parsedHour % 12 === hour % 12)
66
+ ? 'default'
67
+ : 'text', className: "aspect-square shrink-0 sm:w-full", onClick: () => handleTimeChange('hour', hour.toString()), children: use24Hour ? hour.toString().padStart(2, '0') : hour }, hour))) }), _jsx(ScrollBar, { orientation: "horizontal", className: "sm:hidden" })] }), _jsxs(ScrollArea, { className: "w-auto", children: [_jsx("div", { className: "flex flex-col p-2", children: Array.from({ length: 12 }, (_, i) => i * 5).map((minute) => (_jsx(Button, { size: "small", htmlType: "button", type: parsedMinute !== undefined && parsedMinute === minute
68
+ ? 'default'
69
+ : 'text', className: "aspect-square shrink-0 sm:w-full", onClick: () => handleTimeChange('minute', minute.toString()), children: minute.toString().padStart(2, '0') }, minute))) }), _jsx(ScrollBar, { orientation: "horizontal", className: "sm:hidden" })] }), !use24Hour && (_jsx(ScrollArea, { className: "", children: _jsx("div", { className: "flex flex-col p-2", children: ['AM', 'PM'].map((ampm) => (_jsx(Button, { size: "small", htmlType: "button", type: parsedHour !== undefined &&
70
+ ((ampm === 'AM' && parsedHour < 12) ||
71
+ (ampm === 'PM' && parsedHour >= 12))
72
+ ? 'default'
73
+ : 'text', className: "aspect-square shrink-0 sm:w-full", onClick: () => handleTimeChange('ampm', ampm), children: ampm }, ampm))) }) }))] }) })] }));
74
+ }
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import * as ToastPrimitives from "@radix-ui/react-toast";
4
+ import { cva } from "class-variance-authority";
5
+ import { X } from "lucide-react";
6
+ import { cn } from "../lib/utils";
7
+ const ToastProvider = ToastPrimitives.Provider;
8
+ const ToastViewport = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Viewport, { ref: ref, className: cn("fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]", className), ...props })));
9
+ ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
10
+ const toastVariants = cva("group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", {
11
+ variants: {
12
+ variant: {
13
+ default: "border bg-background text-foreground",
14
+ destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ variant: "default",
19
+ },
20
+ });
21
+ const Toast = React.forwardRef(({ className, variant, ...props }, ref) => {
22
+ return (_jsx(ToastPrimitives.Root, { ref: ref, className: cn(toastVariants({ variant }), className), ...props }));
23
+ });
24
+ Toast.displayName = ToastPrimitives.Root.displayName;
25
+ const ToastAction = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Action, { ref: ref, className: cn("inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive", className), ...props })));
26
+ ToastAction.displayName = ToastPrimitives.Action.displayName;
27
+ const ToastClose = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Close, { ref: ref, className: cn("absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", className), "toast-close": "", ...props, children: _jsx(X, { className: "h-4 w-4" }) })));
28
+ ToastClose.displayName = ToastPrimitives.Close.displayName;
29
+ const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Title, { ref: ref, className: cn("text-sm font-semibold", className), ...props })));
30
+ ToastTitle.displayName = ToastPrimitives.Title.displayName;
31
+ const ToastDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Description, { ref: ref, className: cn("text-sm opacity-90", className), ...props })));
32
+ ToastDescription.displayName = ToastPrimitives.Description.displayName;
33
+ export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction, };
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useToast } from "../hooks/use-toast";
3
+ import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, } from "./toast";
4
+ export function Toaster() {
5
+ const { toasts } = useToast();
6
+ return (_jsxs(ToastProvider, { children: [toasts.map(function ({ id, title, description, action, ...props }) {
7
+ return (_jsxs(Toast, { ...props, children: [_jsxs("div", { className: "grid gap-1", children: [title && _jsx(ToastTitle, { children: title }), description && (_jsx(ToastDescription, { children: description }))] }), action, _jsx(ToastClose, {})] }, id));
8
+ }), _jsx(ToastViewport, {})] }));
9
+ }
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
5
+ import { cn } from "../lib/utils";
6
+ import { toggleVariants } from "./toggle";
7
+ const ToggleGroupContext = React.createContext({
8
+ size: "default",
9
+ variant: "default",
10
+ });
11
+ const ToggleGroup = React.forwardRef(({ className, variant, size, children, ...props }, ref) => (_jsx(ToggleGroupPrimitive.Root, { ref: ref, className: cn("flex items-center justify-center gap-1", className), ...props, children: _jsx(ToggleGroupContext.Provider, { value: { variant, size }, children: children }) })));
12
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
13
+ const ToggleGroupItem = React.forwardRef(({ className, children, variant, size, ...props }, ref) => {
14
+ const context = React.useContext(ToggleGroupContext);
15
+ return (_jsx(ToggleGroupPrimitive.Item, { ref: ref, className: cn(toggleVariants({
16
+ variant: context.variant || variant,
17
+ size: context.size || size,
18
+ }), className), ...props, children: children }));
19
+ });
20
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
21
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import * as TogglePrimitive from "@radix-ui/react-toggle";
4
+ import { cva } from "class-variance-authority";
5
+ import { cn } from "../lib/utils";
6
+ const toggleVariants = cva("inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2", {
7
+ variants: {
8
+ variant: {
9
+ default: "bg-transparent",
10
+ outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
11
+ },
12
+ size: {
13
+ default: "h-10 px-3 min-w-10",
14
+ sm: "h-9 px-2.5 min-w-9",
15
+ lg: "h-11 px-5 min-w-11",
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ variant: "default",
20
+ size: "default",
21
+ },
22
+ });
23
+ const Toggle = React.forwardRef(({ className, variant, size, ...props }, ref) => (_jsx(TogglePrimitive.Root, { ref: ref, className: cn(toggleVariants({ variant, size, className })), ...props })));
24
+ Toggle.displayName = TogglePrimitive.Root.displayName;
25
+ export { Toggle, toggleVariants };
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../lib/utils';
3
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
4
+ import * as React from 'react';
5
+ const TooltipProvider = ({ children, ...props }) => (_jsx(TooltipPrimitive.Provider, { delayDuration: 0, ...props, children: children }));
6
+ const Tooltip = TooltipPrimitive.Root;
7
+ const TooltipTrigger = TooltipPrimitive.Trigger;
8
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsxs(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn('z-[9999] origin-[--radix-tooltip-content-transform-origin] overflow-hidden rounded-fds-md bg-fds-gray px-fds-lg py-fds-md !text-fds-base !font-fds-regular text-fds-white shadow-md 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', className), ...props, children: [props.children, _jsx(TooltipPrimitive.Arrow, { className: "fill-fds-gray", width: 12, height: 6 })] })));
9
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
10
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
@@ -0,0 +1,128 @@
1
+ "use client";
2
+ // Inspired by react-hot-toast library
3
+ import * as React from "react";
4
+ const TOAST_LIMIT = 1;
5
+ const TOAST_REMOVE_DELAY = 1000000;
6
+ const actionTypes = {
7
+ ADD_TOAST: "ADD_TOAST",
8
+ UPDATE_TOAST: "UPDATE_TOAST",
9
+ DISMISS_TOAST: "DISMISS_TOAST",
10
+ REMOVE_TOAST: "REMOVE_TOAST",
11
+ };
12
+ let count = 0;
13
+ function genId() {
14
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
15
+ return count.toString();
16
+ }
17
+ const toastTimeouts = new Map();
18
+ const addToRemoveQueue = (toastId) => {
19
+ if (toastTimeouts.has(toastId)) {
20
+ return;
21
+ }
22
+ const timeout = setTimeout(() => {
23
+ toastTimeouts.delete(toastId);
24
+ dispatch({
25
+ type: "REMOVE_TOAST",
26
+ toastId: toastId,
27
+ });
28
+ }, TOAST_REMOVE_DELAY);
29
+ toastTimeouts.set(toastId, timeout);
30
+ };
31
+ export const reducer = (state, action) => {
32
+ switch (action.type) {
33
+ case "ADD_TOAST":
34
+ return {
35
+ ...state,
36
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
37
+ };
38
+ case "UPDATE_TOAST":
39
+ return {
40
+ ...state,
41
+ toasts: state.toasts.map((t) => t.id === action.toast.id ? { ...t, ...action.toast } : t),
42
+ };
43
+ case "DISMISS_TOAST": {
44
+ const { toastId } = action;
45
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
46
+ // but I'll keep it here for simplicity
47
+ if (toastId) {
48
+ addToRemoveQueue(toastId);
49
+ }
50
+ else {
51
+ state.toasts.forEach((toast) => {
52
+ addToRemoveQueue(toast.id);
53
+ });
54
+ }
55
+ return {
56
+ ...state,
57
+ toasts: state.toasts.map((t) => t.id === toastId || toastId === undefined
58
+ ? {
59
+ ...t,
60
+ open: false,
61
+ }
62
+ : t),
63
+ };
64
+ }
65
+ case "REMOVE_TOAST":
66
+ if (action.toastId === undefined) {
67
+ return {
68
+ ...state,
69
+ toasts: [],
70
+ };
71
+ }
72
+ return {
73
+ ...state,
74
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
75
+ };
76
+ }
77
+ };
78
+ const listeners = [];
79
+ let memoryState = { toasts: [] };
80
+ function dispatch(action) {
81
+ memoryState = reducer(memoryState, action);
82
+ listeners.forEach((listener) => {
83
+ listener(memoryState);
84
+ });
85
+ }
86
+ function toast({ ...props }) {
87
+ const id = genId();
88
+ const update = (props) => dispatch({
89
+ type: "UPDATE_TOAST",
90
+ toast: { ...props, id },
91
+ });
92
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
93
+ dispatch({
94
+ type: "ADD_TOAST",
95
+ toast: {
96
+ ...props,
97
+ id,
98
+ open: true,
99
+ onOpenChange: (open) => {
100
+ if (!open)
101
+ dismiss();
102
+ },
103
+ },
104
+ });
105
+ return {
106
+ id: id,
107
+ dismiss,
108
+ update,
109
+ };
110
+ }
111
+ function useToast() {
112
+ const [state, setState] = React.useState(memoryState);
113
+ React.useEffect(() => {
114
+ listeners.push(setState);
115
+ return () => {
116
+ const index = listeners.indexOf(setState);
117
+ if (index > -1) {
118
+ listeners.splice(index, 1);
119
+ }
120
+ };
121
+ }, [state]);
122
+ return {
123
+ ...state,
124
+ toast,
125
+ dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId }),
126
+ };
127
+ }
128
+ export { useToast, toast };
@@ -0,0 +1,67 @@
1
+ // FreightWind Design System - Component Library
2
+ // @freightos/freightwind
3
+ // Utility
4
+ export { cn } from './lib/utils';
5
+ // Hooks
6
+ export { useToast, toast } from './hooks/use-toast';
7
+ // Components
8
+ export * from './components/accordion';
9
+ export * from './components/alert';
10
+ export * from './components/aspect-ratio';
11
+ export * from './components/avatar';
12
+ export * from './components/badge';
13
+ export * from './components/breadcrumb';
14
+ export * from './components/button';
15
+ export * from './components/calendar';
16
+ export * from './components/card';
17
+ export * from './components/chart';
18
+ export * from './components/checkbox';
19
+ export * from './components/chip';
20
+ export * from './components/collapsible';
21
+ export * from './components/command';
22
+ export * from './components/context-menu';
23
+ export * from './components/country-select';
24
+ export * from './components/date-picker';
25
+ export * from './components/date-range-picker';
26
+ export * from './components/date-time-picker';
27
+ export * from './components/dialog';
28
+ export * from './components/drawer';
29
+ export * from './components/dropdown-menu';
30
+ export * from './components/empty';
31
+ export * from './components/file-preview';
32
+ export * from './components/form';
33
+ export * from './components/inline-edit';
34
+ export * from './components/input';
35
+ export * from './components/input-group';
36
+ export * from './components/input-otp';
37
+ export * from './components/label';
38
+ export * from './components/menubar';
39
+ export * from './components/navigation-menu';
40
+ export * from './components/pagination';
41
+ export * from './components/phone-input';
42
+ export * from './components/popover';
43
+ export * from './components/progress';
44
+ export * from './components/radio-button-group';
45
+ export * from './components/radio-group';
46
+ export * from './components/resizable';
47
+ export * from './components/rich-text-editor';
48
+ export * from './components/scroll-area';
49
+ export * from './components/select';
50
+ export * from './components/separator';
51
+ export * from './components/sheet';
52
+ export * from './components/skeleton';
53
+ export * from './components/slider';
54
+ export { Toaster as SonnerToaster } from './components/sonner';
55
+ export * from './components/spinner';
56
+ export * from './components/stepper';
57
+ export * from './components/steps';
58
+ export * from './components/switch';
59
+ export * from './components/table';
60
+ export * from './components/tabs';
61
+ export * from './components/textarea';
62
+ export * from './components/time-picker';
63
+ export * from './components/toast';
64
+ export * from './components/toaster';
65
+ export * from './components/toggle';
66
+ export * from './components/toggle-group';
67
+ export * from './components/tooltip';
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Get flag image URL for country code (ISO 3166-1 alpha-2)
3
+ * Uses Freightos festatic CDN for flag images
4
+ * @param countryCode Two-letter country code (e.g., 'US', 'GB', 'FR')
5
+ * @returns Flag image URL or empty string if invalid
6
+ */
7
+ export const getCountryFlag = (countryCode) => {
8
+ if (!countryCode || countryCode.length !== 2)
9
+ return '';
10
+ const lowerCode = countryCode.toLowerCase();
11
+ // Use Freightos festatic CDN for flag images
12
+ return `https://festatic.freightos.com/flags/1x1/${lowerCode}.svg`;
13
+ };
14
+ /**
15
+ * Get flag emoji for country code (ISO 3166-1 alpha-2)
16
+ * Uses Unicode regional indicator symbols to display flag emojis
17
+ */
18
+ export const getCountryFlagEmoji = (countryCode) => {
19
+ if (!countryCode || countryCode.length !== 2)
20
+ return '';
21
+ const upperCode = countryCode.toUpperCase();
22
+ // Convert country code to regional indicator symbols (flag emoji)
23
+ const codePoints = [...upperCode].map(char => 0x1F1E6 + char.charCodeAt(0) - 65);
24
+ return String.fromCodePoint(...codePoints);
25
+ };
26
+ /**
27
+ * Common country names mapping (ISO 3166-1 alpha-2 codes)
28
+ */
29
+ const COUNTRY_NAMES = {
30
+ US: 'United States',
31
+ GB: 'United Kingdom',
32
+ CA: 'Canada',
33
+ FR: 'France',
34
+ DE: 'Germany',
35
+ IT: 'Italy',
36
+ ES: 'Spain',
37
+ NL: 'Netherlands',
38
+ BE: 'Belgium',
39
+ CH: 'Switzerland',
40
+ AT: 'Austria',
41
+ SE: 'Sweden',
42
+ NO: 'Norway',
43
+ DK: 'Denmark',
44
+ FI: 'Finland',
45
+ PL: 'Poland',
46
+ CZ: 'Czech Republic',
47
+ IE: 'Ireland',
48
+ PT: 'Portugal',
49
+ GR: 'Greece',
50
+ CN: 'China',
51
+ JP: 'Japan',
52
+ KR: 'South Korea',
53
+ IN: 'India',
54
+ AU: 'Australia',
55
+ NZ: 'New Zealand',
56
+ SG: 'Singapore',
57
+ HK: 'Hong Kong',
58
+ TW: 'Taiwan',
59
+ TH: 'Thailand',
60
+ MY: 'Malaysia',
61
+ ID: 'Indonesia',
62
+ PH: 'Philippines',
63
+ VN: 'Vietnam',
64
+ BR: 'Brazil',
65
+ MX: 'Mexico',
66
+ AR: 'Argentina',
67
+ CL: 'Chile',
68
+ CO: 'Colombia',
69
+ PE: 'Peru',
70
+ ZA: 'South Africa',
71
+ EG: 'Egypt',
72
+ IL: 'Israel',
73
+ AE: 'United Arab Emirates',
74
+ SA: 'Saudi Arabia',
75
+ TR: 'Turkey',
76
+ RU: 'Russia',
77
+ UA: 'Ukraine',
78
+ };
79
+ /**
80
+ * Get country information including flag, code, and name
81
+ */
82
+ export const getCountryInfo = (countryCode) => {
83
+ const upperCode = countryCode?.toUpperCase() || '';
84
+ const flag = getCountryFlag(upperCode);
85
+ const name = COUNTRY_NAMES[upperCode] || upperCode;
86
+ return { flag, code: upperCode, name };
87
+ };
@@ -0,0 +1,5 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }