@lp-labs/ui-components 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +256 -2
  4. package/dist/cjs/components/Accordion.d.ts +78 -0
  5. package/dist/cjs/components/Accordion.js +78 -0
  6. package/dist/cjs/components/AdvancedComponents.d.ts +353 -0
  7. package/dist/cjs/components/AdvancedComponents.js +353 -0
  8. package/dist/cjs/components/Alert.d.ts +102 -0
  9. package/dist/cjs/components/Alert.js +102 -0
  10. package/dist/cjs/components/Avatar.d.ts +89 -0
  11. package/dist/cjs/components/Avatar.js +89 -0
  12. package/dist/cjs/components/Badge.d.ts +57 -0
  13. package/dist/cjs/components/Badge.js +57 -0
  14. package/dist/cjs/components/Breadcrumb.d.ts +50 -0
  15. package/dist/cjs/components/Breadcrumb.js +50 -0
  16. package/dist/cjs/components/Button.d.ts +77 -0
  17. package/dist/cjs/components/Button.js +77 -0
  18. package/dist/cjs/components/ButtonVariants.d.ts +261 -0
  19. package/dist/cjs/components/ButtonVariants.js +261 -0
  20. package/dist/cjs/components/Card.d.ts +56 -0
  21. package/dist/cjs/components/Card.js +56 -0
  22. package/dist/cjs/components/CardVariants.d.ts +267 -0
  23. package/dist/cjs/components/CardVariants.js +267 -0
  24. package/dist/cjs/components/Checkbox.d.ts +50 -0
  25. package/dist/cjs/components/Checkbox.js +50 -0
  26. package/dist/cjs/components/Chip.d.ts +104 -0
  27. package/dist/cjs/components/Chip.js +104 -0
  28. package/dist/cjs/components/DataDisplayComponents.d.ts +275 -0
  29. package/dist/cjs/components/DataDisplayComponents.js +275 -0
  30. package/dist/cjs/components/Divider.d.ts +77 -0
  31. package/dist/cjs/components/Divider.js +77 -0
  32. package/dist/cjs/components/Drawer.d.ts +142 -0
  33. package/dist/cjs/components/Drawer.js +142 -0
  34. package/dist/cjs/components/Dropdown.d.ts +139 -0
  35. package/dist/cjs/components/Dropdown.js +139 -0
  36. package/dist/cjs/components/Form.d.ts +41 -0
  37. package/dist/cjs/components/Form.js +41 -0
  38. package/dist/cjs/components/FormGroup.d.ts +58 -0
  39. package/dist/cjs/components/FormGroup.js +58 -0
  40. package/dist/cjs/components/FormInputVariants.d.ts +298 -0
  41. package/dist/cjs/components/FormInputVariants.js +298 -0
  42. package/dist/cjs/components/Image.d.ts +106 -0
  43. package/dist/cjs/components/Image.js +106 -0
  44. package/dist/cjs/components/Input.d.ts +65 -0
  45. package/dist/cjs/components/Input.js +65 -0
  46. package/dist/cjs/components/LayoutComponents.d.ts +258 -0
  47. package/dist/cjs/components/LayoutComponents.js +258 -0
  48. package/dist/cjs/components/Link.d.ts +71 -0
  49. package/dist/cjs/components/Link.js +71 -0
  50. package/dist/cjs/components/LoadingFeedbackComponents.d.ts +230 -0
  51. package/dist/cjs/components/LoadingFeedbackComponents.js +230 -0
  52. package/dist/cjs/components/Menu.d.ts +167 -0
  53. package/dist/cjs/components/Menu.js +167 -0
  54. package/dist/cjs/components/Modal.d.ts +145 -0
  55. package/dist/cjs/components/Modal.js +145 -0
  56. package/dist/cjs/components/ModalTypes.d.ts +288 -0
  57. package/dist/cjs/components/ModalTypes.js +288 -0
  58. package/dist/cjs/components/Navbar.d.ts +181 -0
  59. package/dist/cjs/components/Navbar.js +181 -0
  60. package/dist/cjs/components/NavigationComponents.d.ts +276 -0
  61. package/dist/cjs/components/NavigationComponents.js +276 -0
  62. package/dist/cjs/components/Pagination.d.ts +94 -0
  63. package/dist/cjs/components/Pagination.js +94 -0
  64. package/dist/cjs/components/Popover.d.ts +108 -0
  65. package/dist/cjs/components/Popover.js +108 -0
  66. package/dist/cjs/components/Progress.d.ts +68 -0
  67. package/dist/cjs/components/Progress.js +68 -0
  68. package/dist/cjs/components/Radio.d.ts +93 -0
  69. package/dist/cjs/components/Radio.js +93 -0
  70. package/dist/cjs/components/Rating.d.ts +82 -0
  71. package/dist/cjs/components/Rating.js +82 -0
  72. package/dist/cjs/components/Select.d.ts +74 -0
  73. package/dist/cjs/components/Select.js +74 -0
  74. package/dist/cjs/components/Sidebar.d.ts +174 -0
  75. package/dist/cjs/components/Sidebar.js +174 -0
  76. package/dist/cjs/components/Skeleton.d.ts +57 -0
  77. package/dist/cjs/components/Skeleton.js +57 -0
  78. package/dist/cjs/components/Slider.d.ts +64 -0
  79. package/dist/cjs/components/Slider.js +64 -0
  80. package/dist/cjs/components/Spinner.d.ts +70 -0
  81. package/dist/cjs/components/Spinner.js +70 -0
  82. package/dist/cjs/components/Stack.d.ts +75 -0
  83. package/dist/cjs/components/Stack.js +75 -0
  84. package/dist/cjs/components/Stepper.d.ts +150 -0
  85. package/dist/cjs/components/Stepper.js +150 -0
  86. package/dist/cjs/components/Table.d.ts +173 -0
  87. package/dist/cjs/components/Table.js +173 -0
  88. package/dist/cjs/components/Tabs.d.ts +104 -0
  89. package/dist/cjs/components/Tabs.js +104 -0
  90. package/dist/cjs/components/Tag.d.ts +74 -0
  91. package/dist/cjs/components/Tag.js +74 -0
  92. package/dist/cjs/components/Textarea.d.ts +75 -0
  93. package/dist/cjs/components/Textarea.js +75 -0
  94. package/dist/cjs/components/Timeline.d.ts +124 -0
  95. package/dist/cjs/components/Timeline.js +124 -0
  96. package/dist/cjs/components/Toast.d.ts +155 -0
  97. package/dist/cjs/components/Toast.js +155 -0
  98. package/dist/cjs/components/Toggle.d.ts +75 -0
  99. package/dist/cjs/components/Toggle.js +75 -0
  100. package/dist/cjs/components/Tooltip.d.ts +80 -0
  101. package/dist/cjs/components/Tooltip.js +80 -0
  102. package/dist/cjs/components/TypographyComponents.d.ts +265 -0
  103. package/dist/cjs/components/TypographyComponents.js +265 -0
  104. package/dist/cjs/components/UtilityComponents.d.ts +345 -0
  105. package/dist/cjs/components/UtilityComponents.js +345 -0
  106. package/dist/cjs/components/Video.d.ts +82 -0
  107. package/dist/cjs/components/Video.js +82 -0
  108. package/dist/cjs/components/index.d.ts +311 -0
  109. package/dist/cjs/components/index.js +311 -0
  110. package/dist/cjs/index.d.ts +5 -0
  111. package/dist/cjs/index.js +5 -0
  112. package/dist/cjs/styles/main.css +493 -0
  113. package/dist/cjs/theme/ThemeProvider.d.ts +185 -0
  114. package/dist/cjs/theme/ThemeProvider.js +185 -0
  115. package/dist/cjs/theme/index.d.ts +2 -0
  116. package/dist/cjs/theme/index.js +2 -0
  117. package/dist/cjs/utilities/classNames.d.ts +200 -0
  118. package/dist/cjs/utilities/classNames.js +200 -0
  119. package/dist/cjs/utilities/index.d.ts +3 -0
  120. package/dist/cjs/utilities/index.js +3 -0
  121. package/dist/cjs/utilities/styles.d.ts +94 -0
  122. package/dist/cjs/utilities/styles.js +94 -0
  123. package/dist/esm/components/Accordion.d.ts +78 -0
  124. package/dist/esm/components/Accordion.js +78 -0
  125. package/dist/esm/components/AdvancedComponents.d.ts +353 -0
  126. package/dist/esm/components/AdvancedComponents.js +353 -0
  127. package/dist/esm/components/Alert.d.ts +102 -0
  128. package/dist/esm/components/Alert.js +102 -0
  129. package/dist/esm/components/Avatar.d.ts +89 -0
  130. package/dist/esm/components/Avatar.js +89 -0
  131. package/dist/esm/components/Badge.d.ts +57 -0
  132. package/dist/esm/components/Badge.js +57 -0
  133. package/dist/esm/components/Breadcrumb.d.ts +50 -0
  134. package/dist/esm/components/Breadcrumb.js +50 -0
  135. package/dist/esm/components/Button.d.ts +77 -0
  136. package/dist/esm/components/Button.js +77 -0
  137. package/dist/esm/components/ButtonVariants.d.ts +261 -0
  138. package/dist/esm/components/ButtonVariants.js +261 -0
  139. package/dist/esm/components/Card.d.ts +56 -0
  140. package/dist/esm/components/Card.js +56 -0
  141. package/dist/esm/components/CardVariants.d.ts +267 -0
  142. package/dist/esm/components/CardVariants.js +267 -0
  143. package/dist/esm/components/Checkbox.d.ts +50 -0
  144. package/dist/esm/components/Checkbox.js +50 -0
  145. package/dist/esm/components/Chip.d.ts +104 -0
  146. package/dist/esm/components/Chip.js +104 -0
  147. package/dist/esm/components/DataDisplayComponents.d.ts +275 -0
  148. package/dist/esm/components/DataDisplayComponents.js +275 -0
  149. package/dist/esm/components/Divider.d.ts +77 -0
  150. package/dist/esm/components/Divider.js +77 -0
  151. package/dist/esm/components/Drawer.d.ts +142 -0
  152. package/dist/esm/components/Drawer.js +142 -0
  153. package/dist/esm/components/Dropdown.d.ts +139 -0
  154. package/dist/esm/components/Dropdown.js +139 -0
  155. package/dist/esm/components/Form.d.ts +41 -0
  156. package/dist/esm/components/Form.js +41 -0
  157. package/dist/esm/components/FormGroup.d.ts +58 -0
  158. package/dist/esm/components/FormGroup.js +58 -0
  159. package/dist/esm/components/FormInputVariants.d.ts +298 -0
  160. package/dist/esm/components/FormInputVariants.js +298 -0
  161. package/dist/esm/components/Image.d.ts +106 -0
  162. package/dist/esm/components/Image.js +106 -0
  163. package/dist/esm/components/Input.d.ts +65 -0
  164. package/dist/esm/components/Input.js +65 -0
  165. package/dist/esm/components/LayoutComponents.d.ts +258 -0
  166. package/dist/esm/components/LayoutComponents.js +258 -0
  167. package/dist/esm/components/Link.d.ts +71 -0
  168. package/dist/esm/components/Link.js +71 -0
  169. package/dist/esm/components/LoadingFeedbackComponents.d.ts +230 -0
  170. package/dist/esm/components/LoadingFeedbackComponents.js +230 -0
  171. package/dist/esm/components/Menu.d.ts +167 -0
  172. package/dist/esm/components/Menu.js +167 -0
  173. package/dist/esm/components/Modal.d.ts +145 -0
  174. package/dist/esm/components/Modal.js +145 -0
  175. package/dist/esm/components/ModalTypes.d.ts +288 -0
  176. package/dist/esm/components/ModalTypes.js +288 -0
  177. package/dist/esm/components/Navbar.d.ts +181 -0
  178. package/dist/esm/components/Navbar.js +181 -0
  179. package/dist/esm/components/NavigationComponents.d.ts +276 -0
  180. package/dist/esm/components/NavigationComponents.js +276 -0
  181. package/dist/esm/components/Pagination.d.ts +94 -0
  182. package/dist/esm/components/Pagination.js +94 -0
  183. package/dist/esm/components/Popover.d.ts +108 -0
  184. package/dist/esm/components/Popover.js +108 -0
  185. package/dist/esm/components/Progress.d.ts +68 -0
  186. package/dist/esm/components/Progress.js +68 -0
  187. package/dist/esm/components/Radio.d.ts +93 -0
  188. package/dist/esm/components/Radio.js +93 -0
  189. package/dist/esm/components/Rating.d.ts +82 -0
  190. package/dist/esm/components/Rating.js +82 -0
  191. package/dist/esm/components/Select.d.ts +74 -0
  192. package/dist/esm/components/Select.js +74 -0
  193. package/dist/esm/components/Sidebar.d.ts +174 -0
  194. package/dist/esm/components/Sidebar.js +174 -0
  195. package/dist/esm/components/Skeleton.d.ts +57 -0
  196. package/dist/esm/components/Skeleton.js +57 -0
  197. package/dist/esm/components/Slider.d.ts +64 -0
  198. package/dist/esm/components/Slider.js +64 -0
  199. package/dist/esm/components/Spinner.d.ts +70 -0
  200. package/dist/esm/components/Spinner.js +70 -0
  201. package/dist/esm/components/Stack.d.ts +75 -0
  202. package/dist/esm/components/Stack.js +75 -0
  203. package/dist/esm/components/Stepper.d.ts +150 -0
  204. package/dist/esm/components/Stepper.js +150 -0
  205. package/dist/esm/components/Table.d.ts +173 -0
  206. package/dist/esm/components/Table.js +173 -0
  207. package/dist/esm/components/Tabs.d.ts +104 -0
  208. package/dist/esm/components/Tabs.js +104 -0
  209. package/dist/esm/components/Tag.d.ts +74 -0
  210. package/dist/esm/components/Tag.js +74 -0
  211. package/dist/esm/components/Textarea.d.ts +75 -0
  212. package/dist/esm/components/Textarea.js +75 -0
  213. package/dist/esm/components/Timeline.d.ts +124 -0
  214. package/dist/esm/components/Timeline.js +124 -0
  215. package/dist/esm/components/Toast.d.ts +155 -0
  216. package/dist/esm/components/Toast.js +155 -0
  217. package/dist/esm/components/Toggle.d.ts +75 -0
  218. package/dist/esm/components/Toggle.js +75 -0
  219. package/dist/esm/components/Tooltip.d.ts +80 -0
  220. package/dist/esm/components/Tooltip.js +80 -0
  221. package/dist/esm/components/TypographyComponents.d.ts +265 -0
  222. package/dist/esm/components/TypographyComponents.js +265 -0
  223. package/dist/esm/components/UtilityComponents.d.ts +345 -0
  224. package/dist/esm/components/UtilityComponents.js +345 -0
  225. package/dist/esm/components/Video.d.ts +82 -0
  226. package/dist/esm/components/Video.js +82 -0
  227. package/dist/esm/components/index.d.ts +311 -0
  228. package/dist/esm/components/index.js +311 -0
  229. package/dist/esm/index.d.ts +5 -0
  230. package/dist/esm/index.js +5 -0
  231. package/dist/esm/styles/main.css +493 -0
  232. package/dist/esm/theme/ThemeProvider.d.ts +185 -0
  233. package/dist/esm/theme/ThemeProvider.js +185 -0
  234. package/dist/esm/theme/index.d.ts +2 -0
  235. package/dist/esm/theme/index.js +2 -0
  236. package/dist/esm/utilities/classNames.d.ts +200 -0
  237. package/dist/esm/utilities/classNames.js +200 -0
  238. package/dist/esm/utilities/index.d.ts +3 -0
  239. package/dist/esm/utilities/index.js +3 -0
  240. package/dist/esm/utilities/styles.d.ts +94 -0
  241. package/dist/esm/utilities/styles.js +94 -0
  242. package/dist/styles/main.css +493 -0
  243. package/package.json +124 -6
  244. package/src/styles/main.css +493 -0
