@freightos/freightwind 1.1.0 → 1.1.1

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.
@@ -88,6 +88,6 @@ const Alert = ({ variant = 'info', title, message, closable = false, onClose, ca
88
88
  setVisible(false);
89
89
  onClose?.();
90
90
  }
91
- }, children: (0, jsx_runtime_1.jsx)("div", { style: { overflow: 'hidden' }, children: (0, jsx_runtime_1.jsx)(react_1.AnimatePresence, { initial: false, children: !closing && ((0, jsx_runtime_1.jsxs)(react_1.motion.div, { role: "alert", exit: { y: -20 }, transition: { duration: 0.15, ease: 'easeIn' }, className: (0, utils_1.cn)('flex w-full gap-fds-sm rounded-fds-md border-l-4 bg-card pr-fds-sm shadow-[0_0_10px_0_rgba(35,37,55,0.12)]', title ? 'items-start pl-fds-md py-fds-md' : 'items-center pl-fds-lg py-[5px]', config.borderColor), children: [(0, jsx_runtime_1.jsx)(Icon, { size: title ? 20 : 18, className: (0, utils_1.cn)('shrink-0', title && 'mt-[3px]', config.iconColor) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [title && (0, jsx_runtime_1.jsx)("div", { className: "text-fds-h5 font-fds-bold leading-fds-title text-foreground", children: title }), message && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('text-fds-base text-fds-gray-80 dark:text-white', title && 'mt-fds-xs'), children: message }))] }), showCta && (0, jsx_runtime_1.jsx)("div", { className: "shrink-0", children: callToAction }), showClose && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClose, className: "shrink-0 cursor-pointer text-fds-gray-90 hover:text-fds-gray-100 transition-colors", "aria-label": "Close alert", children: (0, jsx_runtime_1.jsx)(icons_1.IconClose, { size: 16 }) }))] })) }) }) }));
91
+ }, children: (0, jsx_runtime_1.jsx)("div", { style: { overflow: 'hidden' }, children: (0, jsx_runtime_1.jsx)(react_1.AnimatePresence, { initial: false, children: !closing && ((0, jsx_runtime_1.jsxs)(react_1.motion.div, { role: "alert", exit: { y: -20 }, transition: { duration: 0.15, ease: 'easeIn' }, className: (0, utils_1.cn)('flex w-full gap-fds-sm rounded-fds-md border-l-4 bg-card pr-fds-sm shadow-[0_0_10px_0_rgba(35,37,55,0.12)]', title ? 'items-start pl-fds-md py-fds-md' : 'items-center pl-fds-lg py-[5px]', config.borderColor), children: [(0, jsx_runtime_1.jsx)(Icon, { size: title ? 20 : 18, className: (0, utils_1.cn)('shrink-0', title && 'mt-[3px]', config.iconColor) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [title && (0, jsx_runtime_1.jsx)("div", { className: "text-fds-h5 font-fds-bold leading-fds-title text-foreground", children: title }), message && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('text-fds-base text-fds-gray-80 dark:text-white', title && 'mt-fds-xs'), children: message }))] }), showCta && (0, jsx_runtime_1.jsx)("div", { className: "shrink-0", children: callToAction }), showClose && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClose, className: "fw-base shrink-0 cursor-pointer text-fds-gray-90 hover:text-fds-gray-100 transition-colors", "aria-label": "Close alert", children: (0, jsx_runtime_1.jsx)(icons_1.IconClose, { size: 16 }) }))] })) }) }) }));
92
92
  };
93
93
  exports.Alert = Alert;
@@ -41,7 +41,7 @@ const React = __importStar(require("react"));
41
41
  const icon_utils_1 = require("../lib/icon-utils");
42
42
  const utils_1 = require("../lib/utils");
43
43
  const tooltip_1 = require("./tooltip");
