fiboui 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 (141) hide show
  1. package/README.md +101 -0
  2. package/dist/content/Alert/index.d.ts +878 -0
  3. package/dist/content/Avatar/index.d.ts +886 -0
  4. package/dist/content/Badge/index.d.ts +887 -0
  5. package/dist/content/Image/index.d.ts +893 -0
  6. package/dist/content/Label/index.d.ts +879 -0
  7. package/dist/content/Progress/index.d.ts +898 -0
  8. package/dist/content/Skeleton/index.d.ts +879 -0
  9. package/dist/content/Spinner/index.d.ts +880 -0
  10. package/dist/content/Text/index.d.ts +878 -0
  11. package/dist/content/index.d.ts +9 -0
  12. package/dist/core/StateWrapper.d.ts +28 -0
  13. package/dist/core/builder.d.ts +50 -0
  14. package/dist/core/component.d.ts +7 -0
  15. package/dist/core/effects.d.ts +3 -0
  16. package/dist/core/icons.d.ts +11 -0
  17. package/dist/core/index.d.ts +5 -0
  18. package/dist/core/state.d.ts +37 -0
  19. package/dist/core/types.d.ts +51 -0
  20. package/dist/demo.d.ts +7 -0
  21. package/dist/effects-Co9C_Dyx.mjs +9 -0
  22. package/dist/examples/ScaffoldExamples.d.ts +3 -0
  23. package/dist/examples/StateExamples.d.ts +5 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.esm.js +4622 -0
  26. package/dist/index.umd.js +251 -0
  27. package/dist/interactive/Button/index.d.ts +897 -0
  28. package/dist/interactive/Checkbox/index.d.ts +884 -0
  29. package/dist/interactive/Combobox/index.d.ts +898 -0
  30. package/dist/interactive/RadioGroup/index.d.ts +888 -0
  31. package/dist/interactive/Select/index.d.ts +895 -0
  32. package/dist/interactive/Switch/index.d.ts +881 -0
  33. package/dist/interactive/TextField/index.d.ts +892 -0
  34. package/dist/interactive/Textarea/index.d.ts +890 -0
  35. package/dist/interactive/index.d.ts +8 -0
  36. package/dist/layout/Center/index.d.ts +869 -0
  37. package/dist/layout/Column/index.d.ts +881 -0
  38. package/dist/layout/Container/index.d.ts +870 -0
  39. package/dist/layout/DashboardLayout/index.d.ts +870 -0
  40. package/dist/layout/Header/index.d.ts +870 -0
  41. package/dist/layout/Line/index.d.ts +872 -0
  42. package/dist/layout/Row/index.d.ts +879 -0
  43. package/dist/layout/Scaffold/index.d.ts +878 -0
  44. package/dist/layout/ScrollView/index.d.ts +879 -0
  45. package/dist/layout/Sidebar/index.d.ts +870 -0
  46. package/dist/layout/Spacer/index.d.ts +875 -0
  47. package/dist/layout/StakentComponents.d.ts +4 -0
  48. package/dist/layout/index.d.ts +11 -0
  49. package/dist/structure/Banner/index.d.ts +879 -0
  50. package/dist/structure/Box/index.d.ts +869 -0
  51. package/dist/structure/Card/index.d.ts +881 -0
  52. package/dist/structure/Collapse/index.d.ts +884 -0
  53. package/dist/structure/Grid/index.d.ts +1757 -0
  54. package/dist/structure/List/index.d.ts +888 -0
  55. package/dist/structure/Table/index.d.ts +895 -0
  56. package/dist/structure/Tags/index.d.ts +876 -0
  57. package/dist/structure/cards/AssetCard/index.d.ts +884 -0
  58. package/dist/structure/cards/CollectionCard/index.d.ts +880 -0
  59. package/dist/structure/cards/ContentCard/index.d.ts +884 -0
  60. package/dist/structure/cards/ProfileCard/index.d.ts +892 -0
  61. package/dist/structure/cards/index.d.ts +5 -0
  62. package/dist/structure/cards/variants/index.d.ts +3490 -0
  63. package/dist/structure/index.d.ts +9 -0
  64. package/dist/style.css +1 -0
  65. package/dist/theme/cupertino.d.ts +3 -0
  66. package/dist/theme/index.d.ts +5 -0
  67. package/dist/theme/material.d.ts +3 -0
  68. package/dist/theme/provider.d.ts +16 -0
  69. package/dist/theme/types.d.ts +57 -0
  70. package/dist/theme/web.d.ts +3 -0
  71. package/package.json +54 -0
  72. package/src/content/Alert/index.ts +110 -0
  73. package/src/content/Avatar/index.ts +116 -0
  74. package/src/content/Badge/index.ts +162 -0
  75. package/src/content/Image/index.ts +137 -0
  76. package/src/content/Label/index.ts +66 -0
  77. package/src/content/Progress/index.ts +378 -0
  78. package/src/content/Skeleton/index.ts +71 -0
  79. package/src/content/Spinner/index.ts +139 -0
  80. package/src/content/Text/index.ts +74 -0
  81. package/src/content/index.ts +9 -0
  82. package/src/core/StateWrapper.tsx +105 -0
  83. package/src/core/builder.ts +259 -0
  84. package/src/core/component.ts +49 -0
  85. package/src/core/effects.ts +27 -0
  86. package/src/core/icons.tsx +57 -0
  87. package/src/core/index.ts +5 -0
  88. package/src/core/state.ts +233 -0
  89. package/src/core/types.ts +62 -0
  90. package/src/demo.tsx +1045 -0
  91. package/src/examples/ScaffoldExamples.tsx +299 -0
  92. package/src/examples/StateExamples.tsx +149 -0
  93. package/src/index.ts +8 -0
  94. package/src/interactive/Button/index.ts +218 -0
  95. package/src/interactive/Checkbox/index.ts +145 -0
  96. package/src/interactive/Combobox/index.ts +278 -0
  97. package/src/interactive/RadioGroup/index.ts +124 -0
  98. package/src/interactive/Select/index.ts +227 -0
  99. package/src/interactive/Switch/index.ts +123 -0
  100. package/src/interactive/TextField/index.ts +200 -0
  101. package/src/interactive/Textarea/index.ts +129 -0
  102. package/src/interactive/index.ts +8 -0
  103. package/src/layout/Center/index.ts +34 -0
  104. package/src/layout/Column/index.ts +101 -0
  105. package/src/layout/Container/index.ts +28 -0
  106. package/src/layout/DashboardLayout/index.ts +106 -0
  107. package/src/layout/Header/index.ts +50 -0
  108. package/src/layout/Line/index.ts +41 -0
  109. package/src/layout/Row/index.ts +93 -0
  110. package/src/layout/Scaffold/index.ts +133 -0
  111. package/src/layout/ScrollView/index.ts +67 -0
  112. package/src/layout/Sidebar/index.ts +56 -0
  113. package/src/layout/Spacer/index.ts +46 -0
  114. package/src/layout/StakentComponents.tsx +57 -0
  115. package/src/layout/index.ts +11 -0
  116. package/src/structure/Banner/index.ts +92 -0
  117. package/src/structure/Box/index.ts +45 -0
  118. package/src/structure/Card/index.ts +113 -0
  119. package/src/structure/Collapse/index.ts +122 -0
  120. package/src/structure/Grid/index.ts +197 -0
  121. package/src/structure/List/index.ts +185 -0
  122. package/src/structure/Table/index.ts +165 -0
  123. package/src/structure/Tags/index.ts +69 -0
  124. package/src/structure/cards/AssetCard/index.ts +158 -0
  125. package/src/structure/cards/CollectionCard/index.ts +95 -0
  126. package/src/structure/cards/ContentCard/index.ts +127 -0
  127. package/src/structure/cards/ProfileCard/index.ts +152 -0
  128. package/src/structure/cards/index.ts +5 -0
  129. package/src/structure/cards/variants/index.ts +301 -0
  130. package/src/structure/index.ts +10 -0
  131. package/src/styles/base.css +186 -0
  132. package/src/styles/core.css +52 -0
  133. package/src/styles/themes/cupertino.css +197 -0
  134. package/src/styles/themes/material.css +322 -0
  135. package/src/styles/themes/web.css +196 -0
  136. package/src/theme/cupertino.ts +85 -0
  137. package/src/theme/index.ts +5 -0
  138. package/src/theme/material.ts +86 -0
  139. package/src/theme/provider.tsx +76 -0
  140. package/src/theme/types.ts +62 -0
  141. package/src/theme/web.ts +82 -0
