@almadar/ui 5.160.0 → 5.161.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +924 -891
- package/dist/avl/index.js +914 -881
- package/dist/components/index.cjs +944 -934
- package/dist/components/index.d.cts +156 -31
- package/dist/components/index.d.ts +156 -31
- package/dist/components/index.js +931 -924
- package/dist/hooks/index.cjs +25 -49
- package/dist/hooks/index.js +25 -49
- package/dist/locales/index.cjs +75 -147
- package/dist/locales/index.js +75 -147
- package/dist/providers/index.cjs +911 -882
- package/dist/providers/index.js +901 -872
- package/dist/runtime/index.cjs +920 -887
- package/dist/runtime/index.js +910 -877
- package/locales/ar.json +25 -49
- package/locales/en.json +25 -49
- package/locales/sl.json +25 -49
- package/package.json +5 -5
package/dist/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: [
|
|
@@ -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,7 +29213,7 @@ 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
|
{
|
|
@@ -34512,7 +34489,7 @@ var init_MapView = __esm({
|
|
|
34512
34489
|
shadowSize: [41, 41]
|
|
34513
34490
|
});
|
|
34514
34491
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
34515
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback96, useState:
|
|
34492
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback96, useState: useState102 } = React94__default;
|
|
34516
34493
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
34517
34494
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
34518
34495
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -34557,7 +34534,7 @@ var init_MapView = __esm({
|
|
|
34557
34534
|
showAttribution = true
|
|
34558
34535
|
}) {
|
|
34559
34536
|
const eventBus = useEventBus2();
|
|
34560
|
-
const [clickedPosition, setClickedPosition] =
|
|
34537
|
+
const [clickedPosition, setClickedPosition] = useState102(null);
|
|
34561
34538
|
const handleMapClick = useCallback96((lat, lng) => {
|
|
34562
34539
|
if (showClickedPin) {
|
|
34563
34540
|
setClickedPosition({ lat, lng });
|
|
@@ -38919,741 +38896,775 @@ var init_PositionedCanvas = __esm({
|
|
|
38919
38896
|
PositionedCanvas.displayName = "PositionedCanvas";
|
|
38920
38897
|
}
|
|
38921
38898
|
});
|
|
38922
|
-
function
|
|
38923
|
-
|
|
38924
|
-
|
|
38925
|
-
|
|
38926
|
-
|
|
38927
|
-
|
|
38928
|
-
if (!Array.isArray(raw) || raw.length === 0) return [createBlock("paragraph")];
|
|
38929
|
-
return raw.map((row) => {
|
|
38930
|
-
const entity = row;
|
|
38931
|
-
const rawType = entity.type;
|
|
38932
|
-
const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
|
|
38933
|
-
const id = typeof entity.id === "string" && entity.id ? entity.id : nextBlockId(type);
|
|
38934
|
-
return { ...entity, id, type };
|
|
38935
|
-
});
|
|
38936
|
-
}
|
|
38937
|
-
function createBlock(type) {
|
|
38938
|
-
switch (type) {
|
|
38939
|
-
case "bullet-list":
|
|
38940
|
-
case "numbered-list":
|
|
38941
|
-
return {
|
|
38942
|
-
id: nextBlockId(type),
|
|
38943
|
-
type,
|
|
38944
|
-
children: [
|
|
38945
|
-
{ id: nextBlockId("li"), type: "paragraph", content: "" }
|
|
38946
|
-
]
|
|
38947
|
-
};
|
|
38948
|
-
case "image":
|
|
38949
|
-
return {
|
|
38950
|
-
id: nextBlockId(type),
|
|
38951
|
-
type,
|
|
38952
|
-
content: "",
|
|
38953
|
-
metadata: { url: "", caption: "" }
|
|
38954
|
-
};
|
|
38955
|
-
case "code":
|
|
38956
|
-
return {
|
|
38957
|
-
id: nextBlockId(type),
|
|
38958
|
-
type,
|
|
38959
|
-
content: "",
|
|
38960
|
-
metadata: { language: "plaintext" }
|
|
38961
|
-
};
|
|
38962
|
-
case "divider":
|
|
38963
|
-
return { id: nextBlockId(type), type };
|
|
38964
|
-
default:
|
|
38965
|
-
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;
|
|
38966
38905
|
}
|
|
38906
|
+
return null;
|
|
38967
38907
|
}
|
|
38968
|
-
function
|
|
38969
|
-
|
|
38970
|
-
|
|
38971
|
-
|
|
38972
|
-
|
|
38973
|
-
|
|
38974
|
-
|
|
38975
|
-
return {
|
|
38976
|
-
...block,
|
|
38977
|
-
id: nextBlockId(block.type),
|
|
38978
|
-
children: block.children?.map((child) => ({
|
|
38979
|
-
...child,
|
|
38980
|
-
id: nextBlockId("li")
|
|
38981
|
-
})),
|
|
38982
|
-
metadata: block.metadata ? { ...block.metadata } : void 0
|
|
38983
|
-
};
|
|
38984
|
-
}
|
|
38985
|
-
function insertAfter(blocks, targetId, inserted) {
|
|
38986
|
-
const idx = blocks.findIndex((b) => b.id === targetId);
|
|
38987
|
-
if (idx === -1) return [...blocks, inserted];
|
|
38988
|
-
const next = blocks.slice();
|
|
38989
|
-
next.splice(idx + 1, 0, inserted);
|
|
38990
|
-
return next;
|
|
38991
|
-
}
|
|
38992
|
-
function changeBlockType(block, type) {
|
|
38993
|
-
if (block.type === type) return block;
|
|
38994
|
-
if (type === "bullet-list" || type === "numbered-list") {
|
|
38995
|
-
if (block.children && block.children.length > 0) {
|
|
38996
|
-
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;
|
|
38997
38915
|
}
|
|
38998
|
-
const
|
|
38999
|
-
|
|
39000
|
-
|
|
39001
|
-
|
|
39002
|
-
|
|
39003
|
-
|
|
39004
|
-
|
|
39005
|
-
|
|
39006
|
-
|
|
39007
|
-
|
|
39008
|
-
|
|
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);
|
|
39009
38940
|
}
|
|
39010
|
-
|
|
39011
|
-
|
|
39012
|
-
|
|
39013
|
-
|
|
39014
|
-
|
|
39015
|
-
|
|
39016
|
-
|
|
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 "";
|
|
39017
38949
|
}
|
|
39018
|
-
|
|
39019
|
-
|
|
39020
|
-
|
|
39021
|
-
|
|
39022
|
-
|
|
39023
|
-
|
|
39024
|
-
|
|
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;
|
|
39025
38961
|
}
|
|
39026
|
-
|
|
39027
|
-
return { id: block.id, type, content: seed };
|
|
38962
|
+
return null;
|
|
39028
38963
|
}
|
|
39029
|
-
function
|
|
39030
|
-
|
|
39031
|
-
|
|
39032
|
-
|
|
39033
|
-
|
|
39034
|
-
|
|
39035
|
-
|
|
39036
|
-
|
|
39037
|
-
|
|
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;
|
|
39038
38980
|
}
|
|
38981
|
+
if (tag === "a") link = true;
|
|
39039
38982
|
}
|
|
39040
|
-
|
|
39041
|
-
|
|
39042
|
-
|
|
39043
|
-
|
|
39044
|
-
|
|
39045
|
-
|
|
39046
|
-
|
|
39047
|
-
|
|
39048
|
-
|
|
39049
|
-
|
|
39050
|
-
|
|
39051
|
-
|
|
39052
|
-
"inline-flex items-center justify-center",
|
|
39053
|
-
"h-6 w-6 rounded-sm p-0 gap-0",
|
|
39054
|
-
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
39055
|
-
"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",
|
|
39056
|
-
"transition-opacity"
|
|
39057
|
-
),
|
|
39058
|
-
onClick: () => setOpen((v) => !v),
|
|
39059
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", className: "w-3.5 h-3.5" })
|
|
39060
|
-
}
|
|
39061
|
-
),
|
|
39062
|
-
open && /* @__PURE__ */ jsxs(
|
|
39063
|
-
Box,
|
|
39064
|
-
{
|
|
39065
|
-
role: "menu",
|
|
39066
|
-
className: cn(
|
|
39067
|
-
"absolute right-0 z-10 mt-1 w-44",
|
|
39068
|
-
"rounded-container border border-border bg-popover shadow-elevation-popover",
|
|
39069
|
-
"py-1 text-sm"
|
|
39070
|
-
),
|
|
39071
|
-
children: [
|
|
39072
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t(BLOCK_TYPE_LABEL_KEY[block.type]) }),
|
|
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 justify-start rounded-none",
|
|
39080
|
-
onClick: () => {
|
|
39081
|
-
onDuplicate();
|
|
39082
|
-
setOpen(false);
|
|
39083
|
-
},
|
|
39084
|
-
children: [
|
|
39085
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3.5 h-3.5" }),
|
|
39086
|
-
" ",
|
|
39087
|
-
t("richBlockEditor.duplicate")
|
|
39088
|
-
]
|
|
39089
|
-
}
|
|
39090
|
-
),
|
|
39091
|
-
/* @__PURE__ */ jsxs(
|
|
39092
|
-
Button,
|
|
39093
|
-
{
|
|
39094
|
-
type: "button",
|
|
39095
|
-
variant: "ghost",
|
|
39096
|
-
role: "menuitem",
|
|
39097
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-destructive hover:bg-muted justify-start rounded-none",
|
|
39098
|
-
onClick: () => {
|
|
39099
|
-
onDelete();
|
|
39100
|
-
setOpen(false);
|
|
39101
|
-
},
|
|
39102
|
-
children: [
|
|
39103
|
-
/* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3.5 h-3.5" }),
|
|
39104
|
-
" ",
|
|
39105
|
-
t("common.delete")
|
|
39106
|
-
]
|
|
39107
|
-
}
|
|
39108
|
-
),
|
|
39109
|
-
CHANGEABLE_TYPES.includes(block.type) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39110
|
-
/* @__PURE__ */ jsx(Box, { className: "my-1 border-t border-border" }),
|
|
39111
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t("richBlockEditor.turnInto") }),
|
|
39112
|
-
CHANGEABLE_TYPES.filter((bt) => bt !== block.type).map((bt) => /* @__PURE__ */ jsx(
|
|
39113
|
-
Button,
|
|
39114
|
-
{
|
|
39115
|
-
type: "button",
|
|
39116
|
-
variant: "ghost",
|
|
39117
|
-
role: "menuitem",
|
|
39118
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
39119
|
-
onClick: () => {
|
|
39120
|
-
onChangeType(bt);
|
|
39121
|
-
setOpen(false);
|
|
39122
|
-
},
|
|
39123
|
-
children: t(BLOCK_TYPE_LABEL_KEY[bt])
|
|
39124
|
-
},
|
|
39125
|
-
bt
|
|
39126
|
-
))
|
|
39127
|
-
] })
|
|
39128
|
-
]
|
|
39129
|
-
}
|
|
39130
|
-
)
|
|
39131
|
-
] });
|
|
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
|
+
};
|
|
39132
38995
|
}
|
|
39133
|
-
function
|
|
39134
|
-
tag,
|
|
39135
|
-
value,
|
|
39136
|
-
readOnly,
|
|
39137
|
-
placeholder,
|
|
39138
|
-
className,
|
|
39139
|
-
ariaLabel,
|
|
39140
|
-
onValueChange
|
|
39141
|
-
}) {
|
|
39142
|
-
const ref = useRef(null);
|
|
39143
|
-
useEffect(() => {
|
|
39144
|
-
const el = ref.current;
|
|
39145
|
-
if (!el) return;
|
|
39146
|
-
const isFocused = document.activeElement === el;
|
|
39147
|
-
if (!isFocused && el.textContent !== value) {
|
|
39148
|
-
el.textContent = value;
|
|
39149
|
-
}
|
|
39150
|
-
}, [value]);
|
|
39151
|
-
const handleInput = useCallback(
|
|
39152
|
-
(e) => {
|
|
39153
|
-
onValueChange(e.currentTarget.textContent ?? "");
|
|
39154
|
-
},
|
|
39155
|
-
[onValueChange]
|
|
39156
|
-
);
|
|
38996
|
+
function ToolbarButton({ icon: IconCmp, label, active, onExec }) {
|
|
39157
38997
|
return /* @__PURE__ */ jsx(
|
|
39158
|
-
|
|
38998
|
+
Button,
|
|
39159
38999
|
{
|
|
39160
|
-
|
|
39161
|
-
|
|
39162
|
-
|
|
39163
|
-
|
|
39164
|
-
|
|
39165
|
-
|
|
39166
|
-
"aria-multiline": "true",
|
|
39167
|
-
"data-placeholder": placeholder,
|
|
39000
|
+
type: "button",
|
|
39001
|
+
variant: "ghost",
|
|
39002
|
+
size: "sm",
|
|
39003
|
+
"aria-label": label,
|
|
39004
|
+
"aria-pressed": active,
|
|
39005
|
+
title: label,
|
|
39168
39006
|
className: cn(
|
|
39169
|
-
"
|
|
39170
|
-
"
|
|
39171
|
-
className
|
|
39007
|
+
"h-8 w-8 p-0 gap-0 justify-center",
|
|
39008
|
+
active && "bg-muted text-foreground"
|
|
39172
39009
|
),
|
|
39173
|
-
|
|
39010
|
+
onMouseDown: (e) => {
|
|
39011
|
+
e.preventDefault();
|
|
39012
|
+
onExec();
|
|
39013
|
+
},
|
|
39014
|
+
children: /* @__PURE__ */ jsx(IconCmp, { size: 15 })
|
|
39174
39015
|
}
|
|
39175
39016
|
);
|
|
39176
39017
|
}
|
|
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
|
-
|
|
39305
|
-
|
|
39306
|
-
|
|
39307
|
-
|
|
39308
|
-
|
|
39309
|
-
|
|
39310
|
-
|
|
39311
|
-
|
|
39312
|
-
|
|
39313
|
-
|
|
39314
|
-
|
|
39315
|
-
|
|
39316
|
-
|
|
39317
|
-
|
|
39318
|
-
|
|
39319
|
-
|
|
39320
|
-
|
|
39321
|
-
|
|
39322
|
-
|
|
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));
|
|
39323
39168
|
};
|
|
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
|
-
|
|
39353
|
-
|
|
39354
|
-
|
|
39355
|
-
|
|
39356
|
-
|
|
39357
|
-
|
|
39358
|
-
|
|
39359
|
-
|
|
39360
|
-
|
|
39361
|
-
|
|
39362
|
-
|
|
39363
|
-
|
|
39364
|
-
|
|
39365
|
-
|
|
39366
|
-
|
|
39367
|
-
|
|
39368
|
-
|
|
39369
|
-
|
|
39370
|
-
|
|
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 ?? "") } })
|
|
39371
39296
|
] });
|
|
39372
39297
|
}
|
|
39373
|
-
|
|
39374
|
-
|
|
39375
|
-
|
|
39376
|
-
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(
|
|
39377
39301
|
Box,
|
|
39378
39302
|
{
|
|
39379
|
-
|
|
39303
|
+
role: "toolbar",
|
|
39304
|
+
"aria-label": t("richTextEditor.editorToolbar"),
|
|
39380
39305
|
className: cn(
|
|
39381
|
-
"
|
|
39382
|
-
|
|
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"
|
|
39383
39308
|
),
|
|
39384
39309
|
children: [
|
|
39385
|
-
|
|
39386
|
-
|
|
39387
|
-
|
|
39388
|
-
|
|
39389
|
-
|
|
39390
|
-
|
|
39391
|
-
|
|
39392
|
-
|
|
39393
|
-
|
|
39394
|
-
|
|
39395
|
-
|
|
39396
|
-
|
|
39397
|
-
|
|
39398
|
-
|
|
39399
|
-
|
|
39400
|
-
|
|
39401
|
-
type: "button",
|
|
39402
|
-
variant: "ghost",
|
|
39403
|
-
"aria-label": t("richBlockEditor.aria.removeListItem"),
|
|
39404
|
-
className: cn(
|
|
39405
|
-
"h-5 w-5 shrink-0 rounded-sm text-muted-foreground p-0 gap-0",
|
|
39406
|
-
"opacity-0 group-hover/item:opacity-100 hover:bg-muted hover:text-foreground"
|
|
39407
|
-
),
|
|
39408
|
-
onClick: () => removeListItem(child.id),
|
|
39409
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3 h-3" })
|
|
39410
|
-
}
|
|
39411
|
-
)
|
|
39412
|
-
] }, child.id)),
|
|
39413
|
-
!readOnly && showAffordances && /* @__PURE__ */ jsx(Box, { as: "li", className: "list-none pl-0", children: /* @__PURE__ */ jsxs(
|
|
39414
|
-
Button,
|
|
39415
|
-
{
|
|
39416
|
-
type: "button",
|
|
39417
|
-
variant: "ghost",
|
|
39418
|
-
className: cn(
|
|
39419
|
-
"inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
39420
|
-
"hover:text-foreground p-0 h-auto"
|
|
39421
|
-
),
|
|
39422
|
-
onClick: addListItem,
|
|
39423
|
-
children: [
|
|
39424
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3 h-3" }),
|
|
39425
|
-
" ",
|
|
39426
|
-
t("richBlockEditor.addItem")
|
|
39427
|
-
]
|
|
39428
|
-
}
|
|
39429
|
-
) })
|
|
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 })
|
|
39430
39326
|
]
|
|
39431
39327
|
}
|
|
39432
|
-
)
|
|
39433
|
-
|
|
39434
|
-
|
|
39435
|
-
default:
|
|
39436
|
-
return /* @__PURE__ */ jsx(
|
|
39437
|
-
Editable,
|
|
39328
|
+
),
|
|
39329
|
+
/* @__PURE__ */ jsx(
|
|
39330
|
+
Box,
|
|
39438
39331
|
{
|
|
39439
|
-
|
|
39440
|
-
|
|
39441
|
-
|
|
39442
|
-
|
|
39443
|
-
|
|
39444
|
-
|
|
39445
|
-
|
|
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
|
|
39446
39351
|
}
|
|
39447
|
-
)
|
|
39448
|
-
|
|
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 });
|
|
39449
39390
|
};
|
|
39450
|
-
|
|
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(
|
|
39451
39421
|
Box,
|
|
39452
39422
|
{
|
|
39453
|
-
|
|
39454
|
-
|
|
39455
|
-
|
|
39456
|
-
),
|
|
39457
|
-
|
|
39458
|
-
|
|
39459
|
-
|
|
39460
|
-
|
|
39461
|
-
|
|
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,
|
|
39462
39456
|
{
|
|
39463
|
-
|
|
39464
|
-
|
|
39465
|
-
|
|
39466
|
-
|
|
39467
|
-
|
|
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
|
+
}))
|
|
39468
39479
|
}
|
|
39469
|
-
)
|
|
39470
|
-
|
|
39471
|
-
|
|
39472
|
-
}
|
|
39473
|
-
|
|
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
|
+
] }) });
|
|
39474
39496
|
}
|
|
39475
|
-
var
|
|
39476
|
-
|
|
39477
|
-
"components/core/molecules/RichBlockEditor.tsx"() {
|
|
39497
|
+
var init_DocumentPanel = __esm({
|
|
39498
|
+
"components/core/molecules/DocumentPanel.tsx"() {
|
|
39478
39499
|
"use client";
|
|
39479
39500
|
init_cn();
|
|
39480
|
-
|
|
39501
|
+
init_useEventBus();
|
|
39502
|
+
init_Box();
|
|
39503
|
+
init_Stack();
|
|
39481
39504
|
init_Typography();
|
|
39482
39505
|
init_Button();
|
|
39483
|
-
|
|
39484
|
-
init_Divider();
|
|
39485
|
-
init_Input();
|
|
39506
|
+
init_Card();
|
|
39486
39507
|
init_Icon();
|
|
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
|
-
|
|
39529
|
-
|
|
39530
|
-
|
|
39531
|
-
|
|
39532
|
-
|
|
39533
|
-
|
|
39534
|
-
|
|
39535
|
-
|
|
39536
|
-
|
|
39537
|
-
|
|
39538
|
-
|
|
39539
|
-
|
|
39540
|
-
|
|
39541
|
-
|
|
39542
|
-
|
|
39543
|
-
|
|
39544
|
-
|
|
39545
|
-
|
|
39546
|
-
const [blocks, setBlocks] = useState(
|
|
39547
|
-
() => normalizeBlocks(initialBlocks)
|
|
39548
|
-
);
|
|
39549
|
-
const onChangeRef = useRef(onChange);
|
|
39550
|
-
useEffect(() => {
|
|
39551
|
-
onChangeRef.current = onChange;
|
|
39552
|
-
}, [onChange]);
|
|
39553
|
-
const eventBus = useEventBus();
|
|
39554
|
-
const changeEventRef = useRef(changeEvent);
|
|
39555
|
-
useEffect(() => {
|
|
39556
|
-
changeEventRef.current = changeEvent;
|
|
39557
|
-
}, [changeEvent]);
|
|
39558
|
-
const commit = useCallback((next) => {
|
|
39559
|
-
setBlocks(next);
|
|
39560
|
-
onChangeRef.current?.(next);
|
|
39561
|
-
const evt = changeEventRef.current;
|
|
39562
|
-
if (evt) eventBus.emit(`UI:${evt}`, { blocks: next });
|
|
39563
|
-
}, [eventBus]);
|
|
39564
|
-
const handleAppend = useCallback(
|
|
39565
|
-
(type) => {
|
|
39566
|
-
if (readOnly) return;
|
|
39567
|
-
commit([...blocks, createBlock(type)]);
|
|
39568
|
-
},
|
|
39569
|
-
[blocks, commit, readOnly]
|
|
39570
|
-
);
|
|
39571
|
-
const handleUpdate = useCallback(
|
|
39572
|
-
(id, updater) => {
|
|
39573
|
-
commit(replaceBlock(blocks, id, updater));
|
|
39574
|
-
},
|
|
39575
|
-
[blocks, commit]
|
|
39576
|
-
);
|
|
39577
|
-
const handleDelete = useCallback(
|
|
39578
|
-
(id) => {
|
|
39579
|
-
const next = removeBlock(blocks, id);
|
|
39580
|
-
commit(next.length > 0 ? next : [createBlock("paragraph")]);
|
|
39581
|
-
},
|
|
39582
|
-
[blocks, commit]
|
|
39583
|
-
);
|
|
39584
|
-
const handleDuplicate = useCallback(
|
|
39585
|
-
(id) => {
|
|
39586
|
-
const target = blocks.find((b) => b.id === id);
|
|
39587
|
-
if (!target) return;
|
|
39588
|
-
commit(insertAfter(blocks, id, duplicateBlock(target)));
|
|
39589
|
-
},
|
|
39590
|
-
[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
|
+
}
|
|
39591
39567
|
);
|
|
39592
|
-
|
|
39593
|
-
|
|
39594
|
-
|
|
39595
|
-
|
|
39596
|
-
|
|
39597
|
-
|
|
39598
|
-
|
|
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
|
+
}
|
|
39599
39580
|
);
|
|
39600
|
-
|
|
39601
|
-
|
|
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,
|
|
39602
39595
|
{
|
|
39603
|
-
|
|
39604
|
-
|
|
39605
|
-
|
|
39606
|
-
|
|
39607
|
-
|
|
39608
|
-
|
|
39609
|
-
|
|
39610
|
-
|
|
39611
|
-
|
|
39612
|
-
|
|
39613
|
-
|
|
39614
|
-
|
|
39615
|
-
|
|
39616
|
-
|
|
39617
|
-
|
|
39618
|
-
|
|
39619
|
-
return /* @__PURE__ */ jsxs(
|
|
39620
|
-
Button,
|
|
39621
|
-
{
|
|
39622
|
-
type: "button",
|
|
39623
|
-
variant: "ghost",
|
|
39624
|
-
size: "sm",
|
|
39625
|
-
"aria-label": t("richBlockEditor.insertEntry", { label: entryLabel }),
|
|
39626
|
-
title: entryLabel,
|
|
39627
|
-
onClick: () => handleAppend(entry.type),
|
|
39628
|
-
children: [
|
|
39629
|
-
/* @__PURE__ */ jsx(Icon2, { size: 14 }),
|
|
39630
|
-
/* @__PURE__ */ jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
|
|
39631
|
-
]
|
|
39632
|
-
},
|
|
39633
|
-
entry.type
|
|
39634
|
-
);
|
|
39635
|
-
})
|
|
39636
|
-
}
|
|
39637
|
-
),
|
|
39638
|
-
/* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-1 px-3 py-3", children: blocks.map((block) => /* @__PURE__ */ jsx(
|
|
39639
|
-
BlockRow,
|
|
39640
|
-
{
|
|
39641
|
-
block,
|
|
39642
|
-
readOnly,
|
|
39643
|
-
showAffordances: enableBlocks,
|
|
39644
|
-
placeholder,
|
|
39645
|
-
onUpdate: (updater) => handleUpdate(block.id, updater),
|
|
39646
|
-
onDelete: () => handleDelete(block.id),
|
|
39647
|
-
onDuplicate: () => handleDuplicate(block.id),
|
|
39648
|
-
onChangeType: (type) => handleChangeType(block.id, type)
|
|
39649
|
-
},
|
|
39650
|
-
block.id
|
|
39651
|
-
)) })
|
|
39652
|
-
]
|
|
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}`
|
|
39653
39612
|
}
|
|
39654
39613
|
);
|
|
39655
|
-
}
|
|
39656
|
-
|
|
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();
|
|
39657
39668
|
}
|
|
39658
39669
|
});
|
|
39659
39670
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
@@ -44193,8 +44204,8 @@ var init_DataTable = __esm({
|
|
|
44193
44204
|
DataTable.displayName = "DataTable";
|
|
44194
44205
|
}
|
|
44195
44206
|
});
|
|
44196
|
-
function getBadgeVariant(
|
|
44197
|
-
const name =
|
|
44207
|
+
function getBadgeVariant(fieldName2, value) {
|
|
44208
|
+
const name = fieldName2.toLowerCase();
|
|
44198
44209
|
const val = String(value).toLowerCase();
|
|
44199
44210
|
if (name.includes("status")) {
|
|
44200
44211
|
if (val.includes("complete") || val.includes("done") || val.includes("active"))
|
|
@@ -44210,12 +44221,12 @@ function getBadgeVariant(fieldName, value) {
|
|
|
44210
44221
|
}
|
|
44211
44222
|
return "default";
|
|
44212
44223
|
}
|
|
44213
|
-
function formatFieldValue2(value,
|
|
44224
|
+
function formatFieldValue2(value, fieldName2) {
|
|
44214
44225
|
if (typeof value === "number") {
|
|
44215
|
-
if (
|
|
44226
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
44216
44227
|
return `${value}%`;
|
|
44217
44228
|
}
|
|
44218
|
-
if (
|
|
44229
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
44219
44230
|
return `$${value.toLocaleString()}`;
|
|
44220
44231
|
}
|
|
44221
44232
|
return value.toLocaleString();
|
|
@@ -44225,7 +44236,7 @@ function formatFieldValue2(value, fieldName) {
|
|
|
44225
44236
|
}
|
|
44226
44237
|
return String(value);
|
|
44227
44238
|
}
|
|
44228
|
-
function renderRichFieldValue(value,
|
|
44239
|
+
function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
44229
44240
|
if (value === void 0 || value === null) return "\u2014";
|
|
44230
44241
|
const str = String(value);
|
|
44231
44242
|
switch (fieldType) {
|
|
@@ -44236,7 +44247,7 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
44236
44247
|
"img",
|
|
44237
44248
|
{
|
|
44238
44249
|
src: str,
|
|
44239
|
-
alt: formatFieldLabel(
|
|
44250
|
+
alt: formatFieldLabel(fieldName2),
|
|
44240
44251
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
44241
44252
|
loading: "lazy"
|
|
44242
44253
|
}
|
|
@@ -44371,9 +44382,9 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
44371
44382
|
return /* @__PURE__ */ jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
|
|
44372
44383
|
default:
|
|
44373
44384
|
if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
|
|
44374
|
-
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(
|
|
44385
|
+
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(fieldName2, str), children: humanizeEnumValue(str) });
|
|
44375
44386
|
}
|
|
44376
|
-
return formatFieldValue2(value,
|
|
44387
|
+
return formatFieldValue2(value, fieldName2);
|
|
44377
44388
|
}
|
|
44378
44389
|
}
|
|
44379
44390
|
function normalizeFieldDefs(fields) {
|
|
@@ -45216,7 +45227,21 @@ var init_Form = __esm({
|
|
|
45216
45227
|
const normalizedInitialData = React94__default.useMemo(() => {
|
|
45217
45228
|
const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
|
|
45218
45229
|
const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
|
|
45219
|
-
|
|
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;
|
|
45220
45245
|
}, [entity, initialData]);
|
|
45221
45246
|
const entityDerivedFields = React94__default.useMemo(() => {
|
|
45222
45247
|
if (fields && fields.length > 0) return void 0;
|
|
@@ -45345,8 +45370,8 @@ var init_Form = __esm({
|
|
|
45345
45370
|
checkViolations(name, newFormData);
|
|
45346
45371
|
};
|
|
45347
45372
|
const isFieldVisible = React94__default.useCallback(
|
|
45348
|
-
(
|
|
45349
|
-
const condition = conditionalFields[
|
|
45373
|
+
(fieldName2) => {
|
|
45374
|
+
const condition = conditionalFields[fieldName2];
|
|
45350
45375
|
if (!condition) return true;
|
|
45351
45376
|
return Boolean(evaluateFormExpression(condition, evalContext));
|
|
45352
45377
|
},
|
|
@@ -45392,9 +45417,9 @@ var init_Form = __esm({
|
|
|
45392
45417
|
};
|
|
45393
45418
|
const handleInvalid = (e) => {
|
|
45394
45419
|
const target = e.target;
|
|
45395
|
-
const
|
|
45420
|
+
const fieldName2 = target.getAttribute("data-field-name") ?? target.name ?? "";
|
|
45396
45421
|
const fieldMessage = target.validationMessage || "Invalid value";
|
|
45397
|
-
debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
|
|
45422
|
+
debug("forms", "invalid", { mode: formMode, fieldName: fieldName2, fieldMessage });
|
|
45398
45423
|
queueMicrotask(() => {
|
|
45399
45424
|
const form = formRef.current;
|
|
45400
45425
|
if (!form) return;
|
|
@@ -45430,22 +45455,22 @@ var init_Form = __esm({
|
|
|
45430
45455
|
};
|
|
45431
45456
|
const renderField = React94__default.useCallback(
|
|
45432
45457
|
(field) => {
|
|
45433
|
-
const
|
|
45434
|
-
if (!
|
|
45435
|
-
if (!isFieldVisible(
|
|
45458
|
+
const fieldName2 = field.name || field.field;
|
|
45459
|
+
if (!fieldName2) return null;
|
|
45460
|
+
if (!isFieldVisible(fieldName2)) {
|
|
45436
45461
|
return null;
|
|
45437
45462
|
}
|
|
45438
45463
|
const inputType = determineInputType(field);
|
|
45439
|
-
const label = field.label ||
|
|
45440
|
-
const currentValue = formData[
|
|
45441
|
-
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: [
|
|
45442
45467
|
inputType !== "checkbox" && /* @__PURE__ */ jsxs(Typography, { as: "label", variant: "label", weight: "bold", children: [
|
|
45443
45468
|
label,
|
|
45444
45469
|
field.required && /* @__PURE__ */ jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
|
|
45445
45470
|
] }),
|
|
45446
|
-
renderFieldInput(field,
|
|
45471
|
+
renderFieldInput(field, fieldName2, inputType, currentValue, label),
|
|
45447
45472
|
field.hint && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
|
|
45448
|
-
] },
|
|
45473
|
+
] }, fieldName2);
|
|
45449
45474
|
},
|
|
45450
45475
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
45451
45476
|
);
|
|
@@ -45474,8 +45499,8 @@ var init_Form = __esm({
|
|
|
45474
45499
|
}
|
|
45475
45500
|
return field;
|
|
45476
45501
|
}).map((field) => {
|
|
45477
|
-
const
|
|
45478
|
-
const override = fieldOverrides?.find((o) => o.name ===
|
|
45502
|
+
const fieldName2 = field.name || field.field;
|
|
45503
|
+
const override = fieldOverrides?.find((o) => o.name === fieldName2);
|
|
45479
45504
|
if (!override) return field;
|
|
45480
45505
|
return {
|
|
45481
45506
|
...field,
|
|
@@ -45531,11 +45556,11 @@ var init_Form = __esm({
|
|
|
45531
45556
|
] }, section.id);
|
|
45532
45557
|
}).filter(Boolean);
|
|
45533
45558
|
}, [sections, isSectionVisible, collapsedSections, renderField, gap]);
|
|
45534
|
-
function renderFieldInput(field,
|
|
45559
|
+
function renderFieldInput(field, fieldName2, inputType, currentValue, label) {
|
|
45535
45560
|
const commonProps = {
|
|
45536
|
-
id:
|
|
45537
|
-
name:
|
|
45538
|
-
"data-field-name":
|
|
45561
|
+
id: fieldName2,
|
|
45562
|
+
name: fieldName2,
|
|
45563
|
+
"data-field-name": fieldName2,
|
|
45539
45564
|
required: field.required,
|
|
45540
45565
|
disabled: isLoading,
|
|
45541
45566
|
placeholder: field.placeholder,
|
|
@@ -45549,7 +45574,7 @@ var init_Form = __esm({
|
|
|
45549
45574
|
...commonProps,
|
|
45550
45575
|
label: label + (field.required ? " *" : ""),
|
|
45551
45576
|
checked: Boolean(currentValue),
|
|
45552
|
-
onChange: (e) => handleChange(
|
|
45577
|
+
onChange: (e) => handleChange(fieldName2, e.target.checked)
|
|
45553
45578
|
}
|
|
45554
45579
|
);
|
|
45555
45580
|
case "textarea":
|
|
@@ -45558,7 +45583,7 @@ var init_Form = __esm({
|
|
|
45558
45583
|
{
|
|
45559
45584
|
...commonProps,
|
|
45560
45585
|
value: String(currentValue),
|
|
45561
|
-
onChange: (e) => handleChange(
|
|
45586
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45562
45587
|
minLength: field.min,
|
|
45563
45588
|
maxLength: field.max
|
|
45564
45589
|
}
|
|
@@ -45571,14 +45596,14 @@ var init_Form = __esm({
|
|
|
45571
45596
|
...commonProps,
|
|
45572
45597
|
options,
|
|
45573
45598
|
value: String(currentValue),
|
|
45574
|
-
onValueChange: (v) => handleChange(
|
|
45599
|
+
onValueChange: (v) => handleChange(fieldName2, v),
|
|
45575
45600
|
placeholder: field.placeholder || `Select ${label}...`
|
|
45576
45601
|
}
|
|
45577
45602
|
);
|
|
45578
45603
|
}
|
|
45579
45604
|
case "relation": {
|
|
45580
|
-
const relationOptions = relationsData[
|
|
45581
|
-
const relationLoading = relationsLoading[
|
|
45605
|
+
const relationOptions = relationsData[fieldName2] || [];
|
|
45606
|
+
const relationLoading = relationsLoading[fieldName2] || false;
|
|
45582
45607
|
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
45583
45608
|
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
45584
45609
|
return /* @__PURE__ */ jsx(
|
|
@@ -45590,7 +45615,7 @@ var init_Form = __esm({
|
|
|
45590
45615
|
clearable: true,
|
|
45591
45616
|
options: [...relationOptions],
|
|
45592
45617
|
value: selectedValues,
|
|
45593
|
-
onValueChange: (value) => handleChange(
|
|
45618
|
+
onValueChange: (value) => handleChange(fieldName2, Array.isArray(value) ? value : [value]),
|
|
45594
45619
|
placeholder: field.placeholder || `Select ${label}...`
|
|
45595
45620
|
}
|
|
45596
45621
|
);
|
|
@@ -45600,7 +45625,7 @@ var init_Form = __esm({
|
|
|
45600
45625
|
{
|
|
45601
45626
|
...commonProps,
|
|
45602
45627
|
value: currentValue ? String(currentValue) : void 0,
|
|
45603
|
-
onChange: (value) => handleChange(
|
|
45628
|
+
onChange: (value) => handleChange(fieldName2, value),
|
|
45604
45629
|
options: relationOptions,
|
|
45605
45630
|
isLoading: relationLoading,
|
|
45606
45631
|
placeholder: field.placeholder || `Select ${label}...`,
|
|
@@ -45617,7 +45642,7 @@ var init_Form = __esm({
|
|
|
45617
45642
|
placeholder: field.placeholder,
|
|
45618
45643
|
disabled: isLoading,
|
|
45619
45644
|
value: arrayValue,
|
|
45620
|
-
onChange: (next) => handleChange(
|
|
45645
|
+
onChange: (next) => handleChange(fieldName2, [...next])
|
|
45621
45646
|
}
|
|
45622
45647
|
);
|
|
45623
45648
|
}
|
|
@@ -45629,7 +45654,7 @@ var init_Form = __esm({
|
|
|
45629
45654
|
type: "number",
|
|
45630
45655
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
45631
45656
|
onChange: (e) => handleChange(
|
|
45632
|
-
|
|
45657
|
+
fieldName2,
|
|
45633
45658
|
e.target.value ? Number(e.target.value) : void 0
|
|
45634
45659
|
),
|
|
45635
45660
|
min: field.min,
|
|
@@ -45646,7 +45671,7 @@ var init_Form = __esm({
|
|
|
45646
45671
|
icon: DollarSign,
|
|
45647
45672
|
value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
|
|
45648
45673
|
onChange: (e) => handleChange(
|
|
45649
|
-
|
|
45674
|
+
fieldName2,
|
|
45650
45675
|
e.target.value ? Number(e.target.value) : void 0
|
|
45651
45676
|
),
|
|
45652
45677
|
min: field.min,
|
|
@@ -45664,7 +45689,7 @@ var init_Form = __esm({
|
|
|
45664
45689
|
const f3 = files[0];
|
|
45665
45690
|
if (!f3) return;
|
|
45666
45691
|
const reader = new FileReader();
|
|
45667
|
-
reader.onload = () => handleChange(
|
|
45692
|
+
reader.onload = () => handleChange(fieldName2, {
|
|
45668
45693
|
name: f3.name,
|
|
45669
45694
|
mimeType: f3.type,
|
|
45670
45695
|
sizeBytes: f3.size,
|
|
@@ -45681,7 +45706,7 @@ var init_Form = __esm({
|
|
|
45681
45706
|
...commonProps,
|
|
45682
45707
|
type: "date",
|
|
45683
45708
|
value: formatDateValue(currentValue),
|
|
45684
|
-
onChange: (e) => handleChange(
|
|
45709
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45685
45710
|
}
|
|
45686
45711
|
);
|
|
45687
45712
|
case "datetime-local":
|
|
@@ -45691,7 +45716,7 @@ var init_Form = __esm({
|
|
|
45691
45716
|
...commonProps,
|
|
45692
45717
|
type: "datetime-local",
|
|
45693
45718
|
value: formatDateTimeValue(currentValue),
|
|
45694
|
-
onChange: (e) => handleChange(
|
|
45719
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45695
45720
|
}
|
|
45696
45721
|
);
|
|
45697
45722
|
case "email":
|
|
@@ -45701,7 +45726,7 @@ var init_Form = __esm({
|
|
|
45701
45726
|
...commonProps,
|
|
45702
45727
|
type: "email",
|
|
45703
45728
|
value: String(currentValue),
|
|
45704
|
-
onChange: (e) => handleChange(
|
|
45729
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45705
45730
|
minLength: field.min,
|
|
45706
45731
|
maxLength: field.max
|
|
45707
45732
|
}
|
|
@@ -45713,7 +45738,7 @@ var init_Form = __esm({
|
|
|
45713
45738
|
...commonProps,
|
|
45714
45739
|
type: "url",
|
|
45715
45740
|
value: String(currentValue),
|
|
45716
|
-
onChange: (e) => handleChange(
|
|
45741
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45717
45742
|
minLength: field.min,
|
|
45718
45743
|
maxLength: field.max
|
|
45719
45744
|
}
|
|
@@ -45725,7 +45750,7 @@ var init_Form = __esm({
|
|
|
45725
45750
|
...commonProps,
|
|
45726
45751
|
type: "password",
|
|
45727
45752
|
value: String(currentValue),
|
|
45728
|
-
onChange: (e) => handleChange(
|
|
45753
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45729
45754
|
minLength: field.min,
|
|
45730
45755
|
maxLength: field.max
|
|
45731
45756
|
}
|
|
@@ -45738,7 +45763,7 @@ var init_Form = __esm({
|
|
|
45738
45763
|
...commonProps,
|
|
45739
45764
|
type: "text",
|
|
45740
45765
|
value: String(currentValue),
|
|
45741
|
-
onChange: (e) => handleChange(
|
|
45766
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45742
45767
|
minLength: field.min,
|
|
45743
45768
|
maxLength: field.max
|
|
45744
45769
|
}
|
|
@@ -46095,7 +46120,7 @@ function entityFieldsFromListItem(item) {
|
|
|
46095
46120
|
}
|
|
46096
46121
|
return result;
|
|
46097
46122
|
}
|
|
46098
|
-
function getStatusStyle(
|
|
46123
|
+
function getStatusStyle(fieldName2, value) {
|
|
46099
46124
|
const val = String(value).toLowerCase();
|
|
46100
46125
|
if (val.includes("complete") || val.includes("done"))
|
|
46101
46126
|
return STATUS_STYLES.complete;
|
|
@@ -46111,12 +46136,12 @@ function getStatusStyle(fieldName, value) {
|
|
|
46111
46136
|
if (val.includes("low")) return STATUS_STYLES.low;
|
|
46112
46137
|
return STATUS_STYLES.default;
|
|
46113
46138
|
}
|
|
46114
|
-
function formatValue3(value,
|
|
46139
|
+
function formatValue3(value, fieldName2) {
|
|
46115
46140
|
if (typeof value === "number") {
|
|
46116
|
-
if (
|
|
46141
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
46117
46142
|
return `${value}%`;
|
|
46118
46143
|
}
|
|
46119
|
-
if (
|
|
46144
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
46120
46145
|
return new Intl.NumberFormat("en-US", {
|
|
46121
46146
|
style: "currency",
|
|
46122
46147
|
currency: "USD",
|
|
@@ -46139,8 +46164,8 @@ function formatValue3(value, fieldName) {
|
|
|
46139
46164
|
}
|
|
46140
46165
|
return String(value);
|
|
46141
46166
|
}
|
|
46142
|
-
function formatFieldLabel2(
|
|
46143
|
-
return humanizeFieldName(
|
|
46167
|
+
function formatFieldLabel2(fieldName2) {
|
|
46168
|
+
return humanizeFieldName(fieldName2).replace(/\sId$/, "").trim();
|
|
46144
46169
|
}
|
|
46145
46170
|
var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
|
|
46146
46171
|
var init_List = __esm({
|
|
@@ -46208,9 +46233,9 @@ var init_List = __esm({
|
|
|
46208
46233
|
};
|
|
46209
46234
|
StatusBadge = ({
|
|
46210
46235
|
value,
|
|
46211
|
-
fieldName
|
|
46236
|
+
fieldName: fieldName2
|
|
46212
46237
|
}) => {
|
|
46213
|
-
const style = getStatusStyle(
|
|
46238
|
+
const style = getStatusStyle(fieldName2, value);
|
|
46214
46239
|
return /* @__PURE__ */ jsxs(
|
|
46215
46240
|
Typography,
|
|
46216
46241
|
{
|
|
@@ -49142,8 +49167,8 @@ var init_StatCard = __esm({
|
|
|
49142
49167
|
return items.length;
|
|
49143
49168
|
}
|
|
49144
49169
|
if (field.includes(":")) {
|
|
49145
|
-
const [
|
|
49146
|
-
return items.filter((item) => item[
|
|
49170
|
+
const [fieldName2, fieldValue] = field.split(":");
|
|
49171
|
+
return items.filter((item) => item[fieldName2] === fieldValue).length;
|
|
49147
49172
|
}
|
|
49148
49173
|
const fieldExistsOnItems = items.some((item) => field in item);
|
|
49149
49174
|
if (fieldExistsOnItems) {
|
|
@@ -50663,6 +50688,8 @@ var init_component_registry_generated = __esm({
|
|
|
50663
50688
|
init_DocSearch();
|
|
50664
50689
|
init_DocSidebar();
|
|
50665
50690
|
init_DocTOC();
|
|
50691
|
+
init_DocumentDetails();
|
|
50692
|
+
init_DocumentPanel();
|
|
50666
50693
|
init_DocumentViewer();
|
|
50667
50694
|
init_DrawFxLayer();
|
|
50668
50695
|
init_DrawGroup();
|
|
@@ -50772,7 +50799,7 @@ var init_component_registry_generated = __esm({
|
|
|
50772
50799
|
init_RelationSelect();
|
|
50773
50800
|
init_RepeatableFormSection();
|
|
50774
50801
|
init_ReplyTree();
|
|
50775
|
-
|
|
50802
|
+
init_RichTextEditor();
|
|
50776
50803
|
init_RuntimeDebugger2();
|
|
50777
50804
|
init_ScaledDiagram();
|
|
50778
50805
|
init_ScoreDisplay();
|
|
@@ -50935,6 +50962,8 @@ var init_component_registry_generated = __esm({
|
|
|
50935
50962
|
"DocSearch": DocSearch,
|
|
50936
50963
|
"DocSidebar": DocSidebar,
|
|
50937
50964
|
"DocTOC": DocTOC,
|
|
50965
|
+
"DocumentDetails": DocumentDetails,
|
|
50966
|
+
"DocumentPanel": DocumentPanel,
|
|
50938
50967
|
"DocumentViewer": DocumentViewer,
|
|
50939
50968
|
"DrawFxLayer": DrawFxLayer,
|
|
50940
50969
|
"DrawGroup": DrawGroup,
|
|
@@ -51046,7 +51075,7 @@ var init_component_registry_generated = __esm({
|
|
|
51046
51075
|
"RelationSelect": RelationSelect,
|
|
51047
51076
|
"RepeatableFormSection": RepeatableFormSection,
|
|
51048
51077
|
"ReplyTree": ReplyTree,
|
|
51049
|
-
"
|
|
51078
|
+
"RichTextEditor": RichTextEditor,
|
|
51050
51079
|
"RuntimeDebugger": RuntimeDebugger,
|
|
51051
51080
|
"ScaledDiagram": ScaledDiagram,
|
|
51052
51081
|
"ScoreDisplay": ScoreDisplay,
|
|
@@ -51200,10 +51229,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
51200
51229
|
}
|
|
51201
51230
|
if (field && typeof field === "object" && !Array.isArray(field) && !React94__default.isValidElement(field) && !(field instanceof Date)) {
|
|
51202
51231
|
const obj = field;
|
|
51203
|
-
const
|
|
51204
|
-
if (!
|
|
51232
|
+
const fieldName2 = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
|
|
51233
|
+
if (!fieldName2) return field;
|
|
51205
51234
|
if (obj.type || obj.inputType) return field;
|
|
51206
|
-
const entityField = fieldMap.get(
|
|
51235
|
+
const entityField = fieldMap.get(fieldName2);
|
|
51207
51236
|
if (!entityField) return field;
|
|
51208
51237
|
const enriched = { ...obj, type: entityField.type };
|
|
51209
51238
|
if (entityField.required && !("required" in obj)) {
|
|
@@ -51253,9 +51282,9 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
51253
51282
|
}
|
|
51254
51283
|
if (field && typeof field === "object" && !Array.isArray(field) && !React94__default.isValidElement(field) && !(field instanceof Date)) {
|
|
51255
51284
|
const obj = field;
|
|
51256
|
-
const
|
|
51257
|
-
if (!
|
|
51258
|
-
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);
|
|
51259
51288
|
return meta ? { ...obj, ...meta } : field;
|
|
51260
51289
|
}
|
|
51261
51290
|
return field;
|
|
@@ -52094,9 +52123,9 @@ function UISlotRenderer({
|
|
|
52094
52123
|
"ui-slot-renderer relative min-h-full",
|
|
52095
52124
|
className
|
|
52096
52125
|
), children: [
|
|
52097
|
-
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full", children: [
|
|
52098
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 shrink-0" }),
|
|
52099
|
-
/* @__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]" })
|
|
52100
52129
|
] }),
|
|
52101
52130
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "modal", portal: true }),
|
|
52102
52131
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "drawer", portal: true }),
|
|
@@ -55993,7 +56022,7 @@ function buildTraitRenderConfig(binding, traitConfigsByName, payload) {
|
|
|
55993
56022
|
}
|
|
55994
56023
|
return void 0;
|
|
55995
56024
|
}
|
|
55996
|
-
function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
|
|
56025
|
+
function createSharedEntityWriter(binding, tick, traitStatesRef, emit, traitConfigsByName) {
|
|
55997
56026
|
return (scratch) => {
|
|
55998
56027
|
const traitName = binding.trait.name;
|
|
55999
56028
|
const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
|
|
@@ -56002,9 +56031,13 @@ function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
|
|
|
56002
56031
|
const writes = [];
|
|
56003
56032
|
const ctx = createMinimalContext(scratchEntity, {}, currentState);
|
|
56004
56033
|
const declaredDefaults = collectDeclaredConfigDefaults(binding.trait);
|
|
56005
|
-
const
|
|
56006
|
-
|
|
56007
|
-
|
|
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 ?? {} };
|
|
56008
56041
|
}
|
|
56009
56042
|
ctx.mutateEntity = (changes) => {
|
|
56010
56043
|
for (const [field, value] of Object.entries(changes)) {
|
|
@@ -56607,7 +56640,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56607
56640
|
const interval = entries[0].tick.interval;
|
|
56608
56641
|
const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
|
|
56609
56642
|
const writers = entries.map(
|
|
56610
|
-
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
|
|
56643
|
+
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter, traitConfigsByName)
|
|
56611
56644
|
);
|
|
56612
56645
|
runTickFrame(group.storeKey, writers, sharedEntityStore);
|
|
56613
56646
|
});
|
|
@@ -59120,11 +59153,11 @@ function OrbInspector({ node, schema, editable = false, userType = "builder", th
|
|
|
59120
59153
|
const handleAddField = useCallback(() => {
|
|
59121
59154
|
eventBus.emit("UI:ADD_FIELD", {});
|
|
59122
59155
|
}, [eventBus]);
|
|
59123
|
-
const handleUpdateField = useCallback((
|
|
59124
|
-
eventBus.emit("UI:UPDATE_FIELD", { fieldName, updates });
|
|
59156
|
+
const handleUpdateField = useCallback((fieldName2, updates) => {
|
|
59157
|
+
eventBus.emit("UI:UPDATE_FIELD", { fieldName: fieldName2, updates });
|
|
59125
59158
|
}, [eventBus]);
|
|
59126
|
-
const handleRemoveField = useCallback((
|
|
59127
|
-
eventBus.emit("UI:REMOVE_FIELD", { fieldName });
|
|
59159
|
+
const handleRemoveField = useCallback((fieldName2) => {
|
|
59160
|
+
eventBus.emit("UI:REMOVE_FIELD", { fieldName: fieldName2 });
|
|
59128
59161
|
}, [eventBus]);
|
|
59129
59162
|
const handleGuardChange = useCallback((guardExpr) => {
|
|
59130
59163
|
if (!editable) return;
|