@almadar/ui 5.159.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 +958 -912
- package/dist/avl/index.js +947 -901
- package/dist/components/index.cjs +978 -955
- package/dist/components/index.d.cts +156 -31
- package/dist/components/index.d.ts +156 -31
- package/dist/components/index.js +964 -944
- 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 +934 -892
- package/dist/providers/index.js +934 -892
- package/dist/runtime/index.cjs +953 -907
- package/dist/runtime/index.js +943 -897
- 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: [
|
|
@@ -26614,8 +26587,8 @@ function DataGrid({
|
|
|
26614
26587
|
}
|
|
26615
26588
|
return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
26616
26589
|
field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
26617
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
|
|
26618
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", children: formatValue(value, field.format) })
|
|
26590
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "sr-only", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
|
|
26591
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: formatValue(value, field.format) })
|
|
26619
26592
|
] }, field.name);
|
|
26620
26593
|
}) })
|
|
26621
26594
|
] }) })
|
|
@@ -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,12 +27015,16 @@ 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
|
{
|
|
27045
27022
|
className: cn(
|
|
27046
|
-
|
|
27023
|
+
// items-start, not items-center: a multi-line row (title + meta +
|
|
27024
|
+
// progress) centred its action cluster in the vertical middle, so
|
|
27025
|
+
// the buttons floated between the meta fields instead of anchoring
|
|
27026
|
+
// to the title they act on (U-DATALIST-ACTIONS-FLOAT-MID-ROW).
|
|
27027
|
+
"group flex items-start gap-4 transition-all duration-fast",
|
|
27047
27028
|
isCompact ? "px-4 py-2" : "px-6 py-4",
|
|
27048
27029
|
"hover:bg-muted/80",
|
|
27049
27030
|
!isCard && !isCompact && "rounded-lg border border-transparent hover:border-border"
|
|
@@ -27074,11 +27055,19 @@ function DataList({
|
|
|
27074
27055
|
if (value === void 0 || value === null || value === "") return null;
|
|
27075
27056
|
return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
27076
27057
|
field.icon && renderIconInput2(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
27077
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
27078
|
-
|
|
27079
|
-
|
|
27080
|
-
|
|
27081
|
-
|
|
27058
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
27059
|
+
Typography,
|
|
27060
|
+
{
|
|
27061
|
+
variant: "caption",
|
|
27062
|
+
color: "secondary",
|
|
27063
|
+
className: cn(field.format !== "boolean" && "sr-only"),
|
|
27064
|
+
children: [
|
|
27065
|
+
field.label ?? fieldLabel3(field.name),
|
|
27066
|
+
":"
|
|
27067
|
+
]
|
|
27068
|
+
}
|
|
27069
|
+
),
|
|
27070
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: formatValue2(value, field.format, { yes: t("common.yes"), no: t("common.no") }) })
|
|
27082
27071
|
] }, field.name);
|
|
27083
27072
|
}) }),
|
|
27084
27073
|
progressFields.map((field) => {
|
|
@@ -27097,7 +27086,7 @@ function DataList({
|
|
|
27097
27086
|
]
|
|
27098
27087
|
}
|
|
27099
27088
|
),
|
|
27100
|
-
isCard && !isLast && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "
|
|
27089
|
+
(isCard || isCompact) && !isLast && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("border-b border-border/40", isCompact ? "mx-4" : "mx-6") })
|
|
27101
27090
|
] }, id)
|
|
27102
27091
|
);
|
|
27103
27092
|
};
|
|
@@ -27107,7 +27096,13 @@ function DataList({
|
|
|
27107
27096
|
{
|
|
27108
27097
|
className: cn(
|
|
27109
27098
|
isCard && "bg-card rounded-xl border border-border shadow-elevation-dialog overflow-hidden",
|
|
27110
|
-
|
|
27099
|
+
// `gap-*` is inert on a block container, and Box only emits a display
|
|
27100
|
+
// class when its `display` prop is set — so every non-card list had
|
|
27101
|
+
// been asking for a gap that CSS silently dropped. flex-col makes it
|
|
27102
|
+
// real. `compact` keeps gap-0 on purpose: it separates with the row
|
|
27103
|
+
// divider above instead, never both (Almadar_UI_Beauty.md 6).
|
|
27104
|
+
!isCard && "flex flex-col",
|
|
27105
|
+
!isCard && !isCompact && gapClass,
|
|
27111
27106
|
listLookStyles[look],
|
|
27112
27107
|
className
|
|
27113
27108
|
),
|
|
@@ -32296,7 +32291,7 @@ var init_MapView = __esm({
|
|
|
32296
32291
|
shadowSize: [41, 41]
|
|
32297
32292
|
});
|
|
32298
32293
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
32299
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback97, useState:
|
|
32294
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback97, useState: useState97 } = React87__namespace.default;
|
|
32300
32295
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
32301
32296
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
32302
32297
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -32341,7 +32336,7 @@ var init_MapView = __esm({
|
|
|
32341
32336
|
showAttribution = true
|
|
32342
32337
|
}) {
|
|
32343
32338
|
const eventBus = useEventBus2();
|
|
32344
|
-
const [clickedPosition, setClickedPosition] =
|
|
32339
|
+
const [clickedPosition, setClickedPosition] = useState97(null);
|
|
32345
32340
|
const handleMapClick = useCallback97((lat, lng) => {
|
|
32346
32341
|
if (showClickedPin) {
|
|
32347
32342
|
setClickedPosition({ lat, lng });
|
|
@@ -36703,741 +36698,775 @@ var init_PositionedCanvas = __esm({
|
|
|
36703
36698
|
PositionedCanvas.displayName = "PositionedCanvas";
|
|
36704
36699
|
}
|
|
36705
36700
|
});
|
|
36706
|
-
function
|
|
36707
|
-
|
|
36708
|
-
|
|
36709
|
-
|
|
36710
|
-
|
|
36711
|
-
|
|
36712
|
-
if (!Array.isArray(raw) || raw.length === 0) return [createBlock("paragraph")];
|
|
36713
|
-
return raw.map((row) => {
|
|
36714
|
-
const entity = row;
|
|
36715
|
-
const rawType = entity.type;
|
|
36716
|
-
const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
|
|
36717
|
-
const id = typeof entity.id === "string" && entity.id ? entity.id : nextBlockId(type);
|
|
36718
|
-
return { ...entity, id, type };
|
|
36719
|
-
});
|
|
36720
|
-
}
|
|
36721
|
-
function createBlock(type) {
|
|
36722
|
-
switch (type) {
|
|
36723
|
-
case "bullet-list":
|
|
36724
|
-
case "numbered-list":
|
|
36725
|
-
return {
|
|
36726
|
-
id: nextBlockId(type),
|
|
36727
|
-
type,
|
|
36728
|
-
children: [
|
|
36729
|
-
{ id: nextBlockId("li"), type: "paragraph", content: "" }
|
|
36730
|
-
]
|
|
36731
|
-
};
|
|
36732
|
-
case "image":
|
|
36733
|
-
return {
|
|
36734
|
-
id: nextBlockId(type),
|
|
36735
|
-
type,
|
|
36736
|
-
content: "",
|
|
36737
|
-
metadata: { url: "", caption: "" }
|
|
36738
|
-
};
|
|
36739
|
-
case "code":
|
|
36740
|
-
return {
|
|
36741
|
-
id: nextBlockId(type),
|
|
36742
|
-
type,
|
|
36743
|
-
content: "",
|
|
36744
|
-
metadata: { language: "plaintext" }
|
|
36745
|
-
};
|
|
36746
|
-
case "divider":
|
|
36747
|
-
return { id: nextBlockId(type), type };
|
|
36748
|
-
default:
|
|
36749
|
-
return { id: nextBlockId(type), type, content: "" };
|
|
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;
|
|
36750
36707
|
}
|
|
36708
|
+
return null;
|
|
36751
36709
|
}
|
|
36752
|
-
function
|
|
36753
|
-
|
|
36754
|
-
|
|
36755
|
-
|
|
36756
|
-
|
|
36757
|
-
|
|
36758
|
-
|
|
36759
|
-
return {
|
|
36760
|
-
...block,
|
|
36761
|
-
id: nextBlockId(block.type),
|
|
36762
|
-
children: block.children?.map((child) => ({
|
|
36763
|
-
...child,
|
|
36764
|
-
id: nextBlockId("li")
|
|
36765
|
-
})),
|
|
36766
|
-
metadata: block.metadata ? { ...block.metadata } : void 0
|
|
36767
|
-
};
|
|
36768
|
-
}
|
|
36769
|
-
function insertAfter(blocks, targetId, inserted) {
|
|
36770
|
-
const idx = blocks.findIndex((b) => b.id === targetId);
|
|
36771
|
-
if (idx === -1) return [...blocks, inserted];
|
|
36772
|
-
const next = blocks.slice();
|
|
36773
|
-
next.splice(idx + 1, 0, inserted);
|
|
36774
|
-
return next;
|
|
36775
|
-
}
|
|
36776
|
-
function changeBlockType(block, type) {
|
|
36777
|
-
if (block.type === type) return block;
|
|
36778
|
-
if (type === "bullet-list" || type === "numbered-list") {
|
|
36779
|
-
if (block.children && block.children.length > 0) {
|
|
36780
|
-
return { ...block, type };
|
|
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;
|
|
36781
36717
|
}
|
|
36782
|
-
const
|
|
36783
|
-
|
|
36784
|
-
|
|
36785
|
-
|
|
36786
|
-
|
|
36787
|
-
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36792
|
-
|
|
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);
|
|
36793
36742
|
}
|
|
36794
|
-
|
|
36795
|
-
|
|
36796
|
-
|
|
36797
|
-
|
|
36798
|
-
|
|
36799
|
-
|
|
36800
|
-
|
|
36743
|
+
}
|
|
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 "";
|
|
36801
36751
|
}
|
|
36802
|
-
|
|
36803
|
-
|
|
36804
|
-
|
|
36805
|
-
|
|
36806
|
-
|
|
36807
|
-
|
|
36808
|
-
|
|
36752
|
+
return doc.body.innerHTML.replace(//g, "");
|
|
36753
|
+
}
|
|
36754
|
+
function htmlIsEmpty(el) {
|
|
36755
|
+
if (el.querySelector("img, hr")) return false;
|
|
36756
|
+
return (el.textContent ?? "").trim().length === 0;
|
|
36757
|
+
}
|
|
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;
|
|
36809
36763
|
}
|
|
36810
|
-
|
|
36811
|
-
return { id: block.id, type, content: seed };
|
|
36764
|
+
return null;
|
|
36812
36765
|
}
|
|
36813
|
-
function
|
|
36814
|
-
|
|
36815
|
-
|
|
36816
|
-
|
|
36817
|
-
|
|
36818
|
-
|
|
36819
|
-
|
|
36820
|
-
|
|
36821
|
-
|
|
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;
|
|
36822
36782
|
}
|
|
36783
|
+
if (tag === "a") link = true;
|
|
36823
36784
|
}
|
|
36824
|
-
|
|
36825
|
-
|
|
36826
|
-
|
|
36827
|
-
|
|
36828
|
-
|
|
36829
|
-
|
|
36830
|
-
|
|
36831
|
-
|
|
36832
|
-
|
|
36833
|
-
|
|
36834
|
-
|
|
36835
|
-
|
|
36836
|
-
"inline-flex items-center justify-center",
|
|
36837
|
-
"h-6 w-6 rounded-sm p-0 gap-0",
|
|
36838
|
-
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
36839
|
-
"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",
|
|
36840
|
-
"transition-opacity"
|
|
36841
|
-
),
|
|
36842
|
-
onClick: () => setOpen((v) => !v),
|
|
36843
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", className: "w-3.5 h-3.5" })
|
|
36844
|
-
}
|
|
36845
|
-
),
|
|
36846
|
-
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36847
|
-
Box,
|
|
36848
|
-
{
|
|
36849
|
-
role: "menu",
|
|
36850
|
-
className: cn(
|
|
36851
|
-
"absolute right-0 z-10 mt-1 w-44",
|
|
36852
|
-
"rounded-container border border-border bg-popover shadow-elevation-popover",
|
|
36853
|
-
"py-1 text-sm"
|
|
36854
|
-
),
|
|
36855
|
-
children: [
|
|
36856
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t(BLOCK_TYPE_LABEL_KEY[block.type]) }),
|
|
36857
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
36858
|
-
Button,
|
|
36859
|
-
{
|
|
36860
|
-
type: "button",
|
|
36861
|
-
variant: "ghost",
|
|
36862
|
-
role: "menuitem",
|
|
36863
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
36864
|
-
onClick: () => {
|
|
36865
|
-
onDuplicate();
|
|
36866
|
-
setOpen(false);
|
|
36867
|
-
},
|
|
36868
|
-
children: [
|
|
36869
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "w-3.5 h-3.5" }),
|
|
36870
|
-
" ",
|
|
36871
|
-
t("richBlockEditor.duplicate")
|
|
36872
|
-
]
|
|
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 text-destructive hover:bg-muted justify-start rounded-none",
|
|
36882
|
-
onClick: () => {
|
|
36883
|
-
onDelete();
|
|
36884
|
-
setOpen(false);
|
|
36885
|
-
},
|
|
36886
|
-
children: [
|
|
36887
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "trash", className: "w-3.5 h-3.5" }),
|
|
36888
|
-
" ",
|
|
36889
|
-
t("common.delete")
|
|
36890
|
-
]
|
|
36891
|
-
}
|
|
36892
|
-
),
|
|
36893
|
-
CHANGEABLE_TYPES.includes(block.type) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
36894
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "my-1 border-t border-border" }),
|
|
36895
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t("richBlockEditor.turnInto") }),
|
|
36896
|
-
CHANGEABLE_TYPES.filter((bt) => bt !== block.type).map((bt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
36897
|
-
Button,
|
|
36898
|
-
{
|
|
36899
|
-
type: "button",
|
|
36900
|
-
variant: "ghost",
|
|
36901
|
-
role: "menuitem",
|
|
36902
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
36903
|
-
onClick: () => {
|
|
36904
|
-
onChangeType(bt);
|
|
36905
|
-
setOpen(false);
|
|
36906
|
-
},
|
|
36907
|
-
children: t(BLOCK_TYPE_LABEL_KEY[bt])
|
|
36908
|
-
},
|
|
36909
|
-
bt
|
|
36910
|
-
))
|
|
36911
|
-
] })
|
|
36912
|
-
]
|
|
36913
|
-
}
|
|
36914
|
-
)
|
|
36915
|
-
] });
|
|
36785
|
+
node = node.parentNode;
|
|
36786
|
+
}
|
|
36787
|
+
return {
|
|
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
|
|
36796
|
+
};
|
|
36916
36797
|
}
|
|
36917
|
-
function
|
|
36918
|
-
tag,
|
|
36919
|
-
value,
|
|
36920
|
-
readOnly,
|
|
36921
|
-
placeholder,
|
|
36922
|
-
className,
|
|
36923
|
-
ariaLabel,
|
|
36924
|
-
onValueChange
|
|
36925
|
-
}) {
|
|
36926
|
-
const ref = React87.useRef(null);
|
|
36927
|
-
React87.useEffect(() => {
|
|
36928
|
-
const el = ref.current;
|
|
36929
|
-
if (!el) return;
|
|
36930
|
-
const isFocused = document.activeElement === el;
|
|
36931
|
-
if (!isFocused && el.textContent !== value) {
|
|
36932
|
-
el.textContent = value;
|
|
36933
|
-
}
|
|
36934
|
-
}, [value]);
|
|
36935
|
-
const handleInput = React87.useCallback(
|
|
36936
|
-
(e) => {
|
|
36937
|
-
onValueChange(e.currentTarget.textContent ?? "");
|
|
36938
|
-
},
|
|
36939
|
-
[onValueChange]
|
|
36940
|
-
);
|
|
36798
|
+
function ToolbarButton({ icon: IconCmp, label, active, onExec }) {
|
|
36941
36799
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
36942
|
-
|
|
36800
|
+
Button,
|
|
36943
36801
|
{
|
|
36944
|
-
|
|
36945
|
-
|
|
36946
|
-
|
|
36947
|
-
|
|
36948
|
-
|
|
36949
|
-
|
|
36950
|
-
"aria-multiline": "true",
|
|
36951
|
-
"data-placeholder": placeholder,
|
|
36802
|
+
type: "button",
|
|
36803
|
+
variant: "ghost",
|
|
36804
|
+
size: "sm",
|
|
36805
|
+
"aria-label": label,
|
|
36806
|
+
"aria-pressed": active,
|
|
36807
|
+
title: label,
|
|
36952
36808
|
className: cn(
|
|
36953
|
-
"
|
|
36954
|
-
"
|
|
36955
|
-
className
|
|
36809
|
+
"h-8 w-8 p-0 gap-0 justify-center",
|
|
36810
|
+
active && "bg-muted text-foreground"
|
|
36956
36811
|
),
|
|
36957
|
-
|
|
36812
|
+
onMouseDown: (e) => {
|
|
36813
|
+
e.preventDefault();
|
|
36814
|
+
onExec();
|
|
36815
|
+
},
|
|
36816
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(IconCmp, { size: 15 })
|
|
36958
36817
|
}
|
|
36959
36818
|
);
|
|
36960
36819
|
}
|
|
36961
|
-
|
|
36962
|
-
|
|
36963
|
-
|
|
36964
|
-
|
|
36965
|
-
|
|
36966
|
-
|
|
36967
|
-
|
|
36968
|
-
|
|
36969
|
-
|
|
36970
|
-
|
|
36971
|
-
|
|
36972
|
-
|
|
36973
|
-
|
|
36974
|
-
|
|
36975
|
-
|
|
36976
|
-
|
|
36977
|
-
|
|
36978
|
-
|
|
36979
|
-
|
|
36980
|
-
|
|
36981
|
-
|
|
36982
|
-
|
|
36983
|
-
|
|
36984
|
-
|
|
36985
|
-
|
|
36986
|
-
|
|
36987
|
-
|
|
36988
|
-
|
|
36989
|
-
|
|
36990
|
-
|
|
36991
|
-
|
|
36992
|
-
|
|
36993
|
-
|
|
36994
|
-
|
|
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
|
-
|
|
37034
|
-
|
|
37035
|
-
|
|
37036
|
-
|
|
37037
|
-
|
|
37038
|
-
|
|
37039
|
-
|
|
37040
|
-
|
|
37041
|
-
|
|
37042
|
-
|
|
37043
|
-
|
|
37044
|
-
|
|
37045
|
-
|
|
37046
|
-
|
|
37047
|
-
|
|
37048
|
-
|
|
37049
|
-
|
|
37050
|
-
|
|
37051
|
-
|
|
37052
|
-
|
|
37053
|
-
|
|
37054
|
-
|
|
37055
|
-
|
|
37056
|
-
|
|
37057
|
-
|
|
37058
|
-
|
|
37059
|
-
|
|
37060
|
-
|
|
37061
|
-
|
|
37062
|
-
|
|
37063
|
-
|
|
37064
|
-
|
|
37065
|
-
);
|
|
37066
|
-
|
|
37067
|
-
|
|
37068
|
-
|
|
37069
|
-
|
|
37070
|
-
|
|
37071
|
-
|
|
37072
|
-
|
|
37073
|
-
|
|
37074
|
-
|
|
37075
|
-
|
|
37076
|
-
|
|
37077
|
-
|
|
37078
|
-
|
|
37079
|
-
|
|
37080
|
-
|
|
37081
|
-
|
|
37082
|
-
|
|
37083
|
-
|
|
37084
|
-
|
|
37085
|
-
|
|
37086
|
-
|
|
37087
|
-
|
|
37088
|
-
|
|
37089
|
-
|
|
37090
|
-
|
|
37091
|
-
|
|
37092
|
-
|
|
37093
|
-
|
|
37094
|
-
|
|
37095
|
-
|
|
37096
|
-
|
|
37097
|
-
|
|
37098
|
-
|
|
37099
|
-
|
|
37100
|
-
|
|
37101
|
-
|
|
37102
|
-
|
|
37103
|
-
|
|
37104
|
-
|
|
37105
|
-
|
|
37106
|
-
|
|
37107
|
-
|
|
37108
|
-
|
|
37109
|
-
|
|
37110
|
-
|
|
37111
|
-
|
|
37112
|
-
|
|
37113
|
-
|
|
37114
|
-
|
|
37115
|
-
|
|
37116
|
-
|
|
37117
|
-
|
|
37118
|
-
|
|
37119
|
-
|
|
37120
|
-
|
|
37121
|
-
|
|
37122
|
-
|
|
37123
|
-
|
|
37124
|
-
|
|
37125
|
-
|
|
37126
|
-
|
|
37127
|
-
|
|
37128
|
-
|
|
37129
|
-
|
|
37130
|
-
|
|
37131
|
-
|
|
37132
|
-
|
|
37133
|
-
|
|
37134
|
-
|
|
37135
|
-
|
|
37136
|
-
|
|
37137
|
-
|
|
37138
|
-
|
|
37139
|
-
|
|
37140
|
-
|
|
37141
|
-
|
|
37142
|
-
|
|
37143
|
-
|
|
37144
|
-
|
|
37145
|
-
|
|
37146
|
-
|
|
37147
|
-
|
|
37148
|
-
|
|
37149
|
-
|
|
37150
|
-
|
|
37151
|
-
|
|
37152
|
-
|
|
37153
|
-
|
|
37154
|
-
|
|
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 ?? "") } })
|
|
37155
37098
|
] });
|
|
37156
37099
|
}
|
|
37157
|
-
|
|
37158
|
-
|
|
37159
|
-
|
|
37160
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
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(
|
|
37161
37103
|
Box,
|
|
37162
37104
|
{
|
|
37163
|
-
|
|
37105
|
+
role: "toolbar",
|
|
37106
|
+
"aria-label": t("richTextEditor.editorToolbar"),
|
|
37164
37107
|
className: cn(
|
|
37165
|
-
"
|
|
37166
|
-
|
|
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"
|
|
37167
37110
|
),
|
|
37168
37111
|
children: [
|
|
37169
|
-
|
|
37170
|
-
|
|
37171
|
-
|
|
37172
|
-
|
|
37173
|
-
|
|
37174
|
-
|
|
37175
|
-
|
|
37176
|
-
|
|
37177
|
-
|
|
37178
|
-
|
|
37179
|
-
|
|
37180
|
-
|
|
37181
|
-
|
|
37182
|
-
|
|
37183
|
-
|
|
37184
|
-
|
|
37185
|
-
type: "button",
|
|
37186
|
-
variant: "ghost",
|
|
37187
|
-
"aria-label": t("richBlockEditor.aria.removeListItem"),
|
|
37188
|
-
className: cn(
|
|
37189
|
-
"h-5 w-5 shrink-0 rounded-sm text-muted-foreground p-0 gap-0",
|
|
37190
|
-
"opacity-0 group-hover/item:opacity-100 hover:bg-muted hover:text-foreground"
|
|
37191
|
-
),
|
|
37192
|
-
onClick: () => removeListItem(child.id),
|
|
37193
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "trash", className: "w-3 h-3" })
|
|
37194
|
-
}
|
|
37195
|
-
)
|
|
37196
|
-
] }, child.id)),
|
|
37197
|
-
!readOnly && showAffordances && /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "li", className: "list-none pl-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37198
|
-
Button,
|
|
37199
|
-
{
|
|
37200
|
-
type: "button",
|
|
37201
|
-
variant: "ghost",
|
|
37202
|
-
className: cn(
|
|
37203
|
-
"inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
37204
|
-
"hover:text-foreground p-0 h-auto"
|
|
37205
|
-
),
|
|
37206
|
-
onClick: addListItem,
|
|
37207
|
-
children: [
|
|
37208
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "w-3 h-3" }),
|
|
37209
|
-
" ",
|
|
37210
|
-
t("richBlockEditor.addItem")
|
|
37211
|
-
]
|
|
37212
|
-
}
|
|
37213
|
-
) })
|
|
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 })
|
|
37214
37128
|
]
|
|
37215
37129
|
}
|
|
37216
|
-
)
|
|
37217
|
-
|
|
37218
|
-
|
|
37219
|
-
default:
|
|
37220
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37221
|
-
Editable,
|
|
37130
|
+
),
|
|
37131
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37132
|
+
Box,
|
|
37222
37133
|
{
|
|
37223
|
-
|
|
37224
|
-
|
|
37225
|
-
|
|
37226
|
-
|
|
37227
|
-
|
|
37228
|
-
|
|
37229
|
-
|
|
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
|
|
37230
37153
|
}
|
|
37231
|
-
)
|
|
37232
|
-
|
|
37154
|
+
)
|
|
37155
|
+
] });
|
|
37156
|
+
};
|
|
37157
|
+
RichTextEditor.displayName = "RichTextEditor";
|
|
37158
|
+
}
|
|
37159
|
+
});
|
|
37160
|
+
function renderIconInput4(icon, props) {
|
|
37161
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, ...props });
|
|
37162
|
+
}
|
|
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();
|
|
37182
|
+
const { t } = hooks.useTranslate();
|
|
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 });
|
|
37233
37192
|
};
|
|
37234
|
-
|
|
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"
|
|
37221
|
+
}
|
|
37222
|
+
) : titleCommitEvent ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
37235
37223
|
Box,
|
|
37236
37224
|
{
|
|
37237
|
-
|
|
37238
|
-
|
|
37239
|
-
|
|
37240
|
-
),
|
|
37241
|
-
|
|
37242
|
-
|
|
37243
|
-
|
|
37244
|
-
|
|
37245
|
-
|
|
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,
|
|
37246
37258
|
{
|
|
37247
|
-
|
|
37248
|
-
|
|
37249
|
-
|
|
37250
|
-
|
|
37251
|
-
|
|
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
|
+
}))
|
|
37252
37281
|
}
|
|
37253
|
-
)
|
|
37254
|
-
|
|
37255
|
-
|
|
37256
|
-
}
|
|
37257
|
-
|
|
37282
|
+
)
|
|
37283
|
+
] }) })
|
|
37284
|
+
] }),
|
|
37285
|
+
editing ? /* @__PURE__ */ jsxRuntime.jsx(RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
37286
|
+
Box,
|
|
37287
|
+
{
|
|
37288
|
+
onClick: emitWithId(editEvent),
|
|
37289
|
+
className: cn(
|
|
37290
|
+
"rounded-md px-1 -mx-1 min-h-[16rem]",
|
|
37291
|
+
editEvent && "cursor-text transition-colors hover:bg-muted/30"
|
|
37292
|
+
),
|
|
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") || "") })
|
|
37295
|
+
}
|
|
37296
|
+
)
|
|
37297
|
+
] }) });
|
|
37258
37298
|
}
|
|
37259
|
-
var
|
|
37260
|
-
|
|
37261
|
-
"components/core/molecules/RichBlockEditor.tsx"() {
|
|
37299
|
+
var init_DocumentPanel = __esm({
|
|
37300
|
+
"components/core/molecules/DocumentPanel.tsx"() {
|
|
37262
37301
|
"use client";
|
|
37263
37302
|
init_cn();
|
|
37264
|
-
|
|
37303
|
+
init_useEventBus();
|
|
37304
|
+
init_Box();
|
|
37305
|
+
init_Stack();
|
|
37265
37306
|
init_Typography();
|
|
37266
37307
|
init_Button();
|
|
37267
|
-
|
|
37268
|
-
init_Divider();
|
|
37269
|
-
init_Input();
|
|
37308
|
+
init_Card();
|
|
37270
37309
|
init_Icon();
|
|
37271
|
-
|
|
37272
|
-
|
|
37273
|
-
|
|
37274
|
-
|
|
37275
|
-
|
|
37276
|
-
|
|
37277
|
-
|
|
37278
|
-
|
|
37279
|
-
|
|
37280
|
-
|
|
37281
|
-
|
|
37282
|
-
|
|
37283
|
-
|
|
37284
|
-
|
|
37285
|
-
|
|
37286
|
-
|
|
37287
|
-
|
|
37288
|
-
|
|
37289
|
-
|
|
37290
|
-
|
|
37291
|
-
|
|
37292
|
-
|
|
37293
|
-
|
|
37294
|
-
|
|
37295
|
-
|
|
37296
|
-
|
|
37297
|
-
|
|
37298
|
-
|
|
37299
|
-
|
|
37300
|
-
|
|
37301
|
-
|
|
37302
|
-
|
|
37303
|
-
|
|
37304
|
-
|
|
37305
|
-
|
|
37306
|
-
|
|
37307
|
-
|
|
37308
|
-
|
|
37309
|
-
|
|
37310
|
-
|
|
37311
|
-
|
|
37312
|
-
|
|
37313
|
-
|
|
37314
|
-
|
|
37315
|
-
|
|
37316
|
-
|
|
37317
|
-
|
|
37318
|
-
|
|
37319
|
-
|
|
37320
|
-
|
|
37321
|
-
|
|
37322
|
-
|
|
37323
|
-
|
|
37324
|
-
|
|
37325
|
-
|
|
37326
|
-
|
|
37327
|
-
|
|
37328
|
-
|
|
37329
|
-
|
|
37330
|
-
const [blocks, setBlocks] = React87.useState(
|
|
37331
|
-
() => normalizeBlocks(initialBlocks)
|
|
37332
|
-
);
|
|
37333
|
-
const onChangeRef = React87.useRef(onChange);
|
|
37334
|
-
React87.useEffect(() => {
|
|
37335
|
-
onChangeRef.current = onChange;
|
|
37336
|
-
}, [onChange]);
|
|
37337
|
-
const eventBus = useEventBus();
|
|
37338
|
-
const changeEventRef = React87.useRef(changeEvent);
|
|
37339
|
-
React87.useEffect(() => {
|
|
37340
|
-
changeEventRef.current = changeEvent;
|
|
37341
|
-
}, [changeEvent]);
|
|
37342
|
-
const commit = React87.useCallback((next) => {
|
|
37343
|
-
setBlocks(next);
|
|
37344
|
-
onChangeRef.current?.(next);
|
|
37345
|
-
const evt = changeEventRef.current;
|
|
37346
|
-
if (evt) eventBus.emit(`UI:${evt}`, { blocks: next });
|
|
37347
|
-
}, [eventBus]);
|
|
37348
|
-
const handleAppend = React87.useCallback(
|
|
37349
|
-
(type) => {
|
|
37350
|
-
if (readOnly) return;
|
|
37351
|
-
commit([...blocks, createBlock(type)]);
|
|
37352
|
-
},
|
|
37353
|
-
[blocks, commit, readOnly]
|
|
37354
|
-
);
|
|
37355
|
-
const handleUpdate = React87.useCallback(
|
|
37356
|
-
(id, updater) => {
|
|
37357
|
-
commit(replaceBlock(blocks, id, updater));
|
|
37358
|
-
},
|
|
37359
|
-
[blocks, commit]
|
|
37360
|
-
);
|
|
37361
|
-
const handleDelete = React87.useCallback(
|
|
37362
|
-
(id) => {
|
|
37363
|
-
const next = removeBlock(blocks, id);
|
|
37364
|
-
commit(next.length > 0 ? next : [createBlock("paragraph")]);
|
|
37365
|
-
},
|
|
37366
|
-
[blocks, commit]
|
|
37367
|
-
);
|
|
37368
|
-
const handleDuplicate = React87.useCallback(
|
|
37369
|
-
(id) => {
|
|
37370
|
-
const target = blocks.find((b) => b.id === id);
|
|
37371
|
-
if (!target) return;
|
|
37372
|
-
commit(insertAfter(blocks, id, duplicateBlock(target)));
|
|
37373
|
-
},
|
|
37374
|
-
[blocks, commit]
|
|
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 });
|
|
37317
|
+
}
|
|
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
|
|
37343
|
+
}) {
|
|
37344
|
+
const eventBus = useEventBus();
|
|
37345
|
+
const { t } = hooks.useTranslate();
|
|
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
|
+
}
|
|
37375
37369
|
);
|
|
37376
|
-
|
|
37377
|
-
|
|
37378
|
-
|
|
37379
|
-
|
|
37380
|
-
|
|
37381
|
-
|
|
37382
|
-
|
|
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
|
+
}
|
|
37383
37382
|
);
|
|
37384
|
-
|
|
37385
|
-
|
|
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)) });
|
|
37390
|
+
}
|
|
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,
|
|
37386
37397
|
{
|
|
37387
|
-
|
|
37388
|
-
|
|
37389
|
-
|
|
37390
|
-
|
|
37391
|
-
|
|
37392
|
-
|
|
37393
|
-
|
|
37394
|
-
|
|
37395
|
-
|
|
37396
|
-
|
|
37397
|
-
|
|
37398
|
-
|
|
37399
|
-
|
|
37400
|
-
|
|
37401
|
-
|
|
37402
|
-
|
|
37403
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
37404
|
-
Button,
|
|
37405
|
-
{
|
|
37406
|
-
type: "button",
|
|
37407
|
-
variant: "ghost",
|
|
37408
|
-
size: "sm",
|
|
37409
|
-
"aria-label": t("richBlockEditor.insertEntry", { label: entryLabel }),
|
|
37410
|
-
title: entryLabel,
|
|
37411
|
-
onClick: () => handleAppend(entry.type),
|
|
37412
|
-
children: [
|
|
37413
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon2, { size: 14 }),
|
|
37414
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
|
|
37415
|
-
]
|
|
37416
|
-
},
|
|
37417
|
-
entry.type
|
|
37418
|
-
);
|
|
37419
|
-
})
|
|
37420
|
-
}
|
|
37421
|
-
),
|
|
37422
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1 px-3 py-3", children: blocks.map((block) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
37423
|
-
BlockRow,
|
|
37424
|
-
{
|
|
37425
|
-
block,
|
|
37426
|
-
readOnly,
|
|
37427
|
-
showAffordances: enableBlocks,
|
|
37428
|
-
placeholder,
|
|
37429
|
-
onUpdate: (updater) => handleUpdate(block.id, updater),
|
|
37430
|
-
onDelete: () => handleDelete(block.id),
|
|
37431
|
-
onDuplicate: () => handleDuplicate(block.id),
|
|
37432
|
-
onChangeType: (type) => handleChangeType(block.id, type)
|
|
37433
|
-
},
|
|
37434
|
-
block.id
|
|
37435
|
-
)) })
|
|
37436
|
-
]
|
|
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}`
|
|
37437
37414
|
}
|
|
37438
37415
|
);
|
|
37439
|
-
}
|
|
37440
|
-
|
|
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) : "" });
|
|
37432
|
+
}
|
|
37433
|
+
},
|
|
37434
|
+
"data-testid": `document-property-${name}`,
|
|
37435
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "break-words", children: shown })
|
|
37436
|
+
}
|
|
37437
|
+
);
|
|
37438
|
+
};
|
|
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
|
+
] }) });
|
|
37453
|
+
}
|
|
37454
|
+
var init_DocumentDetails = __esm({
|
|
37455
|
+
"components/core/molecules/DocumentDetails.tsx"() {
|
|
37456
|
+
"use client";
|
|
37457
|
+
init_cn();
|
|
37458
|
+
init_format();
|
|
37459
|
+
init_getNestedValue();
|
|
37460
|
+
init_useEventBus();
|
|
37461
|
+
init_Box();
|
|
37462
|
+
init_Stack();
|
|
37463
|
+
init_Typography();
|
|
37464
|
+
init_Badge();
|
|
37465
|
+
init_Card();
|
|
37466
|
+
init_Icon();
|
|
37467
|
+
init_Input();
|
|
37468
|
+
init_Select();
|
|
37469
|
+
init_Switch();
|
|
37441
37470
|
}
|
|
37442
37471
|
});
|
|
37443
37472
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
@@ -42386,8 +42415,8 @@ var init_DataTable = __esm({
|
|
|
42386
42415
|
DataTable.displayName = "DataTable";
|
|
42387
42416
|
}
|
|
42388
42417
|
});
|
|
42389
|
-
function getBadgeVariant(
|
|
42390
|
-
const name =
|
|
42418
|
+
function getBadgeVariant(fieldName2, value) {
|
|
42419
|
+
const name = fieldName2.toLowerCase();
|
|
42391
42420
|
const val = String(value).toLowerCase();
|
|
42392
42421
|
if (name.includes("status")) {
|
|
42393
42422
|
if (val.includes("complete") || val.includes("done") || val.includes("active"))
|
|
@@ -42403,12 +42432,12 @@ function getBadgeVariant(fieldName, value) {
|
|
|
42403
42432
|
}
|
|
42404
42433
|
return "default";
|
|
42405
42434
|
}
|
|
42406
|
-
function formatFieldValue2(value,
|
|
42435
|
+
function formatFieldValue2(value, fieldName2) {
|
|
42407
42436
|
if (typeof value === "number") {
|
|
42408
|
-
if (
|
|
42437
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
42409
42438
|
return `${value}%`;
|
|
42410
42439
|
}
|
|
42411
|
-
if (
|
|
42440
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
42412
42441
|
return `$${value.toLocaleString()}`;
|
|
42413
42442
|
}
|
|
42414
42443
|
return value.toLocaleString();
|
|
@@ -42418,7 +42447,7 @@ function formatFieldValue2(value, fieldName) {
|
|
|
42418
42447
|
}
|
|
42419
42448
|
return String(value);
|
|
42420
42449
|
}
|
|
42421
|
-
function renderRichFieldValue(value,
|
|
42450
|
+
function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
42422
42451
|
if (value === void 0 || value === null) return "\u2014";
|
|
42423
42452
|
const str = String(value);
|
|
42424
42453
|
switch (fieldType) {
|
|
@@ -42429,7 +42458,7 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
42429
42458
|
"img",
|
|
42430
42459
|
{
|
|
42431
42460
|
src: str,
|
|
42432
|
-
alt: formatFieldLabel(
|
|
42461
|
+
alt: formatFieldLabel(fieldName2),
|
|
42433
42462
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
42434
42463
|
loading: "lazy"
|
|
42435
42464
|
}
|
|
@@ -42564,9 +42593,9 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
42564
42593
|
return /* @__PURE__ */ jsxRuntime.jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
|
|
42565
42594
|
default:
|
|
42566
42595
|
if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
|
|
42567
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: getBadgeVariant(
|
|
42596
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: getBadgeVariant(fieldName2, str), children: humanizeEnumValue(str) });
|
|
42568
42597
|
}
|
|
42569
|
-
return formatFieldValue2(value,
|
|
42598
|
+
return formatFieldValue2(value, fieldName2);
|
|
42570
42599
|
}
|
|
42571
42600
|
}
|
|
42572
42601
|
function normalizeFieldDefs(fields) {
|
|
@@ -43036,16 +43065,11 @@ var init_DetailPanel = __esm({
|
|
|
43036
43065
|
footer
|
|
43037
43066
|
] })
|
|
43038
43067
|
] }) });
|
|
43039
|
-
|
|
43040
|
-
Box,
|
|
43041
|
-
|
|
43042
|
-
|
|
43043
|
-
|
|
43044
|
-
className
|
|
43045
|
-
),
|
|
43046
|
-
children: content
|
|
43047
|
-
}
|
|
43048
|
-
);
|
|
43068
|
+
if (!slideOver) {
|
|
43069
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: content });
|
|
43070
|
+
}
|
|
43071
|
+
const panel = /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("fixed inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
|
|
43072
|
+
return typeof document === "undefined" ? panel : reactDom.createPortal(panel, document.body);
|
|
43049
43073
|
};
|
|
43050
43074
|
DetailPanel.displayName = "DetailPanel";
|
|
43051
43075
|
}
|
|
@@ -43414,7 +43438,21 @@ var init_Form = __esm({
|
|
|
43414
43438
|
const normalizedInitialData = React87__namespace.default.useMemo(() => {
|
|
43415
43439
|
const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
|
|
43416
43440
|
const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
|
|
43417
|
-
|
|
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;
|
|
43418
43456
|
}, [entity, initialData]);
|
|
43419
43457
|
const entityDerivedFields = React87__namespace.default.useMemo(() => {
|
|
43420
43458
|
if (fields && fields.length > 0) return void 0;
|
|
@@ -43543,8 +43581,8 @@ var init_Form = __esm({
|
|
|
43543
43581
|
checkViolations(name, newFormData);
|
|
43544
43582
|
};
|
|
43545
43583
|
const isFieldVisible = React87__namespace.default.useCallback(
|
|
43546
|
-
(
|
|
43547
|
-
const condition = conditionalFields[
|
|
43584
|
+
(fieldName2) => {
|
|
43585
|
+
const condition = conditionalFields[fieldName2];
|
|
43548
43586
|
if (!condition) return true;
|
|
43549
43587
|
return Boolean(evaluateFormExpression(condition, evalContext));
|
|
43550
43588
|
},
|
|
@@ -43590,9 +43628,9 @@ var init_Form = __esm({
|
|
|
43590
43628
|
};
|
|
43591
43629
|
const handleInvalid = (e) => {
|
|
43592
43630
|
const target = e.target;
|
|
43593
|
-
const
|
|
43631
|
+
const fieldName2 = target.getAttribute("data-field-name") ?? target.name ?? "";
|
|
43594
43632
|
const fieldMessage = target.validationMessage || "Invalid value";
|
|
43595
|
-
debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
|
|
43633
|
+
debug("forms", "invalid", { mode: formMode, fieldName: fieldName2, fieldMessage });
|
|
43596
43634
|
queueMicrotask(() => {
|
|
43597
43635
|
const form = formRef.current;
|
|
43598
43636
|
if (!form) return;
|
|
@@ -43628,22 +43666,22 @@ var init_Form = __esm({
|
|
|
43628
43666
|
};
|
|
43629
43667
|
const renderField = React87__namespace.default.useCallback(
|
|
43630
43668
|
(field) => {
|
|
43631
|
-
const
|
|
43632
|
-
if (!
|
|
43633
|
-
if (!isFieldVisible(
|
|
43669
|
+
const fieldName2 = field.name || field.field;
|
|
43670
|
+
if (!fieldName2) return null;
|
|
43671
|
+
if (!isFieldVisible(fieldName2)) {
|
|
43634
43672
|
return null;
|
|
43635
43673
|
}
|
|
43636
43674
|
const inputType = determineInputType(field);
|
|
43637
|
-
const label = field.label ||
|
|
43638
|
-
const currentValue = formData[
|
|
43639
|
-
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: [
|
|
43640
43678
|
inputType !== "checkbox" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { as: "label", variant: "label", weight: "bold", children: [
|
|
43641
43679
|
label,
|
|
43642
43680
|
field.required && /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
|
|
43643
43681
|
] }),
|
|
43644
|
-
renderFieldInput(field,
|
|
43682
|
+
renderFieldInput(field, fieldName2, inputType, currentValue, label),
|
|
43645
43683
|
field.hint && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
|
|
43646
|
-
] },
|
|
43684
|
+
] }, fieldName2);
|
|
43647
43685
|
},
|
|
43648
43686
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
43649
43687
|
);
|
|
@@ -43672,8 +43710,8 @@ var init_Form = __esm({
|
|
|
43672
43710
|
}
|
|
43673
43711
|
return field;
|
|
43674
43712
|
}).map((field) => {
|
|
43675
|
-
const
|
|
43676
|
-
const override = fieldOverrides?.find((o) => o.name ===
|
|
43713
|
+
const fieldName2 = field.name || field.field;
|
|
43714
|
+
const override = fieldOverrides?.find((o) => o.name === fieldName2);
|
|
43677
43715
|
if (!override) return field;
|
|
43678
43716
|
return {
|
|
43679
43717
|
...field,
|
|
@@ -43729,11 +43767,11 @@ var init_Form = __esm({
|
|
|
43729
43767
|
] }, section.id);
|
|
43730
43768
|
}).filter(Boolean);
|
|
43731
43769
|
}, [sections, isSectionVisible, collapsedSections, renderField, gap]);
|
|
43732
|
-
function renderFieldInput(field,
|
|
43770
|
+
function renderFieldInput(field, fieldName2, inputType, currentValue, label) {
|
|
43733
43771
|
const commonProps = {
|
|
43734
|
-
id:
|
|
43735
|
-
name:
|
|
43736
|
-
"data-field-name":
|
|
43772
|
+
id: fieldName2,
|
|
43773
|
+
name: fieldName2,
|
|
43774
|
+
"data-field-name": fieldName2,
|
|
43737
43775
|
required: field.required,
|
|
43738
43776
|
disabled: isLoading,
|
|
43739
43777
|
placeholder: field.placeholder,
|
|
@@ -43747,7 +43785,7 @@ var init_Form = __esm({
|
|
|
43747
43785
|
...commonProps,
|
|
43748
43786
|
label: label + (field.required ? " *" : ""),
|
|
43749
43787
|
checked: Boolean(currentValue),
|
|
43750
|
-
onChange: (e) => handleChange(
|
|
43788
|
+
onChange: (e) => handleChange(fieldName2, e.target.checked)
|
|
43751
43789
|
}
|
|
43752
43790
|
);
|
|
43753
43791
|
case "textarea":
|
|
@@ -43756,7 +43794,7 @@ var init_Form = __esm({
|
|
|
43756
43794
|
{
|
|
43757
43795
|
...commonProps,
|
|
43758
43796
|
value: String(currentValue),
|
|
43759
|
-
onChange: (e) => handleChange(
|
|
43797
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43760
43798
|
minLength: field.min,
|
|
43761
43799
|
maxLength: field.max
|
|
43762
43800
|
}
|
|
@@ -43769,14 +43807,14 @@ var init_Form = __esm({
|
|
|
43769
43807
|
...commonProps,
|
|
43770
43808
|
options,
|
|
43771
43809
|
value: String(currentValue),
|
|
43772
|
-
onValueChange: (v) => handleChange(
|
|
43810
|
+
onValueChange: (v) => handleChange(fieldName2, v),
|
|
43773
43811
|
placeholder: field.placeholder || `Select ${label}...`
|
|
43774
43812
|
}
|
|
43775
43813
|
);
|
|
43776
43814
|
}
|
|
43777
43815
|
case "relation": {
|
|
43778
|
-
const relationOptions = relationsData[
|
|
43779
|
-
const relationLoading = relationsLoading[
|
|
43816
|
+
const relationOptions = relationsData[fieldName2] || [];
|
|
43817
|
+
const relationLoading = relationsLoading[fieldName2] || false;
|
|
43780
43818
|
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
43781
43819
|
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
43782
43820
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -43788,7 +43826,7 @@ var init_Form = __esm({
|
|
|
43788
43826
|
clearable: true,
|
|
43789
43827
|
options: [...relationOptions],
|
|
43790
43828
|
value: selectedValues,
|
|
43791
|
-
onValueChange: (value) => handleChange(
|
|
43829
|
+
onValueChange: (value) => handleChange(fieldName2, Array.isArray(value) ? value : [value]),
|
|
43792
43830
|
placeholder: field.placeholder || `Select ${label}...`
|
|
43793
43831
|
}
|
|
43794
43832
|
);
|
|
@@ -43798,7 +43836,7 @@ var init_Form = __esm({
|
|
|
43798
43836
|
{
|
|
43799
43837
|
...commonProps,
|
|
43800
43838
|
value: currentValue ? String(currentValue) : void 0,
|
|
43801
|
-
onChange: (value) => handleChange(
|
|
43839
|
+
onChange: (value) => handleChange(fieldName2, value),
|
|
43802
43840
|
options: relationOptions,
|
|
43803
43841
|
isLoading: relationLoading,
|
|
43804
43842
|
placeholder: field.placeholder || `Select ${label}...`,
|
|
@@ -43815,7 +43853,7 @@ var init_Form = __esm({
|
|
|
43815
43853
|
placeholder: field.placeholder,
|
|
43816
43854
|
disabled: isLoading,
|
|
43817
43855
|
value: arrayValue,
|
|
43818
|
-
onChange: (next) => handleChange(
|
|
43856
|
+
onChange: (next) => handleChange(fieldName2, [...next])
|
|
43819
43857
|
}
|
|
43820
43858
|
);
|
|
43821
43859
|
}
|
|
@@ -43827,7 +43865,7 @@ var init_Form = __esm({
|
|
|
43827
43865
|
type: "number",
|
|
43828
43866
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
43829
43867
|
onChange: (e) => handleChange(
|
|
43830
|
-
|
|
43868
|
+
fieldName2,
|
|
43831
43869
|
e.target.value ? Number(e.target.value) : void 0
|
|
43832
43870
|
),
|
|
43833
43871
|
min: field.min,
|
|
@@ -43844,7 +43882,7 @@ var init_Form = __esm({
|
|
|
43844
43882
|
icon: LucideIcons2.DollarSign,
|
|
43845
43883
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
43846
43884
|
onChange: (e) => handleChange(
|
|
43847
|
-
|
|
43885
|
+
fieldName2,
|
|
43848
43886
|
e.target.value ? Number(e.target.value) : void 0
|
|
43849
43887
|
),
|
|
43850
43888
|
min: field.min,
|
|
@@ -43862,7 +43900,7 @@ var init_Form = __esm({
|
|
|
43862
43900
|
const f3 = files[0];
|
|
43863
43901
|
if (!f3) return;
|
|
43864
43902
|
const reader = new FileReader();
|
|
43865
|
-
reader.onload = () => handleChange(
|
|
43903
|
+
reader.onload = () => handleChange(fieldName2, {
|
|
43866
43904
|
name: f3.name,
|
|
43867
43905
|
mimeType: f3.type,
|
|
43868
43906
|
sizeBytes: f3.size,
|
|
@@ -43879,7 +43917,7 @@ var init_Form = __esm({
|
|
|
43879
43917
|
...commonProps,
|
|
43880
43918
|
type: "date",
|
|
43881
43919
|
value: formatDateValue(currentValue),
|
|
43882
|
-
onChange: (e) => handleChange(
|
|
43920
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
43883
43921
|
}
|
|
43884
43922
|
);
|
|
43885
43923
|
case "datetime-local":
|
|
@@ -43889,7 +43927,7 @@ var init_Form = __esm({
|
|
|
43889
43927
|
...commonProps,
|
|
43890
43928
|
type: "datetime-local",
|
|
43891
43929
|
value: formatDateTimeValue(currentValue),
|
|
43892
|
-
onChange: (e) => handleChange(
|
|
43930
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
43893
43931
|
}
|
|
43894
43932
|
);
|
|
43895
43933
|
case "email":
|
|
@@ -43899,7 +43937,7 @@ var init_Form = __esm({
|
|
|
43899
43937
|
...commonProps,
|
|
43900
43938
|
type: "email",
|
|
43901
43939
|
value: String(currentValue),
|
|
43902
|
-
onChange: (e) => handleChange(
|
|
43940
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43903
43941
|
minLength: field.min,
|
|
43904
43942
|
maxLength: field.max
|
|
43905
43943
|
}
|
|
@@ -43911,7 +43949,7 @@ var init_Form = __esm({
|
|
|
43911
43949
|
...commonProps,
|
|
43912
43950
|
type: "url",
|
|
43913
43951
|
value: String(currentValue),
|
|
43914
|
-
onChange: (e) => handleChange(
|
|
43952
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43915
43953
|
minLength: field.min,
|
|
43916
43954
|
maxLength: field.max
|
|
43917
43955
|
}
|
|
@@ -43923,7 +43961,7 @@ var init_Form = __esm({
|
|
|
43923
43961
|
...commonProps,
|
|
43924
43962
|
type: "password",
|
|
43925
43963
|
value: String(currentValue),
|
|
43926
|
-
onChange: (e) => handleChange(
|
|
43964
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43927
43965
|
minLength: field.min,
|
|
43928
43966
|
maxLength: field.max
|
|
43929
43967
|
}
|
|
@@ -43936,7 +43974,7 @@ var init_Form = __esm({
|
|
|
43936
43974
|
...commonProps,
|
|
43937
43975
|
type: "text",
|
|
43938
43976
|
value: String(currentValue),
|
|
43939
|
-
onChange: (e) => handleChange(
|
|
43977
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43940
43978
|
minLength: field.min,
|
|
43941
43979
|
maxLength: field.max
|
|
43942
43980
|
}
|
|
@@ -44293,7 +44331,7 @@ function entityFieldsFromListItem(item) {
|
|
|
44293
44331
|
}
|
|
44294
44332
|
return result;
|
|
44295
44333
|
}
|
|
44296
|
-
function getStatusStyle(
|
|
44334
|
+
function getStatusStyle(fieldName2, value) {
|
|
44297
44335
|
const val = String(value).toLowerCase();
|
|
44298
44336
|
if (val.includes("complete") || val.includes("done"))
|
|
44299
44337
|
return STATUS_STYLES.complete;
|
|
@@ -44309,12 +44347,12 @@ function getStatusStyle(fieldName, value) {
|
|
|
44309
44347
|
if (val.includes("low")) return STATUS_STYLES.low;
|
|
44310
44348
|
return STATUS_STYLES.default;
|
|
44311
44349
|
}
|
|
44312
|
-
function formatValue3(value,
|
|
44350
|
+
function formatValue3(value, fieldName2) {
|
|
44313
44351
|
if (typeof value === "number") {
|
|
44314
|
-
if (
|
|
44352
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
44315
44353
|
return `${value}%`;
|
|
44316
44354
|
}
|
|
44317
|
-
if (
|
|
44355
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
44318
44356
|
return new Intl.NumberFormat("en-US", {
|
|
44319
44357
|
style: "currency",
|
|
44320
44358
|
currency: "USD",
|
|
@@ -44337,8 +44375,8 @@ function formatValue3(value, fieldName) {
|
|
|
44337
44375
|
}
|
|
44338
44376
|
return String(value);
|
|
44339
44377
|
}
|
|
44340
|
-
function formatFieldLabel2(
|
|
44341
|
-
return humanizeFieldName(
|
|
44378
|
+
function formatFieldLabel2(fieldName2) {
|
|
44379
|
+
return humanizeFieldName(fieldName2).replace(/\sId$/, "").trim();
|
|
44342
44380
|
}
|
|
44343
44381
|
var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
|
|
44344
44382
|
var init_List = __esm({
|
|
@@ -44406,9 +44444,9 @@ var init_List = __esm({
|
|
|
44406
44444
|
};
|
|
44407
44445
|
StatusBadge = ({
|
|
44408
44446
|
value,
|
|
44409
|
-
fieldName
|
|
44447
|
+
fieldName: fieldName2
|
|
44410
44448
|
}) => {
|
|
44411
|
-
const style = getStatusStyle(
|
|
44449
|
+
const style = getStatusStyle(fieldName2, value);
|
|
44412
44450
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
44413
44451
|
Typography,
|
|
44414
44452
|
{
|
|
@@ -47321,8 +47359,8 @@ var init_StatCard = __esm({
|
|
|
47321
47359
|
return items.length;
|
|
47322
47360
|
}
|
|
47323
47361
|
if (field.includes(":")) {
|
|
47324
|
-
const [
|
|
47325
|
-
return items.filter((item) => item[
|
|
47362
|
+
const [fieldName2, fieldValue] = field.split(":");
|
|
47363
|
+
return items.filter((item) => item[fieldName2] === fieldValue).length;
|
|
47326
47364
|
}
|
|
47327
47365
|
const fieldExistsOnItems = items.some((item) => field in item);
|
|
47328
47366
|
if (fieldExistsOnItems) {
|
|
@@ -48842,6 +48880,8 @@ var init_component_registry_generated = __esm({
|
|
|
48842
48880
|
init_DocSearch();
|
|
48843
48881
|
init_DocSidebar();
|
|
48844
48882
|
init_DocTOC();
|
|
48883
|
+
init_DocumentDetails();
|
|
48884
|
+
init_DocumentPanel();
|
|
48845
48885
|
init_DocumentViewer();
|
|
48846
48886
|
init_DrawFxLayer();
|
|
48847
48887
|
init_DrawGroup();
|
|
@@ -48951,7 +48991,7 @@ var init_component_registry_generated = __esm({
|
|
|
48951
48991
|
init_RelationSelect();
|
|
48952
48992
|
init_RepeatableFormSection();
|
|
48953
48993
|
init_ReplyTree();
|
|
48954
|
-
|
|
48994
|
+
init_RichTextEditor();
|
|
48955
48995
|
init_RuntimeDebugger2();
|
|
48956
48996
|
init_ScaledDiagram();
|
|
48957
48997
|
init_ScoreDisplay();
|
|
@@ -49114,6 +49154,8 @@ var init_component_registry_generated = __esm({
|
|
|
49114
49154
|
"DocSearch": DocSearch,
|
|
49115
49155
|
"DocSidebar": DocSidebar,
|
|
49116
49156
|
"DocTOC": DocTOC,
|
|
49157
|
+
"DocumentDetails": DocumentDetails,
|
|
49158
|
+
"DocumentPanel": DocumentPanel,
|
|
49117
49159
|
"DocumentViewer": DocumentViewer,
|
|
49118
49160
|
"DrawFxLayer": DrawFxLayer,
|
|
49119
49161
|
"DrawGroup": DrawGroup,
|
|
@@ -49225,7 +49267,7 @@ var init_component_registry_generated = __esm({
|
|
|
49225
49267
|
"RelationSelect": RelationSelect,
|
|
49226
49268
|
"RepeatableFormSection": RepeatableFormSection,
|
|
49227
49269
|
"ReplyTree": ReplyTree,
|
|
49228
|
-
"
|
|
49270
|
+
"RichTextEditor": RichTextEditor,
|
|
49229
49271
|
"RuntimeDebugger": RuntimeDebugger,
|
|
49230
49272
|
"ScaledDiagram": ScaledDiagram,
|
|
49231
49273
|
"ScoreDisplay": ScoreDisplay,
|
|
@@ -49379,10 +49421,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
49379
49421
|
}
|
|
49380
49422
|
if (field && typeof field === "object" && !Array.isArray(field) && !React87__namespace.default.isValidElement(field) && !(field instanceof Date)) {
|
|
49381
49423
|
const obj = field;
|
|
49382
|
-
const
|
|
49383
|
-
if (!
|
|
49424
|
+
const fieldName2 = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
|
|
49425
|
+
if (!fieldName2) return field;
|
|
49384
49426
|
if (obj.type || obj.inputType) return field;
|
|
49385
|
-
const entityField = fieldMap.get(
|
|
49427
|
+
const entityField = fieldMap.get(fieldName2);
|
|
49386
49428
|
if (!entityField) return field;
|
|
49387
49429
|
const enriched = { ...obj, type: entityField.type };
|
|
49388
49430
|
if (entityField.required && !("required" in obj)) {
|
|
@@ -49432,9 +49474,9 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
49432
49474
|
}
|
|
49433
49475
|
if (field && typeof field === "object" && !Array.isArray(field) && !React87__namespace.default.isValidElement(field) && !(field instanceof Date)) {
|
|
49434
49476
|
const obj = field;
|
|
49435
|
-
const
|
|
49436
|
-
if (!
|
|
49437
|
-
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);
|
|
49438
49480
|
return meta ? { ...obj, ...meta } : field;
|
|
49439
49481
|
}
|
|
49440
49482
|
return field;
|
|
@@ -50273,9 +50315,9 @@ function UISlotRenderer({
|
|
|
50273
50315
|
"ui-slot-renderer relative min-h-full",
|
|
50274
50316
|
className
|
|
50275
50317
|
), children: [
|
|
50276
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex min-h-full", children: [
|
|
50277
|
-
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 shrink-0" }),
|
|
50278
|
-
/* @__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]" })
|
|
50279
50321
|
] }),
|
|
50280
50322
|
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "modal", portal: true }),
|
|
50281
50323
|
/* @__PURE__ */ jsxRuntime.jsx(UISlotComponent, { slot: "drawer", portal: true }),
|