@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.
- package/dist/cjs/components/accordion.js +57 -0
- package/dist/cjs/components/alert.js +76 -0
- package/dist/cjs/components/aspect-ratio.js +39 -0
- package/dist/cjs/components/avatar.js +75 -0
- package/dist/cjs/components/badge.js +24 -0
- package/dist/cjs/components/breadcrumb.js +65 -0
- package/dist/cjs/components/button.js +76 -0
- package/dist/cjs/components/calendar.js +106 -0
- package/dist/cjs/components/card.js +59 -0
- package/dist/cjs/components/chart.js +176 -0
- package/dist/cjs/components/checkbox.js +44 -0
- package/dist/cjs/components/chip.js +26 -0
- package/dist/cjs/components/collapsible.js +43 -0
- package/dist/cjs/components/command.js +73 -0
- package/dist/cjs/components/context-menu.js +83 -0
- package/dist/cjs/components/country-select.js +155 -0
- package/dist/cjs/components/date-picker.js +59 -0
- package/dist/cjs/components/date-range-picker.js +59 -0
- package/dist/cjs/components/date-time-picker.js +106 -0
- package/dist/cjs/components/dialog.js +70 -0
- package/dist/cjs/components/drawer.js +68 -0
- package/dist/cjs/components/dropdown-menu.js +85 -0
- package/dist/cjs/components/empty.js +42 -0
- package/dist/cjs/components/file-preview.js +73 -0
- package/dist/cjs/components/form.js +106 -0
- package/dist/cjs/components/inline-edit.js +83 -0
- package/dist/cjs/components/input-group.js +70 -0
- package/dist/cjs/components/input-otp.js +58 -0
- package/dist/cjs/components/input.js +57 -0
- package/dist/cjs/components/label.js +45 -0
- package/dist/cjs/components/menubar.js +96 -0
- package/dist/cjs/components/navigation-menu.js +68 -0
- package/dist/cjs/components/pagination.js +65 -0
- package/dist/cjs/components/phone-input.js +218 -0
- package/dist/cjs/components/popover.js +49 -0
- package/dist/cjs/components/progress.js +43 -0
- package/dist/cjs/components/radio-button-group.js +84 -0
- package/dist/cjs/components/radio-group.js +50 -0
- package/dist/cjs/components/resizable.js +47 -0
- package/dist/cjs/components/rich-text-editor.js +152 -0
- package/dist/cjs/components/route.js +47 -0
- package/dist/cjs/components/scroll-area.js +48 -0
- package/dist/cjs/components/select.js +71 -0
- package/dist/cjs/components/separator.js +43 -0
- package/dist/cjs/components/sheet.js +245 -0
- package/dist/cjs/components/skeleton.js +8 -0
- package/dist/cjs/components/slider.js +47 -0
- package/dist/cjs/components/sonner.js +25 -0
- package/dist/cjs/components/spinner.js +25 -0
- package/dist/cjs/components/stepper.js +99 -0
- package/dist/cjs/components/steps.js +127 -0
- package/dist/cjs/components/switch.js +66 -0
- package/dist/cjs/components/table.js +66 -0
- package/dist/cjs/components/tabs.js +51 -0
- package/dist/cjs/components/textarea.js +44 -0
- package/dist/cjs/components/time-picker.js +110 -0
- package/dist/cjs/components/toast.js +75 -0
- package/dist/cjs/components/toaster.js +12 -0
- package/dist/cjs/components/toggle-group.js +58 -0
- package/dist/cjs/components/toggle.js +62 -0
- package/dist/cjs/components/tooltip.js +49 -0
- package/dist/cjs/hooks/use-toast.js +166 -0
- package/dist/cjs/index.js +88 -0
- package/dist/cjs/lib/countryUtils.js +93 -0
- package/dist/cjs/lib/utils.js +8 -0
- package/dist/esm/components/accordion.js +18 -0
- package/dist/esm/components/alert.js +39 -0
- package/dist/esm/components/aspect-ratio.js +3 -0
- package/dist/esm/components/avatar.js +37 -0
- package/dist/esm/components/badge.js +20 -0
- package/dist/esm/components/breadcrumb.js +23 -0
- package/dist/esm/components/button.js +39 -0
- package/dist/esm/components/calendar.js +70 -0
- package/dist/esm/components/card.js +18 -0
- package/dist/esm/components/chart.js +135 -0
- package/dist/esm/components/checkbox.js +8 -0
- package/dist/esm/components/chip.js +22 -0
- package/dist/esm/components/collapsible.js +5 -0
- package/dist/esm/components/command.js +29 -0
- package/dist/esm/components/context-menu.js +33 -0
- package/dist/esm/components/country-select.js +118 -0
- package/dist/esm/components/date-picker.js +23 -0
- package/dist/esm/components/date-range-picker.js +23 -0
- package/dist/esm/components/date-time-picker.js +70 -0
- package/dist/esm/components/dialog.js +24 -0
- package/dist/esm/components/drawer.js +23 -0
- package/dist/esm/components/dropdown-menu.js +35 -0
- package/dist/esm/components/empty.js +6 -0
- package/dist/esm/components/file-preview.js +69 -0
- package/dist/esm/components/form.js +63 -0
- package/dist/esm/components/inline-edit.js +47 -0
- package/dist/esm/components/input-group.js +63 -0
- package/dist/esm/components/input-otp.js +19 -0
- package/dist/esm/components/input.js +21 -0
- package/dist/esm/components/label.js +9 -0
- package/dist/esm/components/menubar.js +45 -0
- package/dist/esm/components/navigation-menu.js +24 -0
- package/dist/esm/components/pagination.js +23 -0
- package/dist/esm/components/phone-input.js +181 -0
- package/dist/esm/components/popover.js +10 -0
- package/dist/esm/components/progress.js +7 -0
- package/dist/esm/components/radio-button-group.js +47 -0
- package/dist/esm/components/radio-group.js +13 -0
- package/dist/esm/components/resizable.js +9 -0
- package/dist/esm/components/rich-text-editor.js +145 -0
- package/dist/esm/components/route.js +11 -0
- package/dist/esm/components/scroll-area.js +11 -0
- package/dist/esm/components/select.js +26 -0
- package/dist/esm/components/separator.js +7 -0
- package/dist/esm/components/sheet.js +197 -0
- package/dist/esm/components/skeleton.js +6 -0
- package/dist/esm/components/slider.js +11 -0
- package/dist/esm/components/sonner.js +22 -0
- package/dist/esm/components/spinner.js +21 -0
- package/dist/esm/components/stepper.js +57 -0
- package/dist/esm/components/steps.js +80 -0
- package/dist/esm/components/switch.js +30 -0
- package/dist/esm/components/table.js +22 -0
- package/dist/esm/components/tabs.js +12 -0
- package/dist/esm/components/textarea.js +8 -0
- package/dist/esm/components/time-picker.js +74 -0
- package/dist/esm/components/toast.js +33 -0
- package/dist/esm/components/toaster.js +9 -0
- package/dist/esm/components/toggle-group.js +21 -0
- package/dist/esm/components/toggle.js +25 -0
- package/dist/esm/components/tooltip.js +10 -0
- package/dist/esm/hooks/use-toast.js +128 -0
- package/dist/esm/index.js +67 -0
- package/dist/esm/lib/countryUtils.js +87 -0
- package/dist/esm/lib/utils.js +5 -0
- package/dist/styles.css +152 -0
- package/dist/types/components/accordion.d.ts +11 -0
- package/dist/types/components/alert.d.ts +12 -0
- package/dist/types/components/aspect-ratio.d.ts +3 -0
- package/dist/types/components/avatar.d.ts +19 -0
- package/dist/types/components/badge.d.ts +9 -0
- package/dist/types/components/breadcrumb.d.ts +19 -0
- package/dist/types/components/button.d.ts +14 -0
- package/dist/types/components/calendar.d.ts +7 -0
- package/dist/types/components/card.d.ts +11 -0
- package/dist/types/components/chart.d.ts +66 -0
- package/dist/types/components/checkbox.d.ts +4 -0
- package/dist/types/components/chip.d.ts +10 -0
- package/dist/types/components/collapsible.d.ts +5 -0
- package/dist/types/components/command.d.ts +80 -0
- package/dist/types/components/context-menu.d.ts +27 -0
- package/dist/types/components/country-select.d.ts +17 -0
- package/dist/types/components/date-picker.d.ts +9 -0
- package/dist/types/components/date-range-picker.d.ts +10 -0
- package/dist/types/components/date-time-picker.d.ts +10 -0
- package/dist/types/components/dialog.d.ts +23 -0
- package/dist/types/components/drawer.d.ts +22 -0
- package/dist/types/components/dropdown-menu.d.ts +27 -0
- package/dist/types/components/empty.d.ts +6 -0
- package/dist/types/components/file-preview.d.ts +9 -0
- package/dist/types/components/form.d.ts +23 -0
- package/dist/types/components/inline-edit.d.ts +10 -0
- package/dist/types/components/input-group.d.ts +16 -0
- package/dist/types/components/input-otp.d.ts +34 -0
- package/dist/types/components/input.d.ts +9 -0
- package/dist/types/components/label.d.ts +5 -0
- package/dist/types/components/menubar.d.ts +28 -0
- package/dist/types/components/navigation-menu.d.ts +12 -0
- package/dist/types/components/pagination.d.ts +29 -0
- package/dist/types/components/phone-input.d.ts +20 -0
- package/dist/types/components/popover.d.ts +9 -0
- package/dist/types/components/progress.d.ts +4 -0
- package/dist/types/components/radio-button-group.d.ts +17 -0
- package/dist/types/components/radio-group.d.ts +5 -0
- package/dist/types/components/resizable.d.ts +23 -0
- package/dist/types/components/rich-text-editor.d.ts +8 -0
- package/dist/types/components/route.d.ts +10 -0
- package/dist/types/components/scroll-area.d.ts +5 -0
- package/dist/types/components/select.d.ts +13 -0
- package/dist/types/components/separator.d.ts +4 -0
- package/dist/types/components/sheet.d.ts +49 -0
- package/dist/types/components/skeleton.d.ts +2 -0
- package/dist/types/components/slider.d.ts +4 -0
- package/dist/types/components/sonner.d.ts +4 -0
- package/dist/types/components/spinner.d.ts +8 -0
- package/dist/types/components/stepper.d.ts +17 -0
- package/dist/types/components/steps.d.ts +64 -0
- package/dist/types/components/switch.d.ts +10 -0
- package/dist/types/components/table.d.ts +14 -0
- package/dist/types/components/tabs.d.ts +7 -0
- package/dist/types/components/textarea.d.ts +3 -0
- package/dist/types/components/time-picker.d.ts +10 -0
- package/dist/types/components/toast.d.ts +15 -0
- package/dist/types/components/toaster.d.ts +1 -0
- package/dist/types/components/toggle-group.d.ts +12 -0
- package/dist/types/components/toggle.d.ts +12 -0
- package/dist/types/components/tooltip.d.ts +7 -0
- package/dist/types/hooks/use-toast.d.ts +44 -0
- package/dist/types/index.d.ts +62 -0
- package/dist/types/lib/countryUtils.d.ts +20 -0
- package/dist/types/lib/utils.d.ts +2 -0
- package/package.json +84 -0
- package/tailwind-preset.js +70 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { cn } from '../lib/utils';
|
|
5
|
+
import { Button } from './button';
|
|
6
|
+
import { Input } from './input';
|
|
7
|
+
import { Textarea } from './textarea';
|
|
8
|
+
function InputGroup({ className, ...props }) {
|
|
9
|
+
return (_jsx("div", { "data-slot": "input-group", role: "group", className: cn('group/input-group relative flex w-full items-center rounded-fds-md border border-input-border bg-input outline-none transition-[color,box-shadow]', 'h-[32px] has-[>textarea]:h-auto',
|
|
10
|
+
// Variants based on alignment.
|
|
11
|
+
'has-[>[data-align=inline-start]]:[&>input]:pl-2', 'has-[>[data-align=inline-end]]:[&>input]:pr-2', 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3', 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
|
|
12
|
+
// Focus state.
|
|
13
|
+
'focus-within:border-[#2075bd] focus-within:shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)]',
|
|
14
|
+
// Error state.
|
|
15
|
+
'has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40', className), ...props }));
|
|
16
|
+
}
|
|
17
|
+
const inputGroupAddonVariants = cva("text-muted-foreground flex h-full cursor-text select-none items-center justify-center gap-2 bg-fds-gray-10 px-3 text-xs font-medium group-data-[disabled=true]/input-group:opacity-50 dark:bg-background [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", {
|
|
18
|
+
variants: {
|
|
19
|
+
align: {
|
|
20
|
+
'inline-start': 'order-first rounded-l-[3px] border-r border-input-border',
|
|
21
|
+
'inline-end': 'order-last rounded-r-[3px] border-l border-input-border',
|
|
22
|
+
'block-start': '[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5',
|
|
23
|
+
'block-end': '[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
align: 'inline-start',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
function InputGroupAddon({ className, align = 'inline-start', ...props }) {
|
|
31
|
+
return (_jsx("div", { role: "group", "data-slot": "input-group-addon", "data-align": align, className: cn(inputGroupAddonVariants({ align }), className), onClick: (e) => {
|
|
32
|
+
if (e.target.closest('button')) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
e.currentTarget.parentElement?.querySelector('input')?.focus();
|
|
36
|
+
}, ...props }));
|
|
37
|
+
}
|
|
38
|
+
const inputGroupButtonVariants = cva('flex items-center gap-2 text-sm shadow-none', {
|
|
39
|
+
variants: {
|
|
40
|
+
size: {
|
|
41
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
|
|
42
|
+
sm: 'h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5',
|
|
43
|
+
'icon-xs': 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
|
|
44
|
+
'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
defaultVariants: {
|
|
48
|
+
size: 'xs',
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
function InputGroupButton({ className, htmlType = 'button', type = 'text', size = 'xs', ...props }) {
|
|
52
|
+
return (_jsx(Button, { htmlType: htmlType, type: type, "data-size": size, className: cn(inputGroupButtonVariants({ size }), className), ...props }));
|
|
53
|
+
}
|
|
54
|
+
function InputGroupText({ className, ...props }) {
|
|
55
|
+
return (_jsx("span", { className: cn("flex items-center gap-2 text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className), ...props }));
|
|
56
|
+
}
|
|
57
|
+
function InputGroupInput({ className, ...props }) {
|
|
58
|
+
return (_jsx(Input, { "data-slot": "input-group-control", className: cn('flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent', className), ...props }));
|
|
59
|
+
}
|
|
60
|
+
function InputGroupTextarea({ className, ...props }) {
|
|
61
|
+
return (_jsx(Textarea, { "data-slot": "input-group-control", className: cn('flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent', className), ...props }));
|
|
62
|
+
}
|
|
63
|
+
export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { OTPInput, OTPInputContext } from "input-otp";
|
|
5
|
+
import { Dot } from "lucide-react";
|
|
6
|
+
import { cn } from "../lib/utils";
|
|
7
|
+
const InputOTP = React.forwardRef(({ className, containerClassName, ...props }, ref) => (_jsx(OTPInput, { ref: ref, containerClassName: cn("flex items-center gap-2 has-[:disabled]:opacity-50", containerClassName), className: cn("disabled:cursor-not-allowed", className), ...props })));
|
|
8
|
+
InputOTP.displayName = "InputOTP";
|
|
9
|
+
const InputOTPGroup = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex items-center", className), ...props })));
|
|
10
|
+
InputOTPGroup.displayName = "InputOTPGroup";
|
|
11
|
+
const InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => {
|
|
12
|
+
const inputOTPContext = React.useContext(OTPInputContext);
|
|
13
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
|
|
14
|
+
return (_jsxs("div", { ref: ref, className: cn("relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md", isActive && "z-10 ring-2 ring-ring ring-offset-background", className), ...props, children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "h-4 w-px animate-caret-blink bg-foreground duration-1000" }) }))] }));
|
|
15
|
+
});
|
|
16
|
+
InputOTPSlot.displayName = "InputOTPSlot";
|
|
17
|
+
const InputOTPSeparator = React.forwardRef(({ ...props }, ref) => (_jsx("div", { ref: ref, role: "separator", ...props, children: _jsx(Dot, {}) })));
|
|
18
|
+
InputOTPSeparator.displayName = "InputOTPSeparator";
|
|
19
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../lib/utils';
|
|
5
|
+
const inputVariants = cva('flex w-full rounded-fds-md border border-input-border bg-input text-foreground outline-none transition-[color,box-shadow] file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus:border-[#2075bd] focus:shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)] disabled:cursor-not-allowed disabled:opacity-50', {
|
|
6
|
+
variants: {
|
|
7
|
+
inputSize: {
|
|
8
|
+
small: 'h-[24px] px-2 py-1 text-fds-sm',
|
|
9
|
+
default: 'h-[32px] px-3 py-2 text-fds-base',
|
|
10
|
+
large: 'h-[40px] px-3 py-2 text-fds-h6',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
defaultVariants: {
|
|
14
|
+
inputSize: 'default',
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
const Input = React.forwardRef(({ className, type, inputSize, ...props }, ref) => {
|
|
18
|
+
return (_jsx("input", { type: type, className: cn(inputVariants({ inputSize, className })), ref: ref, ...props }));
|
|
19
|
+
});
|
|
20
|
+
Input.displayName = 'Input';
|
|
21
|
+
export { Input };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { cn } from "../lib/utils";
|
|
6
|
+
const labelVariants = cva("text-fds-sm font-fds-semibold leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|
|
7
|
+
const Label = React.forwardRef(({ className, ...props }, ref) => (_jsx(LabelPrimitive.Root, { ref: ref, className: cn(labelVariants(), className), ...props })));
|
|
8
|
+
Label.displayName = LabelPrimitive.Root.displayName;
|
|
9
|
+
export { Label };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as MenubarPrimitive from "@radix-ui/react-menubar";
|
|
4
|
+
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/utils";
|
|
6
|
+
function MenubarMenu({ ...props }) {
|
|
7
|
+
return _jsx(MenubarPrimitive.Menu, { ...props });
|
|
8
|
+
}
|
|
9
|
+
function MenubarGroup({ ...props }) {
|
|
10
|
+
return _jsx(MenubarPrimitive.Group, { ...props });
|
|
11
|
+
}
|
|
12
|
+
function MenubarPortal({ ...props }) {
|
|
13
|
+
return _jsx(MenubarPrimitive.Portal, { ...props });
|
|
14
|
+
}
|
|
15
|
+
function MenubarRadioGroup({ ...props }) {
|
|
16
|
+
return _jsx(MenubarPrimitive.RadioGroup, { ...props });
|
|
17
|
+
}
|
|
18
|
+
function MenubarSub({ ...props }) {
|
|
19
|
+
return _jsx(MenubarPrimitive.Sub, { "data-slot": "menubar-sub", ...props });
|
|
20
|
+
}
|
|
21
|
+
const Menubar = React.forwardRef(({ className, ...props }, ref) => (_jsx(MenubarPrimitive.Root, { ref: ref, className: cn("flex h-10 items-center space-x-1 rounded-md border bg-background p-1", className), ...props })));
|
|
22
|
+
Menubar.displayName = MenubarPrimitive.Root.displayName;
|
|
23
|
+
const MenubarTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(MenubarPrimitive.Trigger, { ref: ref, className: cn("flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", className), ...props })));
|
|
24
|
+
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
|
|
25
|
+
const MenubarSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => (_jsxs(MenubarPrimitive.SubTrigger, { ref: ref, className: cn("flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", inset && "pl-8", className), ...props, children: [children, _jsx(ChevronRight, { className: "ml-auto h-4 w-4" })] })));
|
|
26
|
+
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
|
|
27
|
+
const MenubarSubContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(MenubarPrimitive.SubContent, { ref: ref, className: cn("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 origin-[--radix-menubar-content-transform-origin]", className), ...props })));
|
|
28
|
+
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
|
|
29
|
+
const MenubarContent = React.forwardRef(({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props }, ref) => (_jsx(MenubarPrimitive.Portal, { children: _jsx(MenubarPrimitive.Content, { ref: ref, align: align, alignOffset: alignOffset, sideOffset: sideOffset, className: cn("z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 origin-[--radix-menubar-content-transform-origin]", className), ...props }) })));
|
|
30
|
+
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
|
|
31
|
+
const MenubarItem = React.forwardRef(({ className, inset, ...props }, ref) => (_jsx(MenubarPrimitive.Item, { ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", inset && "pl-8", className), ...props })));
|
|
32
|
+
MenubarItem.displayName = MenubarPrimitive.Item.displayName;
|
|
33
|
+
const MenubarCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => (_jsxs(MenubarPrimitive.CheckboxItem, { ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), checked: checked, ...props, children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(MenubarPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), children] })));
|
|
34
|
+
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
|
|
35
|
+
const MenubarRadioItem = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(MenubarPrimitive.RadioItem, { ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(MenubarPrimitive.ItemIndicator, { children: _jsx(Circle, { className: "h-2 w-2 fill-current" }) }) }), children] })));
|
|
36
|
+
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
|
|
37
|
+
const MenubarLabel = React.forwardRef(({ className, inset, ...props }, ref) => (_jsx(MenubarPrimitive.Label, { ref: ref, className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className), ...props })));
|
|
38
|
+
MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
|
|
39
|
+
const MenubarSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx(MenubarPrimitive.Separator, { ref: ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props })));
|
|
40
|
+
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
|
|
41
|
+
const MenubarShortcut = ({ className, ...props }) => {
|
|
42
|
+
return (_jsx("span", { className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className), ...props }));
|
|
43
|
+
};
|
|
44
|
+
MenubarShortcut.displayname = "MenubarShortcut";
|
|
45
|
+
export { Menubar, MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem, MenubarSeparator, MenubarLabel, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarPortal, MenubarSubContent, MenubarSubTrigger, MenubarGroup, MenubarSub, MenubarShortcut, };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { ChevronDown } from "lucide-react";
|
|
6
|
+
import { cn } from "../lib/utils";
|
|
7
|
+
const NavigationMenu = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(NavigationMenuPrimitive.Root, { ref: ref, className: cn("relative z-10 flex max-w-max flex-1 items-center justify-center", className), ...props, children: [children, _jsx(NavigationMenuViewport, {})] })));
|
|
8
|
+
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
|
|
9
|
+
const NavigationMenuList = React.forwardRef(({ className, ...props }, ref) => (_jsx(NavigationMenuPrimitive.List, { ref: ref, className: cn("group flex flex-1 list-none items-center justify-center space-x-1", className), ...props })));
|
|
10
|
+
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
|
|
11
|
+
const NavigationMenuItem = NavigationMenuPrimitive.Item;
|
|
12
|
+
const navigationMenuTriggerStyle = cva("group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:bg-accent/50 data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent");
|
|
13
|
+
const NavigationMenuTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(NavigationMenuPrimitive.Trigger, { ref: ref, className: cn(navigationMenuTriggerStyle(), "group", className), ...props, children: [children, " ", _jsx(ChevronDown, { className: "relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180", "aria-hidden": "true" })] })));
|
|
14
|
+
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
|
|
15
|
+
const NavigationMenuContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(NavigationMenuPrimitive.Content, { ref: ref, className: cn("left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ", className), ...props })));
|
|
16
|
+
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
|
|
17
|
+
const NavigationMenuLink = NavigationMenuPrimitive.Link;
|
|
18
|
+
const NavigationMenuViewport = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { className: cn("absolute left-0 top-full flex justify-center"), children: _jsx(NavigationMenuPrimitive.Viewport, { className: cn("origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]", className), ref: ref, ...props }) })));
|
|
19
|
+
NavigationMenuViewport.displayName =
|
|
20
|
+
NavigationMenuPrimitive.Viewport.displayName;
|
|
21
|
+
const NavigationMenuIndicator = React.forwardRef(({ className, ...props }, ref) => (_jsx(NavigationMenuPrimitive.Indicator, { ref: ref, className: cn("top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in", className), ...props, children: _jsx("div", { className: "relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" }) })));
|
|
22
|
+
NavigationMenuIndicator.displayName =
|
|
23
|
+
NavigationMenuPrimitive.Indicator.displayName;
|
|
24
|
+
export { navigationMenuTriggerStyle, NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuContent, NavigationMenuTrigger, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
|
|
4
|
+
import { cn } from '../lib/utils';
|
|
5
|
+
import { buttonVariants, } from './button';
|
|
6
|
+
const Pagination = ({ className, ...props }) => (_jsx("nav", { role: "navigation", "aria-label": "pagination", className: cn('mx-auto flex w-full justify-center', className), ...props }));
|
|
7
|
+
Pagination.displayName = 'Pagination';
|
|
8
|
+
const PaginationContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("ul", { ref: ref, className: cn('flex flex-row items-center gap-1', className), ...props })));
|
|
9
|
+
PaginationContent.displayName = 'PaginationContent';
|
|
10
|
+
const PaginationItem = React.forwardRef(({ className, ...props }, ref) => (_jsx("li", { ref: ref, className: cn('', className), ...props })));
|
|
11
|
+
PaginationItem.displayName = 'PaginationItem';
|
|
12
|
+
const PaginationLink = ({ className, isActive, icon = true, size, ...props }) => (_jsx("a", { "aria-current": isActive ? 'page' : undefined, className: cn(buttonVariants({
|
|
13
|
+
type: isActive ? 'secondary' : 'text',
|
|
14
|
+
size,
|
|
15
|
+
}), icon && 'aspect-square p-0', className), ...props }));
|
|
16
|
+
PaginationLink.displayName = 'PaginationLink';
|
|
17
|
+
const PaginationPrevious = ({ className, ...props }) => (_jsxs(PaginationLink, { "aria-label": "Go to previous page", icon: false, size: "medium", className: cn('gap-1 pl-2.5', className), ...props, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), _jsx("span", { children: "Previous" })] }));
|
|
18
|
+
PaginationPrevious.displayName = 'PaginationPrevious';
|
|
19
|
+
const PaginationNext = ({ className, ...props }) => (_jsxs(PaginationLink, { "aria-label": "Go to next page", icon: false, size: "medium", className: cn('gap-1 pr-2.5', className), ...props, children: [_jsx("span", { children: "Next" }), _jsx(ChevronRight, { className: "h-4 w-4" })] }));
|
|
20
|
+
PaginationNext.displayName = 'PaginationNext';
|
|
21
|
+
const PaginationEllipsis = ({ className, ...props }) => (_jsxs("span", { "aria-hidden": true, className: cn('flex h-9 w-9 items-center justify-center', className), ...props, children: [_jsx(MoreHorizontal, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "More pages" })] }));
|
|
22
|
+
PaginationEllipsis.displayName = 'PaginationEllipsis';
|
|
23
|
+
export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, };
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../lib/utils';
|
|
4
|
+
import { getCountryFlag } from '../lib/countryUtils';
|
|
5
|
+
import { IconCaretDown } from '@freightos/icons';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { parsePhoneNumberFromString, AsYouType, getCountryCallingCode, } from 'libphonenumber-js';
|
|
8
|
+
// Countries with dial codes
|
|
9
|
+
export const PHONE_COUNTRIES = [
|
|
10
|
+
{ code: 'US', name: 'United States', dialCode: '+1' },
|
|
11
|
+
{ code: 'CN', name: 'China', dialCode: '+86' },
|
|
12
|
+
{ code: 'GB', name: 'United Kingdom', dialCode: '+44' },
|
|
13
|
+
{ code: 'CA', name: 'Canada', dialCode: '+1' },
|
|
14
|
+
{ code: 'DE', name: 'Germany', dialCode: '+49' },
|
|
15
|
+
{ code: 'FR', name: 'France', dialCode: '+33' },
|
|
16
|
+
{ code: 'IT', name: 'Italy', dialCode: '+39' },
|
|
17
|
+
{ code: 'ES', name: 'Spain', dialCode: '+34' },
|
|
18
|
+
{ code: 'NL', name: 'Netherlands', dialCode: '+31' },
|
|
19
|
+
{ code: 'BE', name: 'Belgium', dialCode: '+32' },
|
|
20
|
+
{ code: 'CH', name: 'Switzerland', dialCode: '+41' },
|
|
21
|
+
{ code: 'AT', name: 'Austria', dialCode: '+43' },
|
|
22
|
+
{ code: 'SE', name: 'Sweden', dialCode: '+46' },
|
|
23
|
+
{ code: 'NO', name: 'Norway', dialCode: '+47' },
|
|
24
|
+
{ code: 'DK', name: 'Denmark', dialCode: '+45' },
|
|
25
|
+
{ code: 'FI', name: 'Finland', dialCode: '+358' },
|
|
26
|
+
{ code: 'PL', name: 'Poland', dialCode: '+48' },
|
|
27
|
+
{ code: 'CZ', name: 'Czech Republic', dialCode: '+420' },
|
|
28
|
+
{ code: 'IE', name: 'Ireland', dialCode: '+353' },
|
|
29
|
+
{ code: 'PT', name: 'Portugal', dialCode: '+351' },
|
|
30
|
+
{ code: 'GR', name: 'Greece', dialCode: '+30' },
|
|
31
|
+
{ code: 'JP', name: 'Japan', dialCode: '+81' },
|
|
32
|
+
{ code: 'KR', name: 'South Korea', dialCode: '+82' },
|
|
33
|
+
{ code: 'IN', name: 'India', dialCode: '+91' },
|
|
34
|
+
{ code: 'AU', name: 'Australia', dialCode: '+61' },
|
|
35
|
+
{ code: 'NZ', name: 'New Zealand', dialCode: '+64' },
|
|
36
|
+
{ code: 'SG', name: 'Singapore', dialCode: '+65' },
|
|
37
|
+
{ code: 'HK', name: 'Hong Kong', dialCode: '+852' },
|
|
38
|
+
{ code: 'TW', name: 'Taiwan', dialCode: '+886' },
|
|
39
|
+
{ code: 'TH', name: 'Thailand', dialCode: '+66' },
|
|
40
|
+
{ code: 'MY', name: 'Malaysia', dialCode: '+60' },
|
|
41
|
+
{ code: 'ID', name: 'Indonesia', dialCode: '+62' },
|
|
42
|
+
{ code: 'PH', name: 'Philippines', dialCode: '+63' },
|
|
43
|
+
{ code: 'VN', name: 'Vietnam', dialCode: '+84' },
|
|
44
|
+
{ code: 'BR', name: 'Brazil', dialCode: '+55' },
|
|
45
|
+
{ code: 'MX', name: 'Mexico', dialCode: '+52' },
|
|
46
|
+
{ code: 'AR', name: 'Argentina', dialCode: '+54' },
|
|
47
|
+
{ code: 'CL', name: 'Chile', dialCode: '+56' },
|
|
48
|
+
{ code: 'CO', name: 'Colombia', dialCode: '+57' },
|
|
49
|
+
{ code: 'PE', name: 'Peru', dialCode: '+51' },
|
|
50
|
+
{ code: 'ZA', name: 'South Africa', dialCode: '+27' },
|
|
51
|
+
{ code: 'EG', name: 'Egypt', dialCode: '+20' },
|
|
52
|
+
{ code: 'IL', name: 'Israel', dialCode: '+972' },
|
|
53
|
+
{ code: 'AE', name: 'United Arab Emirates', dialCode: '+971' },
|
|
54
|
+
{ code: 'SA', name: 'Saudi Arabia', dialCode: '+966' },
|
|
55
|
+
{ code: 'TR', name: 'Turkey', dialCode: '+90' },
|
|
56
|
+
{ code: 'RU', name: 'Russia', dialCode: '+7' },
|
|
57
|
+
{ code: 'UA', name: 'Ukraine', dialCode: '+380' },
|
|
58
|
+
];
|
|
59
|
+
export const PhoneInput = ({ value = '', onChange, onError, placeholder = 'Enter phone number', defaultCountry = 'US', mostUsedCountries = ['US', 'CN'], countries = PHONE_COUNTRIES, className, disabled = false, }) => {
|
|
60
|
+
const [open, setOpen] = React.useState(false);
|
|
61
|
+
const [search, setSearch] = React.useState('');
|
|
62
|
+
const [selectedCountry, setSelectedCountry] = React.useState(() => countries.find((c) => c.code === defaultCountry) || countries[0]);
|
|
63
|
+
const [phoneNumber, setPhoneNumber] = React.useState('');
|
|
64
|
+
const containerRef = React.useRef(null);
|
|
65
|
+
const searchInputRef = React.useRef(null);
|
|
66
|
+
// Parse initial value to extract country and number
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
if (value) {
|
|
69
|
+
try {
|
|
70
|
+
const parsed = parsePhoneNumberFromString(value);
|
|
71
|
+
if (parsed) {
|
|
72
|
+
const countryCode = parsed.country;
|
|
73
|
+
if (countryCode) {
|
|
74
|
+
const country = countries.find((c) => c.code === countryCode);
|
|
75
|
+
if (country) {
|
|
76
|
+
setSelectedCountry(country);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
setPhoneNumber(parsed.nationalNumber);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Try to extract dial code from value
|
|
83
|
+
const matchingCountry = countries.find((c) => value.startsWith(c.dialCode));
|
|
84
|
+
if (matchingCountry) {
|
|
85
|
+
setSelectedCountry(matchingCountry);
|
|
86
|
+
setPhoneNumber(value.slice(matchingCountry.dialCode.length).trim());
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
setPhoneNumber(value.replace(/^\+\d+\s*/, ''));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
setPhoneNumber(value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
98
|
+
}, []);
|
|
99
|
+
// Filter countries based on search
|
|
100
|
+
const filteredCountries = React.useMemo(() => {
|
|
101
|
+
const searchLower = search.toLowerCase();
|
|
102
|
+
const filtered = countries.filter((country) => country.name.toLowerCase().includes(searchLower) ||
|
|
103
|
+
country.code.toLowerCase().includes(searchLower) ||
|
|
104
|
+
country.dialCode.includes(search));
|
|
105
|
+
return filtered.sort((a, b) => {
|
|
106
|
+
const aIsMostUsed = mostUsedCountries.includes(a.code);
|
|
107
|
+
const bIsMostUsed = mostUsedCountries.includes(b.code);
|
|
108
|
+
if (aIsMostUsed && !bIsMostUsed)
|
|
109
|
+
return -1;
|
|
110
|
+
if (!aIsMostUsed && bIsMostUsed)
|
|
111
|
+
return 1;
|
|
112
|
+
return a.name.localeCompare(b.name);
|
|
113
|
+
});
|
|
114
|
+
}, [countries, search, mostUsedCountries]);
|
|
115
|
+
// Close on click outside
|
|
116
|
+
React.useEffect(() => {
|
|
117
|
+
const handleClickOutside = (e) => {
|
|
118
|
+
if (containerRef.current &&
|
|
119
|
+
!containerRef.current.contains(e.target)) {
|
|
120
|
+
setOpen(false);
|
|
121
|
+
setSearch('');
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
if (open) {
|
|
125
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
126
|
+
}
|
|
127
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
128
|
+
}, [open]);
|
|
129
|
+
const handleCountrySelect = (country) => {
|
|
130
|
+
setSelectedCountry(country);
|
|
131
|
+
setOpen(false);
|
|
132
|
+
setSearch('');
|
|
133
|
+
// Update full value with new country code
|
|
134
|
+
const fullNumber = `${country.dialCode} ${phoneNumber}`.trim();
|
|
135
|
+
onChange?.(fullNumber);
|
|
136
|
+
validateNumber(phoneNumber, country.code);
|
|
137
|
+
};
|
|
138
|
+
const handlePhoneChange = (e) => {
|
|
139
|
+
const input = e.target.value;
|
|
140
|
+
// Format as user types
|
|
141
|
+
const formatter = new AsYouType(selectedCountry.code);
|
|
142
|
+
const formatted = formatter.input(input);
|
|
143
|
+
// Extract just the national number part
|
|
144
|
+
const nationalNumber = formatted.replace(/^\+\d+\s*/, '');
|
|
145
|
+
setPhoneNumber(nationalNumber);
|
|
146
|
+
// Build full international number
|
|
147
|
+
const fullNumber = `${selectedCountry.dialCode} ${nationalNumber}`.trim();
|
|
148
|
+
onChange?.(fullNumber);
|
|
149
|
+
validateNumber(nationalNumber, selectedCountry.code);
|
|
150
|
+
};
|
|
151
|
+
const validateNumber = (number, countryCode) => {
|
|
152
|
+
if (!number || !onError)
|
|
153
|
+
return;
|
|
154
|
+
try {
|
|
155
|
+
const fullNumber = `${getCountryCallingCode(countryCode)}${number.replace(/\D/g, '')}`;
|
|
156
|
+
const parsed = parsePhoneNumberFromString(`+${fullNumber}`, countryCode);
|
|
157
|
+
onError?.(!parsed?.isValid());
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
onError?.(true);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const handleTriggerClick = () => {
|
|
164
|
+
if (!disabled) {
|
|
165
|
+
setOpen(!open);
|
|
166
|
+
if (!open) {
|
|
167
|
+
setTimeout(() => searchInputRef.current?.focus(), 0);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
return (_jsxs("div", { ref: containerRef, className: cn('relative flex min-w-0', className), children: [_jsxs("button", { type: "button", onClick: handleTriggerClick, disabled: disabled, className: cn('flex h-[32px] shrink-0 items-center gap-fds-xs rounded-l-fds-md border border-r-0 border-input-border bg-input px-fds-sm text-fds-base outline-none transition-[color,box-shadow]', open &&
|
|
172
|
+
'border-[#2075bd] shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)]', disabled && 'cursor-not-allowed opacity-50'), children: [_jsx("img", { src: getCountryFlag(selectedCountry.code), alt: selectedCountry.code, className: "h-4 w-4 shrink-0 rounded-full object-cover" }), _jsx("span", { className: "text-fds-sm text-fds-gray-60", children: selectedCountry.dialCode }), _jsx(IconCaretDown, { size: 14, className: cn('shrink-0 text-fds-gray-60 transition-transform', open && 'rotate-180') })] }), _jsx("input", { type: "tel", value: phoneNumber, onChange: handlePhoneChange, placeholder: placeholder, disabled: disabled, className: cn('h-[32px] flex-1 rounded-r-fds-md border border-input-border bg-input px-fds-sm text-fds-base outline-none transition-[color,box-shadow] placeholder:text-muted-foreground', 'focus:border-[#2075bd] focus:shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)]', disabled && 'cursor-not-allowed opacity-50') }), open && (_jsxs("div", { className: "absolute left-0 top-full z-50 mt-fds-xs w-[280px] rounded-fds-md border border-border bg-popover shadow-lg", children: [_jsx("div", { className: "border-b border-border p-fds-xs", children: _jsx("input", { ref: searchInputRef, type: "text", value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Search country...", className: "h-[28px] w-full rounded-fds-sm border border-input-border bg-input px-fds-sm text-fds-sm outline-none focus:border-[#2075bd] focus:shadow-[0_0_0_2px_var(--fds-color-primary-blue-20)]" }) }), _jsx("div", { className: "max-h-[210px] overflow-y-auto p-fds-xs", children: filteredCountries.length === 0 ? (_jsx("div", { className: "px-fds-sm py-fds-md text-center text-fds-sm text-muted-foreground", children: "No countries found" })) : (filteredCountries.map((country, index) => {
|
|
173
|
+
const isSelected = country.code === selectedCountry.code;
|
|
174
|
+
const isMostUsed = mostUsedCountries.includes(country.code);
|
|
175
|
+
const isLastMostUsed = isMostUsed &&
|
|
176
|
+
!search &&
|
|
177
|
+
index === mostUsedCountries.length - 1 &&
|
|
178
|
+
filteredCountries.length > mostUsedCountries.length;
|
|
179
|
+
return (_jsxs(React.Fragment, { children: [_jsxs("div", { onClick: () => handleCountrySelect(country), className: cn('flex cursor-pointer items-center gap-fds-sm rounded-fds-sm px-fds-sm py-fds-xs hover:bg-accent', isSelected && 'bg-accent'), children: [_jsx("img", { src: getCountryFlag(country.code), alt: country.code, className: "h-6 w-6 shrink-0 rounded-full object-cover" }), _jsx("span", { className: "flex-1 truncate text-fds-base", children: country.name }), _jsx("span", { className: "text-fds-sm text-fds-gray-60", children: country.dialCode })] }), isLastMostUsed && (_jsx("div", { className: "my-fds-xs h-px bg-border" }))] }, country.code));
|
|
180
|
+
})) })] }))] }));
|
|
181
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
const Popover = PopoverPrimitive.Root;
|
|
6
|
+
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
7
|
+
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, showArrow = false, ...props }, ref) => (_jsx(PopoverPrimitive.Portal, { children: _jsxs(PopoverPrimitive.Content, { ref: ref, align: align, sideOffset: sideOffset, className: cn("z-[1300] w-72 rounded-md bg-popover p-4 text-popover-foreground shadow-fds-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 origin-[--radix-popover-content-transform-origin]", className), ...props, children: [props.children, showArrow && (_jsx(PopoverPrimitive.Arrow, { className: "fill-popover", width: 16, height: 8 }))] }) })));
|
|
8
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
9
|
+
const PopoverArrow = PopoverPrimitive.Arrow;
|
|
10
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverArrow };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
const Progress = React.forwardRef(({ className, value, ...props }, ref) => (_jsx(ProgressPrimitive.Root, { ref: ref, className: cn("relative h-4 w-full overflow-hidden rounded-full bg-secondary", className), ...props, children: _jsx(ProgressPrimitive.Indicator, { className: "h-full w-full flex-1 bg-primary transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) })));
|
|
6
|
+
Progress.displayName = ProgressPrimitive.Root.displayName;
|
|
7
|
+
export { Progress };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../lib/utils';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { RadioGroup, RadioGroupItem } from './radio-group';
|
|
6
|
+
const radioButtonGroupItemVariants = cva('relative flex cursor-pointer items-center justify-center border bg-card px-[15px] transition-all has-[[data-state=checked]]:z-10', {
|
|
7
|
+
variants: {
|
|
8
|
+
size: {
|
|
9
|
+
small: 'h-[24px]',
|
|
10
|
+
medium: 'h-[32px]',
|
|
11
|
+
large: 'h-[40px]',
|
|
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
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
size: 'medium',
|
|
20
|
+
variant: 'default',
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
const RadioButtonGroup = React.forwardRef(({ className, children, size, borderRadius = 'lg', ...props }, ref) => {
|
|
24
|
+
const childrenArray = React.Children.toArray(children);
|
|
25
|
+
const childrenWithProps = childrenArray.map((child, index) => {
|
|
26
|
+
if (React.isValidElement(child)) {
|
|
27
|
+
const isFirst = index === 0;
|
|
28
|
+
const isLast = index === childrenArray.length - 1;
|
|
29
|
+
const roundedStart = borderRadius === 'full' ? 'rounded-s-full' : 'rounded-s-fds-md';
|
|
30
|
+
const roundedEnd = borderRadius === 'full' ? 'rounded-e-full' : 'rounded-e-fds-md';
|
|
31
|
+
const childProps = child.props;
|
|
32
|
+
return React.cloneElement(child, {
|
|
33
|
+
...childProps,
|
|
34
|
+
size: childProps.size ?? size ?? undefined,
|
|
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
|
+
});
|
|
42
|
+
RadioButtonGroup.displayName = 'RadioButtonGroup';
|
|
43
|
+
const RadioButtonGroupItem = React.forwardRef(({ className, value, id, size, variant, children, ...props }, ref) => {
|
|
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 };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../lib/utils';
|
|
5
|
+
const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
|
|
6
|
+
return (_jsx(RadioGroupPrimitive.Root, { className: cn('grid gap-2', className), ...props, ref: ref }));
|
|
7
|
+
});
|
|
8
|
+
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
|
|
9
|
+
const RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => {
|
|
10
|
+
return (_jsx(RadioGroupPrimitive.Item, { ref: ref, className: cn('aspect-square h-[16px] w-[16px] rounded-full border border-fds-gray-80 text-fds-blue ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-fds-blue', 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" }) }) }));
|
|
11
|
+
});
|
|
12
|
+
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
|
13
|
+
export { RadioGroup, RadioGroupItem };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { GripVertical } from 'lucide-react';
|
|
4
|
+
import * as ResizablePrimitive from 'react-resizable-panels';
|
|
5
|
+
import { cn } from '../lib/utils';
|
|
6
|
+
const ResizablePanelGroup = ({ className, ...props }) => (_jsx(ResizablePrimitive.PanelGroup, { className: cn('flex h-full w-full data-[panel-group-direction=vertical]:flex-col', className), ...props }));
|
|
7
|
+
const ResizablePanel = ResizablePrimitive.Panel;
|
|
8
|
+
const ResizableHandle = ({ withHandle, className, ...props }) => (_jsx(ResizablePrimitive.PanelResizeHandle, { className: cn('relative flex w-px items-center justify-center bg-fds-gray-20 dark:bg-fds-gray-70 after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-fds-blue-50 focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90', className), ...props, children: withHandle && (_jsx("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-fds-gray-20 bg-fds-gray-10 dark:border-fds-gray-70 dark:bg-fds-gray-80", children: _jsx(GripVertical, { className: "h-2.5 w-2.5" }) })) }));
|
|
9
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
|