44
- const buttonVariants = (0, class_variance_authority_1.cva)('inline-flex w-fit items-center justify-center gap-fds-sm whitespace-nowrap rounded-fds-md cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0', {
44
+ const buttonVariants = (0, class_variance_authority_1.cva)('fw-base inline-flex w-fit items-center justify-center gap-fds-sm whitespace-nowrap rounded-fds-md cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0', {
45
45
  variants: {
46
46
  variant: {
47
47
  default: 'bg-fds-blue-30 text-fds-white hover:bg-fds-blue-40',
@@ -49,7 +49,7 @@ const Checkbox = React.forwardRef(({ checked, onCheckedChange, disabled, error,
49
49
  setInternalChecked(val);
50
50
  onCheckedChange?.(val);
51
51
  };
52
- const box = ((0, jsx_runtime_1.jsx)(CheckboxPrimitive.Root, { ref: ref, id: checkboxId, checked: resolvedChecked, onCheckedChange: handleCheckedChange, disabled: disabled, "aria-invalid": error || undefined, className: (0, utils_1.cn)('peer size-4 shrink-0 rounded-fds-sm border cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', disabled
52
+ const box = ((0, jsx_runtime_1.jsx)(CheckboxPrimitive.Root, { ref: ref, id: checkboxId, checked: resolvedChecked, onCheckedChange: handleCheckedChange, disabled: disabled, "aria-invalid": error || undefined, className: (0, utils_1.cn)('fw-base peer size-4 shrink-0 rounded-fds-sm border cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', disabled
53
53
  ? 'cursor-not-allowed bg-fds-gray-10 border-fds-gray-20'
54
54
  : error
55
55
  ? 'border-fds-red-30 bg-fds-red-10 data-[state=checked]:bg-fds-red-30'
@@ -80,5 +80,5 @@ function Chip({ variant = 'default', icon, closable, onClose, badge, children, }
80
80
  };
81
81
  const IconComp = icon ? icon_utils_1.iconMap[icon] : null;
82
82
  const iconOnly = !!icon && !children;
83
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)(chipVariants({ variant }), iconOnly && 'justify-center', badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && '!pl-0.5'), children: [badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)('mr-1 inline-flex items-center justify-center rounded-full min-w-[16px] h-4 px-1 text-[10px] font-fds-semibold leading-none', badgeColors[variant]), children: typeof badge === 'number' && badge > 99 ? '99+' : badge })), IconComp && (0, jsx_runtime_1.jsx)(IconComp, { size: 12, className: children ? 'mr-fds-sm' : '' }), children, closable && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClose, "aria-label": "Remove", className: "ml-fds-sm inline-flex cursor-pointer items-center hover:opacity-70", children: (0, jsx_runtime_1.jsx)(icons_1.IconClose, { size: 10 }) }))] }));
83
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)(chipVariants({ variant }), iconOnly && 'justify-center', badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && '!pl-0.5'), children: [badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)('mr-1 inline-flex items-center justify-center rounded-full min-w-[16px] h-4 px-1 text-[10px] font-fds-semibold leading-none', badgeColors[variant]), children: typeof badge === 'number' && badge > 99 ? '99+' : badge })), IconComp && (0, jsx_runtime_1.jsx)(IconComp, { size: 12, className: children ? 'mr-fds-sm' : '' }), children, closable && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClose, "aria-label": "Remove", className: "fw-base ml-fds-sm inline-flex cursor-pointer items-center hover:opacity-70", children: (0, jsx_runtime_1.jsx)(icons_1.IconClose, { size: 10 }) }))] }));
84
84
  }
@@ -45,7 +45,7 @@ const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
45
45
  exports.RadioGroup = RadioGroup;
46
46
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
47
47
  const RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => {
48
- return ((0, jsx_runtime_1.jsx)(RadioGroupPrimitive.Item, { ref: ref, className: (0, utils_1.cn)('h-[16px] w-[16px] cursor-pointer rounded-full border border-fds-gray-30 bg-white ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:border-fds-gray-20 disabled:bg-fds-gray-10 data-[state=checked]:border-fds-blue-30 data-[state=checked]:disabled:border-fds-gray-30', className), ...props, children: (0, jsx_runtime_1.jsx)(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: (0, jsx_runtime_1.jsx)("div", { className: "h-[8px] w-[8px] rounded-full bg-fds-blue-30 [[disabled]_&]:bg-fds-gray-30" }) }) }));
48
+ return ((0, jsx_runtime_1.jsx)(RadioGroupPrimitive.Item, { ref: ref, className: (0, utils_1.cn)('fw-base h-[16px] w-[16px] cursor-pointer rounded-full border border-fds-gray-30 bg-white ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:border-fds-gray-20 disabled:bg-fds-gray-10 data-[state=checked]:border-fds-blue-30 data-[state=checked]:disabled:border-fds-gray-30', className), ...props, children: (0, jsx_runtime_1.jsx)(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: (0, jsx_runtime_1.jsx)("div", { className: "h-[8px] w-[8px] rounded-full bg-fds-blue-30 [[disabled]_&]:bg-fds-gray-30" }) }) }));
49
49
  });
50
50
  exports.RadioGroupItem = RadioGroupItem;
51
51
  RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
@@ -41,7 +41,7 @@ const React = __importStar(require("react"));
41
41
  const class_variance_authority_1 = require("class-variance-authority");
42
42
  const utils_1 = require("../lib/utils");
43
43
  const use_stable_id_1 = require("../lib/use-stable-id");
44
- const switchVariants = (0, class_variance_authority_1.cva)('peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50', {
44
+ const switchVariants = (0, class_variance_authority_1.cva)('fw-base peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50', {
45
45
  variants: {
46
46
  size: {
47
47
  lg: 'h-5 w-9',
@@ -52,5 +52,5 @@ export const Alert = ({ variant = 'info', title, message, closable = false, onCl
52
52
  setVisible(false);
53
53
  onClose?.();
54
54
  }
55
- }, children: _jsx("div", { style: { overflow: 'hidden' }, children: _jsx(AnimatePresence, { initial: false, children: !closing && (_jsxs(motion.div, { role: "alert", exit: { y: -20 }, transition: { duration: 0.15, ease: 'easeIn' }, className: cn('flex w-full gap-fds-sm rounded-fds-md border-l-4 bg-card pr-fds-sm shadow-[0_0_10px_0_rgba(35,37,55,0.12)]', title ? 'items-start pl-fds-md py-fds-md' : 'items-center pl-fds-lg py-[5px]', config.borderColor), children: [_jsx(Icon, { size: title ? 20 : 18, className: cn('shrink-0', title && 'mt-[3px]', config.iconColor) }), _jsxs("div", { className: "flex-1 min-w-0", children: [title && _jsx("div", { className: "text-fds-h5 font-fds-bold leading-fds-title text-foreground", children: title }), message && (_jsx("div", { className: cn('text-fds-base text-fds-gray-80 dark:text-white', title && 'mt-fds-xs'), children: message }))] }), showCta && _jsx("div", { className: "shrink-0", children: callToAction }), showClose && (_jsx("button", { type: "button", onClick: handleClose, className: "shrink-0 cursor-pointer text-fds-gray-90 hover:text-fds-gray-100 transition-colors", "aria-label": "Close alert", children: _jsx(IconClose, { size: 16 }) }))] })) }) }) }));
55
+ }, children: _jsx("div", { style: { overflow: 'hidden' }, children: _jsx(AnimatePresence, { initial: false, children: !closing && (_jsxs(motion.div, { role: "alert", exit: { y: -20 }, transition: { duration: 0.15, ease: 'easeIn' }, className: cn('flex w-full gap-fds-sm rounded-fds-md border-l-4 bg-card pr-fds-sm shadow-[0_0_10px_0_rgba(35,37,55,0.12)]', title ? 'items-start pl-fds-md py-fds-md' : 'items-center pl-fds-lg py-[5px]', config.borderColor), children: [_jsx(Icon, { size: title ? 20 : 18, className: cn('shrink-0', title && 'mt-[3px]', config.iconColor) }), _jsxs("div", { className: "flex-1 min-w-0", children: [title && _jsx("div", { className: "text-fds-h5 font-fds-bold leading-fds-title text-foreground", children: title }), message && (_jsx("div", { className: cn('text-fds-base text-fds-gray-80 dark:text-white', title && 'mt-fds-xs'), children: message }))] }), showCta && _jsx("div", { className: "shrink-0", children: callToAction }), showClose && (_jsx("button", { type: "button", onClick: handleClose, className: "fw-base shrink-0 cursor-pointer text-fds-gray-90 hover:text-fds-gray-100 transition-colors", "aria-label": "Close alert", children: _jsx(IconClose, { size: 16 }) }))] })) }) }) }));
56
56
  };
