@nubitio/crud 0.5.15 → 0.5.19
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/dist/index.cjs +72 -135
- package/dist/index.d.cts +15 -1
- package/dist/index.d.mts +15 -1
- package/dist/index.mjs +72 -137
- package/dist/style.css +3 -468
- package/package.json +3 -6
package/dist/index.cjs
CHANGED
|
@@ -28,7 +28,6 @@ let react_dom = require("react-dom");
|
|
|
28
28
|
let _nubitio_ui = require("@nubitio/ui");
|
|
29
29
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
30
30
|
let _nubitio_core = require("@nubitio/core");
|
|
31
|
-
let react_dropzone = require("react-dropzone");
|
|
32
31
|
let _tanstack_react_query = require("@tanstack/react-query");
|
|
33
32
|
//#region packages/crud/crud/defineResource.ts
|
|
34
33
|
const stringResourceCache = /* @__PURE__ */ new Map();
|
|
@@ -63,6 +62,17 @@ function defineResource(apiUrl, overrides) {
|
|
|
63
62
|
return resource;
|
|
64
63
|
}
|
|
65
64
|
//#endregion
|
|
65
|
+
//#region packages/crud/crud/embeddedLinesUrl.ts
|
|
66
|
+
/**
|
|
67
|
+
* Builds a formDetail reload URL for {@code #[EmbeddedLines]} line entities.
|
|
68
|
+
*
|
|
69
|
+
* @example embeddedLinesUrl('/api/sales_document_lines', 'document')
|
|
70
|
+
* → '/api/sales_document_lines?document={id}'
|
|
71
|
+
*/
|
|
72
|
+
function embeddedLinesUrl(route, parentQueryParam) {
|
|
73
|
+
return `${route}${route.includes("?") ? "&" : "?"}${parentQueryParam}={id}`;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
66
76
|
//#region packages/crud/datagrid/DataGridEvents.ts
|
|
67
77
|
const DATA_GRID_EVENTS = {
|
|
68
78
|
SELECTION_CHANGED: "datagrid:selection.changed",
|
|
@@ -1243,9 +1253,6 @@ const enumTypeModule = {
|
|
|
1243
1253
|
};
|
|
1244
1254
|
//#endregion
|
|
1245
1255
|
//#region packages/crud/form/FileUploadField.tsx
|
|
1246
|
-
function cx$1(...values) {
|
|
1247
|
-
return values.filter(Boolean).join(" ");
|
|
1248
|
-
}
|
|
1249
1256
|
function resolveMediaPath(media) {
|
|
1250
1257
|
if (!media) return null;
|
|
1251
1258
|
const path = media["path"];
|
|
@@ -1271,27 +1278,6 @@ function resolveMediaIri(uploadUrl, media) {
|
|
|
1271
1278
|
function isImageMimeType(mimeType) {
|
|
1272
1279
|
return !!mimeType && mimeType.startsWith("image/");
|
|
1273
1280
|
}
|
|
1274
|
-
function buildDropzoneAccept(accept) {
|
|
1275
|
-
if (!accept || accept === "*/*" || accept === "*") return void 0;
|
|
1276
|
-
if (accept === "image/*") return {
|
|
1277
|
-
"image/png": [".png"],
|
|
1278
|
-
"image/jpeg": [".jpg", ".jpeg"],
|
|
1279
|
-
"image/webp": [".webp"],
|
|
1280
|
-
"image/gif": [".gif"]
|
|
1281
|
-
};
|
|
1282
|
-
if (accept.includes(",")) return accept.split(",").reduce((acc, token) => {
|
|
1283
|
-
const trimmed = token.trim();
|
|
1284
|
-
if (!trimmed) return acc;
|
|
1285
|
-
if (trimmed.startsWith(".")) {
|
|
1286
|
-
acc["application/octet-stream"] = [...acc["application/octet-stream"] ?? [], trimmed];
|
|
1287
|
-
return acc;
|
|
1288
|
-
}
|
|
1289
|
-
acc[trimmed] = [];
|
|
1290
|
-
return acc;
|
|
1291
|
-
}, {});
|
|
1292
|
-
if (accept.startsWith(".")) return { "application/octet-stream": [accept] };
|
|
1293
|
-
return { [accept]: [] };
|
|
1294
|
-
}
|
|
1295
1281
|
async function uploadMediaFile(file, uploadUrl, httpClient) {
|
|
1296
1282
|
const body = new FormData();
|
|
1297
1283
|
body.append("file", file);
|
|
@@ -1371,17 +1357,6 @@ function FileUploadField({ field, disabled = false, readOnly = false, invalid =
|
|
|
1371
1357
|
t,
|
|
1372
1358
|
uploadUrl
|
|
1373
1359
|
]);
|
|
1374
|
-
const { getRootProps, getInputProps, isDragActive, open } = (0, react_dropzone.useDropzone)({
|
|
1375
|
-
accept: buildDropzoneAccept(field.accept),
|
|
1376
|
-
disabled: disabled || readOnly || status === "uploading",
|
|
1377
|
-
multiple: false,
|
|
1378
|
-
noClick: !!(previewUrl || fileName),
|
|
1379
|
-
noKeyboard: !!(previewUrl || fileName),
|
|
1380
|
-
onDrop: (acceptedFiles) => {
|
|
1381
|
-
const file = acceptedFiles[0];
|
|
1382
|
-
if (file) uploadFile(file);
|
|
1383
|
-
}
|
|
1384
|
-
});
|
|
1385
1360
|
const handleClear = () => {
|
|
1386
1361
|
revokeLocalPreview();
|
|
1387
1362
|
setPreviewUrl(null);
|
|
@@ -1391,104 +1366,35 @@ function FileUploadField({ field, disabled = false, readOnly = false, invalid =
|
|
|
1391
1366
|
setErrorMessage(null);
|
|
1392
1367
|
onCleared(field.name);
|
|
1393
1368
|
};
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
className: "nb-form__file-upload-file-link",
|
|
1424
|
-
href: fileUrl,
|
|
1425
|
-
target: "_blank",
|
|
1426
|
-
rel: "noreferrer",
|
|
1427
|
-
onClick: (event) => event.stopPropagation(),
|
|
1428
|
-
children: t("form.fileUploadOpen")
|
|
1429
|
-
})]
|
|
1430
|
-
})]
|
|
1431
|
-
}),
|
|
1432
|
-
status === "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1433
|
-
className: "nb-form__file-upload-overlay",
|
|
1434
|
-
"aria-live": "polite",
|
|
1435
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1436
|
-
className: "nb-form__file-upload-spinner",
|
|
1437
|
-
"aria-hidden": "true"
|
|
1438
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.fileUploading") })]
|
|
1439
|
-
}),
|
|
1440
|
-
isInteractive && status !== "uploading" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1441
|
-
className: "nb-form__file-upload-actions",
|
|
1442
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1443
|
-
type: "button",
|
|
1444
|
-
className: "nb-form__file-upload-action",
|
|
1445
|
-
onClick: (event) => {
|
|
1446
|
-
event.stopPropagation();
|
|
1447
|
-
open();
|
|
1448
|
-
},
|
|
1449
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {
|
|
1450
|
-
className: "ph ph-arrows-clockwise",
|
|
1451
|
-
"aria-hidden": "true"
|
|
1452
|
-
}), t("form.fileUploadReplace")]
|
|
1453
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1454
|
-
type: "button",
|
|
1455
|
-
className: "nb-form__file-upload-action nb-form__file-upload-action--danger",
|
|
1456
|
-
onClick: (event) => {
|
|
1457
|
-
event.stopPropagation();
|
|
1458
|
-
handleClear();
|
|
1459
|
-
},
|
|
1460
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {
|
|
1461
|
-
className: "ph ph-trash",
|
|
1462
|
-
"aria-hidden": "true"
|
|
1463
|
-
}), t("form.fileUploadRemove")]
|
|
1464
|
-
})]
|
|
1465
|
-
})
|
|
1466
|
-
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1467
|
-
className: "nb-form__file-upload-placeholder",
|
|
1468
|
-
children: [
|
|
1469
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1470
|
-
className: "nb-form__file-upload-icon",
|
|
1471
|
-
"aria-hidden": "true",
|
|
1472
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", { className: `ph ${placeholderIcon}` })
|
|
1473
|
-
}),
|
|
1474
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1475
|
-
className: "nb-form__file-upload-title",
|
|
1476
|
-
children: placeholderTitle
|
|
1477
|
-
}),
|
|
1478
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1479
|
-
className: "nb-form__file-upload-hint",
|
|
1480
|
-
children: placeholderHint
|
|
1481
|
-
})
|
|
1482
|
-
]
|
|
1483
|
-
})]
|
|
1484
|
-
}), errorMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1485
|
-
className: "nb-form__file-upload-error",
|
|
1486
|
-
role: "alert",
|
|
1487
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {
|
|
1488
|
-
className: "ph ph-warning-circle",
|
|
1489
|
-
"aria-hidden": "true"
|
|
1490
|
-
}), errorMessage]
|
|
1491
|
-
})]
|
|
1369
|
+
const value = {
|
|
1370
|
+
fileName,
|
|
1371
|
+
fileUrl,
|
|
1372
|
+
previewUrl
|
|
1373
|
+
};
|
|
1374
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_nubitio_ui.FileDropzone, {
|
|
1375
|
+
accept: field.accept,
|
|
1376
|
+
disabled,
|
|
1377
|
+
readOnly,
|
|
1378
|
+
invalid,
|
|
1379
|
+
image: imageMode,
|
|
1380
|
+
value,
|
|
1381
|
+
uploading: status === "uploading",
|
|
1382
|
+
error: errorMessage,
|
|
1383
|
+
inputId: `nb-form-${field.name}`,
|
|
1384
|
+
inputLabel: field.label,
|
|
1385
|
+
labels: {
|
|
1386
|
+
dropPrompt: t("form.fileUploadDrop"),
|
|
1387
|
+
prompt: t("form.fileUploadPrompt"),
|
|
1388
|
+
imagePrompt: t("form.imageUploadPrompt"),
|
|
1389
|
+
hint: t("form.fileUploadHint"),
|
|
1390
|
+
imageHint: t("form.imageUploadHint"),
|
|
1391
|
+
uploading: t("form.fileUploading"),
|
|
1392
|
+
replace: t("form.fileUploadReplace"),
|
|
1393
|
+
remove: t("form.fileUploadRemove"),
|
|
1394
|
+
open: t("form.fileUploadOpen")
|
|
1395
|
+
},
|
|
1396
|
+
onFileSelect: (file) => void uploadFile(file),
|
|
1397
|
+
onClear: handleClear
|
|
1492
1398
|
});
|
|
1493
1399
|
}
|
|
1494
1400
|
function isImageFileField(field) {
|
|
@@ -3693,6 +3599,17 @@ function normalizeEntityField(row, field, adapter, prependDataByField) {
|
|
|
3693
3599
|
}
|
|
3694
3600
|
}
|
|
3695
3601
|
//#endregion
|
|
3602
|
+
//#region packages/crud/form/loadDetailRows.ts
|
|
3603
|
+
/**
|
|
3604
|
+
* Loads embedded line rows for formDetail edit mode. Accepts both plain JSON
|
|
3605
|
+
* arrays (nubit embedded-lines endpoint) and Hydra collections.
|
|
3606
|
+
*/
|
|
3607
|
+
async function loadDetailRows(httpClient, detailUrl, adapter) {
|
|
3608
|
+
const response = await httpClient.get(detailUrl);
|
|
3609
|
+
const { items } = (adapter ?? HydraAdapter).parseListResponse(response.data);
|
|
3610
|
+
return items;
|
|
3611
|
+
}
|
|
3612
|
+
//#endregion
|
|
3696
3613
|
//#region packages/crud/form/safeRandomId.ts
|
|
3697
3614
|
/**
|
|
3698
3615
|
* Generate a unique-enough id string for internal React keys.
|
|
@@ -4753,7 +4670,7 @@ const NativeFormView = (0, react.forwardRef)((options, ref) => {
|
|
|
4753
4670
|
const detailUrl = typeof detailId === "string" || typeof detailId === "number" ? options.detailUrl?.replace("{id}", String(detailId)) : void 0;
|
|
4754
4671
|
if (!detailUrl) return;
|
|
4755
4672
|
emit(FORM_EVENTS.LOADING, true);
|
|
4756
|
-
httpClient.
|
|
4673
|
+
loadDetailRows(httpClient, detailUrl, options.adapter).then((rows) => setNextDetailRows(rows)).finally(() => emit(FORM_EVENTS.LOADING, false));
|
|
4757
4674
|
}, [
|
|
4758
4675
|
captureExistingMedia,
|
|
4759
4676
|
emit,
|
|
@@ -8543,6 +8460,24 @@ function ToolbarSelect({ id, label, icon = "ph-funnel", value, options, onChange
|
|
|
8543
8460
|
});
|
|
8544
8461
|
}
|
|
8545
8462
|
//#endregion
|
|
8463
|
+
//#region packages/crud/workflow/buildWorkflowRowActions.ts
|
|
8464
|
+
function buildWorkflowRowActions(row, workflow, apiUrl, roles, onDone) {
|
|
8465
|
+
if (!workflow) return [];
|
|
8466
|
+
const current = String(row[workflow.field] ?? "");
|
|
8467
|
+
return workflow.transitions.filter((transition) => transition.from.includes(current)).filter((transition) => !transition.roles?.length || transition.roles.some((role) => roles.includes(role))).map((transition) => ({
|
|
8468
|
+
text: transition.label ?? transition.name,
|
|
8469
|
+
onClick: async () => {
|
|
8470
|
+
const base = apiUrl.replace(/\/$/, "");
|
|
8471
|
+
const id = row.id;
|
|
8472
|
+
await fetch(`${base}/${id}/transition/${transition.name}`, {
|
|
8473
|
+
method: "POST",
|
|
8474
|
+
credentials: "include"
|
|
8475
|
+
});
|
|
8476
|
+
onDone?.();
|
|
8477
|
+
}
|
|
8478
|
+
}));
|
|
8479
|
+
}
|
|
8480
|
+
//#endregion
|
|
8546
8481
|
//#region packages/crud/adapter/RestAdapter.ts
|
|
8547
8482
|
/**
|
|
8548
8483
|
* Backend adapter for plain OpenAPI / REST backends.
|
|
@@ -8722,6 +8657,7 @@ exports.SmartCrudRolesProvider = SmartCrudRolesProvider;
|
|
|
8722
8657
|
exports.ToolbarSelect = ToolbarSelect;
|
|
8723
8658
|
exports.buildFieldColSpanContext = buildFieldColSpanContext;
|
|
8724
8659
|
exports.buildFields = buildFields;
|
|
8660
|
+
exports.buildWorkflowRowActions = buildWorkflowRowActions;
|
|
8725
8661
|
exports.checkboxField = checkboxField;
|
|
8726
8662
|
exports.computeSummaryValue = computeSummaryValue;
|
|
8727
8663
|
Object.defineProperty(exports, "createCrudEvents", {
|
|
@@ -8738,6 +8674,7 @@ exports.datetimeField = datetimeField;
|
|
|
8738
8674
|
exports.defineFieldContract = defineFieldContract;
|
|
8739
8675
|
exports.defineFields = defineFields;
|
|
8740
8676
|
exports.defineResource = defineResource;
|
|
8677
|
+
exports.embeddedLinesUrl = embeddedLinesUrl;
|
|
8741
8678
|
exports.entityField = entityField;
|
|
8742
8679
|
exports.enumField = enumField;
|
|
8743
8680
|
exports.fileField = fileField;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ReactElement, ReactNode, RefObject } from "react";
|
|
2
2
|
import { CoreHttpClient, DataGridEventNames, DataRecord, DataRecord as DataRecord$1, DialogEventNames, FormEventNames, GridData, GridData as GridData$1, createCrudEvents } from "@nubitio/core";
|
|
3
3
|
import { AppDropdownOption } from "@nubitio/ui";
|
|
4
|
+
import { WorkflowSchema } from "@nubitio/hydra";
|
|
4
5
|
|
|
5
6
|
//#region packages/crud/field/FieldType.d.ts
|
|
6
7
|
declare enum FieldType {
|
|
@@ -1013,6 +1014,15 @@ declare function defineResource<T extends DataRecord$1>(apiUrl: string, override
|
|
|
1013
1014
|
id?: string;
|
|
1014
1015
|
}): ResourceConfig<T>;
|
|
1015
1016
|
//#endregion
|
|
1017
|
+
//#region packages/crud/crud/embeddedLinesUrl.d.ts
|
|
1018
|
+
/**
|
|
1019
|
+
* Builds a formDetail reload URL for {@code #[EmbeddedLines]} line entities.
|
|
1020
|
+
*
|
|
1021
|
+
* @example embeddedLinesUrl('/api/sales_document_lines', 'document')
|
|
1022
|
+
* → '/api/sales_document_lines?document={id}'
|
|
1023
|
+
*/
|
|
1024
|
+
declare function embeddedLinesUrl(route: string, parentQueryParam: string): string;
|
|
1025
|
+
//#endregion
|
|
1016
1026
|
//#region packages/crud/crud/CrudPage.d.ts
|
|
1017
1027
|
interface CrudPageProps<T extends DataRecord$1 = DataRecord$1> {
|
|
1018
1028
|
resource: ResourceConfig<T>;
|
|
@@ -1867,6 +1877,9 @@ interface ColumnPresetState {
|
|
|
1867
1877
|
}
|
|
1868
1878
|
declare function useColumnPreset(resource: ResourceConfig): ColumnPresetState;
|
|
1869
1879
|
//#endregion
|
|
1880
|
+
//#region packages/crud/workflow/buildWorkflowRowActions.d.ts
|
|
1881
|
+
declare function buildWorkflowRowActions<T extends DataRecord$1 = DataRecord$1>(row: T, workflow: WorkflowSchema | undefined, apiUrl: string, roles: string[], onDone?: () => void): ResourceToolbarAction[];
|
|
1882
|
+
//#endregion
|
|
1870
1883
|
//#region packages/crud/adapter/HydraAdapter.d.ts
|
|
1871
1884
|
/**
|
|
1872
1885
|
* Default backend adapter for API Platform / JSON-LD + Hydra backends.
|
|
@@ -1905,6 +1918,7 @@ interface ResourceSchemaResolution {
|
|
|
1905
1918
|
* resource publishes one. Explicit `ResourceConfig.formLayout` wins.
|
|
1906
1919
|
*/
|
|
1907
1920
|
formLayout?: FormLayout;
|
|
1921
|
+
workflow?: WorkflowSchema;
|
|
1908
1922
|
}
|
|
1909
1923
|
interface ResourceSchemaResolver {
|
|
1910
1924
|
useResourceSchema(request: ResourceSchemaRequest): ResourceSchemaResolution;
|
|
@@ -1999,4 +2013,4 @@ interface RestQueryDialect {
|
|
|
1999
2013
|
*/
|
|
2000
2014
|
declare function createRestResourceStore(dialect?: RestQueryDialect): ResourceStoreFactory;
|
|
2001
2015
|
//#endregion
|
|
2002
|
-
export { type AuditEntry, type AuditFieldLabelResolver, type AuditTrailConfig, AuditTrailPanel, type AuditTrailPanelProps, type BackendAdapter, type BulkAction, type ColSpan, type ColumnPreset, ColumnPresetSelector, type ColumnPresetState, CrudDialogShell, CrudDrawerShell, type CrudDrawerSize, type CrudDrawerViewEvents, type CrudDrawerViewOptions, CrudFormShell, type CrudFormShellProps, CrudPage, CrudPageShell, type CrudPageViewEvents, type CrudPageViewOptions, type CrudViewMode, type CrudViewModeConfig, DATA_GRID_EVENTS, DEFAULT_DRAWER_SIZE, DEFAULT_DRAWER_WIDTH, DRAWER_WIDTHS, type DataGridSelectionChangedEvent, type DataGridSummaryItem, NativeDataGridView as DataGridView, type DataGridViewOptions, type DataRecord, type DetailSummaryOptions, CrudDialogView as DialogView, type DrawerSize, CrudDrawerView as DrawerView, type EnumOption, FORM_EVENTS, type Field, FieldBuilder, type FieldColSpanContext, type FieldDef, type FieldInput, type FieldOverride, FieldType, type FilterRule, type FormHandle, type FormLayout, type FormLayoutHint, type FormOnChangeFn, type FormPresentationContext, type FormPresentationMode, type FormSection, type FormTab, NativeFormView as FormView, type FormViewOptions, type FormatterFn, type GridCellContext, type GridData, type GridHandle, type GridOnChangeFn, HydraAdapter, type ItemFormatterFn, type LoadOption, type OnChangeFn, CrudPageView as PageView, type ResolvedViewMode, type ResourceConfig, type ResourceEmptyState, type ResourceFilterDescriptor, type ResourceFilterRule, type ResourceFormDetail, type ResourceGridDetail, type ResourceLoadOption, type ResourceLoadOptions, type ResourcePermissions, type ResourceRouting, type ResourceRowActions, ResourceSchemaProvider, type ResourceSchemaProviderProps, type ResourceSchemaResolution, type ResourceSchemaResolver, type ResourceSortDescriptor, type ResourceStore, type ResourceStoreFactory, type ResourceStoreOptions, ResourceStoreProvider, type ResourceStoreProviderProps, type ResourceToolbar, type ResourceToolbarAction, type ResourceToolbarActionVariant, type ResourceToolbarContext, type ResourceToolbarItems, RestAdapter, type RestQueryDialect, type SmartCrudFieldContract, type SmartCrudFieldOperation, type SmartCrudFieldPatch, type SmartCrudHydraFieldContract, type SmartCrudHydraFieldDirective, type SmartCrudManualField, type SmartCrudManualFieldContract, type SmartCrudOperation, SmartCrudPage, SmartCrudRolesProvider, type SummaryCalculateContext, type SummaryFormat, type SummaryItem, type SummaryTextContext, type SummaryType, ToolbarSelect, type ToolbarSelectOption, type ToolbarSelectProps, type ValidationRule, buildFieldColSpanContext, buildFields, checkboxField, computeSummaryValue, createCrudEvents, createRestResourceStore, crudRoute, currencyField, dateField, datetimeField, defineFieldContract, defineFields, defineResource, entityField, enumField, fileField, formatSummaryValue, identityField, imageField, isLongTextField, isShortField, noneField, numberField, parseDrawerWidthPx, passwordField, resolveDrawerLayoutBucket, resolveDrawerSize, resolveDrawerWidth, resolveFieldColSpan, resolveFieldsColSpans, resolveSummaryText, resolveViewMode, selectField, switchField, textField, textareaField, useColumnPreset, useResourceStoreFactory, useSmartCrudRoles, validateFieldContract };
|
|
2016
|
+
export { type AuditEntry, type AuditFieldLabelResolver, type AuditTrailConfig, AuditTrailPanel, type AuditTrailPanelProps, type BackendAdapter, type BulkAction, type ColSpan, type ColumnPreset, ColumnPresetSelector, type ColumnPresetState, CrudDialogShell, CrudDrawerShell, type CrudDrawerSize, type CrudDrawerViewEvents, type CrudDrawerViewOptions, CrudFormShell, type CrudFormShellProps, CrudPage, CrudPageShell, type CrudPageViewEvents, type CrudPageViewOptions, type CrudViewMode, type CrudViewModeConfig, DATA_GRID_EVENTS, DEFAULT_DRAWER_SIZE, DEFAULT_DRAWER_WIDTH, DRAWER_WIDTHS, type DataGridSelectionChangedEvent, type DataGridSummaryItem, NativeDataGridView as DataGridView, type DataGridViewOptions, type DataRecord, type DetailSummaryOptions, CrudDialogView as DialogView, type DrawerSize, CrudDrawerView as DrawerView, type EnumOption, FORM_EVENTS, type Field, FieldBuilder, type FieldColSpanContext, type FieldDef, type FieldInput, type FieldOverride, FieldType, type FilterRule, type FormHandle, type FormLayout, type FormLayoutHint, type FormOnChangeFn, type FormPresentationContext, type FormPresentationMode, type FormSection, type FormTab, NativeFormView as FormView, type FormViewOptions, type FormatterFn, type GridCellContext, type GridData, type GridHandle, type GridOnChangeFn, HydraAdapter, type ItemFormatterFn, type LoadOption, type OnChangeFn, CrudPageView as PageView, type ResolvedViewMode, type ResourceConfig, type ResourceEmptyState, type ResourceFilterDescriptor, type ResourceFilterRule, type ResourceFormDetail, type ResourceGridDetail, type ResourceLoadOption, type ResourceLoadOptions, type ResourcePermissions, type ResourceRouting, type ResourceRowActions, ResourceSchemaProvider, type ResourceSchemaProviderProps, type ResourceSchemaResolution, type ResourceSchemaResolver, type ResourceSortDescriptor, type ResourceStore, type ResourceStoreFactory, type ResourceStoreOptions, ResourceStoreProvider, type ResourceStoreProviderProps, type ResourceToolbar, type ResourceToolbarAction, type ResourceToolbarActionVariant, type ResourceToolbarContext, type ResourceToolbarItems, RestAdapter, type RestQueryDialect, type SmartCrudFieldContract, type SmartCrudFieldOperation, type SmartCrudFieldPatch, type SmartCrudHydraFieldContract, type SmartCrudHydraFieldDirective, type SmartCrudManualField, type SmartCrudManualFieldContract, type SmartCrudOperation, SmartCrudPage, SmartCrudRolesProvider, type SummaryCalculateContext, type SummaryFormat, type SummaryItem, type SummaryTextContext, type SummaryType, ToolbarSelect, type ToolbarSelectOption, type ToolbarSelectProps, type ValidationRule, buildFieldColSpanContext, buildFields, buildWorkflowRowActions, checkboxField, computeSummaryValue, createCrudEvents, createRestResourceStore, crudRoute, currencyField, dateField, datetimeField, defineFieldContract, defineFields, defineResource, embeddedLinesUrl, entityField, enumField, fileField, formatSummaryValue, identityField, imageField, isLongTextField, isShortField, noneField, numberField, parseDrawerWidthPx, passwordField, resolveDrawerLayoutBucket, resolveDrawerSize, resolveDrawerWidth, resolveFieldColSpan, resolveFieldsColSpans, resolveSummaryText, resolveViewMode, selectField, switchField, textField, textareaField, useColumnPreset, useResourceStoreFactory, useSmartCrudRoles, validateFieldContract };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ReactElement, ReactNode, RefObject } from "react";
|
|
2
2
|
import { AppDropdownOption } from "@nubitio/ui";
|
|
3
3
|
import { CoreHttpClient, DataGridEventNames, DataRecord, DataRecord as DataRecord$1, DialogEventNames, FormEventNames, GridData, GridData as GridData$1, createCrudEvents } from "@nubitio/core";
|
|
4
|
+
import { WorkflowSchema } from "@nubitio/hydra";
|
|
4
5
|
|
|
5
6
|
//#region packages/crud/field/FieldType.d.ts
|
|
6
7
|
declare enum FieldType {
|
|
@@ -1013,6 +1014,15 @@ declare function defineResource<T extends DataRecord$1>(apiUrl: string, override
|
|
|
1013
1014
|
id?: string;
|
|
1014
1015
|
}): ResourceConfig<T>;
|
|
1015
1016
|
//#endregion
|
|
1017
|
+
//#region packages/crud/crud/embeddedLinesUrl.d.ts
|
|
1018
|
+
/**
|
|
1019
|
+
* Builds a formDetail reload URL for {@code #[EmbeddedLines]} line entities.
|
|
1020
|
+
*
|
|
1021
|
+
* @example embeddedLinesUrl('/api/sales_document_lines', 'document')
|
|
1022
|
+
* → '/api/sales_document_lines?document={id}'
|
|
1023
|
+
*/
|
|
1024
|
+
declare function embeddedLinesUrl(route: string, parentQueryParam: string): string;
|
|
1025
|
+
//#endregion
|
|
1016
1026
|
//#region packages/crud/crud/CrudPage.d.ts
|
|
1017
1027
|
interface CrudPageProps<T extends DataRecord$1 = DataRecord$1> {
|
|
1018
1028
|
resource: ResourceConfig<T>;
|
|
@@ -1867,6 +1877,9 @@ interface ColumnPresetState {
|
|
|
1867
1877
|
}
|
|
1868
1878
|
declare function useColumnPreset(resource: ResourceConfig): ColumnPresetState;
|
|
1869
1879
|
//#endregion
|
|
1880
|
+
//#region packages/crud/workflow/buildWorkflowRowActions.d.ts
|
|
1881
|
+
declare function buildWorkflowRowActions<T extends DataRecord$1 = DataRecord$1>(row: T, workflow: WorkflowSchema | undefined, apiUrl: string, roles: string[], onDone?: () => void): ResourceToolbarAction[];
|
|
1882
|
+
//#endregion
|
|
1870
1883
|
//#region packages/crud/adapter/HydraAdapter.d.ts
|
|
1871
1884
|
/**
|
|
1872
1885
|
* Default backend adapter for API Platform / JSON-LD + Hydra backends.
|
|
@@ -1905,6 +1918,7 @@ interface ResourceSchemaResolution {
|
|
|
1905
1918
|
* resource publishes one. Explicit `ResourceConfig.formLayout` wins.
|
|
1906
1919
|
*/
|
|
1907
1920
|
formLayout?: FormLayout;
|
|
1921
|
+
workflow?: WorkflowSchema;
|
|
1908
1922
|
}
|
|
1909
1923
|
interface ResourceSchemaResolver {
|
|
1910
1924
|
useResourceSchema(request: ResourceSchemaRequest): ResourceSchemaResolution;
|
|
@@ -1999,4 +2013,4 @@ interface RestQueryDialect {
|
|
|
1999
2013
|
*/
|
|
2000
2014
|
declare function createRestResourceStore(dialect?: RestQueryDialect): ResourceStoreFactory;
|
|
2001
2015
|
//#endregion
|
|
2002
|
-
export { type AuditEntry, type AuditFieldLabelResolver, type AuditTrailConfig, AuditTrailPanel, type AuditTrailPanelProps, type BackendAdapter, type BulkAction, type ColSpan, type ColumnPreset, ColumnPresetSelector, type ColumnPresetState, CrudDialogShell, CrudDrawerShell, type CrudDrawerSize, type CrudDrawerViewEvents, type CrudDrawerViewOptions, CrudFormShell, type CrudFormShellProps, CrudPage, CrudPageShell, type CrudPageViewEvents, type CrudPageViewOptions, type CrudViewMode, type CrudViewModeConfig, DATA_GRID_EVENTS, DEFAULT_DRAWER_SIZE, DEFAULT_DRAWER_WIDTH, DRAWER_WIDTHS, type DataGridSelectionChangedEvent, type DataGridSummaryItem, NativeDataGridView as DataGridView, type DataGridViewOptions, type DataRecord, type DetailSummaryOptions, CrudDialogView as DialogView, type DrawerSize, CrudDrawerView as DrawerView, type EnumOption, FORM_EVENTS, type Field, FieldBuilder, type FieldColSpanContext, type FieldDef, type FieldInput, type FieldOverride, FieldType, type FilterRule, type FormHandle, type FormLayout, type FormLayoutHint, type FormOnChangeFn, type FormPresentationContext, type FormPresentationMode, type FormSection, type FormTab, NativeFormView as FormView, type FormViewOptions, type FormatterFn, type GridCellContext, type GridData, type GridHandle, type GridOnChangeFn, HydraAdapter, type ItemFormatterFn, type LoadOption, type OnChangeFn, CrudPageView as PageView, type ResolvedViewMode, type ResourceConfig, type ResourceEmptyState, type ResourceFilterDescriptor, type ResourceFilterRule, type ResourceFormDetail, type ResourceGridDetail, type ResourceLoadOption, type ResourceLoadOptions, type ResourcePermissions, type ResourceRouting, type ResourceRowActions, ResourceSchemaProvider, type ResourceSchemaProviderProps, type ResourceSchemaResolution, type ResourceSchemaResolver, type ResourceSortDescriptor, type ResourceStore, type ResourceStoreFactory, type ResourceStoreOptions, ResourceStoreProvider, type ResourceStoreProviderProps, type ResourceToolbar, type ResourceToolbarAction, type ResourceToolbarActionVariant, type ResourceToolbarContext, type ResourceToolbarItems, RestAdapter, type RestQueryDialect, type SmartCrudFieldContract, type SmartCrudFieldOperation, type SmartCrudFieldPatch, type SmartCrudHydraFieldContract, type SmartCrudHydraFieldDirective, type SmartCrudManualField, type SmartCrudManualFieldContract, type SmartCrudOperation, SmartCrudPage, SmartCrudRolesProvider, type SummaryCalculateContext, type SummaryFormat, type SummaryItem, type SummaryTextContext, type SummaryType, ToolbarSelect, type ToolbarSelectOption, type ToolbarSelectProps, type ValidationRule, buildFieldColSpanContext, buildFields, checkboxField, computeSummaryValue, createCrudEvents, createRestResourceStore, crudRoute, currencyField, dateField, datetimeField, defineFieldContract, defineFields, defineResource, entityField, enumField, fileField, formatSummaryValue, identityField, imageField, isLongTextField, isShortField, noneField, numberField, parseDrawerWidthPx, passwordField, resolveDrawerLayoutBucket, resolveDrawerSize, resolveDrawerWidth, resolveFieldColSpan, resolveFieldsColSpans, resolveSummaryText, resolveViewMode, selectField, switchField, textField, textareaField, useColumnPreset, useResourceStoreFactory, useSmartCrudRoles, validateFieldContract };
|
|
2016
|
+
export { type AuditEntry, type AuditFieldLabelResolver, type AuditTrailConfig, AuditTrailPanel, type AuditTrailPanelProps, type BackendAdapter, type BulkAction, type ColSpan, type ColumnPreset, ColumnPresetSelector, type ColumnPresetState, CrudDialogShell, CrudDrawerShell, type CrudDrawerSize, type CrudDrawerViewEvents, type CrudDrawerViewOptions, CrudFormShell, type CrudFormShellProps, CrudPage, CrudPageShell, type CrudPageViewEvents, type CrudPageViewOptions, type CrudViewMode, type CrudViewModeConfig, DATA_GRID_EVENTS, DEFAULT_DRAWER_SIZE, DEFAULT_DRAWER_WIDTH, DRAWER_WIDTHS, type DataGridSelectionChangedEvent, type DataGridSummaryItem, NativeDataGridView as DataGridView, type DataGridViewOptions, type DataRecord, type DetailSummaryOptions, CrudDialogView as DialogView, type DrawerSize, CrudDrawerView as DrawerView, type EnumOption, FORM_EVENTS, type Field, FieldBuilder, type FieldColSpanContext, type FieldDef, type FieldInput, type FieldOverride, FieldType, type FilterRule, type FormHandle, type FormLayout, type FormLayoutHint, type FormOnChangeFn, type FormPresentationContext, type FormPresentationMode, type FormSection, type FormTab, NativeFormView as FormView, type FormViewOptions, type FormatterFn, type GridCellContext, type GridData, type GridHandle, type GridOnChangeFn, HydraAdapter, type ItemFormatterFn, type LoadOption, type OnChangeFn, CrudPageView as PageView, type ResolvedViewMode, type ResourceConfig, type ResourceEmptyState, type ResourceFilterDescriptor, type ResourceFilterRule, type ResourceFormDetail, type ResourceGridDetail, type ResourceLoadOption, type ResourceLoadOptions, type ResourcePermissions, type ResourceRouting, type ResourceRowActions, ResourceSchemaProvider, type ResourceSchemaProviderProps, type ResourceSchemaResolution, type ResourceSchemaResolver, type ResourceSortDescriptor, type ResourceStore, type ResourceStoreFactory, type ResourceStoreOptions, ResourceStoreProvider, type ResourceStoreProviderProps, type ResourceToolbar, type ResourceToolbarAction, type ResourceToolbarActionVariant, type ResourceToolbarContext, type ResourceToolbarItems, RestAdapter, type RestQueryDialect, type SmartCrudFieldContract, type SmartCrudFieldOperation, type SmartCrudFieldPatch, type SmartCrudHydraFieldContract, type SmartCrudHydraFieldDirective, type SmartCrudManualField, type SmartCrudManualFieldContract, type SmartCrudOperation, SmartCrudPage, SmartCrudRolesProvider, type SummaryCalculateContext, type SummaryFormat, type SummaryItem, type SummaryTextContext, type SummaryType, ToolbarSelect, type ToolbarSelectOption, type ToolbarSelectProps, type ValidationRule, buildFieldColSpanContext, buildFields, buildWorkflowRowActions, checkboxField, computeSummaryValue, createCrudEvents, createRestResourceStore, crudRoute, currencyField, dateField, datetimeField, defineFieldContract, defineFields, defineResource, embeddedLinesUrl, entityField, enumField, fileField, formatSummaryValue, identityField, imageField, isLongTextField, isShortField, noneField, numberField, parseDrawerWidthPx, passwordField, resolveDrawerLayoutBucket, resolveDrawerSize, resolveDrawerWidth, resolveFieldColSpan, resolveFieldsColSpans, resolveSummaryText, resolveViewMode, selectField, switchField, textField, textareaField, useColumnPreset, useResourceStoreFactory, useSmartCrudRoles, validateFieldContract };
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
2
2
|
import { Route, useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
|
-
import { AppDialog, AppDropdown, Badge, Button, ConfirmDialog, DatePicker, DateRangePicker, Drawer, EmptyState, IconButton, Skeleton, Timeline, TimelineItem } from "@nubitio/ui";
|
|
4
|
+
import { AppDialog, AppDropdown, Badge, Button, ConfirmDialog, DatePicker, DateRangePicker, Drawer, EmptyState, FileDropzone, IconButton, Skeleton, Timeline, TimelineItem } from "@nubitio/ui";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { createCrudEvents, createScopedEventBus, getCoreCurrency, getCoreLocale, getCoreTimezone, useCoreHttpClient, useCoreRuntime, useCoreTranslation, useEvents, useMercureSubscription } from "@nubitio/core";
|
|
7
|
-
import { useDropzone } from "react-dropzone";
|
|
8
7
|
import { useQueryClient } from "@tanstack/react-query";
|
|
9
8
|
//#region packages/crud/crud/defineResource.ts
|
|
10
9
|
const stringResourceCache = /* @__PURE__ */ new Map();
|
|
@@ -39,6 +38,17 @@ function defineResource(apiUrl, overrides) {
|
|
|
39
38
|
return resource;
|
|
40
39
|
}
|
|
41
40
|
//#endregion
|
|
41
|
+
//#region packages/crud/crud/embeddedLinesUrl.ts
|
|
42
|
+
/**
|
|
43
|
+
* Builds a formDetail reload URL for {@code #[EmbeddedLines]} line entities.
|
|
44
|
+
*
|
|
45
|
+
* @example embeddedLinesUrl('/api/sales_document_lines', 'document')
|
|
46
|
+
* → '/api/sales_document_lines?document={id}'
|
|
47
|
+
*/
|
|
48
|
+
function embeddedLinesUrl(route, parentQueryParam) {
|
|
49
|
+
return `${route}${route.includes("?") ? "&" : "?"}${parentQueryParam}={id}`;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
42
52
|
//#region packages/crud/datagrid/DataGridEvents.ts
|
|
43
53
|
const DATA_GRID_EVENTS = {
|
|
44
54
|
SELECTION_CHANGED: "datagrid:selection.changed",
|
|
@@ -1219,9 +1229,6 @@ const enumTypeModule = {
|
|
|
1219
1229
|
};
|
|
1220
1230
|
//#endregion
|
|
1221
1231
|
//#region packages/crud/form/FileUploadField.tsx
|
|
1222
|
-
function cx$1(...values) {
|
|
1223
|
-
return values.filter(Boolean).join(" ");
|
|
1224
|
-
}
|
|
1225
1232
|
function resolveMediaPath(media) {
|
|
1226
1233
|
if (!media) return null;
|
|
1227
1234
|
const path = media["path"];
|
|
@@ -1247,27 +1254,6 @@ function resolveMediaIri(uploadUrl, media) {
|
|
|
1247
1254
|
function isImageMimeType(mimeType) {
|
|
1248
1255
|
return !!mimeType && mimeType.startsWith("image/");
|
|
1249
1256
|
}
|
|
1250
|
-
function buildDropzoneAccept(accept) {
|
|
1251
|
-
if (!accept || accept === "*/*" || accept === "*") return void 0;
|
|
1252
|
-
if (accept === "image/*") return {
|
|
1253
|
-
"image/png": [".png"],
|
|
1254
|
-
"image/jpeg": [".jpg", ".jpeg"],
|
|
1255
|
-
"image/webp": [".webp"],
|
|
1256
|
-
"image/gif": [".gif"]
|
|
1257
|
-
};
|
|
1258
|
-
if (accept.includes(",")) return accept.split(",").reduce((acc, token) => {
|
|
1259
|
-
const trimmed = token.trim();
|
|
1260
|
-
if (!trimmed) return acc;
|
|
1261
|
-
if (trimmed.startsWith(".")) {
|
|
1262
|
-
acc["application/octet-stream"] = [...acc["application/octet-stream"] ?? [], trimmed];
|
|
1263
|
-
return acc;
|
|
1264
|
-
}
|
|
1265
|
-
acc[trimmed] = [];
|
|
1266
|
-
return acc;
|
|
1267
|
-
}, {});
|
|
1268
|
-
if (accept.startsWith(".")) return { "application/octet-stream": [accept] };
|
|
1269
|
-
return { [accept]: [] };
|
|
1270
|
-
}
|
|
1271
1257
|
async function uploadMediaFile(file, uploadUrl, httpClient) {
|
|
1272
1258
|
const body = new FormData();
|
|
1273
1259
|
body.append("file", file);
|
|
@@ -1347,17 +1333,6 @@ function FileUploadField({ field, disabled = false, readOnly = false, invalid =
|
|
|
1347
1333
|
t,
|
|
1348
1334
|
uploadUrl
|
|
1349
1335
|
]);
|
|
1350
|
-
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
|
|
1351
|
-
accept: buildDropzoneAccept(field.accept),
|
|
1352
|
-
disabled: disabled || readOnly || status === "uploading",
|
|
1353
|
-
multiple: false,
|
|
1354
|
-
noClick: !!(previewUrl || fileName),
|
|
1355
|
-
noKeyboard: !!(previewUrl || fileName),
|
|
1356
|
-
onDrop: (acceptedFiles) => {
|
|
1357
|
-
const file = acceptedFiles[0];
|
|
1358
|
-
if (file) uploadFile(file);
|
|
1359
|
-
}
|
|
1360
|
-
});
|
|
1361
1336
|
const handleClear = () => {
|
|
1362
1337
|
revokeLocalPreview();
|
|
1363
1338
|
setPreviewUrl(null);
|
|
@@ -1367,104 +1342,35 @@ function FileUploadField({ field, disabled = false, readOnly = false, invalid =
|
|
|
1367
1342
|
setErrorMessage(null);
|
|
1368
1343
|
onCleared(field.name);
|
|
1369
1344
|
};
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
return /* @__PURE__ */
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
className: "nb-form__file-upload-file-link",
|
|
1400
|
-
href: fileUrl,
|
|
1401
|
-
target: "_blank",
|
|
1402
|
-
rel: "noreferrer",
|
|
1403
|
-
onClick: (event) => event.stopPropagation(),
|
|
1404
|
-
children: t("form.fileUploadOpen")
|
|
1405
|
-
})]
|
|
1406
|
-
})]
|
|
1407
|
-
}),
|
|
1408
|
-
status === "uploading" && /* @__PURE__ */ jsxs("div", {
|
|
1409
|
-
className: "nb-form__file-upload-overlay",
|
|
1410
|
-
"aria-live": "polite",
|
|
1411
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
1412
|
-
className: "nb-form__file-upload-spinner",
|
|
1413
|
-
"aria-hidden": "true"
|
|
1414
|
-
}), /* @__PURE__ */ jsx("span", { children: t("form.fileUploading") })]
|
|
1415
|
-
}),
|
|
1416
|
-
isInteractive && status !== "uploading" && /* @__PURE__ */ jsxs("div", {
|
|
1417
|
-
className: "nb-form__file-upload-actions",
|
|
1418
|
-
children: [/* @__PURE__ */ jsxs("button", {
|
|
1419
|
-
type: "button",
|
|
1420
|
-
className: "nb-form__file-upload-action",
|
|
1421
|
-
onClick: (event) => {
|
|
1422
|
-
event.stopPropagation();
|
|
1423
|
-
open();
|
|
1424
|
-
},
|
|
1425
|
-
children: [/* @__PURE__ */ jsx("i", {
|
|
1426
|
-
className: "ph ph-arrows-clockwise",
|
|
1427
|
-
"aria-hidden": "true"
|
|
1428
|
-
}), t("form.fileUploadReplace")]
|
|
1429
|
-
}), /* @__PURE__ */ jsxs("button", {
|
|
1430
|
-
type: "button",
|
|
1431
|
-
className: "nb-form__file-upload-action nb-form__file-upload-action--danger",
|
|
1432
|
-
onClick: (event) => {
|
|
1433
|
-
event.stopPropagation();
|
|
1434
|
-
handleClear();
|
|
1435
|
-
},
|
|
1436
|
-
children: [/* @__PURE__ */ jsx("i", {
|
|
1437
|
-
className: "ph ph-trash",
|
|
1438
|
-
"aria-hidden": "true"
|
|
1439
|
-
}), t("form.fileUploadRemove")]
|
|
1440
|
-
})]
|
|
1441
|
-
})
|
|
1442
|
-
] }) : /* @__PURE__ */ jsxs("div", {
|
|
1443
|
-
className: "nb-form__file-upload-placeholder",
|
|
1444
|
-
children: [
|
|
1445
|
-
/* @__PURE__ */ jsx("span", {
|
|
1446
|
-
className: "nb-form__file-upload-icon",
|
|
1447
|
-
"aria-hidden": "true",
|
|
1448
|
-
children: /* @__PURE__ */ jsx("i", { className: `ph ${placeholderIcon}` })
|
|
1449
|
-
}),
|
|
1450
|
-
/* @__PURE__ */ jsx("span", {
|
|
1451
|
-
className: "nb-form__file-upload-title",
|
|
1452
|
-
children: placeholderTitle
|
|
1453
|
-
}),
|
|
1454
|
-
/* @__PURE__ */ jsx("span", {
|
|
1455
|
-
className: "nb-form__file-upload-hint",
|
|
1456
|
-
children: placeholderHint
|
|
1457
|
-
})
|
|
1458
|
-
]
|
|
1459
|
-
})]
|
|
1460
|
-
}), errorMessage && /* @__PURE__ */ jsxs("span", {
|
|
1461
|
-
className: "nb-form__file-upload-error",
|
|
1462
|
-
role: "alert",
|
|
1463
|
-
children: [/* @__PURE__ */ jsx("i", {
|
|
1464
|
-
className: "ph ph-warning-circle",
|
|
1465
|
-
"aria-hidden": "true"
|
|
1466
|
-
}), errorMessage]
|
|
1467
|
-
})]
|
|
1345
|
+
const value = {
|
|
1346
|
+
fileName,
|
|
1347
|
+
fileUrl,
|
|
1348
|
+
previewUrl
|
|
1349
|
+
};
|
|
1350
|
+
return /* @__PURE__ */ jsx(FileDropzone, {
|
|
1351
|
+
accept: field.accept,
|
|
1352
|
+
disabled,
|
|
1353
|
+
readOnly,
|
|
1354
|
+
invalid,
|
|
1355
|
+
image: imageMode,
|
|
1356
|
+
value,
|
|
1357
|
+
uploading: status === "uploading",
|
|
1358
|
+
error: errorMessage,
|
|
1359
|
+
inputId: `nb-form-${field.name}`,
|
|
1360
|
+
inputLabel: field.label,
|
|
1361
|
+
labels: {
|
|
1362
|
+
dropPrompt: t("form.fileUploadDrop"),
|
|
1363
|
+
prompt: t("form.fileUploadPrompt"),
|
|
1364
|
+
imagePrompt: t("form.imageUploadPrompt"),
|
|
1365
|
+
hint: t("form.fileUploadHint"),
|
|
1366
|
+
imageHint: t("form.imageUploadHint"),
|
|
1367
|
+
uploading: t("form.fileUploading"),
|
|
1368
|
+
replace: t("form.fileUploadReplace"),
|
|
1369
|
+
remove: t("form.fileUploadRemove"),
|
|
1370
|
+
open: t("form.fileUploadOpen")
|
|
1371
|
+
},
|
|
1372
|
+
onFileSelect: (file) => void uploadFile(file),
|
|
1373
|
+
onClear: handleClear
|
|
1468
1374
|
});
|
|
1469
1375
|
}
|
|
1470
1376
|
function isImageFileField(field) {
|
|
@@ -3669,6 +3575,17 @@ function normalizeEntityField(row, field, adapter, prependDataByField) {
|
|
|
3669
3575
|
}
|
|
3670
3576
|
}
|
|
3671
3577
|
//#endregion
|
|
3578
|
+
//#region packages/crud/form/loadDetailRows.ts
|
|
3579
|
+
/**
|
|
3580
|
+
* Loads embedded line rows for formDetail edit mode. Accepts both plain JSON
|
|
3581
|
+
* arrays (nubit embedded-lines endpoint) and Hydra collections.
|
|
3582
|
+
*/
|
|
3583
|
+
async function loadDetailRows(httpClient, detailUrl, adapter) {
|
|
3584
|
+
const response = await httpClient.get(detailUrl);
|
|
3585
|
+
const { items } = (adapter ?? HydraAdapter).parseListResponse(response.data);
|
|
3586
|
+
return items;
|
|
3587
|
+
}
|
|
3588
|
+
//#endregion
|
|
3672
3589
|
//#region packages/crud/form/safeRandomId.ts
|
|
3673
3590
|
/**
|
|
3674
3591
|
* Generate a unique-enough id string for internal React keys.
|
|
@@ -4729,7 +4646,7 @@ const NativeFormView = forwardRef((options, ref) => {
|
|
|
4729
4646
|
const detailUrl = typeof detailId === "string" || typeof detailId === "number" ? options.detailUrl?.replace("{id}", String(detailId)) : void 0;
|
|
4730
4647
|
if (!detailUrl) return;
|
|
4731
4648
|
emit(FORM_EVENTS.LOADING, true);
|
|
4732
|
-
httpClient.
|
|
4649
|
+
loadDetailRows(httpClient, detailUrl, options.adapter).then((rows) => setNextDetailRows(rows)).finally(() => emit(FORM_EVENTS.LOADING, false));
|
|
4733
4650
|
}, [
|
|
4734
4651
|
captureExistingMedia,
|
|
4735
4652
|
emit,
|
|
@@ -8519,6 +8436,24 @@ function ToolbarSelect({ id, label, icon = "ph-funnel", value, options, onChange
|
|
|
8519
8436
|
});
|
|
8520
8437
|
}
|
|
8521
8438
|
//#endregion
|
|
8439
|
+
//#region packages/crud/workflow/buildWorkflowRowActions.ts
|
|
8440
|
+
function buildWorkflowRowActions(row, workflow, apiUrl, roles, onDone) {
|
|
8441
|
+
if (!workflow) return [];
|
|
8442
|
+
const current = String(row[workflow.field] ?? "");
|
|
8443
|
+
return workflow.transitions.filter((transition) => transition.from.includes(current)).filter((transition) => !transition.roles?.length || transition.roles.some((role) => roles.includes(role))).map((transition) => ({
|
|
8444
|
+
text: transition.label ?? transition.name,
|
|
8445
|
+
onClick: async () => {
|
|
8446
|
+
const base = apiUrl.replace(/\/$/, "");
|
|
8447
|
+
const id = row.id;
|
|
8448
|
+
await fetch(`${base}/${id}/transition/${transition.name}`, {
|
|
8449
|
+
method: "POST",
|
|
8450
|
+
credentials: "include"
|
|
8451
|
+
});
|
|
8452
|
+
onDone?.();
|
|
8453
|
+
}
|
|
8454
|
+
}));
|
|
8455
|
+
}
|
|
8456
|
+
//#endregion
|
|
8522
8457
|
//#region packages/crud/adapter/RestAdapter.ts
|
|
8523
8458
|
/**
|
|
8524
8459
|
* Backend adapter for plain OpenAPI / REST backends.
|
|
@@ -8670,4 +8605,4 @@ function createRestResourceStore(dialect = {}) {
|
|
|
8670
8605
|
};
|
|
8671
8606
|
}
|
|
8672
8607
|
//#endregion
|
|
8673
|
-
export { AuditTrailPanel, ColumnPresetSelector, CrudDialogShell, CrudDrawerShell, CrudFormShell, CrudPage, CrudPageShell, DATA_GRID_EVENTS, DEFAULT_DRAWER_SIZE, DEFAULT_DRAWER_WIDTH, DRAWER_WIDTHS, NativeDataGridView as DataGridView, CrudDialogView as DialogView, CrudDrawerView as DrawerView, FORM_EVENTS, FieldBuilder, FieldType, NativeFormView as FormView, HydraAdapter, CrudPageView as PageView, ResourceSchemaProvider, ResourceStoreProvider, RestAdapter, SmartCrudPage, SmartCrudRolesProvider, ToolbarSelect, buildFieldColSpanContext, buildFields, checkboxField, computeSummaryValue, createCrudEvents, createRestResourceStore, crudRoute, currencyField, dateField, datetimeField, defineFieldContract, defineFields, defineResource, entityField, enumField, fileField, formatSummaryValue, identityField, imageField, isLongTextField, isShortField, noneField, numberField, parseDrawerWidthPx, passwordField, resolveDrawerLayoutBucket, resolveDrawerSize, resolveDrawerWidth, resolveFieldColSpan, resolveFieldsColSpans, resolveSummaryText, resolveViewMode, selectField, switchField, textField, textareaField, useColumnPreset, useResourceStoreFactory, useSmartCrudRoles, validateFieldContract };
|
|
8608
|
+
export { AuditTrailPanel, ColumnPresetSelector, CrudDialogShell, CrudDrawerShell, CrudFormShell, CrudPage, CrudPageShell, DATA_GRID_EVENTS, DEFAULT_DRAWER_SIZE, DEFAULT_DRAWER_WIDTH, DRAWER_WIDTHS, NativeDataGridView as DataGridView, CrudDialogView as DialogView, CrudDrawerView as DrawerView, FORM_EVENTS, FieldBuilder, FieldType, NativeFormView as FormView, HydraAdapter, CrudPageView as PageView, ResourceSchemaProvider, ResourceStoreProvider, RestAdapter, SmartCrudPage, SmartCrudRolesProvider, ToolbarSelect, buildFieldColSpanContext, buildFields, buildWorkflowRowActions, checkboxField, computeSummaryValue, createCrudEvents, createRestResourceStore, crudRoute, currencyField, dateField, datetimeField, defineFieldContract, defineFields, defineResource, embeddedLinesUrl, entityField, enumField, fileField, formatSummaryValue, identityField, imageField, isLongTextField, isShortField, noneField, numberField, parseDrawerWidthPx, passwordField, resolveDrawerLayoutBucket, resolveDrawerSize, resolveDrawerWidth, resolveFieldColSpan, resolveFieldsColSpans, resolveSummaryText, resolveViewMode, selectField, switchField, textField, textareaField, useColumnPreset, useResourceStoreFactory, useSmartCrudRoles, validateFieldContract };
|
package/dist/style.css
CHANGED
|
@@ -617,7 +617,7 @@
|
|
|
617
617
|
font-size: var(--font-size-xs);
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
.nb-datagrid__filter-operator {
|
|
620
|
+
.nb-datagrid__filter-wrap > .nb-datagrid__filter-operator {
|
|
621
621
|
left: 5px;
|
|
622
622
|
position: absolute;
|
|
623
623
|
top: 50%;
|
|
@@ -625,7 +625,7 @@
|
|
|
625
625
|
width: 30px;
|
|
626
626
|
z-index: 2;
|
|
627
627
|
}
|
|
628
|
-
.nb-datagrid__filter-operator.nb-dropdown .nb-dropdown__trigger {
|
|
628
|
+
.nb-datagrid__filter-wrap > .nb-datagrid__filter-operator.nb-dropdown .nb-dropdown__trigger {
|
|
629
629
|
appearance: none;
|
|
630
630
|
background: color-mix(in srgb, var(--accent-color) 10%, transparent);
|
|
631
631
|
border: 1px solid color-mix(in srgb, var(--accent-color) 20%, transparent);
|
|
@@ -641,7 +641,7 @@
|
|
|
641
641
|
text-align: center;
|
|
642
642
|
width: 30px;
|
|
643
643
|
}
|
|
644
|
-
.nb-datagrid__filter-operator.nb-dropdown .nb-dropdown__caret {
|
|
644
|
+
.nb-datagrid__filter-wrap > .nb-datagrid__filter-operator.nb-dropdown .nb-dropdown__caret {
|
|
645
645
|
display: none;
|
|
646
646
|
}
|
|
647
647
|
|
|
@@ -1705,471 +1705,6 @@ html[data-density=compact] .nb-datagrid .nb-badge {
|
|
|
1705
1705
|
box-shadow: none;
|
|
1706
1706
|
}
|
|
1707
1707
|
}
|
|
1708
|
-
.nb-form__file-upload {
|
|
1709
|
-
display: flex;
|
|
1710
|
-
flex-direction: column;
|
|
1711
|
-
gap: var(--space-1);
|
|
1712
|
-
width: 100%;
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
.nb-form__file-upload-zone {
|
|
1716
|
-
align-items: center;
|
|
1717
|
-
background: var(--surface-1);
|
|
1718
|
-
border: 1px dashed var(--border-color);
|
|
1719
|
-
border-radius: var(--radius-lg);
|
|
1720
|
-
box-sizing: border-box;
|
|
1721
|
-
cursor: pointer;
|
|
1722
|
-
display: flex;
|
|
1723
|
-
justify-content: center;
|
|
1724
|
-
min-height: 112px;
|
|
1725
|
-
overflow: hidden;
|
|
1726
|
-
position: relative;
|
|
1727
|
-
transition: border-color var(--transition-base), background var(--transition-base), box-shadow var(--transition-base);
|
|
1728
|
-
width: 100%;
|
|
1729
|
-
}
|
|
1730
|
-
.nb-form__file-upload-zone:hover:not(.nb-form__file-upload-zone--disabled):not(.nb-form__file-upload-zone--filled) {
|
|
1731
|
-
background: color-mix(in srgb, var(--accent-color) 4%, var(--surface-1));
|
|
1732
|
-
border-color: var(--accent-color);
|
|
1733
|
-
}
|
|
1734
|
-
.nb-form__file-upload-zone--active {
|
|
1735
|
-
background: color-mix(in srgb, var(--accent-color) 8%, var(--surface-1));
|
|
1736
|
-
border-color: var(--accent-color);
|
|
1737
|
-
}
|
|
1738
|
-
.nb-form__file-upload-zone--filled {
|
|
1739
|
-
border-style: solid;
|
|
1740
|
-
cursor: default;
|
|
1741
|
-
min-height: 88px;
|
|
1742
|
-
}
|
|
1743
|
-
.nb-form__file-upload-zone--uploading {
|
|
1744
|
-
pointer-events: none;
|
|
1745
|
-
}
|
|
1746
|
-
.nb-form__file-upload-zone--disabled {
|
|
1747
|
-
cursor: not-allowed;
|
|
1748
|
-
opacity: 0.72;
|
|
1749
|
-
}
|
|
1750
|
-
.nb-form__file-upload-zone:focus-visible {
|
|
1751
|
-
box-shadow: 0 0 0 3px var(--focus-ring-color);
|
|
1752
|
-
outline: none;
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
.nb-form__file-upload--image .nb-form__file-upload-zone {
|
|
1756
|
-
min-height: 168px;
|
|
1757
|
-
}
|
|
1758
|
-
|
|
1759
|
-
.nb-form__file-upload--image .nb-form__file-upload-zone--filled {
|
|
1760
|
-
min-height: 180px;
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
.nb-form__file-upload--invalid .nb-form__file-upload-zone {
|
|
1764
|
-
border-color: var(--error-color);
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
.nb-form__file-upload-placeholder {
|
|
1768
|
-
align-items: center;
|
|
1769
|
-
display: flex;
|
|
1770
|
-
flex-direction: column;
|
|
1771
|
-
gap: var(--space-2);
|
|
1772
|
-
max-width: 320px;
|
|
1773
|
-
padding: var(--space-4);
|
|
1774
|
-
text-align: center;
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
.nb-form__file-upload-icon {
|
|
1778
|
-
align-items: center;
|
|
1779
|
-
background: color-mix(in srgb, var(--accent-color) 10%, transparent);
|
|
1780
|
-
border-radius: 999px;
|
|
1781
|
-
color: var(--accent-color);
|
|
1782
|
-
display: inline-flex;
|
|
1783
|
-
font-size: 24px;
|
|
1784
|
-
height: 48px;
|
|
1785
|
-
justify-content: center;
|
|
1786
|
-
width: 48px;
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
.nb-form__file-upload-title {
|
|
1790
|
-
color: var(--text-primary);
|
|
1791
|
-
font-size: var(--font-size-sm);
|
|
1792
|
-
font-weight: var(--font-weight-semibold);
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
.nb-form__file-upload-hint {
|
|
1796
|
-
color: var(--text-tertiary);
|
|
1797
|
-
font-size: var(--font-size-xs);
|
|
1798
|
-
line-height: var(--line-height-tight);
|
|
1799
|
-
}
|
|
1800
|
-
|
|
1801
|
-
.nb-form__file-upload-preview {
|
|
1802
|
-
display: block;
|
|
1803
|
-
height: 100%;
|
|
1804
|
-
max-height: 220px;
|
|
1805
|
-
object-fit: contain;
|
|
1806
|
-
width: 100%;
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
.nb-form__file-upload-file {
|
|
1810
|
-
align-items: center;
|
|
1811
|
-
display: flex;
|
|
1812
|
-
gap: var(--space-3);
|
|
1813
|
-
max-width: 100%;
|
|
1814
|
-
padding: var(--space-3) var(--space-4);
|
|
1815
|
-
width: 100%;
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
.nb-form__file-upload-file-icon {
|
|
1819
|
-
align-items: center;
|
|
1820
|
-
background: var(--surface-0);
|
|
1821
|
-
border: 1px solid var(--border-subtle);
|
|
1822
|
-
border-radius: var(--radius-md);
|
|
1823
|
-
color: var(--accent-color);
|
|
1824
|
-
display: inline-flex;
|
|
1825
|
-
flex: 0 0 auto;
|
|
1826
|
-
font-size: 22px;
|
|
1827
|
-
height: 44px;
|
|
1828
|
-
justify-content: center;
|
|
1829
|
-
width: 44px;
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1832
|
-
.nb-form__file-upload-file-meta {
|
|
1833
|
-
display: flex;
|
|
1834
|
-
flex: 1 1 auto;
|
|
1835
|
-
flex-direction: column;
|
|
1836
|
-
gap: 2px;
|
|
1837
|
-
min-width: 0;
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
.nb-form__file-upload-file-name {
|
|
1841
|
-
color: var(--text-primary);
|
|
1842
|
-
font-size: var(--font-size-sm);
|
|
1843
|
-
font-weight: var(--font-weight-medium);
|
|
1844
|
-
overflow: hidden;
|
|
1845
|
-
text-overflow: ellipsis;
|
|
1846
|
-
white-space: nowrap;
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
.nb-form__file-upload-file-link {
|
|
1850
|
-
color: var(--accent-color);
|
|
1851
|
-
font-size: var(--font-size-xs);
|
|
1852
|
-
text-decoration: none;
|
|
1853
|
-
}
|
|
1854
|
-
.nb-form__file-upload-file-link:hover {
|
|
1855
|
-
text-decoration: underline;
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
.nb-form__file-upload-overlay {
|
|
1859
|
-
align-items: center;
|
|
1860
|
-
background: rgba(0, 0, 0, 0.42);
|
|
1861
|
-
color: #fff;
|
|
1862
|
-
display: flex;
|
|
1863
|
-
flex-direction: column;
|
|
1864
|
-
font-size: var(--font-size-sm);
|
|
1865
|
-
gap: var(--space-2);
|
|
1866
|
-
inset: 0;
|
|
1867
|
-
justify-content: center;
|
|
1868
|
-
position: absolute;
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
.nb-form__file-upload-spinner {
|
|
1872
|
-
animation: nb-form-file-spin 700ms linear infinite;
|
|
1873
|
-
border: 2px solid rgba(255, 255, 255, 0.35);
|
|
1874
|
-
border-radius: 999px;
|
|
1875
|
-
border-top-color: #fff;
|
|
1876
|
-
height: 24px;
|
|
1877
|
-
width: 24px;
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
@keyframes nb-form-file-spin {
|
|
1881
|
-
to {
|
|
1882
|
-
transform: rotate(360deg);
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
.nb-form__file-upload-actions {
|
|
1886
|
-
align-items: center;
|
|
1887
|
-
background: linear-gradient(to top, rgba(0, 0, 0, 0.58), transparent);
|
|
1888
|
-
bottom: 0;
|
|
1889
|
-
display: flex;
|
|
1890
|
-
gap: var(--space-2);
|
|
1891
|
-
inset-inline: 0;
|
|
1892
|
-
justify-content: center;
|
|
1893
|
-
opacity: 0;
|
|
1894
|
-
padding: var(--space-3);
|
|
1895
|
-
position: absolute;
|
|
1896
|
-
transition: opacity var(--transition-base);
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
.nb-form__file-upload-zone--filled:hover .nb-form__file-upload-actions,
|
|
1900
|
-
.nb-form__file-upload-zone--filled:focus-within .nb-form__file-upload-actions {
|
|
1901
|
-
opacity: 1;
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
.nb-form__file-upload-action {
|
|
1905
|
-
align-items: center;
|
|
1906
|
-
background: var(--surface-1);
|
|
1907
|
-
border: 1px solid var(--border-subtle);
|
|
1908
|
-
border-radius: var(--radius-md);
|
|
1909
|
-
color: var(--text-primary);
|
|
1910
|
-
cursor: pointer;
|
|
1911
|
-
display: inline-flex;
|
|
1912
|
-
font: inherit;
|
|
1913
|
-
font-size: var(--font-size-xs);
|
|
1914
|
-
font-weight: var(--font-weight-medium);
|
|
1915
|
-
gap: var(--space-1);
|
|
1916
|
-
min-height: 28px;
|
|
1917
|
-
padding: 0 var(--space-2);
|
|
1918
|
-
transition: background var(--transition-base), border-color var(--transition-base), color var(--transition-base);
|
|
1919
|
-
}
|
|
1920
|
-
.nb-form__file-upload-action:hover {
|
|
1921
|
-
border-color: var(--accent-color);
|
|
1922
|
-
color: var(--accent-color);
|
|
1923
|
-
}
|
|
1924
|
-
.nb-form__file-upload-action--danger:hover {
|
|
1925
|
-
border-color: var(--error-color);
|
|
1926
|
-
color: var(--error-color);
|
|
1927
|
-
}
|
|
1928
|
-
.nb-form__file-upload-action:focus-visible {
|
|
1929
|
-
box-shadow: 0 0 0 2px var(--focus-ring-color);
|
|
1930
|
-
outline: none;
|
|
1931
|
-
}
|
|
1932
|
-
|
|
1933
|
-
.nb-form__file-upload-error {
|
|
1934
|
-
align-items: center;
|
|
1935
|
-
color: var(--error-color);
|
|
1936
|
-
display: inline-flex;
|
|
1937
|
-
font-size: var(--font-size-xs);
|
|
1938
|
-
gap: var(--space-1);
|
|
1939
|
-
}
|
|
1940
|
-
.nb-form__file-upload {
|
|
1941
|
-
display: flex;
|
|
1942
|
-
flex-direction: column;
|
|
1943
|
-
gap: var(--space-1);
|
|
1944
|
-
width: 100%;
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
.nb-form__file-upload-zone {
|
|
1948
|
-
align-items: center;
|
|
1949
|
-
background: var(--surface-1);
|
|
1950
|
-
border: 1px dashed var(--border-color);
|
|
1951
|
-
border-radius: var(--radius-lg);
|
|
1952
|
-
box-sizing: border-box;
|
|
1953
|
-
cursor: pointer;
|
|
1954
|
-
display: flex;
|
|
1955
|
-
justify-content: center;
|
|
1956
|
-
min-height: 112px;
|
|
1957
|
-
overflow: hidden;
|
|
1958
|
-
position: relative;
|
|
1959
|
-
transition: border-color var(--transition-base), background var(--transition-base), box-shadow var(--transition-base);
|
|
1960
|
-
width: 100%;
|
|
1961
|
-
}
|
|
1962
|
-
.nb-form__file-upload-zone:hover:not(.nb-form__file-upload-zone--disabled):not(.nb-form__file-upload-zone--filled) {
|
|
1963
|
-
background: color-mix(in srgb, var(--accent-color) 4%, var(--surface-1));
|
|
1964
|
-
border-color: var(--accent-color);
|
|
1965
|
-
}
|
|
1966
|
-
.nb-form__file-upload-zone--active {
|
|
1967
|
-
background: color-mix(in srgb, var(--accent-color) 8%, var(--surface-1));
|
|
1968
|
-
border-color: var(--accent-color);
|
|
1969
|
-
}
|
|
1970
|
-
.nb-form__file-upload-zone--filled {
|
|
1971
|
-
border-style: solid;
|
|
1972
|
-
cursor: default;
|
|
1973
|
-
min-height: 88px;
|
|
1974
|
-
}
|
|
1975
|
-
.nb-form__file-upload-zone--uploading {
|
|
1976
|
-
pointer-events: none;
|
|
1977
|
-
}
|
|
1978
|
-
.nb-form__file-upload-zone--disabled {
|
|
1979
|
-
cursor: not-allowed;
|
|
1980
|
-
opacity: 0.72;
|
|
1981
|
-
}
|
|
1982
|
-
.nb-form__file-upload-zone:focus-visible {
|
|
1983
|
-
box-shadow: 0 0 0 3px var(--focus-ring-color);
|
|
1984
|
-
outline: none;
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
|
-
.nb-form__file-upload--image .nb-form__file-upload-zone {
|
|
1988
|
-
min-height: 168px;
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
.nb-form__file-upload--image .nb-form__file-upload-zone--filled {
|
|
1992
|
-
min-height: 180px;
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
|
-
.nb-form__file-upload--invalid .nb-form__file-upload-zone {
|
|
1996
|
-
border-color: var(--error-color);
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
.nb-form__file-upload-placeholder {
|
|
2000
|
-
align-items: center;
|
|
2001
|
-
display: flex;
|
|
2002
|
-
flex-direction: column;
|
|
2003
|
-
gap: var(--space-2);
|
|
2004
|
-
max-width: 320px;
|
|
2005
|
-
padding: var(--space-4);
|
|
2006
|
-
text-align: center;
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
.nb-form__file-upload-icon {
|
|
2010
|
-
align-items: center;
|
|
2011
|
-
background: color-mix(in srgb, var(--accent-color) 10%, transparent);
|
|
2012
|
-
border-radius: 999px;
|
|
2013
|
-
color: var(--accent-color);
|
|
2014
|
-
display: inline-flex;
|
|
2015
|
-
font-size: 24px;
|
|
2016
|
-
height: 48px;
|
|
2017
|
-
justify-content: center;
|
|
2018
|
-
width: 48px;
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2021
|
-
.nb-form__file-upload-title {
|
|
2022
|
-
color: var(--text-primary);
|
|
2023
|
-
font-size: var(--font-size-sm);
|
|
2024
|
-
font-weight: var(--font-weight-semibold);
|
|
2025
|
-
}
|
|
2026
|
-
|
|
2027
|
-
.nb-form__file-upload-hint {
|
|
2028
|
-
color: var(--text-tertiary);
|
|
2029
|
-
font-size: var(--font-size-xs);
|
|
2030
|
-
line-height: var(--line-height-tight);
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
|
-
.nb-form__file-upload-preview {
|
|
2034
|
-
display: block;
|
|
2035
|
-
height: 100%;
|
|
2036
|
-
max-height: 220px;
|
|
2037
|
-
object-fit: contain;
|
|
2038
|
-
width: 100%;
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
.nb-form__file-upload-file {
|
|
2042
|
-
align-items: center;
|
|
2043
|
-
display: flex;
|
|
2044
|
-
gap: var(--space-3);
|
|
2045
|
-
max-width: 100%;
|
|
2046
|
-
padding: var(--space-3) var(--space-4);
|
|
2047
|
-
width: 100%;
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2050
|
-
.nb-form__file-upload-file-icon {
|
|
2051
|
-
align-items: center;
|
|
2052
|
-
background: var(--surface-0);
|
|
2053
|
-
border: 1px solid var(--border-subtle);
|
|
2054
|
-
border-radius: var(--radius-md);
|
|
2055
|
-
color: var(--accent-color);
|
|
2056
|
-
display: inline-flex;
|
|
2057
|
-
flex: 0 0 auto;
|
|
2058
|
-
font-size: 22px;
|
|
2059
|
-
height: 44px;
|
|
2060
|
-
justify-content: center;
|
|
2061
|
-
width: 44px;
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
.nb-form__file-upload-file-meta {
|
|
2065
|
-
display: flex;
|
|
2066
|
-
flex: 1 1 auto;
|
|
2067
|
-
flex-direction: column;
|
|
2068
|
-
gap: 2px;
|
|
2069
|
-
min-width: 0;
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
|
-
.nb-form__file-upload-file-name {
|
|
2073
|
-
color: var(--text-primary);
|
|
2074
|
-
font-size: var(--font-size-sm);
|
|
2075
|
-
font-weight: var(--font-weight-medium);
|
|
2076
|
-
overflow: hidden;
|
|
2077
|
-
text-overflow: ellipsis;
|
|
2078
|
-
white-space: nowrap;
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
|
-
.nb-form__file-upload-file-link {
|
|
2082
|
-
color: var(--accent-color);
|
|
2083
|
-
font-size: var(--font-size-xs);
|
|
2084
|
-
text-decoration: none;
|
|
2085
|
-
}
|
|
2086
|
-
.nb-form__file-upload-file-link:hover {
|
|
2087
|
-
text-decoration: underline;
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
.nb-form__file-upload-overlay {
|
|
2091
|
-
align-items: center;
|
|
2092
|
-
background: rgba(0, 0, 0, 0.42);
|
|
2093
|
-
color: #fff;
|
|
2094
|
-
display: flex;
|
|
2095
|
-
flex-direction: column;
|
|
2096
|
-
font-size: var(--font-size-sm);
|
|
2097
|
-
gap: var(--space-2);
|
|
2098
|
-
inset: 0;
|
|
2099
|
-
justify-content: center;
|
|
2100
|
-
position: absolute;
|
|
2101
|
-
}
|
|
2102
|
-
|
|
2103
|
-
.nb-form__file-upload-spinner {
|
|
2104
|
-
animation: nb-form-file-spin 700ms linear infinite;
|
|
2105
|
-
border: 2px solid rgba(255, 255, 255, 0.35);
|
|
2106
|
-
border-radius: 999px;
|
|
2107
|
-
border-top-color: #fff;
|
|
2108
|
-
height: 24px;
|
|
2109
|
-
width: 24px;
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
|
-
@keyframes nb-form-file-spin {
|
|
2113
|
-
to {
|
|
2114
|
-
transform: rotate(360deg);
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
.nb-form__file-upload-actions {
|
|
2118
|
-
align-items: center;
|
|
2119
|
-
background: linear-gradient(to top, rgba(0, 0, 0, 0.58), transparent);
|
|
2120
|
-
bottom: 0;
|
|
2121
|
-
display: flex;
|
|
2122
|
-
gap: var(--space-2);
|
|
2123
|
-
inset-inline: 0;
|
|
2124
|
-
justify-content: center;
|
|
2125
|
-
opacity: 0;
|
|
2126
|
-
padding: var(--space-3);
|
|
2127
|
-
position: absolute;
|
|
2128
|
-
transition: opacity var(--transition-base);
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
|
-
.nb-form__file-upload-zone--filled:hover .nb-form__file-upload-actions,
|
|
2132
|
-
.nb-form__file-upload-zone--filled:focus-within .nb-form__file-upload-actions {
|
|
2133
|
-
opacity: 1;
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
.nb-form__file-upload-action {
|
|
2137
|
-
align-items: center;
|
|
2138
|
-
background: var(--surface-1);
|
|
2139
|
-
border: 1px solid var(--border-subtle);
|
|
2140
|
-
border-radius: var(--radius-md);
|
|
2141
|
-
color: var(--text-primary);
|
|
2142
|
-
cursor: pointer;
|
|
2143
|
-
display: inline-flex;
|
|
2144
|
-
font: inherit;
|
|
2145
|
-
font-size: var(--font-size-xs);
|
|
2146
|
-
font-weight: var(--font-weight-medium);
|
|
2147
|
-
gap: var(--space-1);
|
|
2148
|
-
min-height: 28px;
|
|
2149
|
-
padding: 0 var(--space-2);
|
|
2150
|
-
transition: background var(--transition-base), border-color var(--transition-base), color var(--transition-base);
|
|
2151
|
-
}
|
|
2152
|
-
.nb-form__file-upload-action:hover {
|
|
2153
|
-
border-color: var(--accent-color);
|
|
2154
|
-
color: var(--accent-color);
|
|
2155
|
-
}
|
|
2156
|
-
.nb-form__file-upload-action--danger:hover {
|
|
2157
|
-
border-color: var(--error-color);
|
|
2158
|
-
color: var(--error-color);
|
|
2159
|
-
}
|
|
2160
|
-
.nb-form__file-upload-action:focus-visible {
|
|
2161
|
-
box-shadow: 0 0 0 2px var(--focus-ring-color);
|
|
2162
|
-
outline: none;
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
.nb-form__file-upload-error {
|
|
2166
|
-
align-items: center;
|
|
2167
|
-
color: var(--error-color);
|
|
2168
|
-
display: inline-flex;
|
|
2169
|
-
font-size: var(--font-size-xs);
|
|
2170
|
-
gap: var(--space-1);
|
|
2171
|
-
}
|
|
2172
|
-
|
|
2173
1708
|
.nb-form {
|
|
2174
1709
|
color: var(--text-primary);
|
|
2175
1710
|
display: flex;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nubitio/crud",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Declarative CRUD engine with field DSL, forms, datagrids, RBAC, conditional logic and pluggable adapters (Hydra/REST).",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,10 +56,7 @@
|
|
|
56
56
|
"react-dom": "^19.0.0",
|
|
57
57
|
"react-i18next": "^14.0.0",
|
|
58
58
|
"react-router-dom": "^6.0.0",
|
|
59
|
-
"@nubitio/core": "^0.5.
|
|
60
|
-
"@nubitio/ui": "^0.5.
|
|
61
|
-
},
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"react-dropzone": "^15.0.0"
|
|
59
|
+
"@nubitio/core": "^0.5.19",
|
|
60
|
+
"@nubitio/ui": "^0.5.19"
|
|
64
61
|
}
|
|
65
62
|
}
|