@almadar/ui 5.160.0 → 5.161.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +924 -891
- package/dist/avl/index.js +914 -881
- package/dist/components/index.cjs +944 -934
- package/dist/components/index.d.cts +156 -31
- package/dist/components/index.d.ts +156 -31
- package/dist/components/index.js +931 -924
- package/dist/hooks/index.cjs +25 -49
- package/dist/hooks/index.js +25 -49
- package/dist/locales/index.cjs +75 -147
- package/dist/locales/index.js +75 -147
- package/dist/providers/index.cjs +911 -882
- package/dist/providers/index.js +901 -872
- package/dist/runtime/index.cjs +920 -887
- package/dist/runtime/index.js +910 -877
- package/locales/ar.json +25 -49
- package/locales/en.json +25 -49
- package/locales/sl.json +25 -49
- package/package.json +5 -5
package/dist/providers/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { ANONYMOUS_USER } from '@almadar/core';
|
|
|
8
8
|
import { clsx } from 'clsx';
|
|
9
9
|
import { twMerge } from 'tailwind-merge';
|
|
10
10
|
import * as LucideIcons2 from 'lucide-react';
|
|
11
|
-
import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ArrowLeft, ZoomOut, ZoomIn, Download, DollarSign, ChevronDown, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, HelpCircle, PauseCircle, Search,
|
|
11
|
+
import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ArrowLeft, ZoomOut, ZoomIn, Download, DollarSign, ChevronDown, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, HelpCircle, PauseCircle, Search, Bold, Italic, Underline, Strikethrough, Heading1, Heading2, Heading3, ListOrdered, Quote, Link as Link$1, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, ChevronUp } from 'lucide-react';
|
|
12
12
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import { useTranslate } from '@almadar/ui/hooks';
|
|
@@ -26264,8 +26264,9 @@ function DataGrid({
|
|
|
26264
26264
|
const titleField = fieldDefs.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fieldDefs[0];
|
|
26265
26265
|
const badgeFields = fieldDefs.filter((f3) => f3.variant === "badge" && f3 !== titleField);
|
|
26266
26266
|
const bodyFields = fieldDefs.filter((f3) => f3 !== titleField && !badgeFields.includes(f3));
|
|
26267
|
-
const
|
|
26268
|
-
const
|
|
26267
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
26268
|
+
const inlineCardActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
26269
|
+
const menuCardActions = actionDefs.filter((a) => !inlineCardActions.includes(a));
|
|
26269
26270
|
const fireAction = (action, itemData) => {
|
|
26270
26271
|
if (action.navigatesTo) {
|
|
26271
26272
|
const url = action.navigatesTo.replace(
|
|
@@ -26285,6 +26286,9 @@ function DataGrid({
|
|
|
26285
26286
|
e.stopPropagation();
|
|
26286
26287
|
fireAction(action, itemData);
|
|
26287
26288
|
};
|
|
26289
|
+
const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
|
|
26290
|
+
const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
|
|
26291
|
+
const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
|
|
26288
26292
|
const hasRenderProp = typeof children === "function";
|
|
26289
26293
|
useEffect(() => {
|
|
26290
26294
|
if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
|
|
@@ -26356,55 +26360,40 @@ function DataGrid({
|
|
|
26356
26360
|
{
|
|
26357
26361
|
"data-entity-row": true,
|
|
26358
26362
|
"data-entity-id": id,
|
|
26359
|
-
|
|
26363
|
+
onClick: handleCardClick?.(itemData),
|
|
26364
|
+
className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
|
|
26360
26365
|
children: [
|
|
26361
26366
|
children(itemData, index),
|
|
26362
|
-
actionDefs.length > 0 && /* @__PURE__ */
|
|
26363
|
-
/* @__PURE__ */ jsxs(
|
|
26364
|
-
|
|
26365
|
-
|
|
26366
|
-
|
|
26367
|
-
|
|
26368
|
-
|
|
26369
|
-
|
|
26370
|
-
|
|
26371
|
-
|
|
26372
|
-
|
|
26373
|
-
|
|
26374
|
-
|
|
26375
|
-
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
|
|
26379
|
-
)),
|
|
26380
|
-
maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsx(
|
|
26381
|
-
Menu,
|
|
26382
|
-
{
|
|
26383
|
-
position: "bottom-end",
|
|
26384
|
-
trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26385
|
-
items: actionDefs.slice(maxInlineActions).map((action) => ({
|
|
26386
|
-
label: action.label,
|
|
26387
|
-
icon: action.icon,
|
|
26388
|
-
event: action.event,
|
|
26389
|
-
onClick: () => fireAction(action, itemData)
|
|
26390
|
-
}))
|
|
26391
|
-
}
|
|
26392
|
-
)
|
|
26393
|
-
] }),
|
|
26394
|
-
/* @__PURE__ */ 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__ */ jsx(
|
|
26367
|
+
actionDefs.length > 0 && /* @__PURE__ */ 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__ */ jsxs(HStack, { gap: "xs", className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: [
|
|
26368
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
26369
|
+
Button,
|
|
26370
|
+
{
|
|
26371
|
+
variant: "primary",
|
|
26372
|
+
size: "sm",
|
|
26373
|
+
onClick: handleActionClick(action, itemData),
|
|
26374
|
+
"data-testid": `action-${action.event}`,
|
|
26375
|
+
"data-row-id": String(itemData.id),
|
|
26376
|
+
children: [
|
|
26377
|
+
action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
|
|
26378
|
+
action.label
|
|
26379
|
+
]
|
|
26380
|
+
},
|
|
26381
|
+
idx
|
|
26382
|
+
)),
|
|
26383
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsx(
|
|
26395
26384
|
Menu,
|
|
26396
26385
|
{
|
|
26397
26386
|
position: "bottom-end",
|
|
26398
26387
|
trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26399
|
-
items:
|
|
26388
|
+
items: menuCardActions.map((action) => ({
|
|
26400
26389
|
label: action.label,
|
|
26401
26390
|
icon: action.icon,
|
|
26402
|
-
|
|
26391
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
26403
26392
|
onClick: () => fireAction(action, itemData)
|
|
26404
26393
|
}))
|
|
26405
26394
|
}
|
|
26406
|
-
)
|
|
26407
|
-
] })
|
|
26395
|
+
)
|
|
26396
|
+
] }) })
|
|
26408
26397
|
]
|
|
26409
26398
|
},
|
|
26410
26399
|
id
|
|
@@ -26418,12 +26407,14 @@ function DataGrid({
|
|
|
26418
26407
|
{
|
|
26419
26408
|
"data-entity-row": true,
|
|
26420
26409
|
"data-entity-id": id,
|
|
26410
|
+
onClick: handleCardClick?.(itemData),
|
|
26421
26411
|
className: cn(
|
|
26422
26412
|
"bg-card rounded-lg",
|
|
26423
26413
|
"border border-border",
|
|
26424
26414
|
"shadow-elevation-card hover:shadow-elevation-dialog",
|
|
26425
26415
|
"hover:border-primary transition-all",
|
|
26426
26416
|
"flex flex-col",
|
|
26417
|
+
handleCardClick && "cursor-pointer",
|
|
26427
26418
|
isSelected && "ring-2 ring-primary border-primary"
|
|
26428
26419
|
),
|
|
26429
26420
|
children: [
|
|
@@ -26473,53 +26464,35 @@ function DataGrid({
|
|
|
26473
26464
|
] }, field.name);
|
|
26474
26465
|
}) })
|
|
26475
26466
|
] }),
|
|
26476
|
-
|
|
26477
|
-
|
|
26467
|
+
actionDefs.length > 0 && /* @__PURE__ */ jsxs(HStack, { gap: "xs", onClick: stopCardClick, className: "flex-shrink-0", children: [
|
|
26468
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
26478
26469
|
Button,
|
|
26479
26470
|
{
|
|
26480
|
-
variant:
|
|
26471
|
+
variant: "primary",
|
|
26481
26472
|
size: "sm",
|
|
26482
26473
|
onClick: handleActionClick(action, itemData),
|
|
26483
26474
|
"data-testid": `action-${action.event}`,
|
|
26484
26475
|
"data-row-id": String(itemData.id),
|
|
26485
26476
|
"aria-label": action.label,
|
|
26486
26477
|
title: action.label,
|
|
26487
|
-
className: cn(
|
|
26488
|
-
action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
|
|
26489
|
-
action.icon && "px-2"
|
|
26490
|
-
),
|
|
26478
|
+
className: cn(action.icon && "px-2"),
|
|
26491
26479
|
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
26492
26480
|
},
|
|
26493
26481
|
idx
|
|
26494
26482
|
)),
|
|
26495
|
-
|
|
26483
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsx(
|
|
26496
26484
|
Menu,
|
|
26497
26485
|
{
|
|
26498
26486
|
position: "bottom-end",
|
|
26499
26487
|
trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26500
|
-
items:
|
|
26488
|
+
items: menuCardActions.map((action) => ({
|
|
26501
26489
|
label: action.label,
|
|
26502
26490
|
icon: action.icon,
|
|
26503
|
-
|
|
26491
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
26504
26492
|
onClick: () => fireAction(action, itemData)
|
|
26505
26493
|
}))
|
|
26506
26494
|
}
|
|
26507
|
-
)
|
|
26508
|
-
dangerActions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
26509
|
-
Button,
|
|
26510
|
-
{
|
|
26511
|
-
variant: "ghost",
|
|
26512
|
-
size: "sm",
|
|
26513
|
-
onClick: handleActionClick(action, itemData),
|
|
26514
|
-
"data-testid": `action-${action.event}`,
|
|
26515
|
-
"data-row-id": String(itemData.id),
|
|
26516
|
-
"aria-label": action.label,
|
|
26517
|
-
title: action.label,
|
|
26518
|
-
className: "text-error hover:text-error hover:bg-error/10 px-2",
|
|
26519
|
-
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
26520
|
-
},
|
|
26521
|
-
`danger-${idx}`
|
|
26522
|
-
))
|
|
26495
|
+
)
|
|
26523
26496
|
] })
|
|
26524
26497
|
] }) }),
|
|
26525
26498
|
bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
@@ -26761,54 +26734,59 @@ function DataList({
|
|
|
26761
26734
|
if (!itemActions || itemActions.length === 0) return null;
|
|
26762
26735
|
const inline = maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions;
|
|
26763
26736
|
const overflow = maxInlineActions != null ? itemActions.slice(maxInlineActions) : [];
|
|
26764
|
-
return
|
|
26765
|
-
|
|
26766
|
-
|
|
26767
|
-
|
|
26768
|
-
|
|
26769
|
-
|
|
26770
|
-
|
|
26771
|
-
|
|
26772
|
-
|
|
26773
|
-
|
|
26774
|
-
action
|
|
26775
|
-
|
|
26776
|
-
|
|
26777
|
-
|
|
26778
|
-
|
|
26779
|
-
|
|
26780
|
-
|
|
26781
|
-
|
|
26782
|
-
|
|
26783
|
-
|
|
26784
|
-
|
|
26785
|
-
|
|
26786
|
-
|
|
26787
|
-
|
|
26788
|
-
|
|
26789
|
-
|
|
26790
|
-
|
|
26791
|
-
|
|
26792
|
-
|
|
26793
|
-
|
|
26794
|
-
|
|
26795
|
-
|
|
26796
|
-
|
|
26797
|
-
|
|
26798
|
-
|
|
26799
|
-
|
|
26800
|
-
|
|
26801
|
-
|
|
26802
|
-
|
|
26803
|
-
|
|
26737
|
+
return (
|
|
26738
|
+
// stopPropagation at the cluster: the "⋯" trigger opens the overflow
|
|
26739
|
+
// menu without also firing the row's default click (inline buttons
|
|
26740
|
+
// already stop it in handleActionClick; the Menu panel is portaled).
|
|
26741
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", onClick: rowClickEvent ? (e) => e.stopPropagation() : void 0, className: "flex-shrink-0", children: [
|
|
26742
|
+
inline.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
26743
|
+
Button,
|
|
26744
|
+
{
|
|
26745
|
+
variant: action.variant ?? "ghost",
|
|
26746
|
+
size: "sm",
|
|
26747
|
+
onClick: handleActionClick(action, itemData),
|
|
26748
|
+
"data-testid": `action-${action.event}`,
|
|
26749
|
+
"data-row-id": String(itemData.id),
|
|
26750
|
+
className: cn(
|
|
26751
|
+
action.variant === "danger" && "text-error hover:bg-error/10",
|
|
26752
|
+
// Must sit on the Button itself: the variant's own text colour
|
|
26753
|
+
// beats an inherited one from the row wrapper.
|
|
26754
|
+
onPrimary && "!text-primary-foreground hover:bg-primary-foreground/15"
|
|
26755
|
+
),
|
|
26756
|
+
children: [
|
|
26757
|
+
action.icon && renderIconInput2(action.icon, { size: "xs", className: "mr-1" }),
|
|
26758
|
+
action.label
|
|
26759
|
+
]
|
|
26760
|
+
},
|
|
26761
|
+
idx
|
|
26762
|
+
)),
|
|
26763
|
+
overflow.length > 0 && /* @__PURE__ */ jsx(
|
|
26764
|
+
Menu,
|
|
26765
|
+
{
|
|
26766
|
+
position: "bottom-end",
|
|
26767
|
+
trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
26768
|
+
items: overflow.map((action) => ({
|
|
26769
|
+
label: action.label,
|
|
26770
|
+
icon: action.icon,
|
|
26771
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
26772
|
+
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
26773
|
+
id: itemData.id,
|
|
26774
|
+
row: itemData
|
|
26775
|
+
})
|
|
26776
|
+
}))
|
|
26777
|
+
}
|
|
26778
|
+
)
|
|
26779
|
+
] })
|
|
26780
|
+
);
|
|
26804
26781
|
};
|
|
26782
|
+
const rowClickEvent = itemClickEvent || itemActions?.find((a) => a.variant !== "danger")?.event;
|
|
26805
26783
|
const handleRowClick = (itemData) => () => {
|
|
26806
|
-
if (!
|
|
26784
|
+
if (!rowClickEvent) return;
|
|
26807
26785
|
const payload = {
|
|
26808
26786
|
id: itemData.id,
|
|
26809
26787
|
row: itemData
|
|
26810
26788
|
};
|
|
26811
|
-
eventBus.emit(`UI:${
|
|
26789
|
+
eventBus.emit(`UI:${rowClickEvent}`, payload);
|
|
26812
26790
|
};
|
|
26813
26791
|
if (isLoading) {
|
|
26814
26792
|
return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
|
|
@@ -26856,10 +26834,10 @@ function DataList({
|
|
|
26856
26834
|
{
|
|
26857
26835
|
"data-entity-row": true,
|
|
26858
26836
|
"data-entity-id": id,
|
|
26859
|
-
onClick:
|
|
26837
|
+
onClick: rowClickEvent ? handleRowClick(itemData) : void 0,
|
|
26860
26838
|
className: cn(
|
|
26861
26839
|
"flex px-4 group/rowactions",
|
|
26862
|
-
|
|
26840
|
+
rowClickEvent && "cursor-pointer",
|
|
26863
26841
|
isSent ? "justify-end" : "justify-start"
|
|
26864
26842
|
),
|
|
26865
26843
|
children: /* @__PURE__ */ jsxs(
|
|
@@ -26935,7 +26913,7 @@ function DataList({
|
|
|
26935
26913
|
const id2 = itemData.id || String(index);
|
|
26936
26914
|
const actions = renderItemActions(itemData);
|
|
26937
26915
|
return wrapDnd(
|
|
26938
|
-
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick:
|
|
26916
|
+
/* @__PURE__ */ 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: [
|
|
26939
26917
|
children(itemData, index),
|
|
26940
26918
|
actions && /* @__PURE__ */ 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: [
|
|
26941
26919
|
/* @__PURE__ */ 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 }),
|
|
@@ -26947,7 +26925,6 @@ function DataList({
|
|
|
26947
26925
|
items: (itemActions ?? []).map((action) => ({
|
|
26948
26926
|
label: action.label,
|
|
26949
26927
|
icon: action.icon,
|
|
26950
|
-
event: action.event,
|
|
26951
26928
|
variant: action.variant === "danger" ? "danger" : "default",
|
|
26952
26929
|
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
26953
26930
|
id: itemData.id,
|
|
@@ -26964,7 +26941,7 @@ function DataList({
|
|
|
26964
26941
|
const id = itemData.id || String(index);
|
|
26965
26942
|
const titleValue = getNestedValue(itemData, titleField?.name ?? "");
|
|
26966
26943
|
return wrapDnd(
|
|
26967
|
-
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick:
|
|
26944
|
+
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn(rowClickEvent && "cursor-pointer"), children: [
|
|
26968
26945
|
/* @__PURE__ */ jsxs(
|
|
26969
26946
|
Box,
|
|
26970
26947
|
{
|
|
@@ -32240,7 +32217,7 @@ var init_MapView = __esm({
|
|
|
32240
32217
|
shadowSize: [41, 41]
|
|
32241
32218
|
});
|
|
32242
32219
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
32243
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback97, useState:
|
|
32220
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback97, useState: useState97 } = React87__default;
|
|
32244
32221
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
32245
32222
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
32246
32223
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -32285,7 +32262,7 @@ var init_MapView = __esm({
|
|
|
32285
32262
|
showAttribution = true
|
|
32286
32263
|
}) {
|
|
32287
32264
|
const eventBus = useEventBus2();
|
|
32288
|
-
const [clickedPosition, setClickedPosition] =
|
|
32265
|
+
const [clickedPosition, setClickedPosition] = useState97(null);
|
|
32289
32266
|
const handleMapClick = useCallback97((lat, lng) => {
|
|
32290
32267
|
if (showClickedPin) {
|
|
32291
32268
|
setClickedPosition({ lat, lng });
|
|
@@ -36647,741 +36624,775 @@ var init_PositionedCanvas = __esm({
|
|
|
36647
36624
|
PositionedCanvas.displayName = "PositionedCanvas";
|
|
36648
36625
|
}
|
|
36649
36626
|
});
|
|
36650
|
-
function
|
|
36651
|
-
|
|
36652
|
-
|
|
36653
|
-
|
|
36654
|
-
|
|
36655
|
-
|
|
36656
|
-
if (!Array.isArray(raw) || raw.length === 0) return [createBlock("paragraph")];
|
|
36657
|
-
return raw.map((row) => {
|
|
36658
|
-
const entity = row;
|
|
36659
|
-
const rawType = entity.type;
|
|
36660
|
-
const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
|
|
36661
|
-
const id = typeof entity.id === "string" && entity.id ? entity.id : nextBlockId(type);
|
|
36662
|
-
return { ...entity, id, type };
|
|
36663
|
-
});
|
|
36664
|
-
}
|
|
36665
|
-
function createBlock(type) {
|
|
36666
|
-
switch (type) {
|
|
36667
|
-
case "bullet-list":
|
|
36668
|
-
case "numbered-list":
|
|
36669
|
-
return {
|
|
36670
|
-
id: nextBlockId(type),
|
|
36671
|
-
type,
|
|
36672
|
-
children: [
|
|
36673
|
-
{ id: nextBlockId("li"), type: "paragraph", content: "" }
|
|
36674
|
-
]
|
|
36675
|
-
};
|
|
36676
|
-
case "image":
|
|
36677
|
-
return {
|
|
36678
|
-
id: nextBlockId(type),
|
|
36679
|
-
type,
|
|
36680
|
-
content: "",
|
|
36681
|
-
metadata: { url: "", caption: "" }
|
|
36682
|
-
};
|
|
36683
|
-
case "code":
|
|
36684
|
-
return {
|
|
36685
|
-
id: nextBlockId(type),
|
|
36686
|
-
type,
|
|
36687
|
-
content: "",
|
|
36688
|
-
metadata: { language: "plaintext" }
|
|
36689
|
-
};
|
|
36690
|
-
case "divider":
|
|
36691
|
-
return { id: nextBlockId(type), type };
|
|
36692
|
-
default:
|
|
36693
|
-
return { id: nextBlockId(type), type, content: "" };
|
|
36627
|
+
function safeUrl(raw, kinds) {
|
|
36628
|
+
const url = raw.trim();
|
|
36629
|
+
if (url.startsWith("#") || url.startsWith("/")) return url;
|
|
36630
|
+
const lower = url.toLowerCase();
|
|
36631
|
+
for (const kind of kinds) {
|
|
36632
|
+
if (lower.startsWith(kind)) return url;
|
|
36694
36633
|
}
|
|
36634
|
+
return null;
|
|
36695
36635
|
}
|
|
36696
|
-
function
|
|
36697
|
-
|
|
36698
|
-
|
|
36699
|
-
|
|
36700
|
-
|
|
36701
|
-
|
|
36702
|
-
|
|
36703
|
-
return {
|
|
36704
|
-
...block,
|
|
36705
|
-
id: nextBlockId(block.type),
|
|
36706
|
-
children: block.children?.map((child) => ({
|
|
36707
|
-
...child,
|
|
36708
|
-
id: nextBlockId("li")
|
|
36709
|
-
})),
|
|
36710
|
-
metadata: block.metadata ? { ...block.metadata } : void 0
|
|
36711
|
-
};
|
|
36712
|
-
}
|
|
36713
|
-
function insertAfter(blocks, targetId, inserted) {
|
|
36714
|
-
const idx = blocks.findIndex((b) => b.id === targetId);
|
|
36715
|
-
if (idx === -1) return [...blocks, inserted];
|
|
36716
|
-
const next = blocks.slice();
|
|
36717
|
-
next.splice(idx + 1, 0, inserted);
|
|
36718
|
-
return next;
|
|
36719
|
-
}
|
|
36720
|
-
function changeBlockType(block, type) {
|
|
36721
|
-
if (block.type === type) return block;
|
|
36722
|
-
if (type === "bullet-list" || type === "numbered-list") {
|
|
36723
|
-
if (block.children && block.children.length > 0) {
|
|
36724
|
-
return { ...block, type };
|
|
36636
|
+
function sanitizeNode(el) {
|
|
36637
|
+
const children = Array.from(el.children);
|
|
36638
|
+
for (const child of children) {
|
|
36639
|
+
const tag = child.tagName.toLowerCase();
|
|
36640
|
+
if (DROP_TAGS.has(tag)) {
|
|
36641
|
+
child.remove();
|
|
36642
|
+
continue;
|
|
36725
36643
|
}
|
|
36726
|
-
const
|
|
36727
|
-
|
|
36728
|
-
|
|
36729
|
-
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
|
|
36733
|
-
|
|
36734
|
-
|
|
36735
|
-
|
|
36736
|
-
|
|
36644
|
+
const allowed = ALLOWED_ATTRS[tag];
|
|
36645
|
+
if (!allowed) {
|
|
36646
|
+
sanitizeNode(child);
|
|
36647
|
+
child.replaceWith(...Array.from(child.childNodes));
|
|
36648
|
+
continue;
|
|
36649
|
+
}
|
|
36650
|
+
for (const attr of Array.from(child.attributes)) {
|
|
36651
|
+
const name = attr.name.toLowerCase();
|
|
36652
|
+
if (!allowed.includes(name)) {
|
|
36653
|
+
child.removeAttribute(attr.name);
|
|
36654
|
+
continue;
|
|
36655
|
+
}
|
|
36656
|
+
if (name === "href") {
|
|
36657
|
+
const url = safeUrl(attr.value, ["http://", "https://", "mailto:"]);
|
|
36658
|
+
if (url === null) child.removeAttribute(attr.name);
|
|
36659
|
+
else child.setAttribute("href", url);
|
|
36660
|
+
}
|
|
36661
|
+
if (name === "src") {
|
|
36662
|
+
const url = safeUrl(attr.value, ["http://", "https://", "data:image/"]);
|
|
36663
|
+
if (url === null) child.remove();
|
|
36664
|
+
else child.setAttribute("src", url);
|
|
36665
|
+
}
|
|
36666
|
+
}
|
|
36667
|
+
sanitizeNode(child);
|
|
36737
36668
|
}
|
|
36738
|
-
|
|
36739
|
-
|
|
36740
|
-
|
|
36741
|
-
|
|
36742
|
-
|
|
36743
|
-
|
|
36744
|
-
|
|
36669
|
+
}
|
|
36670
|
+
function sanitizeRichHtml(html) {
|
|
36671
|
+
if (!html || typeof html !== "string") return "";
|
|
36672
|
+
if (typeof window === "undefined" || typeof DOMParser === "undefined") return "";
|
|
36673
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
36674
|
+
sanitizeNode(doc.body);
|
|
36675
|
+
if (!doc.body.querySelector("img, hr") && (doc.body.textContent ?? "").trim().length === 0) {
|
|
36676
|
+
return "";
|
|
36745
36677
|
}
|
|
36746
|
-
|
|
36747
|
-
|
|
36748
|
-
|
|
36749
|
-
|
|
36750
|
-
|
|
36751
|
-
|
|
36752
|
-
|
|
36678
|
+
return doc.body.innerHTML.replace(//g, "");
|
|
36679
|
+
}
|
|
36680
|
+
function htmlIsEmpty(el) {
|
|
36681
|
+
if (el.querySelector("img, hr")) return false;
|
|
36682
|
+
return (el.textContent ?? "").trim().length === 0;
|
|
36683
|
+
}
|
|
36684
|
+
function closestBlock(node, root) {
|
|
36685
|
+
let cur = node;
|
|
36686
|
+
while (cur && cur !== root) {
|
|
36687
|
+
if (cur instanceof Element && BLOCK_TAGS.has(cur.tagName)) return cur;
|
|
36688
|
+
cur = cur.parentNode;
|
|
36753
36689
|
}
|
|
36754
|
-
|
|
36755
|
-
return { id: block.id, type, content: seed };
|
|
36690
|
+
return null;
|
|
36756
36691
|
}
|
|
36757
|
-
function
|
|
36758
|
-
|
|
36759
|
-
|
|
36760
|
-
|
|
36761
|
-
|
|
36762
|
-
|
|
36763
|
-
|
|
36764
|
-
|
|
36765
|
-
|
|
36692
|
+
function RichTextStyles() {
|
|
36693
|
+
return /* @__PURE__ */ jsx("style", { children: RICH_TEXT_CSS });
|
|
36694
|
+
}
|
|
36695
|
+
function readToolbarState(root) {
|
|
36696
|
+
const sel = window.getSelection();
|
|
36697
|
+
if (!sel || sel.rangeCount === 0) return IDLE_TOOLBAR;
|
|
36698
|
+
const anchor = sel.anchorNode;
|
|
36699
|
+
if (!anchor || !root.contains(anchor)) return IDLE_TOOLBAR;
|
|
36700
|
+
let block = null;
|
|
36701
|
+
let link = false;
|
|
36702
|
+
let node = anchor;
|
|
36703
|
+
while (node && node !== root) {
|
|
36704
|
+
if (node instanceof Element) {
|
|
36705
|
+
const tag = node.tagName.toLowerCase();
|
|
36706
|
+
if (!block && (tag === "h1" || tag === "h2" || tag === "h3" || tag === "blockquote" || tag === "pre")) {
|
|
36707
|
+
block = tag;
|
|
36766
36708
|
}
|
|
36709
|
+
if (tag === "a") link = true;
|
|
36767
36710
|
}
|
|
36768
|
-
|
|
36769
|
-
|
|
36770
|
-
|
|
36771
|
-
|
|
36772
|
-
|
|
36773
|
-
|
|
36774
|
-
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
|
|
36780
|
-
"inline-flex items-center justify-center",
|
|
36781
|
-
"h-6 w-6 rounded-sm p-0 gap-0",
|
|
36782
|
-
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
36783
|
-
"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",
|
|
36784
|
-
"transition-opacity"
|
|
36785
|
-
),
|
|
36786
|
-
onClick: () => setOpen((v) => !v),
|
|
36787
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", className: "w-3.5 h-3.5" })
|
|
36788
|
-
}
|
|
36789
|
-
),
|
|
36790
|
-
open && /* @__PURE__ */ jsxs(
|
|
36791
|
-
Box,
|
|
36792
|
-
{
|
|
36793
|
-
role: "menu",
|
|
36794
|
-
className: cn(
|
|
36795
|
-
"absolute right-0 z-10 mt-1 w-44",
|
|
36796
|
-
"rounded-container border border-border bg-popover shadow-elevation-popover",
|
|
36797
|
-
"py-1 text-sm"
|
|
36798
|
-
),
|
|
36799
|
-
children: [
|
|
36800
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t(BLOCK_TYPE_LABEL_KEY[block.type]) }),
|
|
36801
|
-
/* @__PURE__ */ jsxs(
|
|
36802
|
-
Button,
|
|
36803
|
-
{
|
|
36804
|
-
type: "button",
|
|
36805
|
-
variant: "ghost",
|
|
36806
|
-
role: "menuitem",
|
|
36807
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
36808
|
-
onClick: () => {
|
|
36809
|
-
onDuplicate();
|
|
36810
|
-
setOpen(false);
|
|
36811
|
-
},
|
|
36812
|
-
children: [
|
|
36813
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3.5 h-3.5" }),
|
|
36814
|
-
" ",
|
|
36815
|
-
t("richBlockEditor.duplicate")
|
|
36816
|
-
]
|
|
36817
|
-
}
|
|
36818
|
-
),
|
|
36819
|
-
/* @__PURE__ */ jsxs(
|
|
36820
|
-
Button,
|
|
36821
|
-
{
|
|
36822
|
-
type: "button",
|
|
36823
|
-
variant: "ghost",
|
|
36824
|
-
role: "menuitem",
|
|
36825
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-destructive hover:bg-muted justify-start rounded-none",
|
|
36826
|
-
onClick: () => {
|
|
36827
|
-
onDelete();
|
|
36828
|
-
setOpen(false);
|
|
36829
|
-
},
|
|
36830
|
-
children: [
|
|
36831
|
-
/* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3.5 h-3.5" }),
|
|
36832
|
-
" ",
|
|
36833
|
-
t("common.delete")
|
|
36834
|
-
]
|
|
36835
|
-
}
|
|
36836
|
-
),
|
|
36837
|
-
CHANGEABLE_TYPES.includes(block.type) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36838
|
-
/* @__PURE__ */ jsx(Box, { className: "my-1 border-t border-border" }),
|
|
36839
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t("richBlockEditor.turnInto") }),
|
|
36840
|
-
CHANGEABLE_TYPES.filter((bt) => bt !== block.type).map((bt) => /* @__PURE__ */ jsx(
|
|
36841
|
-
Button,
|
|
36842
|
-
{
|
|
36843
|
-
type: "button",
|
|
36844
|
-
variant: "ghost",
|
|
36845
|
-
role: "menuitem",
|
|
36846
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
36847
|
-
onClick: () => {
|
|
36848
|
-
onChangeType(bt);
|
|
36849
|
-
setOpen(false);
|
|
36850
|
-
},
|
|
36851
|
-
children: t(BLOCK_TYPE_LABEL_KEY[bt])
|
|
36852
|
-
},
|
|
36853
|
-
bt
|
|
36854
|
-
))
|
|
36855
|
-
] })
|
|
36856
|
-
]
|
|
36857
|
-
}
|
|
36858
|
-
)
|
|
36859
|
-
] });
|
|
36711
|
+
node = node.parentNode;
|
|
36712
|
+
}
|
|
36713
|
+
return {
|
|
36714
|
+
bold: document.queryCommandState("bold"),
|
|
36715
|
+
italic: document.queryCommandState("italic"),
|
|
36716
|
+
underline: document.queryCommandState("underline"),
|
|
36717
|
+
strikeThrough: document.queryCommandState("strikeThrough"),
|
|
36718
|
+
block,
|
|
36719
|
+
bullets: document.queryCommandState("insertUnorderedList"),
|
|
36720
|
+
numbers: document.queryCommandState("insertOrderedList"),
|
|
36721
|
+
link
|
|
36722
|
+
};
|
|
36860
36723
|
}
|
|
36861
|
-
function
|
|
36862
|
-
tag,
|
|
36863
|
-
value,
|
|
36864
|
-
readOnly,
|
|
36865
|
-
placeholder,
|
|
36866
|
-
className,
|
|
36867
|
-
ariaLabel,
|
|
36868
|
-
onValueChange
|
|
36869
|
-
}) {
|
|
36870
|
-
const ref = useRef(null);
|
|
36871
|
-
useEffect(() => {
|
|
36872
|
-
const el = ref.current;
|
|
36873
|
-
if (!el) return;
|
|
36874
|
-
const isFocused = document.activeElement === el;
|
|
36875
|
-
if (!isFocused && el.textContent !== value) {
|
|
36876
|
-
el.textContent = value;
|
|
36877
|
-
}
|
|
36878
|
-
}, [value]);
|
|
36879
|
-
const handleInput = useCallback(
|
|
36880
|
-
(e) => {
|
|
36881
|
-
onValueChange(e.currentTarget.textContent ?? "");
|
|
36882
|
-
},
|
|
36883
|
-
[onValueChange]
|
|
36884
|
-
);
|
|
36724
|
+
function ToolbarButton({ icon: IconCmp, label, active, onExec }) {
|
|
36885
36725
|
return /* @__PURE__ */ jsx(
|
|
36886
|
-
|
|
36726
|
+
Button,
|
|
36887
36727
|
{
|
|
36888
|
-
|
|
36889
|
-
|
|
36890
|
-
|
|
36891
|
-
|
|
36892
|
-
|
|
36893
|
-
|
|
36894
|
-
"aria-multiline": "true",
|
|
36895
|
-
"data-placeholder": placeholder,
|
|
36728
|
+
type: "button",
|
|
36729
|
+
variant: "ghost",
|
|
36730
|
+
size: "sm",
|
|
36731
|
+
"aria-label": label,
|
|
36732
|
+
"aria-pressed": active,
|
|
36733
|
+
title: label,
|
|
36896
36734
|
className: cn(
|
|
36897
|
-
"
|
|
36898
|
-
"
|
|
36899
|
-
className
|
|
36735
|
+
"h-8 w-8 p-0 gap-0 justify-center",
|
|
36736
|
+
active && "bg-muted text-foreground"
|
|
36900
36737
|
),
|
|
36901
|
-
|
|
36738
|
+
onMouseDown: (e) => {
|
|
36739
|
+
e.preventDefault();
|
|
36740
|
+
onExec();
|
|
36741
|
+
},
|
|
36742
|
+
children: /* @__PURE__ */ jsx(IconCmp, { size: 15 })
|
|
36902
36743
|
}
|
|
36903
36744
|
);
|
|
36904
36745
|
}
|
|
36905
|
-
|
|
36906
|
-
|
|
36907
|
-
|
|
36908
|
-
|
|
36909
|
-
|
|
36910
|
-
|
|
36911
|
-
|
|
36912
|
-
|
|
36913
|
-
|
|
36914
|
-
|
|
36915
|
-
|
|
36916
|
-
|
|
36917
|
-
|
|
36918
|
-
|
|
36919
|
-
|
|
36920
|
-
|
|
36921
|
-
|
|
36922
|
-
|
|
36923
|
-
|
|
36924
|
-
|
|
36925
|
-
|
|
36926
|
-
|
|
36927
|
-
|
|
36928
|
-
|
|
36929
|
-
|
|
36930
|
-
|
|
36931
|
-
|
|
36932
|
-
|
|
36933
|
-
|
|
36934
|
-
|
|
36935
|
-
|
|
36936
|
-
|
|
36937
|
-
|
|
36938
|
-
|
|
36939
|
-
|
|
36940
|
-
|
|
36941
|
-
|
|
36942
|
-
|
|
36943
|
-
|
|
36944
|
-
|
|
36945
|
-
|
|
36946
|
-
|
|
36947
|
-
|
|
36948
|
-
|
|
36949
|
-
|
|
36950
|
-
|
|
36951
|
-
|
|
36952
|
-
|
|
36953
|
-
|
|
36954
|
-
|
|
36955
|
-
|
|
36956
|
-
|
|
36957
|
-
|
|
36958
|
-
|
|
36959
|
-
|
|
36960
|
-
|
|
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
|
-
|
|
36746
|
+
var CHANGE_DEBOUNCE_MS, ALLOWED_ATTRS, DROP_TAGS, MD_BLOCK_PREFIXES, BLOCK_TAGS, MD_INLINE_RULES, RICH_TEXT_CSS, IDLE_TOOLBAR, RichTextEditor;
|
|
36747
|
+
var init_RichTextEditor = __esm({
|
|
36748
|
+
"components/core/molecules/RichTextEditor.tsx"() {
|
|
36749
|
+
"use client";
|
|
36750
|
+
init_cn();
|
|
36751
|
+
init_Box();
|
|
36752
|
+
init_Button();
|
|
36753
|
+
init_useEventBus();
|
|
36754
|
+
CHANGE_DEBOUNCE_MS = 400;
|
|
36755
|
+
ALLOWED_ATTRS = {
|
|
36756
|
+
p: [],
|
|
36757
|
+
h1: [],
|
|
36758
|
+
h2: [],
|
|
36759
|
+
h3: [],
|
|
36760
|
+
h4: [],
|
|
36761
|
+
ul: [],
|
|
36762
|
+
ol: [],
|
|
36763
|
+
li: [],
|
|
36764
|
+
blockquote: [],
|
|
36765
|
+
pre: [],
|
|
36766
|
+
code: [],
|
|
36767
|
+
b: [],
|
|
36768
|
+
strong: [],
|
|
36769
|
+
i: [],
|
|
36770
|
+
em: [],
|
|
36771
|
+
u: [],
|
|
36772
|
+
s: [],
|
|
36773
|
+
strike: [],
|
|
36774
|
+
br: [],
|
|
36775
|
+
hr: [],
|
|
36776
|
+
div: [],
|
|
36777
|
+
span: [],
|
|
36778
|
+
a: ["href"],
|
|
36779
|
+
img: ["src", "alt"]
|
|
36780
|
+
};
|
|
36781
|
+
DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "iframe", "object", "embed", "link", "meta", "form", "input", "button", "textarea", "select"]);
|
|
36782
|
+
MD_BLOCK_PREFIXES = {
|
|
36783
|
+
"#": { kind: "block", tag: "h1" },
|
|
36784
|
+
"##": { kind: "block", tag: "h2" },
|
|
36785
|
+
"###": { kind: "block", tag: "h3" },
|
|
36786
|
+
">": { kind: "block", tag: "blockquote" },
|
|
36787
|
+
"```": { kind: "block", tag: "pre" },
|
|
36788
|
+
"-": { kind: "list", command: "insertUnorderedList" },
|
|
36789
|
+
"*": { kind: "list", command: "insertUnorderedList" },
|
|
36790
|
+
"1.": { kind: "list", command: "insertOrderedList" }
|
|
36791
|
+
};
|
|
36792
|
+
BLOCK_TAGS = /* @__PURE__ */ new Set(["P", "DIV", "LI", "H1", "H2", "H3", "H4", "BLOCKQUOTE", "PRE"]);
|
|
36793
|
+
MD_INLINE_RULES = [
|
|
36794
|
+
{ pattern: /\*\*([^*\n]+)\*\*$/, wrap: "strong" },
|
|
36795
|
+
{ pattern: /(^|[^*])\*([^*\n]+)\*$/, wrap: "em" },
|
|
36796
|
+
{ pattern: /`([^`\n]+)`$/, wrap: "code" }
|
|
36797
|
+
];
|
|
36798
|
+
RICH_TEXT_CSS = `
|
|
36799
|
+
.almadar-rich-text { line-height: 1.7; color: var(--color-foreground); }
|
|
36800
|
+
.almadar-rich-text h1 { font-size: 1.875rem; font-weight: 700; line-height: 1.25; margin: 1.25em 0 0.4em; }
|
|
36801
|
+
.almadar-rich-text h2 { font-size: 1.5rem; font-weight: 650; line-height: 1.3; margin: 1.1em 0 0.4em; }
|
|
36802
|
+
.almadar-rich-text h3 { font-size: 1.25rem; font-weight: 600; line-height: 1.35; margin: 1em 0 0.35em; }
|
|
36803
|
+
.almadar-rich-text h1:first-child, .almadar-rich-text h2:first-child, .almadar-rich-text h3:first-child { margin-top: 0; }
|
|
36804
|
+
.almadar-rich-text p { margin: 0.5em 0; }
|
|
36805
|
+
.almadar-rich-text ul { list-style: disc; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
36806
|
+
.almadar-rich-text ol { list-style: decimal; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
36807
|
+
.almadar-rich-text li { margin: 0.25em 0; }
|
|
36808
|
+
.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; }
|
|
36809
|
+
.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; }
|
|
36810
|
+
.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; }
|
|
36811
|
+
.almadar-rich-text pre code { background: transparent; padding: 0; }
|
|
36812
|
+
.almadar-rich-text a { color: var(--color-primary); text-decoration: underline; }
|
|
36813
|
+
.almadar-rich-text hr { border: none; border-top: 1px solid var(--color-border); margin: 1.25em 0; }
|
|
36814
|
+
.almadar-rich-text img { max-width: 100%; border-radius: 0.375rem; }
|
|
36815
|
+
`;
|
|
36816
|
+
IDLE_TOOLBAR = {
|
|
36817
|
+
bold: false,
|
|
36818
|
+
italic: false,
|
|
36819
|
+
underline: false,
|
|
36820
|
+
strikeThrough: false,
|
|
36821
|
+
block: null,
|
|
36822
|
+
bullets: false,
|
|
36823
|
+
numbers: false,
|
|
36824
|
+
link: false
|
|
36825
|
+
};
|
|
36826
|
+
RichTextEditor = ({
|
|
36827
|
+
value,
|
|
36828
|
+
onChange,
|
|
36829
|
+
changeEvent,
|
|
36830
|
+
readOnly = false,
|
|
36831
|
+
placeholder,
|
|
36832
|
+
showToolbar = true,
|
|
36833
|
+
className
|
|
36834
|
+
}) => {
|
|
36835
|
+
const { t } = useTranslate();
|
|
36836
|
+
const ref = useRef(null);
|
|
36837
|
+
const [toolbar, setToolbar] = useState(IDLE_TOOLBAR);
|
|
36838
|
+
const [empty, setEmpty] = useState(() => !value || !sanitizeRichHtml(value).trim());
|
|
36839
|
+
const eventBus = useEventBus();
|
|
36840
|
+
const onChangeRef = useRef(onChange);
|
|
36841
|
+
const changeEventRef = useRef(changeEvent);
|
|
36842
|
+
useEffect(() => {
|
|
36843
|
+
onChangeRef.current = onChange;
|
|
36844
|
+
changeEventRef.current = changeEvent;
|
|
36845
|
+
}, [onChange, changeEvent]);
|
|
36846
|
+
const emitTimerRef = useRef(null);
|
|
36847
|
+
const emitNow = useCallback(() => {
|
|
36848
|
+
const el = ref.current;
|
|
36849
|
+
if (!el) return;
|
|
36850
|
+
const html = sanitizeRichHtml(el.innerHTML);
|
|
36851
|
+
onChangeRef.current?.(html);
|
|
36852
|
+
const evt = changeEventRef.current;
|
|
36853
|
+
if (evt) eventBus.emit(`UI:${evt}`, { value: html });
|
|
36854
|
+
}, [eventBus]);
|
|
36855
|
+
const scheduleEmit = useCallback(() => {
|
|
36856
|
+
if (emitTimerRef.current) clearTimeout(emitTimerRef.current);
|
|
36857
|
+
emitTimerRef.current = setTimeout(() => {
|
|
36858
|
+
emitTimerRef.current = null;
|
|
36859
|
+
emitNow();
|
|
36860
|
+
}, CHANGE_DEBOUNCE_MS);
|
|
36861
|
+
}, [emitNow]);
|
|
36862
|
+
const flushEmit = useCallback(() => {
|
|
36863
|
+
if (!emitTimerRef.current) return;
|
|
36864
|
+
clearTimeout(emitTimerRef.current);
|
|
36865
|
+
emitTimerRef.current = null;
|
|
36866
|
+
emitNow();
|
|
36867
|
+
}, [emitNow]);
|
|
36868
|
+
useEffect(() => () => {
|
|
36869
|
+
if (emitTimerRef.current) {
|
|
36870
|
+
clearTimeout(emitTimerRef.current);
|
|
36871
|
+
emitTimerRef.current = null;
|
|
36872
|
+
emitNow();
|
|
36873
|
+
}
|
|
36874
|
+
}, [emitNow]);
|
|
36875
|
+
useEffect(() => {
|
|
36876
|
+
if (readOnly) return;
|
|
36877
|
+
const el = ref.current;
|
|
36878
|
+
if (!el) return;
|
|
36879
|
+
if (document.activeElement === el) return;
|
|
36880
|
+
const next = sanitizeRichHtml(value ?? "") || "<p><br></p>";
|
|
36881
|
+
if (el.innerHTML !== next) {
|
|
36882
|
+
el.innerHTML = next;
|
|
36883
|
+
setEmpty(htmlIsEmpty(el));
|
|
36884
|
+
}
|
|
36885
|
+
}, [readOnly, value]);
|
|
36886
|
+
useEffect(() => {
|
|
36887
|
+
if (readOnly) return;
|
|
36888
|
+
document.execCommand("defaultParagraphSeparator", false, "p");
|
|
36889
|
+
}, [readOnly]);
|
|
36890
|
+
useEffect(() => {
|
|
36891
|
+
if (readOnly || !showToolbar) return;
|
|
36892
|
+
const onSelectionChange = () => {
|
|
36893
|
+
const el = ref.current;
|
|
36894
|
+
if (!el) return;
|
|
36895
|
+
setToolbar(readToolbarState(el));
|
|
37051
36896
|
};
|
|
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
|
-
|
|
36897
|
+
document.addEventListener("selectionchange", onSelectionChange);
|
|
36898
|
+
return () => document.removeEventListener("selectionchange", onSelectionChange);
|
|
36899
|
+
}, [readOnly, showToolbar]);
|
|
36900
|
+
const tryInlineMarkdown = useCallback(() => {
|
|
36901
|
+
const root = ref.current;
|
|
36902
|
+
if (!root) return false;
|
|
36903
|
+
const sel = window.getSelection();
|
|
36904
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
36905
|
+
const node = sel.anchorNode;
|
|
36906
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
36907
|
+
if (node.parentElement?.closest("code, pre")) return false;
|
|
36908
|
+
const text = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
36909
|
+
for (const rule of MD_INLINE_RULES) {
|
|
36910
|
+
const m = rule.pattern.exec(text);
|
|
36911
|
+
if (!m) continue;
|
|
36912
|
+
const inner = rule.wrap === "em" ? m[2] : m[1];
|
|
36913
|
+
if (!inner || !inner.trim()) continue;
|
|
36914
|
+
const lead = rule.wrap === "em" ? m[1]?.length ?? 0 : 0;
|
|
36915
|
+
const range = document.createRange();
|
|
36916
|
+
range.setStart(node, m.index + lead);
|
|
36917
|
+
range.setEnd(node, sel.anchorOffset);
|
|
36918
|
+
const el = document.createElement(rule.wrap);
|
|
36919
|
+
el.textContent = inner;
|
|
36920
|
+
range.deleteContents();
|
|
36921
|
+
range.insertNode(el);
|
|
36922
|
+
const after = document.createTextNode("\u200B");
|
|
36923
|
+
el.parentNode?.insertBefore(after, el.nextSibling);
|
|
36924
|
+
const caret = document.createRange();
|
|
36925
|
+
caret.setStart(after, 1);
|
|
36926
|
+
caret.collapse(true);
|
|
36927
|
+
sel.removeAllRanges();
|
|
36928
|
+
sel.addRange(caret);
|
|
36929
|
+
return true;
|
|
36930
|
+
}
|
|
36931
|
+
return false;
|
|
36932
|
+
}, []);
|
|
36933
|
+
const tryBlockMarkdown = useCallback(() => {
|
|
36934
|
+
const root = ref.current;
|
|
36935
|
+
if (!root) return false;
|
|
36936
|
+
const sel = window.getSelection();
|
|
36937
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
36938
|
+
const node = sel.anchorNode;
|
|
36939
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
36940
|
+
const block = closestBlock(node, root);
|
|
36941
|
+
if (block ? block.firstChild !== node : root.firstChild !== node) return false;
|
|
36942
|
+
const prefix = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
36943
|
+
const rule = MD_BLOCK_PREFIXES[prefix];
|
|
36944
|
+
if (!rule) return false;
|
|
36945
|
+
if (node.parentElement?.closest("pre, code")) return false;
|
|
36946
|
+
if (rule.kind === "list" && node.parentElement?.closest("li")) return false;
|
|
36947
|
+
node.deleteData(0, prefix.length);
|
|
36948
|
+
const caret = document.createRange();
|
|
36949
|
+
caret.setStart(node, 0);
|
|
36950
|
+
caret.collapse(true);
|
|
36951
|
+
sel.removeAllRanges();
|
|
36952
|
+
sel.addRange(caret);
|
|
36953
|
+
if (rule.kind === "list") {
|
|
36954
|
+
const container = block ?? node.parentElement;
|
|
36955
|
+
const list = document.createElement(rule.command === "insertOrderedList" ? "ol" : "ul");
|
|
36956
|
+
const li = document.createElement("li");
|
|
36957
|
+
if (block) {
|
|
36958
|
+
while (block.firstChild) li.appendChild(block.firstChild);
|
|
36959
|
+
list.appendChild(li);
|
|
36960
|
+
block.replaceWith(list);
|
|
36961
|
+
} else if (container) {
|
|
36962
|
+
li.appendChild(node);
|
|
36963
|
+
list.appendChild(li);
|
|
36964
|
+
container.appendChild(list);
|
|
36965
|
+
}
|
|
36966
|
+
if (!li.firstChild) li.appendChild(document.createElement("br"));
|
|
36967
|
+
const liCaret = document.createRange();
|
|
36968
|
+
liCaret.selectNodeContents(li);
|
|
36969
|
+
liCaret.collapse(true);
|
|
36970
|
+
sel.removeAllRanges();
|
|
36971
|
+
sel.addRange(liCaret);
|
|
36972
|
+
} else {
|
|
36973
|
+
document.execCommand("formatBlock", false, rule.tag);
|
|
36974
|
+
}
|
|
36975
|
+
return true;
|
|
36976
|
+
}, []);
|
|
36977
|
+
const afterEdit = useCallback(() => {
|
|
36978
|
+
const el = ref.current;
|
|
36979
|
+
if (!el) return;
|
|
36980
|
+
tryInlineMarkdown();
|
|
36981
|
+
setEmpty(htmlIsEmpty(el));
|
|
36982
|
+
setToolbar(readToolbarState(el));
|
|
36983
|
+
scheduleEmit();
|
|
36984
|
+
}, [scheduleEmit, tryInlineMarkdown]);
|
|
36985
|
+
const handleKeyDown = useCallback((e) => {
|
|
36986
|
+
if (e.key === " " && tryBlockMarkdown()) {
|
|
36987
|
+
e.preventDefault();
|
|
36988
|
+
afterEdit();
|
|
36989
|
+
}
|
|
36990
|
+
}, [afterEdit, tryBlockMarkdown]);
|
|
36991
|
+
const execInline = useCallback((command) => {
|
|
36992
|
+
document.execCommand(command, false);
|
|
36993
|
+
afterEdit();
|
|
36994
|
+
}, [afterEdit]);
|
|
36995
|
+
const execBlock = useCallback((tag) => {
|
|
36996
|
+
const next = toolbar.block === tag ? "p" : tag;
|
|
36997
|
+
document.execCommand("formatBlock", false, next);
|
|
36998
|
+
afterEdit();
|
|
36999
|
+
}, [afterEdit, toolbar.block]);
|
|
37000
|
+
const execList = useCallback((command) => {
|
|
37001
|
+
document.execCommand(command, false);
|
|
37002
|
+
afterEdit();
|
|
37003
|
+
}, [afterEdit]);
|
|
37004
|
+
const execLink = useCallback(() => {
|
|
37005
|
+
if (toolbar.link) {
|
|
37006
|
+
document.execCommand("unlink", false);
|
|
37007
|
+
afterEdit();
|
|
37008
|
+
return;
|
|
37009
|
+
}
|
|
37010
|
+
const url = window.prompt(t("richTextEditor.linkPrompt"));
|
|
37011
|
+
if (!url) return;
|
|
37012
|
+
const safe = safeUrl(url, ["http://", "https://", "mailto:"]) ?? `https://${url}`;
|
|
37013
|
+
document.execCommand("createLink", false, safe);
|
|
37014
|
+
afterEdit();
|
|
37015
|
+
}, [afterEdit, t, toolbar.link]);
|
|
37016
|
+
const execRule = useCallback(() => {
|
|
37017
|
+
document.execCommand("insertHorizontalRule", false);
|
|
37018
|
+
afterEdit();
|
|
37019
|
+
}, [afterEdit]);
|
|
37020
|
+
if (readOnly) {
|
|
37021
|
+
return /* @__PURE__ */ jsxs(Box, { className: cn("almadar-rich-text max-w-none", className), children: [
|
|
37022
|
+
/* @__PURE__ */ jsx(RichTextStyles, {}),
|
|
37023
|
+
/* @__PURE__ */ jsx(Box, { dangerouslySetInnerHTML: { __html: sanitizeRichHtml(value ?? "") } })
|
|
37099
37024
|
] });
|
|
37100
37025
|
}
|
|
37101
|
-
|
|
37102
|
-
|
|
37103
|
-
|
|
37104
|
-
return /* @__PURE__ */ jsxs(
|
|
37026
|
+
return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
|
|
37027
|
+
/* @__PURE__ */ jsx(RichTextStyles, {}),
|
|
37028
|
+
showToolbar && /* @__PURE__ */ jsxs(
|
|
37105
37029
|
Box,
|
|
37106
37030
|
{
|
|
37107
|
-
|
|
37031
|
+
role: "toolbar",
|
|
37032
|
+
"aria-label": t("richTextEditor.editorToolbar"),
|
|
37108
37033
|
className: cn(
|
|
37109
|
-
"
|
|
37110
|
-
|
|
37034
|
+
"sticky top-0 z-10 flex flex-wrap items-center gap-0.5 self-start",
|
|
37035
|
+
"rounded-md border border-border bg-background/95 px-1 py-0.5 shadow-sm"
|
|
37111
37036
|
),
|
|
37112
37037
|
children: [
|
|
37113
|
-
|
|
37114
|
-
|
|
37115
|
-
|
|
37116
|
-
|
|
37117
|
-
|
|
37118
|
-
|
|
37119
|
-
|
|
37120
|
-
|
|
37121
|
-
|
|
37122
|
-
|
|
37123
|
-
|
|
37124
|
-
|
|
37125
|
-
|
|
37126
|
-
|
|
37127
|
-
|
|
37128
|
-
|
|
37129
|
-
type: "button",
|
|
37130
|
-
variant: "ghost",
|
|
37131
|
-
"aria-label": t("richBlockEditor.aria.removeListItem"),
|
|
37132
|
-
className: cn(
|
|
37133
|
-
"h-5 w-5 shrink-0 rounded-sm text-muted-foreground p-0 gap-0",
|
|
37134
|
-
"opacity-0 group-hover/item:opacity-100 hover:bg-muted hover:text-foreground"
|
|
37135
|
-
),
|
|
37136
|
-
onClick: () => removeListItem(child.id),
|
|
37137
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3 h-3" })
|
|
37138
|
-
}
|
|
37139
|
-
)
|
|
37140
|
-
] }, child.id)),
|
|
37141
|
-
!readOnly && showAffordances && /* @__PURE__ */ jsx(Box, { as: "li", className: "list-none pl-0", children: /* @__PURE__ */ jsxs(
|
|
37142
|
-
Button,
|
|
37143
|
-
{
|
|
37144
|
-
type: "button",
|
|
37145
|
-
variant: "ghost",
|
|
37146
|
-
className: cn(
|
|
37147
|
-
"inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
37148
|
-
"hover:text-foreground p-0 h-auto"
|
|
37149
|
-
),
|
|
37150
|
-
onClick: addListItem,
|
|
37151
|
-
children: [
|
|
37152
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3 h-3" }),
|
|
37153
|
-
" ",
|
|
37154
|
-
t("richBlockEditor.addItem")
|
|
37155
|
-
]
|
|
37156
|
-
}
|
|
37157
|
-
) })
|
|
37038
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Bold, label: t("richTextEditor.bold"), active: toolbar.bold, onExec: () => execInline("bold") }),
|
|
37039
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Italic, label: t("richTextEditor.italic"), active: toolbar.italic, onExec: () => execInline("italic") }),
|
|
37040
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Underline, label: t("richTextEditor.underline"), active: toolbar.underline, onExec: () => execInline("underline") }),
|
|
37041
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Strikethrough, label: t("richTextEditor.strikethrough"), active: toolbar.strikeThrough, onExec: () => execInline("strikeThrough") }),
|
|
37042
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
37043
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading1, label: t("richTextEditor.heading1"), active: toolbar.block === "h1", onExec: () => execBlock("h1") }),
|
|
37044
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading2, label: t("richTextEditor.heading2"), active: toolbar.block === "h2", onExec: () => execBlock("h2") }),
|
|
37045
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading3, label: t("richTextEditor.heading3"), active: toolbar.block === "h3", onExec: () => execBlock("h3") }),
|
|
37046
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
37047
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: List, label: t("richTextEditor.bulletList"), active: toolbar.bullets, onExec: () => execList("insertUnorderedList") }),
|
|
37048
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: ListOrdered, label: t("richTextEditor.numberedList"), active: toolbar.numbers, onExec: () => execList("insertOrderedList") }),
|
|
37049
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
37050
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Quote, label: t("richTextEditor.quote"), active: toolbar.block === "blockquote", onExec: () => execBlock("blockquote") }),
|
|
37051
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Code, label: t("richTextEditor.code"), active: toolbar.block === "pre", onExec: () => execBlock("pre") }),
|
|
37052
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Link$1, label: toolbar.link ? t("richTextEditor.removeLink") : t("richTextEditor.link"), active: toolbar.link, onExec: execLink }),
|
|
37053
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Minus, label: t("richTextEditor.divider"), onExec: execRule })
|
|
37158
37054
|
]
|
|
37159
37055
|
}
|
|
37160
|
-
)
|
|
37161
|
-
|
|
37162
|
-
|
|
37163
|
-
default:
|
|
37164
|
-
return /* @__PURE__ */ jsx(
|
|
37165
|
-
Editable,
|
|
37056
|
+
),
|
|
37057
|
+
/* @__PURE__ */ jsx(
|
|
37058
|
+
Box,
|
|
37166
37059
|
{
|
|
37167
|
-
|
|
37168
|
-
|
|
37169
|
-
|
|
37170
|
-
|
|
37171
|
-
|
|
37172
|
-
|
|
37173
|
-
|
|
37060
|
+
ref,
|
|
37061
|
+
contentEditable: true,
|
|
37062
|
+
suppressContentEditableWarning: true,
|
|
37063
|
+
role: "textbox",
|
|
37064
|
+
"aria-multiline": "true",
|
|
37065
|
+
"aria-label": t("richTextEditor.editorSurface"),
|
|
37066
|
+
"data-placeholder": placeholder ?? t("richTextEditor.placeholder"),
|
|
37067
|
+
"data-empty": empty ? "true" : "false",
|
|
37068
|
+
className: cn(
|
|
37069
|
+
"almadar-rich-text max-w-none min-h-[8rem] outline-none",
|
|
37070
|
+
"data-[empty=true]:before:content-[attr(data-placeholder)]",
|
|
37071
|
+
"data-[empty=true]:before:text-muted-foreground/60",
|
|
37072
|
+
"data-[empty=true]:before:pointer-events-none",
|
|
37073
|
+
"data-[empty=true]:before:absolute",
|
|
37074
|
+
"relative cursor-text"
|
|
37075
|
+
),
|
|
37076
|
+
onInput: afterEdit,
|
|
37077
|
+
onKeyDown: handleKeyDown,
|
|
37078
|
+
onBlur: flushEmit
|
|
37174
37079
|
}
|
|
37175
|
-
)
|
|
37176
|
-
|
|
37080
|
+
)
|
|
37081
|
+
] });
|
|
37082
|
+
};
|
|
37083
|
+
RichTextEditor.displayName = "RichTextEditor";
|
|
37084
|
+
}
|
|
37085
|
+
});
|
|
37086
|
+
function renderIconInput4(icon, props) {
|
|
37087
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
|
|
37088
|
+
}
|
|
37089
|
+
function DocumentPanel({
|
|
37090
|
+
entity,
|
|
37091
|
+
title,
|
|
37092
|
+
subtitle,
|
|
37093
|
+
value,
|
|
37094
|
+
actions,
|
|
37095
|
+
maxInlineActions,
|
|
37096
|
+
editing = false,
|
|
37097
|
+
titleCommitEvent,
|
|
37098
|
+
contentChangeEvent,
|
|
37099
|
+
editEvent,
|
|
37100
|
+
doneEvent,
|
|
37101
|
+
editLabel,
|
|
37102
|
+
doneLabel,
|
|
37103
|
+
autosaveHint,
|
|
37104
|
+
placeholder,
|
|
37105
|
+
className
|
|
37106
|
+
}) {
|
|
37107
|
+
const eventBus = useEventBus();
|
|
37108
|
+
const { t } = useTranslate();
|
|
37109
|
+
const [titleDraft, setTitleDraft] = useState(null);
|
|
37110
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
37111
|
+
const actionDefs = actions ?? [];
|
|
37112
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
37113
|
+
const inlineActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
37114
|
+
const menuActions = actionDefs.filter((a) => !inlineActions.includes(a));
|
|
37115
|
+
const fireAction = (action) => {
|
|
37116
|
+
if (!action.event) return;
|
|
37117
|
+
eventBus.emit(`UI:${action.event}`, { id: recordId, row: entity });
|
|
37177
37118
|
};
|
|
37178
|
-
|
|
37119
|
+
const commitTitle = () => {
|
|
37120
|
+
if (!titleCommitEvent) return;
|
|
37121
|
+
const next = (titleDraft ?? "").trim();
|
|
37122
|
+
setTitleDraft(null);
|
|
37123
|
+
if (!next || next === title) return;
|
|
37124
|
+
eventBus.emit(`UI:${titleCommitEvent}`, { title: next, id: recordId });
|
|
37125
|
+
};
|
|
37126
|
+
const untitled = t("documentPanel.untitled") || "Untitled";
|
|
37127
|
+
const titleNode = titleCommitEvent && titleDraft !== null ? /* @__PURE__ */ jsx(
|
|
37128
|
+
Input,
|
|
37129
|
+
{
|
|
37130
|
+
value: titleDraft,
|
|
37131
|
+
autoFocus: true,
|
|
37132
|
+
"aria-label": t("common.title"),
|
|
37133
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
37134
|
+
onFocus: (e) => e.currentTarget.select(),
|
|
37135
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
37136
|
+
onBlur: commitTitle,
|
|
37137
|
+
onKeyDown: (e) => {
|
|
37138
|
+
if (e.key === "Enter") {
|
|
37139
|
+
e.preventDefault();
|
|
37140
|
+
commitTitle();
|
|
37141
|
+
} else if (e.key === "Escape") {
|
|
37142
|
+
e.preventDefault();
|
|
37143
|
+
setTitleDraft(null);
|
|
37144
|
+
}
|
|
37145
|
+
},
|
|
37146
|
+
"data-testid": "document-title-input"
|
|
37147
|
+
}
|
|
37148
|
+
) : titleCommitEvent ? /* @__PURE__ */ jsx(
|
|
37179
37149
|
Box,
|
|
37180
37150
|
{
|
|
37181
|
-
|
|
37182
|
-
|
|
37183
|
-
|
|
37184
|
-
),
|
|
37185
|
-
|
|
37186
|
-
|
|
37187
|
-
|
|
37188
|
-
|
|
37189
|
-
|
|
37151
|
+
role: "button",
|
|
37152
|
+
tabIndex: 0,
|
|
37153
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
37154
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
37155
|
+
onKeyDown: (e) => {
|
|
37156
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
37157
|
+
e.preventDefault();
|
|
37158
|
+
setTitleDraft(title ?? "");
|
|
37159
|
+
}
|
|
37160
|
+
},
|
|
37161
|
+
"data-testid": "document-title-editable",
|
|
37162
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", className: cn(!title && "text-muted-foreground"), children: title || untitled })
|
|
37163
|
+
}
|
|
37164
|
+
) : /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || untitled });
|
|
37165
|
+
const emitWithId = (event) => () => {
|
|
37166
|
+
if (event) eventBus.emit(`UI:${event}`, { id: recordId });
|
|
37167
|
+
};
|
|
37168
|
+
return /* @__PURE__ */ jsx(Card, { variant: "elevated", className: cn("w-full", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-6 sm:p-8", children: [
|
|
37169
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
37170
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
37171
|
+
titleNode,
|
|
37172
|
+
subtitle ? /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: subtitle }) : null
|
|
37173
|
+
] }),
|
|
37174
|
+
/* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0 pt-1 items-center", children: editing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
37175
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", className: "hidden sm:block", children: autosaveHint ?? (t("documentPanel.autosaveHint") || "") }),
|
|
37176
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: emitWithId(doneEvent), "data-testid": "document-done", children: doneLabel ?? (t("documentPanel.done") || "Done") })
|
|
37177
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
37178
|
+
editEvent && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: emitWithId(editEvent), "data-testid": "document-edit", children: [
|
|
37179
|
+
/* @__PURE__ */ jsx(Icon, { name: "edit", size: "xs", className: "mr-1" }),
|
|
37180
|
+
editLabel ?? (t("documentPanel.edit") || "Edit")
|
|
37181
|
+
] }),
|
|
37182
|
+
inlineActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
37183
|
+
Button,
|
|
37190
37184
|
{
|
|
37191
|
-
|
|
37192
|
-
|
|
37193
|
-
|
|
37194
|
-
|
|
37195
|
-
|
|
37185
|
+
variant: "primary",
|
|
37186
|
+
size: "sm",
|
|
37187
|
+
onClick: () => fireAction(action),
|
|
37188
|
+
"data-testid": `action-${action.event}`,
|
|
37189
|
+
children: [
|
|
37190
|
+
action.icon && renderIconInput4(action.icon, { size: "xs", className: "mr-1" }),
|
|
37191
|
+
action.label
|
|
37192
|
+
]
|
|
37193
|
+
},
|
|
37194
|
+
idx
|
|
37195
|
+
)),
|
|
37196
|
+
menuActions.length > 0 && /* @__PURE__ */ jsx(
|
|
37197
|
+
Menu,
|
|
37198
|
+
{
|
|
37199
|
+
position: "bottom-end",
|
|
37200
|
+
trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
|
|
37201
|
+
items: menuActions.map((action) => ({
|
|
37202
|
+
label: action.label,
|
|
37203
|
+
icon: action.icon,
|
|
37204
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
37205
|
+
onClick: () => fireAction(action)
|
|
37206
|
+
}))
|
|
37196
37207
|
}
|
|
37197
|
-
)
|
|
37198
|
-
|
|
37199
|
-
|
|
37200
|
-
}
|
|
37201
|
-
|
|
37208
|
+
)
|
|
37209
|
+
] }) })
|
|
37210
|
+
] }),
|
|
37211
|
+
editing ? /* @__PURE__ */ jsx(RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsx(
|
|
37212
|
+
Box,
|
|
37213
|
+
{
|
|
37214
|
+
onClick: emitWithId(editEvent),
|
|
37215
|
+
className: cn(
|
|
37216
|
+
"rounded-md px-1 -mx-1 min-h-[16rem]",
|
|
37217
|
+
editEvent && "cursor-text transition-colors hover:bg-muted/30"
|
|
37218
|
+
),
|
|
37219
|
+
"data-testid": "document-body",
|
|
37220
|
+
children: value && value !== "" ? /* @__PURE__ */ jsx(RichTextEditor, { value, readOnly: true }) : /* @__PURE__ */ jsx(Typography, { variant: "body", color: "muted", children: placeholder ?? (t("documentPanel.placeholder") || "") })
|
|
37221
|
+
}
|
|
37222
|
+
)
|
|
37223
|
+
] }) });
|
|
37202
37224
|
}
|
|
37203
|
-
var
|
|
37204
|
-
|
|
37205
|
-
"components/core/molecules/RichBlockEditor.tsx"() {
|
|
37225
|
+
var init_DocumentPanel = __esm({
|
|
37226
|
+
"components/core/molecules/DocumentPanel.tsx"() {
|
|
37206
37227
|
"use client";
|
|
37207
37228
|
init_cn();
|
|
37208
|
-
|
|
37229
|
+
init_useEventBus();
|
|
37230
|
+
init_Box();
|
|
37231
|
+
init_Stack();
|
|
37209
37232
|
init_Typography();
|
|
37210
37233
|
init_Button();
|
|
37211
|
-
|
|
37212
|
-
init_Divider();
|
|
37213
|
-
init_Input();
|
|
37234
|
+
init_Card();
|
|
37214
37235
|
init_Icon();
|
|
37215
|
-
|
|
37216
|
-
|
|
37217
|
-
|
|
37218
|
-
|
|
37219
|
-
|
|
37220
|
-
|
|
37221
|
-
|
|
37222
|
-
|
|
37223
|
-
|
|
37224
|
-
|
|
37225
|
-
|
|
37226
|
-
|
|
37227
|
-
|
|
37228
|
-
|
|
37229
|
-
|
|
37230
|
-
|
|
37231
|
-
|
|
37232
|
-
|
|
37233
|
-
|
|
37234
|
-
|
|
37235
|
-
|
|
37236
|
-
|
|
37237
|
-
|
|
37238
|
-
|
|
37239
|
-
|
|
37240
|
-
|
|
37241
|
-
|
|
37242
|
-
|
|
37243
|
-
|
|
37244
|
-
|
|
37245
|
-
|
|
37246
|
-
|
|
37247
|
-
|
|
37248
|
-
|
|
37249
|
-
|
|
37250
|
-
|
|
37251
|
-
|
|
37252
|
-
|
|
37253
|
-
|
|
37254
|
-
|
|
37255
|
-
|
|
37256
|
-
|
|
37257
|
-
|
|
37258
|
-
|
|
37259
|
-
|
|
37260
|
-
|
|
37261
|
-
|
|
37262
|
-
|
|
37263
|
-
|
|
37264
|
-
|
|
37265
|
-
|
|
37266
|
-
|
|
37267
|
-
|
|
37268
|
-
|
|
37269
|
-
|
|
37270
|
-
|
|
37271
|
-
|
|
37272
|
-
|
|
37273
|
-
|
|
37274
|
-
const [blocks, setBlocks] = useState(
|
|
37275
|
-
() => normalizeBlocks(initialBlocks)
|
|
37276
|
-
);
|
|
37277
|
-
const onChangeRef = useRef(onChange);
|
|
37278
|
-
useEffect(() => {
|
|
37279
|
-
onChangeRef.current = onChange;
|
|
37280
|
-
}, [onChange]);
|
|
37281
|
-
const eventBus = useEventBus();
|
|
37282
|
-
const changeEventRef = useRef(changeEvent);
|
|
37283
|
-
useEffect(() => {
|
|
37284
|
-
changeEventRef.current = changeEvent;
|
|
37285
|
-
}, [changeEvent]);
|
|
37286
|
-
const commit = useCallback((next) => {
|
|
37287
|
-
setBlocks(next);
|
|
37288
|
-
onChangeRef.current?.(next);
|
|
37289
|
-
const evt = changeEventRef.current;
|
|
37290
|
-
if (evt) eventBus.emit(`UI:${evt}`, { blocks: next });
|
|
37291
|
-
}, [eventBus]);
|
|
37292
|
-
const handleAppend = useCallback(
|
|
37293
|
-
(type) => {
|
|
37294
|
-
if (readOnly) return;
|
|
37295
|
-
commit([...blocks, createBlock(type)]);
|
|
37296
|
-
},
|
|
37297
|
-
[blocks, commit, readOnly]
|
|
37298
|
-
);
|
|
37299
|
-
const handleUpdate = useCallback(
|
|
37300
|
-
(id, updater) => {
|
|
37301
|
-
commit(replaceBlock(blocks, id, updater));
|
|
37302
|
-
},
|
|
37303
|
-
[blocks, commit]
|
|
37304
|
-
);
|
|
37305
|
-
const handleDelete = useCallback(
|
|
37306
|
-
(id) => {
|
|
37307
|
-
const next = removeBlock(blocks, id);
|
|
37308
|
-
commit(next.length > 0 ? next : [createBlock("paragraph")]);
|
|
37309
|
-
},
|
|
37310
|
-
[blocks, commit]
|
|
37311
|
-
);
|
|
37312
|
-
const handleDuplicate = useCallback(
|
|
37313
|
-
(id) => {
|
|
37314
|
-
const target = blocks.find((b) => b.id === id);
|
|
37315
|
-
if (!target) return;
|
|
37316
|
-
commit(insertAfter(blocks, id, duplicateBlock(target)));
|
|
37317
|
-
},
|
|
37318
|
-
[blocks, commit]
|
|
37236
|
+
init_Input();
|
|
37237
|
+
init_Menu();
|
|
37238
|
+
init_RichTextEditor();
|
|
37239
|
+
}
|
|
37240
|
+
});
|
|
37241
|
+
function renderIconInput5(icon, props) {
|
|
37242
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
|
|
37243
|
+
}
|
|
37244
|
+
function fieldName(field) {
|
|
37245
|
+
return field.name ?? field.key ?? "";
|
|
37246
|
+
}
|
|
37247
|
+
function relationLabel(value) {
|
|
37248
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) return null;
|
|
37249
|
+
for (const key of ["name", "title", "label"]) {
|
|
37250
|
+
const candidate = value[key];
|
|
37251
|
+
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
37252
|
+
}
|
|
37253
|
+
const id = value.id;
|
|
37254
|
+
return id !== void 0 && id !== null ? String(id) : null;
|
|
37255
|
+
}
|
|
37256
|
+
function fieldKind(field, value) {
|
|
37257
|
+
if (field.kind) return field.kind;
|
|
37258
|
+
if (field.options && field.options.length > 0) return "select";
|
|
37259
|
+
if (typeof value === "boolean" || field.format === "boolean") return "boolean";
|
|
37260
|
+
if (Array.isArray(value) || relationLabel(value ?? null) !== null) return "readonly";
|
|
37261
|
+
return "text";
|
|
37262
|
+
}
|
|
37263
|
+
function DocumentDetails({
|
|
37264
|
+
entity,
|
|
37265
|
+
fields,
|
|
37266
|
+
metaCommitEvent,
|
|
37267
|
+
title,
|
|
37268
|
+
className
|
|
37269
|
+
}) {
|
|
37270
|
+
const eventBus = useEventBus();
|
|
37271
|
+
const { t } = useTranslate();
|
|
37272
|
+
const [fieldDraft, setFieldDraft] = useState(null);
|
|
37273
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
37274
|
+
const fieldDefs = (fields ?? []).filter((f3) => fieldName(f3) !== "");
|
|
37275
|
+
if (fieldDefs.length === 0) return null;
|
|
37276
|
+
const commitField = (name, next, current) => {
|
|
37277
|
+
setFieldDraft(null);
|
|
37278
|
+
if (!metaCommitEvent || next === current) return;
|
|
37279
|
+
eventBus.emit(`UI:${metaCommitEvent}`, { id: recordId, patch: { id: recordId, [name]: next } });
|
|
37280
|
+
};
|
|
37281
|
+
const renderValue = (field) => {
|
|
37282
|
+
const name = fieldName(field);
|
|
37283
|
+
const raw = getNestedValue(entity ?? {}, name);
|
|
37284
|
+
const kind = fieldKind(field, raw);
|
|
37285
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
37286
|
+
if (kind === "boolean") {
|
|
37287
|
+
return /* @__PURE__ */ jsx(
|
|
37288
|
+
Switch,
|
|
37289
|
+
{
|
|
37290
|
+
checked: Boolean(raw),
|
|
37291
|
+
disabled: !metaCommitEvent,
|
|
37292
|
+
"aria-label": label,
|
|
37293
|
+
onChange: (checked) => commitField(name, checked, Boolean(raw))
|
|
37294
|
+
}
|
|
37319
37295
|
);
|
|
37320
|
-
|
|
37321
|
-
|
|
37322
|
-
|
|
37323
|
-
|
|
37324
|
-
|
|
37325
|
-
|
|
37326
|
-
|
|
37296
|
+
}
|
|
37297
|
+
if (kind === "select") {
|
|
37298
|
+
return /* @__PURE__ */ jsx(
|
|
37299
|
+
Select,
|
|
37300
|
+
{
|
|
37301
|
+
value: raw !== void 0 && raw !== null ? String(raw) : "",
|
|
37302
|
+
disabled: !metaCommitEvent,
|
|
37303
|
+
"aria-label": label,
|
|
37304
|
+
className: "h-8 w-full",
|
|
37305
|
+
options: (field.options ?? []).map((opt) => ({ value: opt, label: humanizeEnumValue(opt) })),
|
|
37306
|
+
onChange: (e) => commitField(name, e.target.value, raw)
|
|
37307
|
+
}
|
|
37327
37308
|
);
|
|
37328
|
-
|
|
37329
|
-
|
|
37309
|
+
}
|
|
37310
|
+
if (kind === "readonly" || !metaCommitEvent) {
|
|
37311
|
+
if (Array.isArray(raw)) {
|
|
37312
|
+
if (raw.length === 0) {
|
|
37313
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: "\u2014" });
|
|
37314
|
+
}
|
|
37315
|
+
return /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: raw.map((item, i) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: relationLabel(item) ?? humanizeEnumValue(String(item)) }, i)) });
|
|
37316
|
+
}
|
|
37317
|
+
const shown2 = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
37318
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "small", className: "break-words", children: shown2 });
|
|
37319
|
+
}
|
|
37320
|
+
if (fieldDraft?.name === name) {
|
|
37321
|
+
return /* @__PURE__ */ jsx(
|
|
37322
|
+
Input,
|
|
37330
37323
|
{
|
|
37331
|
-
|
|
37332
|
-
|
|
37333
|
-
|
|
37334
|
-
|
|
37335
|
-
|
|
37336
|
-
|
|
37337
|
-
|
|
37338
|
-
|
|
37339
|
-
|
|
37340
|
-
|
|
37341
|
-
|
|
37342
|
-
|
|
37343
|
-
|
|
37344
|
-
|
|
37345
|
-
|
|
37346
|
-
|
|
37347
|
-
return /* @__PURE__ */ jsxs(
|
|
37348
|
-
Button,
|
|
37349
|
-
{
|
|
37350
|
-
type: "button",
|
|
37351
|
-
variant: "ghost",
|
|
37352
|
-
size: "sm",
|
|
37353
|
-
"aria-label": t("richBlockEditor.insertEntry", { label: entryLabel }),
|
|
37354
|
-
title: entryLabel,
|
|
37355
|
-
onClick: () => handleAppend(entry.type),
|
|
37356
|
-
children: [
|
|
37357
|
-
/* @__PURE__ */ jsx(Icon2, { size: 14 }),
|
|
37358
|
-
/* @__PURE__ */ jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
|
|
37359
|
-
]
|
|
37360
|
-
},
|
|
37361
|
-
entry.type
|
|
37362
|
-
);
|
|
37363
|
-
})
|
|
37364
|
-
}
|
|
37365
|
-
),
|
|
37366
|
-
/* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-1 px-3 py-3", children: blocks.map((block) => /* @__PURE__ */ jsx(
|
|
37367
|
-
BlockRow,
|
|
37368
|
-
{
|
|
37369
|
-
block,
|
|
37370
|
-
readOnly,
|
|
37371
|
-
showAffordances: enableBlocks,
|
|
37372
|
-
placeholder,
|
|
37373
|
-
onUpdate: (updater) => handleUpdate(block.id, updater),
|
|
37374
|
-
onDelete: () => handleDelete(block.id),
|
|
37375
|
-
onDuplicate: () => handleDuplicate(block.id),
|
|
37376
|
-
onChangeType: (type) => handleChangeType(block.id, type)
|
|
37377
|
-
},
|
|
37378
|
-
block.id
|
|
37379
|
-
)) })
|
|
37380
|
-
]
|
|
37324
|
+
value: fieldDraft.value,
|
|
37325
|
+
autoFocus: true,
|
|
37326
|
+
"aria-label": label,
|
|
37327
|
+
className: "h-8 w-full",
|
|
37328
|
+
onChange: (e) => setFieldDraft({ name, value: e.target.value }),
|
|
37329
|
+
onBlur: () => commitField(name, fieldDraft.value.trim(), raw),
|
|
37330
|
+
onKeyDown: (e) => {
|
|
37331
|
+
if (e.key === "Enter") {
|
|
37332
|
+
e.preventDefault();
|
|
37333
|
+
commitField(name, fieldDraft.value.trim(), raw);
|
|
37334
|
+
} else if (e.key === "Escape") {
|
|
37335
|
+
e.preventDefault();
|
|
37336
|
+
setFieldDraft(null);
|
|
37337
|
+
}
|
|
37338
|
+
},
|
|
37339
|
+
"data-testid": `document-property-input-${name}`
|
|
37381
37340
|
}
|
|
37382
37341
|
);
|
|
37383
|
-
}
|
|
37384
|
-
|
|
37342
|
+
}
|
|
37343
|
+
const shown = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
37344
|
+
return /* @__PURE__ */ jsx(
|
|
37345
|
+
Box,
|
|
37346
|
+
{
|
|
37347
|
+
role: "button",
|
|
37348
|
+
tabIndex: 0,
|
|
37349
|
+
className: cn(
|
|
37350
|
+
"cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
37351
|
+
(raw === void 0 || raw === null || raw === "") && "text-muted-foreground"
|
|
37352
|
+
),
|
|
37353
|
+
onClick: () => setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" }),
|
|
37354
|
+
onKeyDown: (e) => {
|
|
37355
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
37356
|
+
e.preventDefault();
|
|
37357
|
+
setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" });
|
|
37358
|
+
}
|
|
37359
|
+
},
|
|
37360
|
+
"data-testid": `document-property-${name}`,
|
|
37361
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "break-words", children: shown })
|
|
37362
|
+
}
|
|
37363
|
+
);
|
|
37364
|
+
};
|
|
37365
|
+
return /* @__PURE__ */ jsx(Card, { variant: "bordered", className: cn("w-full", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-4", children: [
|
|
37366
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", weight: "medium", className: "uppercase tracking-wide", children: title ?? (t("documentDetails.title") || "Details") }),
|
|
37367
|
+
/* @__PURE__ */ jsx(VStack, { gap: "sm", children: fieldDefs.map((field) => {
|
|
37368
|
+
const name = fieldName(field);
|
|
37369
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
37370
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
37371
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
37372
|
+
field.icon && renderIconInput5(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
37373
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
37374
|
+
] }),
|
|
37375
|
+
/* @__PURE__ */ jsx(Box, { className: "min-w-0", children: renderValue(field) })
|
|
37376
|
+
] }, name);
|
|
37377
|
+
}) })
|
|
37378
|
+
] }) });
|
|
37379
|
+
}
|
|
37380
|
+
var init_DocumentDetails = __esm({
|
|
37381
|
+
"components/core/molecules/DocumentDetails.tsx"() {
|
|
37382
|
+
"use client";
|
|
37383
|
+
init_cn();
|
|
37384
|
+
init_format();
|
|
37385
|
+
init_getNestedValue();
|
|
37386
|
+
init_useEventBus();
|
|
37387
|
+
init_Box();
|
|
37388
|
+
init_Stack();
|
|
37389
|
+
init_Typography();
|
|
37390
|
+
init_Badge();
|
|
37391
|
+
init_Card();
|
|
37392
|
+
init_Icon();
|
|
37393
|
+
init_Input();
|
|
37394
|
+
init_Select();
|
|
37395
|
+
init_Switch();
|
|
37385
37396
|
}
|
|
37386
37397
|
});
|
|
37387
37398
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
@@ -42330,8 +42341,8 @@ var init_DataTable = __esm({
|
|
|
42330
42341
|
DataTable.displayName = "DataTable";
|
|
42331
42342
|
}
|
|
42332
42343
|
});
|
|
42333
|
-
function getBadgeVariant(
|
|
42334
|
-
const name =
|
|
42344
|
+
function getBadgeVariant(fieldName2, value) {
|
|
42345
|
+
const name = fieldName2.toLowerCase();
|
|
42335
42346
|
const val = String(value).toLowerCase();
|
|
42336
42347
|
if (name.includes("status")) {
|
|
42337
42348
|
if (val.includes("complete") || val.includes("done") || val.includes("active"))
|
|
@@ -42347,12 +42358,12 @@ function getBadgeVariant(fieldName, value) {
|
|
|
42347
42358
|
}
|
|
42348
42359
|
return "default";
|
|
42349
42360
|
}
|
|
42350
|
-
function formatFieldValue2(value,
|
|
42361
|
+
function formatFieldValue2(value, fieldName2) {
|
|
42351
42362
|
if (typeof value === "number") {
|
|
42352
|
-
if (
|
|
42363
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
42353
42364
|
return `${value}%`;
|
|
42354
42365
|
}
|
|
42355
|
-
if (
|
|
42366
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
42356
42367
|
return `$${value.toLocaleString()}`;
|
|
42357
42368
|
}
|
|
42358
42369
|
return value.toLocaleString();
|
|
@@ -42362,7 +42373,7 @@ function formatFieldValue2(value, fieldName) {
|
|
|
42362
42373
|
}
|
|
42363
42374
|
return String(value);
|
|
42364
42375
|
}
|
|
42365
|
-
function renderRichFieldValue(value,
|
|
42376
|
+
function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
42366
42377
|
if (value === void 0 || value === null) return "\u2014";
|
|
42367
42378
|
const str = String(value);
|
|
42368
42379
|
switch (fieldType) {
|
|
@@ -42373,7 +42384,7 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
42373
42384
|
"img",
|
|
42374
42385
|
{
|
|
42375
42386
|
src: str,
|
|
42376
|
-
alt: formatFieldLabel(
|
|
42387
|
+
alt: formatFieldLabel(fieldName2),
|
|
42377
42388
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
42378
42389
|
loading: "lazy"
|
|
42379
42390
|
}
|
|
@@ -42508,9 +42519,9 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
42508
42519
|
return /* @__PURE__ */ jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
|
|
42509
42520
|
default:
|
|
42510
42521
|
if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
|
|
42511
|
-
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(
|
|
42522
|
+
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(fieldName2, str), children: humanizeEnumValue(str) });
|
|
42512
42523
|
}
|
|
42513
|
-
return formatFieldValue2(value,
|
|
42524
|
+
return formatFieldValue2(value, fieldName2);
|
|
42514
42525
|
}
|
|
42515
42526
|
}
|
|
42516
42527
|
function normalizeFieldDefs(fields) {
|
|
@@ -43353,7 +43364,21 @@ var init_Form = __esm({
|
|
|
43353
43364
|
const normalizedInitialData = React87__default.useMemo(() => {
|
|
43354
43365
|
const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
|
|
43355
43366
|
const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
|
|
43356
|
-
|
|
43367
|
+
const merged = entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
|
|
43368
|
+
const toId = (value) => {
|
|
43369
|
+
if (value === null || value === void 0 || typeof value !== "object" || value instanceof Date) return value;
|
|
43370
|
+
if (Array.isArray(value)) {
|
|
43371
|
+
return value.map(
|
|
43372
|
+
(item) => item !== null && typeof item === "object" && !Array.isArray(item) && !(item instanceof Date) && item.id !== void 0 && item.id !== null ? String(item.id) : item
|
|
43373
|
+
);
|
|
43374
|
+
}
|
|
43375
|
+
return value.id !== void 0 && value.id !== null ? String(value.id) : value;
|
|
43376
|
+
};
|
|
43377
|
+
const normalized = {};
|
|
43378
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
43379
|
+
normalized[key] = key === "id" ? value : toId(value);
|
|
43380
|
+
}
|
|
43381
|
+
return normalized;
|
|
43357
43382
|
}, [entity, initialData]);
|
|
43358
43383
|
const entityDerivedFields = React87__default.useMemo(() => {
|
|
43359
43384
|
if (fields && fields.length > 0) return void 0;
|
|
@@ -43482,8 +43507,8 @@ var init_Form = __esm({
|
|
|
43482
43507
|
checkViolations(name, newFormData);
|
|
43483
43508
|
};
|
|
43484
43509
|
const isFieldVisible = React87__default.useCallback(
|
|
43485
|
-
(
|
|
43486
|
-
const condition = conditionalFields[
|
|
43510
|
+
(fieldName2) => {
|
|
43511
|
+
const condition = conditionalFields[fieldName2];
|
|
43487
43512
|
if (!condition) return true;
|
|
43488
43513
|
return Boolean(evaluateFormExpression(condition, evalContext));
|
|
43489
43514
|
},
|
|
@@ -43529,9 +43554,9 @@ var init_Form = __esm({
|
|
|
43529
43554
|
};
|
|
43530
43555
|
const handleInvalid = (e) => {
|
|
43531
43556
|
const target = e.target;
|
|
43532
|
-
const
|
|
43557
|
+
const fieldName2 = target.getAttribute("data-field-name") ?? target.name ?? "";
|
|
43533
43558
|
const fieldMessage = target.validationMessage || "Invalid value";
|
|
43534
|
-
debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
|
|
43559
|
+
debug("forms", "invalid", { mode: formMode, fieldName: fieldName2, fieldMessage });
|
|
43535
43560
|
queueMicrotask(() => {
|
|
43536
43561
|
const form = formRef.current;
|
|
43537
43562
|
if (!form) return;
|
|
@@ -43567,22 +43592,22 @@ var init_Form = __esm({
|
|
|
43567
43592
|
};
|
|
43568
43593
|
const renderField = React87__default.useCallback(
|
|
43569
43594
|
(field) => {
|
|
43570
|
-
const
|
|
43571
|
-
if (!
|
|
43572
|
-
if (!isFieldVisible(
|
|
43595
|
+
const fieldName2 = field.name || field.field;
|
|
43596
|
+
if (!fieldName2) return null;
|
|
43597
|
+
if (!isFieldVisible(fieldName2)) {
|
|
43573
43598
|
return null;
|
|
43574
43599
|
}
|
|
43575
43600
|
const inputType = determineInputType(field);
|
|
43576
|
-
const label = field.label ||
|
|
43577
|
-
const currentValue = formData[
|
|
43578
|
-
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", "data-field":
|
|
43601
|
+
const label = field.label || fieldName2.charAt(0).toUpperCase() + fieldName2.slice(1).replace(/([A-Z])/g, " $1");
|
|
43602
|
+
const currentValue = formData[fieldName2] ?? field.defaultValue ?? "";
|
|
43603
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", "data-field": fieldName2, children: [
|
|
43579
43604
|
inputType !== "checkbox" && /* @__PURE__ */ jsxs(Typography, { as: "label", variant: "label", weight: "bold", children: [
|
|
43580
43605
|
label,
|
|
43581
43606
|
field.required && /* @__PURE__ */ jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
|
|
43582
43607
|
] }),
|
|
43583
|
-
renderFieldInput(field,
|
|
43608
|
+
renderFieldInput(field, fieldName2, inputType, currentValue, label),
|
|
43584
43609
|
field.hint && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
|
|
43585
|
-
] },
|
|
43610
|
+
] }, fieldName2);
|
|
43586
43611
|
},
|
|
43587
43612
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
43588
43613
|
);
|
|
@@ -43611,8 +43636,8 @@ var init_Form = __esm({
|
|
|
43611
43636
|
}
|
|
43612
43637
|
return field;
|
|
43613
43638
|
}).map((field) => {
|
|
43614
|
-
const
|
|
43615
|
-
const override = fieldOverrides?.find((o) => o.name ===
|
|
43639
|
+
const fieldName2 = field.name || field.field;
|
|
43640
|
+
const override = fieldOverrides?.find((o) => o.name === fieldName2);
|
|
43616
43641
|
if (!override) return field;
|
|
43617
43642
|
return {
|
|
43618
43643
|
...field,
|
|
@@ -43668,11 +43693,11 @@ var init_Form = __esm({
|
|
|
43668
43693
|
] }, section.id);
|
|
43669
43694
|
}).filter(Boolean);
|
|
43670
43695
|
}, [sections, isSectionVisible, collapsedSections, renderField, gap]);
|
|
43671
|
-
function renderFieldInput(field,
|
|
43696
|
+
function renderFieldInput(field, fieldName2, inputType, currentValue, label) {
|
|
43672
43697
|
const commonProps = {
|
|
43673
|
-
id:
|
|
43674
|
-
name:
|
|
43675
|
-
"data-field-name":
|
|
43698
|
+
id: fieldName2,
|
|
43699
|
+
name: fieldName2,
|
|
43700
|
+
"data-field-name": fieldName2,
|
|
43676
43701
|
required: field.required,
|
|
43677
43702
|
disabled: isLoading,
|
|
43678
43703
|
placeholder: field.placeholder,
|
|
@@ -43686,7 +43711,7 @@ var init_Form = __esm({
|
|
|
43686
43711
|
...commonProps,
|
|
43687
43712
|
label: label + (field.required ? " *" : ""),
|
|
43688
43713
|
checked: Boolean(currentValue),
|
|
43689
|
-
onChange: (e) => handleChange(
|
|
43714
|
+
onChange: (e) => handleChange(fieldName2, e.target.checked)
|
|
43690
43715
|
}
|
|
43691
43716
|
);
|
|
43692
43717
|
case "textarea":
|
|
@@ -43695,7 +43720,7 @@ var init_Form = __esm({
|
|
|
43695
43720
|
{
|
|
43696
43721
|
...commonProps,
|
|
43697
43722
|
value: String(currentValue),
|
|
43698
|
-
onChange: (e) => handleChange(
|
|
43723
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43699
43724
|
minLength: field.min,
|
|
43700
43725
|
maxLength: field.max
|
|
43701
43726
|
}
|
|
@@ -43708,14 +43733,14 @@ var init_Form = __esm({
|
|
|
43708
43733
|
...commonProps,
|
|
43709
43734
|
options,
|
|
43710
43735
|
value: String(currentValue),
|
|
43711
|
-
onValueChange: (v) => handleChange(
|
|
43736
|
+
onValueChange: (v) => handleChange(fieldName2, v),
|
|
43712
43737
|
placeholder: field.placeholder || `Select ${label}...`
|
|
43713
43738
|
}
|
|
43714
43739
|
);
|
|
43715
43740
|
}
|
|
43716
43741
|
case "relation": {
|
|
43717
|
-
const relationOptions = relationsData[
|
|
43718
|
-
const relationLoading = relationsLoading[
|
|
43742
|
+
const relationOptions = relationsData[fieldName2] || [];
|
|
43743
|
+
const relationLoading = relationsLoading[fieldName2] || false;
|
|
43719
43744
|
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
43720
43745
|
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
43721
43746
|
return /* @__PURE__ */ jsx(
|
|
@@ -43727,7 +43752,7 @@ var init_Form = __esm({
|
|
|
43727
43752
|
clearable: true,
|
|
43728
43753
|
options: [...relationOptions],
|
|
43729
43754
|
value: selectedValues,
|
|
43730
|
-
onValueChange: (value) => handleChange(
|
|
43755
|
+
onValueChange: (value) => handleChange(fieldName2, Array.isArray(value) ? value : [value]),
|
|
43731
43756
|
placeholder: field.placeholder || `Select ${label}...`
|
|
43732
43757
|
}
|
|
43733
43758
|
);
|
|
@@ -43737,7 +43762,7 @@ var init_Form = __esm({
|
|
|
43737
43762
|
{
|
|
43738
43763
|
...commonProps,
|
|
43739
43764
|
value: currentValue ? String(currentValue) : void 0,
|
|
43740
|
-
onChange: (value) => handleChange(
|
|
43765
|
+
onChange: (value) => handleChange(fieldName2, value),
|
|
43741
43766
|
options: relationOptions,
|
|
43742
43767
|
isLoading: relationLoading,
|
|
43743
43768
|
placeholder: field.placeholder || `Select ${label}...`,
|
|
@@ -43754,7 +43779,7 @@ var init_Form = __esm({
|
|
|
43754
43779
|
placeholder: field.placeholder,
|
|
43755
43780
|
disabled: isLoading,
|
|
43756
43781
|
value: arrayValue,
|
|
43757
|
-
onChange: (next) => handleChange(
|
|
43782
|
+
onChange: (next) => handleChange(fieldName2, [...next])
|
|
43758
43783
|
}
|
|
43759
43784
|
);
|
|
43760
43785
|
}
|
|
@@ -43766,7 +43791,7 @@ var init_Form = __esm({
|
|
|
43766
43791
|
type: "number",
|
|
43767
43792
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
43768
43793
|
onChange: (e) => handleChange(
|
|
43769
|
-
|
|
43794
|
+
fieldName2,
|
|
43770
43795
|
e.target.value ? Number(e.target.value) : void 0
|
|
43771
43796
|
),
|
|
43772
43797
|
min: field.min,
|
|
@@ -43783,7 +43808,7 @@ var init_Form = __esm({
|
|
|
43783
43808
|
icon: DollarSign,
|
|
43784
43809
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
43785
43810
|
onChange: (e) => handleChange(
|
|
43786
|
-
|
|
43811
|
+
fieldName2,
|
|
43787
43812
|
e.target.value ? Number(e.target.value) : void 0
|
|
43788
43813
|
),
|
|
43789
43814
|
min: field.min,
|
|
@@ -43801,7 +43826,7 @@ var init_Form = __esm({
|
|
|
43801
43826
|
const f3 = files[0];
|
|
43802
43827
|
if (!f3) return;
|
|
43803
43828
|
const reader = new FileReader();
|
|
43804
|
-
reader.onload = () => handleChange(
|
|
43829
|
+
reader.onload = () => handleChange(fieldName2, {
|
|
43805
43830
|
name: f3.name,
|
|
43806
43831
|
mimeType: f3.type,
|
|
43807
43832
|
sizeBytes: f3.size,
|
|
@@ -43818,7 +43843,7 @@ var init_Form = __esm({
|
|
|
43818
43843
|
...commonProps,
|
|
43819
43844
|
type: "date",
|
|
43820
43845
|
value: formatDateValue(currentValue),
|
|
43821
|
-
onChange: (e) => handleChange(
|
|
43846
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
43822
43847
|
}
|
|
43823
43848
|
);
|
|
43824
43849
|
case "datetime-local":
|
|
@@ -43828,7 +43853,7 @@ var init_Form = __esm({
|
|
|
43828
43853
|
...commonProps,
|
|
43829
43854
|
type: "datetime-local",
|
|
43830
43855
|
value: formatDateTimeValue(currentValue),
|
|
43831
|
-
onChange: (e) => handleChange(
|
|
43856
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
43832
43857
|
}
|
|
43833
43858
|
);
|
|
43834
43859
|
case "email":
|
|
@@ -43838,7 +43863,7 @@ var init_Form = __esm({
|
|
|
43838
43863
|
...commonProps,
|
|
43839
43864
|
type: "email",
|
|
43840
43865
|
value: String(currentValue),
|
|
43841
|
-
onChange: (e) => handleChange(
|
|
43866
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43842
43867
|
minLength: field.min,
|
|
43843
43868
|
maxLength: field.max
|
|
43844
43869
|
}
|
|
@@ -43850,7 +43875,7 @@ var init_Form = __esm({
|
|
|
43850
43875
|
...commonProps,
|
|
43851
43876
|
type: "url",
|
|
43852
43877
|
value: String(currentValue),
|
|
43853
|
-
onChange: (e) => handleChange(
|
|
43878
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43854
43879
|
minLength: field.min,
|
|
43855
43880
|
maxLength: field.max
|
|
43856
43881
|
}
|
|
@@ -43862,7 +43887,7 @@ var init_Form = __esm({
|
|
|
43862
43887
|
...commonProps,
|
|
43863
43888
|
type: "password",
|
|
43864
43889
|
value: String(currentValue),
|
|
43865
|
-
onChange: (e) => handleChange(
|
|
43890
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43866
43891
|
minLength: field.min,
|
|
43867
43892
|
maxLength: field.max
|
|
43868
43893
|
}
|
|
@@ -43875,7 +43900,7 @@ var init_Form = __esm({
|
|
|
43875
43900
|
...commonProps,
|
|
43876
43901
|
type: "text",
|
|
43877
43902
|
value: String(currentValue),
|
|
43878
|
-
onChange: (e) => handleChange(
|
|
43903
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
43879
43904
|
minLength: field.min,
|
|
43880
43905
|
maxLength: field.max
|
|
43881
43906
|
}
|
|
@@ -44232,7 +44257,7 @@ function entityFieldsFromListItem(item) {
|
|
|
44232
44257
|
}
|
|
44233
44258
|
return result;
|
|
44234
44259
|
}
|
|
44235
|
-
function getStatusStyle(
|
|
44260
|
+
function getStatusStyle(fieldName2, value) {
|
|
44236
44261
|
const val = String(value).toLowerCase();
|
|
44237
44262
|
if (val.includes("complete") || val.includes("done"))
|
|
44238
44263
|
return STATUS_STYLES.complete;
|
|
@@ -44248,12 +44273,12 @@ function getStatusStyle(fieldName, value) {
|
|
|
44248
44273
|
if (val.includes("low")) return STATUS_STYLES.low;
|
|
44249
44274
|
return STATUS_STYLES.default;
|
|
44250
44275
|
}
|
|
44251
|
-
function formatValue3(value,
|
|
44276
|
+
function formatValue3(value, fieldName2) {
|
|
44252
44277
|
if (typeof value === "number") {
|
|
44253
|
-
if (
|
|
44278
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
44254
44279
|
return `${value}%`;
|
|
44255
44280
|
}
|
|
44256
|
-
if (
|
|
44281
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
44257
44282
|
return new Intl.NumberFormat("en-US", {
|
|
44258
44283
|
style: "currency",
|
|
44259
44284
|
currency: "USD",
|
|
@@ -44276,8 +44301,8 @@ function formatValue3(value, fieldName) {
|
|
|
44276
44301
|
}
|
|
44277
44302
|
return String(value);
|
|
44278
44303
|
}
|
|
44279
|
-
function formatFieldLabel2(
|
|
44280
|
-
return humanizeFieldName(
|
|
44304
|
+
function formatFieldLabel2(fieldName2) {
|
|
44305
|
+
return humanizeFieldName(fieldName2).replace(/\sId$/, "").trim();
|
|
44281
44306
|
}
|
|
44282
44307
|
var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
|
|
44283
44308
|
var init_List = __esm({
|
|
@@ -44345,9 +44370,9 @@ var init_List = __esm({
|
|
|
44345
44370
|
};
|
|
44346
44371
|
StatusBadge = ({
|
|
44347
44372
|
value,
|
|
44348
|
-
fieldName
|
|
44373
|
+
fieldName: fieldName2
|
|
44349
44374
|
}) => {
|
|
44350
|
-
const style = getStatusStyle(
|
|
44375
|
+
const style = getStatusStyle(fieldName2, value);
|
|
44351
44376
|
return /* @__PURE__ */ jsxs(
|
|
44352
44377
|
Typography,
|
|
44353
44378
|
{
|
|
@@ -47260,8 +47285,8 @@ var init_StatCard = __esm({
|
|
|
47260
47285
|
return items.length;
|
|
47261
47286
|
}
|
|
47262
47287
|
if (field.includes(":")) {
|
|
47263
|
-
const [
|
|
47264
|
-
return items.filter((item) => item[
|
|
47288
|
+
const [fieldName2, fieldValue] = field.split(":");
|
|
47289
|
+
return items.filter((item) => item[fieldName2] === fieldValue).length;
|
|
47265
47290
|
}
|
|
47266
47291
|
const fieldExistsOnItems = items.some((item) => field in item);
|
|
47267
47292
|
if (fieldExistsOnItems) {
|
|
@@ -48781,6 +48806,8 @@ var init_component_registry_generated = __esm({
|
|
|
48781
48806
|
init_DocSearch();
|
|
48782
48807
|
init_DocSidebar();
|
|
48783
48808
|
init_DocTOC();
|
|
48809
|
+
init_DocumentDetails();
|
|
48810
|
+
init_DocumentPanel();
|
|
48784
48811
|
init_DocumentViewer();
|
|
48785
48812
|
init_DrawFxLayer();
|
|
48786
48813
|
init_DrawGroup();
|
|
@@ -48890,7 +48917,7 @@ var init_component_registry_generated = __esm({
|
|
|
48890
48917
|
init_RelationSelect();
|
|
48891
48918
|
init_RepeatableFormSection();
|
|
48892
48919
|
init_ReplyTree();
|
|
48893
|
-
|
|
48920
|
+
init_RichTextEditor();
|
|
48894
48921
|
init_RuntimeDebugger2();
|
|
48895
48922
|
init_ScaledDiagram();
|
|
48896
48923
|
init_ScoreDisplay();
|
|
@@ -49053,6 +49080,8 @@ var init_component_registry_generated = __esm({
|
|
|
49053
49080
|
"DocSearch": DocSearch,
|
|
49054
49081
|
"DocSidebar": DocSidebar,
|
|
49055
49082
|
"DocTOC": DocTOC,
|
|
49083
|
+
"DocumentDetails": DocumentDetails,
|
|
49084
|
+
"DocumentPanel": DocumentPanel,
|
|
49056
49085
|
"DocumentViewer": DocumentViewer,
|
|
49057
49086
|
"DrawFxLayer": DrawFxLayer,
|
|
49058
49087
|
"DrawGroup": DrawGroup,
|
|
@@ -49164,7 +49193,7 @@ var init_component_registry_generated = __esm({
|
|
|
49164
49193
|
"RelationSelect": RelationSelect,
|
|
49165
49194
|
"RepeatableFormSection": RepeatableFormSection,
|
|
49166
49195
|
"ReplyTree": ReplyTree,
|
|
49167
|
-
"
|
|
49196
|
+
"RichTextEditor": RichTextEditor,
|
|
49168
49197
|
"RuntimeDebugger": RuntimeDebugger,
|
|
49169
49198
|
"ScaledDiagram": ScaledDiagram,
|
|
49170
49199
|
"ScoreDisplay": ScoreDisplay,
|
|
@@ -49318,10 +49347,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
49318
49347
|
}
|
|
49319
49348
|
if (field && typeof field === "object" && !Array.isArray(field) && !React87__default.isValidElement(field) && !(field instanceof Date)) {
|
|
49320
49349
|
const obj = field;
|
|
49321
|
-
const
|
|
49322
|
-
if (!
|
|
49350
|
+
const fieldName2 = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
|
|
49351
|
+
if (!fieldName2) return field;
|
|
49323
49352
|
if (obj.type || obj.inputType) return field;
|
|
49324
|
-
const entityField = fieldMap.get(
|
|
49353
|
+
const entityField = fieldMap.get(fieldName2);
|
|
49325
49354
|
if (!entityField) return field;
|
|
49326
49355
|
const enriched = { ...obj, type: entityField.type };
|
|
49327
49356
|
if (entityField.required && !("required" in obj)) {
|
|
@@ -49371,9 +49400,9 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
49371
49400
|
}
|
|
49372
49401
|
if (field && typeof field === "object" && !Array.isArray(field) && !React87__default.isValidElement(field) && !(field instanceof Date)) {
|
|
49373
49402
|
const obj = field;
|
|
49374
|
-
const
|
|
49375
|
-
if (!
|
|
49376
|
-
const meta = metaFor(
|
|
49403
|
+
const fieldName2 = typeof obj.key === "string" ? obj.key : typeof obj.name === "string" ? obj.name : void 0;
|
|
49404
|
+
if (!fieldName2 || obj.type) return field;
|
|
49405
|
+
const meta = metaFor(fieldName2);
|
|
49377
49406
|
return meta ? { ...obj, ...meta } : field;
|
|
49378
49407
|
}
|
|
49379
49408
|
return field;
|
|
@@ -50212,9 +50241,9 @@ function UISlotRenderer({
|
|
|
50212
50241
|
"ui-slot-renderer relative min-h-full",
|
|
50213
50242
|
className
|
|
50214
50243
|
), children: [
|
|
50215
|
-
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full", children: [
|
|
50216
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 shrink-0" }),
|
|
50217
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-h-[200px]" })
|
|
50244
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full flex-col lg:flex-row", children: [
|
|
50245
|
+
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 lg:shrink-0" }),
|
|
50246
|
+
/* @__PURE__ */ jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-w-0 min-h-[200px]" })
|
|
50218
50247
|
] }),
|
|
50219
50248
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "modal", portal: true }),
|
|
50220
50249
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "drawer", portal: true }),
|