@@ -0,0 +1,378 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+ type ProgressVariant = 'default' | 'striped' | 'labeled' | 'circular' | 'segments' | 'knob' | 'steps' | 'chevron' | 'floating' | 'pagination' | 'timeline';
6
+
7
+ interface ProgressItem {
8
+ title?: string;
9
+ description?: string;
10
+ date?: string;
11
+ }
12
+
13
+ const ProgressInner = React.memo((props: any) => {
14
+ const {
15
+ value, max, color, height, variant = 'default',
16
+ label, subLabel, items = [],
17
+ className, style, ...rest
18
+ } = props;
19
+
20
+ const percentage = Math.min(100, Math.max(0, (value / max) * 100));
21
+ const mainColor = color || '#3B82F6';
22
+
23
+ if (variant === 'circular') {
24
+ const size = typeof height === 'number' ? height : 64;
25
+ const strokeWidth = 8;
26
+ const radius = (size - strokeWidth) / 2;
27
+ const circumference = radius * 2 * Math.PI;
28
+ const offset = circumference - (percentage / 100) * circumference;
29
+
30
+ return React.createElement('div', {
31
+ className: `relative inline-flex items-center justify-center ${className}`,
32
+ style: { width: size, height: size, ...style },
33
+ ...rest
34
+ }, [
35
+ React.createElement('svg', {
36
+ key: 'svg',
37
+ className: 'transform -rotate-90',
38
+ width: size,
39
+ height: size
40
+ }, [
41
+ React.createElement('circle', {
42
+ key: 'track',
43
+ className: 'text-gray-100',
44
+ stroke: 'currentColor',
45
+ strokeWidth: strokeWidth,
46
+ fill: 'transparent',
47
+ r: radius,
48
+ cx: size / 2,
49
+ cy: size / 2
50
+ }),
51
+ React.createElement('circle', {
52
+ key: 'prog',
53
+ stroke: mainColor,
54
+ strokeWidth: strokeWidth,
55
+ strokeDasharray: circumference,
56
+ strokeDashoffset: offset,
57
+ strokeLinecap: 'round',
58
+ fill: 'transparent',
59
+ r: radius,
60
+ cx: size / 2,
61
+ cy: size / 2,
62
+ className: 'transition-all duration-1000 ease-out'
63
+ })
64
+ ]),
65
+ React.createElement('span', {
66
+ key: 'label',
67
+ className: 'absolute text-sm font-bold text-gray-700'
68
+ }, label || `${Math.round(percentage)}%`)
69
+ ]);
70
+ }
71
+
72
+ if (variant === 'pagination') {
73
+ const count = 5;
74
+ const activeIndex = Math.floor((percentage / 100) * count);
75
+
76
+ return React.createElement('div', {
77
+ className: `flex items-center gap-2 ${className}`,
78
+ style,
79
+ ...rest
80
+ }, Array.from({ length: count }).map((_, i) => {
81
+ const isActive = i === activeIndex;
82
+ return React.createElement('div', {
83
+ key: i,
84
+ className: `h-3 rounded-full transition-all duration-300 ${isActive ? 'w-8' : 'w-3'}`,
85
+ style: { backgroundColor: i <= activeIndex ? mainColor : '#E5E7EB' }
86
+ });
87
+ }));
88
+ }
89
+
90
+ if (variant === 'timeline') {
91
+ const timelineItems = items.length ? items : [
92
+ { title: 'Order components', date: 'Done' },
93
+ { title: 'Draft implementation', date: 'In Progress' },
94
+ { title: 'Verify functionality', date: 'Pending' }
95
+ ];
96
+ const activeIndex = Math.floor((percentage / 100) * timelineItems.length);
97
+
98
+ return React.createElement('div', {
99
+ className: `flex flex-col relative ${className}`,
100
+ style,
101
+ ...rest
102
+ }, timelineItems.map((item: ProgressItem, i: number) => {
103
+ const isCompleted = i < activeIndex;
104
+ const isCurrent = i === activeIndex;
105
+ const isLast = i === timelineItems.length - 1;
106
+
107
+ const statusColor = isCompleted || isCurrent ? mainColor : '#E5E7EB';
108
+ const iconContent = isCompleted ? React.createElement('span', {}, '✓') : (i + 1);
109
+
110
+ return React.createElement('div', {
111
+ key: i,
112
+ className: `relative flex items-start gap-4 pb-8 last:pb-0`
113
+ }, [
114
+ !isLast && React.createElement('div', {
115
+ key: 'tail',
116
+ className: 'absolute left-[19px] top-10 bottom-0 w-0.5 transition-colors duration-500',
117
+ style: { backgroundColor: isCompleted ? mainColor : '#E5E7EB' }
118
+ }),
119
+
120
+ React.createElement('div', {
121
+ key: 'dot',
122
+ className: `relative z-10 w-10 h-10 rounded-full flex items-center justify-center border-2 bg-white transition-all duration-300 shrink-0 text-sm font-bold shadow-sm`,
123
+ style: {
124
+ borderColor: statusColor,
125
+ color: isCompleted ? '#fff' : (isCurrent ? statusColor : '#9CA3AF'),
126
+ backgroundColor: isCompleted ? statusColor : '#fff'
127
+ }
128
+ }, iconContent),
129
+
130
+ React.createElement('div', { key: 'content', className: 'pt-2' }, [
131
+ React.createElement('div', { className: 'text-sm font-bold text-gray-900 leading-none' }, item.title),
132
+ item.description && React.createElement('div', { className: 'text-xs text-gray-500 mt-1.5' }, item.description),
133
+ item.date && React.createElement('div', { className: 'text-xs font-mono text-gray-400 mt-1' }, item.date)
134
+ ])
135
+ ]);
136
+ }));
137
+ }
138
+
139
+ if (variant === 'floating') {
140
+ return React.createElement('div', {
141
+ className: `w-full bg-white rounded-xl shadow-sm border border-gray-100 p-4 relative overflow-hidden ${className}`,
142
+ style,
143
+ ...rest
144
+ }, [
145
+ React.createElement('div', { key: 'info', className: 'flex justify-between items-center mb-3 px-1' }, [
146
+ React.createElement('span', { key: 'l', className: 'text-sm font-semibold text-gray-700' },
147
+ label ? React.createElement('span', { className: 'text-blue-600 mr-2' }, `${Math.round(percentage)}%`) : null,
148
+ label || 'Update in progress...'
149
+ ),
150
+ subLabel && React.createElement('span', { key: 'r', className: 'text-xs font-medium text-gray-400' }, subLabel)
151
+ ]),
152
+ React.createElement('div', {
153
+ key: 'track',
154
+ className: 'w-full bg-blue-50 h-1.5 rounded-full overflow-hidden'
155
+ }, React.createElement('div', {
156
+ className: 'h-full rounded-full transition-all duration-1000 ease-out',
157
+ style: { width: `${percentage}%`, backgroundColor: mainColor }
158
+ }))
159
+ ]);
160
+ }
161
+
162
+ if (variant === 'chevron') {
163
+ const steps = 3;
164
+ const activeIndex = Math.floor((percentage / 100) * steps);
165
+
166
+ return React.createElement('div', {
167
+ className: `flex w-full rounded-lg overflow-hidden ${className}`,
168
+ style,
169
+ ...rest
170
+ }, Array.from({ length: steps }).map((_, i) => {
171
+ const isActive = i <= activeIndex;
172
+
173
+ return React.createElement('div', {
174
+ key: i,
175
+ className: `flex-1 h-10 flex items-center justify-center text-sm font-bold text-white transition-colors duration-300`,
176
+ style: {
177
+ backgroundColor: isActive ? (i === activeIndex ? mainColor : '#60A5FA') : '#E5E7EB',
178
+ clipPath: i === 0
179
+ ? 'polygon(0% 0%, 85% 0%, 100% 50%, 85% 100%, 0% 100%)'
180
+ : i === steps - 1
181
+ ? 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 15% 50%)'
182
+ : 'polygon(0% 0%, 85% 0%, 100% 50%, 85% 100%, 0% 100%, 15% 50%)',
183
+ marginLeft: i === 0 ? 0 : '-10px',
184
+ paddingLeft: i === 0 ? 0 : '10px',
185
+ zIndex: steps - i
186
+ }
187
+ }, `Step ${i + 1}`);
188
+ }));
189
+ }
190
+
191
+ if (variant === 'steps') {
192
+ const steps = 3;
193
+ const activeStep = Math.ceil((percentage / 100) * steps);
194
+
195
+ return React.createElement('div', {
196
+ className: `w-full flex items-center justify-between relative ${className}`,
197
+ style: {
198
+ marginTop: '1rem',
199
+ ...style
200
+ },
201
+ ...rest
202
+ }, [
203
+ React.createElement('div', {
204
+ key: 'line-bg',
205
+ className: 'absolute top-1/2 left-0 w-full h-1.5 bg-gray-200 z-0 transform -translate-y-1/2 rounded-full'
206
+ }),
207
+ React.createElement('div', {
208
+ key: 'line-active',
209
+ className: 'absolute top-1/2 left-0 h-1.5 z-0 transform -translate-y-1/2 transition-all duration-500 rounded-full',
210
+ style: { width: `${percentage}%`, backgroundColor: mainColor }
211
+ }),
212
+ ...Array.from({ length: steps }).map((_, i) => {
213
+ const stepNum = i + 1;
214
+ const isActive = stepNum <= activeStep;
215
+ const isCompleted = stepNum < activeStep;
216
+
217
+ return React.createElement('div', {
218
+ key: i,
219
+ className: `relative z-10 w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold transition-all duration-300 border-4 ${isActive ? 'text-white border-white shadow-md' : 'bg-gray-100 text-gray-400 border-gray-50'}`,
220
+ style: { backgroundColor: isActive ? mainColor : undefined }
221
+ }, isCompleted ? React.createElement('span', {}, '✔') : stepNum);
222
+ })
223
+ ]);
224
+ }
225
+
226
+ const heightVal = height || ((variant === 'labeled' || variant === 'knob') ? 12 : 12);
227
+
228
+ if (variant === 'segments') {
229
+ const segCount = 10;
230
+ const activeSegs = Math.round((percentage / 100) * segCount);
231
+
232
+ return React.createElement('div', {
233
+ className: `flex gap-1.5 w-full ${className}`,
234
+ style,
235
+ ...rest
236
+ },
237
+ Array.from({ length: segCount }).map((_, i) => React.createElement('div', {
238
+ key: i,
239
+ className: `h-3 flex-1 rounded-sm transition-all duration-300 first:rounded-l-full last:rounded-r-full`,
240
+ style: {
241
+ height: height || 12,
242
+ backgroundColor: i < activeSegs ? mainColor : '#E5E7EB'
243
+ }
244
+ }))
245
+ );
246
+ }
247
+
248
+ let innerContent: ReactElement | null = null;
249
+
250
+ if (variant === 'striped') {
251
+ innerContent = React.createElement('div', {
252
+ className: 'w-full h-full opacity-30 animate-[stripes_1s_linear_infinite]',
253
+ style: {
254
+ backgroundImage: 'linear-gradient(45deg,rgba(255,255,255,.25) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.25) 50%,rgba(255,255,255,.25) 75%,transparent 75%,transparent)',
255
+ backgroundSize: '20px 20px'
256
+ }
257
+ });
258
+ }
259
+
260
+ const labelElement = variant === 'labeled' ? React.createElement('div', {
261
+ className: 'absolute -top-12 transform -translate-x-1/2 bg-slate-800 text-white text-xs font-bold py-1.5 px-3 rounded-lg shadow-xl whitespace-nowrap',
262
+ style: { left: `${percentage}%` }
263
+ }, [
264
+ label || `${Math.round(percentage)}%`,
265
+ React.createElement('div', { key: 'arrow', className: 'absolute -bottom-1 left-1/2 transform -translate-x-1/2 w-2 h-2 bg-slate-800 rotate-45' })
266
+ ]) : null;
267
+
268
+ const knobElement = variant === 'knob' ? React.createElement('div', {
269
+ className: 'absolute top-1/2 right-0 w-7 h-7 bg-white rounded-full shadow-lg border-4 transform translate-x-1/2 -translate-y-1/2 flex items-center justify-center',
270
+ style: { borderColor: mainColor }
271
+ }, React.createElement('div', { className: 'w-1.5 h-1.5 rounded-full', style: { backgroundColor: mainColor } })) : null;
272
+
273
+ return React.createElement('div', {
274
+ className: `relative w-full ${variant === 'labeled' ? 'mt-8' : ''}`,
275
+ ...rest
276
+ }, [
277
+ labelElement,
278
+ React.createElement('div', {
279
+ key: 'track',
280
+ className: `w-full bg-slate-100 rounded-full ${className}`,
281
+ style: {
282
+ width: '100%',
283
+ height: heightVal,
284
+ ...style
285
+ }
286
+ },
287
+ React.createElement('div', {
288
+ className: `h-full transition-all duration-1000 ease-out rounded-full flex items-center justify-center relative`,
289
+ style: {
290
+ width: `${percentage}%`,
291
+ backgroundColor: mainColor
292
+ }
293
+ }, [innerContent, knobElement])
294
+ )
295
+ ]);
296
+ });
297
+
298
+ class ProgressBuilder extends FiboBuilder {
299
+ private _value: number = 0;
300
+ private _max: number = 100;
301
+ private _color?: string;
302
+ private _height?: number | string;
303
+ private _variant: ProgressVariant = 'default';
304
+ private _label?: string;
305
+ private _subLabel?: string;
306
+ private _items?: ProgressItem[];
307
+
308
+ value(current: number): this {
309
+ this._value = current;
310
+ return this;
311
+ }
312
+
313
+ max(total: number): this {
314
+ this._max = total;
315
+ return this;
316
+ }
317
+
318
+ color(hex: string): this {
319
+ this._color = hex;
320
+ return this;
321
+ }
322
+
323
+ height(val: number | string): this {
324
+ this._height = val;
325
+ return this;
326
+ }
327
+
328
+ variant(val: ProgressVariant): this {
329
+ this._variant = val;
330
+ return this;
331
+ }
332
+
333
+ label(text: string): this {
334
+ this._label = text;
335
+ return this;
336
+ }
337
+
338
+ subLabel(text: string): this {
339
+ this._subLabel = text;
340
+ return this;
341
+ }
342
+
343
+ items(list: ProgressItem[]): this {
344
+ this._items = list;
345
+ return this;
346
+ }
347
+
348
+ build(): ReactElement {
349
+ const props = {
350
+ value: this._value,
351
+ max: this._max,
352
+ color: this._color,
353
+ height: this._height,
354
+ variant: this._variant,
355
+ label: this._label,
356
+ subLabel: this._subLabel,
357
+ items: this._items,
358
+ className: this.getClassName(),
359
+ style: this.getStyle(),
360
+ ...this._props
361
+ };
362
+
363
+ return React.createElement(ProgressInner, props);
364
+ }
365
+ }
366
+
367
+
368
+ export const Progress = createBuilder(ProgressBuilder);
369
+
370
+ export interface ProgressProps extends BaseProps {
371
+ value: number;
372
+ max?: number;
373
+ color?: string;
374
+ variant?: ProgressVariant;
375
+ label?: string;
376
+ subLabel?: string;
377
+ items?: ProgressItem[];
378
+ }
@@ -0,0 +1,71 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+ const SkeletonInner = React.memo((props: any) => {
6
+ const { width, height, shape, className, style, ...rest } = props;
7
+
8
+ const baseClasses = ['animate-pulse', 'bg-gray-200', 'loading-skeleton'];
9
+
10
+ if (shape === 'circle') baseClasses.push('rounded-full');
11
+ else if (shape === 'rounded-sm') baseClasses.push('rounded-sm');
12
+ else if (shape === 'rounded-md') baseClasses.push('rounded-md');
13
+ else if (shape === 'rounded-lg') baseClasses.push('rounded-lg');
14
+ else if (shape === 'square') baseClasses.push('rounded-none');
15
+ else baseClasses.push('rounded');
16
+
17
+ return React.createElement('div', {
18
+ className: [...baseClasses, className].filter(Boolean).join(' '),
19
+ style: {
20
+ width: width,
21
+ height: height,
22
+ ...style
23
+ },
24
+ ...rest
25
+ });
26
+ });
27
+
28
+ type SkeletonShape = 'circle' | 'square' | 'rounded' | 'rounded-sm' | 'rounded-md' | 'rounded-lg';
29
+
30
+ class SkeletonBuilder extends FiboBuilder {
31
+ private _width: string | number = '100%';
32
+ private _height: string | number = '20px';
33
+ private _shape: SkeletonShape = 'rounded';
34
+
35
+ width(value: string | number): this {
36
+ this._width = value;
37
+ return this;
38
+ }
39
+
40
+ height(value: string | number): this {
41
+ this._height = value;
42
+ return this;
43
+ }
44
+
45
+ shape(value: SkeletonShape): this {
46
+ this._shape = value;
47
+ return this;
48
+ }
49
+
50
+ build(): ReactElement {
51
+ const props = {
52
+ width: this._width,
53
+ height: this._height,
54
+ shape: this._shape,
55
+ className: this.getClassName(),
56
+ style: this.getStyle(),
57
+ ...this._props
58
+ };
59
+
60
+ return React.createElement(SkeletonInner, props);
61
+ }
62
+ }
63
+
64
+
65
+ export const Skeleton = createBuilder(SkeletonBuilder);
66
+
67
+ export interface SkeletonProps extends BaseProps {
68
+ width?: string | number;
69
+ height?: string | number;
70
+ shape?: SkeletonShape;
71
+ }
@@ -0,0 +1,139 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps } from '../../core/types';
4
+
5
+ type SpinnerVariant = 'circle' | 'dots' | 'pulse' | 'blocks';
6
+ type SpinnerSize = 'sm' | 'md' | 'lg' | 'xl' | number;
7
+
8
+ const SpinnerInner = React.memo((props: any) => {
9
+ const { size, color, variant = 'circle', className, style, ...rest } = props;
10
+
11
+ const sizeMap: Record<string, number> = {
12
+ sm: 16,
13
+ md: 24,
14
+ lg: 32,
15
+ xl: 48
16
+ };
17
+
18
+ const pixelSize = typeof size === 'number' ? size : (sizeMap[size] || 24);
19
+ const mainColor = color || "currentColor";
20
+
21
+
22
+ const containerProps = {
23
+ className: `fibo-spinner ${className}`,
24
+ style: { width: pixelSize, height: pixelSize, ...style },
25
+ ...rest
26
+ };
27
+
28
+ if (variant === 'dots') {
29
+ return React.createElement('div', { ...containerProps, className: `${containerProps.className} flex items-center justify-between` },
30
+ [0, 1, 2].map(i => React.createElement('div', {
31
+ key: i,
32
+ className: 'w-[25%] h-[25%] rounded-full animate-bounce',
33
+ style: {
34
+ backgroundColor: mainColor,
35
+ animationDelay: `${i * 0.1}s`
36
+ }
37
+ }))
38
+ );
39
+ }
40
+
41
+ if (variant === 'pulse') {
42
+ return React.createElement('div', { ...containerProps, className: `${containerProps.className} relative flex items-center justify-center` },
43
+ [
44
+ React.createElement('div', {
45
+ key: 'ring',
46
+ className: 'absolute inset-0 rounded-full opacity-75 animate-ping',
47
+ style: { backgroundColor: mainColor }
48
+ }),
49
+ React.createElement('div', {
50
+ key: 'dot',
51
+ className: 'relative rounded-full h-[75%] w-[75%]',
52
+ style: { backgroundColor: mainColor }
53
+ })
54
+ ]
55
+ );
56
+ }
57
+
58
+ if (variant === 'blocks') {
59
+ return React.createElement('div', { ...containerProps, className: `${containerProps.className} grid grid-cols-2 gap-[10%] p-[10%]` },
60
+ [0, 1, 2, 3].map(i => React.createElement('div', {
61
+ key: i,
62
+ className: 'w-full h-full bg-current animate-pulse',
63
+ style: {
64
+ backgroundColor: mainColor,
65
+ animationDelay: `${i * 0.15}s`,
66
+ opacity: 0.6
67
+ }
68
+ }))
69
+ );
70
+ }
71
+
72
+
73
+ return React.createElement(
74
+ 'div',
75
+ { ...containerProps, className: `${containerProps.className} animate-spin` },
76
+ React.createElement("svg", {
77
+ xmlns: "http://www.w3.org/2000/svg",
78
+ fill: "none",
79
+ viewBox: "0 0 24 24",
80
+ style: { width: '100%', height: '100%' }
81
+ },
82
+ React.createElement("circle", {
83
+ className: "opacity-20",
84
+ cx: "12",
85
+ cy: "12",
86
+ r: "10",
87
+ stroke: mainColor,
88
+ strokeWidth: "4"
89
+ }),
90
+ React.createElement("path", {
91
+ className: "",
92
+ fill: mainColor,
93
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
94
+ }))
95
+ );
96
+ });
97
+
98
+ class SpinnerBuilder extends FiboBuilder {
99
+ private _size: SpinnerSize = 'md';
100
+ private _color?: string;
101
+ private _variant: SpinnerVariant = 'circle';
102
+
103
+ size(value: SpinnerSize): this {
104
+ this._size = value;
105
+ return this;
106
+ }
107
+
108
+ color(value: string): this {
109
+ this._color = value;
110
+ return this;
111
+ }
112
+
113
+ variant(value: SpinnerVariant): this {
114
+ this._variant = value;
115
+ return this;
116
+ }
117
+
118
+ build(): ReactElement {
119
+ const props = {
120
+ size: this._size,
121
+ color: this._color,
122
+ variant: this._variant,
123
+ className: this.getClassName(),
124
+ style: this.getStyle(),
125
+ ...this._props
126
+ };
127
+
128
+ return React.createElement(SpinnerInner, props);
129
+ }
130
+ }
131
+
132
+
133
+ export const Spinner = createBuilder(SpinnerBuilder);
134
+
135
+ export interface SpinnerProps extends BaseProps {
136
+ size?: SpinnerSize;
137
+ color?: string;
138
+ variant?: SpinnerVariant;
139
+ }
@@ -0,0 +1,74 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { FiboBuilder, createBuilder } from '../../core/builder';
3
+ import { BaseProps, TextType } from '../../core/types';
4
+
5
+ const TextInner = React.memo((props: any) => {
6
+ const { text, type, className, style, ...rest } = props;
7
+
8
+ const elementMap: Record<TextType, string> = {
9
+ h1: 'h1',
10
+ h2: 'h2',
11
+ h3: 'h3',
12
+ h4: 'h4',
13
+ h5: 'h5',
14
+ h6: 'h6',
15
+ body: 'p',
16
+ caption: 'span',
17
+ label: 'label',
18
+ };
19
+
20
+ return React.createElement(
21
+ elementMap[type as TextType],
22
+ {
23
+ className: `fibo-text fibo-text-${type} ${className}`,
24
+ style,
25
+ ...rest,
26
+ },
27
+ text
28
+ );
29
+ });
30
+
31
+ class TextBuilder extends FiboBuilder {
32
+ private _text: string = '';
33
+ private _type: TextType = 'body';
34
+
35
+ constructor(text: string = '') {
36
+ super();
37
+ this._text = text;
38
+ }
39
+
40
+ text(value: string): this {
41
+ this._text = value;
42
+ return this;
43
+ }
44
+
45
+ type(type: TextType): this {
46
+ this._type = type;
47
+ return this;
48
+ }
49
+
50
+ variant(variant: TextType): this {
51
+ this._type = variant;
52
+ return this;
53
+ }
54
+
55
+ build(): ReactElement {
56
+ const props = {
57
+ text: this._text,
58
+ type: this._type,
59
+ className: this.getClassName(),
60
+ style: this.getStyle(),
61
+ ...this._props
62
+ };
63
+ return React.createElement(TextInner, props);
64
+ }
65
+ }
66
+
67
+
68
+ export const Text = createBuilder(TextBuilder);
69
+
70
+ export interface TextProps extends BaseProps {
71
+ text: string;
72
+ type?: TextType;
73
+ variant?: TextType;
74
+ }
@@ -0,0 +1,9 @@
1
+ export * from './Avatar';
2
+ export * from './Badge';
3
+ export * from './Text';
4
+ export * from './Label';
5
+ export * from './Image';
6
+ export * from './Spinner';
7
+ export * from './Skeleton';
8
+ export * from './Alert';
9
+ export * from './Progress';