@@ -0,0 +1,298 @@
1
+ import React from 'react';
2
+
3
+ export interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
4
+ size?: 'sm' | 'md' | 'lg';
5
+ variant?: 'default' | 'outline' | 'filled' | 'flushed';
6
+ state?: 'default' | 'focus' | 'error' | 'success' | 'disabled';
7
+ label?: string;
8
+ error?: string;
9
+ helpText?: string;
10
+ prefix?: React.ReactNode;
11
+ suffix?: React.ReactNode;
12
+ icon?: React.ReactNode;
13
+ }
14
+
15
+ const baseSizeClass = {
16
+ sm: 'px-3 py-1.5 text-sm',
17
+ md: 'px-4 py-2 text-base',
18
+ lg: 'px-5 py-3 text-lg',
19
+ };
20
+
21
+ const baseVariantClass = {
22
+ default: 'border border-gray-300 bg-white',
23
+ outline: 'border-2 border-gray-300 bg-white',
24
+ filled: 'bg-gray-100 border-b-2 border-gray-300',
25
+ flushed: 'bg-transparent border-b-2 border-gray-300',
26
+ };
27
+
28
+ const baseStateClass = {
29
+ default: 'text-gray-900',
30
+ focus: 'border-blue-500 outline-none',
31
+ error: 'border-red-500 text-red-600',
32
+ success: 'border-green-500 text-green-600',
33
+ disabled: 'bg-gray-50 text-gray-400 cursor-not-allowed',
34
+ };
35
+
36
+ export const InputText: React.FC<FormInputProps> = ({
37
+ size = 'md',
38
+ variant = 'default',
39
+ state = 'default',
40
+ label,
41
+ error,
42
+ helpText,
43
+ prefix,
44
+ suffix,
45
+ className = '',
46
+ ...props
47
+ }) => {
48
+ return (
49
+ <div className="w-full">
50
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
51
+ <div className="relative flex items-center">
52
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
53
+ <input
54
+ type="text"
55
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
56
+ {...props}
57
+ />
58
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
59
+ </div>
60
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
61
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
62
+ </div>
63
+ );
64
+ };
65
+
66
+ export const InputEmail: React.FC<FormInputProps> = ({
67
+ size = 'md',
68
+ variant = 'default',
69
+ state = 'default',
70
+ label,
71
+ error,
72
+ helpText,
73
+ prefix,
74
+ suffix,
75
+ className = '',
76
+ ...props
77
+ }) => {
78
+ return (
79
+ <div className="w-full">
80
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
81
+ <div className="relative flex items-center">
82
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
83
+ <input
84
+ type="email"
85
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
86
+ {...props}
87
+ />
88
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
89
+ </div>
90
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
91
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
92
+ </div>
93
+ );
94
+ };
95
+
96
+ export const InputPassword: React.FC<FormInputProps & { showPassword?: boolean; onTogglePassword?: () => void }> = ({
97
+ size = 'md',
98
+ variant = 'default',
99
+ state = 'default',
100
+ label,
101
+ error,
102
+ helpText,
103
+ prefix,
104
+ showPassword = false,
105
+ onTogglePassword,
106
+ className = '',
107
+ ...props
108
+ }) => {
109
+ return (
110
+ <div className="w-full">
111
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
112
+ <div className="relative flex items-center">
113
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
114
+ <input
115
+ type={showPassword ? 'text' : 'password'}
116
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} pr-10 ${className}`}
117
+ {...props}
118
+ />
119
+ <button
120
+ type="button"
121
+ onClick={onTogglePassword}
122
+ className="absolute right-3 text-gray-500 hover:text-gray-700"
123
+ >
124
+ {showPassword ? '👁️' : '👁️‍🗨️'}
125
+ </button>
126
+ </div>
127
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
128
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
129
+ </div>
130
+ );
131
+ };
132
+
133
+ export const InputNumber: React.FC<FormInputProps> = ({
134
+ size = 'md',
135
+ variant = 'default',
136
+ state = 'default',
137
+ label,
138
+ error,
139
+ helpText,
140
+ prefix,
141
+ suffix,
142
+ className = '',
143
+ ...props
144
+ }) => {
145
+ return (
146
+ <div className="w-full">
147
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
148
+ <div className="relative flex items-center">
149
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
150
+ <input
151
+ type="number"
152
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
153
+ {...props}
154
+ />
155
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
156
+ </div>
157
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
158
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
159
+ </div>
160
+ );
161
+ };
162
+
163
+ export const InputDate: React.FC<FormInputProps> = ({
164
+ size = 'md',
165
+ variant = 'default',
166
+ state = 'default',
167
+ label,
168
+ error,
169
+ helpText,
170
+ className = '',
171
+ ...props
172
+ }) => {
173
+ return (
174
+ <div className="w-full">
175
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
176
+ <input
177
+ type="date"
178
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${className}`}
179
+ {...props}
180
+ />
181
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
182
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
183
+ </div>
184
+ );
185
+ };
186
+
187
+ export const InputTime: React.FC<FormInputProps> = ({
188
+ size = 'md',
189
+ variant = 'default',
190
+ state = 'default',
191
+ label,
192
+ error,
193
+ helpText,
194
+ className = '',
195
+ ...props
196
+ }) => {
197
+ return (
198
+ <div className="w-full">
199
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
200
+ <input
201
+ type="time"
202
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${className}`}
203
+ {...props}
204
+ />
205
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
206
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
207
+ </div>
208
+ );
209
+ };
210
+
211
+ export const InputTel: React.FC<FormInputProps> = ({
212
+ size = 'md',
213
+ variant = 'default',
214
+ state = 'default',
215
+ label,
216
+ error,
217
+ helpText,
218
+ prefix,
219
+ suffix,
220
+ className = '',
221
+ ...props
222
+ }) => {
223
+ return (
224
+ <div className="w-full">
225
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
226
+ <div className="relative flex items-center">
227
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
228
+ <input
229
+ type="tel"
230
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
231
+ {...props}
232
+ />
233
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
234
+ </div>
235
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
236
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
237
+ </div>
238
+ );
239
+ };
240
+
241
+ export const InputUrl: React.FC<FormInputProps> = ({
242
+ size = 'md',
243
+ variant = 'default',
244
+ state = 'default',
245
+ label,
246
+ error,
247
+ helpText,
248
+ prefix,
249
+ suffix,
250
+ className = '',
251
+ ...props
252
+ }) => {
253
+ return (
254
+ <div className="w-full">
255
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
256
+ <div className="relative flex items-center">
257
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
258
+ <input
259
+ type="url"
260
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
261
+ {...props}
262
+ />
263
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
264
+ </div>
265
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
266
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
267
+ </div>
268
+ );
269
+ };
270
+
271
+ export const InputSearch: React.FC<FormInputProps & { onSearch?: (value: string) => void }> = ({
272
+ size = 'md',
273
+ variant = 'default',
274
+ state = 'default',
275
+ label,
276
+ error,
277
+ helpText,
278
+ onSearch,
279
+ className = '',
280
+ ...props
281
+ }) => {
282
+ return (
283
+ <div className="w-full">
284
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
285
+ <div className="relative flex items-center">
286
+ <span className="absolute left-3 text-gray-500">🔍</span>
287
+ <input
288
+ type="search"
289
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} pl-10 ${className}`}
290
+ onChange={(e) => onSearch?.(e.target.value)}
291
+ {...props}
292
+ />
293
+ </div>
294
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
295
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
296
+ </div>
297
+ );
298
+ };
@@ -0,0 +1,298 @@
1
+ import React from 'react';
2
+
3
+ export interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
4
+ size?: 'sm' | 'md' | 'lg';
5
+ variant?: 'default' | 'outline' | 'filled' | 'flushed';
6
+ state?: 'default' | 'focus' | 'error' | 'success' | 'disabled';
7
+ label?: string;
8
+ error?: string;
9
+ helpText?: string;
10
+ prefix?: React.ReactNode;
11
+ suffix?: React.ReactNode;
12
+ icon?: React.ReactNode;
13
+ }
14
+
15
+ const baseSizeClass = {
16
+ sm: 'px-3 py-1.5 text-sm',
17
+ md: 'px-4 py-2 text-base',
18
+ lg: 'px-5 py-3 text-lg',
19
+ };
20
+
21
+ const baseVariantClass = {
22
+ default: 'border border-gray-300 bg-white',
23
+ outline: 'border-2 border-gray-300 bg-white',
24
+ filled: 'bg-gray-100 border-b-2 border-gray-300',
25
+ flushed: 'bg-transparent border-b-2 border-gray-300',
26
+ };
27
+
28
+ const baseStateClass = {
29
+ default: 'text-gray-900',
30
+ focus: 'border-blue-500 outline-none',
31
+ error: 'border-red-500 text-red-600',
32
+ success: 'border-green-500 text-green-600',
33
+ disabled: 'bg-gray-50 text-gray-400 cursor-not-allowed',
34
+ };
35
+
36
+ export const InputText: React.FC<FormInputProps> = ({
37
+ size = 'md',
38
+ variant = 'default',
39
+ state = 'default',
40
+ label,
41
+ error,
42
+ helpText,
43
+ prefix,
44
+ suffix,
45
+ className = '',
46
+ ...props
47
+ }) => {
48
+ return (
49
+ <div className="w-full">
50
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
51
+ <div className="relative flex items-center">
52
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
53
+ <input
54
+ type="text"
55
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
56
+ {...props}
57
+ />
58
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
59
+ </div>
60
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
61
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
62
+ </div>
63
+ );
64
+ };
65
+
66
+ export const InputEmail: React.FC<FormInputProps> = ({
67
+ size = 'md',
68
+ variant = 'default',
69
+ state = 'default',
70
+ label,
71
+ error,
72
+ helpText,
73
+ prefix,
74
+ suffix,
75
+ className = '',
76
+ ...props
77
+ }) => {
78
+ return (
79
+ <div className="w-full">
80
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
81
+ <div className="relative flex items-center">
82
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
83
+ <input
84
+ type="email"
85
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
86
+ {...props}
87
+ />
88
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
89
+ </div>
90
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
91
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
92
+ </div>
93
+ );
94
+ };
95
+
96
+ export const InputPassword: React.FC<FormInputProps & { showPassword?: boolean; onTogglePassword?: () => void }> = ({
97
+ size = 'md',
98
+ variant = 'default',
99
+ state = 'default',
100
+ label,
101
+ error,
102
+ helpText,
103
+ prefix,
104
+ showPassword = false,
105
+ onTogglePassword,
106
+ className = '',
107
+ ...props
108
+ }) => {
109
+ return (
110
+ <div className="w-full">
111
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
112
+ <div className="relative flex items-center">
113
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
114
+ <input
115
+ type={showPassword ? 'text' : 'password'}
116
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} pr-10 ${className}`}
117
+ {...props}
118
+ />
119
+ <button
120
+ type="button"
121
+ onClick={onTogglePassword}
122
+ className="absolute right-3 text-gray-500 hover:text-gray-700"
123
+ >
124
+ {showPassword ? '👁️' : '👁️‍🗨️'}
125
+ </button>
126
+ </div>
127
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
128
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
129
+ </div>
130
+ );
131
+ };
132
+
133
+ export const InputNumber: React.FC<FormInputProps> = ({
134
+ size = 'md',
135
+ variant = 'default',
136
+ state = 'default',
137
+ label,
138
+ error,
139
+ helpText,
140
+ prefix,
141
+ suffix,
142
+ className = '',
143
+ ...props
144
+ }) => {
145
+ return (
146
+ <div className="w-full">
147
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
148
+ <div className="relative flex items-center">
149
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
150
+ <input
151
+ type="number"
152
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
153
+ {...props}
154
+ />
155
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
156
+ </div>
157
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
158
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
159
+ </div>
160
+ );
161
+ };
162
+
163
+ export const InputDate: React.FC<FormInputProps> = ({
164
+ size = 'md',
165
+ variant = 'default',
166
+ state = 'default',
167
+ label,
168
+ error,
169
+ helpText,
170
+ className = '',
171
+ ...props
172
+ }) => {
173
+ return (
174
+ <div className="w-full">
175
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
176
+ <input
177
+ type="date"
178
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${className}`}
179
+ {...props}
180
+ />
181
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
182
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
183
+ </div>
184
+ );
185
+ };
186
+
187
+ export const InputTime: React.FC<FormInputProps> = ({
188
+ size = 'md',
189
+ variant = 'default',
190
+ state = 'default',
191
+ label,
192
+ error,
193
+ helpText,
194
+ className = '',
195
+ ...props
196
+ }) => {
197
+ return (
198
+ <div className="w-full">
199
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
200
+ <input
201
+ type="time"
202
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${className}`}
203
+ {...props}
204
+ />
205
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
206
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
207
+ </div>
208
+ );
209
+ };
210
+
211
+ export const InputTel: React.FC<FormInputProps> = ({
212
+ size = 'md',
213
+ variant = 'default',
214
+ state = 'default',
215
+ label,
216
+ error,
217
+ helpText,
218
+ prefix,
219
+ suffix,
220
+ className = '',
221
+ ...props
222
+ }) => {
223
+ return (
224
+ <div className="w-full">
225
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
226
+ <div className="relative flex items-center">
227
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
228
+ <input
229
+ type="tel"
230
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
231
+ {...props}
232
+ />
233
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
234
+ </div>
235
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
236
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
237
+ </div>
238
+ );
239
+ };
240
+
241
+ export const InputUrl: React.FC<FormInputProps> = ({
242
+ size = 'md',
243
+ variant = 'default',
244
+ state = 'default',
245
+ label,
246
+ error,
247
+ helpText,
248
+ prefix,
249
+ suffix,
250
+ className = '',
251
+ ...props
252
+ }) => {
253
+ return (
254
+ <div className="w-full">
255
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
256
+ <div className="relative flex items-center">
257
+ {prefix && <span className="absolute left-3 text-gray-500">{prefix}</span>}
258
+ <input
259
+ type="url"
260
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} ${prefix ? 'pl-10' : ''} ${suffix ? 'pr-10' : ''} ${className}`}
261
+ {...props}
262
+ />
263
+ {suffix && <span className="absolute right-3 text-gray-500">{suffix}</span>}
264
+ </div>
265
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
266
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
267
+ </div>
268
+ );
269
+ };
270
+
271
+ export const InputSearch: React.FC<FormInputProps & { onSearch?: (value: string) => void }> = ({
272
+ size = 'md',
273
+ variant = 'default',
274
+ state = 'default',
275
+ label,
276
+ error,
277
+ helpText,
278
+ onSearch,
279
+ className = '',
280
+ ...props
281
+ }) => {
282
+ return (
283
+ <div className="w-full">
284
+ {label && <label className="block text-sm font-medium text-gray-700 mb-1">{label}</label>}
285
+ <div className="relative flex items-center">
286
+ <span className="absolute left-3 text-gray-500">🔍</span>
287
+ <input
288
+ type="search"
289
+ className={`w-full rounded-lg transition-colors ${baseSizeClass[size]} ${baseVariantClass[variant]} ${baseStateClass[state]} pl-10 ${className}`}
290
+ onChange={(e) => onSearch?.(e.target.value)}
291
+ {...props}
292
+ />
293
+ </div>
294
+ {error && <p className="text-red-500 text-sm mt-1">{error}</p>}
295
+ {helpText && !error && <p className="text-gray-500 text-sm mt-1">{helpText}</p>}
296
+ </div>
297
+ );
298
+ };
@@ -0,0 +1,106 @@
1
+ import React from 'react';
2
+ import { cn } from '../utilities/classNames';
3
+
4
+ export interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
5
+ src: string;
6
+ alt: string;
7
+ width?: number | string;
8
+ height?: number | string;
9
+ fallback?: React.ReactNode;
10
+ rounded?: boolean;
11
+ border?: boolean;
12
+ shadow?: boolean;
13
+ aspect?: 'square' | 'video' | 'auto';
14
+ objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down';
15
+ onLoadingStateChange?: (state: 'loading' | 'loaded' | 'error') => void;
16
+ className?: string;
17
+ }
18
+
19
+ export const Image = React.forwardRef<HTMLImageElement, ImageProps>(
20
+ (
21
+ {
22
+ src,
23
+ alt,
24
+ width,
25
+ height,
26
+ fallback,
27
+ rounded = false,
28
+ border = false,
29
+ shadow = false,
30
+ aspect = 'auto',
31
+ objectFit = 'cover',
32
+ onLoadingStateChange,
33
+ className,
34
+ ...props
35
+ },
36
+ ref
37
+ ) => {
38
+ const [error, setError] = React.useState(false);
39
+ const [loading, setLoading] = React.useState(true);
40
+
41
+ const aspectClasses = {
42
+ square: 'aspect-square',
43
+ video: 'aspect-video',
44
+ auto: 'auto',
45
+ };
46
+
47
+ const handleLoad = () => {
48
+ setLoading(false);
49
+ onLoadingStateChange?.('loaded');
50
+ };
51
+
52
+ const handleError = () => {
53
+ setError(true);
54
+ setLoading(false);
55
+ onLoadingStateChange?.('error');
56
+ };
57
+
58
+ if (error && fallback) {
59
+ return <>{fallback}</>;
60
+ }
61
+
62
+ return (
63
+ <div
64
+ className={cn(
65
+ 'relative bg-gray-100',
66
+ aspectClasses[aspect] !== 'auto' && aspectClasses[aspect],
67
+ {
68
+ 'rounded-lg': rounded,
69
+ 'border border-gray-200': border,
70
+ 'shadow-md': shadow,
71
+ },
72
+ aspect === 'auto' && !height && 'w-full'
73
+ )}
74
+ style={{
75
+ width: typeof width === 'number' ? `${width}px` : width,
76
+ height: typeof height === 'number' ? `${height}px` : height,
77
+ }}
78
+ >
79
+ <img
80
+ ref={ref}
81
+ src={src}
82
+ alt={alt}
83
+ onLoad={handleLoad}
84
+ onError={handleError}
85
+ className={cn(
86
+ 'w-full h-full',
87
+ {
88
+ rounded: rounded,
89
+ 'animate-pulse': loading,
90
+ },
91
+ className
92
+ )}
93
+ style={{
94
+ objectFit: objectFit,
95
+ }}
96
+ {...props}
97
+ />
98
+ {loading && (
99
+ <div className="absolute inset-0 bg-gray-200 animate-pulse rounded-lg" />
100
+ )}
101
+ </div>
102
+ );
103
+ }
104
+ );
105
+
106
+ Image.displayName = 'Image';