flysoft-react-ui 1.2.10 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_CONTEXT.md +1533 -1401
- package/AI_INTEGRATION_GUIDE.md +358 -343
- package/README.md +498 -464
- package/dist/components/form-controls/Button.d.ts.map +1 -1
- package/dist/components/form-controls/Checkbox.d.ts.map +1 -1
- package/dist/components/form-controls/CurrencyInput.d.ts.map +1 -1
- package/dist/components/form-controls/DatePicker.d.ts.map +1 -1
- package/dist/components/form-controls/Input.d.ts.map +1 -1
- package/dist/components/form-controls/LinkButton.d.ts.map +1 -1
- package/dist/components/form-controls/Pagination.d.ts.map +1 -1
- package/dist/components/form-controls/RadioButtonGroup.d.ts.map +1 -1
- package/dist/components/layout/Accordion.d.ts +8 -0
- package/dist/components/layout/Accordion.d.ts.map +1 -1
- package/dist/components/layout/Card.d.ts +5 -0
- package/dist/components/layout/Card.d.ts.map +1 -1
- package/dist/components/layout/Collection.d.ts +17 -1
- package/dist/components/layout/Collection.d.ts.map +1 -1
- package/dist/components/layout/DataField.d.ts +19 -0
- package/dist/components/layout/DataField.d.ts.map +1 -1
- package/dist/components/layout/DataTable.d.ts.map +1 -1
- package/dist/components/layout/DropdownMenu.d.ts.map +1 -1
- package/dist/components/layout/DropdownPanel.d.ts.map +1 -1
- package/dist/components/layout/Filter.d.ts +8 -0
- package/dist/components/layout/Filter.d.ts.map +1 -1
- package/dist/components/layout/Menu.d.ts.map +1 -1
- package/dist/components/layout/TabsGroup.d.ts.map +1 -1
- package/dist/components/utils/Avatar.d.ts.map +1 -1
- package/dist/components/utils/Badge.d.ts.map +1 -1
- package/dist/components/utils/Dialog.d.ts.map +1 -1
- package/dist/components/utils/Loader.d.ts.map +1 -1
- package/dist/components/utils/RoadMap.d.ts.map +1 -1
- package/dist/components/utils/Snackbar.d.ts.map +1 -1
- package/dist/contexts/AppLayoutContext.d.ts +5 -1
- package/dist/contexts/AppLayoutContext.d.ts.map +1 -1
- package/dist/contexts/ThemeContext.d.ts +11 -1
- package/dist/contexts/ThemeContext.d.ts.map +1 -1
- package/dist/contexts/index.d.ts +2 -2
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/contexts/presets.d.ts +5 -1
- package/dist/contexts/presets.d.ts.map +1 -1
- package/dist/contexts/types.d.ts +51 -0
- package/dist/contexts/types.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +8020 -7426
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/AI_INTEGRATION_GUIDE.md
CHANGED
|
@@ -1,343 +1,358 @@
|
|
|
1
|
-
# AI Integration Guide (Consumer Projects)
|
|
2
|
-
|
|
3
|
-
This file is designed to be copied into any client project that consumes `flysoft-react-ui`. It helps AI agents understand the complete API surface and generate correct code.
|
|
4
|
-
|
|
5
|
-
## 1) Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install flysoft-react-ui
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## 2) Required Runtime Setup
|
|
12
|
-
|
|
13
|
-
At app root:
|
|
14
|
-
|
|
15
|
-
```tsx
|
|
16
|
-
import { ThemeProvider } from "flysoft-react-ui";
|
|
17
|
-
import "flysoft-react-ui/styles";
|
|
18
|
-
|
|
19
|
-
export function AppRoot() {
|
|
20
|
-
return <ThemeProvider initialTheme="light">{/* app */}</ThemeProvider>;
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
For
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- `
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
- `
|
|
79
|
-
- `
|
|
80
|
-
- `
|
|
81
|
-
- `
|
|
82
|
-
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
85
|
-
- `
|
|
86
|
-
- `
|
|
87
|
-
- `
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
93
|
-
- `
|
|
94
|
-
- `
|
|
95
|
-
- `
|
|
96
|
-
- `
|
|
97
|
-
-
|
|
98
|
-
- `
|
|
99
|
-
- `
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- `
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- `
|
|
106
|
-
- `
|
|
107
|
-
- `
|
|
108
|
-
- `
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- `
|
|
112
|
-
- `
|
|
113
|
-
- `
|
|
114
|
-
- `
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
120
|
-
- `
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
124
|
-
|
|
125
|
-
###
|
|
126
|
-
- `
|
|
127
|
-
- `
|
|
128
|
-
- `
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
- `
|
|
132
|
-
- `
|
|
133
|
-
- `
|
|
134
|
-
- `
|
|
135
|
-
- `
|
|
136
|
-
- `
|
|
137
|
-
- `
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- `
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
###
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
<
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
<
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
]
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
<
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
1
|
+
# AI Integration Guide (Consumer Projects)
|
|
2
|
+
|
|
3
|
+
This file is designed to be copied into any client project that consumes `flysoft-react-ui`. It helps AI agents understand the complete API surface and generate correct code.
|
|
4
|
+
|
|
5
|
+
## 1) Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install flysoft-react-ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2) Required Runtime Setup
|
|
12
|
+
|
|
13
|
+
At app root:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { ThemeProvider } from "flysoft-react-ui";
|
|
17
|
+
import "flysoft-react-ui/styles";
|
|
18
|
+
|
|
19
|
+
export function AppRoot() {
|
|
20
|
+
return <ThemeProvider initialTheme="light">{/* app */}</ThemeProvider>;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For data-heavy apps (admin panels, dashboards, CRUDs with lots of info per
|
|
25
|
+
screen), set a tighter global `density`:
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<ThemeProvider initialTheme="light" density="dense">
|
|
29
|
+
{/* app */}
|
|
30
|
+
</ThemeProvider>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Density is a global axis (`"comfortable"` | `"compact"` | `"dense"`) that
|
|
34
|
+
adjusts padding, gaps, typography and control heights via CSS variables.
|
|
35
|
+
Per-component overrides (`compact`, `size`) keep working on top of it.
|
|
36
|
+
|
|
37
|
+
For full app layout with navbar, sidebar, and snackbars:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { AppLayoutProvider } from "flysoft-react-ui";
|
|
41
|
+
import "flysoft-react-ui/styles";
|
|
42
|
+
|
|
43
|
+
export function AppRoot() {
|
|
44
|
+
return (
|
|
45
|
+
<AppLayoutProvider
|
|
46
|
+
initialTheme="light"
|
|
47
|
+
density="dense" // optional: comfortable | compact | dense
|
|
48
|
+
initialNavbar={{ navBarLeftNode: <h1>Mi App</h1>, fullWidthNavbar: true }}
|
|
49
|
+
>
|
|
50
|
+
{/* routes */}
|
|
51
|
+
</AppLayoutProvider>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 3) Copy-paste prompt for AI agents
|
|
57
|
+
|
|
58
|
+
Copy the following block into `.cursorrules`, `AGENTS.md`, `copilot-instructions.md`, `CLAUDE.md`, or your AI system prompt:
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
```md
|
|
63
|
+
This project uses `flysoft-react-ui` as the default UI library.
|
|
64
|
+
|
|
65
|
+
## Rules
|
|
66
|
+
1. Always import from `flysoft-react-ui` (top-level only). Never from internal paths.
|
|
67
|
+
2. Prefer existing library components before creating custom UI. Never duplicate Button, Input, Card, Badge, Dialog, etc.
|
|
68
|
+
3. Use exported TypeScript types for type safety (e.g. ButtonProps, DataTableColumn<T>).
|
|
69
|
+
4. Keep style import at app root only: `import "flysoft-react-ui/styles";`
|
|
70
|
+
5. Wrap app with `ThemeProvider` (or `AppLayoutProvider` for full layout).
|
|
71
|
+
6. Use FontAwesome 5 icon classes (`fa-*`). Components auto-normalize to light style (fal). Never use other icon libraries.
|
|
72
|
+
7. Use theme CSS variables for custom styling: `var(--color-primary)`, `var(--color-bg-default)`, etc.
|
|
73
|
+
8. To change a form-control's background (e.g. inside a same-color Card), pass a `bg-*` via `className` — form-controls merge classes with `twMerge` so it overrides the default. Ex: `<Input className="bg-[var(--color-bg-secondary)]" />`. For `Filter`, use its `bgColor` prop instead.
|
|
74
|
+
|
|
75
|
+
## Available Components
|
|
76
|
+
|
|
77
|
+
### Form Controls
|
|
78
|
+
- `Button` — variant: "primary"|"outline"|"ghost", size: "sm"|"md"|"lg", color: "primary"|"secondary"|"success"|"warning"|"danger"|"info", icon, loading, bg, textColor
|
|
79
|
+
- `LinkButton` — Same as Button but renders as link. Props: to (route/URL), target, variant, size, color, icon
|
|
80
|
+
- `Input` — label, error, icon, iconPosition, size, onIconClick, readOnly. Extends HTML input attributes
|
|
81
|
+
- `AutocompleteInput<T,K>` — Searchable dropdown. Props: options, value, onChange, multiple, getOptionLabel, getOptionValue, renderOption, noResultsText
|
|
82
|
+
- `SearchSelectInput<T,K>` — Dialog-based async search. Props: onSearchPromiseFn, onSingleSearchPromiseFn, dialogTitle, getOptionLabel, getOptionValue
|
|
83
|
+
- `DatePicker` — Standalone calendar. Props: value (Dayjs), onChange, startWeekOn
|
|
84
|
+
- `DateInput` — Input with DatePicker dropdown. Props: value (Dayjs|string), onChange, format ("dd/mm/yyyy"|"mm/dd/yyyy")
|
|
85
|
+
- `Checkbox` — Props: label, labelPosition, error, size, readOnly
|
|
86
|
+
- `RadioButtonGroup` — Props: options ({label,value,disabled}[]), value, onChange, direction ("vertical"|"horizontal"), gap, size
|
|
87
|
+
- `CurrencyInput` — Numeric input formatted as currency (es-AR: 1.234,56). Props: value (number), onChange
|
|
88
|
+
- `Pagination` — URL-based pagination. Props: page, pages, total, isLoading, fieldName
|
|
89
|
+
|
|
90
|
+
### Layout & Data
|
|
91
|
+
- `Card` — Props: title, subtitle, headerActions, footer, variant ("default"|"elevated"|"outlined"), compact (override local de densidad → fuerza preset compact en `--flysoft-density-*` dentro de la card y descendientes), alwaysDisplayHeaderActions
|
|
92
|
+
- `AppLayout` — Main layout. Props: navbar (NavbarInterface), leftDrawer (LeftDrawerInterface), children
|
|
93
|
+
- `Collection` — Flex container density-aware. Props: gap ("tight"|"sm"|"md"|"lg"|string), direction, wrap, density ("comfortable"|"compact"|"dense", override local que redefine `--flysoft-density-*` para esta collection y descendientes)
|
|
94
|
+
- `DataField` — Label+value pair density-aware. Props: label, value, inline, align, link, size ("sm"|"md", "sm" baja un nivel de tipografía), gap ("tight"|"sm"|"md", separación label/value en stack), hideColon (oculta `:` en modo inline)
|
|
95
|
+
- `TabsGroup` + `TabPanel` — Tabbed interface. TabsGroup: tabs ({id,label}[]), paramName (URL sync). TabPanel: tabId
|
|
96
|
+
- `DataTable<T>` — Data table density-aware. Props: columns (DataTableColumn<T>[]), rows, maxRows, isLoading, loadingRows, compact (override local de densidad → fuerza preset compact en `--flysoft-density-*` dentro de la tabla y sus DropdownMenu de acciones), locale
|
|
97
|
+
- DataTableColumn: header, value (key or function), type ("text"|"numeric"|"currency"|"date"), actions, width, align, tooltip, footer
|
|
98
|
+
- `Accordion` — Collapsible section. Props: title, icon, rightNode, defaultOpen, variant, headerClassName, contentClassName, onToggle
|
|
99
|
+
- `Menu<T>` — Simple menu list. Props: options, onOptionSelected, getOptionLabel, renderOption
|
|
100
|
+
- `DropdownMenu<T>` — Portal dropdown. Props: options, onOptionSelected, renderNode, openOnHover, replaceOnSingleOption
|
|
101
|
+
- `DropdownPanel` — Portal dropdown with arbitrary content. Props: children, renderNode, openOnHover
|
|
102
|
+
- `Filter` — Versatile filter by type. filterType: "text"|"number"|"date"|"autocomplete"|"search"|"searchSelect". Props: paramName (URL sync), label, value, onChange
|
|
103
|
+
|
|
104
|
+
### Utility & Feedback
|
|
105
|
+
- `Badge` — Props: variant, size, rounded, icon, iconPosition, bg, textColor, onClick
|
|
106
|
+
- `Avatar` — Props: text (for initials), image, bgColor, textColor, size
|
|
107
|
+
- `RoadMap` — Stage visualization. Props: stages ({name, description?, icon?, variant?, bg?, disabled?}[])
|
|
108
|
+
- `Dialog` — Modal density-aware. Props: isOpen, title, children, footer, onClose, closeOnOverlayClick, compact (override local de densidad), bodyWidth
|
|
109
|
+
- `Loader` — Loading indicator. Props: isLoading, text, keepContentWhileLoading, contentLoadingNode, overlayClassName
|
|
110
|
+
- `FiltersDialog` — Groups multiple filters in dialog. Props: filters (FilterConfig[])
|
|
111
|
+
- `Snackbar` — (Used internally) Toast notification
|
|
112
|
+
- `SnackbarContainer` — Place at root. Props: position, maxSnackbars
|
|
113
|
+
- `Skeleton` — Pulse placeholder. Props: className
|
|
114
|
+
- `ThemeSwitcher` — No props. Self-contained theme toggle
|
|
115
|
+
|
|
116
|
+
### Templates
|
|
117
|
+
- `LoginForm` — Props: onSubmit, loading, error, className
|
|
118
|
+
- `RegistrationForm` — Props: onSubmit, loading, error, className
|
|
119
|
+
- `ContactForm` — Props: onSubmit, loading, success, error, className
|
|
120
|
+
- `DashboardLayout` — Props: title, subtitle, stats (DashboardStat[]), actions, children
|
|
121
|
+
- `SidebarLayout` — Props: title, menuItems (MenuItem[]), user (User), onLogout, children
|
|
122
|
+
- `FormPattern` — Dynamic form builder. Props: title, fields (FormField[]), onSubmit, gridCols, submitText, submitIcon, loading, error, success
|
|
123
|
+
- `ListPattern<T>` — List page with Card + search + filters + pagination + DataTable. Props: title, columns, rows, searchParamName, onAdd, addButtonText, filtersNode, page, pages, total, isLoading, compact
|
|
124
|
+
|
|
125
|
+
### Contexts & Hooks
|
|
126
|
+
- `ThemeProvider` — initialTheme, storageKey, forceInitialTheme, onThemeChange, density ("comfortable" | "compact" | "dense"), densityStorageKey, forceInitialDensity, onDensityChange
|
|
127
|
+
- `useTheme()` — Returns: theme, setTheme, updateTheme, currentThemeName, availableThemes, isDark, resetToDefault, density, setDensity
|
|
128
|
+
- `AuthProvider` — getToken, getUserData, refreshToken, removeToken
|
|
129
|
+
- `AuthContext` — user, login, logout, isAuthenticated, isLoading
|
|
130
|
+
- `CrudProvider<T>` — getPromise, getItemPromise, postPromise, putPromise, deletePromise, urlParams, limit, pageParam
|
|
131
|
+
- `useCrud<T>()` — Returns: list, item, isLoading, pagination, fetchItems, fetchItem, createItem, updateItem, deleteItem, params, page, pages, total
|
|
132
|
+
- `SnackbarProvider` + `useSnackbar()` — showSnackbar(message, variant?, options?), removeSnackbar(id)
|
|
133
|
+
- `AppLayoutProvider` — Combines Theme + Snackbar + AppLayout. Accepts density/densityStorageKey/forceInitialDensity/onDensityChange (propagated to ThemeProvider) in addition to theme props. useAppLayout() to set navbar/drawer dynamically
|
|
134
|
+
- `useAsyncRequest(options)` — Returns: execute(fn), isLoading. Options: successMessage, errorMessage, onSuccess, onError
|
|
135
|
+
- `useBreakpoint()` — Returns: breakpoint, windowSize, isMobile, isTablet, isDesktop
|
|
136
|
+
- `useThemeOverride(options)` — Returns: applyOverride, revertOverride, revertAllOverrides
|
|
137
|
+
- `useElementScroll(ref)` — Returns: scrollY, scrollDirection
|
|
138
|
+
- `useEnum(enum)` — Returns: getArray(), getInstance(id)
|
|
139
|
+
|
|
140
|
+
### Services
|
|
141
|
+
- `apiClient` — HTTP client. Methods: get<T>, post<T>, put<T>, del<T>, getFile, downloadFile, uploadFile, openFile
|
|
142
|
+
- `setApiClientTokenProvider(fn)` — Set auth token globally
|
|
143
|
+
- `createApiClient(config)` — Create isolated API client instance
|
|
144
|
+
|
|
145
|
+
### Helpers
|
|
146
|
+
- `currencyFormat(n)` → "1.234,56"
|
|
147
|
+
- `getErrorMessage(error)` → user-friendly error string
|
|
148
|
+
- `getInitialLetters(text)` → "JP" from "Juan Pérez"
|
|
149
|
+
- `objectToQueryString(obj)` → "a=1&b=2"
|
|
150
|
+
- `queryStringToObject(str)` → {a: "1", b: "2"}
|
|
151
|
+
- `promiseMapper(promise, mapperFn)` — Maps paginated/array/single results
|
|
152
|
+
- `RegularExpressions` — .email, .dateString, .password(config)
|
|
153
|
+
|
|
154
|
+
### Interfaces
|
|
155
|
+
- `NameValueInterface<T>` — { name: string; value: T; extras?: any }
|
|
156
|
+
- `PaginationInterface<T>` — { list: T[]; limit: number; page: number; pages: number; total: number }
|
|
157
|
+
|
|
158
|
+
## Common Patterns
|
|
159
|
+
|
|
160
|
+
### CRUD List Page
|
|
161
|
+
```tsx
|
|
162
|
+
<CrudProvider<User>
|
|
163
|
+
getPromise={(params) => apiClient.get({ url: "/api/users", params })}
|
|
164
|
+
deletePromise={{ execute: (u) => apiClient.del({ url: `/api/users/${u.id}` }), successMessage: "Eliminado" }}
|
|
165
|
+
urlParams={["nombre"]}
|
|
166
|
+
>
|
|
167
|
+
<UserList />
|
|
168
|
+
</CrudProvider>
|
|
169
|
+
|
|
170
|
+
function UserList() {
|
|
171
|
+
const { list, isLoading, pagination, deleteItem } = useCrud<User>();
|
|
172
|
+
const columns: DataTableColumn<User>[] = [
|
|
173
|
+
{ header: "Nombre", value: "name" },
|
|
174
|
+
{ header: "Email", value: "email" },
|
|
175
|
+
{ actions: (row) => [
|
|
176
|
+
<Button key="del" variant="ghost" size="sm" icon="fa-trash" color="danger"
|
|
177
|
+
loading={deleteItem.isLoading} onClick={() => deleteItem.execute(row)}>
|
|
178
|
+
Eliminar
|
|
179
|
+
</Button>
|
|
180
|
+
]}
|
|
181
|
+
];
|
|
182
|
+
return (
|
|
183
|
+
<Card title="Usuarios">
|
|
184
|
+
<Filter filterType="text" paramName="nombre" label="Nombre" />
|
|
185
|
+
<DataTable columns={columns} rows={list ?? []} isLoading={isLoading} />
|
|
186
|
+
{pagination}
|
|
187
|
+
</Card>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Form with Async Save
|
|
193
|
+
```tsx
|
|
194
|
+
const { execute, isLoading } = useAsyncRequest({
|
|
195
|
+
successMessage: "Guardado exitosamente",
|
|
196
|
+
errorMessage: (err) => getErrorMessage(err),
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
<Card title="Nuevo Usuario">
|
|
200
|
+
<Input label="Nombre" value={name} onChange={(e) => setName(e.target.value)} icon="fa-user" />
|
|
201
|
+
<Input label="Email" type="email" value={email} onChange={(e) => setEmail(e.target.value)} icon="fa-envelope" />
|
|
202
|
+
<Button variant="primary" icon="fa-save" loading={isLoading}
|
|
203
|
+
onClick={() => execute(() => apiClient.post({ url: "/api/users", body: { name, email } }))}>
|
|
204
|
+
Guardar
|
|
205
|
+
</Button>
|
|
206
|
+
</Card>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Dialog Confirmation
|
|
210
|
+
```tsx
|
|
211
|
+
<Dialog isOpen={showConfirm} title="Confirmar eliminación" onClose={() => setShowConfirm(false)}
|
|
212
|
+
footer={<>
|
|
213
|
+
<Button variant="ghost" onClick={() => setShowConfirm(false)}>Cancelar</Button>
|
|
214
|
+
<Button variant="primary" color="danger" icon="fa-trash" onClick={handleDelete}>Eliminar</Button>
|
|
215
|
+
</>}
|
|
216
|
+
>
|
|
217
|
+
<p>¿Está seguro?</p>
|
|
218
|
+
</Dialog>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### List Page (without CrudContext)
|
|
222
|
+
Full implementation of Card + search + filters + pagination + DataTable. Uses URL query params for filters and pagination.
|
|
223
|
+
```tsx
|
|
224
|
+
import { useState, useEffect } from "react";
|
|
225
|
+
import { useSearchParams } from "react-router-dom";
|
|
226
|
+
import {
|
|
227
|
+
Card, Button, Collection, Filter, Pagination, DataTable, Dialog,
|
|
228
|
+
} from "flysoft-react-ui";
|
|
229
|
+
import type { DataTableColumn } from "flysoft-react-ui";
|
|
230
|
+
|
|
231
|
+
interface User { id: number; name: string; email: string; role: string; }
|
|
232
|
+
|
|
233
|
+
function UserListPage() {
|
|
234
|
+
const [searchParams] = useSearchParams();
|
|
235
|
+
const [users, setUsers] = useState<User[]>([]);
|
|
236
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
237
|
+
const [page, setPage] = useState(1);
|
|
238
|
+
const [pages, setPages] = useState(1);
|
|
239
|
+
const [total, setTotal] = useState(0);
|
|
240
|
+
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
|
241
|
+
const [selectedUser, setSelectedUser] = useState<User>();
|
|
242
|
+
|
|
243
|
+
// Read filters from URL
|
|
244
|
+
const search = searchParams.get("buscar") || "";
|
|
245
|
+
const role = searchParams.get("rol") || "";
|
|
246
|
+
const currentPage = Number(searchParams.get("pagina") || "1");
|
|
247
|
+
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
setIsLoading(true);
|
|
250
|
+
fetchUsers({ search, role, page: currentPage }).then((res) => {
|
|
251
|
+
setUsers(res.list);
|
|
252
|
+
setPage(res.page);
|
|
253
|
+
setPages(res.pages);
|
|
254
|
+
setTotal(res.total);
|
|
255
|
+
setIsLoading(false);
|
|
256
|
+
});
|
|
257
|
+
}, [search, role, currentPage]);
|
|
258
|
+
|
|
259
|
+
const columns: DataTableColumn<User>[] = [
|
|
260
|
+
{ header: "Nombre", value: (row) => row.name },
|
|
261
|
+
{ header: "Email", value: (row) => row.email },
|
|
262
|
+
{ header: "Rol", value: (row) => row.role },
|
|
263
|
+
{
|
|
264
|
+
align: "center",
|
|
265
|
+
actions: (row) => [
|
|
266
|
+
<Button key="edit" size="sm" variant="ghost" icon="fa-edit"
|
|
267
|
+
onClick={() => handleEdit(row)}>Editar</Button>,
|
|
268
|
+
<Button key="del" size="sm" variant="ghost" icon="fa-trash"
|
|
269
|
+
onClick={() => { setSelectedUser(row); setShowDeleteDialog(true); }}>
|
|
270
|
+
Eliminar
|
|
271
|
+
</Button>,
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<>
|
|
278
|
+
<Card
|
|
279
|
+
title="Usuarios"
|
|
280
|
+
alwaysDisplayHeaderActions
|
|
281
|
+
headerActions={
|
|
282
|
+
<Button icon="fa-plus" onClick={() => handleAdd()}>
|
|
283
|
+
Nuevo Usuario
|
|
284
|
+
</Button>
|
|
285
|
+
}
|
|
286
|
+
>
|
|
287
|
+
<div className="flex justify-between items-center my-2">
|
|
288
|
+
<Collection direction="row" wrap>
|
|
289
|
+
<Filter paramName="buscar" label="Buscar" filterType="search" />
|
|
290
|
+
<Filter paramName="rol" label="Rol" filterType="autocomplete"
|
|
291
|
+
options={[
|
|
292
|
+
{ label: "Admin", value: "admin" },
|
|
293
|
+
{ label: "Editor", value: "editor" },
|
|
294
|
+
]}
|
|
295
|
+
/>
|
|
296
|
+
</Collection>
|
|
297
|
+
<Collection direction="row" wrap>
|
|
298
|
+
<Pagination page={page} pages={pages} total={total}
|
|
299
|
+
fieldName="pagina" isLoading={isLoading} />
|
|
300
|
+
</Collection>
|
|
301
|
+
</div>
|
|
302
|
+
<DataTable columns={columns} rows={users}
|
|
303
|
+
isLoading={isLoading} loadingRows={10} maxRows={10} />
|
|
304
|
+
</Card>
|
|
305
|
+
|
|
306
|
+
<Dialog isOpen={showDeleteDialog} title="Eliminar usuario"
|
|
307
|
+
onClose={() => setShowDeleteDialog(false)}
|
|
308
|
+
footer={<>
|
|
309
|
+
<Button variant="outline" onClick={() => setShowDeleteDialog(false)}>Cancelar</Button>
|
|
310
|
+
<Button variant="primary" color="danger" icon="fa-trash"
|
|
311
|
+
onClick={() => handleDelete(selectedUser)}>Eliminar</Button>
|
|
312
|
+
</>}
|
|
313
|
+
>
|
|
314
|
+
<p>¿Está seguro de eliminar a {selectedUser?.name}?</p>
|
|
315
|
+
</Dialog>
|
|
316
|
+
</>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### List Page (using ListPattern template)
|
|
322
|
+
Same pattern as above but using the `ListPattern` template component for less boilerplate:
|
|
323
|
+
```tsx
|
|
324
|
+
import { ListPattern, Filter } from "flysoft-react-ui";
|
|
325
|
+
import type { DataTableColumn } from "flysoft-react-ui";
|
|
326
|
+
|
|
327
|
+
const columns: DataTableColumn<User>[] = [
|
|
328
|
+
{ header: "Nombre", value: (row) => row.name },
|
|
329
|
+
{ header: "Email", value: (row) => row.email },
|
|
330
|
+
{ actions: (row) => [
|
|
331
|
+
<Button key="edit" size="sm" variant="ghost" icon="fa-edit" onClick={() => edit(row)}>Editar</Button>,
|
|
332
|
+
]},
|
|
333
|
+
];
|
|
334
|
+
|
|
335
|
+
<ListPattern<User>
|
|
336
|
+
title="Usuarios"
|
|
337
|
+
columns={columns}
|
|
338
|
+
rows={users}
|
|
339
|
+
searchParamName="buscar"
|
|
340
|
+
addButtonText="Nuevo"
|
|
341
|
+
onAdd={() => setShowForm(true)}
|
|
342
|
+
filtersNode={
|
|
343
|
+
<Filter paramName="rol" label="Rol" filterType="autocomplete"
|
|
344
|
+
options={[{ label: "Admin", value: "admin" }]} />
|
|
345
|
+
}
|
|
346
|
+
page={page} pages={pages} total={total}
|
|
347
|
+
isLoading={isLoading}
|
|
348
|
+
/>
|
|
349
|
+
```
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## 4) Notes for library maintainers
|
|
355
|
+
|
|
356
|
+
- `src/docs/**` is local demo/dev-only and is not part of public API.
|
|
357
|
+
- Public API must be exported from `src/index.ts`.
|
|
358
|
+
- See `AI_CONTEXT.md` for complete prop interfaces and detailed documentation.
|