@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/components/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { EventBusContext, useTraitScopeChain, useCurrentPagePath, useGameAudioCo
|
|
|
7
7
|
export { GameAudioContext, GameAudioProvider, useGameAudioContext, useNavStack } from '@almadar/ui/providers';
|
|
8
8
|
import { createLogger, isLogLevelEnabled } from '@almadar/logger';
|
|
9
9
|
import * as LucideIcons2 from 'lucide-react';
|
|
10
|
-
import { X, List, Printer, ChevronRight, ChevronLeft, Check, Copy, RotateCcw, Play, Terminal, CheckCircle, XCircle, ChevronDown, Search, ChevronUp, MoreHorizontal, ArrowLeft, DollarSign, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, HelpCircle,
|
|
10
|
+
import { X, List, Printer, ChevronRight, ChevronLeft, Check, Copy, RotateCcw, Play, Terminal, CheckCircle, XCircle, ChevronDown, Search, ChevronUp, MoreHorizontal, ArrowLeft, DollarSign, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, HelpCircle, Bold, Italic, Underline, Strikethrough, Heading1, Heading2, Heading3, ListOrdered, Quote, Link as Link$1, GitBranch, Plus, ArrowRight, Trash, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2 } from 'lucide-react';
|
|
11
11
|
import { useTranslate } from '@almadar/ui/hooks';
|
|
12
12
|
import { useUISlots, useTheme } from '@almadar/ui/context';
|
|
13
13
|
import { evaluate, createMinimalContext } from '@almadar/evaluator';
|
|
@@ -23950,8 +23950,9 @@ function DataGrid({
|
|
|
23950
23950
|
const titleField = fieldDefs.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fieldDefs[0];
|
|
23951
23951
|
const badgeFields = fieldDefs.filter((f3) => f3.variant === "badge" && f3 !== titleField);
|
|
23952
23952
|
const bodyFields = fieldDefs.filter((f3) => f3 !== titleField && !badgeFields.includes(f3));
|
|
23953
|
-
const
|
|
23954
|
-
const
|
|
23953
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
23954
|
+
const inlineCardActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
23955
|
+
const menuCardActions = actionDefs.filter((a) => !inlineCardActions.includes(a));
|
|
23955
23956
|
const fireAction = (action, itemData) => {
|
|
23956
23957
|
if (action.navigatesTo) {
|
|
23957
23958
|
const url = action.navigatesTo.replace(
|
|
@@ -23971,6 +23972,9 @@ function DataGrid({
|
|
|
23971
23972
|
e.stopPropagation();
|
|
23972
23973
|
fireAction(action, itemData);
|
|
23973
23974
|
};
|
|
23975
|
+
const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
|
|
23976
|
+
const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
|
|
23977
|
+
const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
|
|
23974
23978
|
const hasRenderProp = typeof children === "function";
|
|
23975
23979
|
useEffect(() => {
|
|
23976
23980
|
if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
|
|
@@ -24042,55 +24046,40 @@ function DataGrid({
|
|
|
24042
24046
|
{
|
|
24043
24047
|
"data-entity-row": true,
|
|
24044
24048
|
"data-entity-id": id,
|
|
24045
|
-
|
|
24049
|
+
onClick: handleCardClick?.(itemData),
|
|
24050
|
+
className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
|
|
24046
24051
|
children: [
|
|
24047
24052
|
children(itemData, index),
|
|
24048
|
-
actionDefs.length > 0 && /* @__PURE__ */
|
|
24049
|
-
/* @__PURE__ */ jsxs(
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
|
|
24053
|
-
|
|
24054
|
-
|
|
24055
|
-
|
|
24056
|
-
|
|
24057
|
-
|
|
24058
|
-
|
|
24059
|
-
|
|
24060
|
-
|
|
24061
|
-
|
|
24062
|
-
|
|
24063
|
-
|
|
24064
|
-
|
|
24065
|
-
)),
|
|
24066
|
-
maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsx(
|
|
24067
|
-
Menu,
|
|
24068
|
-
{
|
|
24069
|
-
position: "bottom-end",
|
|
24070
|
-
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" }) }),
|
|
24071
|
-
items: actionDefs.slice(maxInlineActions).map((action) => ({
|
|
24072
|
-
label: action.label,
|
|
24073
|
-
icon: action.icon,
|
|
24074
|
-
event: action.event,
|
|
24075
|
-
onClick: () => fireAction(action, itemData)
|
|
24076
|
-
}))
|
|
24077
|
-
}
|
|
24078
|
-
)
|
|
24079
|
-
] }),
|
|
24080
|
-
/* @__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(
|
|
24053
|
+
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: [
|
|
24054
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
24055
|
+
Button,
|
|
24056
|
+
{
|
|
24057
|
+
variant: "primary",
|
|
24058
|
+
size: "sm",
|
|
24059
|
+
onClick: handleActionClick(action, itemData),
|
|
24060
|
+
"data-testid": `action-${action.event}`,
|
|
24061
|
+
"data-row-id": String(itemData.id),
|
|
24062
|
+
children: [
|
|
24063
|
+
action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
|
|
24064
|
+
action.label
|
|
24065
|
+
]
|
|
24066
|
+
},
|
|
24067
|
+
idx
|
|
24068
|
+
)),
|
|
24069
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsx(
|
|
24081
24070
|
Menu,
|
|
24082
24071
|
{
|
|
24083
24072
|
position: "bottom-end",
|
|
24084
24073
|
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" }) }),
|
|
24085
|
-
items:
|
|
24074
|
+
items: menuCardActions.map((action) => ({
|
|
24086
24075
|
label: action.label,
|
|
24087
24076
|
icon: action.icon,
|
|
24088
|
-
|
|
24077
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
24089
24078
|
onClick: () => fireAction(action, itemData)
|
|
24090
24079
|
}))
|
|
24091
24080
|
}
|
|
24092
|
-
)
|
|
24093
|
-
] })
|
|
24081
|
+
)
|
|
24082
|
+
] }) })
|
|
24094
24083
|
]
|
|
24095
24084
|
},
|
|
24096
24085
|
id
|
|
@@ -24104,12 +24093,14 @@ function DataGrid({
|
|
|
24104
24093
|
{
|
|
24105
24094
|
"data-entity-row": true,
|
|
24106
24095
|
"data-entity-id": id,
|
|
24096
|
+
onClick: handleCardClick?.(itemData),
|
|
24107
24097
|
className: cn(
|
|
24108
24098
|
"bg-card rounded-lg",
|
|
24109
24099
|
"border border-border",
|
|
24110
24100
|
"shadow-elevation-card hover:shadow-elevation-dialog",
|
|
24111
24101
|
"hover:border-primary transition-all",
|
|
24112
24102
|
"flex flex-col",
|
|
24103
|
+
handleCardClick && "cursor-pointer",
|
|
24113
24104
|
isSelected && "ring-2 ring-primary border-primary"
|
|
24114
24105
|
),
|
|
24115
24106
|
children: [
|
|
@@ -24159,53 +24150,35 @@ function DataGrid({
|
|
|
24159
24150
|
] }, field.name);
|
|
24160
24151
|
}) })
|
|
24161
24152
|
] }),
|
|
24162
|
-
|
|
24163
|
-
|
|
24153
|
+
actionDefs.length > 0 && /* @__PURE__ */ jsxs(HStack, { gap: "xs", onClick: stopCardClick, className: "flex-shrink-0", children: [
|
|
24154
|
+
inlineCardActions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
24164
24155
|
Button,
|
|
24165
24156
|
{
|
|
24166
|
-
variant:
|
|
24157
|
+
variant: "primary",
|
|
24167
24158
|
size: "sm",
|
|
24168
24159
|
onClick: handleActionClick(action, itemData),
|
|
24169
24160
|
"data-testid": `action-${action.event}`,
|
|
24170
24161
|
"data-row-id": String(itemData.id),
|
|
24171
24162
|
"aria-label": action.label,
|
|
24172
24163
|
title: action.label,
|
|
24173
|
-
className: cn(
|
|
24174
|
-
action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
|
|
24175
|
-
action.icon && "px-2"
|
|
24176
|
-
),
|
|
24164
|
+
className: cn(action.icon && "px-2"),
|
|
24177
24165
|
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
24178
24166
|
},
|
|
24179
24167
|
idx
|
|
24180
24168
|
)),
|
|
24181
|
-
|
|
24169
|
+
menuCardActions.length > 0 && /* @__PURE__ */ jsx(
|
|
24182
24170
|
Menu,
|
|
24183
24171
|
{
|
|
24184
24172
|
position: "bottom-end",
|
|
24185
24173
|
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" }) }),
|
|
24186
|
-
items:
|
|
24174
|
+
items: menuCardActions.map((action) => ({
|
|
24187
24175
|
label: action.label,
|
|
24188
24176
|
icon: action.icon,
|
|
24189
|
-
|
|
24177
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
24190
24178
|
onClick: () => fireAction(action, itemData)
|
|
24191
24179
|
}))
|
|
24192
24180
|
}
|
|
24193
|
-
)
|
|
24194
|
-
dangerActions.map((action, idx) => /* @__PURE__ */ jsx(
|
|
24195
|
-
Button,
|
|
24196
|
-
{
|
|
24197
|
-
variant: "ghost",
|
|
24198
|
-
size: "sm",
|
|
24199
|
-
onClick: handleActionClick(action, itemData),
|
|
24200
|
-
"data-testid": `action-${action.event}`,
|
|
24201
|
-
"data-row-id": String(itemData.id),
|
|
24202
|
-
"aria-label": action.label,
|
|
24203
|
-
title: action.label,
|
|
24204
|
-
className: "text-error hover:text-error hover:bg-error/10 px-2",
|
|
24205
|
-
children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
|
|
24206
|
-
},
|
|
24207
|
-
`danger-${idx}`
|
|
24208
|
-
))
|
|
24181
|
+
)
|
|
24209
24182
|
] })
|
|
24210
24183
|
] }) }),
|
|
24211
24184
|
bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
@@ -24447,54 +24420,59 @@ function DataList({
|
|
|
24447
24420
|
if (!itemActions || itemActions.length === 0) return null;
|
|
24448
24421
|
const inline = maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions;
|
|
24449
24422
|
const overflow = maxInlineActions != null ? itemActions.slice(maxInlineActions) : [];
|
|
24450
|
-
return
|
|
24451
|
-
|
|
24452
|
-
|
|
24453
|
-
|
|
24454
|
-
|
|
24455
|
-
|
|
24456
|
-
|
|
24457
|
-
|
|
24458
|
-
|
|
24459
|
-
|
|
24460
|
-
action
|
|
24461
|
-
|
|
24462
|
-
|
|
24463
|
-
|
|
24464
|
-
|
|
24465
|
-
|
|
24466
|
-
|
|
24467
|
-
|
|
24468
|
-
|
|
24469
|
-
|
|
24470
|
-
|
|
24471
|
-
|
|
24472
|
-
|
|
24473
|
-
|
|
24474
|
-
|
|
24475
|
-
|
|
24476
|
-
|
|
24477
|
-
|
|
24478
|
-
|
|
24479
|
-
|
|
24480
|
-
|
|
24481
|
-
|
|
24482
|
-
|
|
24483
|
-
|
|
24484
|
-
|
|
24485
|
-
|
|
24486
|
-
|
|
24487
|
-
|
|
24488
|
-
|
|
24489
|
-
|
|
24423
|
+
return (
|
|
24424
|
+
// stopPropagation at the cluster: the "⋯" trigger opens the overflow
|
|
24425
|
+
// menu without also firing the row's default click (inline buttons
|
|
24426
|
+
// already stop it in handleActionClick; the Menu panel is portaled).
|
|
24427
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", onClick: rowClickEvent ? (e) => e.stopPropagation() : void 0, className: "flex-shrink-0", children: [
|
|
24428
|
+
inline.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
24429
|
+
Button,
|
|
24430
|
+
{
|
|
24431
|
+
variant: action.variant ?? "ghost",
|
|
24432
|
+
size: "sm",
|
|
24433
|
+
onClick: handleActionClick(action, itemData),
|
|
24434
|
+
"data-testid": `action-${action.event}`,
|
|
24435
|
+
"data-row-id": String(itemData.id),
|
|
24436
|
+
className: cn(
|
|
24437
|
+
action.variant === "danger" && "text-error hover:bg-error/10",
|
|
24438
|
+
// Must sit on the Button itself: the variant's own text colour
|
|
24439
|
+
// beats an inherited one from the row wrapper.
|
|
24440
|
+
onPrimary && "!text-primary-foreground hover:bg-primary-foreground/15"
|
|
24441
|
+
),
|
|
24442
|
+
children: [
|
|
24443
|
+
action.icon && renderIconInput2(action.icon, { size: "xs", className: "mr-1" }),
|
|
24444
|
+
action.label
|
|
24445
|
+
]
|
|
24446
|
+
},
|
|
24447
|
+
idx
|
|
24448
|
+
)),
|
|
24449
|
+
overflow.length > 0 && /* @__PURE__ */ jsx(
|
|
24450
|
+
Menu,
|
|
24451
|
+
{
|
|
24452
|
+
position: "bottom-end",
|
|
24453
|
+
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" }) }),
|
|
24454
|
+
items: overflow.map((action) => ({
|
|
24455
|
+
label: action.label,
|
|
24456
|
+
icon: action.icon,
|
|
24457
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
24458
|
+
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
24459
|
+
id: itemData.id,
|
|
24460
|
+
row: itemData
|
|
24461
|
+
})
|
|
24462
|
+
}))
|
|
24463
|
+
}
|
|
24464
|
+
)
|
|
24465
|
+
] })
|
|
24466
|
+
);
|
|
24490
24467
|
};
|
|
24468
|
+
const rowClickEvent = itemClickEvent || itemActions?.find((a) => a.variant !== "danger")?.event;
|
|
24491
24469
|
const handleRowClick = (itemData) => () => {
|
|
24492
|
-
if (!
|
|
24470
|
+
if (!rowClickEvent) return;
|
|
24493
24471
|
const payload = {
|
|
24494
24472
|
id: itemData.id,
|
|
24495
24473
|
row: itemData
|
|
24496
24474
|
};
|
|
24497
|
-
eventBus.emit(`UI:${
|
|
24475
|
+
eventBus.emit(`UI:${rowClickEvent}`, payload);
|
|
24498
24476
|
};
|
|
24499
24477
|
if (isLoading) {
|
|
24500
24478
|
return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
|
|
@@ -24542,10 +24520,10 @@ function DataList({
|
|
|
24542
24520
|
{
|
|
24543
24521
|
"data-entity-row": true,
|
|
24544
24522
|
"data-entity-id": id,
|
|
24545
|
-
onClick:
|
|
24523
|
+
onClick: rowClickEvent ? handleRowClick(itemData) : void 0,
|
|
24546
24524
|
className: cn(
|
|
24547
24525
|
"flex px-4 group/rowactions",
|
|
24548
|
-
|
|
24526
|
+
rowClickEvent && "cursor-pointer",
|
|
24549
24527
|
isSent ? "justify-end" : "justify-start"
|
|
24550
24528
|
),
|
|
24551
24529
|
children: /* @__PURE__ */ jsxs(
|
|
@@ -24621,7 +24599,7 @@ function DataList({
|
|
|
24621
24599
|
const id2 = itemData.id || String(index);
|
|
24622
24600
|
const actions = renderItemActions(itemData);
|
|
24623
24601
|
return wrapDnd(
|
|
24624
|
-
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick:
|
|
24602
|
+
/* @__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: [
|
|
24625
24603
|
children(itemData, index),
|
|
24626
24604
|
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: [
|
|
24627
24605
|
/* @__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 }),
|
|
@@ -24633,7 +24611,6 @@ function DataList({
|
|
|
24633
24611
|
items: (itemActions ?? []).map((action) => ({
|
|
24634
24612
|
label: action.label,
|
|
24635
24613
|
icon: action.icon,
|
|
24636
|
-
event: action.event,
|
|
24637
24614
|
variant: action.variant === "danger" ? "danger" : "default",
|
|
24638
24615
|
onClick: () => eventBus.emit(`UI:${action.event}`, {
|
|
24639
24616
|
id: itemData.id,
|
|
@@ -24650,7 +24627,7 @@ function DataList({
|
|
|
24650
24627
|
const id = itemData.id || String(index);
|
|
24651
24628
|
const titleValue = getNestedValue(itemData, titleField?.name ?? "");
|
|
24652
24629
|
return wrapDnd(
|
|
24653
|
-
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick:
|
|
24630
|
+
/* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn(rowClickEvent && "cursor-pointer"), children: [
|
|
24654
24631
|
/* @__PURE__ */ jsxs(
|
|
24655
24632
|
Box,
|
|
24656
24633
|
{
|
|
@@ -33277,7 +33254,7 @@ var init_MapView = __esm({
|
|
|
33277
33254
|
shadowSize: [41, 41]
|
|
33278
33255
|
});
|
|
33279
33256
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
33280
|
-
const { useEffect: useEffect69, useRef: useRef65, useCallback: useCallback108, useState:
|
|
33257
|
+
const { useEffect: useEffect69, useRef: useRef65, useCallback: useCallback108, useState: useState106 } = React77__default;
|
|
33281
33258
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
33282
33259
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
33283
33260
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -33322,7 +33299,7 @@ var init_MapView = __esm({
|
|
|
33322
33299
|
showAttribution = true
|
|
33323
33300
|
}) {
|
|
33324
33301
|
const eventBus = useEventBus2();
|
|
33325
|
-
const [clickedPosition, setClickedPosition] =
|
|
33302
|
+
const [clickedPosition, setClickedPosition] = useState106(null);
|
|
33326
33303
|
const handleMapClick = useCallback108((lat, lng) => {
|
|
33327
33304
|
if (showClickedPin) {
|
|
33328
33305
|
setClickedPosition({ lat, lng });
|
|
@@ -37684,741 +37661,775 @@ var init_PositionedCanvas = __esm({
|
|
|
37684
37661
|
PositionedCanvas.displayName = "PositionedCanvas";
|
|
37685
37662
|
}
|
|
37686
37663
|
});
|
|
37687
|
-
function
|
|
37688
|
-
|
|
37689
|
-
|
|
37690
|
-
|
|
37691
|
-
|
|
37692
|
-
|
|
37693
|
-
if (!Array.isArray(raw) || raw.length === 0) return [createBlock("paragraph")];
|
|
37694
|
-
return raw.map((row) => {
|
|
37695
|
-
const entity = row;
|
|
37696
|
-
const rawType = entity.type;
|
|
37697
|
-
const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
|
|
37698
|
-
const id = typeof entity.id === "string" && entity.id ? entity.id : nextBlockId(type);
|
|
37699
|
-
return { ...entity, id, type };
|
|
37700
|
-
});
|
|
37701
|
-
}
|
|
37702
|
-
function createBlock(type) {
|
|
37703
|
-
switch (type) {
|
|
37704
|
-
case "bullet-list":
|
|
37705
|
-
case "numbered-list":
|
|
37706
|
-
return {
|
|
37707
|
-
id: nextBlockId(type),
|
|
37708
|
-
type,
|
|
37709
|
-
children: [
|
|
37710
|
-
{ id: nextBlockId("li"), type: "paragraph", content: "" }
|
|
37711
|
-
]
|
|
37712
|
-
};
|
|
37713
|
-
case "image":
|
|
37714
|
-
return {
|
|
37715
|
-
id: nextBlockId(type),
|
|
37716
|
-
type,
|
|
37717
|
-
content: "",
|
|
37718
|
-
metadata: { url: "", caption: "" }
|
|
37719
|
-
};
|
|
37720
|
-
case "code":
|
|
37721
|
-
return {
|
|
37722
|
-
id: nextBlockId(type),
|
|
37723
|
-
type,
|
|
37724
|
-
content: "",
|
|
37725
|
-
metadata: { language: "plaintext" }
|
|
37726
|
-
};
|
|
37727
|
-
case "divider":
|
|
37728
|
-
return { id: nextBlockId(type), type };
|
|
37729
|
-
default:
|
|
37730
|
-
return { id: nextBlockId(type), type, content: "" };
|
|
37664
|
+
function safeUrl(raw, kinds) {
|
|
37665
|
+
const url = raw.trim();
|
|
37666
|
+
if (url.startsWith("#") || url.startsWith("/")) return url;
|
|
37667
|
+
const lower = url.toLowerCase();
|
|
37668
|
+
for (const kind of kinds) {
|
|
37669
|
+
if (lower.startsWith(kind)) return url;
|
|
37731
37670
|
}
|
|
37671
|
+
return null;
|
|
37732
37672
|
}
|
|
37733
|
-
function
|
|
37734
|
-
|
|
37735
|
-
|
|
37736
|
-
|
|
37737
|
-
|
|
37738
|
-
|
|
37739
|
-
|
|
37740
|
-
return {
|
|
37741
|
-
...block,
|
|
37742
|
-
id: nextBlockId(block.type),
|
|
37743
|
-
children: block.children?.map((child) => ({
|
|
37744
|
-
...child,
|
|
37745
|
-
id: nextBlockId("li")
|
|
37746
|
-
})),
|
|
37747
|
-
metadata: block.metadata ? { ...block.metadata } : void 0
|
|
37748
|
-
};
|
|
37749
|
-
}
|
|
37750
|
-
function insertAfter(blocks, targetId, inserted) {
|
|
37751
|
-
const idx = blocks.findIndex((b) => b.id === targetId);
|
|
37752
|
-
if (idx === -1) return [...blocks, inserted];
|
|
37753
|
-
const next = blocks.slice();
|
|
37754
|
-
next.splice(idx + 1, 0, inserted);
|
|
37755
|
-
return next;
|
|
37756
|
-
}
|
|
37757
|
-
function changeBlockType(block, type) {
|
|
37758
|
-
if (block.type === type) return block;
|
|
37759
|
-
if (type === "bullet-list" || type === "numbered-list") {
|
|
37760
|
-
if (block.children && block.children.length > 0) {
|
|
37761
|
-
return { ...block, type };
|
|
37673
|
+
function sanitizeNode(el) {
|
|
37674
|
+
const children = Array.from(el.children);
|
|
37675
|
+
for (const child of children) {
|
|
37676
|
+
const tag = child.tagName.toLowerCase();
|
|
37677
|
+
if (DROP_TAGS.has(tag)) {
|
|
37678
|
+
child.remove();
|
|
37679
|
+
continue;
|
|
37762
37680
|
}
|
|
37763
|
-
const
|
|
37764
|
-
|
|
37765
|
-
|
|
37766
|
-
|
|
37767
|
-
|
|
37768
|
-
|
|
37769
|
-
|
|
37770
|
-
|
|
37771
|
-
|
|
37772
|
-
|
|
37773
|
-
|
|
37681
|
+
const allowed = ALLOWED_ATTRS[tag];
|
|
37682
|
+
if (!allowed) {
|
|
37683
|
+
sanitizeNode(child);
|
|
37684
|
+
child.replaceWith(...Array.from(child.childNodes));
|
|
37685
|
+
continue;
|
|
37686
|
+
}
|
|
37687
|
+
for (const attr of Array.from(child.attributes)) {
|
|
37688
|
+
const name = attr.name.toLowerCase();
|
|
37689
|
+
if (!allowed.includes(name)) {
|
|
37690
|
+
child.removeAttribute(attr.name);
|
|
37691
|
+
continue;
|
|
37692
|
+
}
|
|
37693
|
+
if (name === "href") {
|
|
37694
|
+
const url = safeUrl(attr.value, ["http://", "https://", "mailto:"]);
|
|
37695
|
+
if (url === null) child.removeAttribute(attr.name);
|
|
37696
|
+
else child.setAttribute("href", url);
|
|
37697
|
+
}
|
|
37698
|
+
if (name === "src") {
|
|
37699
|
+
const url = safeUrl(attr.value, ["http://", "https://", "data:image/"]);
|
|
37700
|
+
if (url === null) child.remove();
|
|
37701
|
+
else child.setAttribute("src", url);
|
|
37702
|
+
}
|
|
37703
|
+
}
|
|
37704
|
+
sanitizeNode(child);
|
|
37774
37705
|
}
|
|
37775
|
-
|
|
37776
|
-
|
|
37777
|
-
|
|
37778
|
-
|
|
37779
|
-
|
|
37780
|
-
|
|
37781
|
-
|
|
37706
|
+
}
|
|
37707
|
+
function sanitizeRichHtml(html) {
|
|
37708
|
+
if (!html || typeof html !== "string") return "";
|
|
37709
|
+
if (typeof window === "undefined" || typeof DOMParser === "undefined") return "";
|
|
37710
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
37711
|
+
sanitizeNode(doc.body);
|
|
37712
|
+
if (!doc.body.querySelector("img, hr") && (doc.body.textContent ?? "").trim().length === 0) {
|
|
37713
|
+
return "";
|
|
37782
37714
|
}
|
|
37783
|
-
|
|
37784
|
-
|
|
37785
|
-
|
|
37786
|
-
|
|
37787
|
-
|
|
37788
|
-
|
|
37789
|
-
|
|
37715
|
+
return doc.body.innerHTML.replace(//g, "");
|
|
37716
|
+
}
|
|
37717
|
+
function htmlIsEmpty(el) {
|
|
37718
|
+
if (el.querySelector("img, hr")) return false;
|
|
37719
|
+
return (el.textContent ?? "").trim().length === 0;
|
|
37720
|
+
}
|
|
37721
|
+
function closestBlock(node, root) {
|
|
37722
|
+
let cur = node;
|
|
37723
|
+
while (cur && cur !== root) {
|
|
37724
|
+
if (cur instanceof Element && BLOCK_TAGS.has(cur.tagName)) return cur;
|
|
37725
|
+
cur = cur.parentNode;
|
|
37790
37726
|
}
|
|
37791
|
-
|
|
37792
|
-
return { id: block.id, type, content: seed };
|
|
37727
|
+
return null;
|
|
37793
37728
|
}
|
|
37794
|
-
function
|
|
37795
|
-
|
|
37796
|
-
|
|
37797
|
-
|
|
37798
|
-
|
|
37799
|
-
|
|
37800
|
-
|
|
37801
|
-
|
|
37802
|
-
|
|
37729
|
+
function RichTextStyles() {
|
|
37730
|
+
return /* @__PURE__ */ jsx("style", { children: RICH_TEXT_CSS });
|
|
37731
|
+
}
|
|
37732
|
+
function readToolbarState(root) {
|
|
37733
|
+
const sel = window.getSelection();
|
|
37734
|
+
if (!sel || sel.rangeCount === 0) return IDLE_TOOLBAR;
|
|
37735
|
+
const anchor = sel.anchorNode;
|
|
37736
|
+
if (!anchor || !root.contains(anchor)) return IDLE_TOOLBAR;
|
|
37737
|
+
let block = null;
|
|
37738
|
+
let link = false;
|
|
37739
|
+
let node = anchor;
|
|
37740
|
+
while (node && node !== root) {
|
|
37741
|
+
if (node instanceof Element) {
|
|
37742
|
+
const tag = node.tagName.toLowerCase();
|
|
37743
|
+
if (!block && (tag === "h1" || tag === "h2" || tag === "h3" || tag === "blockquote" || tag === "pre")) {
|
|
37744
|
+
block = tag;
|
|
37803
37745
|
}
|
|
37746
|
+
if (tag === "a") link = true;
|
|
37804
37747
|
}
|
|
37805
|
-
|
|
37806
|
-
|
|
37807
|
-
|
|
37808
|
-
|
|
37809
|
-
|
|
37810
|
-
|
|
37811
|
-
|
|
37812
|
-
|
|
37813
|
-
|
|
37814
|
-
|
|
37815
|
-
|
|
37816
|
-
|
|
37817
|
-
"inline-flex items-center justify-center",
|
|
37818
|
-
"h-6 w-6 rounded-sm p-0 gap-0",
|
|
37819
|
-
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
37820
|
-
"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",
|
|
37821
|
-
"transition-opacity"
|
|
37822
|
-
),
|
|
37823
|
-
onClick: () => setOpen((v) => !v),
|
|
37824
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", className: "w-3.5 h-3.5" })
|
|
37825
|
-
}
|
|
37826
|
-
),
|
|
37827
|
-
open && /* @__PURE__ */ jsxs(
|
|
37828
|
-
Box,
|
|
37829
|
-
{
|
|
37830
|
-
role: "menu",
|
|
37831
|
-
className: cn(
|
|
37832
|
-
"absolute right-0 z-10 mt-1 w-44",
|
|
37833
|
-
"rounded-container border border-border bg-popover shadow-elevation-popover",
|
|
37834
|
-
"py-1 text-sm"
|
|
37835
|
-
),
|
|
37836
|
-
children: [
|
|
37837
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t(BLOCK_TYPE_LABEL_KEY[block.type]) }),
|
|
37838
|
-
/* @__PURE__ */ jsxs(
|
|
37839
|
-
Button,
|
|
37840
|
-
{
|
|
37841
|
-
type: "button",
|
|
37842
|
-
variant: "ghost",
|
|
37843
|
-
role: "menuitem",
|
|
37844
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
37845
|
-
onClick: () => {
|
|
37846
|
-
onDuplicate();
|
|
37847
|
-
setOpen(false);
|
|
37848
|
-
},
|
|
37849
|
-
children: [
|
|
37850
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3.5 h-3.5" }),
|
|
37851
|
-
" ",
|
|
37852
|
-
t("richBlockEditor.duplicate")
|
|
37853
|
-
]
|
|
37854
|
-
}
|
|
37855
|
-
),
|
|
37856
|
-
/* @__PURE__ */ jsxs(
|
|
37857
|
-
Button,
|
|
37858
|
-
{
|
|
37859
|
-
type: "button",
|
|
37860
|
-
variant: "ghost",
|
|
37861
|
-
role: "menuitem",
|
|
37862
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-destructive hover:bg-muted justify-start rounded-none",
|
|
37863
|
-
onClick: () => {
|
|
37864
|
-
onDelete();
|
|
37865
|
-
setOpen(false);
|
|
37866
|
-
},
|
|
37867
|
-
children: [
|
|
37868
|
-
/* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3.5 h-3.5" }),
|
|
37869
|
-
" ",
|
|
37870
|
-
t("common.delete")
|
|
37871
|
-
]
|
|
37872
|
-
}
|
|
37873
|
-
),
|
|
37874
|
-
CHANGEABLE_TYPES.includes(block.type) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
37875
|
-
/* @__PURE__ */ jsx(Box, { className: "my-1 border-t border-border" }),
|
|
37876
|
-
/* @__PURE__ */ jsx(Box, { className: "px-2 py-1 text-xs uppercase tracking-wide text-muted-foreground", children: t("richBlockEditor.turnInto") }),
|
|
37877
|
-
CHANGEABLE_TYPES.filter((bt) => bt !== block.type).map((bt) => /* @__PURE__ */ jsx(
|
|
37878
|
-
Button,
|
|
37879
|
-
{
|
|
37880
|
-
type: "button",
|
|
37881
|
-
variant: "ghost",
|
|
37882
|
-
role: "menuitem",
|
|
37883
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left justify-start rounded-none",
|
|
37884
|
-
onClick: () => {
|
|
37885
|
-
onChangeType(bt);
|
|
37886
|
-
setOpen(false);
|
|
37887
|
-
},
|
|
37888
|
-
children: t(BLOCK_TYPE_LABEL_KEY[bt])
|
|
37889
|
-
},
|
|
37890
|
-
bt
|
|
37891
|
-
))
|
|
37892
|
-
] })
|
|
37893
|
-
]
|
|
37894
|
-
}
|
|
37895
|
-
)
|
|
37896
|
-
] });
|
|
37748
|
+
node = node.parentNode;
|
|
37749
|
+
}
|
|
37750
|
+
return {
|
|
37751
|
+
bold: document.queryCommandState("bold"),
|
|
37752
|
+
italic: document.queryCommandState("italic"),
|
|
37753
|
+
underline: document.queryCommandState("underline"),
|
|
37754
|
+
strikeThrough: document.queryCommandState("strikeThrough"),
|
|
37755
|
+
block,
|
|
37756
|
+
bullets: document.queryCommandState("insertUnorderedList"),
|
|
37757
|
+
numbers: document.queryCommandState("insertOrderedList"),
|
|
37758
|
+
link
|
|
37759
|
+
};
|
|
37897
37760
|
}
|
|
37898
|
-
function
|
|
37899
|
-
tag,
|
|
37900
|
-
value,
|
|
37901
|
-
readOnly,
|
|
37902
|
-
placeholder,
|
|
37903
|
-
className,
|
|
37904
|
-
ariaLabel,
|
|
37905
|
-
onValueChange
|
|
37906
|
-
}) {
|
|
37907
|
-
const ref = useRef(null);
|
|
37908
|
-
useEffect(() => {
|
|
37909
|
-
const el = ref.current;
|
|
37910
|
-
if (!el) return;
|
|
37911
|
-
const isFocused = document.activeElement === el;
|
|
37912
|
-
if (!isFocused && el.textContent !== value) {
|
|
37913
|
-
el.textContent = value;
|
|
37914
|
-
}
|
|
37915
|
-
}, [value]);
|
|
37916
|
-
const handleInput = useCallback(
|
|
37917
|
-
(e) => {
|
|
37918
|
-
onValueChange(e.currentTarget.textContent ?? "");
|
|
37919
|
-
},
|
|
37920
|
-
[onValueChange]
|
|
37921
|
-
);
|
|
37761
|
+
function ToolbarButton({ icon: IconCmp, label, active, onExec }) {
|
|
37922
37762
|
return /* @__PURE__ */ jsx(
|
|
37923
|
-
|
|
37763
|
+
Button,
|
|
37924
37764
|
{
|
|
37925
|
-
|
|
37926
|
-
|
|
37927
|
-
|
|
37928
|
-
|
|
37929
|
-
|
|
37930
|
-
|
|
37931
|
-
"aria-multiline": "true",
|
|
37932
|
-
"data-placeholder": placeholder,
|
|
37765
|
+
type: "button",
|
|
37766
|
+
variant: "ghost",
|
|
37767
|
+
size: "sm",
|
|
37768
|
+
"aria-label": label,
|
|
37769
|
+
"aria-pressed": active,
|
|
37770
|
+
title: label,
|
|
37933
37771
|
className: cn(
|
|
37934
|
-
"
|
|
37935
|
-
"
|
|
37936
|
-
className
|
|
37772
|
+
"h-8 w-8 p-0 gap-0 justify-center",
|
|
37773
|
+
active && "bg-muted text-foreground"
|
|
37937
37774
|
),
|
|
37938
|
-
|
|
37775
|
+
onMouseDown: (e) => {
|
|
37776
|
+
e.preventDefault();
|
|
37777
|
+
onExec();
|
|
37778
|
+
},
|
|
37779
|
+
children: /* @__PURE__ */ jsx(IconCmp, { size: 15 })
|
|
37939
37780
|
}
|
|
37940
37781
|
);
|
|
37941
37782
|
}
|
|
37942
|
-
|
|
37943
|
-
|
|
37944
|
-
|
|
37945
|
-
|
|
37946
|
-
|
|
37947
|
-
|
|
37948
|
-
|
|
37949
|
-
|
|
37950
|
-
|
|
37951
|
-
|
|
37952
|
-
|
|
37953
|
-
|
|
37954
|
-
|
|
37955
|
-
|
|
37956
|
-
|
|
37957
|
-
|
|
37958
|
-
|
|
37959
|
-
|
|
37960
|
-
|
|
37961
|
-
|
|
37962
|
-
|
|
37963
|
-
|
|
37964
|
-
|
|
37965
|
-
|
|
37966
|
-
|
|
37967
|
-
|
|
37968
|
-
|
|
37969
|
-
|
|
37970
|
-
|
|
37971
|
-
|
|
37972
|
-
|
|
37973
|
-
|
|
37974
|
-
|
|
37975
|
-
|
|
37976
|
-
|
|
37977
|
-
|
|
37978
|
-
|
|
37979
|
-
|
|
37980
|
-
|
|
37981
|
-
|
|
37982
|
-
|
|
37983
|
-
|
|
37984
|
-
|
|
37985
|
-
|
|
37986
|
-
|
|
37987
|
-
|
|
37988
|
-
|
|
37989
|
-
|
|
37990
|
-
|
|
37991
|
-
|
|
37992
|
-
|
|
37993
|
-
|
|
37994
|
-
|
|
37995
|
-
|
|
37996
|
-
|
|
37997
|
-
|
|
37998
|
-
|
|
37999
|
-
|
|
38000
|
-
|
|
38001
|
-
|
|
38002
|
-
|
|
38003
|
-
|
|
38004
|
-
|
|
38005
|
-
|
|
38006
|
-
|
|
38007
|
-
|
|
38008
|
-
|
|
38009
|
-
|
|
38010
|
-
|
|
38011
|
-
|
|
38012
|
-
|
|
38013
|
-
|
|
38014
|
-
|
|
38015
|
-
|
|
38016
|
-
|
|
38017
|
-
|
|
38018
|
-
|
|
38019
|
-
|
|
38020
|
-
|
|
38021
|
-
|
|
38022
|
-
|
|
38023
|
-
|
|
38024
|
-
|
|
38025
|
-
|
|
38026
|
-
|
|
38027
|
-
|
|
38028
|
-
|
|
38029
|
-
|
|
38030
|
-
|
|
38031
|
-
|
|
38032
|
-
|
|
38033
|
-
|
|
38034
|
-
|
|
38035
|
-
|
|
38036
|
-
|
|
38037
|
-
|
|
38038
|
-
|
|
38039
|
-
|
|
38040
|
-
|
|
38041
|
-
|
|
38042
|
-
|
|
38043
|
-
|
|
38044
|
-
|
|
38045
|
-
|
|
38046
|
-
);
|
|
38047
|
-
|
|
38048
|
-
|
|
38049
|
-
|
|
38050
|
-
|
|
38051
|
-
|
|
38052
|
-
|
|
38053
|
-
|
|
38054
|
-
|
|
38055
|
-
|
|
38056
|
-
|
|
38057
|
-
|
|
38058
|
-
|
|
38059
|
-
|
|
38060
|
-
|
|
38061
|
-
|
|
38062
|
-
|
|
38063
|
-
|
|
38064
|
-
|
|
38065
|
-
|
|
38066
|
-
|
|
38067
|
-
|
|
38068
|
-
|
|
38069
|
-
|
|
38070
|
-
|
|
38071
|
-
|
|
38072
|
-
|
|
38073
|
-
|
|
38074
|
-
|
|
38075
|
-
|
|
38076
|
-
|
|
38077
|
-
|
|
38078
|
-
|
|
38079
|
-
|
|
38080
|
-
|
|
38081
|
-
|
|
38082
|
-
|
|
38083
|
-
|
|
38084
|
-
|
|
38085
|
-
|
|
38086
|
-
|
|
38087
|
-
|
|
37783
|
+
var CHANGE_DEBOUNCE_MS, ALLOWED_ATTRS, DROP_TAGS, MD_BLOCK_PREFIXES, BLOCK_TAGS, MD_INLINE_RULES, RICH_TEXT_CSS, IDLE_TOOLBAR, RichTextEditor;
|
|
37784
|
+
var init_RichTextEditor = __esm({
|
|
37785
|
+
"components/core/molecules/RichTextEditor.tsx"() {
|
|
37786
|
+
"use client";
|
|
37787
|
+
init_cn();
|
|
37788
|
+
init_Box();
|
|
37789
|
+
init_Button();
|
|
37790
|
+
init_useEventBus();
|
|
37791
|
+
CHANGE_DEBOUNCE_MS = 400;
|
|
37792
|
+
ALLOWED_ATTRS = {
|
|
37793
|
+
p: [],
|
|
37794
|
+
h1: [],
|
|
37795
|
+
h2: [],
|
|
37796
|
+
h3: [],
|
|
37797
|
+
h4: [],
|
|
37798
|
+
ul: [],
|
|
37799
|
+
ol: [],
|
|
37800
|
+
li: [],
|
|
37801
|
+
blockquote: [],
|
|
37802
|
+
pre: [],
|
|
37803
|
+
code: [],
|
|
37804
|
+
b: [],
|
|
37805
|
+
strong: [],
|
|
37806
|
+
i: [],
|
|
37807
|
+
em: [],
|
|
37808
|
+
u: [],
|
|
37809
|
+
s: [],
|
|
37810
|
+
strike: [],
|
|
37811
|
+
br: [],
|
|
37812
|
+
hr: [],
|
|
37813
|
+
div: [],
|
|
37814
|
+
span: [],
|
|
37815
|
+
a: ["href"],
|
|
37816
|
+
img: ["src", "alt"]
|
|
37817
|
+
};
|
|
37818
|
+
DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "iframe", "object", "embed", "link", "meta", "form", "input", "button", "textarea", "select"]);
|
|
37819
|
+
MD_BLOCK_PREFIXES = {
|
|
37820
|
+
"#": { kind: "block", tag: "h1" },
|
|
37821
|
+
"##": { kind: "block", tag: "h2" },
|
|
37822
|
+
"###": { kind: "block", tag: "h3" },
|
|
37823
|
+
">": { kind: "block", tag: "blockquote" },
|
|
37824
|
+
"```": { kind: "block", tag: "pre" },
|
|
37825
|
+
"-": { kind: "list", command: "insertUnorderedList" },
|
|
37826
|
+
"*": { kind: "list", command: "insertUnorderedList" },
|
|
37827
|
+
"1.": { kind: "list", command: "insertOrderedList" }
|
|
37828
|
+
};
|
|
37829
|
+
BLOCK_TAGS = /* @__PURE__ */ new Set(["P", "DIV", "LI", "H1", "H2", "H3", "H4", "BLOCKQUOTE", "PRE"]);
|
|
37830
|
+
MD_INLINE_RULES = [
|
|
37831
|
+
{ pattern: /\*\*([^*\n]+)\*\*$/, wrap: "strong" },
|
|
37832
|
+
{ pattern: /(^|[^*])\*([^*\n]+)\*$/, wrap: "em" },
|
|
37833
|
+
{ pattern: /`([^`\n]+)`$/, wrap: "code" }
|
|
37834
|
+
];
|
|
37835
|
+
RICH_TEXT_CSS = `
|
|
37836
|
+
.almadar-rich-text { line-height: 1.7; color: var(--color-foreground); }
|
|
37837
|
+
.almadar-rich-text h1 { font-size: 1.875rem; font-weight: 700; line-height: 1.25; margin: 1.25em 0 0.4em; }
|
|
37838
|
+
.almadar-rich-text h2 { font-size: 1.5rem; font-weight: 650; line-height: 1.3; margin: 1.1em 0 0.4em; }
|
|
37839
|
+
.almadar-rich-text h3 { font-size: 1.25rem; font-weight: 600; line-height: 1.35; margin: 1em 0 0.35em; }
|
|
37840
|
+
.almadar-rich-text h1:first-child, .almadar-rich-text h2:first-child, .almadar-rich-text h3:first-child { margin-top: 0; }
|
|
37841
|
+
.almadar-rich-text p { margin: 0.5em 0; }
|
|
37842
|
+
.almadar-rich-text ul { list-style: disc; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
37843
|
+
.almadar-rich-text ol { list-style: decimal; padding-inline-start: 1.5rem; margin: 0.5em 0; }
|
|
37844
|
+
.almadar-rich-text li { margin: 0.25em 0; }
|
|
37845
|
+
.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; }
|
|
37846
|
+
.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; }
|
|
37847
|
+
.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; }
|
|
37848
|
+
.almadar-rich-text pre code { background: transparent; padding: 0; }
|
|
37849
|
+
.almadar-rich-text a { color: var(--color-primary); text-decoration: underline; }
|
|
37850
|
+
.almadar-rich-text hr { border: none; border-top: 1px solid var(--color-border); margin: 1.25em 0; }
|
|
37851
|
+
.almadar-rich-text img { max-width: 100%; border-radius: 0.375rem; }
|
|
37852
|
+
`;
|
|
37853
|
+
IDLE_TOOLBAR = {
|
|
37854
|
+
bold: false,
|
|
37855
|
+
italic: false,
|
|
37856
|
+
underline: false,
|
|
37857
|
+
strikeThrough: false,
|
|
37858
|
+
block: null,
|
|
37859
|
+
bullets: false,
|
|
37860
|
+
numbers: false,
|
|
37861
|
+
link: false
|
|
37862
|
+
};
|
|
37863
|
+
RichTextEditor = ({
|
|
37864
|
+
value,
|
|
37865
|
+
onChange,
|
|
37866
|
+
changeEvent,
|
|
37867
|
+
readOnly = false,
|
|
37868
|
+
placeholder,
|
|
37869
|
+
showToolbar = true,
|
|
37870
|
+
className
|
|
37871
|
+
}) => {
|
|
37872
|
+
const { t } = useTranslate();
|
|
37873
|
+
const ref = useRef(null);
|
|
37874
|
+
const [toolbar, setToolbar] = useState(IDLE_TOOLBAR);
|
|
37875
|
+
const [empty, setEmpty] = useState(() => !value || !sanitizeRichHtml(value).trim());
|
|
37876
|
+
const eventBus = useEventBus();
|
|
37877
|
+
const onChangeRef = useRef(onChange);
|
|
37878
|
+
const changeEventRef = useRef(changeEvent);
|
|
37879
|
+
useEffect(() => {
|
|
37880
|
+
onChangeRef.current = onChange;
|
|
37881
|
+
changeEventRef.current = changeEvent;
|
|
37882
|
+
}, [onChange, changeEvent]);
|
|
37883
|
+
const emitTimerRef = useRef(null);
|
|
37884
|
+
const emitNow = useCallback(() => {
|
|
37885
|
+
const el = ref.current;
|
|
37886
|
+
if (!el) return;
|
|
37887
|
+
const html = sanitizeRichHtml(el.innerHTML);
|
|
37888
|
+
onChangeRef.current?.(html);
|
|
37889
|
+
const evt = changeEventRef.current;
|
|
37890
|
+
if (evt) eventBus.emit(`UI:${evt}`, { value: html });
|
|
37891
|
+
}, [eventBus]);
|
|
37892
|
+
const scheduleEmit = useCallback(() => {
|
|
37893
|
+
if (emitTimerRef.current) clearTimeout(emitTimerRef.current);
|
|
37894
|
+
emitTimerRef.current = setTimeout(() => {
|
|
37895
|
+
emitTimerRef.current = null;
|
|
37896
|
+
emitNow();
|
|
37897
|
+
}, CHANGE_DEBOUNCE_MS);
|
|
37898
|
+
}, [emitNow]);
|
|
37899
|
+
const flushEmit = useCallback(() => {
|
|
37900
|
+
if (!emitTimerRef.current) return;
|
|
37901
|
+
clearTimeout(emitTimerRef.current);
|
|
37902
|
+
emitTimerRef.current = null;
|
|
37903
|
+
emitNow();
|
|
37904
|
+
}, [emitNow]);
|
|
37905
|
+
useEffect(() => () => {
|
|
37906
|
+
if (emitTimerRef.current) {
|
|
37907
|
+
clearTimeout(emitTimerRef.current);
|
|
37908
|
+
emitTimerRef.current = null;
|
|
37909
|
+
emitNow();
|
|
37910
|
+
}
|
|
37911
|
+
}, [emitNow]);
|
|
37912
|
+
useEffect(() => {
|
|
37913
|
+
if (readOnly) return;
|
|
37914
|
+
const el = ref.current;
|
|
37915
|
+
if (!el) return;
|
|
37916
|
+
if (document.activeElement === el) return;
|
|
37917
|
+
const next = sanitizeRichHtml(value ?? "") || "<p><br></p>";
|
|
37918
|
+
if (el.innerHTML !== next) {
|
|
37919
|
+
el.innerHTML = next;
|
|
37920
|
+
setEmpty(htmlIsEmpty(el));
|
|
37921
|
+
}
|
|
37922
|
+
}, [readOnly, value]);
|
|
37923
|
+
useEffect(() => {
|
|
37924
|
+
if (readOnly) return;
|
|
37925
|
+
document.execCommand("defaultParagraphSeparator", false, "p");
|
|
37926
|
+
}, [readOnly]);
|
|
37927
|
+
useEffect(() => {
|
|
37928
|
+
if (readOnly || !showToolbar) return;
|
|
37929
|
+
const onSelectionChange = () => {
|
|
37930
|
+
const el = ref.current;
|
|
37931
|
+
if (!el) return;
|
|
37932
|
+
setToolbar(readToolbarState(el));
|
|
38088
37933
|
};
|
|
38089
|
-
|
|
38090
|
-
|
|
38091
|
-
|
|
38092
|
-
|
|
38093
|
-
|
|
38094
|
-
|
|
38095
|
-
|
|
38096
|
-
|
|
38097
|
-
|
|
38098
|
-
|
|
38099
|
-
|
|
38100
|
-
|
|
38101
|
-
|
|
38102
|
-
|
|
38103
|
-
|
|
38104
|
-
|
|
38105
|
-
!
|
|
38106
|
-
|
|
38107
|
-
|
|
38108
|
-
|
|
38109
|
-
|
|
38110
|
-
|
|
38111
|
-
|
|
38112
|
-
|
|
38113
|
-
|
|
38114
|
-
|
|
38115
|
-
|
|
38116
|
-
|
|
38117
|
-
|
|
38118
|
-
|
|
38119
|
-
|
|
38120
|
-
|
|
38121
|
-
|
|
38122
|
-
|
|
38123
|
-
|
|
38124
|
-
|
|
38125
|
-
|
|
38126
|
-
|
|
38127
|
-
|
|
38128
|
-
|
|
38129
|
-
|
|
38130
|
-
|
|
38131
|
-
|
|
38132
|
-
|
|
38133
|
-
|
|
38134
|
-
|
|
38135
|
-
|
|
37934
|
+
document.addEventListener("selectionchange", onSelectionChange);
|
|
37935
|
+
return () => document.removeEventListener("selectionchange", onSelectionChange);
|
|
37936
|
+
}, [readOnly, showToolbar]);
|
|
37937
|
+
const tryInlineMarkdown = useCallback(() => {
|
|
37938
|
+
const root = ref.current;
|
|
37939
|
+
if (!root) return false;
|
|
37940
|
+
const sel = window.getSelection();
|
|
37941
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
37942
|
+
const node = sel.anchorNode;
|
|
37943
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
37944
|
+
if (node.parentElement?.closest("code, pre")) return false;
|
|
37945
|
+
const text = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
37946
|
+
for (const rule of MD_INLINE_RULES) {
|
|
37947
|
+
const m = rule.pattern.exec(text);
|
|
37948
|
+
if (!m) continue;
|
|
37949
|
+
const inner = rule.wrap === "em" ? m[2] : m[1];
|
|
37950
|
+
if (!inner || !inner.trim()) continue;
|
|
37951
|
+
const lead = rule.wrap === "em" ? m[1]?.length ?? 0 : 0;
|
|
37952
|
+
const range = document.createRange();
|
|
37953
|
+
range.setStart(node, m.index + lead);
|
|
37954
|
+
range.setEnd(node, sel.anchorOffset);
|
|
37955
|
+
const el = document.createElement(rule.wrap);
|
|
37956
|
+
el.textContent = inner;
|
|
37957
|
+
range.deleteContents();
|
|
37958
|
+
range.insertNode(el);
|
|
37959
|
+
const after = document.createTextNode("\u200B");
|
|
37960
|
+
el.parentNode?.insertBefore(after, el.nextSibling);
|
|
37961
|
+
const caret = document.createRange();
|
|
37962
|
+
caret.setStart(after, 1);
|
|
37963
|
+
caret.collapse(true);
|
|
37964
|
+
sel.removeAllRanges();
|
|
37965
|
+
sel.addRange(caret);
|
|
37966
|
+
return true;
|
|
37967
|
+
}
|
|
37968
|
+
return false;
|
|
37969
|
+
}, []);
|
|
37970
|
+
const tryBlockMarkdown = useCallback(() => {
|
|
37971
|
+
const root = ref.current;
|
|
37972
|
+
if (!root) return false;
|
|
37973
|
+
const sel = window.getSelection();
|
|
37974
|
+
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return false;
|
|
37975
|
+
const node = sel.anchorNode;
|
|
37976
|
+
if (!node || node.nodeType !== Node.TEXT_NODE || !root.contains(node)) return false;
|
|
37977
|
+
const block = closestBlock(node, root);
|
|
37978
|
+
if (block ? block.firstChild !== node : root.firstChild !== node) return false;
|
|
37979
|
+
const prefix = (node.textContent ?? "").slice(0, sel.anchorOffset);
|
|
37980
|
+
const rule = MD_BLOCK_PREFIXES[prefix];
|
|
37981
|
+
if (!rule) return false;
|
|
37982
|
+
if (node.parentElement?.closest("pre, code")) return false;
|
|
37983
|
+
if (rule.kind === "list" && node.parentElement?.closest("li")) return false;
|
|
37984
|
+
node.deleteData(0, prefix.length);
|
|
37985
|
+
const caret = document.createRange();
|
|
37986
|
+
caret.setStart(node, 0);
|
|
37987
|
+
caret.collapse(true);
|
|
37988
|
+
sel.removeAllRanges();
|
|
37989
|
+
sel.addRange(caret);
|
|
37990
|
+
if (rule.kind === "list") {
|
|
37991
|
+
const container = block ?? node.parentElement;
|
|
37992
|
+
const list = document.createElement(rule.command === "insertOrderedList" ? "ol" : "ul");
|
|
37993
|
+
const li = document.createElement("li");
|
|
37994
|
+
if (block) {
|
|
37995
|
+
while (block.firstChild) li.appendChild(block.firstChild);
|
|
37996
|
+
list.appendChild(li);
|
|
37997
|
+
block.replaceWith(list);
|
|
37998
|
+
} else if (container) {
|
|
37999
|
+
li.appendChild(node);
|
|
38000
|
+
list.appendChild(li);
|
|
38001
|
+
container.appendChild(list);
|
|
38002
|
+
}
|
|
38003
|
+
if (!li.firstChild) li.appendChild(document.createElement("br"));
|
|
38004
|
+
const liCaret = document.createRange();
|
|
38005
|
+
liCaret.selectNodeContents(li);
|
|
38006
|
+
liCaret.collapse(true);
|
|
38007
|
+
sel.removeAllRanges();
|
|
38008
|
+
sel.addRange(liCaret);
|
|
38009
|
+
} else {
|
|
38010
|
+
document.execCommand("formatBlock", false, rule.tag);
|
|
38011
|
+
}
|
|
38012
|
+
return true;
|
|
38013
|
+
}, []);
|
|
38014
|
+
const afterEdit = useCallback(() => {
|
|
38015
|
+
const el = ref.current;
|
|
38016
|
+
if (!el) return;
|
|
38017
|
+
tryInlineMarkdown();
|
|
38018
|
+
setEmpty(htmlIsEmpty(el));
|
|
38019
|
+
setToolbar(readToolbarState(el));
|
|
38020
|
+
scheduleEmit();
|
|
38021
|
+
}, [scheduleEmit, tryInlineMarkdown]);
|
|
38022
|
+
const handleKeyDown = useCallback((e) => {
|
|
38023
|
+
if (e.key === " " && tryBlockMarkdown()) {
|
|
38024
|
+
e.preventDefault();
|
|
38025
|
+
afterEdit();
|
|
38026
|
+
}
|
|
38027
|
+
}, [afterEdit, tryBlockMarkdown]);
|
|
38028
|
+
const execInline = useCallback((command) => {
|
|
38029
|
+
document.execCommand(command, false);
|
|
38030
|
+
afterEdit();
|
|
38031
|
+
}, [afterEdit]);
|
|
38032
|
+
const execBlock = useCallback((tag) => {
|
|
38033
|
+
const next = toolbar.block === tag ? "p" : tag;
|
|
38034
|
+
document.execCommand("formatBlock", false, next);
|
|
38035
|
+
afterEdit();
|
|
38036
|
+
}, [afterEdit, toolbar.block]);
|
|
38037
|
+
const execList = useCallback((command) => {
|
|
38038
|
+
document.execCommand(command, false);
|
|
38039
|
+
afterEdit();
|
|
38040
|
+
}, [afterEdit]);
|
|
38041
|
+
const execLink = useCallback(() => {
|
|
38042
|
+
if (toolbar.link) {
|
|
38043
|
+
document.execCommand("unlink", false);
|
|
38044
|
+
afterEdit();
|
|
38045
|
+
return;
|
|
38046
|
+
}
|
|
38047
|
+
const url = window.prompt(t("richTextEditor.linkPrompt"));
|
|
38048
|
+
if (!url) return;
|
|
38049
|
+
const safe = safeUrl(url, ["http://", "https://", "mailto:"]) ?? `https://${url}`;
|
|
38050
|
+
document.execCommand("createLink", false, safe);
|
|
38051
|
+
afterEdit();
|
|
38052
|
+
}, [afterEdit, t, toolbar.link]);
|
|
38053
|
+
const execRule = useCallback(() => {
|
|
38054
|
+
document.execCommand("insertHorizontalRule", false);
|
|
38055
|
+
afterEdit();
|
|
38056
|
+
}, [afterEdit]);
|
|
38057
|
+
if (readOnly) {
|
|
38058
|
+
return /* @__PURE__ */ jsxs(Box, { className: cn("almadar-rich-text max-w-none", className), children: [
|
|
38059
|
+
/* @__PURE__ */ jsx(RichTextStyles, {}),
|
|
38060
|
+
/* @__PURE__ */ jsx(Box, { dangerouslySetInnerHTML: { __html: sanitizeRichHtml(value ?? "") } })
|
|
38136
38061
|
] });
|
|
38137
38062
|
}
|
|
38138
|
-
|
|
38139
|
-
|
|
38140
|
-
|
|
38141
|
-
return /* @__PURE__ */ jsxs(
|
|
38063
|
+
return /* @__PURE__ */ jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
|
|
38064
|
+
/* @__PURE__ */ jsx(RichTextStyles, {}),
|
|
38065
|
+
showToolbar && /* @__PURE__ */ jsxs(
|
|
38142
38066
|
Box,
|
|
38143
38067
|
{
|
|
38144
|
-
|
|
38068
|
+
role: "toolbar",
|
|
38069
|
+
"aria-label": t("richTextEditor.editorToolbar"),
|
|
38145
38070
|
className: cn(
|
|
38146
|
-
"
|
|
38147
|
-
|
|
38071
|
+
"sticky top-0 z-10 flex flex-wrap items-center gap-0.5 self-start",
|
|
38072
|
+
"rounded-md border border-border bg-background/95 px-1 py-0.5 shadow-sm"
|
|
38148
38073
|
),
|
|
38149
38074
|
children: [
|
|
38150
|
-
|
|
38151
|
-
|
|
38152
|
-
|
|
38153
|
-
|
|
38154
|
-
|
|
38155
|
-
|
|
38156
|
-
|
|
38157
|
-
|
|
38158
|
-
|
|
38159
|
-
|
|
38160
|
-
|
|
38161
|
-
|
|
38162
|
-
|
|
38163
|
-
|
|
38164
|
-
|
|
38165
|
-
|
|
38166
|
-
type: "button",
|
|
38167
|
-
variant: "ghost",
|
|
38168
|
-
"aria-label": t("richBlockEditor.aria.removeListItem"),
|
|
38169
|
-
className: cn(
|
|
38170
|
-
"h-5 w-5 shrink-0 rounded-sm text-muted-foreground p-0 gap-0",
|
|
38171
|
-
"opacity-0 group-hover/item:opacity-100 hover:bg-muted hover:text-foreground"
|
|
38172
|
-
),
|
|
38173
|
-
onClick: () => removeListItem(child.id),
|
|
38174
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "trash", className: "w-3 h-3" })
|
|
38175
|
-
}
|
|
38176
|
-
)
|
|
38177
|
-
] }, child.id)),
|
|
38178
|
-
!readOnly && showAffordances && /* @__PURE__ */ jsx(Box, { as: "li", className: "list-none pl-0", children: /* @__PURE__ */ jsxs(
|
|
38179
|
-
Button,
|
|
38180
|
-
{
|
|
38181
|
-
type: "button",
|
|
38182
|
-
variant: "ghost",
|
|
38183
|
-
className: cn(
|
|
38184
|
-
"inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
38185
|
-
"hover:text-foreground p-0 h-auto"
|
|
38186
|
-
),
|
|
38187
|
-
onClick: addListItem,
|
|
38188
|
-
children: [
|
|
38189
|
-
/* @__PURE__ */ jsx(Icon, { name: "plus", className: "w-3 h-3" }),
|
|
38190
|
-
" ",
|
|
38191
|
-
t("richBlockEditor.addItem")
|
|
38192
|
-
]
|
|
38193
|
-
}
|
|
38194
|
-
) })
|
|
38075
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Bold, label: t("richTextEditor.bold"), active: toolbar.bold, onExec: () => execInline("bold") }),
|
|
38076
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Italic, label: t("richTextEditor.italic"), active: toolbar.italic, onExec: () => execInline("italic") }),
|
|
38077
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Underline, label: t("richTextEditor.underline"), active: toolbar.underline, onExec: () => execInline("underline") }),
|
|
38078
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Strikethrough, label: t("richTextEditor.strikethrough"), active: toolbar.strikeThrough, onExec: () => execInline("strikeThrough") }),
|
|
38079
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
38080
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading1, label: t("richTextEditor.heading1"), active: toolbar.block === "h1", onExec: () => execBlock("h1") }),
|
|
38081
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading2, label: t("richTextEditor.heading2"), active: toolbar.block === "h2", onExec: () => execBlock("h2") }),
|
|
38082
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Heading3, label: t("richTextEditor.heading3"), active: toolbar.block === "h3", onExec: () => execBlock("h3") }),
|
|
38083
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
38084
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: List, label: t("richTextEditor.bulletList"), active: toolbar.bullets, onExec: () => execList("insertUnorderedList") }),
|
|
38085
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: ListOrdered, label: t("richTextEditor.numberedList"), active: toolbar.numbers, onExec: () => execList("insertOrderedList") }),
|
|
38086
|
+
/* @__PURE__ */ jsx(Box, { className: "mx-1 h-5 w-px bg-border" }),
|
|
38087
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Quote, label: t("richTextEditor.quote"), active: toolbar.block === "blockquote", onExec: () => execBlock("blockquote") }),
|
|
38088
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Code, label: t("richTextEditor.code"), active: toolbar.block === "pre", onExec: () => execBlock("pre") }),
|
|
38089
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Link$1, label: toolbar.link ? t("richTextEditor.removeLink") : t("richTextEditor.link"), active: toolbar.link, onExec: execLink }),
|
|
38090
|
+
/* @__PURE__ */ jsx(ToolbarButton, { icon: Minus, label: t("richTextEditor.divider"), onExec: execRule })
|
|
38195
38091
|
]
|
|
38196
38092
|
}
|
|
38197
|
-
)
|
|
38198
|
-
|
|
38199
|
-
|
|
38200
|
-
default:
|
|
38201
|
-
return /* @__PURE__ */ jsx(
|
|
38202
|
-
Editable,
|
|
38093
|
+
),
|
|
38094
|
+
/* @__PURE__ */ jsx(
|
|
38095
|
+
Box,
|
|
38203
38096
|
{
|
|
38204
|
-
|
|
38205
|
-
|
|
38206
|
-
|
|
38207
|
-
|
|
38208
|
-
|
|
38209
|
-
|
|
38210
|
-
|
|
38097
|
+
ref,
|
|
38098
|
+
contentEditable: true,
|
|
38099
|
+
suppressContentEditableWarning: true,
|
|
38100
|
+
role: "textbox",
|
|
38101
|
+
"aria-multiline": "true",
|
|
38102
|
+
"aria-label": t("richTextEditor.editorSurface"),
|
|
38103
|
+
"data-placeholder": placeholder ?? t("richTextEditor.placeholder"),
|
|
38104
|
+
"data-empty": empty ? "true" : "false",
|
|
38105
|
+
className: cn(
|
|
38106
|
+
"almadar-rich-text max-w-none min-h-[8rem] outline-none",
|
|
38107
|
+
"data-[empty=true]:before:content-[attr(data-placeholder)]",
|
|
38108
|
+
"data-[empty=true]:before:text-muted-foreground/60",
|
|
38109
|
+
"data-[empty=true]:before:pointer-events-none",
|
|
38110
|
+
"data-[empty=true]:before:absolute",
|
|
38111
|
+
"relative cursor-text"
|
|
38112
|
+
),
|
|
38113
|
+
onInput: afterEdit,
|
|
38114
|
+
onKeyDown: handleKeyDown,
|
|
38115
|
+
onBlur: flushEmit
|
|
38211
38116
|
}
|
|
38212
|
-
)
|
|
38213
|
-
|
|
38117
|
+
)
|
|
38118
|
+
] });
|
|
38119
|
+
};
|
|
38120
|
+
RichTextEditor.displayName = "RichTextEditor";
|
|
38121
|
+
}
|
|
38122
|
+
});
|
|
38123
|
+
function renderIconInput4(icon, props) {
|
|
38124
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
|
|
38125
|
+
}
|
|
38126
|
+
function DocumentPanel({
|
|
38127
|
+
entity,
|
|
38128
|
+
title,
|
|
38129
|
+
subtitle,
|
|
38130
|
+
value,
|
|
38131
|
+
actions,
|
|
38132
|
+
maxInlineActions,
|
|
38133
|
+
editing = false,
|
|
38134
|
+
titleCommitEvent,
|
|
38135
|
+
contentChangeEvent,
|
|
38136
|
+
editEvent,
|
|
38137
|
+
doneEvent,
|
|
38138
|
+
editLabel,
|
|
38139
|
+
doneLabel,
|
|
38140
|
+
autosaveHint,
|
|
38141
|
+
placeholder,
|
|
38142
|
+
className
|
|
38143
|
+
}) {
|
|
38144
|
+
const eventBus = useEventBus();
|
|
38145
|
+
const { t } = useTranslate();
|
|
38146
|
+
const [titleDraft, setTitleDraft] = useState(null);
|
|
38147
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
38148
|
+
const actionDefs = actions ?? [];
|
|
38149
|
+
const inlineCap = Math.min(maxInlineActions ?? 1, 1);
|
|
38150
|
+
const inlineActions = actionDefs.filter((a) => a.variant === "primary").slice(0, inlineCap);
|
|
38151
|
+
const menuActions = actionDefs.filter((a) => !inlineActions.includes(a));
|
|
38152
|
+
const fireAction = (action) => {
|
|
38153
|
+
if (!action.event) return;
|
|
38154
|
+
eventBus.emit(`UI:${action.event}`, { id: recordId, row: entity });
|
|
38214
38155
|
};
|
|
38215
|
-
|
|
38156
|
+
const commitTitle = () => {
|
|
38157
|
+
if (!titleCommitEvent) return;
|
|
38158
|
+
const next = (titleDraft ?? "").trim();
|
|
38159
|
+
setTitleDraft(null);
|
|
38160
|
+
if (!next || next === title) return;
|
|
38161
|
+
eventBus.emit(`UI:${titleCommitEvent}`, { title: next, id: recordId });
|
|
38162
|
+
};
|
|
38163
|
+
const untitled = t("documentPanel.untitled") || "Untitled";
|
|
38164
|
+
const titleNode = titleCommitEvent && titleDraft !== null ? /* @__PURE__ */ jsx(
|
|
38165
|
+
Input,
|
|
38166
|
+
{
|
|
38167
|
+
value: titleDraft,
|
|
38168
|
+
autoFocus: true,
|
|
38169
|
+
"aria-label": t("common.title"),
|
|
38170
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
38171
|
+
onFocus: (e) => e.currentTarget.select(),
|
|
38172
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
38173
|
+
onBlur: commitTitle,
|
|
38174
|
+
onKeyDown: (e) => {
|
|
38175
|
+
if (e.key === "Enter") {
|
|
38176
|
+
e.preventDefault();
|
|
38177
|
+
commitTitle();
|
|
38178
|
+
} else if (e.key === "Escape") {
|
|
38179
|
+
e.preventDefault();
|
|
38180
|
+
setTitleDraft(null);
|
|
38181
|
+
}
|
|
38182
|
+
},
|
|
38183
|
+
"data-testid": "document-title-input"
|
|
38184
|
+
}
|
|
38185
|
+
) : titleCommitEvent ? /* @__PURE__ */ jsx(
|
|
38216
38186
|
Box,
|
|
38217
38187
|
{
|
|
38218
|
-
|
|
38219
|
-
|
|
38220
|
-
|
|
38221
|
-
),
|
|
38222
|
-
|
|
38223
|
-
|
|
38224
|
-
|
|
38225
|
-
|
|
38226
|
-
|
|
38188
|
+
role: "button",
|
|
38189
|
+
tabIndex: 0,
|
|
38190
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
38191
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
38192
|
+
onKeyDown: (e) => {
|
|
38193
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
38194
|
+
e.preventDefault();
|
|
38195
|
+
setTitleDraft(title ?? "");
|
|
38196
|
+
}
|
|
38197
|
+
},
|
|
38198
|
+
"data-testid": "document-title-editable",
|
|
38199
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", className: cn(!title && "text-muted-foreground"), children: title || untitled })
|
|
38200
|
+
}
|
|
38201
|
+
) : /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || untitled });
|
|
38202
|
+
const emitWithId = (event) => () => {
|
|
38203
|
+
if (event) eventBus.emit(`UI:${event}`, { id: recordId });
|
|
38204
|
+
};
|
|
38205
|
+
return /* @__PURE__ */ jsx(Card, { variant: "elevated", className: cn("w-full", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-6 sm:p-8", children: [
|
|
38206
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
|
|
38207
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
38208
|
+
titleNode,
|
|
38209
|
+
subtitle ? /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: subtitle }) : null
|
|
38210
|
+
] }),
|
|
38211
|
+
/* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0 pt-1 items-center", children: editing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38212
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", className: "hidden sm:block", children: autosaveHint ?? (t("documentPanel.autosaveHint") || "") }),
|
|
38213
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: emitWithId(doneEvent), "data-testid": "document-done", children: doneLabel ?? (t("documentPanel.done") || "Done") })
|
|
38214
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38215
|
+
editEvent && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: emitWithId(editEvent), "data-testid": "document-edit", children: [
|
|
38216
|
+
/* @__PURE__ */ jsx(Icon, { name: "edit", size: "xs", className: "mr-1" }),
|
|
38217
|
+
editLabel ?? (t("documentPanel.edit") || "Edit")
|
|
38218
|
+
] }),
|
|
38219
|
+
inlineActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
38220
|
+
Button,
|
|
38227
38221
|
{
|
|
38228
|
-
|
|
38229
|
-
|
|
38230
|
-
|
|
38231
|
-
|
|
38232
|
-
|
|
38222
|
+
variant: "primary",
|
|
38223
|
+
size: "sm",
|
|
38224
|
+
onClick: () => fireAction(action),
|
|
38225
|
+
"data-testid": `action-${action.event}`,
|
|
38226
|
+
children: [
|
|
38227
|
+
action.icon && renderIconInput4(action.icon, { size: "xs", className: "mr-1" }),
|
|
38228
|
+
action.label
|
|
38229
|
+
]
|
|
38230
|
+
},
|
|
38231
|
+
idx
|
|
38232
|
+
)),
|
|
38233
|
+
menuActions.length > 0 && /* @__PURE__ */ jsx(
|
|
38234
|
+
Menu,
|
|
38235
|
+
{
|
|
38236
|
+
position: "bottom-end",
|
|
38237
|
+
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" }) }),
|
|
38238
|
+
items: menuActions.map((action) => ({
|
|
38239
|
+
label: action.label,
|
|
38240
|
+
icon: action.icon,
|
|
38241
|
+
variant: action.variant === "danger" ? "danger" : "default",
|
|
38242
|
+
onClick: () => fireAction(action)
|
|
38243
|
+
}))
|
|
38233
38244
|
}
|
|
38234
|
-
)
|
|
38235
|
-
|
|
38236
|
-
|
|
38237
|
-
}
|
|
38238
|
-
|
|
38245
|
+
)
|
|
38246
|
+
] }) })
|
|
38247
|
+
] }),
|
|
38248
|
+
editing ? /* @__PURE__ */ jsx(RichTextEditor, { value, changeEvent: contentChangeEvent, placeholder }) : /* @__PURE__ */ jsx(
|
|
38249
|
+
Box,
|
|
38250
|
+
{
|
|
38251
|
+
onClick: emitWithId(editEvent),
|
|
38252
|
+
className: cn(
|
|
38253
|
+
"rounded-md px-1 -mx-1 min-h-[16rem]",
|
|
38254
|
+
editEvent && "cursor-text transition-colors hover:bg-muted/30"
|
|
38255
|
+
),
|
|
38256
|
+
"data-testid": "document-body",
|
|
38257
|
+
children: value && value !== "" ? /* @__PURE__ */ jsx(RichTextEditor, { value, readOnly: true }) : /* @__PURE__ */ jsx(Typography, { variant: "body", color: "muted", children: placeholder ?? (t("documentPanel.placeholder") || "") })
|
|
38258
|
+
}
|
|
38259
|
+
)
|
|
38260
|
+
] }) });
|
|
38239
38261
|
}
|
|
38240
|
-
var
|
|
38241
|
-
|
|
38242
|
-
"components/core/molecules/RichBlockEditor.tsx"() {
|
|
38262
|
+
var init_DocumentPanel = __esm({
|
|
38263
|
+
"components/core/molecules/DocumentPanel.tsx"() {
|
|
38243
38264
|
"use client";
|
|
38244
38265
|
init_cn();
|
|
38245
|
-
|
|
38266
|
+
init_useEventBus();
|
|
38267
|
+
init_Box();
|
|
38268
|
+
init_Stack();
|
|
38246
38269
|
init_Typography();
|
|
38247
38270
|
init_Button();
|
|
38248
|
-
|
|
38249
|
-
init_Divider();
|
|
38250
|
-
init_Input();
|
|
38271
|
+
init_Card();
|
|
38251
38272
|
init_Icon();
|
|
38252
|
-
|
|
38253
|
-
|
|
38254
|
-
|
|
38255
|
-
|
|
38256
|
-
|
|
38257
|
-
|
|
38258
|
-
|
|
38259
|
-
|
|
38260
|
-
|
|
38261
|
-
|
|
38262
|
-
|
|
38263
|
-
|
|
38264
|
-
|
|
38265
|
-
|
|
38266
|
-
|
|
38267
|
-
|
|
38268
|
-
|
|
38269
|
-
|
|
38270
|
-
|
|
38271
|
-
|
|
38272
|
-
|
|
38273
|
-
|
|
38274
|
-
|
|
38275
|
-
|
|
38276
|
-
|
|
38277
|
-
|
|
38278
|
-
|
|
38279
|
-
|
|
38280
|
-
|
|
38281
|
-
|
|
38282
|
-
|
|
38283
|
-
|
|
38284
|
-
|
|
38285
|
-
|
|
38286
|
-
|
|
38287
|
-
|
|
38288
|
-
|
|
38289
|
-
|
|
38290
|
-
|
|
38291
|
-
|
|
38292
|
-
|
|
38293
|
-
|
|
38294
|
-
|
|
38295
|
-
|
|
38296
|
-
|
|
38297
|
-
|
|
38298
|
-
|
|
38299
|
-
|
|
38300
|
-
|
|
38301
|
-
|
|
38302
|
-
|
|
38303
|
-
|
|
38304
|
-
|
|
38305
|
-
|
|
38306
|
-
|
|
38307
|
-
|
|
38308
|
-
|
|
38309
|
-
|
|
38310
|
-
|
|
38311
|
-
const [blocks, setBlocks] = useState(
|
|
38312
|
-
() => normalizeBlocks(initialBlocks)
|
|
38313
|
-
);
|
|
38314
|
-
const onChangeRef = useRef(onChange);
|
|
38315
|
-
useEffect(() => {
|
|
38316
|
-
onChangeRef.current = onChange;
|
|
38317
|
-
}, [onChange]);
|
|
38318
|
-
const eventBus = useEventBus();
|
|
38319
|
-
const changeEventRef = useRef(changeEvent);
|
|
38320
|
-
useEffect(() => {
|
|
38321
|
-
changeEventRef.current = changeEvent;
|
|
38322
|
-
}, [changeEvent]);
|
|
38323
|
-
const commit = useCallback((next) => {
|
|
38324
|
-
setBlocks(next);
|
|
38325
|
-
onChangeRef.current?.(next);
|
|
38326
|
-
const evt = changeEventRef.current;
|
|
38327
|
-
if (evt) eventBus.emit(`UI:${evt}`, { blocks: next });
|
|
38328
|
-
}, [eventBus]);
|
|
38329
|
-
const handleAppend = useCallback(
|
|
38330
|
-
(type) => {
|
|
38331
|
-
if (readOnly) return;
|
|
38332
|
-
commit([...blocks, createBlock(type)]);
|
|
38333
|
-
},
|
|
38334
|
-
[blocks, commit, readOnly]
|
|
38335
|
-
);
|
|
38336
|
-
const handleUpdate = useCallback(
|
|
38337
|
-
(id, updater) => {
|
|
38338
|
-
commit(replaceBlock(blocks, id, updater));
|
|
38339
|
-
},
|
|
38340
|
-
[blocks, commit]
|
|
38341
|
-
);
|
|
38342
|
-
const handleDelete = useCallback(
|
|
38343
|
-
(id) => {
|
|
38344
|
-
const next = removeBlock(blocks, id);
|
|
38345
|
-
commit(next.length > 0 ? next : [createBlock("paragraph")]);
|
|
38346
|
-
},
|
|
38347
|
-
[blocks, commit]
|
|
38348
|
-
);
|
|
38349
|
-
const handleDuplicate = useCallback(
|
|
38350
|
-
(id) => {
|
|
38351
|
-
const target = blocks.find((b) => b.id === id);
|
|
38352
|
-
if (!target) return;
|
|
38353
|
-
commit(insertAfter(blocks, id, duplicateBlock(target)));
|
|
38354
|
-
},
|
|
38355
|
-
[blocks, commit]
|
|
38273
|
+
init_Input();
|
|
38274
|
+
init_Menu();
|
|
38275
|
+
init_RichTextEditor();
|
|
38276
|
+
}
|
|
38277
|
+
});
|
|
38278
|
+
function renderIconInput5(icon, props) {
|
|
38279
|
+
return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
|
|
38280
|
+
}
|
|
38281
|
+
function fieldName(field) {
|
|
38282
|
+
return field.name ?? field.key ?? "";
|
|
38283
|
+
}
|
|
38284
|
+
function relationLabel(value) {
|
|
38285
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) return null;
|
|
38286
|
+
for (const key of ["name", "title", "label"]) {
|
|
38287
|
+
const candidate = value[key];
|
|
38288
|
+
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
38289
|
+
}
|
|
38290
|
+
const id = value.id;
|
|
38291
|
+
return id !== void 0 && id !== null ? String(id) : null;
|
|
38292
|
+
}
|
|
38293
|
+
function fieldKind(field, value) {
|
|
38294
|
+
if (field.kind) return field.kind;
|
|
38295
|
+
if (field.options && field.options.length > 0) return "select";
|
|
38296
|
+
if (typeof value === "boolean" || field.format === "boolean") return "boolean";
|
|
38297
|
+
if (Array.isArray(value) || relationLabel(value ?? null) !== null) return "readonly";
|
|
38298
|
+
return "text";
|
|
38299
|
+
}
|
|
38300
|
+
function DocumentDetails({
|
|
38301
|
+
entity,
|
|
38302
|
+
fields,
|
|
38303
|
+
metaCommitEvent,
|
|
38304
|
+
title,
|
|
38305
|
+
className
|
|
38306
|
+
}) {
|
|
38307
|
+
const eventBus = useEventBus();
|
|
38308
|
+
const { t } = useTranslate();
|
|
38309
|
+
const [fieldDraft, setFieldDraft] = useState(null);
|
|
38310
|
+
const recordId = entity?.id !== void 0 && entity?.id !== null ? String(entity.id) : "";
|
|
38311
|
+
const fieldDefs = (fields ?? []).filter((f3) => fieldName(f3) !== "");
|
|
38312
|
+
if (fieldDefs.length === 0) return null;
|
|
38313
|
+
const commitField = (name, next, current) => {
|
|
38314
|
+
setFieldDraft(null);
|
|
38315
|
+
if (!metaCommitEvent || next === current) return;
|
|
38316
|
+
eventBus.emit(`UI:${metaCommitEvent}`, { id: recordId, patch: { id: recordId, [name]: next } });
|
|
38317
|
+
};
|
|
38318
|
+
const renderValue = (field) => {
|
|
38319
|
+
const name = fieldName(field);
|
|
38320
|
+
const raw = getNestedValue(entity ?? {}, name);
|
|
38321
|
+
const kind = fieldKind(field, raw);
|
|
38322
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
38323
|
+
if (kind === "boolean") {
|
|
38324
|
+
return /* @__PURE__ */ jsx(
|
|
38325
|
+
Switch,
|
|
38326
|
+
{
|
|
38327
|
+
checked: Boolean(raw),
|
|
38328
|
+
disabled: !metaCommitEvent,
|
|
38329
|
+
"aria-label": label,
|
|
38330
|
+
onChange: (checked) => commitField(name, checked, Boolean(raw))
|
|
38331
|
+
}
|
|
38356
38332
|
);
|
|
38357
|
-
|
|
38358
|
-
|
|
38359
|
-
|
|
38360
|
-
|
|
38361
|
-
|
|
38362
|
-
|
|
38363
|
-
|
|
38333
|
+
}
|
|
38334
|
+
if (kind === "select") {
|
|
38335
|
+
return /* @__PURE__ */ jsx(
|
|
38336
|
+
Select,
|
|
38337
|
+
{
|
|
38338
|
+
value: raw !== void 0 && raw !== null ? String(raw) : "",
|
|
38339
|
+
disabled: !metaCommitEvent,
|
|
38340
|
+
"aria-label": label,
|
|
38341
|
+
className: "h-8 w-full",
|
|
38342
|
+
options: (field.options ?? []).map((opt) => ({ value: opt, label: humanizeEnumValue(opt) })),
|
|
38343
|
+
onChange: (e) => commitField(name, e.target.value, raw)
|
|
38344
|
+
}
|
|
38364
38345
|
);
|
|
38365
|
-
|
|
38366
|
-
|
|
38346
|
+
}
|
|
38347
|
+
if (kind === "readonly" || !metaCommitEvent) {
|
|
38348
|
+
if (Array.isArray(raw)) {
|
|
38349
|
+
if (raw.length === 0) {
|
|
38350
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: "\u2014" });
|
|
38351
|
+
}
|
|
38352
|
+
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)) });
|
|
38353
|
+
}
|
|
38354
|
+
const shown2 = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
38355
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "small", className: "break-words", children: shown2 });
|
|
38356
|
+
}
|
|
38357
|
+
if (fieldDraft?.name === name) {
|
|
38358
|
+
return /* @__PURE__ */ jsx(
|
|
38359
|
+
Input,
|
|
38367
38360
|
{
|
|
38368
|
-
|
|
38369
|
-
|
|
38370
|
-
|
|
38371
|
-
|
|
38372
|
-
|
|
38373
|
-
|
|
38374
|
-
|
|
38375
|
-
|
|
38376
|
-
|
|
38377
|
-
|
|
38378
|
-
|
|
38379
|
-
|
|
38380
|
-
|
|
38381
|
-
|
|
38382
|
-
|
|
38383
|
-
|
|
38384
|
-
return /* @__PURE__ */ jsxs(
|
|
38385
|
-
Button,
|
|
38386
|
-
{
|
|
38387
|
-
type: "button",
|
|
38388
|
-
variant: "ghost",
|
|
38389
|
-
size: "sm",
|
|
38390
|
-
"aria-label": t("richBlockEditor.insertEntry", { label: entryLabel }),
|
|
38391
|
-
title: entryLabel,
|
|
38392
|
-
onClick: () => handleAppend(entry.type),
|
|
38393
|
-
children: [
|
|
38394
|
-
/* @__PURE__ */ jsx(Icon2, { size: 14 }),
|
|
38395
|
-
/* @__PURE__ */ jsx(Typography, { as: "span", variant: "caption", className: "ml-1 hidden text-xs sm:inline", children: entryLabel })
|
|
38396
|
-
]
|
|
38397
|
-
},
|
|
38398
|
-
entry.type
|
|
38399
|
-
);
|
|
38400
|
-
})
|
|
38401
|
-
}
|
|
38402
|
-
),
|
|
38403
|
-
/* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-1 px-3 py-3", children: blocks.map((block) => /* @__PURE__ */ jsx(
|
|
38404
|
-
BlockRow,
|
|
38405
|
-
{
|
|
38406
|
-
block,
|
|
38407
|
-
readOnly,
|
|
38408
|
-
showAffordances: enableBlocks,
|
|
38409
|
-
placeholder,
|
|
38410
|
-
onUpdate: (updater) => handleUpdate(block.id, updater),
|
|
38411
|
-
onDelete: () => handleDelete(block.id),
|
|
38412
|
-
onDuplicate: () => handleDuplicate(block.id),
|
|
38413
|
-
onChangeType: (type) => handleChangeType(block.id, type)
|
|
38414
|
-
},
|
|
38415
|
-
block.id
|
|
38416
|
-
)) })
|
|
38417
|
-
]
|
|
38361
|
+
value: fieldDraft.value,
|
|
38362
|
+
autoFocus: true,
|
|
38363
|
+
"aria-label": label,
|
|
38364
|
+
className: "h-8 w-full",
|
|
38365
|
+
onChange: (e) => setFieldDraft({ name, value: e.target.value }),
|
|
38366
|
+
onBlur: () => commitField(name, fieldDraft.value.trim(), raw),
|
|
38367
|
+
onKeyDown: (e) => {
|
|
38368
|
+
if (e.key === "Enter") {
|
|
38369
|
+
e.preventDefault();
|
|
38370
|
+
commitField(name, fieldDraft.value.trim(), raw);
|
|
38371
|
+
} else if (e.key === "Escape") {
|
|
38372
|
+
e.preventDefault();
|
|
38373
|
+
setFieldDraft(null);
|
|
38374
|
+
}
|
|
38375
|
+
},
|
|
38376
|
+
"data-testid": `document-property-input-${name}`
|
|
38418
38377
|
}
|
|
38419
38378
|
);
|
|
38420
|
-
}
|
|
38421
|
-
|
|
38379
|
+
}
|
|
38380
|
+
const shown = raw === void 0 || raw === null || raw === "" ? "\u2014" : relationLabel(raw) ?? formatValue(raw, field.format);
|
|
38381
|
+
return /* @__PURE__ */ jsx(
|
|
38382
|
+
Box,
|
|
38383
|
+
{
|
|
38384
|
+
role: "button",
|
|
38385
|
+
tabIndex: 0,
|
|
38386
|
+
className: cn(
|
|
38387
|
+
"cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
38388
|
+
(raw === void 0 || raw === null || raw === "") && "text-muted-foreground"
|
|
38389
|
+
),
|
|
38390
|
+
onClick: () => setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" }),
|
|
38391
|
+
onKeyDown: (e) => {
|
|
38392
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
38393
|
+
e.preventDefault();
|
|
38394
|
+
setFieldDraft({ name, value: raw !== void 0 && raw !== null ? String(raw) : "" });
|
|
38395
|
+
}
|
|
38396
|
+
},
|
|
38397
|
+
"data-testid": `document-property-${name}`,
|
|
38398
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "break-words", children: shown })
|
|
38399
|
+
}
|
|
38400
|
+
);
|
|
38401
|
+
};
|
|
38402
|
+
return /* @__PURE__ */ jsx(Card, { variant: "bordered", className: cn("w-full", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "p-4", children: [
|
|
38403
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", weight: "medium", className: "uppercase tracking-wide", children: title ?? (t("documentDetails.title") || "Details") }),
|
|
38404
|
+
/* @__PURE__ */ jsx(VStack, { gap: "sm", children: fieldDefs.map((field) => {
|
|
38405
|
+
const name = fieldName(field);
|
|
38406
|
+
const label = field.label ?? field.header ?? humanizeFieldName(name);
|
|
38407
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
38408
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
38409
|
+
field.icon && renderIconInput5(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
38410
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
38411
|
+
] }),
|
|
38412
|
+
/* @__PURE__ */ jsx(Box, { className: "min-w-0", children: renderValue(field) })
|
|
38413
|
+
] }, name);
|
|
38414
|
+
}) })
|
|
38415
|
+
] }) });
|
|
38416
|
+
}
|
|
38417
|
+
var init_DocumentDetails = __esm({
|
|
38418
|
+
"components/core/molecules/DocumentDetails.tsx"() {
|
|
38419
|
+
"use client";
|
|
38420
|
+
init_cn();
|
|
38421
|
+
init_format();
|
|
38422
|
+
init_getNestedValue();
|
|
38423
|
+
init_useEventBus();
|
|
38424
|
+
init_Box();
|
|
38425
|
+
init_Stack();
|
|
38426
|
+
init_Typography();
|
|
38427
|
+
init_Badge();
|
|
38428
|
+
init_Card();
|
|
38429
|
+
init_Icon();
|
|
38430
|
+
init_Input();
|
|
38431
|
+
init_Select();
|
|
38432
|
+
init_Switch();
|
|
38422
38433
|
}
|
|
38423
38434
|
});
|
|
38424
38435
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
@@ -43092,7 +43103,9 @@ var init_molecules2 = __esm({
|
|
|
43092
43103
|
init_QrScanner();
|
|
43093
43104
|
init_OptionConstraintGroup();
|
|
43094
43105
|
init_PositionedCanvas();
|
|
43095
|
-
|
|
43106
|
+
init_RichTextEditor();
|
|
43107
|
+
init_DocumentPanel();
|
|
43108
|
+
init_DocumentDetails();
|
|
43096
43109
|
init_ReplyTree();
|
|
43097
43110
|
init_BranchingLogicBuilder();
|
|
43098
43111
|
init_VersionDiff();
|
|
@@ -43592,8 +43605,8 @@ var init_DataTable = __esm({
|
|
|
43592
43605
|
DataTable.displayName = "DataTable";
|
|
43593
43606
|
}
|
|
43594
43607
|
});
|
|
43595
|
-
function getBadgeVariant(
|
|
43596
|
-
const name =
|
|
43608
|
+
function getBadgeVariant(fieldName2, value) {
|
|
43609
|
+
const name = fieldName2.toLowerCase();
|
|
43597
43610
|
const val = String(value).toLowerCase();
|
|
43598
43611
|
if (name.includes("status")) {
|
|
43599
43612
|
if (val.includes("complete") || val.includes("done") || val.includes("active"))
|
|
@@ -43609,12 +43622,12 @@ function getBadgeVariant(fieldName, value) {
|
|
|
43609
43622
|
}
|
|
43610
43623
|
return "default";
|
|
43611
43624
|
}
|
|
43612
|
-
function formatFieldValue2(value,
|
|
43625
|
+
function formatFieldValue2(value, fieldName2) {
|
|
43613
43626
|
if (typeof value === "number") {
|
|
43614
|
-
if (
|
|
43627
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
43615
43628
|
return `${value}%`;
|
|
43616
43629
|
}
|
|
43617
|
-
if (
|
|
43630
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
43618
43631
|
return `$${value.toLocaleString()}`;
|
|
43619
43632
|
}
|
|
43620
43633
|
return value.toLocaleString();
|
|
@@ -43624,7 +43637,7 @@ function formatFieldValue2(value, fieldName) {
|
|
|
43624
43637
|
}
|
|
43625
43638
|
return String(value);
|
|
43626
43639
|
}
|
|
43627
|
-
function renderRichFieldValue(value,
|
|
43640
|
+
function renderRichFieldValue(value, fieldName2, fieldType, meta) {
|
|
43628
43641
|
if (value === void 0 || value === null) return "\u2014";
|
|
43629
43642
|
const str2 = String(value);
|
|
43630
43643
|
switch (fieldType) {
|
|
@@ -43635,7 +43648,7 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
43635
43648
|
"img",
|
|
43636
43649
|
{
|
|
43637
43650
|
src: str2,
|
|
43638
|
-
alt: formatFieldLabel(
|
|
43651
|
+
alt: formatFieldLabel(fieldName2),
|
|
43639
43652
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
43640
43653
|
loading: "lazy"
|
|
43641
43654
|
}
|
|
@@ -43770,9 +43783,9 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
|
|
|
43770
43783
|
return /* @__PURE__ */ jsx("a", { href: `tel:${str2}`, className: "text-primary hover:underline", children: str2 });
|
|
43771
43784
|
default:
|
|
43772
43785
|
if (meta?.values && meta.values.length > 0 && meta.values.includes(str2)) {
|
|
43773
|
-
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(
|
|
43786
|
+
return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(fieldName2, str2), children: humanizeEnumValue(str2) });
|
|
43774
43787
|
}
|
|
43775
|
-
return formatFieldValue2(value,
|
|
43788
|
+
return formatFieldValue2(value, fieldName2);
|
|
43776
43789
|
}
|
|
43777
43790
|
}
|
|
43778
43791
|
function normalizeFieldDefs(fields) {
|
|
@@ -44615,7 +44628,21 @@ var init_Form = __esm({
|
|
|
44615
44628
|
const normalizedInitialData = React77__default.useMemo(() => {
|
|
44616
44629
|
const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
|
|
44617
44630
|
const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
|
|
44618
|
-
|
|
44631
|
+
const merged = entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
|
|
44632
|
+
const toId = (value) => {
|
|
44633
|
+
if (value === null || value === void 0 || typeof value !== "object" || value instanceof Date) return value;
|
|
44634
|
+
if (Array.isArray(value)) {
|
|
44635
|
+
return value.map(
|
|
44636
|
+
(item) => item !== null && typeof item === "object" && !Array.isArray(item) && !(item instanceof Date) && item.id !== void 0 && item.id !== null ? String(item.id) : item
|
|
44637
|
+
);
|
|
44638
|
+
}
|
|
44639
|
+
return value.id !== void 0 && value.id !== null ? String(value.id) : value;
|
|
44640
|
+
};
|
|
44641
|
+
const normalized = {};
|
|
44642
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
44643
|
+
normalized[key] = key === "id" ? value : toId(value);
|
|
44644
|
+
}
|
|
44645
|
+
return normalized;
|
|
44619
44646
|
}, [entity, initialData]);
|
|
44620
44647
|
const entityDerivedFields = React77__default.useMemo(() => {
|
|
44621
44648
|
if (fields && fields.length > 0) return void 0;
|
|
@@ -44744,8 +44771,8 @@ var init_Form = __esm({
|
|
|
44744
44771
|
checkViolations(name, newFormData);
|
|
44745
44772
|
};
|
|
44746
44773
|
const isFieldVisible = React77__default.useCallback(
|
|
44747
|
-
(
|
|
44748
|
-
const condition = conditionalFields[
|
|
44774
|
+
(fieldName2) => {
|
|
44775
|
+
const condition = conditionalFields[fieldName2];
|
|
44749
44776
|
if (!condition) return true;
|
|
44750
44777
|
return Boolean(evaluateFormExpression(condition, evalContext));
|
|
44751
44778
|
},
|
|
@@ -44791,9 +44818,9 @@ var init_Form = __esm({
|
|
|
44791
44818
|
};
|
|
44792
44819
|
const handleInvalid = (e) => {
|
|
44793
44820
|
const target = e.target;
|
|
44794
|
-
const
|
|
44821
|
+
const fieldName2 = target.getAttribute("data-field-name") ?? target.name ?? "";
|
|
44795
44822
|
const fieldMessage = target.validationMessage || "Invalid value";
|
|
44796
|
-
debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
|
|
44823
|
+
debug("forms", "invalid", { mode: formMode, fieldName: fieldName2, fieldMessage });
|
|
44797
44824
|
queueMicrotask(() => {
|
|
44798
44825
|
const form = formRef.current;
|
|
44799
44826
|
if (!form) return;
|
|
@@ -44829,22 +44856,22 @@ var init_Form = __esm({
|
|
|
44829
44856
|
};
|
|
44830
44857
|
const renderField = React77__default.useCallback(
|
|
44831
44858
|
(field) => {
|
|
44832
|
-
const
|
|
44833
|
-
if (!
|
|
44834
|
-
if (!isFieldVisible(
|
|
44859
|
+
const fieldName2 = field.name || field.field;
|
|
44860
|
+
if (!fieldName2) return null;
|
|
44861
|
+
if (!isFieldVisible(fieldName2)) {
|
|
44835
44862
|
return null;
|
|
44836
44863
|
}
|
|
44837
44864
|
const inputType = determineInputType(field);
|
|
44838
|
-
const label = field.label ||
|
|
44839
|
-
const currentValue2 = formData[
|
|
44840
|
-
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", "data-field":
|
|
44865
|
+
const label = field.label || fieldName2.charAt(0).toUpperCase() + fieldName2.slice(1).replace(/([A-Z])/g, " $1");
|
|
44866
|
+
const currentValue2 = formData[fieldName2] ?? field.defaultValue ?? "";
|
|
44867
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", "data-field": fieldName2, children: [
|
|
44841
44868
|
inputType !== "checkbox" && /* @__PURE__ */ jsxs(Typography, { as: "label", variant: "label", weight: "bold", children: [
|
|
44842
44869
|
label,
|
|
44843
44870
|
field.required && /* @__PURE__ */ jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
|
|
44844
44871
|
] }),
|
|
44845
|
-
renderFieldInput(field,
|
|
44872
|
+
renderFieldInput(field, fieldName2, inputType, currentValue2, label),
|
|
44846
44873
|
field.hint && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
|
|
44847
|
-
] },
|
|
44874
|
+
] }, fieldName2);
|
|
44848
44875
|
},
|
|
44849
44876
|
[formData, isFieldVisible, relationsData, relationsLoading, isLoading]
|
|
44850
44877
|
);
|
|
@@ -44873,8 +44900,8 @@ var init_Form = __esm({
|
|
|
44873
44900
|
}
|
|
44874
44901
|
return field;
|
|
44875
44902
|
}).map((field) => {
|
|
44876
|
-
const
|
|
44877
|
-
const override = fieldOverrides?.find((o) => o.name ===
|
|
44903
|
+
const fieldName2 = field.name || field.field;
|
|
44904
|
+
const override = fieldOverrides?.find((o) => o.name === fieldName2);
|
|
44878
44905
|
if (!override) return field;
|
|
44879
44906
|
return {
|
|
44880
44907
|
...field,
|
|
@@ -44930,11 +44957,11 @@ var init_Form = __esm({
|
|
|
44930
44957
|
] }, section.id);
|
|
44931
44958
|
}).filter(Boolean);
|
|
44932
44959
|
}, [sections, isSectionVisible, collapsedSections, renderField, gap]);
|
|
44933
|
-
function renderFieldInput(field,
|
|
44960
|
+
function renderFieldInput(field, fieldName2, inputType, currentValue2, label) {
|
|
44934
44961
|
const commonProps = {
|
|
44935
|
-
id:
|
|
44936
|
-
name:
|
|
44937
|
-
"data-field-name":
|
|
44962
|
+
id: fieldName2,
|
|
44963
|
+
name: fieldName2,
|
|
44964
|
+
"data-field-name": fieldName2,
|
|
44938
44965
|
required: field.required,
|
|
44939
44966
|
disabled: isLoading,
|
|
44940
44967
|
placeholder: field.placeholder,
|
|
@@ -44948,7 +44975,7 @@ var init_Form = __esm({
|
|
|
44948
44975
|
...commonProps,
|
|
44949
44976
|
label: label + (field.required ? " *" : ""),
|
|
44950
44977
|
checked: Boolean(currentValue2),
|
|
44951
|
-
onChange: (e) => handleChange(
|
|
44978
|
+
onChange: (e) => handleChange(fieldName2, e.target.checked)
|
|
44952
44979
|
}
|
|
44953
44980
|
);
|
|
44954
44981
|
case "textarea":
|
|
@@ -44957,7 +44984,7 @@ var init_Form = __esm({
|
|
|
44957
44984
|
{
|
|
44958
44985
|
...commonProps,
|
|
44959
44986
|
value: String(currentValue2),
|
|
44960
|
-
onChange: (e) => handleChange(
|
|
44987
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
44961
44988
|
minLength: field.min,
|
|
44962
44989
|
maxLength: field.max
|
|
44963
44990
|
}
|
|
@@ -44970,14 +44997,14 @@ var init_Form = __esm({
|
|
|
44970
44997
|
...commonProps,
|
|
44971
44998
|
options,
|
|
44972
44999
|
value: String(currentValue2),
|
|
44973
|
-
onValueChange: (v) => handleChange(
|
|
45000
|
+
onValueChange: (v) => handleChange(fieldName2, v),
|
|
44974
45001
|
placeholder: field.placeholder || `Select ${label}...`
|
|
44975
45002
|
}
|
|
44976
45003
|
);
|
|
44977
45004
|
}
|
|
44978
45005
|
case "relation": {
|
|
44979
|
-
const relationOptions = relationsData[
|
|
44980
|
-
const relationLoading = relationsLoading[
|
|
45006
|
+
const relationOptions = relationsData[fieldName2] || [];
|
|
45007
|
+
const relationLoading = relationsLoading[fieldName2] || false;
|
|
44981
45008
|
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
44982
45009
|
const selectedValues = Array.isArray(currentValue2) ? currentValue2.map((v) => String(v)) : [];
|
|
44983
45010
|
return /* @__PURE__ */ jsx(
|
|
@@ -44989,7 +45016,7 @@ var init_Form = __esm({
|
|
|
44989
45016
|
clearable: true,
|
|
44990
45017
|
options: [...relationOptions],
|
|
44991
45018
|
value: selectedValues,
|
|
44992
|
-
onValueChange: (value) => handleChange(
|
|
45019
|
+
onValueChange: (value) => handleChange(fieldName2, Array.isArray(value) ? value : [value]),
|
|
44993
45020
|
placeholder: field.placeholder || `Select ${label}...`
|
|
44994
45021
|
}
|
|
44995
45022
|
);
|
|
@@ -44999,7 +45026,7 @@ var init_Form = __esm({
|
|
|
44999
45026
|
{
|
|
45000
45027
|
...commonProps,
|
|
45001
45028
|
value: currentValue2 ? String(currentValue2) : void 0,
|
|
45002
|
-
onChange: (value) => handleChange(
|
|
45029
|
+
onChange: (value) => handleChange(fieldName2, value),
|
|
45003
45030
|
options: relationOptions,
|
|
45004
45031
|
isLoading: relationLoading,
|
|
45005
45032
|
placeholder: field.placeholder || `Select ${label}...`,
|
|
@@ -45016,7 +45043,7 @@ var init_Form = __esm({
|
|
|
45016
45043
|
placeholder: field.placeholder,
|
|
45017
45044
|
disabled: isLoading,
|
|
45018
45045
|
value: arrayValue,
|
|
45019
|
-
onChange: (next) => handleChange(
|
|
45046
|
+
onChange: (next) => handleChange(fieldName2, [...next])
|
|
45020
45047
|
}
|
|
45021
45048
|
);
|
|
45022
45049
|
}
|
|
@@ -45028,7 +45055,7 @@ var init_Form = __esm({
|
|
|
45028
45055
|
type: "number",
|
|
45029
45056
|
value: currentValue2 !== void 0 && currentValue2 !== "" ? String(currentValue2) : "",
|
|
45030
45057
|
onChange: (e) => handleChange(
|
|
45031
|
-
|
|
45058
|
+
fieldName2,
|
|
45032
45059
|
e.target.value ? Number(e.target.value) : void 0
|
|
45033
45060
|
),
|
|
45034
45061
|
min: field.min,
|
|
@@ -45045,7 +45072,7 @@ var init_Form = __esm({
|
|
|
45045
45072
|
icon: DollarSign,
|
|
45046
45073
|
value: currentValue2 !== void 0 && currentValue2 !== "" ? String(currentValue2) : "",
|
|
45047
45074
|
onChange: (e) => handleChange(
|
|
45048
|
-
|
|
45075
|
+
fieldName2,
|
|
45049
45076
|
e.target.value ? Number(e.target.value) : void 0
|
|
45050
45077
|
),
|
|
45051
45078
|
min: field.min,
|
|
@@ -45063,7 +45090,7 @@ var init_Form = __esm({
|
|
|
45063
45090
|
const f3 = files[0];
|
|
45064
45091
|
if (!f3) return;
|
|
45065
45092
|
const reader = new FileReader();
|
|
45066
|
-
reader.onload = () => handleChange(
|
|
45093
|
+
reader.onload = () => handleChange(fieldName2, {
|
|
45067
45094
|
name: f3.name,
|
|
45068
45095
|
mimeType: f3.type,
|
|
45069
45096
|
sizeBytes: f3.size,
|
|
@@ -45080,7 +45107,7 @@ var init_Form = __esm({
|
|
|
45080
45107
|
...commonProps,
|
|
45081
45108
|
type: "date",
|
|
45082
45109
|
value: formatDateValue(currentValue2),
|
|
45083
|
-
onChange: (e) => handleChange(
|
|
45110
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45084
45111
|
}
|
|
45085
45112
|
);
|
|
45086
45113
|
case "datetime-local":
|
|
@@ -45090,7 +45117,7 @@ var init_Form = __esm({
|
|
|
45090
45117
|
...commonProps,
|
|
45091
45118
|
type: "datetime-local",
|
|
45092
45119
|
value: formatDateTimeValue(currentValue2),
|
|
45093
|
-
onChange: (e) => handleChange(
|
|
45120
|
+
onChange: (e) => handleChange(fieldName2, e.target.value)
|
|
45094
45121
|
}
|
|
45095
45122
|
);
|
|
45096
45123
|
case "email":
|
|
@@ -45100,7 +45127,7 @@ var init_Form = __esm({
|
|
|
45100
45127
|
...commonProps,
|
|
45101
45128
|
type: "email",
|
|
45102
45129
|
value: String(currentValue2),
|
|
45103
|
-
onChange: (e) => handleChange(
|
|
45130
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45104
45131
|
minLength: field.min,
|
|
45105
45132
|
maxLength: field.max
|
|
45106
45133
|
}
|
|
@@ -45112,7 +45139,7 @@ var init_Form = __esm({
|
|
|
45112
45139
|
...commonProps,
|
|
45113
45140
|
type: "url",
|
|
45114
45141
|
value: String(currentValue2),
|
|
45115
|
-
onChange: (e) => handleChange(
|
|
45142
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45116
45143
|
minLength: field.min,
|
|
45117
45144
|
maxLength: field.max
|
|
45118
45145
|
}
|
|
@@ -45124,7 +45151,7 @@ var init_Form = __esm({
|
|
|
45124
45151
|
...commonProps,
|
|
45125
45152
|
type: "password",
|
|
45126
45153
|
value: String(currentValue2),
|
|
45127
|
-
onChange: (e) => handleChange(
|
|
45154
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45128
45155
|
minLength: field.min,
|
|
45129
45156
|
maxLength: field.max
|
|
45130
45157
|
}
|
|
@@ -45137,7 +45164,7 @@ var init_Form = __esm({
|
|
|
45137
45164
|
...commonProps,
|
|
45138
45165
|
type: "text",
|
|
45139
45166
|
value: String(currentValue2),
|
|
45140
|
-
onChange: (e) => handleChange(
|
|
45167
|
+
onChange: (e) => handleChange(fieldName2, e.target.value),
|
|
45141
45168
|
minLength: field.min,
|
|
45142
45169
|
maxLength: field.max
|
|
45143
45170
|
}
|
|
@@ -45494,7 +45521,7 @@ function entityFieldsFromListItem(item) {
|
|
|
45494
45521
|
}
|
|
45495
45522
|
return result;
|
|
45496
45523
|
}
|
|
45497
|
-
function getStatusStyle(
|
|
45524
|
+
function getStatusStyle(fieldName2, value) {
|
|
45498
45525
|
const val = String(value).toLowerCase();
|
|
45499
45526
|
if (val.includes("complete") || val.includes("done"))
|
|
45500
45527
|
return STATUS_STYLES.complete;
|
|
@@ -45510,12 +45537,12 @@ function getStatusStyle(fieldName, value) {
|
|
|
45510
45537
|
if (val.includes("low")) return STATUS_STYLES.low;
|
|
45511
45538
|
return STATUS_STYLES.default;
|
|
45512
45539
|
}
|
|
45513
|
-
function formatValue3(value,
|
|
45540
|
+
function formatValue3(value, fieldName2) {
|
|
45514
45541
|
if (typeof value === "number") {
|
|
45515
|
-
if (
|
|
45542
|
+
if (fieldName2.toLowerCase().includes("progress") || fieldName2.toLowerCase().includes("percent")) {
|
|
45516
45543
|
return `${value}%`;
|
|
45517
45544
|
}
|
|
45518
|
-
if (
|
|
45545
|
+
if (fieldName2.toLowerCase().includes("budget") || fieldName2.toLowerCase().includes("cost")) {
|
|
45519
45546
|
return new Intl.NumberFormat("en-US", {
|
|
45520
45547
|
style: "currency",
|
|
45521
45548
|
currency: "USD",
|
|
@@ -45538,8 +45565,8 @@ function formatValue3(value, fieldName) {
|
|
|
45538
45565
|
}
|
|
45539
45566
|
return String(value);
|
|
45540
45567
|
}
|
|
45541
|
-
function formatFieldLabel2(
|
|
45542
|
-
return humanizeFieldName(
|
|
45568
|
+
function formatFieldLabel2(fieldName2) {
|
|
45569
|
+
return humanizeFieldName(fieldName2).replace(/\sId$/, "").trim();
|
|
45543
45570
|
}
|
|
45544
45571
|
var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
|
|
45545
45572
|
var init_List = __esm({
|
|
@@ -45607,9 +45634,9 @@ var init_List = __esm({
|
|
|
45607
45634
|
};
|
|
45608
45635
|
StatusBadge = ({
|
|
45609
45636
|
value,
|
|
45610
|
-
fieldName
|
|
45637
|
+
fieldName: fieldName2
|
|
45611
45638
|
}) => {
|
|
45612
|
-
const style = getStatusStyle(
|
|
45639
|
+
const style = getStatusStyle(fieldName2, value);
|
|
45613
45640
|
return /* @__PURE__ */ jsxs(
|
|
45614
45641
|
Typography,
|
|
45615
45642
|
{
|
|
@@ -48522,8 +48549,8 @@ var init_StatCard = __esm({
|
|
|
48522
48549
|
return items.length;
|
|
48523
48550
|
}
|
|
48524
48551
|
if (field.includes(":")) {
|
|
48525
|
-
const [
|
|
48526
|
-
return items.filter((item) => item[
|
|
48552
|
+
const [fieldName2, fieldValue] = field.split(":");
|
|
48553
|
+
return items.filter((item) => item[fieldName2] === fieldValue).length;
|
|
48527
48554
|
}
|
|
48528
48555
|
const fieldExistsOnItems = items.some((item) => field in item);
|
|
48529
48556
|
if (fieldExistsOnItems) {
|
|
@@ -50043,6 +50070,8 @@ var init_component_registry_generated = __esm({
|
|
|
50043
50070
|
init_DocSearch();
|
|
50044
50071
|
init_DocSidebar();
|
|
50045
50072
|
init_DocTOC();
|
|
50073
|
+
init_DocumentDetails();
|
|
50074
|
+
init_DocumentPanel();
|
|
50046
50075
|
init_DocumentViewer();
|
|
50047
50076
|
init_DrawFxLayer();
|
|
50048
50077
|
init_DrawGroup();
|
|
@@ -50152,7 +50181,7 @@ var init_component_registry_generated = __esm({
|
|
|
50152
50181
|
init_RelationSelect();
|
|
50153
50182
|
init_RepeatableFormSection();
|
|
50154
50183
|
init_ReplyTree();
|
|
50155
|
-
|
|
50184
|
+
init_RichTextEditor();
|
|
50156
50185
|
init_RuntimeDebugger2();
|
|
50157
50186
|
init_ScaledDiagram();
|
|
50158
50187
|
init_ScoreDisplay();
|
|
@@ -50315,6 +50344,8 @@ var init_component_registry_generated = __esm({
|
|
|
50315
50344
|
"DocSearch": DocSearch,
|
|
50316
50345
|
"DocSidebar": DocSidebar,
|
|
50317
50346
|
"DocTOC": DocTOC,
|
|
50347
|
+
"DocumentDetails": DocumentDetails,
|
|
50348
|
+
"DocumentPanel": DocumentPanel,
|
|
50318
50349
|
"DocumentViewer": DocumentViewer,
|
|
50319
50350
|
"DrawFxLayer": DrawFxLayer,
|
|
50320
50351
|
"DrawGroup": DrawGroup,
|
|
@@ -50426,7 +50457,7 @@ var init_component_registry_generated = __esm({
|
|
|
50426
50457
|
"RelationSelect": RelationSelect,
|
|
50427
50458
|
"RepeatableFormSection": RepeatableFormSection,
|
|
50428
50459
|
"ReplyTree": ReplyTree,
|
|
50429
|
-
"
|
|
50460
|
+
"RichTextEditor": RichTextEditor,
|
|
50430
50461
|
"RuntimeDebugger": RuntimeDebugger,
|
|
50431
50462
|
"ScaledDiagram": ScaledDiagram,
|
|
50432
50463
|
"ScoreDisplay": ScoreDisplay,
|
|
@@ -50580,10 +50611,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
50580
50611
|
}
|
|
50581
50612
|
if (field && typeof field === "object" && !Array.isArray(field) && !React77__default.isValidElement(field) && !(field instanceof Date)) {
|
|
50582
50613
|
const obj = field;
|
|
50583
|
-
const
|
|
50584
|
-
if (!
|
|
50614
|
+
const fieldName2 = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
|
|
50615
|
+
if (!fieldName2) return field;
|
|
50585
50616
|
if (obj.type || obj.inputType) return field;
|
|
50586
|
-
const entityField = fieldMap.get(
|
|
50617
|
+
const entityField = fieldMap.get(fieldName2);
|
|
50587
50618
|
if (!entityField) return field;
|
|
50588
50619
|
const enriched = { ...obj, type: entityField.type };
|
|
50589
50620
|
if (entityField.required && !("required" in obj)) {
|
|
@@ -50633,9 +50664,9 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
50633
50664
|
}
|
|
50634
50665
|
if (field && typeof field === "object" && !Array.isArray(field) && !React77__default.isValidElement(field) && !(field instanceof Date)) {
|
|
50635
50666
|
const obj = field;
|
|
50636
|
-
const
|
|
50637
|
-
if (!
|
|
50638
|
-
const meta = metaFor(
|
|
50667
|
+
const fieldName2 = typeof obj.key === "string" ? obj.key : typeof obj.name === "string" ? obj.name : void 0;
|
|
50668
|
+
if (!fieldName2 || obj.type) return field;
|
|
50669
|
+
const meta = metaFor(fieldName2);
|
|
50639
50670
|
return meta ? { ...obj, ...meta } : field;
|
|
50640
50671
|
}
|
|
50641
50672
|
return field;
|
|
@@ -51474,9 +51505,9 @@ function UISlotRenderer({
|
|
|
51474
51505
|
"ui-slot-renderer relative min-h-full",
|
|
51475
51506
|
className
|
|
51476
51507
|
), children: [
|
|
51477
|
-
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full", children: [
|
|
51478
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 shrink-0" }),
|
|
51479
|
-
/* @__PURE__ */ jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-h-[200px]" })
|
|
51508
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex min-h-full flex-col lg:flex-row", children: [
|
|
51509
|
+
/* @__PURE__ */ jsx(UISlotComponent, { slot: "sidebar", className: "ui-slot-sidebar min-w-0 lg:shrink-0" }),
|
|
51510
|
+
/* @__PURE__ */ jsx(UISlotComponent, { slot: "main", className: "ui-slot-main flex-1 min-w-0 min-h-[200px]" })
|
|
51480
51511
|
] }),
|
|
51481
51512
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "modal", portal: true }),
|
|
51482
51513
|
/* @__PURE__ */ jsx(UISlotComponent, { slot: "drawer", portal: true }),
|
|
@@ -53464,54 +53495,6 @@ var en_default = {
|
|
|
53464
53495
|
"template.faq": "Frequently Asked Questions",
|
|
53465
53496
|
"template.ourTeam": "Our Team",
|
|
53466
53497
|
"template.caseStudies": "Case Studies",
|
|
53467
|
-
"richBlockEditor.toolbar.text": "Text",
|
|
53468
|
-
"richBlockEditor.toolbar.h1": "H1",
|
|
53469
|
-
"richBlockEditor.toolbar.h2": "H2",
|
|
53470
|
-
"richBlockEditor.toolbar.h3": "H3",
|
|
53471
|
-
"richBlockEditor.toolbar.bulletList": "Bullet list",
|
|
53472
|
-
"richBlockEditor.toolbar.numbered": "Numbered",
|
|
53473
|
-
"richBlockEditor.toolbar.quote": "Quote",
|
|
53474
|
-
"richBlockEditor.toolbar.code": "Code",
|
|
53475
|
-
"richBlockEditor.toolbar.divider": "Divider",
|
|
53476
|
-
"richBlockEditor.toolbar.image": "Image",
|
|
53477
|
-
"richBlockEditor.blockType.paragraph": "Text",
|
|
53478
|
-
"richBlockEditor.blockType.heading1": "Heading 1",
|
|
53479
|
-
"richBlockEditor.blockType.heading2": "Heading 2",
|
|
53480
|
-
"richBlockEditor.blockType.heading3": "Heading 3",
|
|
53481
|
-
"richBlockEditor.blockType.bulletList": "Bullet list",
|
|
53482
|
-
"richBlockEditor.blockType.numberedList": "Numbered list",
|
|
53483
|
-
"richBlockEditor.blockType.quote": "Quote",
|
|
53484
|
-
"richBlockEditor.blockType.code": "Code",
|
|
53485
|
-
"richBlockEditor.blockType.divider": "Divider",
|
|
53486
|
-
"richBlockEditor.blockType.image": "Image",
|
|
53487
|
-
"richBlockEditor.blockActions": "Block actions",
|
|
53488
|
-
"richBlockEditor.duplicate": "Duplicate",
|
|
53489
|
-
"richBlockEditor.turnInto": "Turn into",
|
|
53490
|
-
"richBlockEditor.placeholder.heading1": "Heading 1",
|
|
53491
|
-
"richBlockEditor.placeholder.heading2": "Heading 2",
|
|
53492
|
-
"richBlockEditor.placeholder.heading3": "Heading 3",
|
|
53493
|
-
"richBlockEditor.placeholder.quote": "Quote",
|
|
53494
|
-
"richBlockEditor.placeholder.code": "Enter code",
|
|
53495
|
-
"richBlockEditor.placeholder.paragraph": "Start writing...",
|
|
53496
|
-
"richBlockEditor.placeholder.listItem": "List item",
|
|
53497
|
-
"richBlockEditor.placeholder.caption": "Caption (optional)",
|
|
53498
|
-
"richBlockEditor.aria.heading1Block": "Heading 1 block",
|
|
53499
|
-
"richBlockEditor.aria.heading2Block": "Heading 2 block",
|
|
53500
|
-
"richBlockEditor.aria.heading3Block": "Heading 3 block",
|
|
53501
|
-
"richBlockEditor.aria.quoteBlock": "Quote block",
|
|
53502
|
-
"richBlockEditor.aria.codeBlock": "Code block",
|
|
53503
|
-
"richBlockEditor.aria.codeLanguage": "Code language",
|
|
53504
|
-
"richBlockEditor.aria.imageUrl": "Image URL",
|
|
53505
|
-
"richBlockEditor.aria.imageCaption": "Image caption",
|
|
53506
|
-
"richBlockEditor.aria.listItem": "List item",
|
|
53507
|
-
"richBlockEditor.aria.removeListItem": "Remove list item",
|
|
53508
|
-
"richBlockEditor.aria.paragraphBlock": "Paragraph block",
|
|
53509
|
-
"richBlockEditor.embeddedImage": "Embedded image",
|
|
53510
|
-
"richBlockEditor.noImageUrl": "No image URL set",
|
|
53511
|
-
"richBlockEditor.addItem": "Add item",
|
|
53512
|
-
"richBlockEditor.insertParagraphBelow": "Insert paragraph below",
|
|
53513
|
-
"richBlockEditor.editorToolbar": "Block editor toolbar",
|
|
53514
|
-
"richBlockEditor.insertEntry": "Insert {{label}}",
|
|
53515
53498
|
"versionDiff.compare": "Compare",
|
|
53516
53499
|
"versionDiff.to": "to",
|
|
53517
53500
|
"versionDiff.beforeRevision": "Before revision",
|
|
@@ -53859,7 +53842,31 @@ var en_default = {
|
|
|
53859
53842
|
"td.survivedAllWaves": "Survived all waves!",
|
|
53860
53843
|
"td.victory": "Victory!",
|
|
53861
53844
|
"td.wave": "Wave",
|
|
53862
|
-
"td.waveInProgress": "Wave in progress\u2026"
|
|
53845
|
+
"td.waveInProgress": "Wave in progress\u2026",
|
|
53846
|
+
"documentDetails.title": "Details",
|
|
53847
|
+
"documentPanel.untitled": "Untitled",
|
|
53848
|
+
"documentPanel.edit": "Edit",
|
|
53849
|
+
"documentPanel.done": "Done",
|
|
53850
|
+
"documentPanel.autosaveHint": "Saves as you type",
|
|
53851
|
+
"documentPanel.placeholder": "Start writing\u2026",
|
|
53852
|
+
"richTextEditor.editorToolbar": "Formatting toolbar",
|
|
53853
|
+
"richTextEditor.editorSurface": "Rich text editor",
|
|
53854
|
+
"richTextEditor.bold": "Bold",
|
|
53855
|
+
"richTextEditor.italic": "Italic",
|
|
53856
|
+
"richTextEditor.underline": "Underline",
|
|
53857
|
+
"richTextEditor.strikethrough": "Strikethrough",
|
|
53858
|
+
"richTextEditor.heading1": "Heading 1",
|
|
53859
|
+
"richTextEditor.heading2": "Heading 2",
|
|
53860
|
+
"richTextEditor.heading3": "Heading 3",
|
|
53861
|
+
"richTextEditor.bulletList": "Bullet list",
|
|
53862
|
+
"richTextEditor.numberedList": "Numbered list",
|
|
53863
|
+
"richTextEditor.quote": "Quote",
|
|
53864
|
+
"richTextEditor.code": "Code",
|
|
53865
|
+
"richTextEditor.link": "Add link",
|
|
53866
|
+
"richTextEditor.removeLink": "Remove link",
|
|
53867
|
+
"richTextEditor.divider": "Divider",
|
|
53868
|
+
"richTextEditor.linkPrompt": "Link address",
|
|
53869
|
+
"richTextEditor.placeholder": "Start writing\u2026"
|
|
53863
53870
|
};
|
|
53864
53871
|
|
|
53865
53872
|
// hooks/useTranslate.ts
|
|
@@ -53880,7 +53887,7 @@ var I18nContext = createContext({
|
|
|
53880
53887
|
});
|
|
53881
53888
|
I18nContext.displayName = "I18nContext";
|
|
53882
53889
|
var I18nProvider = I18nContext.Provider;
|
|
53883
|
-
function
|
|
53890
|
+
function useTranslate116() {
|
|
53884
53891
|
return useContext(I18nContext);
|
|
53885
53892
|
}
|
|
53886
53893
|
function createTranslate(messages) {
|
|
@@ -54162,4 +54169,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
|
|
|
54162
54169
|
});
|
|
54163
54170
|
}
|
|
54164
54171
|
|
|
54165
|
-
export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AlgoGraphCanvas, AlgorithmCanvas, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AtlasImage, AtlasPanel, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmojiPicker, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, FxOverlay, GameAudioToggle, GameHud, GameIcon, GameMenu, GameShell, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, ImportPreviewTree, ImportProgress, ImportSourcePicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, LearningScene3D, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, Modal, ModalSlot, ModuleCard, Navigation, NodeSlotEditor, NotifyListener, NumberStepper, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, PageTransition, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, Presence, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree,
|
|
54172
|
+
export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AlgoGraphCanvas, AlgorithmCanvas, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AtlasImage, AtlasPanel, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentDetails, DocumentPanel, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmojiPicker, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, FxOverlay, GameAudioToggle, GameHud, GameIcon, GameMenu, GameShell, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, ImportPreviewTree, ImportProgress, ImportSourcePicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, LearningScene3D, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, Modal, ModalSlot, ModuleCard, Navigation, NodeSlotEditor, NotifyListener, NumberStepper, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, PageTransition, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, Presence, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, RichTextEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, ServiceCatalog, SharedEntityStoreContext, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateGraph, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VersionDiff, ViolationAlert, VoteStack, WizardContainer, WizardNavigation, WizardProgress, arrowBetween, billboardLabel, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createInitialGameState, createSharedEntityStore, createTranslate, createUnitAnimationState, cylinderBetween, get3DClickPayload, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, meshSphere, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, registerCodeLanguageLoader, renderPatternValue, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, runTickFrame, sanitizeRichHtml, screenToIso, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, useAgentChat, useAnchorRect, useAtlasSliceDataUrl, useAuthContext, useCamera, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useMediaQuery, useOrbitalHistory, usePresence, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useSwipeGesture, useTapReveal, useTraitListens, useTranslate116 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };
|