@almadar/ui 5.159.0 → 5.161.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +958 -912
- package/dist/avl/index.js +947 -901
- package/dist/components/index.cjs +978 -955
- package/dist/components/index.d.cts +156 -31
- package/dist/components/index.d.ts +156 -31
- package/dist/components/index.js +964 -944
- package/dist/hooks/index.cjs +25 -49
- package/dist/hooks/index.js +25 -49
- package/dist/locales/index.cjs +75 -147
- package/dist/locales/index.js +75 -147
- package/dist/providers/index.cjs +934 -892
- package/dist/providers/index.js +934 -892
- package/dist/runtime/index.cjs +953 -907
- package/dist/runtime/index.js +943 -897
- package/locales/ar.json +25 -49
- package/locales/en.json +25 -49
- package/locales/sl.json +25 -49
- package/package.json +5 -5
package/dist/avl/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { useTranslate } from '@almadar/ui/hooks';
|
|
|
9
9
|
import { InMemoryPersistence, StateMachineManager, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, normalizeCallSiteConfigToValues, interpolateValue } from '@almadar/runtime';
|
|
10
10
|
import { FieldTypeSchema, isInlineTrait, isPageReference, buildResolvedTraitConfigs, schemaToIR, getPage, mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, walkSExpr, isRenderBindingMarker, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER, isFileValue, ANIMATION_NAMES } from '@almadar/core';
|
|
11
11
|
import * as LucideIcons2 from 'lucide-react';
|
|
12
|
-
import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, 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,
|
|
12
|
+
import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, 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';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import { UISlotProvider, useUISlots, useTheme } from '@almadar/ui/context';
|
|
15
15
|
import { evaluateGuard, evaluateListenPayloadExpr, evaluate, createMinimalContext, executeEffects } from '@almadar/evaluator';
|
|
@@ -28536,8 +28536,9 @@ function DataGrid({
|
|
|
28536
28536
|
const titleField = fieldDefs.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fieldDefs[0];
|
|
28537
28537
|
const badgeFields = fieldDefs.filter((f3) => f3.variant === "badge" && f3 !== titleField);
|
|
28538
28538
|
const bodyFields = fieldDefs.filter((f3) => f3 !== titleField && !badgeFields.includes(f3));
|
|
28539
|
-
const
|
|
28540
|
-
const
|
|
28539
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
28540
|
+
const inlineCardActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
28541
|
+
const menuCardActions = actionDefs.filter((a) => !inlineCardActions.includes(a));
|
|
28541
28542
|
const fireAction = (action, itemData) => {
|
|
28542
28543
|
if (action.navigatesTo) {
|
|
28543
28544
|
const url = action.navigatesTo.replace(
|
|
@@ -28557,6 +28558,9 @@ function DataGrid({
|
|
|
28557
28558
|
e.stopPropagation();
|
|
28558
28559
|
fireAction(action, itemData);
|
|
28559
28560
|
};
|
|
28561
|
+
const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
|
|
28562
|
+
const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
|
|
28563
|
+
const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
|
|
28560
28564
|
const hasRenderProp = typeof children === "function";
|
|
28561
28565
|
useEffect(() => {
|
|
28562
28566
|
if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
|
|
@@ -28628,55 +28632,40 @@ function DataGrid({
|
|
|
28628
28632
|
{
|
|
28629
28633
|
"data-entity-row": true,
|
|
28630
28634
|
"data-entity-id": id,
|
|
28631
|
-
|
|
28635
|
+
onClick: handleCardClick?.(itemData),
|
|
28636
|
+
className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
|
|
28632
28637
|
children: [
|
|
28633
28638
|
children(itemData, index),
|
|
28634
|
-
actionDefs.length > 0 && /* @__PURE__ */
|
|
28635
|
-
/* @__PURE__ */ jsxs(
|
|
28636
|
-
|
|
28637
|
-
|
|
28638
|
-
|
|
28639
|
-
|
|
28640
|
-
|
|
28641
|
-
|
|
28642
|
-
|
|
28643
|
-
|
|
28644
|
-
|
|
28645
|
-
|
|
28646
|
-
|
|
28647
|
-
|
|
28648
|
-
|
|
28649
|
-
|
|
28650
|
-
|
|
28651
|
-
)),
|
|
28652
|
-
maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsx(
|
|
28653
|
-
Menu,
|
|
28654
|
-
{
|
|
28655
|
-
position: "bottom-end",
|
|
28656
|
-
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" }) }),
|
|
28657
|
-
items: actionDefs.slice(maxInlineActions).map((action) => ({
|
|
28658
|
-
label: action.label,
|
|
28659
|
-
icon: action.icon,
|
|
28660
|
-
event: action.event,
|
|
28661
|
-
onClick: () => fireAction(action, itemData)
|
|
28662
|
-
}))
|
|
28663
|
-
}
|
|
28664
|
-
)
|
|
28665
|
-
] }),
|
|
28666
|
-
/* @__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(
|
|
28639
|
+
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: [
|
|
28640
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
28641
|
+
Button,
|
|
28642
|
+
{
|
|
28643
|
+
variant: "primary",
|
|
28644
|
+
size: "sm",
|
|
28645
|
+
onClick: handleActionClick(action, itemData),
|
|
28646
|
+
"data-testid": `action-${action.event}`,
|
|
28647
|
+
"data-row-id": String(itemData.id),
|
|
28648
|
+
children: [
|
|
28649
|
+
action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
|
|
28650
|
+
action.label
|
|
28651
|
+
]
|
|
28652
|
+
},
|
|
28653
|
+
idx
|
|
28654
|
+
)),
|
|
28655
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsx(
|
|
28667
28656
|
Menu,
|
|
28668
28657
|
{
|
|
28669
28658
|
position: "bottom-end",
|
|
28670
28659
|
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" }) }),
|
|
28671
|
-
items:
|
|
28660
|
+
items: menuCardActions.map((action) => ({
|
|
28672
28661
|
label: action.label,
|
|
28673
28662
|
icon: action.icon,
|
|
28674
|
-
|
|
28663
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
28675
28664
|
onClick: () => fireAction(action, itemData)
|
|
28676
28665
|
}))
|
|
28677
28666
|
}
|
|
28678
|
-
)
|
|
28679
|
-
] })
|
|
28667
|
+
)
|
|
28668
|
+
] }) })
|
|
28680
28669
|
]
|
|
28681
28670
|
},
|
|
28682
28671
|
id
|
|
@@ -28690,12 +28679,14 @@ function DataGrid({
|
|
|
28690
28679
|
{
|
|
28691
28680
|
"data-entity-row": true,
|
|
28692
28681
|
"data-entity-id": id,
|
|
28682
|
+
onClick: handleCardClick?.(itemData),
|
|
28693
28683
|
className: cn(
|
|
28694
28684
|
"bg-card rounded-lg",
|
|
28695
28685
|
"border border-border",
|
|
28696
28686
|
"shadow-elevation-card hover:shadow-elevation-dialog",
|
|
28697
28687
|
"hover:border-primary transition-all",
|
|
28698
28688
|
"flex flex-col",
|
|
28689
|
+
handleCardClick && "cursor-pointer",
|
|
28699
28690
|
isSelected && "ring-2 ring-primary border-primary"
|
|
28700
28691
|
),
|
|
28701
28692
|
children: [
|
|
@@ -28745,53 +28736,35 @@ function DataGrid({
|
|
|
28745
28736
|
] }, field.name);
|
|
28746
28737
|
}) })
|
|
28747
28738
|
] }),
|
|
28748
|
-
|
|
28749
|
-
|
|
28739
|
+
actionDefs.length > 0 && /* @__PURE__ */ jsxs(HStack, { gap: "xs", onClick: stopCardClick, className: "flex-shrink-0", children: [
|
|
28740
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
28750
28741
|
Button,
|
|
28751
28742
|
{
|
|
28752
|
-
variant:
|
|
28743
|
+
variant: "primary",
|
|
28753
28744
|
size: "sm",
|
|
28754
28745
|
onClick: handleActionClick(action, itemData),
|
|
28755
28746
|
"data-testid": `action-${action.event}`,
|
|
28756
28747
|
"data-row-id": String(itemData.id),
|
|
28757
28748
|
"aria-label": action.label,
|
|
28758
28749
|
title: action.label,
|
|
28759
|
-
className: cn(
|
|
28760
|
-
action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
|
|
28761
|
-
action.icon && "px-2"
|
|
28762
|
-
),
|
|
28750
|
+
className: cn(action.icon && "px-2"),
|
|
28763
28751
|
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
28764
28752
|
},
|
|
28765
28753
|
idx
|
|
28766
28754
|
)),
|
|
28767
|
-
|
|
28755
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsx(
|
|
28768
28756
|
Menu,
|
|
28769
28757
|
{
|
|
28770
28758
|
position: "bottom-end",
|
|
28771
28759
|
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" }) }),
|
|
28772
|
-
items:
|
|
28760
|
+
items: menuCardActions.map((action) => ({
|
|
28773
28761
|
label: action.label,
|
|
28774
28762
|
icon: action.icon,
|
|
28775
|
-
|
|
28763
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
28776
28764
|
onClick: () => fireAction(action, itemData)
|
|
28777
28765
|
}))
|
|
28778
28766
|
}
|
|
28779
|
-
)
|
|
28780
|
-
dangerActions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
28781
|
-
Button,
|
|
28782
|
-
{
|
|
28783
|
-
variant: "ghost",
|
|
28784
|
-
size: "sm",
|
|
28785
|
-
onClick: handleActionClick(action, itemData),
|
|
28786
|
-
"data-testid": `action-${action.event}`,
|
|
28787
|
-
"data-row-id": String(itemData.id),
|
|
28788
|
-
"aria-label": action.label,
|
|
28789
|
-
title: action.label,
|
|
28790
|
-
className: "text-error hover:text-error hover:bg-error/10 px-2",
|
|
28791
|
-
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
28792
|
-
},
|
|
28793
|
-
`danger-${idx}`
|
|
28794
|
-
))
|
|
28767
|
+
)
|
|
28795
28768
|
] })
|
|
28796
28769
|
] }) }),
|
|
28797
28770
|
bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
@@ -28812,8 +28785,8 @@ function DataGrid({
|
|
|
28812
28785
|
}
|
|
28813
28786
|
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
28814
28787
|
field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
28815
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
|
|
28816
|
-
/* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue(value, field.format) })
|
|
28788
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "sr-only", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
|
|
28789
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: formatValue(value, field.format) })
|
|
28817
28790
|
] }, field.name);
|
|
28818
28791
|
}) })
|
|
28819
28792
|
] }) })
|
|
@@ -29033,54 +29006,59 @@ function DataList({
|
|
|
29033
29006
|
if (!itemActions || itemActions.length === 0) return null;
|
|
29034
29007
|
const inline = maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions;
|
|
29035
29008
|
const overflow = maxInlineActions != null ? itemActions.slice(maxInlineActions) : [];
|
|
29036
|
-
return
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
|
|
29045
|
-
|
|
29046
|
-
action
|
|
29047
|
-
|
|
29048
|
-
|
|
29049
|
-
|
|
29050
|
-
|
|
29051
|
-
|
|
29052
|
-
|
|
29053
|
-
|
|
29054
|
-
|
|
29055
|
-
|
|
29056
|
-
|
|
29057
|
-
|
|
29058
|
-
|
|
29059
|
-
|
|
29060
|
-
|
|
29061
|
-
|
|
29062
|
-
|
|
29063
|
-
|
|
29064
|
-
|
|
29065
|
-
|
|
29066
|
-
|
|
29067
|
-
|
|
29068
|
-
|
|
29069
|
-
|
|
29070
|
-
|
|
29071
|
-
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29009
|
+
return (
|
|
29010
|
+
// stopPropagation at the cluster: the "⋯" trigger opens the overflow
|
|
29011
|
+
// menu without also firing the row's default click (inline buttons
|
|
29012
|
+
// already stop it in handleActionClick; the Menu panel is portaled).
|
|
29013
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", onClick: rowClickEvent ? (e) => e.stopPropagation() : void 0, className: "flex-shrink-0", children: [
|
|
29014
|
+
inline.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
29015
|
+
Button,
|
|
29016
|
+
{
|
|
29017
|
+
variant: action.variant ?? "ghost",
|
|
29018
|
+
size: "sm",
|
|
29019
|
+
onClick: handleActionClick(action, itemData),
|
|
29020
|
+
"data-testid": `action-${action.event}`,
|
|
29021
|
+
"data-row-id": String(itemData.id),
|
|
29022
|
+
className: cn(
|
|
29023
|
+
action.variant === "danger" && "text-error hover:bg-error/10",
|
|
29024
|
+
// Must sit on the Button itself: the variant's own text colour
|
|
29025
|
+
// beats an inherited one from the row wrapper.
|
|
29026
|
+
onPrimary && "!text-primary-foreground hover:bg-primary-foreground/15"
|
|
29027
|
+
),
|
|
29028
|
+
children: [
|
|
29029
|
+
action.icon && renderIconInput2(action.icon, { size: "xs", className: "mr-1" }),
|
|
29030
|
+
action.label
|
|
29031
|
+
]
|
|
29032
|
+
},
|
|
29033
|
+
idx
|
|
29034
|
+
)),
|
|
29035
|
+
overflow.length > 0 && /* @__PURE__ */ jsx(
|
|
29036
|
+
Menu,
|
|
29037
|
+
{
|
|
29038
|
+
position: "bottom-end",
|
|
29039
|
+
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" }) }),
|
|
29040
|
+
items: overflow.map((action) => ({
|
|
29041
|
+
label: action.label,
|
|
29042
|
+
icon: action.icon,
|
|
29043
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
29044
|
+
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
29045
|
+
id: itemData.id,
|
|
29046
|
+
row: itemData
|
|
29047
|
+
})
|
|
29048
|
+
}))
|
|
29049
|
+
}
|
|
29050
|
+
)
|
|
29051
|
+
] })
|
|
29052
|
+
);
|
|
29076
29053
|
};
|
|
29054
|
+
const rowClickEvent = itemClickEvent || itemActions?.find((a) => a.variant !== "danger")?.event;
|
|
29077
29055
|
const handleRowClick = (itemData) => () => {
|
|
29078
|
-
if (!
|
|
29056
|
+
if (!rowClickEvent) return;
|
|
29079
29057
|
const payload = {
|
|
29080
29058
|
id: itemData.id,
|
|
29081
29059
|
row: itemData
|
|
29082
29060
|
};
|
|
29083
|
-
eventBus.emit(`UI:${
|
|
29061
|
+
eventBus.emit(`UI:${rowClickEvent}`, payload);
|
|
29084
29062
|
};
|
|
29085
29063
|
if (isLoading) {
|
|
29086
29064
|
return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
|
|
@@ -29128,10 +29106,10 @@ function DataList({
|
|
|
29128
29106
|
{
|
|
29129
29107
|
"data-entity-row": true,
|
|
29130
29108
|
"data-entity-id": id,
|
|
29131
|
-
onClick:
|
|
29109
|
+
onClick: rowClickEvent ? handleRowClick(itemData) : void 0,
|
|
29132
29110
|
className: cn(
|
|
29133
29111
|
"flex px-4 group/rowactions",
|
|
29134
|
-
|
|
29112
|
+
rowClickEvent && "cursor-pointer",
|
|
29135
29113
|
isSent ? "justify-end" : "justify-start"
|
|
29136
29114
|
),
|
|
29137
29115
|
children: /* @__PURE__ */ jsxs(
|
|
@@ -29207,7 +29185,7 @@ function DataList({
|
|
|
29207
29185
|
const id2 = itemData.id || String(index);
|
|
29208
29186
|
const actions = renderItemActions(itemData);
|
|
29209
29187
|
return wrapDnd(
|
|
29210
|
-
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick:
|
|
29188
|
+
/* @__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: [
|
|
29211
29189
|
children(itemData, index),
|
|
29212
29190
|
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: [
|
|
29213
29191
|
/* @__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 }),
|
|
@@ -29219,7 +29197,6 @@ function DataList({
|
|
|
29219
29197
|
items: (itemActions ?? []).map((action) => ({
|
|
29220
29198
|
label: action.label,
|
|
29221
29199
|
icon: action.icon,
|
|
29222
|
-
event: action.event,
|
|
29223
29200
|
variant: action.variant === "danger" ? "danger" : "default",
|
|
29224
29201
|
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
29225
29202
|
id: itemData.id,
|
|
@@ -29236,12 +29213,16 @@ function DataList({
|
|
|
29236
29213
|
const id = itemData.id || String(index);
|
|
29237
29214
|
const titleValue = getNestedValue(itemData, titleField?.name ?? "");
|
|
29238
29215
|
return wrapDnd(
|
|
29239
|
-
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick:
|
|
29216
|
+
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn(rowClickEvent && "cursor-pointer"), children: [
|
|
29240
29217
|
/* @__PURE__ */ jsxs(
|
|
29241
29218
|
Box,
|
|
29242
29219
|
{
|
|
29243
29220
|
className: cn(
|
|
29244
|
-
|
|
29221
|
+
// items-start, not items-center: a multi-line row (title + meta +
|
|
29222
|
+
// progress) centred its action cluster in the vertical middle, so
|
|
29223
|
+
// the buttons floated between the meta fields instead of anchoring
|
|
29224
|
+
// to the title they act on (U-DATALIST-ACTIONS-FLOAT-MID-ROW).
|
|
29225
|
+
"group flex items-start gap-4 transition-all duration-fast",
|
|
29245
29226
|
isCompact ? "px-4 py-2" : "px-6 py-4",
|
|
29246
29227
|
"hover:bg-muted/80",
|
|
29247
29228
|
!isCard && !isCompact && "rounded-lg border border-transparent hover:border-border"
|
|
@@ -29272,11 +29253,19 @@ function DataList({
|
|
|
29272
29253
|
if (value === void 0 || value === null || value === "") return null;
|
|
29273
29254
|
return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
29274
29255
|
field.icon && renderIconInput2(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
29275
|
-
/* @__PURE__ */ jsxs(
|
|
29276
|
-
|
|
29277
|
-
|
|
29278
|
-
|
|
29279
|
-
|
|
29256
|
+
/* @__PURE__ */ jsxs(
|
|
29257
|
+
Typography,
|
|
29258
|
+
{
|
|
29259
|
+
variant: "caption",
|
|
29260
|
+
color: "secondary",
|
|
29261
|
+
className: cn(field.format !== "boolean" && "sr-only"),
|
|
29262
|
+
children: [
|
|
29263
|
+
field.label ?? fieldLabel3(field.name),
|
|
29264
|
+
":"
|
|
29265
|
+
]
|
|
29266
|
+
}
|
|
29267
|
+
),
|
|
29268
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: formatValue2(value, field.format, { yes: t("common.yes"), no: t("common.no") }) })
|
|
29280
29269
|
] }, field.name);
|
|
29281
29270
|
}) }),
|
|
29282
29271
|
progressFields.map((field) => {
|
|
@@ -29295,7 +29284,7 @@ function DataList({
|
|
|
29295
29284
|
]
|
|
29296
29285
|
}
|
|
29297
29286
|
),
|
|
29298
|
-
isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "
|
|
29287
|
+
(isCard || isCompact) && !isLast && /* @__PURE__ */ jsx(Box, { className: cn("border-b border-border/40", isCompact ? "mx-4" : "mx-6") })
|
|
29299
29288
|
] }, id)
|
|
29300
29289
|
);
|
|
29301
29290
|
};
|
|
@@ -29305,7 +29294,13 @@ function DataList({
|
|
|
29305
29294
|
{
|
|
29306
29295
|
className: cn(
|
|
29307
29296
|
isCard && "bg-card rounded-xl border border-border shadow-elevation-dialog overflow-hidden",
|
|
29308
|
-
|
|
29297
|
+
// `gap-*` is inert on a block container, and Box only emits a display
|
|
29298
|
+
// class when its `display` prop is set — so every non-card list had
|
|
29299
|
+
// been asking for a gap that CSS silently dropped. flex-col makes it
|
|
29300
|
+
// real. `compact` keeps gap-0 on purpose: it separates with the row
|
|
29301
|
+
// divider above instead, never both (Almadar_UI_Beauty.md 6).
|
|
29302
|
+
!isCard && "flex flex-col",
|
|
29303
|
+
!isCard && !isCompact && gapClass,
|
|
29309
29304
|
listLookStyles[look],
|
|
29310
29305
|
className
|
|
29311
29306
|
),
|
|
@@ -34494,7 +34489,7 @@ var init_MapView = __esm({
|
|
|
34494
34489
|
shadowSize: [41, 41]
|
|
34495
34490
|
});
|
|
34496
34491
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
34497
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback96, useState:
|
|
34492
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback96, useState: useState102 } = React94__default;
|
|
34498
34493
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
34499
34494
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
34500
34495
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -34539,7 +34534,7 @@ var init_MapView = __esm({
|
|
|
34539
34534
|
showAttribution = true
|
|
34540
34535
|
}) {
|
|
34541
34536
|
const eventBus = useEventBus2();
|
|
34542
|
-
const [clickedPosition, setClickedPosition] =
|
|
34537
|
+
const [clickedPosition, setClickedPosition] = useState102(null);
|
|
34543
34538
|
const handleMapClick = useCallback96((lat, lng) => {
|
|
34544
34539
|
if (showClickedPin) {
|
|
34545
34540
|
setClickedPosition({ lat, lng });
|
|
@@ -38901,741 +38896,775 @@ var init_PositionedCanvas = __esm({
|
|
|
38901
38896
|
PositionedCanvas.displayName = "PositionedCanvas";
|
|
38902
38897
|
}
|
|
38903
38898
|
});
|
|
38904
|
-
function
|
|
38905
|
-
|
|
38906
|
-
|
|
38907
|
-
|
|
38908
|
-
|
|
38909
|
-
|
|
38910
|
-
if (!Array.isArray(raw) || raw.length === 0) return [createBlock("paragraph")];
|
|
38911
|
-
return raw.map((row) => {
|
|
38912
|
-
const entity = row;
|
|
38913
|
-
const rawType = entity.type;
|
|
38914
|
-
const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
|
|
38915
|
-
const id = typeof entity.id === "string" && entity.id ? entity.id : nextBlockId(type);
|
|
38916
|
-
return { ...entity, id, type };
|
|
38917
|
-
});
|
|
38918
|
-
}
|
|
38919
|
-
function createBlock(type) {
|
|
38920
|
-
switch (type) {
|
|
38921
|
-
case "bullet-list":
|
|
38922
|
-
case "numbered-list":
|
|
38923
|
-
return {
|
|
38924
|
-
id: nextBlockId(type),
|
|
38925
|
-
type,
|
|
38926
|
-
children: [
|
|
38927
|
-
{ id: nextBlockId("li"), type: "paragraph", content: "" }
|
|
38928
|
-
]
|
|
38929
|
-
};
|
|
38930
|
-
case "image":
|
|
38931
|
-
return {
|
|
38932
|
-
id: nextBlockId(type),
|
|
38933
|
-
type,
|
|
38934
|
-
content: "",
|
|
38935
|
-
metadata: { url: "", caption: "" }
|
|
38936
|
-
};
|
|
38937
|
-
case "code":
|
|
38938
|
-
return {
|
|
38939
|
-
id: nextBlockId(type),
|
|
38940
|
-
type,
|
|
38941
|
-
content: "",
|
|
38942
|
-
metadata: { language: "plaintext" }
|
|
38943
|
-
};
|
|
38944
|
-
case "divider":
|
|
38945
|
-
return { id: nextBlockId(type), type };
|
|
38946
|
-
default:
|
|
38947
|
-
return { id: nextBlockId(type), type, content: "" };
|
|
38899
|
+
function safeUrl(raw, kinds) {
|
|
38900
|
+
const url = raw.trim();
|
|
38901
|
+
if (url.startsWith("#") || url.startsWith("/")) return url;
|
|
38902
|
+
const lower = url.toLowerCase();
|
|
38903
|
+
for (const kind of kinds) {
|
|
38904
|
+
if (lower.startsWith(kind)) return url;
|
|
38948
38905
|
}
|
|
38906
|
+
return null;
|
|
38949
38907
|
}
|
|
38950
|
-
function
|
|
38951
|
-
|
|
38952
|
-
|
|
38953
|
-
|
|
38954
|
-
|
|
38955
|
-
|
|
38956
|
-
|
|
38957
|
-
return {
|
|
38958
|
-
...block,
|
|
38959
|
-
id: nextBlockId(block.type),
|
|
38960
|
-
children: block.children?.map((child) => ({
|
|
38961
|
-
...child,
|
|
38962
|
-
id: nextBlockId("li")
|
|
38963
|
-
})),
|
|
38964
|
-
metadata: block.metadata ? { ...block.metadata } : void 0
|
|
38965
|
-
};
|
|
38966
|
-
}
|
|
38967
|
-
function insertAfter(blocks, targetId, inserted) {
|
|
38968
|
-
const idx = blocks.findIndex((b) => b.id === targetId);
|
|
38969
|
-
if (idx === -1) return [...blocks, inserted];
|
|
38970
|
-
const next = blocks.slice();
|
|
38971
|
-
next.splice(idx + 1, 0, inserted);
|
|
38972
|
-
return next;
|
|
38973
|
-
}
|
|
38974
|
-
function changeBlockType(block, type) {
|
|
38975
|
-
if (block.type === type) return block;
|
|
38976
|
-
if (type === "bullet-list" || type === "numbered-list") {
|
|
38977
|
-
if (block.children && block.children.length > 0) {
|
|
38978
|
-
return { ...block, type };
|
|
38908
|
+
function sanitizeNode(el) {
|
|
38909
|
+
const children = Array.from(el.children);
|
|
38910
|
+
for (const child of children) {
|
|
38911
|
+
const tag = child.tagName.toLowerCase();
|
|
38912
|
+
if (DROP_TAGS.has(tag)) {
|
|
38913
|
+
child.remove();
|
|
38914
|
+
continue;
|
|
38979
38915
|
}
|
|
38980
|
-
const
|
|
38981
|
-
|
|
38982
|
-
|
|
38983
|
-
|
|
38984
|
-
|
|
38985
|
-
|
|
38986
|
-
|
|
38987
|
-
|
|
38988
|
-
|
|
38989
|
-
|
|
38990
|
-
|
|
38916
|
+
const allowed = ALLOWED_ATTRS[tag];
|
|
38917
|
+
if (!allowed) {
|
|
38918
|
+
sanitizeNode(child);
|
|
38919
|
+
child.replaceWith(...Array.from(child.childNodes));
|
|
38920
|
+
continue;
|
|
38921
|
+
}
|
|
38922
|
+
for (const attr of Array.from(child.attributes)) {
|
|
38923
|
+
const name = attr.name.toLowerCase();
|
|
38924
|
+
if (!allowed.includes(name)) {
|
|
38925
|
+
child.removeAttribute(attr.name);
|
|
38926
|
+
continue;
|
|
38927
|
+
}
|
|
38928
|
+
if (name === "href") {
|
|
38929
|
+
const url = safeUrl(attr.value, ["http://", "https://", "mailto:"]);
|
|
38930
|
+
if (url === null) child.removeAttribute(attr.name);
|
|
38931
|
+
else child.setAttribute("href", url);
|
|
38932
|
+
}
|
|
38933
|
+
if (name === "src") {
|
|
38934
|
+
const url = safeUrl(attr.value, ["http://", "https://", "data:image/"]);
|
|
38935
|
+
if (url === null) child.remove();
|
|
38936
|
+
else child.setAttribute("src", url);
|
|
38937
|
+
}
|
|
38938
|
+
}
|
|
38939
|
+
sanitizeNode(child);
|
|
38991
38940
|
}
|
|
38992
|
-
|
|
38993
|
-
|
|
38994
|
-
|
|
38995
|
-
|
|
38996
|
-
|
|
38997
|
-
|
|
38998
|
-
|
|
38941
|
+
}
|
|
38942
|
+
function sanitizeRichHtml(html) {
|
|
38943
|
+
if (!html || typeof html !== "string") return "";
|
|
38944
|
+
if (typeof window === "undefined" || typeof DOMParser === "undefined") return "";
|
|
38945
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
38946
|
+
sanitizeNode(doc.body);
|
|
38947
|
+
if (!doc.body.querySelector("img, hr") && (doc.body.textContent ?? "").trim().length === 0) {
|
|
38948
|
+
return "";
|
|
38999
38949
|
}
|
|
39000
|
-
|
|
39001
|
-
|
|
39002
|
-
|
|
39003
|
-
|
|
39004
|
-
|
|
39005
|
-
|
|
39006
|
-
|
|
38950
|
+
return doc.body.innerHTML.replace(//g, "");
|
|
38951
|
+
}
|
|
38952
|
+
function htmlIsEmpty(el) {
|
|
38953
|
+
if (el.querySelector("img, hr")) return false;
|
|
38954
|
+
return (el.textContent ?? "").trim().length === 0;
|
|
38955
|
+
}
|
|
38956
|
+
function closestBlock(node, root) {
|
|
38957
|
+
let cur = node;
|
|
38958
|
+
while (cur && cur !== root) {
|
|
38959
|
+
if (cur instanceof Element && BLOCK_TAGS.has(cur.tagName)) return cur;
|
|
38960
|
+
cur = cur.parentNode;
|
|
39007
38961
|
}
|
|
39008
|
-
|
|
39009
|
-
return { id: block.id, type, content: seed };
|
|
38962
|
+
return null;
|
|
39010
38963
|
}
|
|
39011
|
-
function
|
|
39012
|
-
|
|
39013
|
-
|
|
39014
|
-
|
|
39015
|
-
|
|
39016
|
-
|
|
39017
|
-
|
|
39018
|
-
|
|
39019
|
-
|
|
38964
|
+
function RichTextStyles() {
|
|
38965
|
+
return /* @__PURE__ */ jsx("style", { children: RICH_TEXT_CSS });
|
|
38966
|
+
}
|
|
38967
|
+
function readToolbarState(root) {
|
|
38968
|
+
const sel = window.getSelection();
|
|
38969
|
+
if (!sel || sel.rangeCount === 0) return IDLE_TOOLBAR;
|
|
38970
|
+
const anchor = sel.anchorNode;
|
|
38971
|
+
if (!anchor || !root.contains(anchor)) return IDLE_TOOLBAR;
|
|
38972
|
+
let block = null;
|
|
38973
|
+
let link = false;
|
|
38974
|
+
let node = anchor;
|
|
38975
|
+
while (node && node !== root) {
|
|
38976
|
+
if (node instanceof Element) {
|
|
38977
|
+
const tag = node.tagName.toLowerCase();
|
|
38978
|
+
if (!block && (tag === "h1" || tag === "h2" || tag === "h3" || tag === "blockquote" || tag === "pre")) {
|
|
38979
|
+
block = tag;
|
|
39020
38980
|
}
|
|
38981
|
+
if (tag === "a") link = true;
|
|
39021
38982
|
}
|
|
39022
|
-
|
|
39023
|
-
|
|
39024
|
-
|
|
39025
|
-
|
|
39026
|
-
|
|
39027
|
-
|
|
39028
|
-
|
|
39029
|
-
|
|
39030
|
-
|
|
39031
|
-
|
|
39032
|
-
|
|
39033
|
-
|
|
39034
|
-
"inline-flex items-center justify-center",
|
|
39035
|
-
"h-6 w-6 rounded-sm p-0 gap-0",
|
|
39036
|
-
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
39037
|
-
"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",
|
|
39038
|
-
"transition-opacity"
|
|
39039
|
-
),
|
|
39040
|
-
onClick: () => setOpen((v) => !v),
|
|
39041
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", className: "w-3.5 h-3.5" })
|
|
39042
|
-
}
|
|
39043
|
-
),
|
|
39044
|
-
open && /* @__PURE__ */ jsxs(
|
|
39045
|
-
Box,
|
|
39046
|
-
{
|
|
39047
|
-
role: "menu",
|
|
39048
|
-
className: cn(
|
|
39049
|
-
"absolute right-0 z-10 mt-1 w-44",
|
|
39050
|
-
"rounded-container border border-border bg-popover shadow-elevation-popover",
|
|
39051
|
-
"py-1 text-sm"
|
|
39052
|
-
),
|
|
39053
|
-
children: [
|
|
39054
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t(BLOCK_TYPE_LABEL_KEY[block.type]) }),
|
|
39055
|
-
/* @__PURE__ */ jsxs(
|
|
39056
|
-
Button,
|
|
39057
|
-
{
|
|
39058
|
-
type: "button",
|
|
39059
|
-
variant: "ghost",
|
|
39060
|
-
role: "menuitem",
|
|
39061
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
39062
|
-
onClick: () => {
|
|
39063
|
-
onDuplicate();
|
|
39064
|
-
setOpen(false);
|
|
39065
|
-
},
|
|
39066
|
-
children: [
|
|
39067
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3.5 h-3.5" }),
|
|
39068
|
-
" ",
|
|
39069
|
-
t("richBlockEditor.duplicate")
|
|
39070
|
-
]
|
|
39071
|
-
}
|
|
39072
|
-
),
|
|
39073
|
-
/* @__PURE__ */ jsxs(
|
|
39074
|
-
Button,
|
|
39075
|
-
{
|
|
39076
|
-
type: "button",
|
|
39077
|
-
variant: "ghost",
|
|
39078
|
-
role: "menuitem",
|
|
39079
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-destructive hover:bg-muted justify-start rounded-none",
|
|
39080
|
-
onClick: () => {
|
|
39081
|
-
onDelete();
|
|
39082
|
-
setOpen(false);
|
|
39083
|
-
},
|
|
39084
|
-
children: [
|
|
39085
|
-
/* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3.5 h-3.5" }),
|
|
39086
|
-
" ",
|
|
39087
|
-
t("common.delete")
|
|
39088
|
-
]
|
|
39089
|
-
}
|
|
39090
|
-
),
|
|
39091
|
-
CHANGEABLE_TYPES.includes(block.type) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39092
|
-
/* @__PURE__ */ jsx(Box, { className: "my-1 border-t border-border" }),
|
|
39093
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t("richBlockEditor.turnInto") }),
|
|
39094
|
-
CHANGEABLE_TYPES.filter((bt) => bt !== block.type).map((bt) => /* @__PURE__ */ jsx(
|
|
39095
|
-
Button,
|
|
39096
|
-
{
|
|
39097
|
-
type: "button",
|
|
39098
|
-
variant: "ghost",
|
|
39099
|
-
role: "menuitem",
|
|
39100
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
39101
|
-
onClick: () => {
|
|
39102
|
-
onChangeType(bt);
|
|
39103
|
-
setOpen(false);
|
|
39104
|
-
},
|
|
39105
|
-
children: t(BLOCK_TYPE_LABEL_KEY[bt])
|
|
39106
|
-
},
|
|
39107
|
-
bt
|
|
39108
|
-
))
|
|
39109
|
-
] })
|
|
39110
|
-
]
|
|
39111
|
-
}
|
|
39112
|
-
)
|
|
39113
|
-
] });
|
|
38983
|
+
node = node.parentNode;
|
|
38984
|
+
}
|
|
38985
|
+
return {
|
|
38986
|
+
bold: document.queryCommandState("bold"),
|
|
38987
|
+
italic: document.queryCommandState("italic"),
|
|
38988
|
+
underline: document.queryCommandState("underline"),
|
|
38989
|
+
strikeThrough: document.queryCommandState("strikeThrough"),
|
|
38990
|
+
block,
|
|
38991
|
+
bullets: document.queryCommandState("insertUnorderedList"),
|
|
38992
|
+
numbers: document.queryCommandState("insertOrderedList"),
|
|
38993
|
+
link
|
|
38994
|
+
};
|
|
39114
38995
|
}
|
|
39115
|
-
function
|
|
39116
|
-
tag,
|
|
39117
|
-
value,
|
|
39118
|
-
readOnly,
|
|
39119
|
-
placeholder,
|
|
39120
|
-
className,
|
|
39121
|
-
ariaLabel,
|
|
39122
|
-
onValueChange
|
|
39123
|
-
}) {
|
|
39124
|
-
const ref = useRef(null);
|
|
39125
|
-
useEffect(() => {
|
|
39126
|
-
const el = ref.current;
|
|
39127
|
-
if (!el) return;
|
|
39128
|
-
const isFocused = document.activeElement === el;
|
|
39129
|
-
if (!isFocused && el.textContent !== value) {
|
|
39130
|
-
el.textContent = value;
|
|
39131
|
-
}
|
|
39132
|
-
}, [value]);
|
|
39133
|
-
const handleInput = useCallback(
|
|
39134
|
-
(e) => {
|
|
39135
|
-
onValueChange(e.currentTarget.textContent ?? "");
|
|
39136
|
-
},
|
|
39137
|
-
[onValueChange]
|
|
39138
|
-
);
|
|
38996
|
+
function ToolbarButton({ icon: IconCmp, label, active, onExec }) {
|
|
39139
38997
|
return /* @__PURE__ */ jsx(
|
|
39140
|
-
|
|
38998
|
+
Button,
|
|
39141
38999
|
{
|
|
39142
|
-
|
|
39143
|
-
|
|
39144
|
-
|
|
39145
|
-
|
|
39146
|
-
|
|
39147
|
-
|
|
39148
|
-
"aria-multiline": "true",
|
|
39149
|
-
"data-placeholder": placeholder,
|
|
39000
|
+
type: "button",
|
|
39001
|
+
variant: "ghost",
|
|
39002
|
+
size: "sm",
|
|
39003
|
+
"aria-label": label,
|
|
39004
|
+
"aria-pressed": active,
|
|
39005
|
+
title: label,
|
|
39150
39006
|
className: cn(
|
|
39151
|
-
"
|
|
39152
|
-
"
|
|
39153
|
-
className
|
|
39007
|
+
"h-8 w-8 p-0 gap-0 justify-center",
|
|
39008
|
+
active && "bg-muted text-foreground"
|
|
39154
39009
|
),
|
|
39155
|
-
|
|
39010
|
+
onMouseDown: (e) => {
|
|
39011
|
+
e.preventDefault();
|
|
39012
|
+
onExec();
|
|
39013
|
+
},
|
|
39014
|
+
children: /* @__PURE__ */ jsx(IconCmp, { size: 15 })
|
|
39156
39015
|
}
|
|
39157
39016
|
);
|
|
39158
39017
|
}
|
|
39159
|
-
|
|
39160
|
-
|
|
39161
|
-
|
|
39162
|
-
|
|
39163
|
-
|
|
39164
|
-
|
|
39165
|
-
|
|
39166
|
-
|
|
39167
|
-
|
|
39168
|
-
|
|
39169
|
-
|
|
39170
|
-
|
|
39171
|
-
|
|
39172
|
-
|
|
39173
|
-
|
|
39174
|
-
|
|
39175
|
-
|
|
39176
|
-
|
|
39177
|
-
|
|
39178
|
-
|
|
39179
|
-
|
|
39180
|
-
|
|
39181
|
-
|
|
39182
|
-
|
|
39183
|
-
|
|
39184
|
-
|
|
39185
|
-
|
|
39186
|
-
|
|
39187
|
-
|
|
39188
|
-
|
|
39189
|
-
|
|
39190
|
-
|
|
39191
|
-
|
|
39192
|
-
|
|
39193
|
-
|
|
39194
|
-
|
|
39195
|
-
|
|
39196
|
-
|
|
39197
|
-
|
|
39198
|
-
|
|
39199
|
-
|
|
39200
|
-
|
|
39201
|
-
|
|
39202
|
-
|
|
39203
|
-
|
|
39204
|
-
|
|
39205
|
-
|
|
39206
|
-
|
|
39207
|
-
|
|
39208
|
-
|
|
39209
|
-
|
|
39210
|
-
|
|
39211
|
-
|
|
39212
|
-
|
|
39213
|
-
|
|
39214
|
-
|
|
39215
|
-
|
|
39216
|
-
|
|
39217
|
-
|
|
39218
|
-
|
|
39219
|
-
|
|
39220
|
-
|
|
39221
|
-
|
|
39222
|
-
|
|
39223
|
-
|
|
39224
|
-
|
|
39225
|
-
|
|
39226
|
-
|
|
39227
|
-
|
|
39228
|
-
|
|
39229
|
-
|
|
39230
|
-
|
|
39231
|
-
|
|
39232
|
-
|
|
39233
|
-
|
|
39234
|
-
|
|
39235
|
-
|
|
39236
|
-
|
|
39237
|
-
|
|
39238
|
-
|
|
39239
|
-
|
|
39240
|
-
|
|
39241
|
-
|
|
39242
|
-
|
|
39243
|
-
|
|
39244
|
-
|
|
39245
|
-
|
|
39246
|
-
|
|
39247
|
-
|
|
39248
|
-
|
|
39249
|
-
|
|
39250
|
-
|
|
39251
|
-
|
|
39252
|
-
|
|
39253
|
-
|
|
39254
|
-
|
|
39255
|
-
|
|
39256
|
-
|
|
39257
|
-
|
|
39258
|
-
|
|
39259
|
-
|
|
39260
|
-
|
|
39261
|
-
|
|
39262
|
-
|
|
39263
|
-
);
|
|
39264
|
-
|
|
39265
|
-
|
|
39266
|
-
|
|
39267
|
-
|
|
39268
|
-
|
|
39269
|
-
|
|
39270
|
-
|
|
39271
|
-
|
|
39272
|
-
|
|
39273
|
-
|
|
39274
|
-
|
|
39275
|
-
|
|
39276
|
-
|
|
39277
|
-
|
|
39278
|
-
|
|
39279
|
-
|
|
39280
|
-
|
|
39281
|
-
|
|
39282
|
-
|
|
39283
|
-
|
|
39284
|
-
|
|
39285
|
-
|
|
39286
|
-
|
|
39287
|
-
|
|
39288
|
-
|
|
39289
|
-
|
|
39290
|
-
|
|
39291
|
-
|
|
39292
|
-
|
|
39293
|
-
|
|
39294
|
-
|
|
39295
|
-
|
|
39296
|
-
|
|
39297
|
-
|
|
39298
|
-
|
|
39299
|
-
|
|
39300
|
-
|
|
39301
|
-
|
|
39302
|
-
|
|
39303
|
-
|
|
39304
|
-
|
|
39018
|
+
var CHANGE_DEBOUNCE_MS, ALLOWED_ATTRS, DROP_TAGS, MD_BLOCK_PREFIXES, BLOCK_TAGS, MD_INLINE_RULES, RICH_TEXT_CSS, IDLE_TOOLBAR, RichTextEditor;
|
|
39019
|
+
var init_RichTextEditor = __esm({
|
|
39020
|
+
"components/core/molecules/RichTextEditor.tsx"() {
|
|
39021
|
+
"use client";
|
|
39022
|
+
init_cn();
|
|
39023
|
+
init_Box();
|
|
39024
|
+
init_Button();
|
|
39025
|
+
init_useEventBus();
|
|
39026
|
+
CHANGE_DEBOUNCE_MS = 400;
|
|
39027
|
+
ALLOWED_ATTRS = {
|
|
39028
|
+
p: [],
|
|
39029
|
+
h1: [],
|
|
39030
|
+
h2: [],
|
|
39031
|
+
h3: [],
|
|
39032
|
+
h4: [],
|
|
39033
|
+
ul: [],
|
|
39034
|
+
ol: [],
|
|
39035
|
+
li: [],
|
|
39036
|
+
blockquote: [],
|
|
39037
|
+
pre: [],
|
|
39038
|
+
code: [],
|
|
39039
|
+
b: [],
|
|
39040
|
+
strong: [],
|
|
39041
|
+
i: [],
|
|
39042
|
+
em: [],
|
|
39043
|
+
u: [],
|
|
39044
|
+
s: [],
|
|
39045
|
+
strike: [],
|
|
39046
|
+
br: [],
|
|
39047
|
+
hr: [],
|
|
39048
|
+
div: [],
|
|
39049
|
+
span: [],
|
|
39050
|
+
a: ["href"],
|
|
39051
|
+
img: ["src", "alt"]
|
|
39052
|
+
};
|
|
39053
|
+
DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "iframe", "object", "embed", "link", "meta", "form", "input", "button", "textarea", "select"]);
|
|
39054
|
+
MD_BLOCK_PREFIXES = {
|
|
39055
|
+
"#": { kind: "block", tag: "h1" },
|
|
39056
|
+
"##": { kind: "block", tag: "h2" },
|
|
39057
|
+
"###": { kind: "block", tag: "h3" },
|
|
39058
|
+
">": { kind: "block", tag: "blockquote" },
|
|
39059
|
+
"```": { kind: "block", tag: "pre" },
|
|
39060
|
+
"-": { kind: "list", command: "insertUnorderedList" },
|
|
39061
|
+
"*": { kind: "list", command: "insertUnorderedList" },
|
|
39062
|
+
"1.": { kind: "list", command: "insertOrderedList" }
|
|
39063
|
+
};
|
|
39064
|
+
BLOCK_TAGS = /* @__PURE__ */ new Set(["P", "DIV", "LI", "H1", "H2", "H3", "H4", "BLOCKQUOTE", "PRE"]);
|
|
39065
|
+
MD_INLINE_RULES = [
|
|
39066
|
+
{ pattern: /\*\*([^*\n]+)\*\*$/, wrap: "strong" },
|
|
39067
|
+
{ pattern: /(^|[^*])\*([^*\n]+)\*$/, wrap: "em" },
|
|
39068
|
+
{ pattern: /`([^`\n]+)`$/, wrap: "code" }
|
|
39069
|
+
];
|
|
39070
|
+
RICH_TEXT_CSS = `
|
|
39071
|
+
.almadar-rich-text { line-height: 1.7; color: var(--color-foreground); }
|
|
39072
|
+
.almadar-rich-text h1 { font-size: 1.875rem; font-weight: 700; line-height: 1.25; margin: 1.25em 0 0.4em; }
|
|
39073
|
+
.almadar-rich-text h2 { font-size: 1.5rem; font-weight: 650; line-height: 1.3; margin: 1.1em 0 0.4em; }
|
|
39074
|
+
.almadar-rich-text h3 { font-size: 1.25rem; font-weight: 600; line-height: 1.35; margin: 1em 0 0.35em; }
|
|
39075
|
+
.almadar-rich-text h1:first-child, .almadar-rich-text h2:first-child, .almadar-rich-text h3:first-child { margin-top: 0; }
|
|
39076
|
+
.almadar-rich-text p { margin: 0.5em 0; }
|
|
39077
|
+
.almadar-rich-text ul { list-style: disc; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
39078
|
+
.almadar-rich-text ol { list-style: decimal; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
39079
|
+
.almadar-rich-text li { margin: 0.25em 0; }
|
|
39080
|
+
.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; }
|
|
39081
|
+
.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; }
|
|
39082
|
+
.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; }
|
|
39083
|
+
.almadar-rich-text pre code { background: transparent; padding: 0; }
|
|
39084
|
+
.almadar-rich-text a { color: var(--color-primary); text-decoration: underline; }
|
|
39085
|
+
.almadar-rich-text hr { border: none; border-top: 1px solid var(--color-border); margin: 1.25em 0; }
|
|
39086
|
+
.almadar-rich-text img { max-width: 100%; border-radius: 0.375rem; }
|
|
39087
|
+
`;
|
|
39088
|
+
IDLE_TOOLBAR = {
|
|
39089
|
+
bold: false,
|
|
39090
|
+
italic: false,
|
|
39091
|
+
underline: false,
|
|
39092
|
+
strikeThrough: false,
|
|
39093
|
+
block: null,
|
|
39094
|
+
bullets: false,
|
|
39095
|
+
numbers: false,
|
|
39096
|
+
link: false
|
|
39097
|
+
};
|
|
39098
|
+
RichTextEditor = ({
|
|
39099
|
+
value,
|
|
39100
|
+
onChange,
|
|
39101
|
+
changeEvent,
|
|
39102
|
+
readOnly = false,
|
|
39103
|
+
placeholder,
|
|
39104
|
+
showToolbar = true,
|
|
39105
|
+
className
|
|
39106
|
+
}) => {
|
|
39107
|
+
const { t } = useTranslate();
|
|
39108
|
+
const ref = useRef(null);
|
|
39109
|
+
const [toolbar, setToolbar] = useState(IDLE_TOOLBAR);
|
|
39110
|
+
const [empty, setEmpty] = useState(() => !value || !sanitizeRichHtml(value).trim());
|
|
39111
|
+
const eventBus = useEventBus();
|
|
39112
|
+
const onChangeRef = useRef(onChange);
|
|
39113
|
+
const changeEventRef = useRef(changeEvent);
|
|
39114
|
+
useEffect(() => {
|
|
39115
|
+
onChangeRef.current = onChange;
|
|
39116
|
+
changeEventRef.current = changeEvent;
|
|
39117
|
+
}, [onChange, changeEvent]);
|
|
39118
|
+
const emitTimerRef = useRef(null);
|
|
39119
|
+
const emitNow = useCallback(() => {
|
|
39120
|
+
const el = ref.current;
|
|
39121
|
+
if (!el) return;
|
|
39122
|
+
const html = sanitizeRichHtml(el.innerHTML);
|
|
39123
|
+
onChangeRef.current?.(html);
|
|
39124
|
+
const evt = changeEventRef.current;
|
|
39125
|
+
if (evt) eventBus.emit(`UI:${evt}`, { value: html });
|
|
39126
|
+
}, [eventBus]);
|
|
39127
|
+
const scheduleEmit = useCallback(() => {
|
|
39128
|
+
if (emitTimerRef.current) clearTimeout(emitTimerRef.current);
|
|
39129
|
+
emitTimerRef.current = setTimeout(() => {
|
|
39130
|
+
emitTimerRef.current = null;
|
|
39131
|
+
emitNow();
|
|
39132
|
+
}, CHANGE_DEBOUNCE_MS);
|
|
39133
|
+
}, [emitNow]);
|
|
39134
|
+
const flushEmit = useCallback(() => {
|
|
39135
|
+
if (!emitTimerRef.current) return;
|
|
39136
|
+
clearTimeout(emitTimerRef.current);
|
|
39137
|
+
emitTimerRef.current = null;
|
|
39138
|
+
emitNow();
|
|
39139
|
+
}, [emitNow]);
|
|
39140
|
+
useEffect(() => () => {
|
|
39141
|
+
if (emitTimerRef.current) {
|
|
39142
|
+
clearTimeout(emitTimerRef.current);
|
|
39143
|
+
emitTimerRef.current = null;
|
|
39144
|
+
emitNow();
|
|
39145
|
+
}
|
|
39146
|
+
}, [emitNow]);
|
|
39147
|
+
useEffect(() => {
|
|
39148
|
+
if (readOnly) return;
|
|
39149
|
+
const el = ref.current;
|
|
39150
|
+
if (!el) return;
|
|
39151
|
+
if (document.activeElement === el) return;
|
|
39152
|
+
const next = sanitizeRichHtml(value ?? "") || "<p><br></p>";
|
|
39153
|
+
if (el.innerHTML !== next) {
|
|
39154
|
+
el.innerHTML = next;
|
|
39155
|
+
setEmpty(htmlIsEmpty(el));
|
|
39156
|
+
}
|
|
39157
|
+
}, [readOnly, value]);
|
|
39158
|
+
useEffect(() => {
|
|
39159
|
+
if (readOnly) return;
|
|
39160
|
+
document.execCommand("defaultParagraphSeparator", false, "p");
|
|
39161
|
+
}, [readOnly]);
|
|
39162
|
+
useEffect(() => {
|
|
39163
|
+
if (readOnly || !showToolbar) return;
|
|
39164
|
+
const onSelectionChange = () => {
|
|
39165
|
+
const el = ref.current;
|
|
39166
|
+
if (!el) return;
|
|
39167
|
+
setToolbar(readToolbarState(el));
|
|
39305
39168
|
};
|
|
39306
|
-
|
|
39307
|
-
|
|
39308
|
-
|
|
39309
|
-
|
|
39310
|
-
|
|
39311
|
-
|
|
39312
|
-
|
|
39313
|
-
|
|
39314
|
-
|
|
39315
|
-
|
|
39316
|
-
|
|
39317
|
-
|
|
39318
|
-
|
|
39319
|
-
|
|
39320
|
-
|
|
39321
|
-
|
|
39322
|
-
!
|
|
39323
|
-
|
|
39324
|
-
|
|
39325
|
-
|
|
39326
|
-
|
|
39327
|
-
|
|
39328
|
-
|
|
39329
|
-
|
|
39330
|
-
|
|
39331
|
-
|
|
39332
|
-
|
|
39333
|
-
|
|
39334
|
-
|
|
39335
|
-
|
|
39336
|
-
|
|
39337
|
-
|
|
39338
|
-
|
|
39339
|
-
|
|
39340
|
-
|
|
39341
|
-
|
|
39342
|
-
|
|
39343
|
-
|
|
39344
|
-
|
|
39345
|
-
|
|
39346
|
-
|
|
39347
|
-
|
|
39348
|
-
|
|
39349
|
-
|
|
39350
|
-
|
|
39351
|
-
|
|
39352
|
-
|
|
39169
|
+
document.addEventListener("selectionchange", onSelectionChange);
|
|
39170
|
+
return () => document.removeEventListener("selectionchange", onSelectionChange);
|
|
39171
|
+
}, [readOnly, showToolbar]);
|
|
39172
|
+
const tryInlineMarkdown = useCallback(() => {
|
|
39173
|
+
const root = ref.current;
|
|
39174
|
+
if (!root) return false;
|
|
39175
|
+
const sel = window.getSelection();
|
|
39176
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
39177
|
+
const node = sel.anchorNode;
|
|
39178
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
39179
|
+
if (node.parentElement?.closest("code, pre")) return false;
|
|
39180
|
+
const text = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
39181
|
+
for (const rule of MD_INLINE_RULES) {
|
|
39182
|
+
const m = rule.pattern.exec(text);
|
|
39183
|
+
if (!m) continue;
|
|
39184
|
+
const inner = rule.wrap === "em" ? m[2] : m[1];
|
|
39185
|
+
if (!inner || !inner.trim()) continue;
|
|
39186
|
+
const lead = rule.wrap === "em" ? m[1]?.length ?? 0 : 0;
|
|
39187
|
+
const range = document.createRange();
|
|
39188
|
+
range.setStart(node, m.index + lead);
|
|
39189
|
+
range.setEnd(node, sel.anchorOffset);
|
|
39190
|
+
const el = document.createElement(rule.wrap);
|
|
39191
|
+
el.textContent = inner;
|
|
39192
|
+
range.deleteContents();
|
|
39193
|
+
range.insertNode(el);
|
|
39194
|
+
const after = document.createTextNode("\u200B");
|
|
39195
|
+
el.parentNode?.insertBefore(after, el.nextSibling);
|
|
39196
|
+
const caret = document.createRange();
|
|
39197
|
+
caret.setStart(after, 1);
|
|
39198
|
+
caret.collapse(true);
|
|
39199
|
+
sel.removeAllRanges();
|
|
39200
|
+
sel.addRange(caret);
|
|
39201
|
+
return true;
|
|
39202
|
+
}
|
|
39203
|
+
return false;
|
|
39204
|
+
}, []);
|
|
39205
|
+
const tryBlockMarkdown = useCallback(() => {
|
|
39206
|
+
const root = ref.current;
|
|
39207
|
+
if (!root) return false;
|
|
39208
|
+
const sel = window.getSelection();
|
|
39209
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
39210
|
+
const node = sel.anchorNode;
|
|
39211
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
39212
|
+
const block = closestBlock(node, root);
|
|
39213
|
+
if (block ? block.firstChild !== node : root.firstChild !== node) return false;
|
|
39214
|
+
const prefix = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
39215
|
+
const rule = MD_BLOCK_PREFIXES[prefix];
|
|
39216
|
+
if (!rule) return false;
|
|
39217
|
+
if (node.parentElement?.closest("pre, code")) return false;
|
|
39218
|
+
if (rule.kind === "list" && node.parentElement?.closest("li")) return false;
|
|
39219
|
+
node.deleteData(0, prefix.length);
|
|
39220
|
+
const caret = document.createRange();
|
|
39221
|
+
caret.setStart(node, 0);
|
|
39222
|
+
caret.collapse(true);
|
|
39223
|
+
sel.removeAllRanges();
|
|
39224
|
+
sel.addRange(caret);
|
|
39225
|
+
if (rule.kind === "list") {
|
|
39226
|
+
const container = block ?? node.parentElement;
|
|
39227
|
+
const list = document.createElement(rule.command === "insertOrderedList" ? "ol" : "ul");
|
|
39228
|
+
const li = document.createElement("li");
|
|
39229
|
+
if (block) {
|
|
39230
|
+
while (block.firstChild) li.appendChild(block.firstChild);
|
|
39231
|
+
list.appendChild(li);
|
|
39232
|
+
block.replaceWith(list);
|
|
39233
|
+
} else if (container) {
|
|
39234
|
+
li.appendChild(node);
|
|
39235
|
+
list.appendChild(li);
|
|
39236
|
+
container.appendChild(list);
|
|
39237
|
+
}
|
|
39238
|
+
if (!li.firstChild) li.appendChild(document.createElement("br"));
|
|
39239
|
+
const liCaret = document.createRange();
|
|
39240
|
+
liCaret.selectNodeContents(li);
|
|
39241
|
+
liCaret.collapse(true);
|
|
39242
|
+
sel.removeAllRanges();
|
|
39243
|
+
sel.addRange(liCaret);
|
|
39244
|
+
} else {
|
|
39245
|
+
document.execCommand("formatBlock", false, rule.tag);
|
|
39246
|
+
}
|
|
39247
|
+
return true;
|
|
39248
|
+
}, []);
|
|
39249
|
+
const afterEdit = useCallback(() => {
|
|
39250
|
+
const el = ref.current;
|
|
39251
|
+
if (!el) return;
|
|
39252
|
+
tryInlineMarkdown();
|
|
39253
|
+
setEmpty(htmlIsEmpty(el));
|
|
39254
|
+
setToolbar(readToolbarState(el));
|
|
39255
|
+
scheduleEmit();
|
|
39256
|
+
}, [scheduleEmit, tryInlineMarkdown]);
|
|
39257
|
+
const handleKeyDown = useCallback((e) => {
|
|
39258
|
+
if (e.key === " " && tryBlockMarkdown()) {
|
|
39259
|
+
e.preventDefault();
|
|
39260
|
+
afterEdit();
|
|
39261
|
+
}
|
|
39262
|
+
}, [afterEdit, tryBlockMarkdown]);
|
|
39263
|
+
const execInline = useCallback((command) => {
|
|
39264
|
+
document.execCommand(command, false);
|
|
39265
|
+
afterEdit();
|
|
39266
|
+
}, [afterEdit]);
|
|
39267
|
+
const execBlock = useCallback((tag) => {
|
|
39268
|
+
const next = toolbar.block === tag ? "p" : tag;
|
|
39269
|
+
document.execCommand("formatBlock", false, next);
|
|
39270
|
+
afterEdit();
|
|
39271
|
+
}, [afterEdit, toolbar.block]);
|
|
39272
|
+
const execList = useCallback((command) => {
|
|
39273
|
+
document.execCommand(command, false);
|
|
39274
|
+
afterEdit();
|
|
39275
|
+
}, [afterEdit]);
|
|
39276
|
+
const execLink = useCallback(() => {
|
|
39277
|
+
if (toolbar.link) {
|
|
39278
|
+
document.execCommand("unlink", false);
|
|
39279
|
+
afterEdit();
|
|
39280
|
+
return;
|
|
39281
|
+
}
|
|
39282
|
+
const url = window.prompt(t("richTextEditor.linkPrompt"));
|
|
39283
|
+
if (!url) return;
|
|
39284
|
+
const safe = safeUrl(url, ["http://", "https://", "mailto:"]) ?? `https://${url}`;
|
|
39285
|
+
document.execCommand("createLink", false, safe);
|
|
39286
|
+
afterEdit();
|
|
39287
|
+
}, [afterEdit, t, toolbar.link]);
|
|
39288
|
+
const execRule = useCallback(() => {
|
|
39289
|
+
document.execCommand("insertHorizontalRule", false);
|
|
39290
|
+
afterEdit();
|
|
39291
|
+
}, [afterEdit]);
|
|
39292
|
+
if (readOnly) {
|
|
39293
|
+
return /* @__PURE__ */ jsxs(Box, { className: cn("almadar-rich-text max-w-none", className), children: [
|
|
39294
|
+
/* @__PURE__ */ jsx(RichTextStyles, {}),
|
|
39295
|
+
/* @__PURE__ */ jsx(Box, { dangerouslySetInnerHTML: { __html: sanitizeRichHtml(value ?? "") } })
|
|
39353
39296
|
] });
|
|
39354
39297
|
}
|
|
39355
|
-
|
|
39356
|
-
|
|
39357
|
-
|
|
39358
|
-
return /* @__PURE__ */ jsxs(
|
|
39298
|
+
return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
|
|
39299
|
+
/* @__PURE__ */ jsx(RichTextStyles, {}),
|
|
39300
|
+
showToolbar && /* @__PURE__ */ jsxs(
|
|
39359
39301
|
Box,
|
|
39360
39302
|
{
|
|
39361
|
-
|
|
39303
|
+
role: "toolbar",
|
|
39304
|
+
"aria-label": t("richTextEditor.editorToolbar"),
|
|
39362
39305
|
className: cn(
|
|
39363
|
-
"
|
|
39364
|
-
|
|
39306
|
+
"sticky top-0 z-10 flex flex-wrap items-center gap-0.5 self-start",
|
|
39307
|
+
"rounded-md border border-border bg-background/95 px-1 py-0.5 shadow-sm"
|
|
39365
39308
|
),
|
|
39366
39309
|
children: [
|
|
39367
|
-
|
|
39368
|
-
|
|
39369
|
-
|
|
39370
|
-
|
|
39371
|
-
|
|
39372
|
-
|
|
39373
|
-
|
|
39374
|
-
|
|
39375
|
-
|
|
39376
|
-
|
|
39377
|
-
|
|
39378
|
-
|
|
39379
|
-
|
|
39380
|
-
|
|
39381
|
-
|
|
39382
|
-
|
|
39383
|
-
type: "button",
|
|
39384
|
-
variant: "ghost",
|
|
39385
|
-
"aria-label": t("richBlockEditor.aria.removeListItem"),
|
|
39386
|
-
className: cn(
|
|
39387
|
-
"h-5 w-5 shrink-0 rounded-sm text-muted-foreground p-0 gap-0",
|
|
39388
|
-
"opacity-0 group-hover/item:opacity-100 hover:bg-muted hover:text-foreground"
|
|
39389
|
-
),
|
|
39390
|
-
onClick: () => removeListItem(child.id),
|
|
39391
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3 h-3" })
|
|
39392
|
-
}
|
|
39393
|
-
)
|
|
39394
|
-
] }, child.id)),
|
|
39395
|
-
!readOnly && showAffordances && /* @__PURE__ */ jsx(Box, { as: "li", className: "list-none pl-0", children: /* @__PURE__ */ jsxs(
|
|
39396
|
-
Button,
|
|
39397
|
-
{
|
|
39398
|
-
type: "button",
|
|
39399
|
-
variant: "ghost",
|
|
39400
|
-
className: cn(
|
|
39401
|
-
"inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
39402
|
-
"hover:text-foreground p-0 h-auto"
|
|
39403
|
-
),
|
|
39404
|
-
onClick: addListItem,
|
|
39405
|
-
children: [
|
|
39406
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3 h-3" }),
|
|
39407
|
-
" ",
|
|
39408
|
-
t("richBlockEditor.addItem")
|
|
39409
|
-
]
|
|
39410
|
-
}
|
|
39411
|
-
) })
|
|
39310
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Bold, label: t("richTextEditor.bold"), active: toolbar.bold, onExec: () => execInline("bold") }),
|
|
39311
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Italic, label: t("richTextEditor.italic"), active: toolbar.italic, onExec: () => execInline("italic") }),
|
|
39312
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Underline, label: t("richTextEditor.underline"), active: toolbar.underline, onExec: () => execInline("underline") }),
|
|
39313
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Strikethrough, label: t("richTextEditor.strikethrough"), active: toolbar.strikeThrough, onExec: () => execInline("strikeThrough") }),
|
|
39314
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
39315
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading1, label: t("richTextEditor.heading1"), active: toolbar.block === "h1", onExec: () => execBlock("h1") }),
|
|
39316
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading2, label: t("richTextEditor.heading2"), active: toolbar.block === "h2", onExec: () => execBlock("h2") }),
|
|
39317
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading3, label: t("richTextEditor.heading3"), active: toolbar.block === "h3", onExec: () => execBlock("h3") }),
|
|
39318
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
39319
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: List, label: t("richTextEditor.bulletList"), active: toolbar.bullets, onExec: () => execList("insertUnorderedList") }),
|
|
39320
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: ListOrdered, label: t("richTextEditor.numberedList"), active: toolbar.numbers, onExec: () => execList("insertOrderedList") }),
|
|
39321
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
39322
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Quote, label: t("richTextEditor.quote"), active: toolbar.block === "blockquote", onExec: () => execBlock("blockquote") }),
|
|
39323
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Code, label: t("richTextEditor.code"), active: toolbar.block === "pre", onExec: () => execBlock("pre") }),
|
|
39324
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Link$1, label: toolbar.link ? t("richTextEditor.removeLink") : t("richTextEditor.link"), active: toolbar.link, onExec: execLink }),
|
|
39325
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Minus, label: t("richTextEditor.divider"), onExec: execRule })
|
|
39412
39326
|
]
|
|
39413
39327
|
}
|
|
39414
|
-
)
|
|
39415
|
-
|
|
39416
|
-
|
|
39417
|
-
default:
|
|
39418
|
-
return /* @__PURE__ */ jsx(
|
|
39419
|
-
Editable,
|
|
39328
|
+
),
|
|
39329
|
+
/* @__PURE__ */ jsx(
|
|
39330
|
+
Box,
|
|
39420
39331
|
{
|
|
39421
|
-
|
|
39422
|
-
|
|
39423
|
-
|
|
39424
|
-
|
|
39425
|
-
|
|
39426
|
-
|
|
39427
|
-
|
|
39332
|
+
ref,
|
|
39333
|
+
contentEditable: true,
|
|
39334
|
+
suppressContentEditableWarning: true,
|
|
39335
|
+
role: "textbox",
|
|
39336
|
+
"aria-multiline": "true",
|
|
39337
|
+
"aria-label": t("richTextEditor.editorSurface"),
|
|
39338
|
+
"data-placeholder": placeholder ?? t("richTextEditor.placeholder"),
|
|
39339
|
+
"data-empty": empty ? "true" : "false",
|
|
39340
|
+
className: cn(
|
|
39341
|
+
"almadar-rich-text max-w-none min-h-[8rem] outline-none",
|
|
39342
|
+
"data-[empty=true]:before:content-[attr(data-placeholder)]",
|
|
39343
|
+
"data-[empty=true]:before:text-muted-foreground/60",
|
|
39344
|
+
"data-[empty=true]:before:pointer-events-none",
|
|
39345
|
+
"data-[empty=true]:before:absolute",
|
|
39346
|
+
"relative cursor-text"
|
|
39347
|
+
),
|
|
39348
|
+
onInput: afterEdit,
|
|
39349
|
+
onKeyDown: handleKeyDown,
|
|
39350
|
+
onBlur: flushEmit
|
|
39428
39351
|
}
|
|
39429
|
-
)
|
|
39430
|
-
|
|
39352
|
+
)
|
|
39353
|
+
] });
|
|
39354
|
+
};
|
|
39355
|
+
RichTextEditor.displayName = "RichTextEditor";
|
|
39356
|
+
}
|
|
39357
|
+
});
|
|
39358
|
+
function renderIconInput4(icon, props) {
|
|
39359
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
|
|
39360
|
+
}
|
|
39361
|
+
function DocumentPanel({
|
|
39362
|
+
entity,
|
|
39363
|
+
title,
|
|
39364
|
+
subtitle,
|
|
39365
|
+
value,
|
|
39366
|
+
actions,
|
|
39367
|
+
maxInlineActions,
|
|
39368
|
+
editing = false,
|
|
39369
|
+
titleCommitEvent,
|
|
39370
|
+
contentChangeEvent,
|
|
39371
|
+
editEvent,
|
|
39372
|
+
doneEvent,
|
|
39373
|
+
editLabel,
|
|
39374
|
+
doneLabel,
|
|
39375
|
+
autosaveHint,
|
|
39376
|
+
placeholder,
|
|
39377
|
+
className
|
|
39378
|
+
}) {
|
|
39379
|
+
const eventBus = useEventBus();
|
|
39380
|
+
const { t } = useTranslate();
|
|
39381
|
+
const [titleDraft, setTitleDraft] = useState(null);
|
|
39382
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
39383
|
+
const actionDefs = actions ?? [];
|
|
39384
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
39385
|
+
const inlineActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
39386
|
+
const menuActions = actionDefs.filter((a) => !inlineActions.includes(a));
|
|
39387
|
+
const fireAction = (action) => {
|
|
39388
|
+
if (!action.event) return;
|
|
39389
|
+
eventBus.emit(`UI:${action.event}`, { id: recordId, row: entity });
|
|
39431
39390
|
};
|
|
39432
|
-
|
|
39391
|
+
const commitTitle = () => {
|
|
39392
|
+
if (!titleCommitEvent) return;
|
|
39393
|
+
const next = (titleDraft ?? "").trim();
|
|
39394
|
+
setTitleDraft(null);
|
|
39395
|
+
if (!next || next === title) return;
|
|
39396
|
+
eventBus.emit(`UI:${titleCommitEvent}`, { title: next, id: recordId });
|
|
39397
|
+
};
|
|
39398
|
+
const untitled = t("documentPanel.untitled") || "Untitled";
|
|
39399
|
+
const titleNode = titleCommitEvent && titleDraft !== null ? /* @__PURE__ */ jsx(
|
|
39400
|
+
Input,
|
|
39401
|
+
{
|
|
39402
|
+
value: titleDraft,
|
|
39403
|
+
autoFocus: true,
|
|
39404
|
+
"aria-label": t("common.title"),
|
|
39405
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
39406
|
+
onFocus: (e) => e.currentTarget.select(),
|
|
39407
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
39408
|
+
onBlur: commitTitle,
|
|
39409
|
+
onKeyDown: (e) => {
|
|
39410
|
+
if (e.key === "Enter") {
|
|
39411
|
+
e.preventDefault();
|
|
39412
|
+
commitTitle();
|
|
39413
|
+
} else if (e.key === "Escape") {
|
|
39414
|
+
e.preventDefault();
|
|
39415
|
+
setTitleDraft(null);
|
|
39416
|
+
}
|
|
39417
|
+
},
|
|
39418
|
+
"data-testid": "document-title-input"
|
|
39419
|
+
}
|
|
39420
|
+
) : titleCommitEvent ? /* @__PURE__ */ jsx(
|
|
39433
39421
|
Box,
|
|
39434
39422
|
{
|
|
39435
|
-
|
|
39436
|
-
|
|
39437
|
-
|
|
39438
|
-
),
|
|
39439
|
-
|
|
39440
|
-
|
|
39441
|
-
|
|
39442
|
-
|
|
39443
|
-
|
|
39423
|
+
role: "button",
|
|
39424
|
+
tabIndex: 0,
|
|
39425
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
39426
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
39427
|
+
onKeyDown: (e) => {
|
|
39428
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
39429
|
+
e.preventDefault();
|
|
39430
|
+
setTitleDraft(title ?? "");
|
|
39431
|
+
}
|
|
39432
|
+
},
|
|
39433
|
+
"data-testid": "document-title-editable",
|
|
39434
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", className: cn(!title && "text-muted-foreground"), children: title || untitled })
|
|
39435
|
+
}
|
|
39436
|
+
) : /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || untitled });
|
|
39437
|
+
const emitWithId = (event) => () => {
|
|
39438
|
+
if (event) eventBus.emit(`UI:${event}`, { id: recordId });
|
|
39439
|
+
};
|
|
39440
|
+
return /* @__PURE__ */ jsx(Card, { variant: "elevated", className: cn("w-full", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-6 sm:p-8", children: [
|
|
39441
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
39442
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
39443
|
+
titleNode,
|
|
39444
|
+
subtitle ? /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: subtitle }) : null
|
|
39445
|
+
] }),
|
|
39446
|
+
/* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0 pt-1 items-center", children: editing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39447
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", className: "hidden sm:block", children: autosaveHint ?? (t("documentPanel.autosaveHint") || "") }),
|
|
39448
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: emitWithId(doneEvent), "data-testid": "document-done", children: doneLabel ?? (t("documentPanel.done") || "Done") })
|
|
39449
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39450
|
+
editEvent && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: emitWithId(editEvent), "data-testid": "document-edit", children: [
|
|
39451
|
+
/* @__PURE__ */ jsx(Icon, { name: "edit", size: "xs", className: "mr-1" }),
|
|
39452
|
+
editLabel ?? (t("documentPanel.edit") || "Edit")
|
|
39453
|
+
] }),
|
|
39454
|
+
inlineActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
39455
|
+
Button,
|
|
39444
39456
|
{
|
|
39445
|
-
|
|
39446
|
-
|
|
39447
|
-
|
|
39448
|
-
|
|
39449
|
-
|
|
39457
|
+
variant: "primary",
|
|
39458
|
+
size: "sm",
|
|
39459
|
+
onClick: () => fireAction(action),
|
|
39460
|
+
"data-testid": `action-${action.event}`,
|
|
39461
|
+
children: [
|
|
39462
|
+
action.icon && renderIconInput4(action.icon, { size: "xs", className: "mr-1" }),
|
|
39463
|
+
action.label
|
|
39464
|
+
]
|
|
39465
|
+
},
|
|
39466
|
+
idx
|
|
39467
|
+
)),
|
|
39468
|
+
menuActions.length > 0 && /* @__PURE__ */ jsx(
|
|
39469
|
+
Menu,
|
|
39470
|
+
{
|
|
39471
|
+
position: "bottom-end",
|
|
39472
|
+
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" }) }),
|
|
39473
|
+
items: menuActions.map((action) => ({
|
|
39474
|
+
label: action.label,
|
|
39475
|
+
icon: action.icon,
|
|
39476
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
39477
|
+
onClick: () => fireAction(action)
|
|
39478
|
+
}))
|
|
39450
39479
|
}
|
|
39451
|
-
)
|
|
39452
|
-
|
|
39453
|
-
|
|
39454
|
-
}
|
|
39455
|
-
|
|
39480
|
+
)
|
|
39481
|
+
] }) })
|
|
39482
|
+
] }),
|
|
39483
|
+
editing ? /* @__PURE__ */ jsx(RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsx(
|
|
39484
|
+
Box,
|
|
39485
|
+
{
|
|
39486
|
+
onClick: emitWithId(editEvent),
|
|
39487
|
+
className: cn(
|
|
39488
|
+
"rounded-md px-1 -mx-1 min-h-[16rem]",
|
|
39489
|
+
editEvent && "cursor-text transition-colors hover:bg-muted/30"
|
|
39490
|
+
),
|
|
39491
|
+
"data-testid": "document-body",
|
|
39492
|
+
children: value && value !== "" ? /* @__PURE__ */ jsx(RichTextEditor, { value, readOnly: true }) : /* @__PURE__ */ jsx(Typography, { variant: "body", color: "muted", children: placeholder ?? (t("documentPanel.placeholder") || "") })
|
|
39493
|
+
}
|
|
39494
|
+
)
|
|
39495
|
+
] }) });
|
|
39456
39496
|
}
|
|
39457
|
-
var
|
|
39458
|
-
|
|
39459
|
-
"components/core/molecules/RichBlockEditor.tsx"() {
|
|
39497
|
+
var init_DocumentPanel = __esm({
|
|
39498
|
+
"components/core/molecules/DocumentPanel.tsx"() {
|
|
39460
39499
|
"use client";
|
|
39461
39500
|
init_cn();
|
|
39462
|
-
|
|
39501
|
+
init_useEventBus();
|
|
39502
|
+
init_Box();
|
|
39503
|
+
init_Stack();
|
|
39463
39504
|
init_Typography();
|
|
39464
39505
|
init_Button();
|
|
39465
|
-
|
|
39466
|
-
init_Divider();
|
|
39467
|
-
init_Input();
|
|
39506
|
+
init_Card();
|
|
39468
39507
|
init_Icon();
|
|
39469
|
-
|
|
39470
|
-
|
|
39471
|
-
|
|
39472
|
-
|
|
39473
|
-
|
|
39474
|
-
|
|
39475
|
-
|
|
39476
|
-
|
|
39477
|
-
|
|
39478
|
-
|
|
39479
|
-
|
|
39480
|
-
|
|
39481
|
-
|
|
39482
|
-
|
|
39483
|
-
|
|
39484
|
-
|
|
39485
|
-
|
|
39486
|
-
|
|
39487
|
-
|
|
39488
|
-
|
|
39489
|
-
|
|
39490
|
-
|
|
39491
|
-
|
|
39492
|
-
|
|
39493
|
-
|
|
39494
|
-
|
|
39495
|
-
|
|
39496
|
-
|
|
39497
|
-
|
|
39498
|
-
|
|
39499
|
-
|
|
39500
|
-
|
|
39501
|
-
|
|
39502
|
-
|
|
39503
|
-
|
|
39504
|
-
|
|
39505
|
-
|
|
39506
|
-
|
|
39507
|
-
|
|
39508
|
-
|
|
39509
|
-
|
|
39510
|
-
|
|
39511
|
-
|
|
39512
|
-
|
|
39513
|
-
|
|
39514
|
-
|
|
39515
|
-
|
|
39516
|
-
|
|
39517
|
-
|
|
39518
|
-
|
|
39519
|
-
|
|
39520
|
-
|
|
39521
|
-
|
|
39522
|
-
|
|
39523
|
-
|
|
39524
|
-
|
|
39525
|
-
|
|
39526
|
-
|
|
39527
|
-
|
|
39528
|
-
const [blocks, setBlocks] = useState(
|
|
39529
|
-
() => normalizeBlocks(initialBlocks)
|
|
39530
|
-
);
|
|
39531
|
-
const onChangeRef = useRef(onChange);
|
|
39532
|
-
useEffect(() => {
|
|
39533
|
-
onChangeRef.current = onChange;
|
|
39534
|
-
}, [onChange]);
|
|
39535
|
-
const eventBus = useEventBus();
|
|
39536
|
-
const changeEventRef = useRef(changeEvent);
|
|
39537
|
-
useEffect(() => {
|
|
39538
|
-
changeEventRef.current = changeEvent;
|
|
39539
|
-
}, [changeEvent]);
|
|
39540
|
-
const commit = useCallback((next) => {
|
|
39541
|
-
setBlocks(next);
|
|
39542
|
-
onChangeRef.current?.(next);
|
|
39543
|
-
const evt = changeEventRef.current;
|
|
39544
|
-
if (evt) eventBus.emit(`UI:${evt}`, { blocks: next });
|
|
39545
|
-
}, [eventBus]);
|
|
39546
|
-
const handleAppend = useCallback(
|
|
39547
|
-
(type) => {
|
|
39548
|
-
if (readOnly) return;
|
|
39549
|
-
commit([...blocks, createBlock(type)]);
|
|
39550
|
-
},
|
|
39551
|
-
[blocks, commit, readOnly]
|
|
39552
|
-
);
|
|
39553
|
-
const handleUpdate = useCallback(
|
|
39554
|
-
(id, updater) => {
|
|
39555
|
-
commit(replaceBlock(blocks, id, updater));
|
|
39556
|
-
},
|
|
39557
|
-
[blocks, commit]
|
|
39558
|
-
);
|
|
39559
|
-
const handleDelete = useCallback(
|
|
39560
|
-
(id) => {
|
|
39561
|
-
const next = removeBlock(blocks, id);
|
|
39562
|
-
commit(next.length > 0 ? next : [createBlock("paragraph")]);
|
|
39563
|
-
},
|
|
39564
|
-
[blocks, commit]
|
|
39565
|
-
);
|
|
39566
|
-
const handleDuplicate = useCallback(
|
|
39567
|
-
(id) => {
|
|
39568
|
-
const target = blocks.find((b) => b.id === id);
|
|
39569
|
-
if (!target) return;
|
|
39570
|
-
commit(insertAfter(blocks, id, duplicateBlock(target)));
|
|
39571
|
-
},
|
|
39572
|
-
[blocks, commit]
|
|
39508
|
+
init_Input();
|
|
39509
|
+
init_Menu();
|
|
39510
|
+
init_RichTextEditor();
|
|
39511
|
+
}
|
|
39512
|
+
});
|
|
39513
|
+
function renderIconInput5(icon, props) {
|
|
39514
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
|
|
39515
|
+
}
|
|
39516
|
+
function fieldName(field) {
|
|
39517
|
+
return field.name ?? field.key ?? "";
|
|
39518
|
+
}
|
|
39519
|
+
function relationLabel(value) {
|
|
39520
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) return null;
|
|
39521
|
+
for (const key of ["name", "title", "label"]) {
|
|
39522
|
+
const candidate = value[key];
|
|
39523
|
+
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
39524
|
+
}
|
|
39525
|
+
const id = value.id;
|
|
39526
|
+
return id !== void 0 && id !== null ? String(id) : null;
|
|
39527
|
+
}
|
|
39528
|
+
function fieldKind(field, value) {
|
|
39529
|
+
if (field.kind) return field.kind;
|
|
39530
|
+
if (field.options && field.options.length > 0) return "select";
|
|
39531
|
+
if (typeof value === "boolean" || field.format === "boolean") return "boolean";
|
|
39532
|
+
if (Array.isArray(value) || relationLabel(value ?? null) !== null) return "readonly";
|
|
39533
|
+
return "text";
|
|
39534
|
+
}
|
|
39535
|
+
function DocumentDetails({
|
|
39536
|
+
entity,
|
|
39537
|
+
fields,
|
|
39538
|
+
metaCommitEvent,
|
|
39539
|
+
title,
|
|
39540
|
+
className
|
|
39541
|
+
}) {
|
|
39542
|
+
const eventBus = useEventBus();
|
|
39543
|
+
const { t } = useTranslate();
|
|
39544
|
+
const [fieldDraft, setFieldDraft] = useState(null);
|
|
39545
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
39546
|
+
const fieldDefs = (fields ?? []).filter((f3) => fieldName(f3) !== "");
|
|
39547
|
+
if (fieldDefs.length === 0) return null;
|
|
39548
|
+
const commitField = (name, next, current) => {
|
|
39549
|
+
setFieldDraft(null);
|
|
39550
|
+
if (!metaCommitEvent || next === current) return;
|
|
39551
|
+
eventBus.emit(`UI:${metaCommitEvent}`, { id: recordId, patch: { id: recordId, [name]: next } });
|
|
39552
|
+
};
|
|
39553
|
+
const renderValue = (field) => {
|
|
39554
|
+
const name = fieldName(field);
|
|
39555
|
+
const raw = getNestedValue(entity ?? {}, name);
|
|
39556
|
+
const kind = fieldKind(field, raw);
|
|
39557
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
39558
|
+
if (kind === "boolean") {
|
|
39559
|
+
return /* @__PURE__ */ jsx(
|
|
39560
|
+
Switch,
|
|
39561
|
+
{
|
|
39562
|
+
checked: Boolean(raw),
|
|
39563
|
+
disabled: !metaCommitEvent,
|
|
39564
|
+
"aria-label": label,
|
|
39565
|
+
onChange: (checked) => commitField(name, checked, Boolean(raw))
|
|
39566
|
+
}
|
|
39573
39567
|
);
|
|
39574
|
-
|
|
39575
|
-
|
|
39576
|
-
|
|
39577
|
-
|
|
39578
|
-
|
|
39579
|
-
|
|
39580
|
-
|
|
39568
|
+
}
|
|
39569
|
+
if (kind === "select") {
|
|
39570
|
+
return /* @__PURE__ */ jsx(
|
|
39571
|
+
Select,
|
|
39572
|
+
{
|
|
39573
|
+
value: raw !== void 0 && raw !== null ? String(raw) : "",
|
|
39574
|
+
disabled: !metaCommitEvent,
|
|
39575
|
+
"aria-label": label,
|
|
39576
|
+
className: "h-8 w-full",
|
|
39577
|
+
options: (field.options ?? []).map((opt) => ({ value: opt, label: humanizeEnumValue(opt) })),
|
|
39578
|
+
onChange: (e) => commitField(name, e.target.value, raw)
|
|
39579
|
+
}
|
|
39581
39580
|
);
|
|
39582
|
-
|
|
39583
|
-
|
|
39581
|
+
}
|
|
39582
|
+
if (kind === "readonly" || !metaCommitEvent) {
|
|
39583
|
+
if (Array.isArray(raw)) {
|
|
39584
|
+
if (raw.length === 0) {
|
|
39585
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: "\u2014" });
|
|
39586
|
+
}
|
|
39587
|
+
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)) });
|
|
39588
|
+
}
|
|
39589
|
+
const shown2 = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
39590
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "small", className: "break-words", children: shown2 });
|
|
39591
|
+
}
|
|
39592
|
+
if (fieldDraft?.name === name) {
|
|
39593
|
+
return /* @__PURE__ */ jsx(
|
|
39594
|
+
Input,
|
|
39584
39595
|
{
|
|
39585
|
-
|
|
39586
|
-
|
|
39587
|
-
|
|
39588
|
-
|
|
39589
|
-
|
|
39590
|
-
|
|
39591
|
-
|
|
39592
|
-
|
|
39593
|
-
|
|
39594
|
-
|
|
39595
|
-
|
|
39596
|
-
|
|
39597
|
-
|
|
39598
|
-
|
|
39599
|
-
|
|
39600
|
-
|
|
39601
|
-
return /* @__PURE__ */ jsxs(
|
|
39602
|
-
Button,
|
|
39603
|
-
{
|
|
39604
|
-
type: "button",
|
|
39605
|
-
variant: "ghost",
|
|
39606
|
-
size: "sm",
|
|
39607
|
-
"aria-label": t("richBlockEditor.insertEntry", { label: entryLabel }),
|
|
39608
|
-
title: entryLabel,
|
|
39609
|
-
onClick: () => handleAppend(entry.type),
|
|
39610
|
-
children: [
|
|
39611
|
-
/* @__PURE__ */ jsx(Icon2, { size: 14 }),
|
|
39612
|
-
/* @__PURE__ */ jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
|
|
39613
|
-
]
|
|
39614
|
-
},
|
|
39615
|
-
entry.type
|
|
39616
|
-
);
|
|
39617
|
-
})
|
|
39618
|
-
}
|
|
39619
|
-
),
|
|
39620
|
-
/* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-1 px-3 py-3", children: blocks.map((block) => /* @__PURE__ */ jsx(
|
|
39621
|
-
BlockRow,
|
|
39622
|
-
{
|
|
39623
|
-
block,
|
|
39624
|
-
readOnly,
|
|
39625
|
-
showAffordances: enableBlocks,
|
|
39626
|
-
placeholder,
|
|
39627
|
-
onUpdate: (updater) => handleUpdate(block.id, updater),
|
|
39628
|
-
onDelete: () => handleDelete(block.id),
|
|
39629
|
-
onDuplicate: () => handleDuplicate(block.id),
|
|
39630
|
-
onChangeType: (type) => handleChangeType(block.id, type)
|
|
39631
|
-
},
|
|
39632
|
-
block.id
|
|
39633
|
-
)) })
|
|
39634
|
-
]
|
|
39596
|
+
value: fieldDraft.value,
|
|
39597
|
+
autoFocus: true,
|
|
39598
|
+
"aria-label": label,
|
|
39599
|
+
className: "h-8 w-full",
|
|
39600
|
+
onChange: (e) => setFieldDraft({ name, value: e.target.value }),
|
|
39601
|
+
onBlur: () => commitField(name, fieldDraft.value.trim(), raw),
|
|
39602
|
+
onKeyDown: (e) => {
|
|
39603
|
+
if (e.key === "Enter") {
|
|
39604
|
+
e.preventDefault();
|
|
39605
|
+
commitField(name, fieldDraft.value.trim(), raw);
|
|
39606
|
+
} else if (e.key === "Escape") {
|
|
39607
|
+
e.preventDefault();
|
|
39608
|
+
setFieldDraft(null);
|
|
39609
|
+
}
|
|
39610
|
+
},
|
|
39611
|
+
"data-testid": `document-property-input-${name}`
|
|
39635
39612
|
}
|
|
39636
39613
|
);
|
|
39637
|
-
}
|
|
39638
|
-
|
|
39614
|
+
}
|
|
39615
|
+
const shown = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
39616
|
+
return /* @__PURE__ */ jsx(
|
|
39617
|
+
Box,
|
|
39618
|
+
{
|
|
39619
|
+
role: "button",
|
|
39620
|
+
tabIndex: 0,
|
|
39621
|
+
className: cn(
|
|
39622
|
+
"cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
39623
|
+
(raw === void 0 || raw === null || raw === "") && "text-muted-foreground"
|
|
39624
|
+
),
|
|
39625
|
+
onClick: () => setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" }),
|
|
39626
|
+
onKeyDown: (e) => {
|
|
39627
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
39628
|
+
e.preventDefault();
|
|
39629
|
+
setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" });
|
|
39630
|
+
}
|
|
39631
|
+
},
|
|
39632
|
+
"data-testid": `document-property-${name}`,
|
|
39633
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "break-words", children: shown })
|
|
39634
|
+
}
|
|
39635
|
+
);
|
|
39636
|
+
};
|
|
39637
|
+
return /* @__PURE__ */ jsx(Card, { variant: "bordered", className: cn("w-full", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-4", children: [
|
|
39638
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", weight: "medium", className: "uppercase tracking-wide", children: title ?? (t("documentDetails.title") || "Details") }),
|
|
39639
|
+
/* @__PURE__ */ jsx(VStack, { gap: "sm", children: fieldDefs.map((field) => {
|
|
39640
|
+
const name = fieldName(field);
|
|
39641
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
39642
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
39643
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
39644
|
+
field.icon && renderIconInput5(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
39645
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
39646
|
+
] }),
|
|
39647
|
+
/* @__PURE__ */ jsx(Box, { className: "min-w-0", children: renderValue(field) })
|
|
39648
|
+
] }, name);
|
|
39649
|
+
}) })
|
|
39650
|
+
] }) });
|
|
39651
|
+
}
|
|
39652
|
+
var init_DocumentDetails = __esm({
|
|
39653
|
+
"components/core/molecules/DocumentDetails.tsx"() {
|
|
39654
|
+
"use client";
|
|
39655
|
+
init_cn();
|
|
39656
|
+
init_format();
|
|
39657
|
+
init_getNestedValue();
|
|
39658
|
+
init_useEventBus();
|
|
39659
|
+
init_Box();
|
|
39660
|
+
init_Stack();
|
|
39661
|
+
init_Typography();
|
|
39662
|
+
init_Badge();
|
|
39663
|
+
init_Card();
|
|
39664
|
+
init_Icon();
|
|
39665
|
+
init_Input();
|
|
39666
|
+
init_Select();
|
|
39667
|
+
init_Switch();
|
|
39639
39668
|
}
|
|
39640
39669
|
});
|
|
39641
39670
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
@@ -44175,8 +44204,8 @@ var init_DataTable = __esm({
|
|
|
44175
44204
|
DataTable.displayName = "DataTable";
|
|
44176
44205
|
}
|
|
44177
44206
|
});
|
|
44178
|
-
function getBadgeVariant(
|
|
44179
|
-
const name =
|
|
44207
|
+
function getBadgeVariant(fieldName2, value) {
|
|
44208
|
+
const name = fieldName2.toLowerCase();
|
|
44180
44209
|
const val = String(value).toLowerCase();
|
|
44181
44210
|
if (name.includes("status")) {
|
|
44182
44211
|
if (val.includes("complete") || val.includes("done") || val.includes("active"))
|
|
@@ -44192,12 +44221,12 @@ function getBadgeVariant(fieldName, value) {
|
|
|
44192
44221
|
}
|
|
44193
44222
|
return "default";
|
|
44194
44223
|
}
|
|
44195
|
-
function formatFieldValue2(value,
|
|
44224
|
+
function formatFieldValue2(value, fieldName2) {
|
|
44196
44225
|
if (typeof value === "number") {
|
|
44197
|
-
if (
|
|
44226
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
44198
44227
|
return `${value}%`;
|
|
44199
44228
|
}
|
|
44200
|
-
if (
|
|
44229
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
44201
44230
|
return `$${value.toLocaleString()}`;
|
|
44202
44231
|
}
|
|
44203
44232
|
return value.toLocaleString();
|
|
@@ -44207,7 +44236,7 @@ function formatFieldValue2(value, fieldName) {
|
|
|
44207
44236
|
}
|
|
44208
44237
|
return String(value);
|
|
44209
44238
|
}
|
|
44210
|
-
function renderRichFieldValue(value,
|
|
44239
|
+
function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
44211
44240
|
if (value === void 0 || value === null) return "\u2014";
|
|
44212
44241
|
const str = String(value);
|
|
44213
44242
|
switch (fieldType) {
|
|
@@ -44218,7 +44247,7 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
44218
44247
|
"img",
|
|
44219
44248
|
{
|
|
44220
44249
|
src: str,
|
|
44221
|
-
alt: formatFieldLabel(
|
|
44250
|
+
alt: formatFieldLabel(fieldName2),
|
|
44222
44251
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
44223
44252
|
loading: "lazy"
|
|
44224
44253
|
}
|
|
@@ -44353,9 +44382,9 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
44353
44382
|
return /* @__PURE__ */ jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
|
|
44354
44383
|
default:
|
|
44355
44384
|
if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
|
|
44356
|
-
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(
|
|
44385
|
+
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(fieldName2, str), children: humanizeEnumValue(str) });
|
|
44357
44386
|
}
|
|
44358
|
-
return formatFieldValue2(value,
|
|
44387
|
+
return formatFieldValue2(value, fieldName2);
|
|
44359
44388
|
}
|
|
44360
44389
|
}
|
|
44361
44390
|
function normalizeFieldDefs(fields) {
|
|
@@ -44825,16 +44854,11 @@ var init_DetailPanel = __esm({
|
|
|
44825
44854
|
footer
|
|
44826
44855
|
] })
|
|
44827
44856
|
] }) });
|
|
44828
|
-
|
|
44829
|
-
Box,
|
|
44830
|
-
|
|
44831
|
-
|
|
44832
|
-
|
|
44833
|
-
className
|
|
44834
|
-
),
|
|
44835
|
-
children: content
|
|
44836
|
-
}
|
|
44837
|
-
);
|
|
44857
|
+
if (!slideOver) {
|
|
44858
|
+
return /* @__PURE__ */ jsx(Box, { className, children: content });
|
|
44859
|
+
}
|
|
44860
|
+
const panel = /* @__PURE__ */ jsx(Box, { className: cn("fixed inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
|
|
44861
|
+
return typeof document === "undefined" ? panel : createPortal(panel, document.body);
|
|
44838
44862
|
};
|
|
44839
44863
|
DetailPanel.displayName = "DetailPanel";
|
|
44840
44864
|
}
|
|
@@ -45203,7 +45227,21 @@ var init_Form = __esm({
|
|
|
45203
45227
|
const normalizedInitialData = React94__default.useMemo(() => {
|
|
45204
45228
|
const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
|
|
45205
45229
|
const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
|
|
45206
|
-
|
|
45230
|
+
const merged = entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
|
|
45231
|
+
const toId = (value) => {
|
|
45232
|
+
if (value === null || value === void 0 || typeof value !== "object" || value instanceof Date) return value;
|
|
45233
|
+
if (Array.isArray(value)) {
|
|
45234
|
+
return value.map(
|
|
45235
|
+
(item) => item !== null && typeof item === "object" && !Array.isArray(item) && !(item instanceof Date) && item.id !== void 0 && item.id !== null ? String(item.id) : item
|
|
45236
|
+
);
|
|
45237
|
+
}
|
|
45238
|
+
return value.id !== void 0 && value.id !== null ? String(value.id) : value;
|
|
45239
|
+
};
|
|
45240
|
+
const normalized = {};
|
|
45241
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
45242
|
+
normalized[key] = key === "id" ? value : toId(value);
|
|
45243
|
+
}
|
|
45244
|
+
return normalized;
|
|
45207
45245
|
}, [entity, initialData]);
|
|
45208
45246
|
const entityDerivedFields = React94__default.useMemo(() => {
|
|
45209
45247
|
if (fields && fields.length > 0) return void 0;
|
|
@@ -45332,8 +45370,8 @@ var init_Form = __esm({
|
|
|
45332
45370
|
checkViolations(name, newFormData);
|
|
45333
45371
|
};
|
|
45334
45372
|
const isFieldVisible = React94__default.useCallback(
|
|
45335
|
-
(
|
|
45336
|
-
const condition = conditionalFields[
|
|
45373
|
+
(fieldName2) => {
|
|
45374
|
+
const condition = conditionalFields[fieldName2];
|
|
45337
45375
|
if (!condition) return true;
|
|
45338
45376
|
return Boolean(evaluateFormExpression(condition, evalContext));
|
|
45339
45377
|
},
|
|
@@ -45379,9 +45417,9 @@ var init_Form = __esm({
|
|
|
45379
45417
|
};
|
|
45380
45418
|
const handleInvalid = (e) => {
|
|
45381
45419
|
const target = e.target;
|
|
45382
|
-
const
|
|
45420
|
+
const fieldName2 = target.getAttribute("data-field-name") ?? target.name ?? "";
|
|
45383
45421
|
const fieldMessage = target.validationMessage || "Invalid value";
|
|
45384
|
-
debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
|
|
45422
|
+
debug("forms", "invalid", { mode: formMode, fieldName: fieldName2, fieldMessage });
|
|
45385
45423
|
queueMicrotask(() => {
|
|
45386
45424
|
const form = formRef.current;
|
|
45387
45425
|
if (!form) return;
|
|
@@ -45417,22 +45455,22 @@ var init_Form = __esm({
|
|
|
45417
45455
|
};
|
|
45418
45456
|
const renderField = React94__default.useCallback(
|
|
45419
45457
|
(field) => {
|
|
45420
|
-
const
|
|
45421
|
-
if (!
|
|
45422
|
-
if (!isFieldVisible(
|
|
45458
|
+
const fieldName2 = field.name || field.field;
|
|
45459
|
+
if (!fieldName2) return null;
|
|
45460
|
+
if (!isFieldVisible(fieldName2)) {
|
|
45423
45461
|
return null;
|
|
45424
45462
|
}
|
|
45425
45463
|
const inputType = determineInputType(field);
|
|
45426
|
-
const label = field.label ||
|
|
45427
|
-
const currentValue = formData[
|
|
45428
|
-
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", "data-field":
|
|
45464
|
+
const label = field.label || fieldName2.charAt(0).toUpperCase() + fieldName2.slice(1).replace(/([A-Z])/g, " $1");
|
|
45465
|
+
const currentValue = formData[fieldName2] ?? field.defaultValue ?? "";
|
|
45466
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", "data-field": fieldName2, children: [
|
|
45429
45467
|
inputType !== "checkbox" && /* @__PURE__ */ jsxs(Typography, { as: "label", variant: "label", weight: "bold", children: [
|
|
45430
45468
|
label,
|
|
45431
45469
|
field.required && /* @__PURE__ */ jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
|
|
45432
45470
|
] }),
|
|
45433
|
-
renderFieldInput(field,
|
|
45471
|
+
renderFieldInput(field, fieldName2, inputType, currentValue, label),
|
|
45434
45472
|
field.hint && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
|
|
45435
|
-
] },
|
|
45473
|
+
] }, fieldName2);
|
|
45436
45474
|
},
|
|
45437
45475
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
45438
45476
|
);
|
|
@@ -45461,8 +45499,8 @@ var init_Form = __esm({
|
|
|
45461
45499
|
}
|
|
45462
45500
|
return field;
|
|
45463
45501
|
}).map((field) => {
|
|
45464
|
-
const
|
|
45465
|
-
const override = fieldOverrides?.find((o) => o.name ===
|
|
45502
|
+
const fieldName2 = field.name || field.field;
|
|
45503
|
+
const override = fieldOverrides?.find((o) => o.name === fieldName2);
|
|
45466
45504
|
if (!override) return field;
|
|
45467
45505
|
return {
|
|
45468
45506
|
...field,
|
|
@@ -45518,11 +45556,11 @@ var init_Form = __esm({
|
|
|
45518
45556
|
] }, section.id);
|
|
45519
45557
|
}).filter(Boolean);
|
|
45520
45558
|
}, [sections, isSectionVisible, collapsedSections, renderField, gap]);
|
|
45521
|
-
function renderFieldInput(field,
|
|
45559
|
+
function renderFieldInput(field, fieldName2, inputType, currentValue, label) {
|
|
45522
45560
|
const commonProps = {
|
|
45523
|
-
id:
|
|
45524
|
-
name:
|
|
45525
|
-
"data-field-name":
|
|
45561
|
+
id: fieldName2,
|
|
45562
|
+
name: fieldName2,
|
|
45563
|
+
"data-field-name": fieldName2,
|
|
45526
45564
|
required: field.required,
|
|
45527
45565
|
disabled: isLoading,
|
|
45528
45566
|
placeholder: field.placeholder,
|
|
@@ -45536,7 +45574,7 @@ var init_Form = __esm({
|
|
|
45536
45574
|
...commonProps,
|
|
45537
45575
|
label: label + (field.required ? " *" : ""),
|
|
45538
45576
|
checked: Boolean(currentValue),
|
|
45539
|
-
onChange: (e) => handleChange(
|
|
45577
|
+
onChange: (e) => handleChange(fieldName2, e.target.checked)
|
|
45540
45578
|
}
|
|
45541
45579
|
);
|
|
45542
45580
|
case "textarea":
|
|
@@ -45545,7 +45583,7 @@ var init_Form = __esm({
|
|
|
45545
45583
|
{
|
|
45546
45584
|
...commonProps,
|
|
45547
45585
|
value: String(currentValue),
|
|
45548
|
-
onChange: (e) => handleChange(
|
|
45586
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45549
45587
|
minLength: field.min,
|
|
45550
45588
|
maxLength: field.max
|
|
45551
45589
|
}
|
|
@@ -45558,14 +45596,14 @@ var init_Form = __esm({
|
|
|
45558
45596
|
...commonProps,
|
|
45559
45597
|
options,
|
|
45560
45598
|
value: String(currentValue),
|
|
45561
|
-
onValueChange: (v) => handleChange(
|
|
45599
|
+
onValueChange: (v) => handleChange(fieldName2, v),
|
|
45562
45600
|
placeholder: field.placeholder || `Select ${label}...`
|
|
45563
45601
|
}
|
|
45564
45602
|
);
|
|
45565
45603
|
}
|
|
45566
45604
|
case "relation": {
|
|
45567
|
-
const relationOptions = relationsData[
|
|
45568
|
-
const relationLoading = relationsLoading[
|
|
45605
|
+
const relationOptions = relationsData[fieldName2] || [];
|
|
45606
|
+
const relationLoading = relationsLoading[fieldName2] || false;
|
|
45569
45607
|
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
45570
45608
|
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
45571
45609
|
return /* @__PURE__ */ jsx(
|
|
@@ -45577,7 +45615,7 @@ var init_Form = __esm({
|
|
|
45577
45615
|
clearable: true,
|
|
45578
45616
|
options: [...relationOptions],
|
|
45579
45617
|
value: selectedValues,
|
|
45580
|
-
onValueChange: (value) => handleChange(
|
|
45618
|
+
onValueChange: (value) => handleChange(fieldName2, Array.isArray(value) ? value : [value]),
|
|
45581
45619
|
placeholder: field.placeholder || `Select ${label}...`
|
|
45582
45620
|
}
|
|
45583
45621
|
);
|
|
@@ -45587,7 +45625,7 @@ var init_Form = __esm({
|
|
|
45587
45625
|
{
|
|
45588
45626
|
...commonProps,
|
|
45589
45627
|
value: currentValue ? String(currentValue) : void 0,
|
|
45590
|
-
onChange: (value) => handleChange(
|
|
45628
|
+
onChange: (value) => handleChange(fieldName2, value),
|
|
45591
45629
|
options: relationOptions,
|
|
45592
45630
|
isLoading: relationLoading,
|
|
45593
45631
|
placeholder: field.placeholder || `Select ${label}...`,
|
|
@@ -45604,7 +45642,7 @@ var init_Form = __esm({
|
|
|
45604
45642
|
placeholder: field.placeholder,
|
|
45605
45643
|
disabled: isLoading,
|
|
45606
45644
|
value: arrayValue,
|
|
45607
|
-
onChange: (next) => handleChange(
|
|
45645
|
+
onChange: (next) => handleChange(fieldName2, [...next])
|
|
45608
45646
|
}
|
|
45609
45647
|
);
|
|
45610
45648
|
}
|
|
@@ -45616,7 +45654,7 @@ var init_Form = __esm({
|
|
|
45616
45654
|
type: "number",
|
|
45617
45655
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
45618
45656
|
onChange: (e) => handleChange(
|
|
45619
|
-
|
|
45657
|
+
fieldName2,
|
|
45620
45658
|
e.target.value ? Number(e.target.value) : void 0
|
|
45621
45659
|
),
|
|
45622
45660
|
min: field.min,
|
|
@@ -45633,7 +45671,7 @@ var init_Form = __esm({
|
|
|
45633
45671
|
icon: DollarSign,
|
|
45634
45672
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
45635
45673
|
onChange: (e) => handleChange(
|
|
45636
|
-
|
|
45674
|
+
fieldName2,
|
|
45637
45675
|
e.target.value ? Number(e.target.value) : void 0
|
|
45638
45676
|
),
|
|
45639
45677
|
min: field.min,
|
|
@@ -45651,7 +45689,7 @@ var init_Form = __esm({
|
|
|
45651
45689
|
const f3 = files[0];
|
|
45652
45690
|
if (!f3) return;
|
|
45653
45691
|
const reader = new FileReader();
|
|
45654
|
-
reader.onload = () => handleChange(
|
|
45692
|
+
reader.onload = () => handleChange(fieldName2, {
|
|
45655
45693
|
name: f3.name,
|
|
45656
45694
|
mimeType: f3.type,
|
|
45657
45695
|
sizeBytes: f3.size,
|
|
@@ -45668,7 +45706,7 @@ var init_Form = __esm({
|
|
|
45668
45706
|
...commonProps,
|
|
45669
45707
|
type: "date",
|
|
45670
45708
|
value: formatDateValue(currentValue),
|
|
45671
|
-
onChange: (e) => handleChange(
|
|
45709
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45672
45710
|
}
|
|
45673
45711
|
);
|
|
45674
45712
|
case "datetime-local":
|
|
@@ -45678,7 +45716,7 @@ var init_Form = __esm({
|
|
|
45678
45716
|
...commonProps,
|
|
45679
45717
|
type: "datetime-local",
|
|
45680
45718
|
value: formatDateTimeValue(currentValue),
|
|
45681
|
-
onChange: (e) => handleChange(
|
|
45719
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45682
45720
|
}
|
|
45683
45721
|
);
|
|
45684
45722
|
case "email":
|
|
@@ -45688,7 +45726,7 @@ var init_Form = __esm({
|
|
|
45688
45726
|
...commonProps,
|
|
45689
45727
|
type: "email",
|
|
45690
45728
|
value: String(currentValue),
|
|
45691
|
-
onChange: (e) => handleChange(
|
|
45729
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45692
45730
|
minLength: field.min,
|
|
45693
45731
|
maxLength: field.max
|
|
45694
45732
|
}
|
|
@@ -45700,7 +45738,7 @@ var init_Form = __esm({
|
|
|
45700
45738
|
...commonProps,
|
|
45701
45739
|
type: "url",
|
|
45702
45740
|
value: String(currentValue),
|
|
45703
|
-
onChange: (e) => handleChange(
|
|
45741
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45704
45742
|
minLength: field.min,
|
|
45705
45743
|
maxLength: field.max
|
|
45706
45744
|
}
|
|
@@ -45712,7 +45750,7 @@ var init_Form = __esm({
|
|
|
45712
45750
|
...commonProps,
|
|
45713
45751
|
type: "password",
|
|
45714
45752
|
value: String(currentValue),
|
|
45715
|
-
onChange: (e) => handleChange(
|
|
45753
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45716
45754
|
minLength: field.min,
|
|
45717
45755
|
maxLength: field.max
|
|
45718
45756
|
}
|
|
@@ -45725,7 +45763,7 @@ var init_Form = __esm({
|
|
|
45725
45763
|
...commonProps,
|
|
45726
45764
|
type: "text",
|
|
45727
45765
|
value: String(currentValue),
|
|
45728
|
-
onChange: (e) => handleChange(
|
|
45766
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45729
45767
|
minLength: field.min,
|
|
45730
45768
|
maxLength: field.max
|
|
45731
45769
|
}
|
|
@@ -46082,7 +46120,7 @@ function entityFieldsFromListItem(item) {
|
|
|
46082
46120
|
}
|
|
46083
46121
|
return result;
|
|
46084
46122
|
}
|
|
46085
|
-
function getStatusStyle(
|
|
46123
|
+
function getStatusStyle(fieldName2, value) {
|
|
46086
46124
|
const val = String(value).toLowerCase();
|
|
46087
46125
|
if (val.includes("complete") || val.includes("done"))
|
|
46088
46126
|
return STATUS_STYLES.complete;
|
|
@@ -46098,12 +46136,12 @@ function getStatusStyle(fieldName, value) {
|
|
|
46098
46136
|
if (val.includes("low")) return STATUS_STYLES.low;
|
|
46099
46137
|
return STATUS_STYLES.default;
|
|
46100
46138
|
}
|
|
46101
|
-
function formatValue3(value,
|
|
46139
|
+
function formatValue3(value, fieldName2) {
|
|
46102
46140
|
if (typeof value === "number") {
|
|
46103
|
-
if (
|
|
46141
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
46104
46142
|
return `${value}%`;
|
|
46105
46143
|
}
|
|
46106
|
-
if (
|
|
46144
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
46107
46145
|
return new Intl.NumberFormat("en-US", {
|
|
46108
46146
|
style: "currency",
|
|
46109
46147
|
currency: "USD",
|
|
@@ -46126,8 +46164,8 @@ function formatValue3(value, fieldName) {
|
|
|
46126
46164
|
}
|
|
46127
46165
|
return String(value);
|
|
46128
46166
|
}
|
|
46129
|
-
function formatFieldLabel2(
|
|
46130
|
-
return humanizeFieldName(
|
|
46167
|
+
function formatFieldLabel2(fieldName2) {
|
|
46168
|
+
return humanizeFieldName(fieldName2).replace(/\sId$/, "").trim();
|
|
46131
46169
|
}
|
|
46132
46170
|
var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
|
|
46133
46171
|
var init_List = __esm({
|
|
@@ -46195,9 +46233,9 @@ var init_List = __esm({
|
|
|
46195
46233
|
};
|
|
46196
46234
|
StatusBadge = ({
|
|
46197
46235
|
value,
|
|
46198
|
-
fieldName
|
|
46236
|
+
fieldName: fieldName2
|
|
46199
46237
|
}) => {
|
|
46200
|
-
const style = getStatusStyle(
|
|
46238
|
+
const style = getStatusStyle(fieldName2, value);
|
|
46201
46239
|
return /* @__PURE__ */ jsxs(
|
|
46202
46240
|
Typography,
|
|
46203
46241
|
{
|
|
@@ -49129,8 +49167,8 @@ var init_StatCard = __esm({
|
|
|
49129
49167
|
return items.length;
|
|
49130
49168
|
}
|
|
49131
49169
|
if (field.includes(":")) {
|
|
49132
|
-
const [
|
|
49133
|
-
return items.filter((item) => item[
|
|
49170
|
+
const [fieldName2, fieldValue] = field.split(":");
|
|
49171
|
+
return items.filter((item) => item[fieldName2] === fieldValue).length;
|
|
49134
49172
|
}
|
|
49135
49173
|
const fieldExistsOnItems = items.some((item) => field in item);
|
|
49136
49174
|
if (fieldExistsOnItems) {
|
|
@@ -50650,6 +50688,8 @@ var init_component_registry_generated = __esm({
|
|
|
50650
50688
|
init_DocSearch();
|
|
50651
50689
|
init_DocSidebar();
|
|
50652
50690
|
init_DocTOC();
|
|
50691
|
+
init_DocumentDetails();
|
|
50692
|
+
init_DocumentPanel();
|
|
50653
50693
|
init_DocumentViewer();
|
|
50654
50694
|
init_DrawFxLayer();
|
|
50655
50695
|
init_DrawGroup();
|
|
@@ -50759,7 +50799,7 @@ var init_component_registry_generated = __esm({
|
|
|
50759
50799
|
init_RelationSelect();
|
|
50760
50800
|
init_RepeatableFormSection();
|
|
50761
50801
|
init_ReplyTree();
|
|
50762
|
-
|
|
50802
|
+
init_RichTextEditor();
|
|
50763
50803
|
init_RuntimeDebugger2();
|
|
50764
50804
|
init_ScaledDiagram();
|
|
50765
50805
|
init_ScoreDisplay();
|
|
@@ -50922,6 +50962,8 @@ var init_component_registry_generated = __esm({
|
|
|
50922
50962
|
"DocSearch": DocSearch,
|
|
50923
50963
|
"DocSidebar": DocSidebar,
|
|
50924
50964
|
"DocTOC": DocTOC,
|
|
50965
|
+
"DocumentDetails": DocumentDetails,
|
|
50966
|
+
"DocumentPanel": DocumentPanel,
|
|
50925
50967
|
"DocumentViewer": DocumentViewer,
|
|
50926
50968
|
"DrawFxLayer": DrawFxLayer,
|
|
50927
50969
|
"DrawGroup": DrawGroup,
|
|
@@ -51033,7 +51075,7 @@ var init_component_registry_generated = __esm({
|
|
|
51033
51075
|
"RelationSelect": RelationSelect,
|
|
51034
51076
|
"RepeatableFormSection": RepeatableFormSection,
|
|
51035
51077
|
"ReplyTree": ReplyTree,
|
|
51036
|
-
"
|
|
51078
|
+
"RichTextEditor": RichTextEditor,
|
|
51037
51079
|
"RuntimeDebugger": RuntimeDebugger,
|
|
51038
51080
|
"ScaledDiagram": ScaledDiagram,
|
|
51039
51081
|
"ScoreDisplay": ScoreDisplay,
|
|
@@ -51187,10 +51229,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
51187
51229
|
}
|
|
51188
51230
|
if (field && typeof field === "object" && !Array.isArray(field) && !React94__default.isValidElement(field) && !(field instanceof Date)) {
|
|
51189
51231
|
const obj = field;
|
|
51190
|
-
const
|
|
51191
|
-
if (!
|
|
51232
|
+
const fieldName2 = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
|
|
51233
|
+
if (!fieldName2) return field;
|
|
51192
51234
|
if (obj.type || obj.inputType) return field;
|
|
51193
|
-
const entityField = fieldMap.get(
|
|
51235
|
+
const entityField = fieldMap.get(fieldName2);
|
|
51194
51236
|
if (!entityField) return field;
|
|
51195
51237
|
const enriched = { ...obj, type: entityField.type };
|
|
51196
51238
|
if (entityField.required && !("required" in obj)) {
|
|
@@ -51240,9 +51282,9 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
51240
51282
|
}
|
|
51241
51283
|
if (field && typeof field === "object" && !Array.isArray(field) && !React94__default.isValidElement(field) && !(field instanceof Date)) {
|
|
51242
51284
|
const obj = field;
|
|
51243
|
-
const
|
|
51244
|
-
if (!
|
|
51245
|
-
const meta = metaFor(
|
|
51285
|
+
const fieldName2 = typeof obj.key === "string" ? obj.key : typeof obj.name === "string" ? obj.name : void 0;
|
|
51286
|
+
if (!fieldName2 || obj.type) return field;
|
|
51287
|
+
const meta = metaFor(fieldName2);
|
|
51246
51288
|
return meta ? { ...obj, ...meta } : field;
|
|
51247
51289
|
}
|
|
51248
51290
|
return field;
|
|
@@ -52081,9 +52123,9 @@ function UISlotRenderer({
|
|
|
52081
52123
|
"ui-slot-renderer relative min-h-full",
|
|
52082
52124
|
className
|
|
52083
52125
|
), children: [
|
|
52084
|
-
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full", children: [
|
|
52085
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 shrink-0" }),
|
|
52086
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-h-[200px]" })
|
|
52126
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full flex-col lg:flex-row", children: [
|
|
52127
|
+
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 lg:shrink-0" }),
|
|
52128
|
+
/* @__PURE__ */ jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-w-0 min-h-[200px]" })
|
|
52087
52129
|
] }),
|
|
52088
52130
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "modal", portal: true }),
|
|
52089
52131
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "drawer", portal: true }),
|
|
@@ -55980,7 +56022,7 @@ function buildTraitRenderConfig(binding, traitConfigsByName, payload) {
|
|
|
55980
56022
|
}
|
|
55981
56023
|
return void 0;
|
|
55982
56024
|
}
|
|
55983
|
-
function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
|
|
56025
|
+
function createSharedEntityWriter(binding, tick, traitStatesRef, emit, traitConfigsByName) {
|
|
55984
56026
|
return (scratch) => {
|
|
55985
56027
|
const traitName = binding.trait.name;
|
|
55986
56028
|
const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
|
|
@@ -55989,9 +56031,13 @@ function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
|
|
|
55989
56031
|
const writes = [];
|
|
55990
56032
|
const ctx = createMinimalContext(scratchEntity, {}, currentState);
|
|
55991
56033
|
const declaredDefaults = collectDeclaredConfigDefaults(binding.trait);
|
|
55992
|
-
const
|
|
55993
|
-
|
|
55994
|
-
|
|
56034
|
+
const resolvedByName = traitConfigsByName?.[traitName];
|
|
56035
|
+
const callSiteRaw = getBindingConfig(binding);
|
|
56036
|
+
const callSiteConfig = callSiteRaw ? Object.fromEntries(
|
|
56037
|
+
Object.entries(callSiteRaw).filter(([, v]) => !containsConfigForward(v))
|
|
56038
|
+
) : void 0;
|
|
56039
|
+
if (declaredDefaults || resolvedByName || callSiteConfig) {
|
|
56040
|
+
ctx.config = { ...declaredDefaults ?? {}, ...resolvedByName ?? {}, ...callSiteConfig ?? {} };
|
|
55995
56041
|
}
|
|
55996
56042
|
ctx.mutateEntity = (changes) => {
|
|
55997
56043
|
for (const [field, value] of Object.entries(changes)) {
|
|
@@ -56594,7 +56640,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56594
56640
|
const interval = entries[0].tick.interval;
|
|
56595
56641
|
const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
|
|
56596
56642
|
const writers = entries.map(
|
|
56597
|
-
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
|
|
56643
|
+
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter, traitConfigsByName)
|
|
56598
56644
|
);
|
|
56599
56645
|
runTickFrame(group.storeKey, writers, sharedEntityStore);
|
|
56600
56646
|
});
|
|
@@ -59107,11 +59153,11 @@ function OrbInspector({ node, schema, editable = false, userType = "builder", th
|
|
|
59107
59153
|
const handleAddField = useCallback(() => {
|
|
59108
59154
|
eventBus.emit("UI:ADD_FIELD", {});
|
|
59109
59155
|
}, [eventBus]);
|
|
59110
|
-
const handleUpdateField = useCallback((
|
|
59111
|
-
eventBus.emit("UI:UPDATE_FIELD", { fieldName, updates });
|
|
59156
|
+
const handleUpdateField = useCallback((fieldName2, updates) => {
|
|
59157
|
+
eventBus.emit("UI:UPDATE_FIELD", { fieldName: fieldName2, updates });
|
|
59112
59158
|
}, [eventBus]);
|
|
59113
|
-
const handleRemoveField = useCallback((
|
|
59114
|
-
eventBus.emit("UI:REMOVE_FIELD", { fieldName });
|
|
59159
|
+
const handleRemoveField = useCallback((fieldName2) => {
|
|
59160
|
+
eventBus.emit("UI:REMOVE_FIELD", { fieldName: fieldName2 });
|
|
59115
59161
|
}, [eventBus]);
|
|
59116
59162
|
const handleGuardChange = useCallback((guardExpr) => {
|
|
59117
59163
|
if (!editable) return;
|