mautourco-components 0.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.
- package/README.md +187 -0
- package/dist/components/atoms/Avatar/Avatar.d.ts +14 -0
- package/dist/components/atoms/Avatar/Avatar.js +31 -0
- package/dist/components/atoms/Button/Button.d.ts +27 -0
- package/dist/components/atoms/Button/Button.js +35 -0
- package/dist/components/atoms/Checkbox/Checkbox.d.ts +13 -0
- package/dist/components/atoms/Checkbox/Checkbox.js +33 -0
- package/dist/components/atoms/Icon/Icon.d.ts +10 -0
- package/dist/components/atoms/Icon/Icon.js +102 -0
- package/dist/components/atoms/Icon/icons/ArrivalIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/ArrivalIcon.js +31 -0
- package/dist/components/atoms/Icon/icons/CalendarIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/CalendarIcon.js +41 -0
- package/dist/components/atoms/Icon/icons/CarIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/CarIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/Check.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/Check.js +30 -0
- package/dist/components/atoms/Icon/icons/CheckCircleIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/CheckCircleIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/Chevron.d.ts +9 -0
- package/dist/components/atoms/Icon/icons/Chevron.js +54 -0
- package/dist/components/atoms/Icon/icons/ChevronDownIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/ChevronDownIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/Close.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/Close.js +30 -0
- package/dist/components/atoms/Icon/icons/DeleteIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/DeleteIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/DepartureIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/DepartureIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/EyeIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/EyeIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/FacebookIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/FacebookIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/InfoIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/InfoIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/LinkedInIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/LinkedInIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/MapPinIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/MapPinIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/MautoucoLogo.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/MautoucoLogo.js +37 -0
- package/dist/components/atoms/Icon/icons/MenuIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/MenuIcon.js +37 -0
- package/dist/components/atoms/Icon/icons/MoreIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/MoreIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/Search.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/Search.js +30 -0
- package/dist/components/atoms/Icon/icons/Settings.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/Settings.js +30 -0
- package/dist/components/atoms/Icon/icons/StrollerIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/StrollerIcon.js +30 -0
- package/dist/components/atoms/Icon/icons/TwitterIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/TwitterIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/User.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/User.js +30 -0
- package/dist/components/atoms/Icon/icons/UserIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/UserIcon.js +41 -0
- package/dist/components/atoms/Icon/icons/Youtube.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/Youtube.js +36 -0
- package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.d.ts +12 -0
- package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.js +53 -0
- package/dist/components/atoms/Inputs/Input/Input.d.ts +15 -0
- package/dist/components/atoms/Inputs/Input/Input.js +27 -0
- package/dist/components/atoms/Inputs/Textarea/Textarea.d.ts +14 -0
- package/dist/components/atoms/Inputs/Textarea/Textarea.js +15 -0
- package/dist/components/atoms/Link/Link.d.ts +44 -0
- package/dist/components/atoms/Link/Link.js +76 -0
- package/dist/components/atoms/SelectedValue/SelectedValue.d.ts +11 -0
- package/dist/components/atoms/SelectedValue/SelectedValue.js +29 -0
- package/dist/components/atoms/Spinner/Spinner.d.ts +9 -0
- package/dist/components/atoms/Spinner/Spinner.js +38 -0
- package/dist/components/atoms/Spinner/variants/ButtonSpinner.d.ts +8 -0
- package/dist/components/atoms/Spinner/variants/ButtonSpinner.js +19 -0
- package/dist/components/atoms/Spinner/variants/LoadingSpinner.d.ts +7 -0
- package/dist/components/atoms/Spinner/variants/LoadingSpinner.js +7 -0
- package/dist/components/atoms/Tab/Tab.d.ts +22 -0
- package/dist/components/atoms/Tab/Tab.js +54 -0
- package/dist/components/atoms/Typography/Heading/Heading.d.ts +9 -0
- package/dist/components/atoms/Typography/Heading/Heading.js +25 -0
- package/dist/components/atoms/Typography/Text/Text.d.ts +10 -0
- package/dist/components/atoms/Typography/Text/Text.js +77 -0
- package/dist/components/atoms/Typography/Typography.d.ts +24 -0
- package/dist/components/atoms/Typography/Typography.js +100 -0
- package/dist/components/molecules/MultiSelectDropdown/MultiSelectDropdown.d.ts +29 -0
- package/dist/components/molecules/MultiSelectDropdown/MultiSelectDropdown.js +106 -0
- package/dist/components/molecules/UserCard/UserCard.d.ts +20 -0
- package/dist/components/molecules/UserCard/UserCard.js +57 -0
- package/dist/components/organisms/Footer/Footer.d.ts +38 -0
- package/dist/components/organisms/Footer/Footer.js +74 -0
- package/dist/components/organisms/TopNavigation/DesktopNav.d.ts +33 -0
- package/dist/components/organisms/TopNavigation/DesktopNav.js +26 -0
- package/dist/components/organisms/TopNavigation/MobileNav.d.ts +32 -0
- package/dist/components/organisms/TopNavigation/MobileNav.js +45 -0
- package/dist/components/organisms/TopNavigation/TopNavigation.d.ts +33 -0
- package/dist/components/organisms/TopNavigation/TopNavigation.js +20 -0
- package/dist/hooks/useMobile.d.ts +5 -0
- package/dist/hooks/useMobile.js +26 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +28 -0
- package/dist/styles/tokens/tokens.d.ts +3108 -0
- package/dist/styles/tokens/tokens.js +2652 -0
- package/package.json +90 -0
- package/src/components/atoms/Avatar/Avatar.tsx +60 -0
- package/src/components/atoms/Button/Button.css +200 -0
- package/src/components/atoms/Button/Button.tsx +82 -0
- package/src/components/atoms/Checkbox/Checkbox.tsx +69 -0
- package/src/components/atoms/Icon/Icon.tsx +135 -0
- package/src/components/atoms/Icon/icons/ArrivalIcon.tsx +52 -0
- package/src/components/atoms/Icon/icons/CalendarIcon.tsx +63 -0
- package/src/components/atoms/Icon/icons/CarIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/Check.tsx +36 -0
- package/src/components/atoms/Icon/icons/CheckCircleIcon.tsx +48 -0
- package/src/components/atoms/Icon/icons/Chevron.tsx +73 -0
- package/src/components/atoms/Icon/icons/ChevronDownIcon.tsx +46 -0
- package/src/components/atoms/Icon/icons/Close.tsx +40 -0
- package/src/components/atoms/Icon/icons/DeleteIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/DepartureIcon.tsx +50 -0
- package/src/components/atoms/Icon/icons/EyeIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/FacebookIcon.tsx +50 -0
- package/src/components/atoms/Icon/icons/InfoIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/LinkedInIcon.tsx +50 -0
- package/src/components/atoms/Icon/icons/MapPinIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/MautoucoLogo.tsx +93 -0
- package/src/components/atoms/Icon/icons/MenuIcon.tsx +49 -0
- package/src/components/atoms/Icon/icons/MoreIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/Search.tsx +37 -0
- package/src/components/atoms/Icon/icons/Settings.tsx +38 -0
- package/src/components/atoms/Icon/icons/StrollerIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/TwitterIcon.tsx +50 -0
- package/src/components/atoms/Icon/icons/User.tsx +37 -0
- package/src/components/atoms/Icon/icons/UserIcon.tsx +63 -0
- package/src/components/atoms/Icon/icons/Youtube.tsx +50 -0
- package/src/components/atoms/Inputs/DropdownInput/DropdownInput.tsx +96 -0
- package/src/components/atoms/Inputs/Input/Input.tsx +66 -0
- package/src/components/atoms/Inputs/Textarea/Textarea.tsx +51 -0
- package/src/components/atoms/Link/Link.tsx +168 -0
- package/src/components/atoms/SelectedValue/SelectedValue.tsx +59 -0
- package/src/components/atoms/Spinner/Spinner.tsx +56 -0
- package/src/components/atoms/Spinner/variants/ButtonSpinner.tsx +37 -0
- package/src/components/atoms/Spinner/variants/LoadingSpinner.tsx +22 -0
- package/src/components/atoms/Tab/Tab.css +147 -0
- package/src/components/atoms/Tab/Tab.tsx +96 -0
- package/src/components/atoms/Typography/Typography.tsx +153 -0
- package/src/components/molecules/MultiSelectDropdown/MultiSelectDropdown.tsx +245 -0
- package/src/components/molecules/UserCard/UserCard.stories.tsx +36 -0
- package/src/components/molecules/UserCard/UserCard.tsx +173 -0
- package/src/components/organisms/Footer/Footer.tsx +290 -0
- package/src/components/organisms/TopNavigation/DesktopNav.tsx +122 -0
- package/src/components/organisms/TopNavigation/MobileNav.tsx +212 -0
- package/src/components/organisms/TopNavigation/TopNavigation.tsx +45 -0
- package/src/styles/components/avatar.css +58 -0
- package/src/styles/components/checkbox.css +132 -0
- package/src/styles/components/dropdown.css +214 -0
- package/src/styles/components/forms.css +147 -0
- package/src/styles/components/multiselect-dropdown.css +231 -0
- package/src/styles/components/organism/footer.css +113 -0
- package/src/styles/components/organism/topnavigation.css +162 -0
- package/src/styles/components/scrollbar.css +63 -0
- package/src/styles/components/selected-value.css +80 -0
- package/src/styles/components/typography.css +251 -0
- package/src/styles/tokens/_tokens.scss +2072 -0
- package/src/styles/tokens/tokens.css +2075 -0
- package/src/styles/tokens/tokens.js +2653 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
interface YouTubeIconProps {
|
|
4
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl";
|
|
5
|
+
className?: string;
|
|
6
|
+
color?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const YouTubeIcon: React.FC<YouTubeIconProps> = ({
|
|
10
|
+
size = "md",
|
|
11
|
+
className = "",
|
|
12
|
+
color,
|
|
13
|
+
}) => {
|
|
14
|
+
const getSizeClasses = () => {
|
|
15
|
+
switch (size) {
|
|
16
|
+
case "xs":
|
|
17
|
+
return "w-3 h-3";
|
|
18
|
+
case "sm":
|
|
19
|
+
return "w-4 h-4";
|
|
20
|
+
case "md":
|
|
21
|
+
return "w-5 h-5";
|
|
22
|
+
case "lg":
|
|
23
|
+
return "w-6 h-6";
|
|
24
|
+
case "xl":
|
|
25
|
+
return "w-8 h-8";
|
|
26
|
+
default:
|
|
27
|
+
return "w-5 h-5";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const sizeClasses = getSizeClasses();
|
|
32
|
+
const colorClass = color ? `text-${color}` : "text-current";
|
|
33
|
+
const classes = `${sizeClasses} ${colorClass} ${className}`;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<svg
|
|
37
|
+
viewBox="0 0 24 24"
|
|
38
|
+
fill="none"
|
|
39
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
40
|
+
className={classes}
|
|
41
|
+
>
|
|
42
|
+
<path
|
|
43
|
+
d="M22.9024 6.50346C22.6407 5.51804 21.8696 4.74196 20.8906 4.47858C19.116 4 12.0001 4 12.0001 4C12.0001 4 4.88427 4 3.10965 4.47858C2.13061 4.742 1.35952 5.51804 1.09781 6.50346C0.622314 8.28958 0.622314 12.0162 0.622314 12.0162C0.622314 12.0162 0.622314 15.7427 1.09781 17.5289C1.35952 18.5143 2.13061 19.258 3.10965 19.5214C4.88427 20 12.0001 20 12.0001 20C12.0001 20 19.1159 20 20.8906 19.5214C21.8696 19.258 22.6407 18.5143 22.9024 17.5289C23.3779 15.7427 23.3779 12.0162 23.3779 12.0162C23.3779 12.0162 23.3779 8.28958 22.9024 6.50346ZM9.67282 15.3996V8.63271L15.6203 12.0162L9.67282 15.3996Z"
|
|
44
|
+
fill="currentColor"
|
|
45
|
+
/>
|
|
46
|
+
</svg>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default YouTubeIcon;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import Icon from '../../Icon/Icon';
|
|
3
|
+
import Spinner from '../../Spinner/Spinner';
|
|
4
|
+
|
|
5
|
+
interface DropdownInputProps {
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
state?: 'default' | 'loading' | 'selected' | 'error' | 'disabled';
|
|
9
|
+
onClick?: () => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
options?: string[];
|
|
12
|
+
onSelect?: (option: string) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DropdownInput: React.FC<DropdownInputProps> = ({
|
|
16
|
+
placeholder = 'Select item name',
|
|
17
|
+
value,
|
|
18
|
+
state = 'default',
|
|
19
|
+
onClick,
|
|
20
|
+
className = '',
|
|
21
|
+
options = [],
|
|
22
|
+
onSelect
|
|
23
|
+
}) => {
|
|
24
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
25
|
+
const handleClick = () => {
|
|
26
|
+
if (state === 'disabled' || state === 'loading') return;
|
|
27
|
+
|
|
28
|
+
setIsOpen(!isOpen);
|
|
29
|
+
onClick?.();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleOptionSelect = (option: string) => {
|
|
33
|
+
onSelect?.(option);
|
|
34
|
+
setIsOpen(false);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getStateClasses = () => {
|
|
38
|
+
const baseClasses = isOpen ? 'dropdown-input--open' : '';
|
|
39
|
+
switch (state) {
|
|
40
|
+
case 'loading':
|
|
41
|
+
return `${baseClasses} dropdown-input--loading`;
|
|
42
|
+
case 'selected':
|
|
43
|
+
return `${baseClasses} dropdown-input--selected`;
|
|
44
|
+
case 'error':
|
|
45
|
+
return `${baseClasses} dropdown-input--error`;
|
|
46
|
+
case 'disabled':
|
|
47
|
+
return `${baseClasses} dropdown-input--disabled`;
|
|
48
|
+
default:
|
|
49
|
+
return `${baseClasses} dropdown-input--default`;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getIcon = () => {
|
|
54
|
+
if (state === 'loading') {
|
|
55
|
+
return <Spinner size="sm" className="dropdown-input__icon" />;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Icon
|
|
60
|
+
name={isOpen ? 'chevron-up' : 'chevron-down'}
|
|
61
|
+
size="sm"
|
|
62
|
+
className="dropdown-input__icon dropdown-input__icon--chevron"
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const displayText = state === 'loading' ? 'Loading...' : (value || placeholder);
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className={`dropdown-container ${className}`}>
|
|
71
|
+
<div
|
|
72
|
+
className={`dropdown-input ${getStateClasses()}`}
|
|
73
|
+
onClick={handleClick}
|
|
74
|
+
>
|
|
75
|
+
<span className="dropdown-input__text">{displayText}</span>
|
|
76
|
+
{getIcon()}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
{isOpen && options.length > 0 && (
|
|
80
|
+
<div className="dropdown-menu">
|
|
81
|
+
{options.map((option, index) => (
|
|
82
|
+
<div
|
|
83
|
+
key={index}
|
|
84
|
+
className="dropdown-option"
|
|
85
|
+
onClick={() => handleOptionSelect(option)}
|
|
86
|
+
>
|
|
87
|
+
{option}
|
|
88
|
+
</div>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
)}
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default DropdownInput;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Icon from '../../Icon/Icon';
|
|
3
|
+
|
|
4
|
+
interface InputProps {
|
|
5
|
+
variant?: 'default' | 'focus' | 'success' | 'error' | 'disabled';
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
11
|
+
onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
|
12
|
+
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
|
13
|
+
icon?: 'search' | 'close' | 'settings' | 'user';
|
|
14
|
+
iconPosition?: 'leading' | 'trailing';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Input: React.FC<InputProps> = ({
|
|
18
|
+
variant = 'default',
|
|
19
|
+
placeholder = 'Input text',
|
|
20
|
+
value,
|
|
21
|
+
disabled = false,
|
|
22
|
+
className = '',
|
|
23
|
+
onChange,
|
|
24
|
+
onFocus,
|
|
25
|
+
onBlur,
|
|
26
|
+
icon,
|
|
27
|
+
iconPosition = 'trailing',
|
|
28
|
+
}) => {
|
|
29
|
+
const baseClasses = 'input-field';
|
|
30
|
+
const variantClasses = {
|
|
31
|
+
default: 'input-field--default',
|
|
32
|
+
focus: 'input-field--focus',
|
|
33
|
+
success: 'input-field--success',
|
|
34
|
+
error: 'input-field--error',
|
|
35
|
+
disabled: 'input-field--disabled'
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const inputClasses = `${baseClasses} ${variantClasses[variant]} ${icon ? `input-field--with-icon input-field--icon-${iconPosition}` : ''} ${className}`.trim();
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className={`input-wrapper ${icon ? 'input-wrapper--with-icon' : ''}`.trim()}>
|
|
42
|
+
{icon && iconPosition === 'leading' && (
|
|
43
|
+
<span className="input-icon input-icon--leading">
|
|
44
|
+
<Icon name={icon} size="sm" />
|
|
45
|
+
</span>
|
|
46
|
+
)}
|
|
47
|
+
<input
|
|
48
|
+
type="text"
|
|
49
|
+
className={inputClasses}
|
|
50
|
+
placeholder={placeholder}
|
|
51
|
+
value={value}
|
|
52
|
+
disabled={disabled || variant === 'disabled'}
|
|
53
|
+
onChange={onChange}
|
|
54
|
+
onFocus={onFocus}
|
|
55
|
+
onBlur={onBlur}
|
|
56
|
+
/>
|
|
57
|
+
{icon && iconPosition === 'trailing' && (
|
|
58
|
+
<span className="input-icon input-icon--trailing">
|
|
59
|
+
<Icon name={icon} size="sm" />
|
|
60
|
+
</span>
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default Input;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface TextareaProps {
|
|
4
|
+
variant?: 'default' | 'focus' | 'success' | 'error' | 'disabled';
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
value?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
rows?: number;
|
|
9
|
+
className?: string;
|
|
10
|
+
onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
|
11
|
+
onFocus?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
|
|
12
|
+
onBlur?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Textarea: React.FC<TextareaProps> = ({
|
|
16
|
+
variant = 'default',
|
|
17
|
+
placeholder = 'Enter your text...',
|
|
18
|
+
value,
|
|
19
|
+
disabled = false,
|
|
20
|
+
rows = 4,
|
|
21
|
+
className = '',
|
|
22
|
+
onChange,
|
|
23
|
+
onFocus,
|
|
24
|
+
onBlur,
|
|
25
|
+
}) => {
|
|
26
|
+
const baseClasses = 'input-field';
|
|
27
|
+
const variantClasses = {
|
|
28
|
+
default: 'input-field--default',
|
|
29
|
+
focus: 'input-field--focus',
|
|
30
|
+
success: 'input-field--success',
|
|
31
|
+
error: 'input-field--error',
|
|
32
|
+
disabled: 'input-field--disabled'
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const textareaClasses = `${baseClasses} ${variantClasses[variant]} ${className}`;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<textarea
|
|
39
|
+
className={textareaClasses}
|
|
40
|
+
placeholder={placeholder}
|
|
41
|
+
value={value}
|
|
42
|
+
disabled={disabled || variant === 'disabled'}
|
|
43
|
+
rows={rows}
|
|
44
|
+
onChange={onChange}
|
|
45
|
+
onFocus={onFocus}
|
|
46
|
+
onBlur={onBlur}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default Textarea;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text } from '../Typography/Typography';
|
|
3
|
+
|
|
4
|
+
export interface LinkProps {
|
|
5
|
+
/**
|
|
6
|
+
* Le texte du lien
|
|
7
|
+
*/
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* L'URL du lien
|
|
11
|
+
*/
|
|
12
|
+
href?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Fonction appelée lors du clic
|
|
15
|
+
*/
|
|
16
|
+
onClick?: () => void;
|
|
17
|
+
/**
|
|
18
|
+
* État du lien
|
|
19
|
+
*/
|
|
20
|
+
state?: 'default' | 'hover' | 'visited' | 'focused';
|
|
21
|
+
/**
|
|
22
|
+
* Thème du lien
|
|
23
|
+
*/
|
|
24
|
+
theme?: 'light' | 'dark' | 'teal';
|
|
25
|
+
/**
|
|
26
|
+
* Si le lien est associé à un radio button
|
|
27
|
+
*/
|
|
28
|
+
withRadio?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Si le radio button est sélectionné
|
|
31
|
+
*/
|
|
32
|
+
radioChecked?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Fonction appelée lors du clic sur le radio button
|
|
35
|
+
*/
|
|
36
|
+
onRadioChange?: (checked: boolean) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Classes CSS supplémentaires
|
|
39
|
+
*/
|
|
40
|
+
className?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Si le lien est désactivé
|
|
43
|
+
*/
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const Link: React.FC<LinkProps> = ({
|
|
48
|
+
children,
|
|
49
|
+
href,
|
|
50
|
+
onClick,
|
|
51
|
+
state = 'default',
|
|
52
|
+
theme = 'light',
|
|
53
|
+
withRadio = false,
|
|
54
|
+
radioChecked = false,
|
|
55
|
+
onRadioChange,
|
|
56
|
+
className = '',
|
|
57
|
+
disabled = false,
|
|
58
|
+
}) => {
|
|
59
|
+
const handleClick = (e: React.MouseEvent) => {
|
|
60
|
+
if (disabled) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
onClick?.();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleRadioChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
68
|
+
if (disabled) return;
|
|
69
|
+
onRadioChange?.(e.target.checked);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getThemeClasses = () => {
|
|
73
|
+
const baseClasses = 'inline-flex items-center gap-3 transition-all duration-200';
|
|
74
|
+
|
|
75
|
+
switch (theme) {
|
|
76
|
+
case 'dark':
|
|
77
|
+
return `${baseClasses} text-white`;
|
|
78
|
+
case 'teal':
|
|
79
|
+
return `${baseClasses} text-teal-600`;
|
|
80
|
+
default: // light
|
|
81
|
+
return `${baseClasses} text-gray-700`;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const getStateClasses = () => {
|
|
86
|
+
if (disabled) {
|
|
87
|
+
return 'opacity-50 cursor-not-allowed';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
switch (state) {
|
|
91
|
+
case 'hover':
|
|
92
|
+
return 'hover:opacity-80';
|
|
93
|
+
case 'visited':
|
|
94
|
+
return theme === 'teal' ? 'text-cyan-400' : 'text-purple-600';
|
|
95
|
+
case 'focused':
|
|
96
|
+
return 'focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-current';
|
|
97
|
+
default:
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const getRadioClasses = () => {
|
|
103
|
+
const baseClasses = 'w-5 h-5 border-2 rounded-sm transition-all duration-200';
|
|
104
|
+
|
|
105
|
+
if (disabled) {
|
|
106
|
+
return `${baseClasses} border-gray-200 bg-gray-100`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
switch (theme) {
|
|
110
|
+
case 'dark':
|
|
111
|
+
return `${baseClasses} border-white ${radioChecked ? 'bg-transparent' : 'bg-transparent'}`;
|
|
112
|
+
case 'teal':
|
|
113
|
+
return `${baseClasses} border-teal-600 ${radioChecked ? 'bg-transparent' : 'bg-transparent'}`;
|
|
114
|
+
default: // light
|
|
115
|
+
return `${baseClasses} border-gray-400 ${radioChecked ? 'bg-transparent' : 'bg-transparent'}`;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const linkContent = (
|
|
120
|
+
<Text
|
|
121
|
+
as="span"
|
|
122
|
+
className={`underline ${getThemeClasses()} ${getStateClasses()} ${className}`}
|
|
123
|
+
onClick={handleClick}
|
|
124
|
+
>
|
|
125
|
+
{children}
|
|
126
|
+
</Text>
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
if (withRadio) {
|
|
130
|
+
return (
|
|
131
|
+
<label className="inline-flex items-center gap-3 cursor-pointer">
|
|
132
|
+
<input
|
|
133
|
+
type="radio"
|
|
134
|
+
checked={radioChecked}
|
|
135
|
+
onChange={handleRadioChange}
|
|
136
|
+
disabled={disabled}
|
|
137
|
+
className={getRadioClasses()}
|
|
138
|
+
aria-label={`Sélectionner ${children}`}
|
|
139
|
+
/>
|
|
140
|
+
{linkContent}
|
|
141
|
+
</label>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (href) {
|
|
146
|
+
return (
|
|
147
|
+
<a
|
|
148
|
+
href={href}
|
|
149
|
+
className={`${getThemeClasses()} ${getStateClasses()} ${className}`}
|
|
150
|
+
onClick={handleClick}
|
|
151
|
+
aria-disabled={disabled}
|
|
152
|
+
>
|
|
153
|
+
{children}
|
|
154
|
+
</a>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<button
|
|
160
|
+
type="button"
|
|
161
|
+
className={`${getThemeClasses()} ${getStateClasses()} ${className}`}
|
|
162
|
+
onClick={handleClick}
|
|
163
|
+
disabled={disabled}
|
|
164
|
+
>
|
|
165
|
+
{children}
|
|
166
|
+
</button>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Icon from '../Icon/Icon';
|
|
3
|
+
import { Text } from '../Typography/Typography';
|
|
4
|
+
|
|
5
|
+
interface SelectedValueProps {
|
|
6
|
+
value: string;
|
|
7
|
+
onRemove?: () => void;
|
|
8
|
+
className?: string;
|
|
9
|
+
iconSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
10
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
11
|
+
variant?: 'filled' | 'text';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const SelectedValue: React.FC<SelectedValueProps> = ({
|
|
15
|
+
value,
|
|
16
|
+
onRemove,
|
|
17
|
+
className = '',
|
|
18
|
+
iconSize = 'xs',
|
|
19
|
+
size = 'md',
|
|
20
|
+
variant = 'filled',
|
|
21
|
+
}) => {
|
|
22
|
+
const handleRemove = (event: React.MouseEvent) => {
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
if (onRemove) {
|
|
25
|
+
onRemove();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const classes = `selected-value selected-value--${size} selected-value--${variant} ${className}`.trim();
|
|
30
|
+
|
|
31
|
+
const getTextSize = () => {
|
|
32
|
+
return size; // Utilise directement la taille passée en prop
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className={classes}>
|
|
37
|
+
<Text
|
|
38
|
+
size={getTextSize() as any}
|
|
39
|
+
variant="medium"
|
|
40
|
+
leading="4"
|
|
41
|
+
className="selected-value__text"
|
|
42
|
+
>
|
|
43
|
+
{value}
|
|
44
|
+
</Text>
|
|
45
|
+
{variant !== 'text' && onRemove && (
|
|
46
|
+
<button
|
|
47
|
+
type="button"
|
|
48
|
+
className="selected-value__remove"
|
|
49
|
+
onClick={handleRemove}
|
|
50
|
+
aria-label={`Remove ${value}`}
|
|
51
|
+
>
|
|
52
|
+
<Icon name="close" size={iconSize} className="selected-value__remove-icon" />
|
|
53
|
+
</button>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default SelectedValue;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface SpinnerProps {
|
|
4
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
5
|
+
className?: string;
|
|
6
|
+
color?: string;
|
|
7
|
+
speed?: 'slow' | 'normal' | 'fast';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Spinner: React.FC<SpinnerProps> = ({
|
|
11
|
+
size = 'md',
|
|
12
|
+
className = '',
|
|
13
|
+
color,
|
|
14
|
+
speed = 'normal'
|
|
15
|
+
}) => {
|
|
16
|
+
const getSizeClasses = () => {
|
|
17
|
+
switch (size) {
|
|
18
|
+
case 'xs': return 'w-3 h-3';
|
|
19
|
+
case 'sm': return 'w-4 h-4';
|
|
20
|
+
case 'md': return 'w-5 h-5';
|
|
21
|
+
case 'lg': return 'w-6 h-6';
|
|
22
|
+
case 'xl': return 'w-8 h-8';
|
|
23
|
+
default: return 'w-5 h-5';
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getSpeedClasses = () => {
|
|
28
|
+
switch (speed) {
|
|
29
|
+
case 'slow': return 'animate-spin-slow';
|
|
30
|
+
case 'fast': return 'animate-spin-fast';
|
|
31
|
+
default: return 'animate-spin';
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const sizeClasses = getSizeClasses();
|
|
36
|
+
const speedClasses = getSpeedClasses();
|
|
37
|
+
const colorClass = color ? `text-${color}` : 'text-current';
|
|
38
|
+
const classes = `${sizeClasses} ${speedClasses} ${colorClass} ${className}`;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<svg
|
|
42
|
+
className={classes}
|
|
43
|
+
viewBox="0 0 24 24"
|
|
44
|
+
fill="none"
|
|
45
|
+
stroke="currentColor"
|
|
46
|
+
strokeWidth="2"
|
|
47
|
+
strokeLinecap="round"
|
|
48
|
+
strokeLinejoin="round"
|
|
49
|
+
>
|
|
50
|
+
<path d="M21 12A9 9 0 1 1 3 12A9 9 0 0 1 21 12Z" strokeOpacity="0.25" />
|
|
51
|
+
<path d="M21 12A9 9 0 0 0 3 12" />
|
|
52
|
+
</svg>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default Spinner;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Spinner from '../Spinner';
|
|
3
|
+
|
|
4
|
+
interface ButtonSpinnerProps {
|
|
5
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
6
|
+
className?: string;
|
|
7
|
+
variant?: 'primary' | 'secondary' | 'white';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ButtonSpinner: React.FC<ButtonSpinnerProps> = ({
|
|
11
|
+
size = 'sm',
|
|
12
|
+
className = '',
|
|
13
|
+
variant = 'white'
|
|
14
|
+
}) => {
|
|
15
|
+
const getVariantClass = () => {
|
|
16
|
+
switch (variant) {
|
|
17
|
+
case 'primary':
|
|
18
|
+
return 'text-white';
|
|
19
|
+
case 'secondary':
|
|
20
|
+
return 'text-gray-600';
|
|
21
|
+
case 'white':
|
|
22
|
+
return 'text-white';
|
|
23
|
+
default:
|
|
24
|
+
return 'text-white';
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Spinner
|
|
30
|
+
size={size}
|
|
31
|
+
speed="fast"
|
|
32
|
+
className={`${getVariantClass()} ${className}`}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default ButtonSpinner;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Spinner from '../Spinner';
|
|
3
|
+
|
|
4
|
+
interface LoadingSpinnerProps {
|
|
5
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const LoadingSpinner: React.FC<LoadingSpinnerProps> = ({
|
|
10
|
+
size = 'md',
|
|
11
|
+
className = ''
|
|
12
|
+
}) => {
|
|
13
|
+
return (
|
|
14
|
+
<Spinner
|
|
15
|
+
size={size}
|
|
16
|
+
speed="normal"
|
|
17
|
+
className={`text-blue-500 ${className}`}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default LoadingSpinner;
|