@almadar/ui 5.160.0 → 5.161.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/dist/avl/index.cjs +924 -891
- package/dist/avl/index.js +914 -881
- package/dist/components/index.cjs +944 -934
- package/dist/components/index.d.cts +156 -31
- package/dist/components/index.d.ts +156 -31
- package/dist/components/index.js +931 -924
- package/dist/hooks/index.cjs +25 -49
- package/dist/hooks/index.js +25 -49
- package/dist/locales/index.cjs +75 -147
- package/dist/locales/index.js +75 -147
- package/dist/providers/index.cjs +911 -882
- package/dist/providers/index.js +901 -872
- package/dist/runtime/index.cjs +920 -887
- package/dist/runtime/index.js +910 -877
- package/locales/ar.json +25 -49
- package/locales/en.json +25 -49
- package/locales/sl.json +25 -49
- package/package.json +5 -5
package/dist/providers/index.cjs
CHANGED
|
@@ -26338,8 +26338,9 @@ function DataGrid({
|
|
|
26338
26338
|
const titleField = fieldDefs.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fieldDefs[0];
|
|
26339
26339
|
const badgeFields = fieldDefs.filter((f3) => f3.variant === "badge" && f3 !== titleField);
|
|
26340
26340
|
const bodyFields = fieldDefs.filter((f3) => f3 !== titleField && !badgeFields.includes(f3));
|
|
26341
|
-
const
|
|
26342
|
-
const
|
|
26341
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
26342
|
+
const inlineCardActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
26343
|
+
const menuCardActions = actionDefs.filter((a) => !inlineCardActions.includes(a));
|
|
26343
26344
|
const fireAction = (action, itemData) => {
|
|
26344
26345
|
if (action.navigatesTo) {
|
|
26345
26346
|
const url = action.navigatesTo.replace(
|
|
@@ -26359,6 +26360,9 @@ function DataGrid({
|
|
|
26359
26360
|
e.stopPropagation();
|
|
26360
26361
|
fireAction(action, itemData);
|
|
26361
26362
|
};
|
|
26363
|
+
const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
|
|
26364
|
+
const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
|
|
26365
|
+
const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
|
|
26362
26366
|
const hasRenderProp = typeof children === "function";
|
|
26363
26367
|
React87.useEffect(() => {
|
|
26364
26368
|
if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
|
|
@@ -26430,55 +26434,40 @@ function DataGrid({
|
|
|
26430
26434
|
{
|
|
26431
26435
|
"data-entity-row": true,
|
|
26432
26436
|
"data-entity-id": id,
|
|
26433
|
-
|
|
26437
|
+
onClick: handleCardClick?.(itemData),
|
|
26438
|
+
className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
|
|
26434
26439
|
children: [
|
|
26435
26440
|
children(itemData, index),
|
|
26436
|
-
actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.
|
|
26437
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
26438
|
-
|
|
26439
|
-
|
|
26440
|
-
|
|
26441
|
-
|
|
26442
|
-
|
|
26443
|
-
|
|
26444
|
-
|
|
26445
|
-
|
|
26446
|
-
|
|
26447
|
-
|
|
26448
|
-
|
|
26449
|
-
|
|
26450
|
-
|
|
26451
|
-
|
|
26452
|
-
|
|
26453
|
-
)),
|
|
26454
|
-
maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26455
|
-
Menu,
|
|
26456
|
-
{
|
|
26457
|
-
position: "bottom-end",
|
|
26458
|
-
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26459
|
-
items: actionDefs.slice(maxInlineActions).map((action) => ({
|
|
26460
|
-
label: action.label,
|
|
26461
|
-
icon: action.icon,
|
|
26462
|
-
event: action.event,
|
|
26463
|
-
onClick: () => fireAction(action, itemData)
|
|
26464
|
-
}))
|
|
26465
|
-
}
|
|
26466
|
-
)
|
|
26467
|
-
] }),
|
|
26468
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden [@media(pointer:coarse)]:block rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
26441
|
+
actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { onClick: stopCardClick, className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: [
|
|
26442
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26443
|
+
Button,
|
|
26444
|
+
{
|
|
26445
|
+
variant: "primary",
|
|
26446
|
+
size: "sm",
|
|
26447
|
+
onClick: handleActionClick(action, itemData),
|
|
26448
|
+
"data-testid": `action-${action.event}`,
|
|
26449
|
+
"data-row-id": String(itemData.id),
|
|
26450
|
+
children: [
|
|
26451
|
+
action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
|
|
26452
|
+
action.label
|
|
26453
|
+
]
|
|
26454
|
+
},
|
|
26455
|
+
idx
|
|
26456
|
+
)),
|
|
26457
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26469
26458
|
Menu,
|
|
26470
26459
|
{
|
|
26471
26460
|
position: "bottom-end",
|
|
26472
26461
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26473
|
-
items:
|
|
26462
|
+
items: menuCardActions.map((action) => ({
|
|
26474
26463
|
label: action.label,
|
|
26475
26464
|
icon: action.icon,
|
|
26476
|
-
|
|
26465
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
26477
26466
|
onClick: () => fireAction(action, itemData)
|
|
26478
26467
|
}))
|
|
26479
26468
|
}
|
|
26480
|
-
)
|
|
26481
|
-
] })
|
|
26469
|
+
)
|
|
26470
|
+
] }) })
|
|
26482
26471
|
]
|
|
26483
26472
|
},
|
|
26484
26473
|
id
|
|
@@ -26492,12 +26481,14 @@ function DataGrid({
|
|
|
26492
26481
|
{
|
|
26493
26482
|
"data-entity-row": true,
|
|
26494
26483
|
"data-entity-id": id,
|
|
26484
|
+
onClick: handleCardClick?.(itemData),
|
|
26495
26485
|
className: cn(
|
|
26496
26486
|
"bg-card rounded-lg",
|
|
26497
26487
|
"border border-border",
|
|
26498
26488
|
"shadow-elevation-card hover:shadow-elevation-dialog",
|
|
26499
26489
|
"hover:border-primary transition-all",
|
|
26500
26490
|
"flex flex-col",
|
|
26491
|
+
handleCardClick && "cursor-pointer",
|
|
26501
26492
|
isSelected && "ring-2 ring-primary border-primary"
|
|
26502
26493
|
),
|
|
26503
26494
|
children: [
|
|
@@ -26547,53 +26538,35 @@ function DataGrid({
|
|
|
26547
26538
|
] }, field.name);
|
|
26548
26539
|
}) })
|
|
26549
26540
|
] }),
|
|
26550
|
-
|
|
26551
|
-
|
|
26541
|
+
actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", onClick: stopCardClick, className: "flex-shrink-0", children: [
|
|
26542
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
26552
26543
|
Button,
|
|
26553
26544
|
{
|
|
26554
|
-
variant:
|
|
26545
|
+
variant: "primary",
|
|
26555
26546
|
size: "sm",
|
|
26556
26547
|
onClick: handleActionClick(action, itemData),
|
|
26557
26548
|
"data-testid": `action-${action.event}`,
|
|
26558
26549
|
"data-row-id": String(itemData.id),
|
|
26559
26550
|
"aria-label": action.label,
|
|
26560
26551
|
title: action.label,
|
|
26561
|
-
className: cn(
|
|
26562
|
-
action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
|
|
26563
|
-
action.icon && "px-2"
|
|
26564
|
-
),
|
|
26552
|
+
className: cn(action.icon && "px-2"),
|
|
26565
26553
|
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
26566
26554
|
},
|
|
26567
26555
|
idx
|
|
26568
26556
|
)),
|
|
26569
|
-
|
|
26557
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26570
26558
|
Menu,
|
|
26571
26559
|
{
|
|
26572
26560
|
position: "bottom-end",
|
|
26573
26561
|
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26574
|
-
items:
|
|
26562
|
+
items: menuCardActions.map((action) => ({
|
|
26575
26563
|
label: action.label,
|
|
26576
26564
|
icon: action.icon,
|
|
26577
|
-
|
|
26565
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
26578
26566
|
onClick: () => fireAction(action, itemData)
|
|
26579
26567
|
}))
|
|
26580
26568
|
}
|
|
26581
|
-
)
|
|
26582
|
-
dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
26583
|
-
Button,
|
|
26584
|
-
{
|
|
26585
|
-
variant: "ghost",
|
|
26586
|
-
size: "sm",
|
|
26587
|
-
onClick: handleActionClick(action, itemData),
|
|
26588
|
-
"data-testid": `action-${action.event}`,
|
|
26589
|
-
"data-row-id": String(itemData.id),
|
|
26590
|
-
"aria-label": action.label,
|
|
26591
|
-
title: action.label,
|
|
26592
|
-
className: "text-error hover:text-error hover:bg-error/10 px-2",
|
|
26593
|
-
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
26594
|
-
},
|
|
26595
|
-
`danger-${idx}`
|
|
26596
|
-
))
|
|
26569
|
+
)
|
|
26597
26570
|
] })
|
|
26598
26571
|
] }) }),
|
|
26599
26572
|
bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
@@ -26835,54 +26808,59 @@ function DataList({
|
|
|
26835
26808
|
if (!itemActions || itemActions.length === 0) return null;
|
|
26836
26809
|
const inline = maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions;
|
|
26837
26810
|
const overflow = maxInlineActions != null ? itemActions.slice(maxInlineActions) : [];
|
|
26838
|
-
return
|
|
26839
|
-
|
|
26840
|
-
|
|
26841
|
-
|
|
26842
|
-
|
|
26843
|
-
|
|
26844
|
-
|
|
26845
|
-
|
|
26846
|
-
|
|
26847
|
-
|
|
26848
|
-
action
|
|
26849
|
-
|
|
26850
|
-
|
|
26851
|
-
|
|
26852
|
-
|
|
26853
|
-
|
|
26854
|
-
|
|
26855
|
-
|
|
26856
|
-
|
|
26857
|
-
|
|
26858
|
-
|
|
26859
|
-
|
|
26860
|
-
|
|
26861
|
-
|
|
26862
|
-
|
|
26863
|
-
|
|
26864
|
-
|
|
26865
|
-
|
|
26866
|
-
|
|
26867
|
-
|
|
26868
|
-
|
|
26869
|
-
|
|
26870
|
-
|
|
26871
|
-
|
|
26872
|
-
|
|
26873
|
-
|
|
26874
|
-
|
|
26875
|
-
|
|
26876
|
-
|
|
26877
|
-
|
|
26811
|
+
return (
|
|
26812
|
+
// stopPropagation at the cluster: the "⋯" trigger opens the overflow
|
|
26813
|
+
// menu without also firing the row's default click (inline buttons
|
|
26814
|
+
// already stop it in handleActionClick; the Menu panel is portaled).
|
|
26815
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", onClick: rowClickEvent ? (e) => e.stopPropagation() : void 0, className: "flex-shrink-0", children: [
|
|
26816
|
+
inline.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26817
|
+
Button,
|
|
26818
|
+
{
|
|
26819
|
+
variant: action.variant ?? "ghost",
|
|
26820
|
+
size: "sm",
|
|
26821
|
+
onClick: handleActionClick(action, itemData),
|
|
26822
|
+
"data-testid": `action-${action.event}`,
|
|
26823
|
+
"data-row-id": String(itemData.id),
|
|
26824
|
+
className: cn(
|
|
26825
|
+
action.variant === "danger" && "text-error hover:bg-error/10",
|
|
26826
|
+
// Must sit on the Button itself: the variant's own text colour
|
|
26827
|
+
// beats an inherited one from the row wrapper.
|
|
26828
|
+
onPrimary && "!text-primary-foreground hover:bg-primary-foreground/15"
|
|
26829
|
+
),
|
|
26830
|
+
children: [
|
|
26831
|
+
action.icon && renderIconInput2(action.icon, { size: "xs", className: "mr-1" }),
|
|
26832
|
+
action.label
|
|
26833
|
+
]
|
|
26834
|
+
},
|
|
26835
|
+
idx
|
|
26836
|
+
)),
|
|
26837
|
+
overflow.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26838
|
+
Menu,
|
|
26839
|
+
{
|
|
26840
|
+
position: "bottom-end",
|
|
26841
|
+
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26842
|
+
items: overflow.map((action) => ({
|
|
26843
|
+
label: action.label,
|
|
26844
|
+
icon: action.icon,
|
|
26845
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
26846
|
+
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
26847
|
+
id: itemData.id,
|
|
26848
|
+
row: itemData
|
|
26849
|
+
})
|
|
26850
|
+
}))
|
|
26851
|
+
}
|
|
26852
|
+
)
|
|
26853
|
+
] })
|
|
26854
|
+
);
|
|
26878
26855
|
};
|
|
26856
|
+
const rowClickEvent = itemClickEvent || itemActions?.find((a) => a.variant !== "danger")?.event;
|
|
26879
26857
|
const handleRowClick = (itemData) => () => {
|
|
26880
|
-
if (!
|
|
26858
|
+
if (!rowClickEvent) return;
|
|
26881
26859
|
const payload = {
|
|
26882
26860
|
id: itemData.id,
|
|
26883
26861
|
row: itemData
|
|
26884
26862
|
};
|
|
26885
|
-
eventBus.emit(`UI:${
|
|
26863
|
+
eventBus.emit(`UI:${rowClickEvent}`, payload);
|
|
26886
26864
|
};
|
|
26887
26865
|
if (isLoading) {
|
|
26888
26866
|
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
|
|
@@ -26930,10 +26908,10 @@ function DataList({
|
|
|
26930
26908
|
{
|
|
26931
26909
|
"data-entity-row": true,
|
|
26932
26910
|
"data-entity-id": id,
|
|
26933
|
-
onClick:
|
|
26911
|
+
onClick: rowClickEvent ? handleRowClick(itemData) : void 0,
|
|
26934
26912
|
className: cn(
|
|
26935
26913
|
"flex px-4 group/rowactions",
|
|
26936
|
-
|
|
26914
|
+
rowClickEvent && "cursor-pointer",
|
|
26937
26915
|
isSent ? "justify-end" : "justify-start"
|
|
26938
26916
|
),
|
|
26939
26917
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -27009,7 +26987,7 @@ function DataList({
|
|
|
27009
26987
|
const id2 = itemData.id || String(index);
|
|
27010
26988
|
const actions = renderItemActions(itemData);
|
|
27011
26989
|
return wrapDnd(
|
|
27012
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick:
|
|
26990
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn("relative group/rowactions", rowClickEvent && "cursor-pointer"), children: [
|
|
27013
26991
|
children(itemData, index),
|
|
27014
26992
|
actions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: [
|
|
27015
26993
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5 [@media(pointer:coarse)]:hidden", children: actions }),
|
|
@@ -27021,7 +26999,6 @@ function DataList({
|
|
|
27021
26999
|
items: (itemActions ?? []).map((action) => ({
|
|
27022
27000
|
label: action.label,
|
|
27023
27001
|
icon: action.icon,
|
|
27024
|
-
event: action.event,
|
|
27025
27002
|
variant: action.variant === "danger" ? "danger" : "default",
|
|
27026
27003
|
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
27027
27004
|
id: itemData.id,
|
|
@@ -27038,7 +27015,7 @@ function DataList({
|
|
|
27038
27015
|
const id = itemData.id || String(index);
|
|
27039
27016
|
const titleValue = getNestedValue(itemData, titleField?.name ?? "");
|
|
27040
27017
|
return wrapDnd(
|
|
27041
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick:
|
|
27018
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn(rowClickEvent && "cursor-pointer"), children: [
|
|
27042
27019
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
27043
27020
|
Box,
|
|
27044
27021
|
{
|
|
@@ -32314,7 +32291,7 @@ var init_MapView = __esm({
|
|
|
32314
32291
|
shadowSize: [41, 41]
|
|
32315
32292
|
});
|
|
32316
32293
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
32317
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback97, useState:
|
|
32294
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback97, useState: useState97 } = React87__namespace.default;
|
|
32318
32295
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
32319
32296
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
32320
32297
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -32359,7 +32336,7 @@ var init_MapView = __esm({
|
|
|
32359
32336
|
showAttribution = true
|
|
32360
32337
|
}) {
|
|
32361
32338
|
const eventBus = useEventBus2();
|
|
32362
|
-
const [clickedPosition, setClickedPosition] =
|
|
32339
|
+
const [clickedPosition, setClickedPosition] = useState97(null);
|
|
32363
32340
|
const handleMapClick = useCallback97((lat, lng) => {
|
|
32364
32341
|
if (showClickedPin) {
|
|
32365
32342
|
setClickedPosition({ lat, lng });
|
|
@@ -36721,741 +36698,775 @@ var init_PositionedCanvas = __esm({
|
|
|
36721
36698
|
PositionedCanvas.displayName = "PositionedCanvas";
|
|
36722
36699
|
}
|
|
36723
36700
|
});
|
|
36724
|
-
function
|
|
36725
|
-
|
|
36726
|
-
|
|
36727
|
-
|
|
36701
|
+
function safeUrl(raw, kinds) {
|
|
36702
|
+
const url = raw.trim();
|
|
36703
|
+
if (url.startsWith("#") || url.startsWith("/")) return url;
|
|
36704
|
+
const lower = url.toLowerCase();
|
|
36705
|
+
for (const kind of kinds) {
|
|
36706
|
+
if (lower.startsWith(kind)) return url;
|
|
36707
|
+
}
|
|
36708
|
+
return null;
|
|
36728
36709
|
}
|
|
36729
|
-
function
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
const
|
|
36733
|
-
|
|
36734
|
-
|
|
36735
|
-
|
|
36736
|
-
|
|
36737
|
-
|
|
36710
|
+
function sanitizeNode(el) {
|
|
36711
|
+
const children = Array.from(el.children);
|
|
36712
|
+
for (const child of children) {
|
|
36713
|
+
const tag = child.tagName.toLowerCase();
|
|
36714
|
+
if (DROP_TAGS.has(tag)) {
|
|
36715
|
+
child.remove();
|
|
36716
|
+
continue;
|
|
36717
|
+
}
|
|
36718
|
+
const allowed = ALLOWED_ATTRS[tag];
|
|
36719
|
+
if (!allowed) {
|
|
36720
|
+
sanitizeNode(child);
|
|
36721
|
+
child.replaceWith(...Array.from(child.childNodes));
|
|
36722
|
+
continue;
|
|
36723
|
+
}
|
|
36724
|
+
for (const attr of Array.from(child.attributes)) {
|
|
36725
|
+
const name = attr.name.toLowerCase();
|
|
36726
|
+
if (!allowed.includes(name)) {
|
|
36727
|
+
child.removeAttribute(attr.name);
|
|
36728
|
+
continue;
|
|
36729
|
+
}
|
|
36730
|
+
if (name === "href") {
|
|
36731
|
+
const url = safeUrl(attr.value, ["http://", "https://", "mailto:"]);
|
|
36732
|
+
if (url === null) child.removeAttribute(attr.name);
|
|
36733
|
+
else child.setAttribute("href", url);
|
|
36734
|
+
}
|
|
36735
|
+
if (name === "src") {
|
|
36736
|
+
const url = safeUrl(attr.value, ["http://", "https://", "data:image/"]);
|
|
36737
|
+
if (url === null) child.remove();
|
|
36738
|
+
else child.setAttribute("src", url);
|
|
36739
|
+
}
|
|
36740
|
+
}
|
|
36741
|
+
sanitizeNode(child);
|
|
36742
|
+
}
|
|
36738
36743
|
}
|
|
36739
|
-
function
|
|
36740
|
-
|
|
36741
|
-
|
|
36742
|
-
|
|
36743
|
-
|
|
36744
|
-
|
|
36745
|
-
|
|
36746
|
-
children: [
|
|
36747
|
-
{ id: nextBlockId("li"), type: "paragraph", content: "" }
|
|
36748
|
-
]
|
|
36749
|
-
};
|
|
36750
|
-
case "image":
|
|
36751
|
-
return {
|
|
36752
|
-
id: nextBlockId(type),
|
|
36753
|
-
type,
|
|
36754
|
-
content: "",
|
|
36755
|
-
metadata: { url: "", caption: "" }
|
|
36756
|
-
};
|
|
36757
|
-
case "code":
|
|
36758
|
-
return {
|
|
36759
|
-
id: nextBlockId(type),
|
|
36760
|
-
type,
|
|
36761
|
-
content: "",
|
|
36762
|
-
metadata: { language: "plaintext" }
|
|
36763
|
-
};
|
|
36764
|
-
case "divider":
|
|
36765
|
-
return { id: nextBlockId(type), type };
|
|
36766
|
-
default:
|
|
36767
|
-
return { id: nextBlockId(type), type, content: "" };
|
|
36744
|
+
function sanitizeRichHtml(html) {
|
|
36745
|
+
if (!html || typeof html !== "string") return "";
|
|
36746
|
+
if (typeof window === "undefined" || typeof DOMParser === "undefined") return "";
|
|
36747
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
36748
|
+
sanitizeNode(doc.body);
|
|
36749
|
+
if (!doc.body.querySelector("img, hr") && (doc.body.textContent ?? "").trim().length === 0) {
|
|
36750
|
+
return "";
|
|
36768
36751
|
}
|
|
36752
|
+
return doc.body.innerHTML.replace(//g, "");
|
|
36769
36753
|
}
|
|
36770
|
-
function
|
|
36771
|
-
|
|
36754
|
+
function htmlIsEmpty(el) {
|
|
36755
|
+
if (el.querySelector("img, hr")) return false;
|
|
36756
|
+
return (el.textContent ?? "").trim().length === 0;
|
|
36772
36757
|
}
|
|
36773
|
-
function
|
|
36774
|
-
|
|
36758
|
+
function closestBlock(node, root) {
|
|
36759
|
+
let cur = node;
|
|
36760
|
+
while (cur && cur !== root) {
|
|
36761
|
+
if (cur instanceof Element && BLOCK_TAGS.has(cur.tagName)) return cur;
|
|
36762
|
+
cur = cur.parentNode;
|
|
36763
|
+
}
|
|
36764
|
+
return null;
|
|
36775
36765
|
}
|
|
36776
|
-
function
|
|
36766
|
+
function RichTextStyles() {
|
|
36767
|
+
return /* @__PURE__ */ jsxRuntime.jsx("style", { children: RICH_TEXT_CSS });
|
|
36768
|
+
}
|
|
36769
|
+
function readToolbarState(root) {
|
|
36770
|
+
const sel = window.getSelection();
|
|
36771
|
+
if (!sel || sel.rangeCount === 0) return IDLE_TOOLBAR;
|
|
36772
|
+
const anchor = sel.anchorNode;
|
|
36773
|
+
if (!anchor || !root.contains(anchor)) return IDLE_TOOLBAR;
|
|
36774
|
+
let block = null;
|
|
36775
|
+
let link = false;
|
|
36776
|
+
let node = anchor;
|
|
36777
|
+
while (node && node !== root) {
|
|
36778
|
+
if (node instanceof Element) {
|
|
36779
|
+
const tag = node.tagName.toLowerCase();
|
|
36780
|
+
if (!block && (tag === "h1" || tag === "h2" || tag === "h3" || tag === "blockquote" || tag === "pre")) {
|
|
36781
|
+
block = tag;
|
|
36782
|
+
}
|
|
36783
|
+
if (tag === "a") link = true;
|
|
36784
|
+
}
|
|
36785
|
+
node = node.parentNode;
|
|
36786
|
+
}
|
|
36777
36787
|
return {
|
|
36778
|
-
|
|
36779
|
-
|
|
36780
|
-
|
|
36781
|
-
|
|
36782
|
-
|
|
36783
|
-
|
|
36784
|
-
|
|
36788
|
+
bold: document.queryCommandState("bold"),
|
|
36789
|
+
italic: document.queryCommandState("italic"),
|
|
36790
|
+
underline: document.queryCommandState("underline"),
|
|
36791
|
+
strikeThrough: document.queryCommandState("strikeThrough"),
|
|
36792
|
+
block,
|
|
36793
|
+
bullets: document.queryCommandState("insertUnorderedList"),
|
|
36794
|
+
numbers: document.queryCommandState("insertOrderedList"),
|
|
36795
|
+
link
|
|
36785
36796
|
};
|
|
36786
36797
|
}
|
|
36787
|
-
function
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36792
|
-
|
|
36793
|
-
|
|
36794
|
-
|
|
36795
|
-
|
|
36796
|
-
|
|
36797
|
-
|
|
36798
|
-
|
|
36798
|
+
function ToolbarButton({ icon: IconCmp, label, active, onExec }) {
|
|
36799
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
36800
|
+
Button,
|
|
36801
|
+
{
|
|
36802
|
+
type: "button",
|
|
36803
|
+
variant: "ghost",
|
|
36804
|
+
size: "sm",
|
|
36805
|
+
"aria-label": label,
|
|
36806
|
+
"aria-pressed": active,
|
|
36807
|
+
title: label,
|
|
36808
|
+
className: cn(
|
|
36809
|
+
"h-8 w-8 p-0 gap-0 justify-center",
|
|
36810
|
+
active && "bg-muted text-foreground"
|
|
36811
|
+
),
|
|
36812
|
+
onMouseDown: (e) => {
|
|
36813
|
+
e.preventDefault();
|
|
36814
|
+
onExec();
|
|
36815
|
+
},
|
|
36816
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(IconCmp, { size: 15 })
|
|
36799
36817
|
}
|
|
36800
|
-
|
|
36801
|
-
|
|
36802
|
-
|
|
36803
|
-
|
|
36804
|
-
|
|
36805
|
-
|
|
36806
|
-
|
|
36807
|
-
|
|
36808
|
-
|
|
36809
|
-
|
|
36810
|
-
|
|
36811
|
-
|
|
36812
|
-
|
|
36813
|
-
|
|
36814
|
-
|
|
36815
|
-
|
|
36816
|
-
|
|
36817
|
-
|
|
36818
|
-
|
|
36819
|
-
|
|
36820
|
-
|
|
36821
|
-
|
|
36822
|
-
|
|
36823
|
-
|
|
36824
|
-
|
|
36825
|
-
|
|
36818
|
+
);
|
|
36819
|
+
}
|
|
36820
|
+
var CHANGE_DEBOUNCE_MS, ALLOWED_ATTRS, DROP_TAGS, MD_BLOCK_PREFIXES, BLOCK_TAGS, MD_INLINE_RULES, RICH_TEXT_CSS, IDLE_TOOLBAR, RichTextEditor;
|
|
36821
|
+
var init_RichTextEditor = __esm({
|
|
36822
|
+
"components/core/molecules/RichTextEditor.tsx"() {
|
|
36823
|
+
"use client";
|
|
36824
|
+
init_cn();
|
|
36825
|
+
init_Box();
|
|
36826
|
+
init_Button();
|
|
36827
|
+
init_useEventBus();
|
|
36828
|
+
CHANGE_DEBOUNCE_MS = 400;
|
|
36829
|
+
ALLOWED_ATTRS = {
|
|
36830
|
+
p: [],
|
|
36831
|
+
h1: [],
|
|
36832
|
+
h2: [],
|
|
36833
|
+
h3: [],
|
|
36834
|
+
h4: [],
|
|
36835
|
+
ul: [],
|
|
36836
|
+
ol: [],
|
|
36837
|
+
li: [],
|
|
36838
|
+
blockquote: [],
|
|
36839
|
+
pre: [],
|
|
36840
|
+
code: [],
|
|
36841
|
+
b: [],
|
|
36842
|
+
strong: [],
|
|
36843
|
+
i: [],
|
|
36844
|
+
em: [],
|
|
36845
|
+
u: [],
|
|
36846
|
+
s: [],
|
|
36847
|
+
strike: [],
|
|
36848
|
+
br: [],
|
|
36849
|
+
hr: [],
|
|
36850
|
+
div: [],
|
|
36851
|
+
span: [],
|
|
36852
|
+
a: ["href"],
|
|
36853
|
+
img: ["src", "alt"]
|
|
36854
|
+
};
|
|
36855
|
+
DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "iframe", "object", "embed", "link", "meta", "form", "input", "button", "textarea", "select"]);
|
|
36856
|
+
MD_BLOCK_PREFIXES = {
|
|
36857
|
+
"#": { kind: "block", tag: "h1" },
|
|
36858
|
+
"##": { kind: "block", tag: "h2" },
|
|
36859
|
+
"###": { kind: "block", tag: "h3" },
|
|
36860
|
+
">": { kind: "block", tag: "blockquote" },
|
|
36861
|
+
"```": { kind: "block", tag: "pre" },
|
|
36862
|
+
"-": { kind: "list", command: "insertUnorderedList" },
|
|
36863
|
+
"*": { kind: "list", command: "insertUnorderedList" },
|
|
36864
|
+
"1.": { kind: "list", command: "insertOrderedList" }
|
|
36865
|
+
};
|
|
36866
|
+
BLOCK_TAGS = /* @__PURE__ */ new Set(["P", "DIV", "LI", "H1", "H2", "H3", "H4", "BLOCKQUOTE", "PRE"]);
|
|
36867
|
+
MD_INLINE_RULES = [
|
|
36868
|
+
{ pattern: /\*\*([^*\n]+)\*\*$/, wrap: "strong" },
|
|
36869
|
+
{ pattern: /(^|[^*])\*([^*\n]+)\*$/, wrap: "em" },
|
|
36870
|
+
{ pattern: /`([^`\n]+)`$/, wrap: "code" }
|
|
36871
|
+
];
|
|
36872
|
+
RICH_TEXT_CSS = `
|
|
36873
|
+
.almadar-rich-text { line-height: 1.7; color: var(--color-foreground); }
|
|
36874
|
+
.almadar-rich-text h1 { font-size: 1.875rem; font-weight: 700; line-height: 1.25; margin: 1.25em 0 0.4em; }
|
|
36875
|
+
.almadar-rich-text h2 { font-size: 1.5rem; font-weight: 650; line-height: 1.3; margin: 1.1em 0 0.4em; }
|
|
36876
|
+
.almadar-rich-text h3 { font-size: 1.25rem; font-weight: 600; line-height: 1.35; margin: 1em 0 0.35em; }
|
|
36877
|
+
.almadar-rich-text h1:first-child, .almadar-rich-text h2:first-child, .almadar-rich-text h3:first-child { margin-top: 0; }
|
|
36878
|
+
.almadar-rich-text p { margin: 0.5em 0; }
|
|
36879
|
+
.almadar-rich-text ul { list-style: disc; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
36880
|
+
.almadar-rich-text ol { list-style: decimal; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
36881
|
+
.almadar-rich-text li { margin: 0.25em 0; }
|
|
36882
|
+
.almadar-rich-text blockquote { border-inline-start: 3px solid var(--color-primary); padding-inline-start: 1rem; font-style: italic; color: var(--color-muted-foreground); margin: 0.75em 0; }
|
|
36883
|
+
.almadar-rich-text pre { background: var(--color-muted); border: 1px solid var(--color-border); border-radius: 0.375rem; padding: 0.75rem 1rem; font-family: ui-monospace, monospace; font-size: 0.875em; white-space: pre-wrap; margin: 0.75em 0; }
|
|
36884
|
+
.almadar-rich-text code { font-family: ui-monospace, monospace; font-size: 0.875em; background: var(--color-muted); border-radius: 0.25rem; padding: 0.1em 0.35em; }
|
|
36885
|
+
.almadar-rich-text pre code { background: transparent; padding: 0; }
|
|
36886
|
+
.almadar-rich-text a { color: var(--color-primary); text-decoration: underline; }
|
|
36887
|
+
.almadar-rich-text hr { border: none; border-top: 1px solid var(--color-border); margin: 1.25em 0; }
|
|
36888
|
+
.almadar-rich-text img { max-width: 100%; border-radius: 0.375rem; }
|
|
36889
|
+
`;
|
|
36890
|
+
IDLE_TOOLBAR = {
|
|
36891
|
+
bold: false,
|
|
36892
|
+
italic: false,
|
|
36893
|
+
underline: false,
|
|
36894
|
+
strikeThrough: false,
|
|
36895
|
+
block: null,
|
|
36896
|
+
bullets: false,
|
|
36897
|
+
numbers: false,
|
|
36898
|
+
link: false
|
|
36899
|
+
};
|
|
36900
|
+
RichTextEditor = ({
|
|
36901
|
+
value,
|
|
36902
|
+
onChange,
|
|
36903
|
+
changeEvent,
|
|
36904
|
+
readOnly = false,
|
|
36905
|
+
placeholder,
|
|
36906
|
+
showToolbar = true,
|
|
36907
|
+
className
|
|
36908
|
+
}) => {
|
|
36909
|
+
const { t } = hooks.useTranslate();
|
|
36910
|
+
const ref = React87.useRef(null);
|
|
36911
|
+
const [toolbar, setToolbar] = React87.useState(IDLE_TOOLBAR);
|
|
36912
|
+
const [empty, setEmpty] = React87.useState(() => !value || !sanitizeRichHtml(value).trim());
|
|
36913
|
+
const eventBus = useEventBus();
|
|
36914
|
+
const onChangeRef = React87.useRef(onChange);
|
|
36915
|
+
const changeEventRef = React87.useRef(changeEvent);
|
|
36916
|
+
React87.useEffect(() => {
|
|
36917
|
+
onChangeRef.current = onChange;
|
|
36918
|
+
changeEventRef.current = changeEvent;
|
|
36919
|
+
}, [onChange, changeEvent]);
|
|
36920
|
+
const emitTimerRef = React87.useRef(null);
|
|
36921
|
+
const emitNow = React87.useCallback(() => {
|
|
36922
|
+
const el = ref.current;
|
|
36923
|
+
if (!el) return;
|
|
36924
|
+
const html = sanitizeRichHtml(el.innerHTML);
|
|
36925
|
+
onChangeRef.current?.(html);
|
|
36926
|
+
const evt = changeEventRef.current;
|
|
36927
|
+
if (evt) eventBus.emit(`UI:${evt}`, { value: html });
|
|
36928
|
+
}, [eventBus]);
|
|
36929
|
+
const scheduleEmit = React87.useCallback(() => {
|
|
36930
|
+
if (emitTimerRef.current) clearTimeout(emitTimerRef.current);
|
|
36931
|
+
emitTimerRef.current = setTimeout(() => {
|
|
36932
|
+
emitTimerRef.current = null;
|
|
36933
|
+
emitNow();
|
|
36934
|
+
}, CHANGE_DEBOUNCE_MS);
|
|
36935
|
+
}, [emitNow]);
|
|
36936
|
+
const flushEmit = React87.useCallback(() => {
|
|
36937
|
+
if (!emitTimerRef.current) return;
|
|
36938
|
+
clearTimeout(emitTimerRef.current);
|
|
36939
|
+
emitTimerRef.current = null;
|
|
36940
|
+
emitNow();
|
|
36941
|
+
}, [emitNow]);
|
|
36942
|
+
React87.useEffect(() => () => {
|
|
36943
|
+
if (emitTimerRef.current) {
|
|
36944
|
+
clearTimeout(emitTimerRef.current);
|
|
36945
|
+
emitTimerRef.current = null;
|
|
36946
|
+
emitNow();
|
|
36947
|
+
}
|
|
36948
|
+
}, [emitNow]);
|
|
36949
|
+
React87.useEffect(() => {
|
|
36950
|
+
if (readOnly) return;
|
|
36951
|
+
const el = ref.current;
|
|
36952
|
+
if (!el) return;
|
|
36953
|
+
if (document.activeElement === el) return;
|
|
36954
|
+
const next = sanitizeRichHtml(value ?? "") || "<p><br></p>";
|
|
36955
|
+
if (el.innerHTML !== next) {
|
|
36956
|
+
el.innerHTML = next;
|
|
36957
|
+
setEmpty(htmlIsEmpty(el));
|
|
36958
|
+
}
|
|
36959
|
+
}, [readOnly, value]);
|
|
36960
|
+
React87.useEffect(() => {
|
|
36961
|
+
if (readOnly) return;
|
|
36962
|
+
document.execCommand("defaultParagraphSeparator", false, "p");
|
|
36963
|
+
}, [readOnly]);
|
|
36964
|
+
React87.useEffect(() => {
|
|
36965
|
+
if (readOnly || !showToolbar) return;
|
|
36966
|
+
const onSelectionChange = () => {
|
|
36967
|
+
const el = ref.current;
|
|
36968
|
+
if (!el) return;
|
|
36969
|
+
setToolbar(readToolbarState(el));
|
|
36970
|
+
};
|
|
36971
|
+
document.addEventListener("selectionchange", onSelectionChange);
|
|
36972
|
+
return () => document.removeEventListener("selectionchange", onSelectionChange);
|
|
36973
|
+
}, [readOnly, showToolbar]);
|
|
36974
|
+
const tryInlineMarkdown = React87.useCallback(() => {
|
|
36975
|
+
const root = ref.current;
|
|
36976
|
+
if (!root) return false;
|
|
36977
|
+
const sel = window.getSelection();
|
|
36978
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
36979
|
+
const node = sel.anchorNode;
|
|
36980
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
36981
|
+
if (node.parentElement?.closest("code, pre")) return false;
|
|
36982
|
+
const text = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
36983
|
+
for (const rule of MD_INLINE_RULES) {
|
|
36984
|
+
const m = rule.pattern.exec(text);
|
|
36985
|
+
if (!m) continue;
|
|
36986
|
+
const inner = rule.wrap === "em" ? m[2] : m[1];
|
|
36987
|
+
if (!inner || !inner.trim()) continue;
|
|
36988
|
+
const lead = rule.wrap === "em" ? m[1]?.length ?? 0 : 0;
|
|
36989
|
+
const range = document.createRange();
|
|
36990
|
+
range.setStart(node, m.index + lead);
|
|
36991
|
+
range.setEnd(node, sel.anchorOffset);
|
|
36992
|
+
const el = document.createElement(rule.wrap);
|
|
36993
|
+
el.textContent = inner;
|
|
36994
|
+
range.deleteContents();
|
|
36995
|
+
range.insertNode(el);
|
|
36996
|
+
const after = document.createTextNode("\u200B");
|
|
36997
|
+
el.parentNode?.insertBefore(after, el.nextSibling);
|
|
36998
|
+
const caret = document.createRange();
|
|
36999
|
+
caret.setStart(after, 1);
|
|
37000
|
+
caret.collapse(true);
|
|
37001
|
+
sel.removeAllRanges();
|
|
37002
|
+
sel.addRange(caret);
|
|
37003
|
+
return true;
|
|
37004
|
+
}
|
|
37005
|
+
return false;
|
|
37006
|
+
}, []);
|
|
37007
|
+
const tryBlockMarkdown = React87.useCallback(() => {
|
|
37008
|
+
const root = ref.current;
|
|
37009
|
+
if (!root) return false;
|
|
37010
|
+
const sel = window.getSelection();
|
|
37011
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
37012
|
+
const node = sel.anchorNode;
|
|
37013
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
37014
|
+
const block = closestBlock(node, root);
|
|
37015
|
+
if (block ? block.firstChild !== node : root.firstChild !== node) return false;
|
|
37016
|
+
const prefix = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
37017
|
+
const rule = MD_BLOCK_PREFIXES[prefix];
|
|
37018
|
+
if (!rule) return false;
|
|
37019
|
+
if (node.parentElement?.closest("pre, code")) return false;
|
|
37020
|
+
if (rule.kind === "list" && node.parentElement?.closest("li")) return false;
|
|
37021
|
+
node.deleteData(0, prefix.length);
|
|
37022
|
+
const caret = document.createRange();
|
|
37023
|
+
caret.setStart(node, 0);
|
|
37024
|
+
caret.collapse(true);
|
|
37025
|
+
sel.removeAllRanges();
|
|
37026
|
+
sel.addRange(caret);
|
|
37027
|
+
if (rule.kind === "list") {
|
|
37028
|
+
const container = block ?? node.parentElement;
|
|
37029
|
+
const list = document.createElement(rule.command === "insertOrderedList" ? "ol" : "ul");
|
|
37030
|
+
const li = document.createElement("li");
|
|
37031
|
+
if (block) {
|
|
37032
|
+
while (block.firstChild) li.appendChild(block.firstChild);
|
|
37033
|
+
list.appendChild(li);
|
|
37034
|
+
block.replaceWith(list);
|
|
37035
|
+
} else if (container) {
|
|
37036
|
+
li.appendChild(node);
|
|
37037
|
+
list.appendChild(li);
|
|
37038
|
+
container.appendChild(list);
|
|
37039
|
+
}
|
|
37040
|
+
if (!li.firstChild) li.appendChild(document.createElement("br"));
|
|
37041
|
+
const liCaret = document.createRange();
|
|
37042
|
+
liCaret.selectNodeContents(li);
|
|
37043
|
+
liCaret.collapse(true);
|
|
37044
|
+
sel.removeAllRanges();
|
|
37045
|
+
sel.addRange(liCaret);
|
|
37046
|
+
} else {
|
|
37047
|
+
document.execCommand("formatBlock", false, rule.tag);
|
|
37048
|
+
}
|
|
37049
|
+
return true;
|
|
37050
|
+
}, []);
|
|
37051
|
+
const afterEdit = React87.useCallback(() => {
|
|
37052
|
+
const el = ref.current;
|
|
37053
|
+
if (!el) return;
|
|
37054
|
+
tryInlineMarkdown();
|
|
37055
|
+
setEmpty(htmlIsEmpty(el));
|
|
37056
|
+
setToolbar(readToolbarState(el));
|
|
37057
|
+
scheduleEmit();
|
|
37058
|
+
}, [scheduleEmit, tryInlineMarkdown]);
|
|
37059
|
+
const handleKeyDown = React87.useCallback((e) => {
|
|
37060
|
+
if (e.key === " " && tryBlockMarkdown()) {
|
|
37061
|
+
e.preventDefault();
|
|
37062
|
+
afterEdit();
|
|
37063
|
+
}
|
|
37064
|
+
}, [afterEdit, tryBlockMarkdown]);
|
|
37065
|
+
const execInline = React87.useCallback((command) => {
|
|
37066
|
+
document.execCommand(command, false);
|
|
37067
|
+
afterEdit();
|
|
37068
|
+
}, [afterEdit]);
|
|
37069
|
+
const execBlock = React87.useCallback((tag) => {
|
|
37070
|
+
const next = toolbar.block === tag ? "p" : tag;
|
|
37071
|
+
document.execCommand("formatBlock", false, next);
|
|
37072
|
+
afterEdit();
|
|
37073
|
+
}, [afterEdit, toolbar.block]);
|
|
37074
|
+
const execList = React87.useCallback((command) => {
|
|
37075
|
+
document.execCommand(command, false);
|
|
37076
|
+
afterEdit();
|
|
37077
|
+
}, [afterEdit]);
|
|
37078
|
+
const execLink = React87.useCallback(() => {
|
|
37079
|
+
if (toolbar.link) {
|
|
37080
|
+
document.execCommand("unlink", false);
|
|
37081
|
+
afterEdit();
|
|
37082
|
+
return;
|
|
37083
|
+
}
|
|
37084
|
+
const url = window.prompt(t("richTextEditor.linkPrompt"));
|
|
37085
|
+
if (!url) return;
|
|
37086
|
+
const safe = safeUrl(url, ["http://", "https://", "mailto:"]) ?? `https://${url}`;
|
|
37087
|
+
document.execCommand("createLink", false, safe);
|
|
37088
|
+
afterEdit();
|
|
37089
|
+
}, [afterEdit, t, toolbar.link]);
|
|
37090
|
+
const execRule = React87.useCallback(() => {
|
|
37091
|
+
document.execCommand("insertHorizontalRule", false);
|
|
37092
|
+
afterEdit();
|
|
37093
|
+
}, [afterEdit]);
|
|
37094
|
+
if (readOnly) {
|
|
37095
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("almadar-rich-text max-w-none", className), children: [
|
|
37096
|
+
/* @__PURE__ */ jsxRuntime.jsx(RichTextStyles, {}),
|
|
37097
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { dangerouslySetInnerHTML: { __html: sanitizeRichHtml(value ?? "") } })
|
|
37098
|
+
] });
|
|
37099
|
+
}
|
|
37100
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
|
|
37101
|
+
/* @__PURE__ */ jsxRuntime.jsx(RichTextStyles, {}),
|
|
37102
|
+
showToolbar && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37103
|
+
Box,
|
|
37104
|
+
{
|
|
37105
|
+
role: "toolbar",
|
|
37106
|
+
"aria-label": t("richTextEditor.editorToolbar"),
|
|
37107
|
+
className: cn(
|
|
37108
|
+
"sticky top-0 z-10 flex flex-wrap items-center gap-0.5 self-start",
|
|
37109
|
+
"rounded-md border border-border bg-background/95 px-1 py-0.5 shadow-sm"
|
|
37110
|
+
),
|
|
37111
|
+
children: [
|
|
37112
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Bold, label: t("richTextEditor.bold"), active: toolbar.bold, onExec: () => execInline("bold") }),
|
|
37113
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Italic, label: t("richTextEditor.italic"), active: toolbar.italic, onExec: () => execInline("italic") }),
|
|
37114
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Underline, label: t("richTextEditor.underline"), active: toolbar.underline, onExec: () => execInline("underline") }),
|
|
37115
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Strikethrough, label: t("richTextEditor.strikethrough"), active: toolbar.strikeThrough, onExec: () => execInline("strikeThrough") }),
|
|
37116
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
37117
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Heading1, label: t("richTextEditor.heading1"), active: toolbar.block === "h1", onExec: () => execBlock("h1") }),
|
|
37118
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Heading2, label: t("richTextEditor.heading2"), active: toolbar.block === "h2", onExec: () => execBlock("h2") }),
|
|
37119
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Heading3, label: t("richTextEditor.heading3"), active: toolbar.block === "h3", onExec: () => execBlock("h3") }),
|
|
37120
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
37121
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.List, label: t("richTextEditor.bulletList"), active: toolbar.bullets, onExec: () => execList("insertUnorderedList") }),
|
|
37122
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.ListOrdered, label: t("richTextEditor.numberedList"), active: toolbar.numbers, onExec: () => execList("insertOrderedList") }),
|
|
37123
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
37124
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Quote, label: t("richTextEditor.quote"), active: toolbar.block === "blockquote", onExec: () => execBlock("blockquote") }),
|
|
37125
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Code, label: t("richTextEditor.code"), active: toolbar.block === "pre", onExec: () => execBlock("pre") }),
|
|
37126
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Link, label: toolbar.link ? t("richTextEditor.removeLink") : t("richTextEditor.link"), active: toolbar.link, onExec: execLink }),
|
|
37127
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { icon: LucideIcons2.Minus, label: t("richTextEditor.divider"), onExec: execRule })
|
|
37128
|
+
]
|
|
37129
|
+
}
|
|
37130
|
+
),
|
|
37131
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37132
|
+
Box,
|
|
37133
|
+
{
|
|
37134
|
+
ref,
|
|
37135
|
+
contentEditable: true,
|
|
37136
|
+
suppressContentEditableWarning: true,
|
|
37137
|
+
role: "textbox",
|
|
37138
|
+
"aria-multiline": "true",
|
|
37139
|
+
"aria-label": t("richTextEditor.editorSurface"),
|
|
37140
|
+
"data-placeholder": placeholder ?? t("richTextEditor.placeholder"),
|
|
37141
|
+
"data-empty": empty ? "true" : "false",
|
|
37142
|
+
className: cn(
|
|
37143
|
+
"almadar-rich-text max-w-none min-h-[8rem] outline-none",
|
|
37144
|
+
"data-[empty=true]:before:content-[attr(data-placeholder)]",
|
|
37145
|
+
"data-[empty=true]:before:text-muted-foreground/60",
|
|
37146
|
+
"data-[empty=true]:before:pointer-events-none",
|
|
37147
|
+
"data-[empty=true]:before:absolute",
|
|
37148
|
+
"relative cursor-text"
|
|
37149
|
+
),
|
|
37150
|
+
onInput: afterEdit,
|
|
37151
|
+
onKeyDown: handleKeyDown,
|
|
37152
|
+
onBlur: flushEmit
|
|
37153
|
+
}
|
|
37154
|
+
)
|
|
37155
|
+
] });
|
|
36826
37156
|
};
|
|
37157
|
+
RichTextEditor.displayName = "RichTextEditor";
|
|
36827
37158
|
}
|
|
36828
|
-
|
|
36829
|
-
|
|
37159
|
+
});
|
|
37160
|
+
function renderIconInput4(icon, props) {
|
|
37161
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, ...props });
|
|
36830
37162
|
}
|
|
36831
|
-
function
|
|
37163
|
+
function DocumentPanel({
|
|
37164
|
+
entity,
|
|
37165
|
+
title,
|
|
37166
|
+
subtitle,
|
|
37167
|
+
value,
|
|
37168
|
+
actions,
|
|
37169
|
+
maxInlineActions,
|
|
37170
|
+
editing = false,
|
|
37171
|
+
titleCommitEvent,
|
|
37172
|
+
contentChangeEvent,
|
|
37173
|
+
editEvent,
|
|
37174
|
+
doneEvent,
|
|
37175
|
+
editLabel,
|
|
37176
|
+
doneLabel,
|
|
37177
|
+
autosaveHint,
|
|
37178
|
+
placeholder,
|
|
37179
|
+
className
|
|
37180
|
+
}) {
|
|
37181
|
+
const eventBus = useEventBus();
|
|
36832
37182
|
const { t } = hooks.useTranslate();
|
|
36833
|
-
const [
|
|
36834
|
-
const
|
|
36835
|
-
|
|
36836
|
-
|
|
36837
|
-
|
|
36838
|
-
|
|
36839
|
-
|
|
36840
|
-
|
|
37183
|
+
const [titleDraft, setTitleDraft] = React87.useState(null);
|
|
37184
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
37185
|
+
const actionDefs = actions ?? [];
|
|
37186
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
37187
|
+
const inlineActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
37188
|
+
const menuActions = actionDefs.filter((a) => !inlineActions.includes(a));
|
|
37189
|
+
const fireAction = (action) => {
|
|
37190
|
+
if (!action.event) return;
|
|
37191
|
+
eventBus.emit(`UI:${action.event}`, { id: recordId, row: entity });
|
|
37192
|
+
};
|
|
37193
|
+
const commitTitle = () => {
|
|
37194
|
+
if (!titleCommitEvent) return;
|
|
37195
|
+
const next = (titleDraft ?? "").trim();
|
|
37196
|
+
setTitleDraft(null);
|
|
37197
|
+
if (!next || next === title) return;
|
|
37198
|
+
eventBus.emit(`UI:${titleCommitEvent}`, { title: next, id: recordId });
|
|
37199
|
+
};
|
|
37200
|
+
const untitled = t("documentPanel.untitled") || "Untitled";
|
|
37201
|
+
const titleNode = titleCommitEvent && titleDraft !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
37202
|
+
Input,
|
|
37203
|
+
{
|
|
37204
|
+
value: titleDraft,
|
|
37205
|
+
autoFocus: true,
|
|
37206
|
+
"aria-label": t("common.title"),
|
|
37207
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
37208
|
+
onFocus: (e) => e.currentTarget.select(),
|
|
37209
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
37210
|
+
onBlur: commitTitle,
|
|
37211
|
+
onKeyDown: (e) => {
|
|
37212
|
+
if (e.key === "Enter") {
|
|
37213
|
+
e.preventDefault();
|
|
37214
|
+
commitTitle();
|
|
37215
|
+
} else if (e.key === "Escape") {
|
|
37216
|
+
e.preventDefault();
|
|
37217
|
+
setTitleDraft(null);
|
|
37218
|
+
}
|
|
37219
|
+
},
|
|
37220
|
+
"data-testid": "document-title-input"
|
|
36841
37221
|
}
|
|
36842
|
-
|
|
36843
|
-
|
|
36844
|
-
|
|
36845
|
-
|
|
36846
|
-
|
|
36847
|
-
|
|
36848
|
-
|
|
36849
|
-
{
|
|
36850
|
-
|
|
36851
|
-
|
|
36852
|
-
|
|
36853
|
-
|
|
36854
|
-
|
|
36855
|
-
|
|
36856
|
-
|
|
36857
|
-
|
|
36858
|
-
|
|
36859
|
-
|
|
36860
|
-
|
|
36861
|
-
|
|
36862
|
-
|
|
36863
|
-
|
|
36864
|
-
|
|
37222
|
+
) : titleCommitEvent ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
37223
|
+
Box,
|
|
37224
|
+
{
|
|
37225
|
+
role: "button",
|
|
37226
|
+
tabIndex: 0,
|
|
37227
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
37228
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
37229
|
+
onKeyDown: (e) => {
|
|
37230
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
37231
|
+
e.preventDefault();
|
|
37232
|
+
setTitleDraft(title ?? "");
|
|
37233
|
+
}
|
|
37234
|
+
},
|
|
37235
|
+
"data-testid": "document-title-editable",
|
|
37236
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", className: cn(!title && "text-muted-foreground"), children: title || untitled })
|
|
37237
|
+
}
|
|
37238
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || untitled });
|
|
37239
|
+
const emitWithId = (event) => () => {
|
|
37240
|
+
if (event) eventBus.emit(`UI:${event}`, { id: recordId });
|
|
37241
|
+
};
|
|
37242
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { variant: "elevated", className: cn("w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: "p-6 sm:p-8", children: [
|
|
37243
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
37244
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
37245
|
+
titleNode,
|
|
37246
|
+
subtitle ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: subtitle }) : null
|
|
37247
|
+
] }),
|
|
37248
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-shrink-0 pt-1 items-center", children: editing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
37249
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", className: "hidden sm:block", children: autosaveHint ?? (t("documentPanel.autosaveHint") || "") }),
|
|
37250
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", size: "sm", onClick: emitWithId(doneEvent), "data-testid": "document-done", children: doneLabel ?? (t("documentPanel.done") || "Done") })
|
|
37251
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
37252
|
+
editEvent && /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", onClick: emitWithId(editEvent), "data-testid": "document-edit", children: [
|
|
37253
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "edit", size: "xs", className: "mr-1" }),
|
|
37254
|
+
editLabel ?? (t("documentPanel.edit") || "Edit")
|
|
37255
|
+
] }),
|
|
37256
|
+
inlineActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37257
|
+
Button,
|
|
37258
|
+
{
|
|
37259
|
+
variant: "primary",
|
|
37260
|
+
size: "sm",
|
|
37261
|
+
onClick: () => fireAction(action),
|
|
37262
|
+
"data-testid": `action-${action.event}`,
|
|
37263
|
+
children: [
|
|
37264
|
+
action.icon && renderIconInput4(action.icon, { size: "xs", className: "mr-1" }),
|
|
37265
|
+
action.label
|
|
37266
|
+
]
|
|
37267
|
+
},
|
|
37268
|
+
idx
|
|
37269
|
+
)),
|
|
37270
|
+
menuActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
37271
|
+
Menu,
|
|
37272
|
+
{
|
|
37273
|
+
position: "bottom-end",
|
|
37274
|
+
trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
37275
|
+
items: menuActions.map((action) => ({
|
|
37276
|
+
label: action.label,
|
|
37277
|
+
icon: action.icon,
|
|
37278
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
37279
|
+
onClick: () => fireAction(action)
|
|
37280
|
+
}))
|
|
37281
|
+
}
|
|
37282
|
+
)
|
|
37283
|
+
] }) })
|
|
37284
|
+
] }),
|
|
37285
|
+
editing ? /* @__PURE__ */ jsxRuntime.jsx(RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
36865
37286
|
Box,
|
|
36866
37287
|
{
|
|
36867
|
-
|
|
37288
|
+
onClick: emitWithId(editEvent),
|
|
36868
37289
|
className: cn(
|
|
36869
|
-
"
|
|
36870
|
-
"
|
|
36871
|
-
"py-1 text-sm"
|
|
37290
|
+
"rounded-md px-1 -mx-1 min-h-[16rem]",
|
|
37291
|
+
editEvent && "cursor-text transition-colors hover:bg-muted/30"
|
|
36872
37292
|
),
|
|
36873
|
-
|
|
36874
|
-
|
|
36875
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
36876
|
-
Button,
|
|
36877
|
-
{
|
|
36878
|
-
type: "button",
|
|
36879
|
-
variant: "ghost",
|
|
36880
|
-
role: "menuitem",
|
|
36881
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
36882
|
-
onClick: () => {
|
|
36883
|
-
onDuplicate();
|
|
36884
|
-
setOpen(false);
|
|
36885
|
-
},
|
|
36886
|
-
children: [
|
|
36887
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "w-3.5 h-3.5" }),
|
|
36888
|
-
" ",
|
|
36889
|
-
t("richBlockEditor.duplicate")
|
|
36890
|
-
]
|
|
36891
|
-
}
|
|
36892
|
-
),
|
|
36893
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
36894
|
-
Button,
|
|
36895
|
-
{
|
|
36896
|
-
type: "button",
|
|
36897
|
-
variant: "ghost",
|
|
36898
|
-
role: "menuitem",
|
|
36899
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-destructive hover:bg-muted justify-start rounded-none",
|
|
36900
|
-
onClick: () => {
|
|
36901
|
-
onDelete();
|
|
36902
|
-
setOpen(false);
|
|
36903
|
-
},
|
|
36904
|
-
children: [
|
|
36905
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "trash", className: "w-3.5 h-3.5" }),
|
|
36906
|
-
" ",
|
|
36907
|
-
t("common.delete")
|
|
36908
|
-
]
|
|
36909
|
-
}
|
|
36910
|
-
),
|
|
36911
|
-
CHANGEABLE_TYPES.includes(block.type) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
36912
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "my-1 border-t border-border" }),
|
|
36913
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t("richBlockEditor.turnInto") }),
|
|
36914
|
-
CHANGEABLE_TYPES.filter((bt) => bt !== block.type).map((bt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
36915
|
-
Button,
|
|
36916
|
-
{
|
|
36917
|
-
type: "button",
|
|
36918
|
-
variant: "ghost",
|
|
36919
|
-
role: "menuitem",
|
|
36920
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
36921
|
-
onClick: () => {
|
|
36922
|
-
onChangeType(bt);
|
|
36923
|
-
setOpen(false);
|
|
36924
|
-
},
|
|
36925
|
-
children: t(BLOCK_TYPE_LABEL_KEY[bt])
|
|
36926
|
-
},
|
|
36927
|
-
bt
|
|
36928
|
-
))
|
|
36929
|
-
] })
|
|
36930
|
-
]
|
|
37293
|
+
"data-testid": "document-body",
|
|
37294
|
+
children: value && value !== "" ? /* @__PURE__ */ jsxRuntime.jsx(RichTextEditor, { value, readOnly: true }) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "muted", children: placeholder ?? (t("documentPanel.placeholder") || "") })
|
|
36931
37295
|
}
|
|
36932
37296
|
)
|
|
36933
|
-
] });
|
|
37297
|
+
] }) });
|
|
36934
37298
|
}
|
|
36935
|
-
|
|
36936
|
-
|
|
36937
|
-
|
|
36938
|
-
|
|
36939
|
-
|
|
36940
|
-
|
|
36941
|
-
|
|
36942
|
-
|
|
36943
|
-
|
|
36944
|
-
|
|
36945
|
-
|
|
36946
|
-
|
|
36947
|
-
|
|
36948
|
-
|
|
36949
|
-
|
|
36950
|
-
|
|
36951
|
-
|
|
36952
|
-
},
|
|
36953
|
-
const handleInput = React87.useCallback(
|
|
36954
|
-
(e) => {
|
|
36955
|
-
onValueChange(e.currentTarget.textContent ?? "");
|
|
36956
|
-
},
|
|
36957
|
-
[onValueChange]
|
|
36958
|
-
);
|
|
36959
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
36960
|
-
Box,
|
|
36961
|
-
{
|
|
36962
|
-
as: tag,
|
|
36963
|
-
ref,
|
|
36964
|
-
contentEditable: !readOnly,
|
|
36965
|
-
suppressContentEditableWarning: true,
|
|
36966
|
-
role: readOnly ? void 0 : "textbox",
|
|
36967
|
-
"aria-label": ariaLabel,
|
|
36968
|
-
"aria-multiline": "true",
|
|
36969
|
-
"data-placeholder": placeholder,
|
|
36970
|
-
className: cn(
|
|
36971
|
-
"outline-none focus-visible:ring-1 focus-visible:ring-ring rounded-sm",
|
|
36972
|
-
"empty:before:content-[attr(data-placeholder)] empty:before:text-muted-foreground/60",
|
|
36973
|
-
className
|
|
36974
|
-
),
|
|
36975
|
-
onInput: handleInput
|
|
36976
|
-
}
|
|
36977
|
-
);
|
|
37299
|
+
var init_DocumentPanel = __esm({
|
|
37300
|
+
"components/core/molecules/DocumentPanel.tsx"() {
|
|
37301
|
+
"use client";
|
|
37302
|
+
init_cn();
|
|
37303
|
+
init_useEventBus();
|
|
37304
|
+
init_Box();
|
|
37305
|
+
init_Stack();
|
|
37306
|
+
init_Typography();
|
|
37307
|
+
init_Button();
|
|
37308
|
+
init_Card();
|
|
37309
|
+
init_Icon();
|
|
37310
|
+
init_Input();
|
|
37311
|
+
init_Menu();
|
|
37312
|
+
init_RichTextEditor();
|
|
37313
|
+
}
|
|
37314
|
+
});
|
|
37315
|
+
function renderIconInput5(icon, props) {
|
|
37316
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, ...props });
|
|
36978
37317
|
}
|
|
36979
|
-
function
|
|
36980
|
-
|
|
36981
|
-
|
|
36982
|
-
|
|
36983
|
-
|
|
36984
|
-
|
|
36985
|
-
|
|
36986
|
-
|
|
36987
|
-
|
|
37318
|
+
function fieldName(field) {
|
|
37319
|
+
return field.name ?? field.key ?? "";
|
|
37320
|
+
}
|
|
37321
|
+
function relationLabel(value) {
|
|
37322
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) return null;
|
|
37323
|
+
for (const key of ["name", "title", "label"]) {
|
|
37324
|
+
const candidate = value[key];
|
|
37325
|
+
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
37326
|
+
}
|
|
37327
|
+
const id = value.id;
|
|
37328
|
+
return id !== void 0 && id !== null ? String(id) : null;
|
|
37329
|
+
}
|
|
37330
|
+
function fieldKind(field, value) {
|
|
37331
|
+
if (field.kind) return field.kind;
|
|
37332
|
+
if (field.options && field.options.length > 0) return "select";
|
|
37333
|
+
if (typeof value === "boolean" || field.format === "boolean") return "boolean";
|
|
37334
|
+
if (Array.isArray(value) || relationLabel(value ?? null) !== null) return "readonly";
|
|
37335
|
+
return "text";
|
|
37336
|
+
}
|
|
37337
|
+
function DocumentDetails({
|
|
37338
|
+
entity,
|
|
37339
|
+
fields,
|
|
37340
|
+
metaCommitEvent,
|
|
37341
|
+
title,
|
|
37342
|
+
className
|
|
36988
37343
|
}) {
|
|
37344
|
+
const eventBus = useEventBus();
|
|
36989
37345
|
const { t } = hooks.useTranslate();
|
|
36990
|
-
const
|
|
36991
|
-
|
|
36992
|
-
|
|
36993
|
-
);
|
|
36994
|
-
const
|
|
36995
|
-
(
|
|
36996
|
-
|
|
36997
|
-
|
|
36998
|
-
|
|
36999
|
-
|
|
37000
|
-
|
|
37001
|
-
|
|
37002
|
-
|
|
37003
|
-
|
|
37004
|
-
|
|
37005
|
-
|
|
37006
|
-
|
|
37007
|
-
|
|
37008
|
-
|
|
37009
|
-
|
|
37010
|
-
|
|
37011
|
-
|
|
37012
|
-
|
|
37013
|
-
|
|
37014
|
-
|
|
37015
|
-
|
|
37016
|
-
|
|
37017
|
-
|
|
37018
|
-
|
|
37019
|
-
|
|
37020
|
-
|
|
37021
|
-
|
|
37022
|
-
|
|
37023
|
-
|
|
37024
|
-
|
|
37025
|
-
|
|
37026
|
-
|
|
37027
|
-
}
|
|
37028
|
-
|
|
37029
|
-
|
|
37030
|
-
|
|
37031
|
-
|
|
37032
|
-
|
|
37033
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37034
|
-
Editable,
|
|
37035
|
-
{
|
|
37036
|
-
tag: "h1",
|
|
37037
|
-
value: block.content ?? "",
|
|
37038
|
-
readOnly,
|
|
37039
|
-
placeholder: placeholder ?? t("richBlockEditor.placeholder.heading1"),
|
|
37040
|
-
ariaLabel: t("richBlockEditor.aria.heading1Block"),
|
|
37041
|
-
className: "text-3xl font-bold leading-tight",
|
|
37042
|
-
onValueChange: setContent
|
|
37043
|
-
}
|
|
37044
|
-
);
|
|
37045
|
-
case "heading-2":
|
|
37046
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37047
|
-
Editable,
|
|
37048
|
-
{
|
|
37049
|
-
tag: "h2",
|
|
37050
|
-
value: block.content ?? "",
|
|
37051
|
-
readOnly,
|
|
37052
|
-
placeholder: placeholder ?? t("richBlockEditor.placeholder.heading2"),
|
|
37053
|
-
ariaLabel: t("richBlockEditor.aria.heading2Block"),
|
|
37054
|
-
className: "text-2xl font-semibold leading-tight",
|
|
37055
|
-
onValueChange: setContent
|
|
37056
|
-
}
|
|
37057
|
-
);
|
|
37058
|
-
case "heading-3":
|
|
37059
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37060
|
-
Editable,
|
|
37061
|
-
{
|
|
37062
|
-
tag: "h3",
|
|
37063
|
-
value: block.content ?? "",
|
|
37064
|
-
readOnly,
|
|
37065
|
-
placeholder: placeholder ?? t("richBlockEditor.placeholder.heading3"),
|
|
37066
|
-
ariaLabel: t("richBlockEditor.aria.heading3Block"),
|
|
37067
|
-
className: "text-xl font-semibold leading-tight",
|
|
37068
|
-
onValueChange: setContent
|
|
37069
|
-
}
|
|
37070
|
-
);
|
|
37071
|
-
case "quote":
|
|
37072
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37073
|
-
Editable,
|
|
37074
|
-
{
|
|
37075
|
-
tag: "blockquote",
|
|
37076
|
-
value: block.content ?? "",
|
|
37077
|
-
readOnly,
|
|
37078
|
-
placeholder: placeholder ?? t("richBlockEditor.placeholder.quote"),
|
|
37079
|
-
ariaLabel: t("richBlockEditor.aria.quoteBlock"),
|
|
37080
|
-
className: "border-l-4 border-primary/60 pl-4 italic text-muted-foreground",
|
|
37081
|
-
onValueChange: setContent
|
|
37082
|
-
}
|
|
37083
|
-
);
|
|
37084
|
-
case "code":
|
|
37085
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "rounded-md border border-border bg-muted/40", children: [
|
|
37086
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between border-b border-border px-3 py-1 text-xs text-muted-foreground", children: [
|
|
37087
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", variant: "caption", className: "uppercase tracking-wide", children: t("richBlockEditor.blockType.code") }),
|
|
37088
|
-
!readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
37089
|
-
Input,
|
|
37090
|
-
{
|
|
37091
|
-
inputType: "text",
|
|
37092
|
-
value: String(block.metadata?.language ?? "plaintext"),
|
|
37093
|
-
"aria-label": t("richBlockEditor.aria.codeLanguage"),
|
|
37094
|
-
className: cn(
|
|
37095
|
-
"h-6 w-32 rounded-sm border border-border bg-background",
|
|
37096
|
-
"px-2 text-xs outline-none focus:ring-1 focus:ring-ring"
|
|
37097
|
-
),
|
|
37098
|
-
onChange: (e) => setMetadata("language", e.target.value)
|
|
37099
|
-
}
|
|
37100
|
-
),
|
|
37101
|
-
readOnly && /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", variant: "caption", className: "text-xs", children: String(block.metadata?.language ?? "plaintext") })
|
|
37102
|
-
] }),
|
|
37103
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37104
|
-
Editable,
|
|
37105
|
-
{
|
|
37106
|
-
tag: "pre",
|
|
37107
|
-
value: block.content ?? "",
|
|
37108
|
-
readOnly,
|
|
37109
|
-
placeholder: placeholder ?? t("richBlockEditor.placeholder.code"),
|
|
37110
|
-
ariaLabel: t("richBlockEditor.aria.codeBlock"),
|
|
37111
|
-
className: "block whitespace-pre-wrap p-3 font-mono text-sm leading-relaxed",
|
|
37112
|
-
onValueChange: setContent
|
|
37113
|
-
}
|
|
37114
|
-
)
|
|
37115
|
-
] });
|
|
37116
|
-
case "divider":
|
|
37117
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Divider, { className: "my-2" });
|
|
37118
|
-
case "image": {
|
|
37119
|
-
const url = String(block.metadata?.url ?? "");
|
|
37120
|
-
const caption = String(block.metadata?.caption ?? "");
|
|
37121
|
-
const imgProps = {
|
|
37122
|
-
src: url,
|
|
37123
|
-
alt: caption || t("richBlockEditor.embeddedImage"),
|
|
37124
|
-
className: "max-h-96 w-full rounded-md border border-border object-contain"
|
|
37125
|
-
};
|
|
37126
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "space-y-2", children: [
|
|
37127
|
-
url ? /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "img", ...imgProps }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37128
|
-
Box,
|
|
37129
|
-
{
|
|
37130
|
-
className: cn(
|
|
37131
|
-
"flex h-32 items-center justify-center",
|
|
37132
|
-
"rounded-md border border-dashed border-border",
|
|
37133
|
-
"text-sm text-muted-foreground"
|
|
37134
|
-
),
|
|
37135
|
-
children: [
|
|
37136
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "image", className: "mr-2 w-4 h-4" }),
|
|
37137
|
-
" ",
|
|
37138
|
-
t("richBlockEditor.noImageUrl")
|
|
37139
|
-
]
|
|
37140
|
-
}
|
|
37141
|
-
),
|
|
37142
|
-
!readOnly && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col gap-2 sm:flex-row", children: [
|
|
37143
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37144
|
-
Input,
|
|
37145
|
-
{
|
|
37146
|
-
inputType: "url",
|
|
37147
|
-
value: url,
|
|
37148
|
-
placeholder: "https://example.com/image.png",
|
|
37149
|
-
"aria-label": t("richBlockEditor.aria.imageUrl"),
|
|
37150
|
-
className: cn(
|
|
37151
|
-
"h-8 flex-1 rounded-sm border border-border bg-background",
|
|
37152
|
-
"px-2 text-sm outline-none focus:ring-1 focus:ring-ring"
|
|
37153
|
-
),
|
|
37154
|
-
onChange: (e) => setMetadata("url", e.target.value)
|
|
37155
|
-
}
|
|
37156
|
-
),
|
|
37157
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37158
|
-
Input,
|
|
37159
|
-
{
|
|
37160
|
-
inputType: "text",
|
|
37161
|
-
value: caption,
|
|
37162
|
-
placeholder: t("richBlockEditor.placeholder.caption"),
|
|
37163
|
-
"aria-label": t("richBlockEditor.aria.imageCaption"),
|
|
37164
|
-
className: cn(
|
|
37165
|
-
"h-8 flex-1 rounded-sm border border-border bg-background",
|
|
37166
|
-
"px-2 text-sm outline-none focus:ring-1 focus:ring-ring"
|
|
37167
|
-
),
|
|
37168
|
-
onChange: (e) => setMetadata("caption", e.target.value)
|
|
37169
|
-
}
|
|
37170
|
-
)
|
|
37171
|
-
] }),
|
|
37172
|
-
readOnly && caption && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-center text-muted-foreground", children: caption })
|
|
37173
|
-
] });
|
|
37346
|
+
const [fieldDraft, setFieldDraft] = React87.useState(null);
|
|
37347
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
37348
|
+
const fieldDefs = (fields ?? []).filter((f3) => fieldName(f3) !== "");
|
|
37349
|
+
if (fieldDefs.length === 0) return null;
|
|
37350
|
+
const commitField = (name, next, current) => {
|
|
37351
|
+
setFieldDraft(null);
|
|
37352
|
+
if (!metaCommitEvent || next === current) return;
|
|
37353
|
+
eventBus.emit(`UI:${metaCommitEvent}`, { id: recordId, patch: { id: recordId, [name]: next } });
|
|
37354
|
+
};
|
|
37355
|
+
const renderValue = (field) => {
|
|
37356
|
+
const name = fieldName(field);
|
|
37357
|
+
const raw = getNestedValue(entity ?? {}, name);
|
|
37358
|
+
const kind = fieldKind(field, raw);
|
|
37359
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
37360
|
+
if (kind === "boolean") {
|
|
37361
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37362
|
+
Switch,
|
|
37363
|
+
{
|
|
37364
|
+
checked: Boolean(raw),
|
|
37365
|
+
disabled: !metaCommitEvent,
|
|
37366
|
+
"aria-label": label,
|
|
37367
|
+
onChange: (checked) => commitField(name, checked, Boolean(raw))
|
|
37368
|
+
}
|
|
37369
|
+
);
|
|
37370
|
+
}
|
|
37371
|
+
if (kind === "select") {
|
|
37372
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37373
|
+
Select,
|
|
37374
|
+
{
|
|
37375
|
+
value: raw !== void 0 && raw !== null ? String(raw) : "",
|
|
37376
|
+
disabled: !metaCommitEvent,
|
|
37377
|
+
"aria-label": label,
|
|
37378
|
+
className: "h-8 w-full",
|
|
37379
|
+
options: (field.options ?? []).map((opt) => ({ value: opt, label: humanizeEnumValue(opt) })),
|
|
37380
|
+
onChange: (e) => commitField(name, e.target.value, raw)
|
|
37381
|
+
}
|
|
37382
|
+
);
|
|
37383
|
+
}
|
|
37384
|
+
if (kind === "readonly" || !metaCommitEvent) {
|
|
37385
|
+
if (Array.isArray(raw)) {
|
|
37386
|
+
if (raw.length === 0) {
|
|
37387
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: "\u2014" });
|
|
37388
|
+
}
|
|
37389
|
+
return /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-wrap", children: raw.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", children: relationLabel(item) ?? humanizeEnumValue(String(item)) }, i)) });
|
|
37174
37390
|
}
|
|
37175
|
-
|
|
37176
|
-
|
|
37177
|
-
|
|
37178
|
-
|
|
37179
|
-
|
|
37180
|
-
|
|
37181
|
-
|
|
37182
|
-
|
|
37183
|
-
|
|
37184
|
-
|
|
37185
|
-
|
|
37186
|
-
|
|
37187
|
-
|
|
37188
|
-
|
|
37189
|
-
|
|
37190
|
-
|
|
37191
|
-
|
|
37192
|
-
|
|
37193
|
-
|
|
37194
|
-
|
|
37195
|
-
|
|
37196
|
-
|
|
37197
|
-
|
|
37198
|
-
|
|
37199
|
-
|
|
37200
|
-
|
|
37201
|
-
|
|
37202
|
-
|
|
37203
|
-
|
|
37204
|
-
|
|
37205
|
-
|
|
37206
|
-
|
|
37207
|
-
|
|
37208
|
-
|
|
37209
|
-
|
|
37210
|
-
|
|
37211
|
-
|
|
37212
|
-
|
|
37213
|
-
|
|
37214
|
-
|
|
37215
|
-
|
|
37216
|
-
Button,
|
|
37217
|
-
{
|
|
37218
|
-
type: "button",
|
|
37219
|
-
variant: "ghost",
|
|
37220
|
-
className: cn(
|
|
37221
|
-
"inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
37222
|
-
"hover:text-foreground p-0 h-auto"
|
|
37223
|
-
),
|
|
37224
|
-
onClick: addListItem,
|
|
37225
|
-
children: [
|
|
37226
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "w-3 h-3" }),
|
|
37227
|
-
" ",
|
|
37228
|
-
t("richBlockEditor.addItem")
|
|
37229
|
-
]
|
|
37230
|
-
}
|
|
37231
|
-
) })
|
|
37232
|
-
]
|
|
37391
|
+
const shown2 = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
37392
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "break-words", children: shown2 });
|
|
37393
|
+
}
|
|
37394
|
+
if (fieldDraft?.name === name) {
|
|
37395
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37396
|
+
Input,
|
|
37397
|
+
{
|
|
37398
|
+
value: fieldDraft.value,
|
|
37399
|
+
autoFocus: true,
|
|
37400
|
+
"aria-label": label,
|
|
37401
|
+
className: "h-8 w-full",
|
|
37402
|
+
onChange: (e) => setFieldDraft({ name, value: e.target.value }),
|
|
37403
|
+
onBlur: () => commitField(name, fieldDraft.value.trim(), raw),
|
|
37404
|
+
onKeyDown: (e) => {
|
|
37405
|
+
if (e.key === "Enter") {
|
|
37406
|
+
e.preventDefault();
|
|
37407
|
+
commitField(name, fieldDraft.value.trim(), raw);
|
|
37408
|
+
} else if (e.key === "Escape") {
|
|
37409
|
+
e.preventDefault();
|
|
37410
|
+
setFieldDraft(null);
|
|
37411
|
+
}
|
|
37412
|
+
},
|
|
37413
|
+
"data-testid": `document-property-input-${name}`
|
|
37414
|
+
}
|
|
37415
|
+
);
|
|
37416
|
+
}
|
|
37417
|
+
const shown = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
37418
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37419
|
+
Box,
|
|
37420
|
+
{
|
|
37421
|
+
role: "button",
|
|
37422
|
+
tabIndex: 0,
|
|
37423
|
+
className: cn(
|
|
37424
|
+
"cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
37425
|
+
(raw === void 0 || raw === null || raw === "") && "text-muted-foreground"
|
|
37426
|
+
),
|
|
37427
|
+
onClick: () => setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" }),
|
|
37428
|
+
onKeyDown: (e) => {
|
|
37429
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
37430
|
+
e.preventDefault();
|
|
37431
|
+
setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" });
|
|
37233
37432
|
}
|
|
37234
|
-
|
|
37433
|
+
},
|
|
37434
|
+
"data-testid": `document-property-${name}`,
|
|
37435
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "break-words", children: shown })
|
|
37235
37436
|
}
|
|
37236
|
-
|
|
37237
|
-
default:
|
|
37238
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37239
|
-
Editable,
|
|
37240
|
-
{
|
|
37241
|
-
tag: "p",
|
|
37242
|
-
value: block.content ?? "",
|
|
37243
|
-
readOnly,
|
|
37244
|
-
placeholder: placeholder ?? t("richBlockEditor.placeholder.paragraph"),
|
|
37245
|
-
ariaLabel: t("richBlockEditor.aria.paragraphBlock"),
|
|
37246
|
-
className: "leading-7",
|
|
37247
|
-
onValueChange: setContent
|
|
37248
|
-
}
|
|
37249
|
-
);
|
|
37250
|
-
}
|
|
37437
|
+
);
|
|
37251
37438
|
};
|
|
37252
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37253
|
-
|
|
37254
|
-
{
|
|
37255
|
-
|
|
37256
|
-
|
|
37257
|
-
|
|
37258
|
-
|
|
37259
|
-
|
|
37260
|
-
|
|
37261
|
-
|
|
37262
|
-
|
|
37263
|
-
|
|
37264
|
-
|
|
37265
|
-
|
|
37266
|
-
readOnly,
|
|
37267
|
-
onDelete,
|
|
37268
|
-
onDuplicate,
|
|
37269
|
-
onChangeType
|
|
37270
|
-
}
|
|
37271
|
-
) }),
|
|
37272
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "min-w-0 flex-1", children: renderBody() })
|
|
37273
|
-
]
|
|
37274
|
-
}
|
|
37275
|
-
);
|
|
37439
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { variant: "bordered", className: cn("w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: "p-4", children: [
|
|
37440
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", weight: "medium", className: "uppercase tracking-wide", children: title ?? (t("documentDetails.title") || "Details") }),
|
|
37441
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", children: fieldDefs.map((field) => {
|
|
37442
|
+
const name = fieldName(field);
|
|
37443
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
37444
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
37445
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
37446
|
+
field.icon && renderIconInput5(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
37447
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
37448
|
+
] }),
|
|
37449
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "min-w-0", children: renderValue(field) })
|
|
37450
|
+
] }, name);
|
|
37451
|
+
}) })
|
|
37452
|
+
] }) });
|
|
37276
37453
|
}
|
|
37277
|
-
var
|
|
37278
|
-
|
|
37279
|
-
"components/core/molecules/RichBlockEditor.tsx"() {
|
|
37454
|
+
var init_DocumentDetails = __esm({
|
|
37455
|
+
"components/core/molecules/DocumentDetails.tsx"() {
|
|
37280
37456
|
"use client";
|
|
37281
37457
|
init_cn();
|
|
37282
|
-
|
|
37283
|
-
|
|
37284
|
-
|
|
37458
|
+
init_format();
|
|
37459
|
+
init_getNestedValue();
|
|
37460
|
+
init_useEventBus();
|
|
37285
37461
|
init_Box();
|
|
37286
|
-
|
|
37287
|
-
|
|
37462
|
+
init_Stack();
|
|
37463
|
+
init_Typography();
|
|
37464
|
+
init_Badge();
|
|
37465
|
+
init_Card();
|
|
37288
37466
|
init_Icon();
|
|
37289
|
-
|
|
37290
|
-
|
|
37291
|
-
|
|
37292
|
-
{ type: "heading-1", labelKey: "richBlockEditor.toolbar.h1", icon: LucideIcons2.Heading1 },
|
|
37293
|
-
{ type: "heading-2", labelKey: "richBlockEditor.toolbar.h2", icon: LucideIcons2.Heading2 },
|
|
37294
|
-
{ type: "heading-3", labelKey: "richBlockEditor.toolbar.h3", icon: LucideIcons2.Heading3 },
|
|
37295
|
-
{ type: "bullet-list", labelKey: "richBlockEditor.toolbar.bulletList", icon: LucideIcons2.List },
|
|
37296
|
-
{ type: "numbered-list", labelKey: "richBlockEditor.toolbar.numbered", icon: LucideIcons2.ListOrdered },
|
|
37297
|
-
{ type: "quote", labelKey: "richBlockEditor.toolbar.quote", icon: LucideIcons2.Quote },
|
|
37298
|
-
{ type: "code", labelKey: "richBlockEditor.toolbar.code", icon: LucideIcons2.Code },
|
|
37299
|
-
{ type: "divider", labelKey: "richBlockEditor.toolbar.divider", icon: LucideIcons2.Minus },
|
|
37300
|
-
{ type: "image", labelKey: "richBlockEditor.toolbar.image", icon: LucideIcons2.Image }
|
|
37301
|
-
];
|
|
37302
|
-
BLOCK_TYPE_LABEL_KEY = {
|
|
37303
|
-
paragraph: "richBlockEditor.blockType.paragraph",
|
|
37304
|
-
"heading-1": "richBlockEditor.blockType.heading1",
|
|
37305
|
-
"heading-2": "richBlockEditor.blockType.heading2",
|
|
37306
|
-
"heading-3": "richBlockEditor.blockType.heading3",
|
|
37307
|
-
"bullet-list": "richBlockEditor.blockType.bulletList",
|
|
37308
|
-
"numbered-list": "richBlockEditor.blockType.numberedList",
|
|
37309
|
-
quote: "richBlockEditor.blockType.quote",
|
|
37310
|
-
code: "richBlockEditor.blockType.code",
|
|
37311
|
-
divider: "richBlockEditor.blockType.divider",
|
|
37312
|
-
image: "richBlockEditor.blockType.image"
|
|
37313
|
-
};
|
|
37314
|
-
CHANGEABLE_TYPES = [
|
|
37315
|
-
"paragraph",
|
|
37316
|
-
"heading-1",
|
|
37317
|
-
"heading-2",
|
|
37318
|
-
"heading-3",
|
|
37319
|
-
"bullet-list",
|
|
37320
|
-
"numbered-list",
|
|
37321
|
-
"quote",
|
|
37322
|
-
"code"
|
|
37323
|
-
];
|
|
37324
|
-
_idSeq = 0;
|
|
37325
|
-
BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
37326
|
-
"paragraph",
|
|
37327
|
-
"heading-1",
|
|
37328
|
-
"heading-2",
|
|
37329
|
-
"heading-3",
|
|
37330
|
-
"bullet-list",
|
|
37331
|
-
"numbered-list",
|
|
37332
|
-
"quote",
|
|
37333
|
-
"code",
|
|
37334
|
-
"divider",
|
|
37335
|
-
"image"
|
|
37336
|
-
]);
|
|
37337
|
-
RichBlockEditor = ({
|
|
37338
|
-
initialBlocks,
|
|
37339
|
-
onChange,
|
|
37340
|
-
changeEvent,
|
|
37341
|
-
readOnly = false,
|
|
37342
|
-
placeholder,
|
|
37343
|
-
enableBlocks = true,
|
|
37344
|
-
showToolbar = true,
|
|
37345
|
-
className
|
|
37346
|
-
}) => {
|
|
37347
|
-
const { t } = hooks.useTranslate();
|
|
37348
|
-
const [blocks, setBlocks] = React87.useState(
|
|
37349
|
-
() => normalizeBlocks(initialBlocks)
|
|
37350
|
-
);
|
|
37351
|
-
const onChangeRef = React87.useRef(onChange);
|
|
37352
|
-
React87.useEffect(() => {
|
|
37353
|
-
onChangeRef.current = onChange;
|
|
37354
|
-
}, [onChange]);
|
|
37355
|
-
const eventBus = useEventBus();
|
|
37356
|
-
const changeEventRef = React87.useRef(changeEvent);
|
|
37357
|
-
React87.useEffect(() => {
|
|
37358
|
-
changeEventRef.current = changeEvent;
|
|
37359
|
-
}, [changeEvent]);
|
|
37360
|
-
const commit = React87.useCallback((next) => {
|
|
37361
|
-
setBlocks(next);
|
|
37362
|
-
onChangeRef.current?.(next);
|
|
37363
|
-
const evt = changeEventRef.current;
|
|
37364
|
-
if (evt) eventBus.emit(`UI:${evt}`, { blocks: next });
|
|
37365
|
-
}, [eventBus]);
|
|
37366
|
-
const handleAppend = React87.useCallback(
|
|
37367
|
-
(type) => {
|
|
37368
|
-
if (readOnly) return;
|
|
37369
|
-
commit([...blocks, createBlock(type)]);
|
|
37370
|
-
},
|
|
37371
|
-
[blocks, commit, readOnly]
|
|
37372
|
-
);
|
|
37373
|
-
const handleUpdate = React87.useCallback(
|
|
37374
|
-
(id, updater) => {
|
|
37375
|
-
commit(replaceBlock(blocks, id, updater));
|
|
37376
|
-
},
|
|
37377
|
-
[blocks, commit]
|
|
37378
|
-
);
|
|
37379
|
-
const handleDelete = React87.useCallback(
|
|
37380
|
-
(id) => {
|
|
37381
|
-
const next = removeBlock(blocks, id);
|
|
37382
|
-
commit(next.length > 0 ? next : [createBlock("paragraph")]);
|
|
37383
|
-
},
|
|
37384
|
-
[blocks, commit]
|
|
37385
|
-
);
|
|
37386
|
-
const handleDuplicate = React87.useCallback(
|
|
37387
|
-
(id) => {
|
|
37388
|
-
const target = blocks.find((b) => b.id === id);
|
|
37389
|
-
if (!target) return;
|
|
37390
|
-
commit(insertAfter(blocks, id, duplicateBlock(target)));
|
|
37391
|
-
},
|
|
37392
|
-
[blocks, commit]
|
|
37393
|
-
);
|
|
37394
|
-
const handleChangeType = React87.useCallback(
|
|
37395
|
-
(id, type) => {
|
|
37396
|
-
commit(
|
|
37397
|
-
replaceBlock(blocks, id, (b) => changeBlockType(b, type))
|
|
37398
|
-
);
|
|
37399
|
-
},
|
|
37400
|
-
[blocks, commit]
|
|
37401
|
-
);
|
|
37402
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37403
|
-
Card,
|
|
37404
|
-
{
|
|
37405
|
-
variant: "bordered",
|
|
37406
|
-
padding: "none",
|
|
37407
|
-
className: cn("flex flex-col text-card-foreground", className),
|
|
37408
|
-
children: [
|
|
37409
|
-
enableBlocks && showToolbar && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
37410
|
-
Box,
|
|
37411
|
-
{
|
|
37412
|
-
role: "toolbar",
|
|
37413
|
-
"aria-label": t("richBlockEditor.editorToolbar"),
|
|
37414
|
-
className: cn(
|
|
37415
|
-
"flex flex-wrap items-center gap-1",
|
|
37416
|
-
"border-b border-border bg-muted/30 px-2 py-2"
|
|
37417
|
-
),
|
|
37418
|
-
children: TOOLBAR_ENTRIES.map((entry) => {
|
|
37419
|
-
const Icon2 = entry.icon;
|
|
37420
|
-
const entryLabel = t(entry.labelKey);
|
|
37421
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37422
|
-
Button,
|
|
37423
|
-
{
|
|
37424
|
-
type: "button",
|
|
37425
|
-
variant: "ghost",
|
|
37426
|
-
size: "sm",
|
|
37427
|
-
"aria-label": t("richBlockEditor.insertEntry", { label: entryLabel }),
|
|
37428
|
-
title: entryLabel,
|
|
37429
|
-
onClick: () => handleAppend(entry.type),
|
|
37430
|
-
children: [
|
|
37431
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon2, { size: 14 }),
|
|
37432
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
|
|
37433
|
-
]
|
|
37434
|
-
},
|
|
37435
|
-
entry.type
|
|
37436
|
-
);
|
|
37437
|
-
})
|
|
37438
|
-
}
|
|
37439
|
-
),
|
|
37440
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1 px-3 py-3", children: blocks.map((block) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
37441
|
-
BlockRow,
|
|
37442
|
-
{
|
|
37443
|
-
block,
|
|
37444
|
-
readOnly,
|
|
37445
|
-
showAffordances: enableBlocks,
|
|
37446
|
-
placeholder,
|
|
37447
|
-
onUpdate: (updater) => handleUpdate(block.id, updater),
|
|
37448
|
-
onDelete: () => handleDelete(block.id),
|
|
37449
|
-
onDuplicate: () => handleDuplicate(block.id),
|
|
37450
|
-
onChangeType: (type) => handleChangeType(block.id, type)
|
|
37451
|
-
},
|
|
37452
|
-
block.id
|
|
37453
|
-
)) })
|
|
37454
|
-
]
|
|
37455
|
-
}
|
|
37456
|
-
);
|
|
37457
|
-
};
|
|
37458
|
-
RichBlockEditor.displayName = "RichBlockEditor";
|
|
37467
|
+
init_Input();
|
|
37468
|
+
init_Select();
|
|
37469
|
+
init_Switch();
|
|
37459
37470
|
}
|
|
37460
37471
|
});
|
|
37461
37472
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
@@ -42404,8 +42415,8 @@ var init_DataTable = __esm({
|
|
|
42404
42415
|
DataTable.displayName = "DataTable";
|
|
42405
42416
|
}
|
|
42406
42417
|
});
|
|
42407
|
-
function getBadgeVariant(
|
|
42408
|
-
const name =
|
|
42418
|
+
function getBadgeVariant(fieldName2, value) {
|
|
42419
|
+
const name = fieldName2.toLowerCase();
|
|
42409
42420
|
const val = String(value).toLowerCase();
|
|
42410
42421
|
if (name.includes("status")) {
|
|
42411
42422
|
if (val.includes("complete") || val.includes("done") || val.includes("active"))
|
|
@@ -42421,12 +42432,12 @@ function getBadgeVariant(fieldName, value) {
|
|
|
42421
42432
|
}
|
|
42422
42433
|
return "default";
|
|
42423
42434
|
}
|
|
42424
|
-
function formatFieldValue2(value,
|
|
42435
|
+
function formatFieldValue2(value, fieldName2) {
|
|
42425
42436
|
if (typeof value === "number") {
|
|
42426
|
-
if (
|
|
42437
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
42427
42438
|
return `${value}%`;
|
|
42428
42439
|
}
|
|
42429
|
-
if (
|
|
42440
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
42430
42441
|
return `$${value.toLocaleString()}`;
|
|
42431
42442
|
}
|
|
42432
42443
|
return value.toLocaleString();
|
|
@@ -42436,7 +42447,7 @@ function formatFieldValue2(value, fieldName) {
|
|
|
42436
42447
|
}
|
|
42437
42448
|
return String(value);
|
|
42438
42449
|
}
|
|
42439
|
-
function renderRichFieldValue(value,
|
|
42450
|
+
function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
42440
42451
|
if (value === void 0 || value === null) return "\u2014";
|
|
42441
42452
|
const str = String(value);
|
|
42442
42453
|
switch (fieldType) {
|
|
@@ -42447,7 +42458,7 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
42447
42458
|
"img",
|
|
42448
42459
|
{
|
|
42449
42460
|
src: str,
|
|
42450
|
-
alt: formatFieldLabel(
|
|
42461
|
+
alt: formatFieldLabel(fieldName2),
|
|
42451
42462
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
42452
42463
|
loading: "lazy"
|
|
42453
42464
|
}
|
|
@@ -42582,9 +42593,9 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
42582
42593
|
return /* @__PURE__ */ jsxRuntime.jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
|
|
42583
42594
|
default:
|
|
42584
42595
|
if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
|
|
42585
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: getBadgeVariant(
|
|
42596
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: getBadgeVariant(fieldName2, str), children: humanizeEnumValue(str) });
|
|
42586
42597
|
}
|
|
42587
|
-
return formatFieldValue2(value,
|
|
42598
|
+
return formatFieldValue2(value, fieldName2);
|
|
42588
42599
|
}
|
|
42589
42600
|
}
|
|
42590
42601
|
function normalizeFieldDefs(fields) {
|
|
@@ -43427,7 +43438,21 @@ var init_Form = __esm({
|
|
|
43427
43438
|
const normalizedInitialData = React87__namespace.default.useMemo(() => {
|
|
43428
43439
|
const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
|
|
43429
43440
|
const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
|
|
43430
|
-
|
|
43441
|
+
const merged = entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
|
|
43442
|
+
const toId = (value) => {
|
|
43443
|
+
if (value === null || value === void 0 || typeof value !== "object" || value instanceof Date) return value;
|
|
43444
|
+
if (Array.isArray(value)) {
|
|
43445
|
+
return value.map(
|
|
43446
|
+
(item) => item !== null && typeof item === "object" && !Array.isArray(item) && !(item instanceof Date) && item.id !== void 0 && item.id !== null ? String(item.id) : item
|
|
43447
|
+
);
|
|
43448
|
+
}
|
|
43449
|
+
return value.id !== void 0 && value.id !== null ? String(value.id) : value;
|
|
43450
|
+
};
|
|
43451
|
+
const normalized = {};
|
|
43452
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
43453
|
+
normalized[key] = key === "id" ? value : toId(value);
|
|
43454
|
+
}
|
|
43455
|
+
return normalized;
|
|
43431
43456
|
}, [entity, initialData]);
|
|
43432
43457
|
const entityDerivedFields = React87__namespace.default.useMemo(() => {
|
|
43433
43458
|
if (fields && fields.length > 0) return void 0;
|
|
@@ -43556,8 +43581,8 @@ var init_Form = __esm({
|
|
|
43556
43581
|
checkViolations(name, newFormData);
|
|
43557
43582
|
};
|
|
43558
43583
|
const isFieldVisible = React87__namespace.default.useCallback(
|
|
43559
|
-
(
|
|
43560
|
-
const condition = conditionalFields[
|
|
43584
|
+
(fieldName2) => {
|
|
43585
|
+
const condition = conditionalFields[fieldName2];
|
|
43561
43586
|
if (!condition) return true;
|
|
43562
43587
|
return Boolean(evaluateFormExpression(condition, evalContext));
|
|
43563
43588
|
},
|
|
@@ -43603,9 +43628,9 @@ var init_Form = __esm({
|
|
|
43603
43628
|
};
|
|
43604
43629
|
const handleInvalid = (e) => {
|
|
43605
43630
|
const target = e.target;
|
|
43606
|
-
const
|
|
43631
|
+
const fieldName2 = target.getAttribute("data-field-name") ?? target.name ?? "";
|
|
43607
43632
|
const fieldMessage = target.validationMessage || "Invalid value";
|
|
43608
|
-
debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
|
|
43633
|
+
debug("forms", "invalid", { mode: formMode, fieldName: fieldName2, fieldMessage });
|
|
43609
43634
|
queueMicrotask(() => {
|
|
43610
43635
|
const form = formRef.current;
|
|
43611
43636
|
if (!form) return;
|
|
@@ -43641,22 +43666,22 @@ var init_Form = __esm({
|
|
|
43641
43666
|
};
|
|
43642
43667
|
const renderField = React87__namespace.default.useCallback(
|
|
43643
43668
|
(field) => {
|
|
43644
|
-
const
|
|
43645
|
-
if (!
|
|
43646
|
-
if (!isFieldVisible(
|
|
43669
|
+
const fieldName2 = field.name || field.field;
|
|
43670
|
+
if (!fieldName2) return null;
|
|
43671
|
+
if (!isFieldVisible(fieldName2)) {
|
|
43647
43672
|
return null;
|
|
43648
43673
|
}
|
|
43649
43674
|
const inputType = determineInputType(field);
|
|
43650
|
-
const label = field.label ||
|
|
43651
|
-
const currentValue = formData[
|
|
43652
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", "data-field":
|
|
43675
|
+
const label = field.label || fieldName2.charAt(0).toUpperCase() + fieldName2.slice(1).replace(/([A-Z])/g, " $1");
|
|
43676
|
+
const currentValue = formData[fieldName2] ?? field.defaultValue ?? "";
|
|
43677
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", "data-field": fieldName2, children: [
|
|
43653
43678
|
inputType !== "checkbox" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { as: "label", variant: "label", weight: "bold", children: [
|
|
43654
43679
|
label,
|
|
43655
43680
|
field.required && /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
|
|
43656
43681
|
] }),
|
|
43657
|
-
renderFieldInput(field,
|
|
43682
|
+
renderFieldInput(field, fieldName2, inputType, currentValue, label),
|
|
43658
43683
|
field.hint && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
|
|
43659
|
-
] },
|
|
43684
|
+
] }, fieldName2);
|
|
43660
43685
|
},
|
|
43661
43686
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
43662
43687
|
);
|
|
@@ -43685,8 +43710,8 @@ var init_Form = __esm({
|
|
|
43685
43710
|
}
|
|
43686
43711
|
return field;
|
|
43687
43712
|
}).map((field) => {
|
|
43688
|
-
const
|
|
43689
|
-
const override = fieldOverrides?.find((o) => o.name ===
|
|
43713
|
+
const fieldName2 = field.name || field.field;
|
|
43714
|
+
const override = fieldOverrides?.find((o) => o.name === fieldName2);
|
|
43690
43715
|
if (!override) return field;
|
|
43691
43716
|
return {
|
|
43692
43717
|
...field,
|
|
@@ -43742,11 +43767,11 @@ var init_Form = __esm({
|
|
|
43742
43767
|
] }, section.id);
|
|
43743
43768
|
}).filter(Boolean);
|
|
43744
43769
|
}, [sections, isSectionVisible, collapsedSections, renderField, gap]);
|
|
43745
|
-
function renderFieldInput(field,
|
|
43770
|
+
function renderFieldInput(field, fieldName2, inputType, currentValue, label) {
|
|
43746
43771
|
const commonProps = {
|
|
43747
|
-
id:
|
|
43748
|
-
name:
|
|
43749
|
-
"data-field-name":
|
|
43772
|
+
id: fieldName2,
|
|
43773
|
+
name: fieldName2,
|
|
43774
|
+
"data-field-name": fieldName2,
|
|
43750
43775
|
required: field.required,
|
|
43751
43776
|
disabled: isLoading,
|
|
43752
43777
|
placeholder: field.placeholder,
|
|
@@ -43760,7 +43785,7 @@ var init_Form = __esm({
|
|
|
43760
43785
|
...commonProps,
|
|
43761
43786
|
label: label + (field.required ? " *" : ""),
|
|
43762
43787
|
checked: Boolean(currentValue),
|
|
43763
|
-
onChange: (e) => handleChange(
|
|
43788
|
+
onChange: (e) => handleChange(fieldName2, e.target.checked)
|
|
43764
43789
|
}
|
|
43765
43790
|
);
|
|
43766
43791
|
case "textarea":
|
|
@@ -43769,7 +43794,7 @@ var init_Form = __esm({
|
|
|
43769
43794
|
{
|
|
43770
43795
|
...commonProps,
|
|
43771
43796
|
value: String(currentValue),
|
|
43772
|
-
onChange: (e) => handleChange(
|
|
43797
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43773
43798
|
minLength: field.min,
|
|
43774
43799
|
maxLength: field.max
|
|
43775
43800
|
}
|
|
@@ -43782,14 +43807,14 @@ var init_Form = __esm({
|
|
|
43782
43807
|
...commonProps,
|
|
43783
43808
|
options,
|
|
43784
43809
|
value: String(currentValue),
|
|
43785
|
-
onValueChange: (v) => handleChange(
|
|
43810
|
+
onValueChange: (v) => handleChange(fieldName2, v),
|
|
43786
43811
|
placeholder: field.placeholder || `Select ${label}...`
|
|
43787
43812
|
}
|
|
43788
43813
|
);
|
|
43789
43814
|
}
|
|
43790
43815
|
case "relation": {
|
|
43791
|
-
const relationOptions = relationsData[
|
|
43792
|
-
const relationLoading = relationsLoading[
|
|
43816
|
+
const relationOptions = relationsData[fieldName2] || [];
|
|
43817
|
+
const relationLoading = relationsLoading[fieldName2] || false;
|
|
43793
43818
|
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
43794
43819
|
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
43795
43820
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -43801,7 +43826,7 @@ var init_Form = __esm({
|
|
|
43801
43826
|
clearable: true,
|
|
43802
43827
|
options: [...relationOptions],
|
|
43803
43828
|
value: selectedValues,
|
|
43804
|
-
onValueChange: (value) => handleChange(
|
|
43829
|
+
onValueChange: (value) => handleChange(fieldName2, Array.isArray(value) ? value : [value]),
|
|
43805
43830
|
placeholder: field.placeholder || `Select ${label}...`
|
|
43806
43831
|
}
|
|
43807
43832
|
);
|
|
@@ -43811,7 +43836,7 @@ var init_Form = __esm({
|
|
|
43811
43836
|
{
|
|
43812
43837
|
...commonProps,
|
|
43813
43838
|
value: currentValue ? String(currentValue) : void 0,
|
|
43814
|
-
onChange: (value) => handleChange(
|
|
43839
|
+
onChange: (value) => handleChange(fieldName2, value),
|
|
43815
43840
|
options: relationOptions,
|
|
43816
43841
|
isLoading: relationLoading,
|
|
43817
43842
|
placeholder: field.placeholder || `Select ${label}...`,
|
|
@@ -43828,7 +43853,7 @@ var init_Form = __esm({
|
|
|
43828
43853
|
placeholder: field.placeholder,
|
|
43829
43854
|
disabled: isLoading,
|
|
43830
43855
|
value: arrayValue,
|
|
43831
|
-
onChange: (next) => handleChange(
|
|
43856
|
+
onChange: (next) => handleChange(fieldName2, [...next])
|
|
43832
43857
|
}
|
|
43833
43858
|
);
|
|
43834
43859
|
}
|
|
@@ -43840,7 +43865,7 @@ var init_Form = __esm({
|
|
|
43840
43865
|
type: "number",
|
|
43841
43866
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
43842
43867
|
onChange: (e) => handleChange(
|
|
43843
|
-
|
|
43868
|
+
fieldName2,
|
|
43844
43869
|
e.target.value ? Number(e.target.value) : void 0
|
|
43845
43870
|
),
|
|
43846
43871
|
min: field.min,
|
|
@@ -43857,7 +43882,7 @@ var init_Form = __esm({
|
|
|
43857
43882
|
icon: LucideIcons2.DollarSign,
|
|
43858
43883
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
43859
43884
|
onChange: (e) => handleChange(
|
|
43860
|
-
|
|
43885
|
+
fieldName2,
|
|
43861
43886
|
e.target.value ? Number(e.target.value) : void 0
|
|
43862
43887
|
),
|
|
43863
43888
|
min: field.min,
|
|
@@ -43875,7 +43900,7 @@ var init_Form = __esm({
|
|
|
43875
43900
|
const f3 = files[0];
|
|
43876
43901
|
if (!f3) return;
|
|
43877
43902
|
const reader = new FileReader();
|
|
43878
|
-
reader.onload = () => handleChange(
|
|
43903
|
+
reader.onload = () => handleChange(fieldName2, {
|
|
43879
43904
|
name: f3.name,
|
|
43880
43905
|
mimeType: f3.type,
|
|
43881
43906
|
sizeBytes: f3.size,
|
|
@@ -43892,7 +43917,7 @@ var init_Form = __esm({
|
|
|
43892
43917
|
...commonProps,
|
|
43893
43918
|
type: "date",
|
|
43894
43919
|
value: formatDateValue(currentValue),
|
|
43895
|
-
onChange: (e) => handleChange(
|
|
43920
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
43896
43921
|
}
|
|
43897
43922
|
);
|
|
43898
43923
|
case "datetime-local":
|
|
@@ -43902,7 +43927,7 @@ var init_Form = __esm({
|
|
|
43902
43927
|
...commonProps,
|
|
43903
43928
|
type: "datetime-local",
|
|
43904
43929
|
value: formatDateTimeValue(currentValue),
|
|
43905
|
-
onChange: (e) => handleChange(
|
|
43930
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
43906
43931
|
}
|
|
43907
43932
|
);
|
|
43908
43933
|
case "email":
|
|
@@ -43912,7 +43937,7 @@ var init_Form = __esm({
|
|
|
43912
43937
|
...commonProps,
|
|
43913
43938
|
type: "email",
|
|
43914
43939
|
value: String(currentValue),
|
|
43915
|
-
onChange: (e) => handleChange(
|
|
43940
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43916
43941
|
minLength: field.min,
|
|
43917
43942
|
maxLength: field.max
|
|
43918
43943
|
}
|
|
@@ -43924,7 +43949,7 @@ var init_Form = __esm({
|
|
|
43924
43949
|
...commonProps,
|
|
43925
43950
|
type: "url",
|
|
43926
43951
|
value: String(currentValue),
|
|
43927
|
-
onChange: (e) => handleChange(
|
|
43952
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43928
43953
|
minLength: field.min,
|
|
43929
43954
|
maxLength: field.max
|
|
43930
43955
|
}
|
|
@@ -43936,7 +43961,7 @@ var init_Form = __esm({
|
|
|
43936
43961
|
...commonProps,
|
|
43937
43962
|
type: "password",
|
|
43938
43963
|
value: String(currentValue),
|
|
43939
|
-
onChange: (e) => handleChange(
|
|
43964
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43940
43965
|
minLength: field.min,
|
|
43941
43966
|
maxLength: field.max
|
|
43942
43967
|
}
|
|
@@ -43949,7 +43974,7 @@ var init_Form = __esm({
|
|
|
43949
43974
|
...commonProps,
|
|
43950
43975
|
type: "text",
|
|
43951
43976
|
value: String(currentValue),
|
|
43952
|
-
onChange: (e) => handleChange(
|
|
43977
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43953
43978
|
minLength: field.min,
|
|
43954
43979
|
maxLength: field.max
|
|
43955
43980
|
}
|
|
@@ -44306,7 +44331,7 @@ function entityFieldsFromListItem(item) {
|
|
|
44306
44331
|
}
|
|
44307
44332
|
return result;
|
|
44308
44333
|
}
|
|
44309
|
-
function getStatusStyle(
|
|
44334
|
+
function getStatusStyle(fieldName2, value) {
|
|
44310
44335
|
const val = String(value).toLowerCase();
|
|
44311
44336
|
if (val.includes("complete") || val.includes("done"))
|
|
44312
44337
|
return STATUS_STYLES.complete;
|
|
@@ -44322,12 +44347,12 @@ function getStatusStyle(fieldName, value) {
|
|
|
44322
44347
|
if (val.includes("low")) return STATUS_STYLES.low;
|
|
44323
44348
|
return STATUS_STYLES.default;
|
|
44324
44349
|
}
|
|
44325
|
-
function formatValue3(value,
|
|
44350
|
+
function formatValue3(value, fieldName2) {
|
|
44326
44351
|
if (typeof value === "number") {
|
|
44327
|
-
if (
|
|
44352
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
44328
44353
|
return `${value}%`;
|
|
44329
44354
|
}
|
|
44330
|
-
if (
|
|
44355
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
44331
44356
|
return new Intl.NumberFormat("en-US", {
|
|
44332
44357
|
style: "currency",
|
|
44333
44358
|
currency: "USD",
|
|
@@ -44350,8 +44375,8 @@ function formatValue3(value, fieldName) {
|
|
|
44350
44375
|
}
|
|
44351
44376
|
return String(value);
|
|
44352
44377
|
}
|
|
44353
|
-
function formatFieldLabel2(
|
|
44354
|
-
return humanizeFieldName(
|
|
44378
|
+
function formatFieldLabel2(fieldName2) {
|
|
44379
|
+
return humanizeFieldName(fieldName2).replace(/\sId$/, "").trim();
|
|
44355
44380
|
}
|
|
44356
44381
|
var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
|
|
44357
44382
|
var init_List = __esm({
|
|
@@ -44419,9 +44444,9 @@ var init_List = __esm({
|
|
|
44419
44444
|
};
|
|
44420
44445
|
StatusBadge = ({
|
|
44421
44446
|
value,
|
|
44422
|
-
fieldName
|
|
44447
|
+
fieldName: fieldName2
|
|
44423
44448
|
}) => {
|
|
44424
|
-
const style = getStatusStyle(
|
|
44449
|
+
const style = getStatusStyle(fieldName2, value);
|
|
44425
44450
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
44426
44451
|
Typography,
|
|
44427
44452
|
{
|
|
@@ -47334,8 +47359,8 @@ var init_StatCard = __esm({
|
|
|
47334
47359
|
return items.length;
|
|
47335
47360
|
}
|
|
47336
47361
|
if (field.includes(":")) {
|
|
47337
|
-
const [
|
|
47338
|
-
return items.filter((item) => item[
|
|
47362
|
+
const [fieldName2, fieldValue] = field.split(":");
|
|
47363
|
+
return items.filter((item) => item[fieldName2] === fieldValue).length;
|
|
47339
47364
|
}
|
|
47340
47365
|
const fieldExistsOnItems = items.some((item) => field in item);
|
|
47341
47366
|
if (fieldExistsOnItems) {
|
|
@@ -48855,6 +48880,8 @@ var init_component_registry_generated = __esm({
|
|
|
48855
48880
|
init_DocSearch();
|
|
48856
48881
|
init_DocSidebar();
|
|
48857
48882
|
init_DocTOC();
|
|
48883
|
+
init_DocumentDetails();
|
|
48884
|
+
init_DocumentPanel();
|
|
48858
48885
|
init_DocumentViewer();
|
|
48859
48886
|
init_DrawFxLayer();
|
|
48860
48887
|
init_DrawGroup();
|
|
@@ -48964,7 +48991,7 @@ var init_component_registry_generated = __esm({
|
|
|
48964
48991
|
init_RelationSelect();
|
|
48965
48992
|
init_RepeatableFormSection();
|
|
48966
48993
|
init_ReplyTree();
|
|
48967
|
-
|
|
48994
|
+
init_RichTextEditor();
|
|
48968
48995
|
init_RuntimeDebugger2();
|
|
48969
48996
|
init_ScaledDiagram();
|
|
48970
48997
|
init_ScoreDisplay();
|
|
@@ -49127,6 +49154,8 @@ var init_component_registry_generated = __esm({
|
|
|
49127
49154
|
"DocSearch": DocSearch,
|
|
49128
49155
|
"DocSidebar": DocSidebar,
|
|
49129
49156
|
"DocTOC": DocTOC,
|
|
49157
|
+
"DocumentDetails": DocumentDetails,
|
|
49158
|
+
"DocumentPanel": DocumentPanel,
|
|
49130
49159
|
"DocumentViewer": DocumentViewer,
|
|
49131
49160
|
"DrawFxLayer": DrawFxLayer,
|
|
49132
49161
|
"DrawGroup": DrawGroup,
|
|
@@ -49238,7 +49267,7 @@ var init_component_registry_generated = __esm({
|
|
|
49238
49267
|
"RelationSelect": RelationSelect,
|
|
49239
49268
|
"RepeatableFormSection": RepeatableFormSection,
|
|
49240
49269
|
"ReplyTree": ReplyTree,
|
|
49241
|
-
"
|
|
49270
|
+
"RichTextEditor": RichTextEditor,
|
|
49242
49271
|
"RuntimeDebugger": RuntimeDebugger,
|
|
49243
49272
|
"ScaledDiagram": ScaledDiagram,
|
|
49244
49273
|
"ScoreDisplay": ScoreDisplay,
|
|
@@ -49392,10 +49421,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
49392
49421
|
}
|
|
49393
49422
|
if (field && typeof field === "object" && !Array.isArray(field) && !React87__namespace.default.isValidElement(field) && !(field instanceof Date)) {
|
|
49394
49423
|
const obj = field;
|
|
49395
|
-
const
|
|
49396
|
-
if (!
|
|
49424
|
+
const fieldName2 = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
|
|
49425
|
+
if (!fieldName2) return field;
|
|
49397
49426
|
if (obj.type || obj.inputType) return field;
|
|
49398
|
-
const entityField = fieldMap.get(
|
|
49427
|
+
const entityField = fieldMap.get(fieldName2);
|
|
49399
49428
|
if (!entityField) return field;
|
|
49400
49429
|
const enriched = { ...obj, type: entityField.type };
|
|
49401
49430
|
if (entityField.required && !("required" in obj)) {
|
|
@@ -49445,9 +49474,9 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
49445
49474
|
}
|
|
49446
49475
|
if (field && typeof field === "object" && !Array.isArray(field) && !React87__namespace.default.isValidElement(field) && !(field instanceof Date)) {
|
|
49447
49476
|
const obj = field;
|
|
49448
|
-
const
|
|
49449
|
-
if (!
|
|
49450
|
-
const meta = metaFor(
|
|
49477
|
+
const fieldName2 = typeof obj.key === "string" ? obj.key : typeof obj.name === "string" ? obj.name : void 0;
|
|
49478
|
+
if (!fieldName2 || obj.type) return field;
|
|
49479
|
+
const meta = metaFor(fieldName2);
|
|
49451
49480
|
return meta ? { ...obj, ...meta } : field;
|
|
49452
49481
|
}
|
|
49453
49482
|
return field;
|
|
@@ -50286,9 +50315,9 @@ function UISlotRenderer({
|
|
|
50286
50315
|
"ui-slot-renderer relative min-h-full",
|
|
50287
50316
|
className
|
|
50288
50317
|
), children: [
|
|
50289
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex min-h-full", children: [
|
|
50290
|
-
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 shrink-0" }),
|
|
50291
|
-
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-h-[200px]" })
|
|
50318
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex min-h-full flex-col lg:flex-row", children: [
|
|
50319
|
+
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 lg:shrink-0" }),
|
|
50320
|
+
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-w-0 min-h-[200px]" })
|
|
50292
50321
|
] }),
|
|
50293
50322
|
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "modal", portal: true }),
|
|
50294
50323
|
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "drawer", portal: true }),
|