@@ -5,7 +5,7 @@ import * as React from 'react';
5
5
  import { iconMap } from '../lib/icon-utils';
6
6
  import { cn } from '../lib/utils';
7
7
  import { Tooltip } from './tooltip';
8
- const buttonVariants = cva('inline-flex w-fit items-center justify-center gap-fds-sm whitespace-nowrap rounded-fds-md cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0', {
8
+ const buttonVariants = cva('fw-base inline-flex w-fit items-center justify-center gap-fds-sm whitespace-nowrap rounded-fds-md cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0', {
9
9
  variants: {
10
10
  variant: {
11
11
  default: 'bg-fds-blue-30 text-fds-white hover:bg-fds-blue-40',
@@ -13,7 +13,7 @@ const Checkbox = React.forwardRef(({ checked, onCheckedChange, disabled, error,
13
13
  setInternalChecked(val);
14
14
  onCheckedChange?.(val);
15
15
  };
16
- const box = (_jsx(CheckboxPrimitive.Root, { ref: ref, id: checkboxId, checked: resolvedChecked, onCheckedChange: handleCheckedChange, disabled: disabled, "aria-invalid": error || undefined, className: cn('peer size-4 shrink-0 rounded-fds-sm border cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', disabled
16
+ const box = (_jsx(CheckboxPrimitive.Root, { ref: ref, id: checkboxId, checked: resolvedChecked, onCheckedChange: handleCheckedChange, disabled: disabled, "aria-invalid": error || undefined, className: cn('fw-base peer size-4 shrink-0 rounded-fds-sm border cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', disabled
17
17
  ? 'cursor-not-allowed bg-fds-gray-10 border-fds-gray-20'
18
18
  : error
19
19
  ? 'border-fds-red-30 bg-fds-red-10 data-[state=checked]:bg-fds-red-30'
@@ -42,6 +42,6 @@ function Chip({ variant = 'default', icon, closable, onClose, badge, children, }
42
42
  };
43
43
  const IconComp = icon ? iconMap[icon] : null;
44
44
  const iconOnly = !!icon && !children;
45
- return (_jsxs("div", { className: cn(chipVariants({ variant }), iconOnly && 'justify-center', badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && '!pl-0.5'), children: [badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && (_jsx("span", { className: cn('mr-1 inline-flex items-center justify-center rounded-full min-w-[16px] h-4 px-1 text-[10px] font-fds-semibold leading-none', badgeColors[variant]), children: typeof badge === 'number' && badge > 99 ? '99+' : badge })), IconComp && _jsx(IconComp, { size: 12, className: children ? 'mr-fds-sm' : '' }), children, closable && (_jsx("button", { type: "button", onClick: handleClose, "aria-label": "Remove", className: "ml-fds-sm inline-flex cursor-pointer items-center hover:opacity-70", children: _jsx(IconClose, { size: 10 }) }))] }));
45
+ return (_jsxs("div", { className: cn(chipVariants({ variant }), iconOnly && 'justify-center', badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && '!pl-0.5'), children: [badge !== undefined && (typeof badge === 'string' ? badge.length > 0 : badge > 0) && (_jsx("span", { className: cn('mr-1 inline-flex items-center justify-center rounded-full min-w-[16px] h-4 px-1 text-[10px] font-fds-semibold leading-none', badgeColors[variant]), children: typeof badge === 'number' && badge > 99 ? '99+' : badge })), IconComp && _jsx(IconComp, { size: 12, className: children ? 'mr-fds-sm' : '' }), children, closable && (_jsx("button", { type: "button", onClick: handleClose, "aria-label": "Remove", className: "fw-base ml-fds-sm inline-flex cursor-pointer items-center hover:opacity-70", children: _jsx(IconClose, { size: 10 }) }))] }));
46
46
  }
47
47
  export { Chip, chipVariants };
@@ -8,7 +8,7 @@ const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
8
8
  });
9
9
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
10
10
  const RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => {
11
- return (_jsx(RadioGroupPrimitive.Item, { ref: ref, className: cn('h-[16px] w-[16px] cursor-pointer rounded-full border border-fds-gray-30 bg-white ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:border-fds-gray-20 disabled:bg-fds-gray-10 data-[state=checked]:border-fds-blue-30 data-[state=checked]:disabled:border-fds-gray-30', className), ...props, children: _jsx(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: _jsx("div", { className: "h-[8px] w-[8px] rounded-full bg-fds-blue-30 [[disabled]_&]:bg-fds-gray-30" }) }) }));
11
+ return (_jsx(RadioGroupPrimitive.Item, { ref: ref, className: cn('fw-base h-[16px] w-[16px] cursor-pointer rounded-full border border-fds-gray-30 bg-white ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:border-fds-gray-20 disabled:bg-fds-gray-10 data-[state=checked]:border-fds-blue-30 data-[state=checked]:disabled:border-fds-gray-30', className), ...props, children: _jsx(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: _jsx("div", { className: "h-[8px] w-[8px] rounded-full bg-fds-blue-30 [[disabled]_&]:bg-fds-gray-30" }) }) }));
12
12
  });
13
13
  RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
14
14
  export { RadioGroup, RadioGroupItem };
@@ -5,7 +5,7 @@ import * as React from 'react';
5
5
  import { cva } from 'class-variance-authority';
6
6
  import { cn } from '../lib/utils';
7
7
  import { useStableId } from '../lib/use-stable-id';
8
- const switchVariants = cva('peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50', {
8
+ const switchVariants = cva('fw-base peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fds-blue-30 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50', {
9
9
  variants: {
10
10
  size: {
11
11
  lg: 'h-5 w-9',
@@ -0,0 +1,54 @@
1
+ # FreightWind Design System
2
+
3
+ FreightWind is the Freightos Design System — a React component library styled with Tailwind CSS v4 and FDS (Freightos Design System) tokens.
4
+
5
+ ## Setup
6
+
7
+ FreightWind requires two imports:
8
+
9
+ 1. **CSS tokens** — import the token stylesheet in your root layout or global CSS:
10
+
11
+ ```css
12
+ @import "@freightos/freightwind/tokens.css";
13
+ ```
14
+
15
+ 2. **Components** — import components from the package:
16
+
17
+ ```tsx
18
+ import { Button, Alert, Checkbox } from '@freightos/freightwind';
19
+ ```
20
+
21
+ 3. **Icons** — icons come from the `@freightos/icons` peer dependency:
22
+
23
+ ```tsx
24
+ import { IconSearch, IconClose, IconUser } from '@freightos/icons';
25
+ ```
26
+
27
+ Components that accept an `icon` prop use kebab-case icon names (e.g. `icon="search"`, `icon="close"`), not direct icon imports.
28
+
29
+ ## Tailwind CSS requirement
30
+
31
+ FreightWind components use Tailwind CSS v4 utility classes. Your project must have Tailwind CSS configured. The `tokens.css` file provides all necessary theme tokens and custom utilities.
32
+
33
+ ## Available components
34
+
35
+ See `overview-components.md` for a full list of components with their props and usage.
36
+
37
+ ## Available icons
38
+
39
+ See `overview-icons.md` for details on the icon system.
40
+
41
+ ## Design tokens
42
+
43
+ FreightWind uses a custom token system instead of Tailwind defaults:
44
+
45
+ - **Colors**: `overview-design-tokens/colors.md` — semantic color palette (blue, red, green, yellow, gray, purple)
46
+ - **Typography**: `overview-design-tokens/typography.md` — font sizes, weights, and line heights
47
+ - **Spacing**: `overview-design-tokens/spacing.md` — consistent spacing scale
48
+
49
+ ## Key conventions
50
+
51
+ - Always use FDS tokens (`text-fds-*`, `p-fds-*`, `rounded-fds-*`, `bg-fds-*`) instead of Tailwind defaults
52
+ - All components support both controlled and uncontrolled usage patterns
53
+ - Components with `icon` props accept kebab-case icon names: `"search"`, `"close"`, `"user"`, `"risk"`, etc.
54
+ - Use `cn()` utility (exported from the package) for className merging
@@ -0,0 +1,81 @@
1
+ # Color Tokens
2
+
3
+ FreightWind uses the FDS (Freightos Design System) color palette. Always use FDS color tokens instead of Tailwind defaults.
4
+
5
+ ## Primary — Blue
6
+
7
+ The primary action color. Use for buttons, links, and interactive elements.
8
+
9
+ | Token | Class | Usage |
10
+ |-------|-------|-------|
11
+ | Blue 05 | `bg-fds-blue-05` | Disabled checked state |
12
+ | Blue 10 | `bg-fds-blue-10` | Hover backgrounds, selected states |
13
+ | Blue 20 | `bg-fds-blue-20` | Light accent backgrounds |
14
+ | Blue 30 | `bg-fds-blue-30`, `text-fds-blue-30` | Primary action color (default) |
15
+ | Blue 40 | `bg-fds-blue-40`, `text-fds-blue-40` | Hover state for primary actions |
16
+ | Blue 50 | `bg-fds-blue-50` | Active/pressed state |
17
+
18
+ ## Semantic — Red (Error/Danger)
19
+
20
+ | Token | Class | Usage |
21
+ |-------|-------|-------|
22
+ | Red 10 | `bg-fds-red-10` | Error background tint |
23
+ | Red 20 | `bg-fds-red-20` | Error chip background |
24
+ | Red 30 | `bg-fds-red-30`, `text-fds-red-30` | Error/danger primary |
25
+ | Red 40 | `bg-fds-red-40` | Error hover state |
26
+
27
+ ## Semantic — Green (Success)
28
+
29
+ | Token | Class | Usage |
30
+ |-------|-------|-------|
31
+ | Green 20 | `bg-fds-green-20` | Success background tint |
32
+ | Green 30 | `bg-fds-green-30`, `text-fds-green-30` | Success primary |
33
+ | Green 40 | `bg-fds-green-40` | Success strong |
34
+
35
+ ## Semantic — Yellow (Warning)
36
+
37
+ | Token | Class | Usage |
38
+ |-------|-------|-------|
39
+ | Yellow 20 | `bg-fds-yellow-20` | Warning background tint |
40
+ | Yellow 30 | `bg-fds-yellow-30`, `text-fds-yellow-30` | Warning primary |
41
+ | Yellow 50 | `bg-fds-yellow-50` | Warning strong |
42
+
43
+ ## Gray Scale
44
+
45
+ Use for text, borders, backgrounds, and disabled states.
46
+
47
+ | Token | Class | Usage |
48
+ |-------|-------|-------|
49
+ | Gray 05 | `bg-fds-gray-05` | Lightest background |
50
+ | Gray 10 | `bg-fds-gray-10` | Disabled background |
51
+ | Gray 20 | `bg-fds-gray-20` | Disabled borders, light backgrounds |
52
+ | Gray 30 | `bg-fds-gray-30` | Default borders |
53
+ | Gray 40 | `bg-fds-gray-40` | Muted icons |
54
+ | Gray 60 | `bg-fds-gray-60`, `text-fds-gray-60` | Disabled text, secondary text |
55
+ | Gray 80 | `text-fds-gray-80` | Body text |
56
+ | Gray 90 | `text-fds-gray-90` | Dark text |
57
+ | Gray 100 | `text-fds-gray-100`, `bg-fds-gray-100` | Darkest text, tooltip bg |
58
+
59
+ ## Accent — Purple
60
+
61
+ | Token | Class | Usage |
62
+ |-------|-------|-------|
63
+ | Purple 1 | `text-fds-purple-1` | Accent text |
64
+ | Purple 2 | `bg-fds-purple-2` | Accent background |
65
+
66
+ ## White
67
+
68
+ | Token | Class | Usage |
69
+ |-------|-------|-------|
70
+ | White | `text-fds-white`, `bg-fds-white` | White text/backgrounds |
71
+
72
+ ## Decision guide
73
+
74
+ - **Primary actions** (buttons, links): `fds-blue-30`
75
+ - **Destructive actions**: `fds-red-30`
76
+ - **Success states**: `fds-green-30`
77
+ - **Warning states**: `fds-yellow-30`
78
+ - **Body text**: `fds-gray-80`
79
+ - **Disabled text**: `fds-gray-60`
80
+ - **Borders**: `fds-gray-30` (default), `fds-gray-20` (disabled)
81
+ - **Page background**: `bg-ground`
@@ -0,0 +1,45 @@
1
+ # Spacing Tokens
2
+
3
+ FreightWind uses FDS spacing tokens for consistent sizing. Use these instead of Tailwind defaults.
4
+
5
+ ## Spacing scale
6
+
7
+ | Token | Class prefix | Size | Usage |
8
+ |-------|-------------|------|-------|
9
+ | XS | `p-fds-xs`, `m-fds-xs`, `gap-fds-xs` | 4px | Tight spacing (icon gaps, small padding) |
10
+ | SM | `p-fds-sm`, `m-fds-sm`, `gap-fds-sm` | 8px | Default component internal spacing |
11
+ | MD | `p-fds-md`, `m-fds-md`, `gap-fds-md` | 12px | Medium padding, form field spacing |
12
+ | LG | `p-fds-lg`, `m-fds-lg`, `gap-fds-lg` | 16px | Section padding, card padding |
13
+ | XL | `p-fds-xl`, `m-fds-xl`, `gap-fds-xl` | 24px | Large section spacing |
14
+ | XXL | `p-fds-xxl`, `m-fds-xxl`, `gap-fds-xxl` | 32px | Page-level spacing |
15
+
16
+ All spacing tokens work with Tailwind's full set of utility prefixes: `p-`, `px-`, `py-`, `pt-`, `pr-`, `pb-`, `pl-`, `m-`, `mx-`, `my-`, `mt-`, `mr-`, `mb-`, `ml-`, `gap-`, `gap-x-`, `gap-y-`.
17
+
18
+ ## Border radius
19
+
20
+ | Token | Class | Value | Usage |
21
+ |-------|-------|-------|-------|
22
+ | SM | `rounded-fds-sm` | 2px | Checkboxes, small elements |
23
+ | MD | `rounded-fds-md` | 4px | Buttons, inputs, cards |
24
+ | LG | `rounded-fds-lg` | 8px | Modals, popovers |
25
+
26
+ ## Shadows
27
+
28
+ | Token | Class | Usage |
29
+ |-------|-------|-------|
30
+ | SM | `shadow-fds-sm` | Subtle elevation (dropdowns) |
31
+ | MD | `shadow-fds-md` | Medium elevation (cards, popovers) |
32
+ | LG | `shadow-fds-lg` | High elevation (modals) |
33
+
34
+ ## Usage example
35
+
36
+ ```tsx
37
+ <div className="p-fds-lg rounded-fds-md shadow-fds-sm">
38
+ <h2 className="mb-fds-sm text-fds-h5 font-fds-bold">Card Title</h2>
39
+ <p className="text-fds-base text-fds-gray-80">Card content with consistent spacing.</p>
40
+ <div className="mt-fds-md flex gap-fds-sm">
41
+ <Button variant="default">Confirm</Button>
42
+ <Button variant="secondary">Cancel</Button>
43
+ </div>
44
+ </div>
45
+ ```
@@ -0,0 +1,50 @@
1
+ # Typography Tokens
2
+
3
+ FreightWind uses FDS typography tokens. Always use these instead of Tailwind default sizes.
4
+
5
+ ## Font sizes
6
+
7
+ | Token | Class | Size | Usage |
8
+ |-------|-------|------|-------|
9
+ | XS | `text-fds-xs` | 10px | Captions, fine print |
10
+ | SM | `text-fds-sm` | 12px | Small labels, badges, chips |
11
+ | Base | `text-fds-base` | 14px | Body text (default) |
12
+ | H6 | `text-fds-h6` | 16px | Small headings, large labels |
13
+ | H5 | `text-fds-h5` | 18px | Section headings |
14
+ | H4 | `text-fds-h4` | 22px | Page sub-headings |
15
+ | H3 | `text-fds-h3` | 24px | Page headings |
16
+ | H2 | `text-fds-h2` | 32px | Major headings |
17
+ | H1 | `text-fds-h1` | 40px | Hero headings |
18
+
19
+ ## Font weights
20
+
21
+ | Token | Class | Weight | Usage |
22
+ |-------|-------|--------|-------|
23
+ | Regular | `font-fds-regular` | 400 | Body text |
24
+ | Semibold | `font-fds-semibold` | 600 | Labels, emphasis |
25
+ | Bold | `font-fds-bold` | 700 | Headings, strong emphasis |
26
+
27
+ ## Line heights
28
+
29
+ | Token | Class | Value | Usage |
30
+ |-------|-------|-------|-------|
31
+ | Title | `leading-fds-title` | 1.25 | Headings (h1-h6) |
32
+ | Body | `leading-fds-body` | 1.5 | Body text, paragraphs |
33
+
34
+ ## Usage patterns
35
+
36
+ ```tsx
37
+ // Page heading
38
+ <h1 className="text-fds-h3 font-fds-bold leading-fds-title text-foreground">Page Title</h1>
39
+
40
+ // Body text
41
+ <p className="text-fds-base text-fds-gray-80">Body content here.</p>
42
+
43
+ // Small label
44
+ <span className="text-fds-sm font-fds-semibold text-fds-gray-60">Label</span>
45
+
46
+ // Caption
47
+ <span className="text-fds-xs text-fds-gray-60">Fine print</span>
48
+ ```
49
+
50
+ Heading size classes (`text-fds-h1` through `text-fds-h6`) set font-size only. Always pair with `leading-fds-title` for proper line height.
@@ -0,0 +1,252 @@
1
+ # Components Overview
2
+
3
+ ## Component list
4
+
5
+ | Component | Purpose | Key props |
6
+ |-----------|---------|-----------|
7
+ | `Button` | Primary action trigger | `variant`, `size`, `icon`, `loading`, `tooltip`, `fullWidth` |
8
+ | `Alert` | Contextual feedback banner | `variant`, `title`, `message`, `closable`, `callToAction` |
9
+ | `Avatar` | User or entity representation | `variant`, `size`, `icon`, `title`, `flag`, `src` |
10
+ | `Badge` | Numeric indicator or status dot | `value`, `size`, `variant`, `status`, `text` |
11
+ | `Checkbox` | Boolean or indeterminate toggle | `checked`, `onCheckedChange`, `disabled`, `error`, `children` |
12
+ | `Chip` | Compact label with optional badge | `variant`, `icon`, `closable`, `badge`, `children` |
13
+ | `MessageProvider` / `message` | Toast notifications | Provider wraps app; `message.success()`, `.info()`, `.warning()`, `.error()` |
14
+ | `PopConfirm` | Confirmation popover | `title`, `onConfirm`, `onCancel`, `placement`, `slotProps` |
15
+ | `RadioButtonGroup` | Segmented button selection | `options`, `value`, `onValueChange`, `size`, `orientation` |
16
+ | `RadioGroup` / `RadioGroupItem` | Traditional radio selection | Standard Radix RadioGroup API |
17
+ | `Slider` | Range value selector | `value`, `onValueChange`, `min`, `max`, `step` |
18
+ | `Switch` | On/off toggle | `checked`, `onCheckedChange`, `disabled`, `error`, `size`, `children` |
19
+ | `Tooltip` | Contextual hover information | `message`, `placement`, `children` |
20
+
21
+ ## Button
22
+
23
+ The most commonly used component. Always use `Button` for clickable actions.
24
+
25
+ ```tsx
26
+ import { Button } from '@freightos/freightwind';
27
+
28
+ // Primary action
29
+ <Button variant="default" size="md">Submit</Button>
30
+
31
+ // Secondary action
32
+ <Button variant="secondary">Cancel</Button>
33
+
34
+ // Danger action
35
+ <Button variant="danger">Delete</Button>
36
+
37
+ // Icon-only button (tooltip is required)
38
+ <Button icon="search" tooltip="Search" />
39
+
40
+ // Loading state
41
+ <Button loading>Saving...</Button>
42
+
43
+ // Toggle button
44
+ <Button variant="toggle" active={isActive}>Grid View</Button>
45
+ ```
46
+
47
+ **Variants**: `default` (primary blue), `secondary` (outlined blue), `tertiary` (text-only blue), `link` (text link), `danger` (red), `danger-ghost` (outlined red), `toggle` (gray border, blue when active).
48
+
49
+ **Sizes**: `sm` (24px height), `md` (32px height, default), `lg` (40px height).
50
+
51
+ **Icon-only buttons** must have a `tooltip` prop for accessibility. Pass icon names in kebab-case: `icon="search"`, `icon="close"`, `icon="settings"`.
52
+
53
+ ## Alert
54
+
55
+ Contextual feedback banner with icon, optional title, message, and close button.
56
+
57
+ ```tsx
58
+ import { Alert } from '@freightos/freightwind';
59
+
60
+ // Simple message-only alert
61
+ <Alert variant="info" message="Your shipment has been updated." />
62
+
63
+ // Alert with title
64
+ <Alert variant="warning" title="Attention" message="Rate expires in 24 hours." />
65
+
66
+ // Closable alert
67
+ <Alert variant="success" message="Saved!" closable onClose={() => {}} />
68
+
69
+ // Alert with call-to-action (only when no title)
70
+ <Alert variant="error" message="Connection failed." callToAction={<Button size="sm" variant="danger">Retry</Button>} />
71
+ ```
72
+
73
+ **Variants**: `info` (blue), `success` (green), `warning` (yellow), `error` (red), `special` (purple).
74
+
75
+ ## Avatar
76
+
77
+ User or entity representation. Content priority: `src` > `flag` > `title` > `icon` > default user placeholder.
78
+
79
+ ```tsx
80
+ import { Avatar } from '@freightos/freightwind';
81
+
82
+ // Image avatar
83
+ <Avatar src="https://example.com/photo.jpg" alt="John" />
84
+
85
+ // Country flag
86
+ <Avatar flag="US" />
87
+
88
+ // Initial letter
89
+ <Avatar title="John Doe" />
90
+
91
+ // Icon avatar
92
+ <Avatar icon="settings" variant="info" />
93
+
94
+ // Sized avatar
95
+ <Avatar title="JD" size="lg" bordered />
96
+ ```
97
+
98
+ **Sizes**: `xs` (16px), `sm` (24px), `md` (32px, default), `lg` (40px), `xl` (58px).
99
+
100
+ **Variants**: `default` (purple), `info` (blue), `secondary` (light blue), `warning` (yellow), `neutral` (gray), `positive` (green), `filled` (white bg), `ghost` (transparent).
101
+
102
+ ## Badge
103
+
104
+ Numeric indicator or status dot. Can wrap a child element for positioning.
105
+
106
+ ```tsx
107
+ import { Badge } from '@freightos/freightwind';
108
+
109
+ // Standalone count badge
110
+ <Badge value={5} />
111
+
112
+ // Badge wrapping an icon/button
113
+ <Badge value={3}><IconBell size={20} /></Badge>
114
+
115
+ // Status dot with text
116
+ <Badge status="success" text="Active" />
117
+
118
+ // Numbers over 99 display as "99+"
119
+ <Badge value={150} />
120
+ ```
121
+
122
+ ## Checkbox
123
+
124
+ Boolean or indeterminate toggle with optional label.
125
+
126
+ ```tsx
127
+ import { Checkbox } from '@freightos/freightwind';
128
+
129
+ // With label
130
+ <Checkbox checked={value} onCheckedChange={setValue}>Accept terms</Checkbox>
131
+
132
+ // Without label
133
+ <Checkbox checked={value} onCheckedChange={setValue} />
134
+
135
+ // Indeterminate state
136
+ <Checkbox checked="indeterminate" onCheckedChange={setValue}>Select all</Checkbox>
137
+
138
+ // Error state
139
+ <Checkbox error>Required field</Checkbox>
140
+ ```
141
+
142
+ ## Chip
143
+
144
+ Compact label with optional icon, badge, and close button.
145
+
146
+ ```tsx
147
+ import { Chip } from '@freightos/freightwind';
148
+
149
+ // Basic chip
150
+ <Chip>Active</Chip>
151
+
152
+ // With variant and icon
153
+ <Chip variant="success" icon="check-circled">Approved</Chip>
154
+
155
+ // With badge count
156
+ <Chip variant="info" badge={3}>Notifications</Chip>
157
+
158
+ // Closable
159
+ <Chip closable onClose={() => {}}>Filter</Chip>
160
+ ```
161
+
162
+ **Variants**: `default` (purple), `neutral` (gray), `info` (light blue), `highlight` (bright blue), `warning` (yellow), `success` (green), `notice` (light red), `error` (red).
163
+
164
+ ## Switch
165
+
166
+ On/off toggle with optional label.
167
+
168
+ ```tsx
169
+ import { Switch } from '@freightos/freightwind';
170
+
171
+ // With label
172
+ <Switch checked={value} onCheckedChange={setValue}>Enable notifications</Switch>
173
+
174
+ // Without label
175
+ <Switch checked={value} onCheckedChange={setValue} />
176
+
177
+ // Sizes
178
+ <Switch size="sm">Small switch</Switch>
179
+ <Switch size="lg">Large switch</Switch>
180
+ ```
181
+
182
+ ## RadioButtonGroup
183
+
184
+ Segmented button selector. Use for choosing between 2-5 mutually exclusive options.
185
+
186
+ ```tsx
187
+ import { RadioButtonGroup } from '@freightos/freightwind';
188
+
189
+ <RadioButtonGroup
190
+ options={[
191
+ { value: 'list', label: 'List' },
192
+ { value: 'grid', label: 'Grid' },
193
+ { value: 'map', label: 'Map' },
194
+ ]}
195
+ value={view}
196
+ onValueChange={setView}
197
+ size="md"
198
+ />
199
+ ```
200
+
201
+ ## Slider
202
+
203
+ Range value selector.
204
+
205
+ ```tsx
206
+ import { Slider } from '@freightos/freightwind';
207
+
208
+ <Slider value={[50]} onValueChange={setValue} min={0} max={100} step={1} />
209
+ ```
210
+
211
+ ## Tooltip
212
+
213
+ Hover tooltip. Wraps any element.
214
+
215
+ ```tsx
216
+ import { Tooltip } from '@freightos/freightwind';
217
+
218
+ <Tooltip message="Click to save" placement="top">
219
+ <Button>Save</Button>
220
+ </Tooltip>
221
+ ```
222
+
223
+ **Placements**: `top`, `bottom`, `start`, `end`, `top-start`, `top-end`, `bottom-start`, `bottom-end`.
224
+
225
+ ## PopConfirm
226
+
227
+ Confirmation popover. Wraps a trigger element.
228
+
229
+ ```tsx
230
+ import { PopConfirm } from '@freightos/freightwind';
231
+
232
+ <PopConfirm title="Are you sure you want to delete this?" onConfirm={handleDelete}>
233
+ <Button variant="danger">Delete</Button>
234
+ </PopConfirm>
235
+ ```
236
+
237
+ ## MessageProvider / message
238
+
239
+ Toast notification system. Add `MessageProvider` once at the app root, then call `message.*()` anywhere.
240
+
241
+ ```tsx
242
+ import { MessageProvider, message } from '@freightos/freightwind';
243
+
244
+ // In your root layout:
245
+ <MessageProvider />
246
+
247
+ // Anywhere in your app:
248
+ message.success('Shipment created successfully');
249
+ message.error('Failed to save changes');
250
+ message.warning('Rate expires soon');
251
+ message.info('New update available');
252
+ ```
@@ -0,0 +1,52 @@
1
+ # Icons
2
+
3
+ FreightWind uses `@freightos/icons` as a peer dependency for all iconography.
4
+
5
+ ## Direct icon imports
6
+
7
+ For standalone icon usage, import directly from `@freightos/icons`:
8
+
9
+ ```tsx
10
+ import { IconSearch, IconClose, IconUser, IconRisk } from '@freightos/icons';
11
+
12
+ <IconSearch size={16} />
13
+ <IconClose size={20} className="text-fds-gray-80" />
14
+ ```
15
+
16
+ All icons accept `size` (number, in px) and `className` props. Icons inherit `currentColor` by default.
17
+
18
+ ## Icon prop on components
19
+
20
+ Components like `Button`, `Avatar`, and `Chip` accept an `icon` prop with a kebab-case name string:
21
+
22
+ ```tsx
23
+ <Button icon="search" tooltip="Search" />
24
+ <Avatar icon="settings" />
25
+ <Chip icon="check-circled">Done</Chip>
26
+ ```
27
+
28
+ Do NOT pass React components to the `icon` prop — use the kebab-case string name.
29
+
30
+ ## Common icon names
31
+
32
+ | Name | Component | Usage |
33
+ |------|-----------|-------|
34
+ | `search` | `IconSearch` | Search actions |
35
+ | `close` | `IconClose` | Close/dismiss actions |
36
+ | `user` | `IconUser` | User profiles |
37
+ | `settings` | `IconSettings` | Settings/gear |
38
+ | `risk` | `IconRisk` | Warning/caution |
39
+ | `check-circled` | `IconCheckCircled` | Success/confirmation |
40
+ | `info-circled` | `IconInfoCircled` | Information |
41
+ | `negative-circled` | `IconNegativeCircled` | Error/negative |
42
+ | `arrow-down` | `IconArrowDown` | Directional |
43
+ | `arrow-up` | `IconArrowUp` | Directional |
44
+ | `edit` | `IconEdit` | Edit actions |
45
+ | `delete` | `IconDelete` | Delete actions |
46
+ | `download` | `IconDownload` | Download actions |
47
+ | `upload` | `IconUpload` | Upload actions |
48
+ | `bookmark` | `IconBookmark` | Bookmark/save |
49
+
50
+ ## Icon style
51
+
52
+ All icons use stroke-only outlines (`stroke="currentColor"`). They are designed at 24px but scale cleanly to any size.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freightos/freightwind",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "private": false,
5
5
  "description": "FreightWind Design System — React UI components for Freightos applications",
6
6
  "main": "./dist/cjs/index.js",
@@ -18,6 +18,7 @@
18
18
  "files": [
19
19
  "dist",
20
20
  "tokens.css",
21
+ "guidelines",
21
22
  "README.md",
22
23
  "LICENSE"
23
24
  ],
package/tokens.css CHANGED
@@ -385,3 +385,25 @@
385
385
  @utility text-fds-h6 {
386
386
  font-size: var(--text-fds-h6);
387
387
  }
388
+
389
+ /* Scoped preflight for FreightWind components.
390
+ Apply to native form elements (<button>, <input>, <textarea>, <select>)
391
+ so components work without global Tailwind preflight. */
392
+ @utility fw-base {
393
+ box-sizing: border-box;
394
+ margin: 0;
395
+ padding: 0;
396
+ border: 0 solid var(--border, currentColor);
397
+ font: inherit;
398
+ font-feature-settings: inherit;
399
+ font-variation-settings: inherit;
400
+ letter-spacing: inherit;
401
+ color: inherit;
402
+ background-color: transparent;
403
+ border-radius: 0;
404
+ line-height: inherit;
405
+ -webkit-appearance: none;
406
+ appearance: none;
407
+ -webkit-font-smoothing: antialiased;
408
+ -moz-osx-font-smoothing: grayscale;
409
+ }