@nocios/crudify-components 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/.github/workflows/test.yml +59 -0
- package/.nvmrc +1 -0
- package/README.md +398 -0
- package/README_DEPTH.md +1230 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +85 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +506 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/CrudiaMarkdownField-C54-A_J3.d.mts +328 -0
- package/dist/CrudiaMarkdownField-C8HQh7s5.d.ts +328 -0
- package/dist/GlobalNotificationProvider-Zq18OkpI.d.mts +96 -0
- package/dist/GlobalNotificationProvider-Zq18OkpI.d.ts +96 -0
- package/dist/api-B4uXiHF0.d.mts +118 -0
- package/dist/api-B4uXiHF0.d.ts +118 -0
- package/dist/chunk-2XOTIEKS.js +1 -0
- package/dist/chunk-5HFI5CZ5.js +1 -0
- package/dist/chunk-CHDM7KGH.js +1 -0
- package/dist/chunk-HVTRRU4W.mjs +1 -0
- package/dist/chunk-JAPL7EZJ.mjs +1 -0
- package/dist/chunk-JNEWPO2J.mjs +1 -0
- package/dist/chunk-MFYHD6S5.js +1 -0
- package/dist/chunk-MGJZTOEM.mjs +1 -0
- package/dist/chunk-NBQH6QOU.mjs +1 -0
- package/dist/chunk-NSV6ECYO.js +1 -0
- package/dist/chunk-PNI3ZBZV.js +1 -0
- package/dist/chunk-U4RS66TB.mjs +1 -0
- package/dist/components.d.mts +24 -0
- package/dist/components.d.ts +24 -0
- package/dist/components.js +1 -0
- package/dist/components.mjs +1 -0
- package/dist/errorTranslation-DGdrMidg.d.ts +143 -0
- package/dist/errorTranslation-qwwQTvCO.d.mts +143 -0
- package/dist/hooks.d.mts +6 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +1 -0
- package/dist/hooks.mjs +1 -0
- package/dist/index-BUKX3duW.d.ts +854 -0
- package/dist/index-Y9tTsinC.d.mts +854 -0
- package/dist/index.d.mts +1274 -0
- package/dist/index.d.ts +1274 -0
- package/dist/index.js +6 -0
- package/dist/index.mjs +6 -0
- package/dist/utils.d.mts +175 -0
- package/dist/utils.d.ts +175 -0
- package/dist/utils.js +1 -0
- package/dist/utils.mjs +1 -0
- package/package.json +88 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
var addSorting = (function() {
|
|
3
|
+
'use strict';
|
|
4
|
+
var cols,
|
|
5
|
+
currentSort = {
|
|
6
|
+
index: 0,
|
|
7
|
+
desc: false
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// returns the summary table element
|
|
11
|
+
function getTable() {
|
|
12
|
+
return document.querySelector('.coverage-summary');
|
|
13
|
+
}
|
|
14
|
+
// returns the thead element of the summary table
|
|
15
|
+
function getTableHeader() {
|
|
16
|
+
return getTable().querySelector('thead tr');
|
|
17
|
+
}
|
|
18
|
+
// returns the tbody element of the summary table
|
|
19
|
+
function getTableBody() {
|
|
20
|
+
return getTable().querySelector('tbody');
|
|
21
|
+
}
|
|
22
|
+
// returns the th element for nth column
|
|
23
|
+
function getNthColumn(n) {
|
|
24
|
+
return getTableHeader().querySelectorAll('th')[n];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function onFilterInput() {
|
|
28
|
+
const searchValue = document.getElementById('fileSearch').value;
|
|
29
|
+
const rows = document.getElementsByTagName('tbody')[0].children;
|
|
30
|
+
|
|
31
|
+
// Try to create a RegExp from the searchValue. If it fails (invalid regex),
|
|
32
|
+
// it will be treated as a plain text search
|
|
33
|
+
let searchRegex;
|
|
34
|
+
try {
|
|
35
|
+
searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive
|
|
36
|
+
} catch (error) {
|
|
37
|
+
searchRegex = null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < rows.length; i++) {
|
|
41
|
+
const row = rows[i];
|
|
42
|
+
let isMatch = false;
|
|
43
|
+
|
|
44
|
+
if (searchRegex) {
|
|
45
|
+
// If a valid regex was created, use it for matching
|
|
46
|
+
isMatch = searchRegex.test(row.textContent);
|
|
47
|
+
} else {
|
|
48
|
+
// Otherwise, fall back to the original plain text search
|
|
49
|
+
isMatch = row.textContent
|
|
50
|
+
.toLowerCase()
|
|
51
|
+
.includes(searchValue.toLowerCase());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
row.style.display = isMatch ? '' : 'none';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// loads the search box
|
|
59
|
+
function addSearchBox() {
|
|
60
|
+
var template = document.getElementById('filterTemplate');
|
|
61
|
+
var templateClone = template.content.cloneNode(true);
|
|
62
|
+
templateClone.getElementById('fileSearch').oninput = onFilterInput;
|
|
63
|
+
template.parentElement.appendChild(templateClone);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// loads all columns
|
|
67
|
+
function loadColumns() {
|
|
68
|
+
var colNodes = getTableHeader().querySelectorAll('th'),
|
|
69
|
+
colNode,
|
|
70
|
+
cols = [],
|
|
71
|
+
col,
|
|
72
|
+
i;
|
|
73
|
+
|
|
74
|
+
for (i = 0; i < colNodes.length; i += 1) {
|
|
75
|
+
colNode = colNodes[i];
|
|
76
|
+
col = {
|
|
77
|
+
key: colNode.getAttribute('data-col'),
|
|
78
|
+
sortable: !colNode.getAttribute('data-nosort'),
|
|
79
|
+
type: colNode.getAttribute('data-type') || 'string'
|
|
80
|
+
};
|
|
81
|
+
cols.push(col);
|
|
82
|
+
if (col.sortable) {
|
|
83
|
+
col.defaultDescSort = col.type === 'number';
|
|
84
|
+
colNode.innerHTML =
|
|
85
|
+
colNode.innerHTML + '<span class="sorter"></span>';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return cols;
|
|
89
|
+
}
|
|
90
|
+
// attaches a data attribute to every tr element with an object
|
|
91
|
+
// of data values keyed by column name
|
|
92
|
+
function loadRowData(tableRow) {
|
|
93
|
+
var tableCols = tableRow.querySelectorAll('td'),
|
|
94
|
+
colNode,
|
|
95
|
+
col,
|
|
96
|
+
data = {},
|
|
97
|
+
i,
|
|
98
|
+
val;
|
|
99
|
+
for (i = 0; i < tableCols.length; i += 1) {
|
|
100
|
+
colNode = tableCols[i];
|
|
101
|
+
col = cols[i];
|
|
102
|
+
val = colNode.getAttribute('data-value');
|
|
103
|
+
if (col.type === 'number') {
|
|
104
|
+
val = Number(val);
|
|
105
|
+
}
|
|
106
|
+
data[col.key] = val;
|
|
107
|
+
}
|
|
108
|
+
return data;
|
|
109
|
+
}
|
|
110
|
+
// loads all row data
|
|
111
|
+
function loadData() {
|
|
112
|
+
var rows = getTableBody().querySelectorAll('tr'),
|
|
113
|
+
i;
|
|
114
|
+
|
|
115
|
+
for (i = 0; i < rows.length; i += 1) {
|
|
116
|
+
rows[i].data = loadRowData(rows[i]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// sorts the table using the data for the ith column
|
|
120
|
+
function sortByIndex(index, desc) {
|
|
121
|
+
var key = cols[index].key,
|
|
122
|
+
sorter = function(a, b) {
|
|
123
|
+
a = a.data[key];
|
|
124
|
+
b = b.data[key];
|
|
125
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
126
|
+
},
|
|
127
|
+
finalSorter = sorter,
|
|
128
|
+
tableBody = document.querySelector('.coverage-summary tbody'),
|
|
129
|
+
rowNodes = tableBody.querySelectorAll('tr'),
|
|
130
|
+
rows = [],
|
|
131
|
+
i;
|
|
132
|
+
|
|
133
|
+
if (desc) {
|
|
134
|
+
finalSorter = function(a, b) {
|
|
135
|
+
return -1 * sorter(a, b);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (i = 0; i < rowNodes.length; i += 1) {
|
|
140
|
+
rows.push(rowNodes[i]);
|
|
141
|
+
tableBody.removeChild(rowNodes[i]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
rows.sort(finalSorter);
|
|
145
|
+
|
|
146
|
+
for (i = 0; i < rows.length; i += 1) {
|
|
147
|
+
tableBody.appendChild(rows[i]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// removes sort indicators for current column being sorted
|
|
151
|
+
function removeSortIndicators() {
|
|
152
|
+
var col = getNthColumn(currentSort.index),
|
|
153
|
+
cls = col.className;
|
|
154
|
+
|
|
155
|
+
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
|
|
156
|
+
col.className = cls;
|
|
157
|
+
}
|
|
158
|
+
// adds sort indicators for current column being sorted
|
|
159
|
+
function addSortIndicators() {
|
|
160
|
+
getNthColumn(currentSort.index).className += currentSort.desc
|
|
161
|
+
? ' sorted-desc'
|
|
162
|
+
: ' sorted';
|
|
163
|
+
}
|
|
164
|
+
// adds event listeners for all sorter widgets
|
|
165
|
+
function enableUI() {
|
|
166
|
+
var i,
|
|
167
|
+
el,
|
|
168
|
+
ithSorter = function ithSorter(i) {
|
|
169
|
+
var col = cols[i];
|
|
170
|
+
|
|
171
|
+
return function() {
|
|
172
|
+
var desc = col.defaultDescSort;
|
|
173
|
+
|
|
174
|
+
if (currentSort.index === i) {
|
|
175
|
+
desc = !currentSort.desc;
|
|
176
|
+
}
|
|
177
|
+
sortByIndex(i, desc);
|
|
178
|
+
removeSortIndicators();
|
|
179
|
+
currentSort.index = i;
|
|
180
|
+
currentSort.desc = desc;
|
|
181
|
+
addSortIndicators();
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
for (i = 0; i < cols.length; i += 1) {
|
|
185
|
+
if (cols[i].sortable) {
|
|
186
|
+
// add the click event handler on the th so users
|
|
187
|
+
// dont have to click on those tiny arrows
|
|
188
|
+
el = getNthColumn(i).querySelector('.sorter').parentElement;
|
|
189
|
+
if (el.addEventListener) {
|
|
190
|
+
el.addEventListener('click', ithSorter(i));
|
|
191
|
+
} else {
|
|
192
|
+
el.attachEvent('onclick', ithSorter(i));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// adds sorting functionality to the UI
|
|
198
|
+
return function() {
|
|
199
|
+
if (!getTable()) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
cols = loadColumns();
|
|
203
|
+
loadData();
|
|
204
|
+
addSearchBox();
|
|
205
|
+
addSortIndicators();
|
|
206
|
+
enableUI();
|
|
207
|
+
};
|
|
208
|
+
})();
|
|
209
|
+
|
|
210
|
+
window.addEventListener('load', addSorting);
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { A as AutoGenerateConfig } from './GlobalNotificationProvider-Zq18OkpI.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Password validation types and constants
|
|
7
|
+
* Used for password requirements validation in forms
|
|
8
|
+
*/
|
|
9
|
+
type PasswordRuleType = "minLength" | "alphanumeric" | "uppercase" | "lowercase" | "number" | "special";
|
|
10
|
+
interface PasswordRule {
|
|
11
|
+
type: PasswordRuleType;
|
|
12
|
+
value?: number | string;
|
|
13
|
+
message: string;
|
|
14
|
+
enforce?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface EvaluatedPasswordRule {
|
|
17
|
+
message: string;
|
|
18
|
+
valid: boolean;
|
|
19
|
+
enforce: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Default password rules used as fallback when no custom rules are provided.
|
|
23
|
+
* Messages are translation keys that should be translated at runtime.
|
|
24
|
+
*/
|
|
25
|
+
declare const DEFAULT_PASSWORD_RULES: PasswordRule[];
|
|
26
|
+
|
|
27
|
+
type BoxScreenType = "login" | "signUp" | "forgotPassword" | "resetPassword" | "checkCode";
|
|
28
|
+
interface CrudifyLoginConfig {
|
|
29
|
+
publicApiKey?: string | null;
|
|
30
|
+
env?: "dev" | "stg" | "api" | "prod";
|
|
31
|
+
appName?: string;
|
|
32
|
+
logo?: string;
|
|
33
|
+
loginActions?: string[];
|
|
34
|
+
}
|
|
35
|
+
interface CrudifyLoginTranslations {
|
|
36
|
+
[key: string]: string | CrudifyLoginTranslations;
|
|
37
|
+
}
|
|
38
|
+
interface UserLoginData {
|
|
39
|
+
token: string;
|
|
40
|
+
username?: string;
|
|
41
|
+
email?: string;
|
|
42
|
+
userId?: string;
|
|
43
|
+
profile?: Record<string, unknown>;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
interface CrudifyLoginProps {
|
|
47
|
+
onScreenChange?: (screen: BoxScreenType, params?: Record<string, string>) => void;
|
|
48
|
+
onExternalNavigate?: (path: string) => void;
|
|
49
|
+
onLoginSuccess?: (userData: UserLoginData, redirectUrl?: string) => void;
|
|
50
|
+
onError?: (error: string) => void;
|
|
51
|
+
initialScreen?: BoxScreenType;
|
|
52
|
+
redirectUrl?: string;
|
|
53
|
+
autoReadFromCookies?: boolean;
|
|
54
|
+
translations?: CrudifyLoginTranslations;
|
|
55
|
+
translationsUrl?: string;
|
|
56
|
+
language?: string;
|
|
57
|
+
/** Custom password rules for reset password form. Falls back to default rules if not provided. */
|
|
58
|
+
passwordRules?: PasswordRule[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
declare const CrudifyLogin: React.FC<CrudifyLoginProps>;
|
|
62
|
+
|
|
63
|
+
interface UserProfileDisplayProps {
|
|
64
|
+
showExtendedData?: boolean;
|
|
65
|
+
showProfileCard?: boolean;
|
|
66
|
+
autoRefresh?: boolean;
|
|
67
|
+
}
|
|
68
|
+
declare const UserProfileDisplay: React.FC<UserProfileDisplayProps>;
|
|
69
|
+
|
|
70
|
+
declare const POLICY_ACTIONS: readonly ["create", "read", "update", "delete"];
|
|
71
|
+
type PolicyAction = typeof POLICY_ACTIONS[number];
|
|
72
|
+
declare const PREFERRED_POLICY_ORDER: PolicyAction[];
|
|
73
|
+
|
|
74
|
+
type Policy = {
|
|
75
|
+
id: string;
|
|
76
|
+
action: PolicyAction;
|
|
77
|
+
fields?: {
|
|
78
|
+
allow: string[];
|
|
79
|
+
owner_allow: string[];
|
|
80
|
+
deny: string[];
|
|
81
|
+
};
|
|
82
|
+
permission?: string;
|
|
83
|
+
};
|
|
84
|
+
type FieldErrorMap = string | ({
|
|
85
|
+
_error?: string;
|
|
86
|
+
} & Record<string, string | undefined>);
|
|
87
|
+
interface PoliciesProps {
|
|
88
|
+
policies: Policy[];
|
|
89
|
+
onChange: (next: Policy[]) => void;
|
|
90
|
+
availableFields: string[];
|
|
91
|
+
errors?: FieldErrorMap;
|
|
92
|
+
isSubmitting?: boolean;
|
|
93
|
+
}
|
|
94
|
+
declare const Policies: React.FC<PoliciesProps>;
|
|
95
|
+
|
|
96
|
+
declare function LoginComponent(): react_jsx_runtime.JSX.Element;
|
|
97
|
+
/**
|
|
98
|
+
* Componente simple de estado de sesión para mostrar en cualquier lugar
|
|
99
|
+
*/
|
|
100
|
+
declare function SessionStatus(): react_jsx_runtime.JSX.Element;
|
|
101
|
+
|
|
102
|
+
interface CrudiaAutoGenerateProps {
|
|
103
|
+
config: AutoGenerateConfig;
|
|
104
|
+
value?: string;
|
|
105
|
+
onChange?: (value: string) => void;
|
|
106
|
+
label?: string;
|
|
107
|
+
error?: boolean;
|
|
108
|
+
helperText?: string;
|
|
109
|
+
readOnly?: boolean;
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Componente para campos autogenerados (códigos secuenciales)
|
|
114
|
+
*
|
|
115
|
+
* Características:
|
|
116
|
+
* - Auto-fetch del código al montar
|
|
117
|
+
* - Detección automática de errores de duplicado
|
|
118
|
+
* - Botón "Regenerar" en endAdornment cuando hay error de duplicado
|
|
119
|
+
* - Estados de loading y error
|
|
120
|
+
* - Readonly por defecto
|
|
121
|
+
* - Integración con useAutoGenerate hook
|
|
122
|
+
*
|
|
123
|
+
* Flujo de Manejo de Errores de Duplicado:
|
|
124
|
+
* 1. Usuario abre formulario → Código se genera automáticamente (ej: PROD-0013671)
|
|
125
|
+
* 2. Usuario llena formulario y hace submit
|
|
126
|
+
* 3. Backend retorna error "duplicate key" o "unique constraint"
|
|
127
|
+
* 4. Formulario padre pasa error={true} y helperText="El código ya existe"
|
|
128
|
+
* 5. Componente detecta palabras clave de duplicado y muestra botón de regenerar
|
|
129
|
+
* 6. Usuario hace click en botón de regenerar → Nuevo código se genera
|
|
130
|
+
* 7. onChange se llama con nuevo código → Formulario padre limpia el error
|
|
131
|
+
* 8. Botón de regenerar desaparece (porque ya no hay error)
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* // Uso básico
|
|
136
|
+
* <CrudiaAutoGenerate
|
|
137
|
+
* config={{ prefix: "PROD-", padding: 7 }}
|
|
138
|
+
* onChange={(code) => setFormData({ ...formData, barCode: code })}
|
|
139
|
+
* label="Código de Barras"
|
|
140
|
+
* />
|
|
141
|
+
*
|
|
142
|
+
* // Con manejo de error de duplicado desde el formulario
|
|
143
|
+
* <CrudiaAutoGenerate
|
|
144
|
+
* config={{ prefix: "PROD-", padding: 7 }}
|
|
145
|
+
* onChange={(code) => {
|
|
146
|
+
* setFormData({ ...formData, barCode: code });
|
|
147
|
+
* // Limpiar error cuando cambia el código
|
|
148
|
+
* setFormErrors({ ...formErrors, barCode: null });
|
|
149
|
+
* }}
|
|
150
|
+
* label="Código de Barras"
|
|
151
|
+
* error={!!formErrors.barCode}
|
|
152
|
+
* helperText={formErrors.barCode}
|
|
153
|
+
* />
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
declare const CrudiaAutoGenerate: React.FC<CrudiaAutoGenerateProps>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* File field component with:
|
|
160
|
+
* - Drag & drop
|
|
161
|
+
* - File preview
|
|
162
|
+
* - Progress bar during upload
|
|
163
|
+
* - Delete files (soft delete)
|
|
164
|
+
* - Type and size validation
|
|
165
|
+
* - Single/multiple support
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Deletion handlers exposed by the component
|
|
170
|
+
*/
|
|
171
|
+
interface CrudiaFileFieldDeletionHandlers {
|
|
172
|
+
/** Execute all pending deletions (call this on form success callback) */
|
|
173
|
+
commitDeletions: () => Promise<{
|
|
174
|
+
success: boolean;
|
|
175
|
+
errors: string[];
|
|
176
|
+
}>;
|
|
177
|
+
/** Cancel all pending deletions and restore files */
|
|
178
|
+
restorePendingDeletions: () => void;
|
|
179
|
+
/** Whether there are files pending deletion */
|
|
180
|
+
hasPendingDeletions: boolean;
|
|
181
|
+
/** Mark the field as submitted (triggers validation errors display) */
|
|
182
|
+
markAsSubmitted: () => void;
|
|
183
|
+
/** Whether the field is valid */
|
|
184
|
+
isValid: boolean;
|
|
185
|
+
/** Whether files are currently being uploaded */
|
|
186
|
+
isUploading: boolean;
|
|
187
|
+
/** Wait for all uploads to complete - returns completed file paths */
|
|
188
|
+
waitForUploads: () => Promise<string[]>;
|
|
189
|
+
/** Get completed file paths synchronously (may be stale if uploads just finished) */
|
|
190
|
+
getCompletedFilePaths: () => string[];
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Props del componente CrudiaFileField
|
|
194
|
+
*/
|
|
195
|
+
interface CrudiaFileFieldProps {
|
|
196
|
+
/** Label del campo */
|
|
197
|
+
label?: string;
|
|
198
|
+
/** Tipos MIME permitidos (ej: ["image/png", "image/jpeg"]) */
|
|
199
|
+
accept?: string[];
|
|
200
|
+
/** Tamaño máximo por archivo en bytes */
|
|
201
|
+
maxFileSize?: number;
|
|
202
|
+
/** Permitir múltiples archivos */
|
|
203
|
+
multiple?: boolean;
|
|
204
|
+
/** Número máximo de archivos (solo si multiple=true) */
|
|
205
|
+
maxFiles?: number;
|
|
206
|
+
/** Número mínimo de archivos requeridos */
|
|
207
|
+
minFiles?: number;
|
|
208
|
+
/** Campo requerido */
|
|
209
|
+
required?: boolean;
|
|
210
|
+
/** Campo deshabilitado */
|
|
211
|
+
disabled?: boolean;
|
|
212
|
+
/** Error externo */
|
|
213
|
+
error?: boolean;
|
|
214
|
+
/** Texto de ayuda o error */
|
|
215
|
+
helperText?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Callback cuando cambian los filePaths de archivos completados
|
|
218
|
+
* Los filePaths son rutas relativas con visibility (public/... o private/...)
|
|
219
|
+
*/
|
|
220
|
+
onChange?: (filePaths: string[]) => void;
|
|
221
|
+
/** Callback cuando se valida el campo */
|
|
222
|
+
onValidation?: (isValid: boolean, error: string | null) => void;
|
|
223
|
+
/** Archivos existentes (para edición) - usar filePath (ruta relativa con visibility) */
|
|
224
|
+
initialFiles?: Array<{
|
|
225
|
+
filePath: string;
|
|
226
|
+
name: string;
|
|
227
|
+
size?: number;
|
|
228
|
+
contentType?: string;
|
|
229
|
+
}>;
|
|
230
|
+
/** Texto placeholder para drag zone */
|
|
231
|
+
placeholder?: string;
|
|
232
|
+
/** Mostrar lista de archivos */
|
|
233
|
+
showFileList?: boolean;
|
|
234
|
+
/**
|
|
235
|
+
* Visibilidad de los archivos subidos
|
|
236
|
+
* @default "private"
|
|
237
|
+
*/
|
|
238
|
+
visibility?: "public" | "private";
|
|
239
|
+
/**
|
|
240
|
+
* Mostrar preview de imágenes
|
|
241
|
+
* @default true para imágenes
|
|
242
|
+
*/
|
|
243
|
+
showPreview?: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* URL base para prefijar al path del archivo
|
|
246
|
+
* El valor guardado será baseUrl + path
|
|
247
|
+
* También se usa para previsualizar/descargar archivos públicos en modo readonly
|
|
248
|
+
*/
|
|
249
|
+
baseUrl: string;
|
|
250
|
+
/**
|
|
251
|
+
* Callback called when deletion handlers are ready
|
|
252
|
+
* Use this to get access to commitDeletions and restorePendingDeletions functions
|
|
253
|
+
*/
|
|
254
|
+
onDeletionHandlersReady?: (handlers: CrudiaFileFieldDeletionHandlers) => void;
|
|
255
|
+
/**
|
|
256
|
+
* Form mode: 'create' or 'edit' - affects delete behavior
|
|
257
|
+
* - create: delete shows confirmation and deletes immediately from server
|
|
258
|
+
* - edit: existing files use pendingDeletion, new files delete immediately
|
|
259
|
+
* @default "create"
|
|
260
|
+
*/
|
|
261
|
+
mode?: "create" | "edit";
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Main file field component
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```tsx
|
|
268
|
+
* // Basic usage - single file
|
|
269
|
+
* <CrudiaFileField
|
|
270
|
+
* label="Document"
|
|
271
|
+
* accept={["application/pdf"]}
|
|
272
|
+
* onChange={(filePaths) => setFormData({ ...formData, document: filePaths[0] })}
|
|
273
|
+
* />
|
|
274
|
+
*
|
|
275
|
+
* // Multiple files with limits
|
|
276
|
+
* <CrudiaFileField
|
|
277
|
+
* label="Images"
|
|
278
|
+
* accept={["image/png", "image/jpeg"]}
|
|
279
|
+
* multiple
|
|
280
|
+
* maxFiles={5}
|
|
281
|
+
* minFiles={1}
|
|
282
|
+
* maxFileSize={5 * 1024 * 1024}
|
|
283
|
+
* onChange={(filePaths) => setFormData({ ...formData, images: filePaths })}
|
|
284
|
+
* />
|
|
285
|
+
*
|
|
286
|
+
* // With initial files (edit mode)
|
|
287
|
+
* <CrudiaFileField
|
|
288
|
+
* label="Attachments"
|
|
289
|
+
* multiple
|
|
290
|
+
* initialFiles={existingFiles}
|
|
291
|
+
* onChange={handleFilesChange}
|
|
292
|
+
* />
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
declare const CrudiaFileField: React.FC<CrudiaFileFieldProps>;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Markdown field component with rich text editing using MDXEditor
|
|
299
|
+
* - WYSIWYG markdown editing
|
|
300
|
+
* - Toolbar with formatting options
|
|
301
|
+
* - Saves content as markdown string
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
interface CrudiaMarkdownFieldProps {
|
|
305
|
+
/** Field label */
|
|
306
|
+
label?: string;
|
|
307
|
+
/** Current value (markdown string) */
|
|
308
|
+
value?: string;
|
|
309
|
+
/** Callback when content changes */
|
|
310
|
+
onChange?: (value: string) => void;
|
|
311
|
+
/** Required field */
|
|
312
|
+
required?: boolean;
|
|
313
|
+
/** Disabled/readonly field */
|
|
314
|
+
disabled?: boolean;
|
|
315
|
+
/** External error state */
|
|
316
|
+
error?: boolean;
|
|
317
|
+
/** Helper or error text */
|
|
318
|
+
helperText?: string;
|
|
319
|
+
/** Placeholder text */
|
|
320
|
+
placeholder?: string;
|
|
321
|
+
/** Minimum editor height in pixels */
|
|
322
|
+
minHeight?: number;
|
|
323
|
+
/** Maximum editor height in pixels (scrolls after) */
|
|
324
|
+
maxHeight?: number;
|
|
325
|
+
}
|
|
326
|
+
declare const CrudiaMarkdownField: React.FC<CrudiaMarkdownFieldProps>;
|
|
327
|
+
|
|
328
|
+
export { type BoxScreenType as B, CrudifyLogin as C, DEFAULT_PASSWORD_RULES as D, type EvaluatedPasswordRule as E, LoginComponent as L, Policies as P, SessionStatus as S, UserProfileDisplay as U, CrudiaAutoGenerate as a, CrudiaFileField as b, CrudiaMarkdownField as c, type CrudifyLoginConfig as d, type CrudifyLoginProps as e, type CrudifyLoginTranslations as f, type UserLoginData as g, type PolicyAction as h, type CrudiaAutoGenerateProps as i, type CrudiaFileFieldProps as j, type CrudiaMarkdownFieldProps as k, type PasswordRule as l, POLICY_ACTIONS as m, PREFERRED_POLICY_ORDER as n, type CrudiaFileFieldDeletionHandlers as o, type PasswordRuleType as p };
|