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.
Files changed (163) hide show
  1. package/README.md +187 -0
  2. package/dist/components/atoms/Avatar/Avatar.d.ts +14 -0
  3. package/dist/components/atoms/Avatar/Avatar.js +31 -0
  4. package/dist/components/atoms/Button/Button.d.ts +27 -0
  5. package/dist/components/atoms/Button/Button.js +35 -0
  6. package/dist/components/atoms/Checkbox/Checkbox.d.ts +13 -0
  7. package/dist/components/atoms/Checkbox/Checkbox.js +33 -0
  8. package/dist/components/atoms/Icon/Icon.d.ts +10 -0
  9. package/dist/components/atoms/Icon/Icon.js +102 -0
  10. package/dist/components/atoms/Icon/icons/ArrivalIcon.d.ts +8 -0
  11. package/dist/components/atoms/Icon/icons/ArrivalIcon.js +31 -0
  12. package/dist/components/atoms/Icon/icons/CalendarIcon.d.ts +12 -0
  13. package/dist/components/atoms/Icon/icons/CalendarIcon.js +41 -0
  14. package/dist/components/atoms/Icon/icons/CarIcon.d.ts +8 -0
  15. package/dist/components/atoms/Icon/icons/CarIcon.js +30 -0
  16. package/dist/components/atoms/Icon/icons/Check.d.ts +8 -0
  17. package/dist/components/atoms/Icon/icons/Check.js +30 -0
  18. package/dist/components/atoms/Icon/icons/CheckCircleIcon.d.ts +8 -0
  19. package/dist/components/atoms/Icon/icons/CheckCircleIcon.js +30 -0
  20. package/dist/components/atoms/Icon/icons/Chevron.d.ts +9 -0
  21. package/dist/components/atoms/Icon/icons/Chevron.js +54 -0
  22. package/dist/components/atoms/Icon/icons/ChevronDownIcon.d.ts +8 -0
  23. package/dist/components/atoms/Icon/icons/ChevronDownIcon.js +30 -0
  24. package/dist/components/atoms/Icon/icons/Close.d.ts +8 -0
  25. package/dist/components/atoms/Icon/icons/Close.js +30 -0
  26. package/dist/components/atoms/Icon/icons/DeleteIcon.d.ts +8 -0
  27. package/dist/components/atoms/Icon/icons/DeleteIcon.js +30 -0
  28. package/dist/components/atoms/Icon/icons/DepartureIcon.d.ts +8 -0
  29. package/dist/components/atoms/Icon/icons/DepartureIcon.js +30 -0
  30. package/dist/components/atoms/Icon/icons/EyeIcon.d.ts +8 -0
  31. package/dist/components/atoms/Icon/icons/EyeIcon.js +30 -0
  32. package/dist/components/atoms/Icon/icons/FacebookIcon.d.ts +8 -0
  33. package/dist/components/atoms/Icon/icons/FacebookIcon.js +36 -0
  34. package/dist/components/atoms/Icon/icons/InfoIcon.d.ts +8 -0
  35. package/dist/components/atoms/Icon/icons/InfoIcon.js +30 -0
  36. package/dist/components/atoms/Icon/icons/LinkedInIcon.d.ts +8 -0
  37. package/dist/components/atoms/Icon/icons/LinkedInIcon.js +36 -0
  38. package/dist/components/atoms/Icon/icons/MapPinIcon.d.ts +8 -0
  39. package/dist/components/atoms/Icon/icons/MapPinIcon.js +30 -0
  40. package/dist/components/atoms/Icon/icons/MautoucoLogo.d.ts +8 -0
  41. package/dist/components/atoms/Icon/icons/MautoucoLogo.js +37 -0
  42. package/dist/components/atoms/Icon/icons/MenuIcon.d.ts +8 -0
  43. package/dist/components/atoms/Icon/icons/MenuIcon.js +37 -0
  44. package/dist/components/atoms/Icon/icons/MoreIcon.d.ts +8 -0
  45. package/dist/components/atoms/Icon/icons/MoreIcon.js +30 -0
  46. package/dist/components/atoms/Icon/icons/Search.d.ts +8 -0
  47. package/dist/components/atoms/Icon/icons/Search.js +30 -0
  48. package/dist/components/atoms/Icon/icons/Settings.d.ts +8 -0
  49. package/dist/components/atoms/Icon/icons/Settings.js +30 -0
  50. package/dist/components/atoms/Icon/icons/StrollerIcon.d.ts +8 -0
  51. package/dist/components/atoms/Icon/icons/StrollerIcon.js +30 -0
  52. package/dist/components/atoms/Icon/icons/TwitterIcon.d.ts +8 -0
  53. package/dist/components/atoms/Icon/icons/TwitterIcon.js +36 -0
  54. package/dist/components/atoms/Icon/icons/User.d.ts +8 -0
  55. package/dist/components/atoms/Icon/icons/User.js +30 -0
  56. package/dist/components/atoms/Icon/icons/UserIcon.d.ts +12 -0
  57. package/dist/components/atoms/Icon/icons/UserIcon.js +41 -0
  58. package/dist/components/atoms/Icon/icons/Youtube.d.ts +8 -0
  59. package/dist/components/atoms/Icon/icons/Youtube.js +36 -0
  60. package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.d.ts +12 -0
  61. package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.js +53 -0
  62. package/dist/components/atoms/Inputs/Input/Input.d.ts +15 -0
  63. package/dist/components/atoms/Inputs/Input/Input.js +27 -0
  64. package/dist/components/atoms/Inputs/Textarea/Textarea.d.ts +14 -0
  65. package/dist/components/atoms/Inputs/Textarea/Textarea.js +15 -0
  66. package/dist/components/atoms/Link/Link.d.ts +44 -0
  67. package/dist/components/atoms/Link/Link.js +76 -0
  68. package/dist/components/atoms/SelectedValue/SelectedValue.d.ts +11 -0
  69. package/dist/components/atoms/SelectedValue/SelectedValue.js +29 -0
  70. package/dist/components/atoms/Spinner/Spinner.d.ts +9 -0
  71. package/dist/components/atoms/Spinner/Spinner.js +38 -0
  72. package/dist/components/atoms/Spinner/variants/ButtonSpinner.d.ts +8 -0
  73. package/dist/components/atoms/Spinner/variants/ButtonSpinner.js +19 -0
  74. package/dist/components/atoms/Spinner/variants/LoadingSpinner.d.ts +7 -0
  75. package/dist/components/atoms/Spinner/variants/LoadingSpinner.js +7 -0
  76. package/dist/components/atoms/Tab/Tab.d.ts +22 -0
  77. package/dist/components/atoms/Tab/Tab.js +54 -0
  78. package/dist/components/atoms/Typography/Heading/Heading.d.ts +9 -0
  79. package/dist/components/atoms/Typography/Heading/Heading.js +25 -0
  80. package/dist/components/atoms/Typography/Text/Text.d.ts +10 -0
  81. package/dist/components/atoms/Typography/Text/Text.js +77 -0
  82. package/dist/components/atoms/Typography/Typography.d.ts +24 -0
  83. package/dist/components/atoms/Typography/Typography.js +100 -0
  84. package/dist/components/molecules/MultiSelectDropdown/MultiSelectDropdown.d.ts +29 -0
  85. package/dist/components/molecules/MultiSelectDropdown/MultiSelectDropdown.js +106 -0
  86. package/dist/components/molecules/UserCard/UserCard.d.ts +20 -0
  87. package/dist/components/molecules/UserCard/UserCard.js +57 -0
  88. package/dist/components/organisms/Footer/Footer.d.ts +38 -0
  89. package/dist/components/organisms/Footer/Footer.js +74 -0
  90. package/dist/components/organisms/TopNavigation/DesktopNav.d.ts +33 -0
  91. package/dist/components/organisms/TopNavigation/DesktopNav.js +26 -0
  92. package/dist/components/organisms/TopNavigation/MobileNav.d.ts +32 -0
  93. package/dist/components/organisms/TopNavigation/MobileNav.js +45 -0
  94. package/dist/components/organisms/TopNavigation/TopNavigation.d.ts +33 -0
  95. package/dist/components/organisms/TopNavigation/TopNavigation.js +20 -0
  96. package/dist/hooks/useMobile.d.ts +5 -0
  97. package/dist/hooks/useMobile.js +26 -0
  98. package/dist/index.d.ts +23 -0
  99. package/dist/index.js +28 -0
  100. package/dist/styles/tokens/tokens.d.ts +3108 -0
  101. package/dist/styles/tokens/tokens.js +2652 -0
  102. package/package.json +90 -0
  103. package/src/components/atoms/Avatar/Avatar.tsx +60 -0
  104. package/src/components/atoms/Button/Button.css +200 -0
  105. package/src/components/atoms/Button/Button.tsx +82 -0
  106. package/src/components/atoms/Checkbox/Checkbox.tsx +69 -0
  107. package/src/components/atoms/Icon/Icon.tsx +135 -0
  108. package/src/components/atoms/Icon/icons/ArrivalIcon.tsx +52 -0
  109. package/src/components/atoms/Icon/icons/CalendarIcon.tsx +63 -0
  110. package/src/components/atoms/Icon/icons/CarIcon.tsx +44 -0
  111. package/src/components/atoms/Icon/icons/Check.tsx +36 -0
  112. package/src/components/atoms/Icon/icons/CheckCircleIcon.tsx +48 -0
  113. package/src/components/atoms/Icon/icons/Chevron.tsx +73 -0
  114. package/src/components/atoms/Icon/icons/ChevronDownIcon.tsx +46 -0
  115. package/src/components/atoms/Icon/icons/Close.tsx +40 -0
  116. package/src/components/atoms/Icon/icons/DeleteIcon.tsx +44 -0
  117. package/src/components/atoms/Icon/icons/DepartureIcon.tsx +50 -0
  118. package/src/components/atoms/Icon/icons/EyeIcon.tsx +44 -0
  119. package/src/components/atoms/Icon/icons/FacebookIcon.tsx +50 -0
  120. package/src/components/atoms/Icon/icons/InfoIcon.tsx +44 -0
  121. package/src/components/atoms/Icon/icons/LinkedInIcon.tsx +50 -0
  122. package/src/components/atoms/Icon/icons/MapPinIcon.tsx +44 -0
  123. package/src/components/atoms/Icon/icons/MautoucoLogo.tsx +93 -0
  124. package/src/components/atoms/Icon/icons/MenuIcon.tsx +49 -0
  125. package/src/components/atoms/Icon/icons/MoreIcon.tsx +44 -0
  126. package/src/components/atoms/Icon/icons/Search.tsx +37 -0
  127. package/src/components/atoms/Icon/icons/Settings.tsx +38 -0
  128. package/src/components/atoms/Icon/icons/StrollerIcon.tsx +44 -0
  129. package/src/components/atoms/Icon/icons/TwitterIcon.tsx +50 -0
  130. package/src/components/atoms/Icon/icons/User.tsx +37 -0
  131. package/src/components/atoms/Icon/icons/UserIcon.tsx +63 -0
  132. package/src/components/atoms/Icon/icons/Youtube.tsx +50 -0
  133. package/src/components/atoms/Inputs/DropdownInput/DropdownInput.tsx +96 -0
  134. package/src/components/atoms/Inputs/Input/Input.tsx +66 -0
  135. package/src/components/atoms/Inputs/Textarea/Textarea.tsx +51 -0
  136. package/src/components/atoms/Link/Link.tsx +168 -0
  137. package/src/components/atoms/SelectedValue/SelectedValue.tsx +59 -0
  138. package/src/components/atoms/Spinner/Spinner.tsx +56 -0
  139. package/src/components/atoms/Spinner/variants/ButtonSpinner.tsx +37 -0
  140. package/src/components/atoms/Spinner/variants/LoadingSpinner.tsx +22 -0
  141. package/src/components/atoms/Tab/Tab.css +147 -0
  142. package/src/components/atoms/Tab/Tab.tsx +96 -0
  143. package/src/components/atoms/Typography/Typography.tsx +153 -0
  144. package/src/components/molecules/MultiSelectDropdown/MultiSelectDropdown.tsx +245 -0
  145. package/src/components/molecules/UserCard/UserCard.stories.tsx +36 -0
  146. package/src/components/molecules/UserCard/UserCard.tsx +173 -0
  147. package/src/components/organisms/Footer/Footer.tsx +290 -0
  148. package/src/components/organisms/TopNavigation/DesktopNav.tsx +122 -0
  149. package/src/components/organisms/TopNavigation/MobileNav.tsx +212 -0
  150. package/src/components/organisms/TopNavigation/TopNavigation.tsx +45 -0
  151. package/src/styles/components/avatar.css +58 -0
  152. package/src/styles/components/checkbox.css +132 -0
  153. package/src/styles/components/dropdown.css +214 -0
  154. package/src/styles/components/forms.css +147 -0
  155. package/src/styles/components/multiselect-dropdown.css +231 -0
  156. package/src/styles/components/organism/footer.css +113 -0
  157. package/src/styles/components/organism/topnavigation.css +162 -0
  158. package/src/styles/components/scrollbar.css +63 -0
  159. package/src/styles/components/selected-value.css +80 -0
  160. package/src/styles/components/typography.css +251 -0
  161. package/src/styles/tokens/_tokens.scss +2072 -0
  162. package/src/styles/tokens/tokens.css +2075 -0
  163. 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;