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.
- package/README.md +101 -0
- package/dist/content/Alert/index.d.ts +878 -0
- package/dist/content/Avatar/index.d.ts +886 -0
- package/dist/content/Badge/index.d.ts +887 -0
- package/dist/content/Image/index.d.ts +893 -0
- package/dist/content/Label/index.d.ts +879 -0
- package/dist/content/Progress/index.d.ts +898 -0
- package/dist/content/Skeleton/index.d.ts +879 -0
- package/dist/content/Spinner/index.d.ts +880 -0
- package/dist/content/Text/index.d.ts +878 -0
- package/dist/content/index.d.ts +9 -0
- package/dist/core/StateWrapper.d.ts +28 -0
- package/dist/core/builder.d.ts +50 -0
- package/dist/core/component.d.ts +7 -0
- package/dist/core/effects.d.ts +3 -0
- package/dist/core/icons.d.ts +11 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/state.d.ts +37 -0
- package/dist/core/types.d.ts +51 -0
- package/dist/demo.d.ts +7 -0
- package/dist/effects-Co9C_Dyx.mjs +9 -0
- package/dist/examples/ScaffoldExamples.d.ts +3 -0
- package/dist/examples/StateExamples.d.ts +5 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.esm.js +4622 -0
- package/dist/index.umd.js +251 -0
- package/dist/interactive/Button/index.d.ts +897 -0
- package/dist/interactive/Checkbox/index.d.ts +884 -0
- package/dist/interactive/Combobox/index.d.ts +898 -0
- package/dist/interactive/RadioGroup/index.d.ts +888 -0
- package/dist/interactive/Select/index.d.ts +895 -0
- package/dist/interactive/Switch/index.d.ts +881 -0
- package/dist/interactive/TextField/index.d.ts +892 -0
- package/dist/interactive/Textarea/index.d.ts +890 -0
- package/dist/interactive/index.d.ts +8 -0
- package/dist/layout/Center/index.d.ts +869 -0
- package/dist/layout/Column/index.d.ts +881 -0
- package/dist/layout/Container/index.d.ts +870 -0
- package/dist/layout/DashboardLayout/index.d.ts +870 -0
- package/dist/layout/Header/index.d.ts +870 -0
- package/dist/layout/Line/index.d.ts +872 -0
- package/dist/layout/Row/index.d.ts +879 -0
- package/dist/layout/Scaffold/index.d.ts +878 -0
- package/dist/layout/ScrollView/index.d.ts +879 -0
- package/dist/layout/Sidebar/index.d.ts +870 -0
- package/dist/layout/Spacer/index.d.ts +875 -0
- package/dist/layout/StakentComponents.d.ts +4 -0
- package/dist/layout/index.d.ts +11 -0
- package/dist/structure/Banner/index.d.ts +879 -0
- package/dist/structure/Box/index.d.ts +869 -0
- package/dist/structure/Card/index.d.ts +881 -0
- package/dist/structure/Collapse/index.d.ts +884 -0
- package/dist/structure/Grid/index.d.ts +1757 -0
- package/dist/structure/List/index.d.ts +888 -0
- package/dist/structure/Table/index.d.ts +895 -0
- package/dist/structure/Tags/index.d.ts +876 -0
- package/dist/structure/cards/AssetCard/index.d.ts +884 -0
- package/dist/structure/cards/CollectionCard/index.d.ts +880 -0
- package/dist/structure/cards/ContentCard/index.d.ts +884 -0
- package/dist/structure/cards/ProfileCard/index.d.ts +892 -0
- package/dist/structure/cards/index.d.ts +5 -0
- package/dist/structure/cards/variants/index.d.ts +3490 -0
- package/dist/structure/index.d.ts +9 -0
- package/dist/style.css +1 -0
- package/dist/theme/cupertino.d.ts +3 -0
- package/dist/theme/index.d.ts +5 -0
- package/dist/theme/material.d.ts +3 -0
- package/dist/theme/provider.d.ts +16 -0
- package/dist/theme/types.d.ts +57 -0
- package/dist/theme/web.d.ts +3 -0
- package/package.json +54 -0
- package/src/content/Alert/index.ts +110 -0
- package/src/content/Avatar/index.ts +116 -0
- package/src/content/Badge/index.ts +162 -0
- package/src/content/Image/index.ts +137 -0
- package/src/content/Label/index.ts +66 -0
- package/src/content/Progress/index.ts +378 -0
- package/src/content/Skeleton/index.ts +71 -0
- package/src/content/Spinner/index.ts +139 -0
- package/src/content/Text/index.ts +74 -0
- package/src/content/index.ts +9 -0
- package/src/core/StateWrapper.tsx +105 -0
- package/src/core/builder.ts +259 -0
- package/src/core/component.ts +49 -0
- package/src/core/effects.ts +27 -0
- package/src/core/icons.tsx +57 -0
- package/src/core/index.ts +5 -0
- package/src/core/state.ts +233 -0
- package/src/core/types.ts +62 -0
- package/src/demo.tsx +1045 -0
- package/src/examples/ScaffoldExamples.tsx +299 -0
- package/src/examples/StateExamples.tsx +149 -0
- package/src/index.ts +8 -0
- package/src/interactive/Button/index.ts +218 -0
- package/src/interactive/Checkbox/index.ts +145 -0
- package/src/interactive/Combobox/index.ts +278 -0
- package/src/interactive/RadioGroup/index.ts +124 -0
- package/src/interactive/Select/index.ts +227 -0
- package/src/interactive/Switch/index.ts +123 -0
- package/src/interactive/TextField/index.ts +200 -0
- package/src/interactive/Textarea/index.ts +129 -0
- package/src/interactive/index.ts +8 -0
- package/src/layout/Center/index.ts +34 -0
- package/src/layout/Column/index.ts +101 -0
- package/src/layout/Container/index.ts +28 -0
- package/src/layout/DashboardLayout/index.ts +106 -0
- package/src/layout/Header/index.ts +50 -0
- package/src/layout/Line/index.ts +41 -0
- package/src/layout/Row/index.ts +93 -0
- package/src/layout/Scaffold/index.ts +133 -0
- package/src/layout/ScrollView/index.ts +67 -0
- package/src/layout/Sidebar/index.ts +56 -0
- package/src/layout/Spacer/index.ts +46 -0
- package/src/layout/StakentComponents.tsx +57 -0
- package/src/layout/index.ts +11 -0
- package/src/structure/Banner/index.ts +92 -0
- package/src/structure/Box/index.ts +45 -0
- package/src/structure/Card/index.ts +113 -0
- package/src/structure/Collapse/index.ts +122 -0
- package/src/structure/Grid/index.ts +197 -0
- package/src/structure/List/index.ts +185 -0
- package/src/structure/Table/index.ts +165 -0
- package/src/structure/Tags/index.ts +69 -0
- package/src/structure/cards/AssetCard/index.ts +158 -0
- package/src/structure/cards/CollectionCard/index.ts +95 -0
- package/src/structure/cards/ContentCard/index.ts +127 -0
- package/src/structure/cards/ProfileCard/index.ts +152 -0
- package/src/structure/cards/index.ts +5 -0
- package/src/structure/cards/variants/index.ts +301 -0
- package/src/structure/index.ts +10 -0
- package/src/styles/base.css +186 -0
- package/src/styles/core.css +52 -0
- package/src/styles/themes/cupertino.css +197 -0
- package/src/styles/themes/material.css +322 -0
- package/src/styles/themes/web.css +196 -0
- package/src/theme/cupertino.ts +85 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/material.ts +86 -0
- package/src/theme/provider.tsx +76 -0
- package/src/theme/types.ts +62 -0
- package/src/theme/web.ts +82 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FiboBuilder, createBuilder } from '../../core/builder';
|
|
3
|
+
import { BaseProps } from '../../core/types';
|
|
4
|
+
|
|
5
|
+
type GridVariant = 'standard' | 'masonry' | 'bento';
|
|
6
|
+
type GridGap = 'none' | 'sm' | 'md' | 'lg' | 'xl' | number;
|
|
7
|
+
type GridCols = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
8
|
+
|
|
9
|
+
interface ResponsiveCols {
|
|
10
|
+
sm?: GridCols;
|
|
11
|
+
md?: GridCols;
|
|
12
|
+
lg?: GridCols;
|
|
13
|
+
xl?: GridCols;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const GridInner = React.memo((props: any) => {
|
|
17
|
+
const {
|
|
18
|
+
children,
|
|
19
|
+
variant = 'standard',
|
|
20
|
+
columns = 1,
|
|
21
|
+
gap = 'md',
|
|
22
|
+
className,
|
|
23
|
+
style,
|
|
24
|
+
...rest
|
|
25
|
+
} = props;
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const getGapClass = (g: GridGap) => {
|
|
29
|
+
if (typeof g === 'number') return '';
|
|
30
|
+
const gaps: Record<string, string> = {
|
|
31
|
+
none: 'gap-0',
|
|
32
|
+
sm: 'gap-2',
|
|
33
|
+
md: 'gap-4',
|
|
34
|
+
lg: 'gap-6',
|
|
35
|
+
xl: 'gap-8'
|
|
36
|
+
};
|
|
37
|
+
return gaps[g] || 'gap-4';
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const getGapStyle = (g: GridGap) => {
|
|
41
|
+
if (typeof g === 'number') return g + 'px';
|
|
42
|
+
return undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
const getColsClass = (cols: GridCols | ResponsiveCols) => {
|
|
47
|
+
if (typeof cols === 'number') return `grid-cols-${cols}`;
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
let classes = [];
|
|
51
|
+
if (cols.sm) classes.push(`sm:grid-cols-${cols.sm}`);
|
|
52
|
+
if (cols.md) classes.push(`md:grid-cols-${cols.md}`);
|
|
53
|
+
if (cols.lg) classes.push(`lg:grid-cols-${cols.lg}`);
|
|
54
|
+
if (cols.xl) classes.push(`xl:grid-cols-${cols.xl}`);
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
return classes.join(' ') || 'grid-cols-1';
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if (variant === 'masonry') {
|
|
62
|
+
const getMasonryColsClass = (cols: GridCols | ResponsiveCols) => {
|
|
63
|
+
if (typeof cols === 'number') return `columns-${cols}`;
|
|
64
|
+
let classes = [];
|
|
65
|
+
if (cols.sm) classes.push(`sm:columns-${cols.sm}`);
|
|
66
|
+
if (cols.md) classes.push(`md:columns-${cols.md}`);
|
|
67
|
+
if (cols.lg) classes.push(`lg:columns-${cols.lg}`);
|
|
68
|
+
if (cols.xl) classes.push(`xl:columns-${cols.xl}`);
|
|
69
|
+
return classes.join(' ') || 'columns-1';
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return React.createElement('div', {
|
|
73
|
+
className: `${getMasonryColsClass(columns)} ${getGapClass(gap)} space-y-4 ${className}`,
|
|
74
|
+
style: {
|
|
75
|
+
columnGap: getGapStyle(gap),
|
|
76
|
+
...style
|
|
77
|
+
},
|
|
78
|
+
...rest
|
|
79
|
+
}, React.Children.map(children, child =>
|
|
80
|
+
React.createElement('div', { className: 'break-inside-avoid mb-4' }, child)
|
|
81
|
+
));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
return React.createElement('div', {
|
|
86
|
+
className: `grid ${getColsClass(columns)} ${getGapClass(gap)} ${className}`,
|
|
87
|
+
style: {
|
|
88
|
+
gap: getGapStyle(gap),
|
|
89
|
+
...style
|
|
90
|
+
},
|
|
91
|
+
...rest
|
|
92
|
+
}, children);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
const GridItemInner = React.memo((props: any) => {
|
|
97
|
+
const { children, colSpan, rowSpan, className, style, ...rest } = props;
|
|
98
|
+
|
|
99
|
+
const getSpanClass = () => {
|
|
100
|
+
let classes = [];
|
|
101
|
+
if (colSpan) classes.push(`col-span-${colSpan}`);
|
|
102
|
+
if (rowSpan) classes.push(`row-span-${rowSpan}`);
|
|
103
|
+
return classes.join(' ');
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return React.createElement('div', {
|
|
107
|
+
className: `${getSpanClass()} ${className}`,
|
|
108
|
+
style,
|
|
109
|
+
...rest
|
|
110
|
+
}, children);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class GridBuilder extends FiboBuilder {
|
|
115
|
+
private _variant: GridVariant = 'standard';
|
|
116
|
+
private _columns: GridCols | ResponsiveCols = 1;
|
|
117
|
+
private _gap: GridGap = 'md';
|
|
118
|
+
protected _children: ReactNode[] = [];
|
|
119
|
+
|
|
120
|
+
variant(v: GridVariant): this {
|
|
121
|
+
this._variant = v;
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
columns(cols: GridCols | ResponsiveCols): this {
|
|
126
|
+
this._columns = cols;
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
gap(g: GridGap): this {
|
|
131
|
+
this._gap = g;
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
children(nodes: ReactNode[]): this {
|
|
136
|
+
this._children = nodes;
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
build(): ReactElement {
|
|
141
|
+
const props = {
|
|
142
|
+
variant: this._variant,
|
|
143
|
+
columns: this._columns,
|
|
144
|
+
gap: this._gap,
|
|
145
|
+
children: this._children,
|
|
146
|
+
className: this.getClassName(),
|
|
147
|
+
style: this.getStyle(),
|
|
148
|
+
...this._props
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return React.createElement(GridInner, props);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
class GridItemBuilder extends FiboBuilder {
|
|
156
|
+
private _colSpan?: number;
|
|
157
|
+
private _rowSpan?: number;
|
|
158
|
+
protected _children: ReactNode[] = [];
|
|
159
|
+
|
|
160
|
+
colSpan(span: number): this {
|
|
161
|
+
this._colSpan = span;
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
rowSpan(span: number): this {
|
|
166
|
+
this._rowSpan = span;
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
children(nodes: ReactNode[]): this {
|
|
171
|
+
this._children = nodes;
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
build(): ReactElement {
|
|
176
|
+
const props = {
|
|
177
|
+
colSpan: this._colSpan,
|
|
178
|
+
rowSpan: this._rowSpan,
|
|
179
|
+
children: this._children,
|
|
180
|
+
className: this.getClassName(),
|
|
181
|
+
style: this.getStyle(),
|
|
182
|
+
...this._props
|
|
183
|
+
};
|
|
184
|
+
return React.createElement(GridItemInner, props);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
export const Grid = createBuilder(GridBuilder);
|
|
190
|
+
|
|
191
|
+
export const GridItem = createBuilder(GridItemBuilder);
|
|
192
|
+
|
|
193
|
+
export interface GridProps extends BaseProps {
|
|
194
|
+
variant?: GridVariant;
|
|
195
|
+
columns?: GridCols | ResponsiveCols;
|
|
196
|
+
gap?: GridGap;
|
|
197
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FiboBuilder, createBuilder } from '../../core/builder';
|
|
3
|
+
import { BaseProps } from '../../core/types';
|
|
4
|
+
import { Box } from '../Box';
|
|
5
|
+
|
|
6
|
+
type ListVariant = 'default' | 'card' | 'floating';
|
|
7
|
+
|
|
8
|
+
const ListInner = React.memo((props: any) => {
|
|
9
|
+
const {
|
|
10
|
+
items,
|
|
11
|
+
renderItem,
|
|
12
|
+
variant,
|
|
13
|
+
separator,
|
|
14
|
+
loading,
|
|
15
|
+
threshold,
|
|
16
|
+
onEndReached,
|
|
17
|
+
className,
|
|
18
|
+
style
|
|
19
|
+
} = props;
|
|
20
|
+
|
|
21
|
+
const observerRef = React.useRef<HTMLDivElement>(null);
|
|
22
|
+
|
|
23
|
+
React.useEffect(() => {
|
|
24
|
+
if (!onEndReached || loading) return;
|
|
25
|
+
|
|
26
|
+
const observer = new IntersectionObserver(
|
|
27
|
+
(entries) => {
|
|
28
|
+
if (entries[0].isIntersecting) {
|
|
29
|
+
onEndReached?.();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{ threshold: threshold }
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (observerRef.current) {
|
|
36
|
+
observer.observe(observerRef.current);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return () => observer.disconnect();
|
|
40
|
+
}, [loading, items.length, onEndReached, threshold]);
|
|
41
|
+
|
|
42
|
+
const variantStyles: Record<ListVariant, any> = {
|
|
43
|
+
default: { gap: '0px' },
|
|
44
|
+
card: { gap: '12px' },
|
|
45
|
+
floating: { gap: '8px' }
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const itemContainerStyles: Record<ListVariant, any> = {
|
|
49
|
+
default: {
|
|
50
|
+
padding: '12px 16px',
|
|
51
|
+
borderBottom: separator ? '1px solid #F3F4F6' : 'none',
|
|
52
|
+
backgroundColor: 'transparent',
|
|
53
|
+
transition: 'background-color 0.2s'
|
|
54
|
+
},
|
|
55
|
+
card: {
|
|
56
|
+
padding: '16px',
|
|
57
|
+
backgroundColor: '#fff',
|
|
58
|
+
borderRadius: '16px',
|
|
59
|
+
boxShadow: '0 2px 8px -2px rgba(0,0,0,0.05)',
|
|
60
|
+
border: '1px solid #F3F4F6',
|
|
61
|
+
transition: 'transform 0.2s, box-shadow 0.2s'
|
|
62
|
+
},
|
|
63
|
+
floating: {
|
|
64
|
+
padding: '8px 12px',
|
|
65
|
+
borderRadius: '12px',
|
|
66
|
+
backgroundColor: 'transparent',
|
|
67
|
+
transition: 'background-color 0.2s'
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const variantClasses: Record<ListVariant, string[]> = {
|
|
72
|
+
default: ['hover:bg-gray-50', 'first:rounded-t-xl', 'last:rounded-b-xl'],
|
|
73
|
+
card: ['hover:-translate-y-0.5', 'hover:shadow-md'],
|
|
74
|
+
floating: ['hover:bg-white', 'hover:shadow-sm']
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return Box()
|
|
78
|
+
.className(className)
|
|
79
|
+
.classNames(['flex', 'flex-col', 'w-full'])
|
|
80
|
+
.style({
|
|
81
|
+
...variantStyles[variant as ListVariant],
|
|
82
|
+
...style
|
|
83
|
+
})
|
|
84
|
+
.children(
|
|
85
|
+
React.createElement(React.Fragment, {}, [
|
|
86
|
+
...items.map((item: any, index: number) =>
|
|
87
|
+
React.cloneElement(
|
|
88
|
+
Box()
|
|
89
|
+
.style(itemContainerStyles[variant as ListVariant])
|
|
90
|
+
.classNames(variantClasses[variant as ListVariant])
|
|
91
|
+
.children(
|
|
92
|
+
renderItem ? renderItem(item, index) : null
|
|
93
|
+
)
|
|
94
|
+
.build(),
|
|
95
|
+
{ key: `item-${index}` }
|
|
96
|
+
)
|
|
97
|
+
),
|
|
98
|
+
|
|
99
|
+
onEndReached && (
|
|
100
|
+
React.createElement('div', {
|
|
101
|
+
ref: observerRef,
|
|
102
|
+
className: 'py-4 flex justify-center w-full'
|
|
103
|
+
}, loading ? (
|
|
104
|
+
|
|
105
|
+
React.createElement('div', { className: 'animate-spin rounded-full h-5 w-5 border-2 border-gray-300 border-b-blue-600' })
|
|
106
|
+
) : (
|
|
107
|
+
|
|
108
|
+
React.createElement('div', { style: { height: '20px' } })
|
|
109
|
+
))
|
|
110
|
+
)
|
|
111
|
+
])
|
|
112
|
+
)
|
|
113
|
+
.build();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
class ListBuilder<T = any> extends FiboBuilder {
|
|
117
|
+
private _items: T[] = [];
|
|
118
|
+
private _renderItem?: (item: T, index: number) => ReactNode;
|
|
119
|
+
private _variant: ListVariant = 'default';
|
|
120
|
+
private _separator: boolean = false;
|
|
121
|
+
|
|
122
|
+
items(items: T[]): this {
|
|
123
|
+
this._items = items;
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
renderItem(fn: (item: T, index: number) => ReactNode): this {
|
|
128
|
+
this._renderItem = fn;
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
variant(variant: ListVariant): this {
|
|
133
|
+
this._variant = variant;
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
separator(show: boolean = true): this {
|
|
138
|
+
this._separator = show;
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private _onEndReached?: () => void;
|
|
143
|
+
private _loading: boolean = false;
|
|
144
|
+
private _threshold: number = 0.5;
|
|
145
|
+
|
|
146
|
+
onEndReached(handler: () => void): this {
|
|
147
|
+
this._onEndReached = handler;
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
loading(isLoading: boolean): this {
|
|
152
|
+
this._loading = isLoading;
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
threshold(value: number): this {
|
|
157
|
+
this._threshold = value;
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
build(): ReactElement {
|
|
162
|
+
const props = {
|
|
163
|
+
items: this._items,
|
|
164
|
+
renderItem: this._renderItem,
|
|
165
|
+
variant: this._variant,
|
|
166
|
+
separator: this._separator,
|
|
167
|
+
loading: this._loading,
|
|
168
|
+
threshold: this._threshold,
|
|
169
|
+
onEndReached: this._onEndReached,
|
|
170
|
+
className: this.getClassName(),
|
|
171
|
+
style: this.getStyle()
|
|
172
|
+
};
|
|
173
|
+
return React.createElement(ListInner, props);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
export const List = createBuilder(ListBuilder);
|
|
179
|
+
|
|
180
|
+
export interface ListProps<T = any> extends BaseProps {
|
|
181
|
+
items: T[];
|
|
182
|
+
renderItem?: (item: T, index: number) => ReactNode;
|
|
183
|
+
variant?: ListVariant;
|
|
184
|
+
separator?: boolean;
|
|
185
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FiboBuilder, createBuilder } from '../../core/builder';
|
|
3
|
+
import { BaseProps } from '../../core/types';
|
|
4
|
+
import { Box } from '../Box';
|
|
5
|
+
|
|
6
|
+
type TableVariant = 'default' | 'clean';
|
|
7
|
+
type TableDensity = 'compact' | 'standard' | 'relaxed';
|
|
8
|
+
|
|
9
|
+
export interface TableColumn<T = any> {
|
|
10
|
+
header: string;
|
|
11
|
+
accessor?: keyof T;
|
|
12
|
+
render?: (item: T) => ReactNode;
|
|
13
|
+
width?: string;
|
|
14
|
+
align?: 'left' | 'center' | 'right';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const TableInner = React.memo((props: any) => {
|
|
18
|
+
const {
|
|
19
|
+
data,
|
|
20
|
+
columns,
|
|
21
|
+
variant,
|
|
22
|
+
density,
|
|
23
|
+
striped,
|
|
24
|
+
width,
|
|
25
|
+
className,
|
|
26
|
+
style
|
|
27
|
+
} = props;
|
|
28
|
+
|
|
29
|
+
const tableStyles: React.CSSProperties = {
|
|
30
|
+
width: '100%',
|
|
31
|
+
borderCollapse: 'separate',
|
|
32
|
+
borderSpacing: '0',
|
|
33
|
+
...style
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (width) {
|
|
37
|
+
tableStyles.width = typeof width === 'number' ? `${width}px` : width;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const containerClass = variant === 'clean'
|
|
41
|
+
? ['bg-white', 'rounded-2xl', 'border', 'border-gray-100', 'overflow-hidden', 'shadow-sm']
|
|
42
|
+
: [];
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
const cellPadding: Record<TableDensity, string> = {
|
|
46
|
+
compact: '10px 16px',
|
|
47
|
+
standard: '16px 24px',
|
|
48
|
+
relaxed: '24px 32px'
|
|
49
|
+
};
|
|
50
|
+
const padding = cellPadding[density as TableDensity];
|
|
51
|
+
|
|
52
|
+
return Box()
|
|
53
|
+
.className(className)
|
|
54
|
+
.classNames(containerClass)
|
|
55
|
+
.children(
|
|
56
|
+
React.createElement('table', { style: tableStyles }, [
|
|
57
|
+
|
|
58
|
+
React.createElement('thead', { key: 'thead', className: 'bg-gray-50/50' },
|
|
59
|
+
React.createElement('tr', {},
|
|
60
|
+
columns.map((col: any, i: number) =>
|
|
61
|
+
React.createElement('th', {
|
|
62
|
+
key: i,
|
|
63
|
+
style: {
|
|
64
|
+
textAlign: col.align || 'left',
|
|
65
|
+
padding: padding,
|
|
66
|
+
width: col.width
|
|
67
|
+
},
|
|
68
|
+
className: 'text-xs font-bold text-gray-400 uppercase tracking-widest'
|
|
69
|
+
}, col.header)
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
),
|
|
73
|
+
|
|
74
|
+
React.createElement('tbody', { key: 'tbody' },
|
|
75
|
+
data.map((row: any, i: number) =>
|
|
76
|
+
React.createElement('tr', {
|
|
77
|
+
key: i,
|
|
78
|
+
|
|
79
|
+
className: `group transition-all duration-200 border-b border-gray-50 last:border-b-0 ${
|
|
80
|
+
striped && i % 2 !== 0 ? 'bg-gray-50/30' : 'bg-transparent'
|
|
81
|
+
} ${variant === 'clean' ? 'hover:bg-white hover:shadow-md hover:scale-[1.002] hover:z-10 relative' : 'hover:bg-gray-50/50'}`
|
|
82
|
+
},
|
|
83
|
+
columns.map((col: any, j: number) =>
|
|
84
|
+
React.createElement('td', {
|
|
85
|
+
key: j,
|
|
86
|
+
style: {
|
|
87
|
+
textAlign: col.align || 'left',
|
|
88
|
+
padding: padding,
|
|
89
|
+
borderTop: variant === 'default' ? '1px solid #F3F4F6' : 'none'
|
|
90
|
+
},
|
|
91
|
+
className: 'text-sm text-gray-900 font-medium'
|
|
92
|
+
},
|
|
93
|
+
col.render ? col.render(row) : (col.accessor ? row[col.accessor] as ReactNode : null)
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
])
|
|
100
|
+
).build();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
class TableBuilder<T = any> extends FiboBuilder {
|
|
104
|
+
private _data: T[] = [];
|
|
105
|
+
private _columns: TableColumn<T>[] = [];
|
|
106
|
+
private _variant: TableVariant = 'clean';
|
|
107
|
+
private _density: TableDensity = 'standard';
|
|
108
|
+
private _striped: boolean = false;
|
|
109
|
+
private _width: string | number | undefined;
|
|
110
|
+
|
|
111
|
+
data(items: T[]): this {
|
|
112
|
+
this._data = items;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
columns(cols: TableColumn<T>[]): this {
|
|
117
|
+
this._columns = cols;
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
variant(variant: TableVariant): this {
|
|
122
|
+
this._variant = variant;
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
density(density: TableDensity): this {
|
|
127
|
+
this._density = density;
|
|
128
|
+
return this;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
striped(enable: boolean = true): this {
|
|
132
|
+
this._striped = enable;
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
width(value: string | number): this {
|
|
137
|
+
this._width = value;
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
build(): ReactElement {
|
|
142
|
+
const props = {
|
|
143
|
+
data: this._data,
|
|
144
|
+
columns: this._columns,
|
|
145
|
+
variant: this._variant,
|
|
146
|
+
density: this._density,
|
|
147
|
+
striped: this._striped,
|
|
148
|
+
width: this._width,
|
|
149
|
+
className: this.getClassName(),
|
|
150
|
+
style: this.getStyle()
|
|
151
|
+
};
|
|
152
|
+
return React.createElement(TableInner, props);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
export const Table = createBuilder(TableBuilder);
|
|
158
|
+
|
|
159
|
+
export interface TableProps<T = any> extends BaseProps {
|
|
160
|
+
data: T[];
|
|
161
|
+
columns: TableColumn<T>[];
|
|
162
|
+
variant?: TableVariant;
|
|
163
|
+
density?: TableDensity;
|
|
164
|
+
striped?: boolean;
|
|
165
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import { FiboBuilder, createBuilder } from '../../core/builder';
|
|
3
|
+
import { BaseProps } from '../../core/types';
|
|
4
|
+
|
|
5
|
+
interface TagItem {
|
|
6
|
+
title: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const TagsInner = React.memo((props: any) => {
|
|
10
|
+
const { items, className, style, ...rest } = props;
|
|
11
|
+
|
|
12
|
+
const tags = items.map((item: TagItem, index: number) =>
|
|
13
|
+
React.createElement(
|
|
14
|
+
'span',
|
|
15
|
+
{
|
|
16
|
+
key: index,
|
|
17
|
+
className: 'fibo-tag',
|
|
18
|
+
},
|
|
19
|
+
item.title
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
return React.createElement(
|
|
24
|
+
'div',
|
|
25
|
+
{
|
|
26
|
+
className,
|
|
27
|
+
style,
|
|
28
|
+
...rest,
|
|
29
|
+
},
|
|
30
|
+
...tags
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
class TagsBuilder extends FiboBuilder {
|
|
35
|
+
private _items: TagItem[] = [];
|
|
36
|
+
|
|
37
|
+
constructor(items: TagItem[] = []) {
|
|
38
|
+
super();
|
|
39
|
+
this._items = items;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
items(items: TagItem[]): this {
|
|
43
|
+
this._items = items;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
build(): ReactElement {
|
|
48
|
+
const className = ['fibo-tags', 'flex', 'gap-2', 'flex-wrap', ...this._classNames]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.join(' ');
|
|
51
|
+
|
|
52
|
+
const props = {
|
|
53
|
+
items: this._items,
|
|
54
|
+
className: className,
|
|
55
|
+
style: this.getStyle(),
|
|
56
|
+
...this._props
|
|
57
|
+
};
|
|
58
|
+
return React.createElement(TagsInner, props);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
export const Tags = createBuilder(TagsBuilder);
|
|
64
|
+
|
|
65
|
+
export interface TagsProps extends BaseProps {
|
|
66
|
+
items: TagItem[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type { TagItem };
|