@tightknitai/block-kitchen 0.8.6 → 0.8.8
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/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +650 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +651 -4
- package/dist/index.js.map +1 -1
- package/dist/{palette-DToUE_3J.d.cts → palette-5_Tx97Gk.d.cts} +117 -3
- package/dist/{palette-DToUE_3J.d.ts → palette-5_Tx97Gk.d.ts} +117 -3
- package/dist/palette.cjs +180 -0
- package/dist/palette.cjs.map +1 -1
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/palette.js +181 -1
- package/dist/palette.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSensors, useSensor, PointerSensor, TouchSensor, KeyboardSensor, pointerWithin, closestCenter, DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
|
|
2
2
|
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
|
|
3
|
-
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, Plus, ChevronDown, BookOpen, ExternalLink, AlertTriangle, Trash2, Code2, MoreHorizontal, Send, Search, CheckCircle2, Check, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, Pencil, Copy, Type, Bold, Italic, Strikethrough, Code, List, ListOrdered, Quote, Undo2, Redo2, Link as Link$1, Smile } from 'lucide-react';
|
|
3
|
+
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, ChartColumnBig, Container, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, Plus, ChevronDown, BookOpen, ExternalLink, AlertTriangle, Trash2, Code2, MoreHorizontal, Send, Search, CheckCircle2, Check, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, Pencil, Copy, Type, Bold, Italic, Strikethrough, Underline, Code, List, ListOrdered, Quote, Undo2, Redo2, Link as Link$1, Smile } from 'lucide-react';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { createContext, useMemo, useState, useCallback, useRef, useEffect, useId, useContext } from 'react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -984,6 +984,186 @@ var defaultPalette = [
|
|
|
984
984
|
})
|
|
985
985
|
}
|
|
986
986
|
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
name: "Data Visualization",
|
|
990
|
+
icon: ChartColumnBig,
|
|
991
|
+
variants: [
|
|
992
|
+
{
|
|
993
|
+
id: "dataviz_line",
|
|
994
|
+
label: "Line chart",
|
|
995
|
+
factory: () => ({
|
|
996
|
+
type: "data_visualization",
|
|
997
|
+
title: "Weekly active users by platform",
|
|
998
|
+
chart: {
|
|
999
|
+
type: "line",
|
|
1000
|
+
series: [
|
|
1001
|
+
{
|
|
1002
|
+
name: "Desktop",
|
|
1003
|
+
data: [
|
|
1004
|
+
{ label: "Mon", value: 800 },
|
|
1005
|
+
{ label: "Tue", value: 920 },
|
|
1006
|
+
{ label: "Wed", value: 880 },
|
|
1007
|
+
{ label: "Thu", value: 1010 },
|
|
1008
|
+
{ label: "Fri", value: 1120 }
|
|
1009
|
+
]
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
name: "Mobile",
|
|
1013
|
+
data: [
|
|
1014
|
+
{ label: "Mon", value: 400 },
|
|
1015
|
+
{ label: "Tue", value: 530 },
|
|
1016
|
+
{ label: "Wed", value: 500 },
|
|
1017
|
+
{ label: "Thu", value: 590 },
|
|
1018
|
+
{ label: "Fri", value: 600 }
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
],
|
|
1022
|
+
axis_config: {
|
|
1023
|
+
categories: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
|
1024
|
+
x_label: "Day",
|
|
1025
|
+
y_label: "Users"
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
})
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
id: "dataviz_bar",
|
|
1032
|
+
label: "Bar chart",
|
|
1033
|
+
factory: () => ({
|
|
1034
|
+
type: "data_visualization",
|
|
1035
|
+
title: "Messages sent by platform",
|
|
1036
|
+
chart: {
|
|
1037
|
+
type: "bar",
|
|
1038
|
+
series: [
|
|
1039
|
+
{
|
|
1040
|
+
name: "Desktop",
|
|
1041
|
+
data: [
|
|
1042
|
+
{ label: "Mon", value: 1500 },
|
|
1043
|
+
{ label: "Tue", value: 1400 },
|
|
1044
|
+
{ label: "Wed", value: 1700 },
|
|
1045
|
+
{ label: "Thu", value: 1600 },
|
|
1046
|
+
{ label: "Fri", value: 1280 }
|
|
1047
|
+
]
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
name: "Mobile",
|
|
1051
|
+
data: [
|
|
1052
|
+
{ label: "Mon", value: 800 },
|
|
1053
|
+
{ label: "Tue", value: 750 },
|
|
1054
|
+
{ label: "Wed", value: 920 },
|
|
1055
|
+
{ label: "Thu", value: 880 },
|
|
1056
|
+
{ label: "Fri", value: 700 }
|
|
1057
|
+
]
|
|
1058
|
+
}
|
|
1059
|
+
],
|
|
1060
|
+
axis_config: {
|
|
1061
|
+
categories: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
|
1062
|
+
x_label: "Day",
|
|
1063
|
+
y_label: "Messages"
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
})
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
id: "dataviz_area",
|
|
1070
|
+
label: "Area chart",
|
|
1071
|
+
factory: () => ({
|
|
1072
|
+
type: "data_visualization",
|
|
1073
|
+
title: "Concurrent users by platform",
|
|
1074
|
+
chart: {
|
|
1075
|
+
type: "area",
|
|
1076
|
+
series: [
|
|
1077
|
+
{
|
|
1078
|
+
name: "Desktop",
|
|
1079
|
+
data: [
|
|
1080
|
+
{ label: "Mon", value: 2800 },
|
|
1081
|
+
{ label: "Tue", value: 3e3 },
|
|
1082
|
+
{ label: "Wed", value: 3400 },
|
|
1083
|
+
{ label: "Thu", value: 3200 },
|
|
1084
|
+
{ label: "Fri", value: 3500 }
|
|
1085
|
+
]
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
name: "Mobile",
|
|
1089
|
+
data: [
|
|
1090
|
+
{ label: "Mon", value: 1400 },
|
|
1091
|
+
{ label: "Tue", value: 1500 },
|
|
1092
|
+
{ label: "Wed", value: 1700 },
|
|
1093
|
+
{ label: "Thu", value: 1600 },
|
|
1094
|
+
{ label: "Fri", value: 1800 }
|
|
1095
|
+
]
|
|
1096
|
+
}
|
|
1097
|
+
],
|
|
1098
|
+
axis_config: {
|
|
1099
|
+
categories: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
|
1100
|
+
x_label: "Day",
|
|
1101
|
+
y_label: "Users"
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
})
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
id: "dataviz_pie",
|
|
1108
|
+
label: "Pie chart",
|
|
1109
|
+
factory: () => ({
|
|
1110
|
+
type: "data_visualization",
|
|
1111
|
+
title: "Plan distribution by tier",
|
|
1112
|
+
chart: {
|
|
1113
|
+
type: "pie",
|
|
1114
|
+
segments: [
|
|
1115
|
+
{ label: "Free", value: 4200 },
|
|
1116
|
+
{ label: "Pro", value: 2300 },
|
|
1117
|
+
{ label: "Business+", value: 1100 },
|
|
1118
|
+
{ label: "Enterprise", value: 480 }
|
|
1119
|
+
]
|
|
1120
|
+
}
|
|
1121
|
+
})
|
|
1122
|
+
}
|
|
1123
|
+
]
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
name: "Container",
|
|
1127
|
+
icon: Container,
|
|
1128
|
+
variants: [
|
|
1129
|
+
{
|
|
1130
|
+
id: "container_collapsible",
|
|
1131
|
+
label: "Collapsible container",
|
|
1132
|
+
factory: () => ({
|
|
1133
|
+
type: "container",
|
|
1134
|
+
title: { type: "plain_text", text: "Bulk update: 2 records selected" },
|
|
1135
|
+
subtitle: { type: "plain_text", text: "Review changes before confirming" },
|
|
1136
|
+
is_collapsible: true,
|
|
1137
|
+
child_blocks: [
|
|
1138
|
+
{
|
|
1139
|
+
type: "section",
|
|
1140
|
+
text: { type: "mrkdwn", text: "*DCW-1024*\nStatus: Open \u2192 Closed" }
|
|
1141
|
+
},
|
|
1142
|
+
{ type: "divider" },
|
|
1143
|
+
{
|
|
1144
|
+
type: "section",
|
|
1145
|
+
text: { type: "mrkdwn", text: "*DCW-1025*\nStatus: In Progress \u2192 Closed" }
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
type: "actions",
|
|
1149
|
+
elements: [
|
|
1150
|
+
{
|
|
1151
|
+
type: "button",
|
|
1152
|
+
text: { type: "plain_text", text: "Confirm All", emoji: true },
|
|
1153
|
+
style: "primary",
|
|
1154
|
+
action_id: "bulk_confirm"
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
type: "button",
|
|
1158
|
+
text: { type: "plain_text", text: "Cancel", emoji: true },
|
|
1159
|
+
action_id: "bulk_cancel"
|
|
1160
|
+
}
|
|
1161
|
+
]
|
|
1162
|
+
}
|
|
1163
|
+
]
|
|
1164
|
+
})
|
|
1165
|
+
}
|
|
1166
|
+
]
|
|
987
1167
|
}
|
|
988
1168
|
];
|
|
989
1169
|
var legacyInputVariants = [
|
|
@@ -1462,6 +1642,10 @@ function labelForBlockType(type) {
|
|
|
1462
1642
|
return "Plan";
|
|
1463
1643
|
case "task_card":
|
|
1464
1644
|
return "Task Card";
|
|
1645
|
+
case "data_visualization":
|
|
1646
|
+
return "Data Visualization";
|
|
1647
|
+
case "container":
|
|
1648
|
+
return "Container";
|
|
1465
1649
|
}
|
|
1466
1650
|
}
|
|
1467
1651
|
function cn(...inputs) {
|
|
@@ -3376,6 +3560,160 @@ function CarouselEditor({ block, onChange }) {
|
|
|
3376
3560
|
] })
|
|
3377
3561
|
] });
|
|
3378
3562
|
}
|
|
3563
|
+
var MAX_CHILDREN = 10;
|
|
3564
|
+
var WIDTHS = ["narrow", "standard", "wide", "full"];
|
|
3565
|
+
function ContainerEditor({ block, onChange }) {
|
|
3566
|
+
const children = block.child_blocks ?? [];
|
|
3567
|
+
const iconUrl = block.icon && "image_url" in block.icon ? block.icon.image_url ?? "" : "";
|
|
3568
|
+
const iconAlt = block.icon?.alt_text ?? "";
|
|
3569
|
+
const removeChildAt = (idx) => {
|
|
3570
|
+
onChange({ ...block, child_blocks: children.filter((_, i) => i !== idx) });
|
|
3571
|
+
};
|
|
3572
|
+
const addChild = () => {
|
|
3573
|
+
const child = {
|
|
3574
|
+
type: "section",
|
|
3575
|
+
text: { type: "mrkdwn", text: "New block." }
|
|
3576
|
+
};
|
|
3577
|
+
onChange({ ...block, child_blocks: [...children, child] });
|
|
3578
|
+
};
|
|
3579
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
3580
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Heading shown at the top of the container.", htmlFor: "container-title", children: /* @__PURE__ */ jsx(
|
|
3581
|
+
Input,
|
|
3582
|
+
{
|
|
3583
|
+
id: "container-title",
|
|
3584
|
+
value: block.title?.text ?? "",
|
|
3585
|
+
maxLength: 150,
|
|
3586
|
+
placeholder: "e.g. Bulk update: 2 records selected",
|
|
3587
|
+
onChange: (e) => onChange({ ...block, title: { type: "plain_text", text: e.target.value } })
|
|
3588
|
+
}
|
|
3589
|
+
) }),
|
|
3590
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Subtitle", help: "Optional secondary line under the title.", htmlFor: "container-subtitle", children: /* @__PURE__ */ jsx(
|
|
3591
|
+
Input,
|
|
3592
|
+
{
|
|
3593
|
+
id: "container-subtitle",
|
|
3594
|
+
value: block.subtitle?.text ?? "",
|
|
3595
|
+
maxLength: 150,
|
|
3596
|
+
placeholder: "e.g. Review changes before confirming",
|
|
3597
|
+
onChange: (e) => onChange({
|
|
3598
|
+
...block,
|
|
3599
|
+
subtitle: e.target.value ? { type: "plain_text", text: e.target.value } : void 0
|
|
3600
|
+
})
|
|
3601
|
+
}
|
|
3602
|
+
) }),
|
|
3603
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Icon URL", help: "Optional image shown left of the title.", htmlFor: "container-icon", children: /* @__PURE__ */ jsx(
|
|
3604
|
+
Input,
|
|
3605
|
+
{
|
|
3606
|
+
id: "container-icon",
|
|
3607
|
+
type: "url",
|
|
3608
|
+
value: iconUrl,
|
|
3609
|
+
placeholder: "https://example.com/icon.png",
|
|
3610
|
+
onChange: (e) => onChange({
|
|
3611
|
+
...block,
|
|
3612
|
+
icon: e.target.value ? { type: "image", image_url: e.target.value, alt_text: iconAlt || "Container icon" } : void 0
|
|
3613
|
+
})
|
|
3614
|
+
}
|
|
3615
|
+
) }),
|
|
3616
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Width", help: "How wide the container renders in the message.", children: /* @__PURE__ */ jsx(
|
|
3617
|
+
RadioGroup,
|
|
3618
|
+
{
|
|
3619
|
+
value: block.width ?? "standard",
|
|
3620
|
+
onValueChange: (v) => onChange({ ...block, width: v }),
|
|
3621
|
+
className: "flex flex-row flex-wrap gap-3",
|
|
3622
|
+
children: WIDTHS.map((w) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3623
|
+
/* @__PURE__ */ jsx(RadioGroupItem, { value: w, id: `container-width-${w}` }),
|
|
3624
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `container-width-${w}`, className: "text-xs capitalize", children: w })
|
|
3625
|
+
] }, w))
|
|
3626
|
+
}
|
|
3627
|
+
) }),
|
|
3628
|
+
/* @__PURE__ */ jsx(
|
|
3629
|
+
Checkbox,
|
|
3630
|
+
{
|
|
3631
|
+
id: "container-collapsible",
|
|
3632
|
+
label: "Collapsible",
|
|
3633
|
+
help: "Let readers expand and collapse the container.",
|
|
3634
|
+
checked: !!block.is_collapsible,
|
|
3635
|
+
onChange: (checked) => onChange({
|
|
3636
|
+
...block,
|
|
3637
|
+
is_collapsible: checked || void 0,
|
|
3638
|
+
default_collapsed: checked ? block.default_collapsed : void 0
|
|
3639
|
+
})
|
|
3640
|
+
}
|
|
3641
|
+
),
|
|
3642
|
+
/* @__PURE__ */ jsx(
|
|
3643
|
+
Checkbox,
|
|
3644
|
+
{
|
|
3645
|
+
id: "container-default-collapsed",
|
|
3646
|
+
label: "Collapsed by default",
|
|
3647
|
+
help: "Start collapsed on first render. Requires Collapsible.",
|
|
3648
|
+
checked: !!block.default_collapsed,
|
|
3649
|
+
disabled: !block.is_collapsible,
|
|
3650
|
+
onChange: (checked) => onChange({ ...block, default_collapsed: checked || void 0 })
|
|
3651
|
+
}
|
|
3652
|
+
),
|
|
3653
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3654
|
+
/* @__PURE__ */ jsx(Label, { children: "Child blocks" }),
|
|
3655
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "A container holds 1-10 blocks. To edit a child's content, use the View JSON drawer." }),
|
|
3656
|
+
children.map((child, idx) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border bg-muted/20 px-3 py-2", children: [
|
|
3657
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground", children: [
|
|
3658
|
+
idx + 1,
|
|
3659
|
+
". ",
|
|
3660
|
+
labelForBlockType(child.type)
|
|
3661
|
+
] }),
|
|
3662
|
+
/* @__PURE__ */ jsx(
|
|
3663
|
+
"button",
|
|
3664
|
+
{
|
|
3665
|
+
type: "button",
|
|
3666
|
+
"aria-label": "Remove child block",
|
|
3667
|
+
onClick: () => removeChildAt(idx),
|
|
3668
|
+
disabled: children.length <= 1,
|
|
3669
|
+
className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive disabled:cursor-not-allowed disabled:opacity-40",
|
|
3670
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
|
|
3671
|
+
}
|
|
3672
|
+
)
|
|
3673
|
+
] }, idx)),
|
|
3674
|
+
/* @__PURE__ */ jsxs(
|
|
3675
|
+
Button,
|
|
3676
|
+
{
|
|
3677
|
+
type: "button",
|
|
3678
|
+
size: "sm",
|
|
3679
|
+
onClick: addChild,
|
|
3680
|
+
disabled: children.length >= MAX_CHILDREN,
|
|
3681
|
+
className: "self-start",
|
|
3682
|
+
children: [
|
|
3683
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
3684
|
+
" Add block"
|
|
3685
|
+
]
|
|
3686
|
+
}
|
|
3687
|
+
)
|
|
3688
|
+
] })
|
|
3689
|
+
] });
|
|
3690
|
+
}
|
|
3691
|
+
function Checkbox({
|
|
3692
|
+
id,
|
|
3693
|
+
label,
|
|
3694
|
+
help,
|
|
3695
|
+
checked,
|
|
3696
|
+
disabled,
|
|
3697
|
+
onChange
|
|
3698
|
+
}) {
|
|
3699
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3700
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3701
|
+
/* @__PURE__ */ jsx(
|
|
3702
|
+
"input",
|
|
3703
|
+
{
|
|
3704
|
+
id,
|
|
3705
|
+
type: "checkbox",
|
|
3706
|
+
checked,
|
|
3707
|
+
disabled,
|
|
3708
|
+
onChange: (e) => onChange(e.target.checked),
|
|
3709
|
+
className: "h-3.5 w-3.5 cursor-pointer rounded border-input disabled:cursor-not-allowed disabled:opacity-40"
|
|
3710
|
+
}
|
|
3711
|
+
),
|
|
3712
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: id, className: "cursor-pointer text-xs", children: label })
|
|
3713
|
+
] }),
|
|
3714
|
+
help ? /* @__PURE__ */ jsx("p", { className: "ml-5 text-[11px] leading-snug text-muted-foreground", children: help }) : null
|
|
3715
|
+
] });
|
|
3716
|
+
}
|
|
3379
3717
|
var MAX_ELEMENTS = 5;
|
|
3380
3718
|
function ContextActionsEditor({ block, onChange }) {
|
|
3381
3719
|
const elements = block.elements ?? [];
|
|
@@ -3814,6 +4152,294 @@ function ImageItemCard({
|
|
|
3814
4152
|
) })
|
|
3815
4153
|
] });
|
|
3816
4154
|
}
|
|
4155
|
+
var CHART_TYPES = ["line", "bar", "area", "pie"];
|
|
4156
|
+
function isCartesian(chart) {
|
|
4157
|
+
return chart.type !== "pie";
|
|
4158
|
+
}
|
|
4159
|
+
function cartesianToSegments(chart) {
|
|
4160
|
+
return (chart.series[0]?.data ?? []).map((d) => ({ label: d.label, value: d.value }));
|
|
4161
|
+
}
|
|
4162
|
+
function segmentsToCartesian(type, segments) {
|
|
4163
|
+
return {
|
|
4164
|
+
type,
|
|
4165
|
+
series: [{ name: "Series 1", data: segments.map((s) => ({ label: s.label, value: s.value })) }],
|
|
4166
|
+
axis_config: { categories: segments.map((s) => s.label) }
|
|
4167
|
+
};
|
|
4168
|
+
}
|
|
4169
|
+
function convertChart(chart, nextType) {
|
|
4170
|
+
if (nextType === chart.type) {
|
|
4171
|
+
return chart;
|
|
4172
|
+
}
|
|
4173
|
+
if (nextType === "pie") {
|
|
4174
|
+
return { type: "pie", segments: isCartesian(chart) ? cartesianToSegments(chart) : chart.segments };
|
|
4175
|
+
}
|
|
4176
|
+
if (isCartesian(chart)) {
|
|
4177
|
+
return { ...chart, type: nextType };
|
|
4178
|
+
}
|
|
4179
|
+
return segmentsToCartesian(nextType, chart.segments);
|
|
4180
|
+
}
|
|
4181
|
+
function DataVisualizationEditor({ block, onChange }) {
|
|
4182
|
+
const { chart } = block;
|
|
4183
|
+
const setChart = (next) => onChange({ ...block, chart: next });
|
|
4184
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
4185
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Heading shown above the chart.", htmlFor: "dataviz-title", children: /* @__PURE__ */ jsx(
|
|
4186
|
+
Input,
|
|
4187
|
+
{
|
|
4188
|
+
id: "dataviz-title",
|
|
4189
|
+
value: block.title,
|
|
4190
|
+
placeholder: "e.g. Weekly active users",
|
|
4191
|
+
onChange: (e) => onChange({ ...block, title: e.target.value })
|
|
4192
|
+
}
|
|
4193
|
+
) }),
|
|
4194
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Chart type", children: /* @__PURE__ */ jsx(
|
|
4195
|
+
RadioGroup,
|
|
4196
|
+
{
|
|
4197
|
+
value: chart.type,
|
|
4198
|
+
onValueChange: (v) => setChart(convertChart(chart, v)),
|
|
4199
|
+
className: "flex flex-row flex-wrap gap-3",
|
|
4200
|
+
children: CHART_TYPES.map((t) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
4201
|
+
/* @__PURE__ */ jsx(RadioGroupItem, { value: t, id: `dataviz-type-${t}` }),
|
|
4202
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `dataviz-type-${t}`, className: "text-xs capitalize", children: t })
|
|
4203
|
+
] }, t))
|
|
4204
|
+
}
|
|
4205
|
+
) }),
|
|
4206
|
+
isCartesian(chart) ? /* @__PURE__ */ jsx(CartesianFields, { chart, onChange: setChart }) : /* @__PURE__ */ jsx(PieFields, { chart, onChange: setChart })
|
|
4207
|
+
] });
|
|
4208
|
+
}
|
|
4209
|
+
function NumberInput({
|
|
4210
|
+
id,
|
|
4211
|
+
value,
|
|
4212
|
+
onCommit,
|
|
4213
|
+
ariaLabel,
|
|
4214
|
+
className
|
|
4215
|
+
}) {
|
|
4216
|
+
const [draft, setDraft] = useState(String(value));
|
|
4217
|
+
useEffect(() => {
|
|
4218
|
+
setDraft(String(value));
|
|
4219
|
+
}, [value]);
|
|
4220
|
+
return /* @__PURE__ */ jsx(
|
|
4221
|
+
Input,
|
|
4222
|
+
{
|
|
4223
|
+
id,
|
|
4224
|
+
type: "number",
|
|
4225
|
+
inputMode: "numeric",
|
|
4226
|
+
"aria-label": ariaLabel,
|
|
4227
|
+
value: draft,
|
|
4228
|
+
className,
|
|
4229
|
+
onChange: (e) => {
|
|
4230
|
+
const raw = e.target.value;
|
|
4231
|
+
setDraft(raw);
|
|
4232
|
+
if (raw === "" || raw === "-" || raw === "." || raw === "-.") {
|
|
4233
|
+
return;
|
|
4234
|
+
}
|
|
4235
|
+
const next = Number(raw);
|
|
4236
|
+
if (!Number.isNaN(next)) {
|
|
4237
|
+
onCommit(next);
|
|
4238
|
+
}
|
|
4239
|
+
},
|
|
4240
|
+
onBlur: () => {
|
|
4241
|
+
const next = Number(draft);
|
|
4242
|
+
const safe = draft.trim() === "" || Number.isNaN(next) ? 0 : next;
|
|
4243
|
+
onCommit(safe);
|
|
4244
|
+
setDraft(String(safe));
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
);
|
|
4248
|
+
}
|
|
4249
|
+
function CartesianFields({ chart, onChange }) {
|
|
4250
|
+
const series = chart.series;
|
|
4251
|
+
const categories = chart.axis_config?.categories && chart.axis_config.categories.length > 0 ? chart.axis_config.categories : series[0]?.data.map((d) => d.label) ?? [];
|
|
4252
|
+
const xLabel = chart.axis_config?.x_label ?? "";
|
|
4253
|
+
const yLabel = chart.axis_config?.y_label ?? "";
|
|
4254
|
+
const commit = (nextCategories, nextSeries, axis) => {
|
|
4255
|
+
const aligned = nextSeries.map((s) => ({
|
|
4256
|
+
name: s.name,
|
|
4257
|
+
data: nextCategories.map((label, i) => ({ label, value: s.data[i]?.value ?? 0 }))
|
|
4258
|
+
}));
|
|
4259
|
+
const x = axis?.x_label ?? xLabel;
|
|
4260
|
+
const y = axis?.y_label ?? yLabel;
|
|
4261
|
+
onChange({
|
|
4262
|
+
type: chart.type,
|
|
4263
|
+
series: aligned,
|
|
4264
|
+
axis_config: {
|
|
4265
|
+
categories: nextCategories,
|
|
4266
|
+
...x ? { x_label: x } : {},
|
|
4267
|
+
...y ? { y_label: y } : {}
|
|
4268
|
+
}
|
|
4269
|
+
});
|
|
4270
|
+
};
|
|
4271
|
+
const setCategory = (col, label) => commit(
|
|
4272
|
+
categories.map((c, i) => i === col ? label : c),
|
|
4273
|
+
series
|
|
4274
|
+
);
|
|
4275
|
+
const addCategory = () => commit([...categories, `Cat ${categories.length + 1}`], series);
|
|
4276
|
+
const removeCategory = (col) => commit(
|
|
4277
|
+
categories.filter((_, i) => i !== col),
|
|
4278
|
+
series.map((s) => ({ name: s.name, data: s.data.filter((_, i) => i !== col) }))
|
|
4279
|
+
);
|
|
4280
|
+
const setCell = (seriesIdx, col, value) => commit(
|
|
4281
|
+
categories,
|
|
4282
|
+
series.map(
|
|
4283
|
+
(s, i) => i === seriesIdx ? { name: s.name, data: s.data.map((d, j) => j === col ? { ...d, value } : d) } : s
|
|
4284
|
+
)
|
|
4285
|
+
);
|
|
4286
|
+
const setSeriesName = (seriesIdx, name) => commit(
|
|
4287
|
+
categories,
|
|
4288
|
+
series.map((s, i) => i === seriesIdx ? { ...s, name } : s)
|
|
4289
|
+
);
|
|
4290
|
+
const addSeries = () => commit(categories, [
|
|
4291
|
+
...series,
|
|
4292
|
+
{ name: `Series ${series.length + 1}`, data: categories.map((label) => ({ label, value: 0 })) }
|
|
4293
|
+
]);
|
|
4294
|
+
const removeSeries = (seriesIdx) => commit(
|
|
4295
|
+
categories,
|
|
4296
|
+
series.filter((_, i) => i !== seriesIdx)
|
|
4297
|
+
);
|
|
4298
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
4299
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
4300
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(EditorField, { label: "X-axis label", htmlFor: "dataviz-x-label", children: /* @__PURE__ */ jsx(
|
|
4301
|
+
Input,
|
|
4302
|
+
{
|
|
4303
|
+
id: "dataviz-x-label",
|
|
4304
|
+
value: xLabel,
|
|
4305
|
+
placeholder: "e.g. Day",
|
|
4306
|
+
onChange: (e) => commit(categories, series, { x_label: e.target.value })
|
|
4307
|
+
}
|
|
4308
|
+
) }) }),
|
|
4309
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(EditorField, { label: "Y-axis label", htmlFor: "dataviz-y-label", children: /* @__PURE__ */ jsx(
|
|
4310
|
+
Input,
|
|
4311
|
+
{
|
|
4312
|
+
id: "dataviz-y-label",
|
|
4313
|
+
value: yLabel,
|
|
4314
|
+
placeholder: "e.g. Users",
|
|
4315
|
+
onChange: (e) => commit(categories, series, { y_label: e.target.value })
|
|
4316
|
+
}
|
|
4317
|
+
) }) })
|
|
4318
|
+
] }),
|
|
4319
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Data", help: "Categories are the x-axis; each series is plotted across them.", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 overflow-x-auto", children: [
|
|
4320
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
4321
|
+
/* @__PURE__ */ jsx("span", { className: "w-36 shrink-0", "aria-hidden": "true" }),
|
|
4322
|
+
categories.map((cat, c) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-[88px] flex-1 items-center gap-1", children: [
|
|
4323
|
+
/* @__PURE__ */ jsx(
|
|
4324
|
+
Input,
|
|
4325
|
+
{
|
|
4326
|
+
"aria-label": `Category ${c + 1}`,
|
|
4327
|
+
value: cat,
|
|
4328
|
+
placeholder: `Cat ${c + 1}`,
|
|
4329
|
+
onChange: (e) => setCategory(c, e.target.value),
|
|
4330
|
+
className: "h-8 text-xs"
|
|
4331
|
+
}
|
|
4332
|
+
),
|
|
4333
|
+
/* @__PURE__ */ jsx(
|
|
4334
|
+
"button",
|
|
4335
|
+
{
|
|
4336
|
+
type: "button",
|
|
4337
|
+
"aria-label": `Remove category ${c + 1}`,
|
|
4338
|
+
onClick: () => removeCategory(c),
|
|
4339
|
+
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
|
|
4340
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
4341
|
+
}
|
|
4342
|
+
)
|
|
4343
|
+
] }, c))
|
|
4344
|
+
] }),
|
|
4345
|
+
series.map((s, si) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
4346
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-36 shrink-0 items-center gap-1", children: [
|
|
4347
|
+
/* @__PURE__ */ jsx(
|
|
4348
|
+
Input,
|
|
4349
|
+
{
|
|
4350
|
+
"aria-label": `Series ${si + 1} name`,
|
|
4351
|
+
value: s.name,
|
|
4352
|
+
placeholder: `Series ${si + 1}`,
|
|
4353
|
+
onChange: (e) => setSeriesName(si, e.target.value),
|
|
4354
|
+
className: "h-8 text-xs"
|
|
4355
|
+
}
|
|
4356
|
+
),
|
|
4357
|
+
/* @__PURE__ */ jsx(
|
|
4358
|
+
"button",
|
|
4359
|
+
{
|
|
4360
|
+
type: "button",
|
|
4361
|
+
"aria-label": `Remove series ${si + 1}`,
|
|
4362
|
+
onClick: () => removeSeries(si),
|
|
4363
|
+
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
|
|
4364
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
4365
|
+
}
|
|
4366
|
+
)
|
|
4367
|
+
] }),
|
|
4368
|
+
categories.map((cat, c) => /* @__PURE__ */ jsx("div", { className: "min-w-[88px] flex-1", children: /* @__PURE__ */ jsx(
|
|
4369
|
+
NumberInput,
|
|
4370
|
+
{
|
|
4371
|
+
value: s.data[c]?.value ?? 0,
|
|
4372
|
+
onCommit: (n) => setCell(si, c, n),
|
|
4373
|
+
ariaLabel: `${s.name || `Series ${si + 1}`} value for ${cat || `category ${c + 1}`}`,
|
|
4374
|
+
className: "h-8 text-xs"
|
|
4375
|
+
}
|
|
4376
|
+
) }, c))
|
|
4377
|
+
] }, si))
|
|
4378
|
+
] }) }),
|
|
4379
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
4380
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addSeries, className: "self-start", children: [
|
|
4381
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
4382
|
+
" Add series"
|
|
4383
|
+
] }),
|
|
4384
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addCategory, className: "self-start", children: [
|
|
4385
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
4386
|
+
" Add category"
|
|
4387
|
+
] })
|
|
4388
|
+
] })
|
|
4389
|
+
] });
|
|
4390
|
+
}
|
|
4391
|
+
function PieFields({ chart, onChange }) {
|
|
4392
|
+
const segments = chart.segments;
|
|
4393
|
+
const setSegment = (idx, change) => onChange({ ...chart, segments: segments.map((s, i) => i === idx ? { ...s, ...change } : s) });
|
|
4394
|
+
const removeSegment = (idx) => onChange({ ...chart, segments: segments.filter((_, i) => i !== idx) });
|
|
4395
|
+
const addSegment = () => onChange({ ...chart, segments: [...segments, { label: `Segment ${segments.length + 1}`, value: 0 }] });
|
|
4396
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
|
|
4397
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: "Segments" }),
|
|
4398
|
+
segments.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "No segments. Add one to render a slice." }) : null,
|
|
4399
|
+
segments.map((seg, idx) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded border bg-background p-2", children: [
|
|
4400
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4401
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground", children: [
|
|
4402
|
+
"Segment ",
|
|
4403
|
+
idx + 1
|
|
4404
|
+
] }),
|
|
4405
|
+
/* @__PURE__ */ jsx(
|
|
4406
|
+
"button",
|
|
4407
|
+
{
|
|
4408
|
+
type: "button",
|
|
4409
|
+
"aria-label": "Remove segment",
|
|
4410
|
+
onClick: () => removeSegment(idx),
|
|
4411
|
+
className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
|
|
4412
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
|
|
4413
|
+
}
|
|
4414
|
+
)
|
|
4415
|
+
] }),
|
|
4416
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
4417
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(EditorField, { label: "Label", htmlFor: `pie-label-${idx}`, children: /* @__PURE__ */ jsx(
|
|
4418
|
+
Input,
|
|
4419
|
+
{
|
|
4420
|
+
id: `pie-label-${idx}`,
|
|
4421
|
+
value: seg.label,
|
|
4422
|
+
placeholder: "e.g. Free",
|
|
4423
|
+
onChange: (e) => setSegment(idx, { label: e.target.value })
|
|
4424
|
+
}
|
|
4425
|
+
) }) }),
|
|
4426
|
+
/* @__PURE__ */ jsx("div", { className: "w-28", children: /* @__PURE__ */ jsx(EditorField, { label: "Value", htmlFor: `pie-value-${idx}`, children: /* @__PURE__ */ jsx(
|
|
4427
|
+
NumberInput,
|
|
4428
|
+
{
|
|
4429
|
+
id: `pie-value-${idx}`,
|
|
4430
|
+
value: seg.value,
|
|
4431
|
+
onCommit: (n) => setSegment(idx, { value: n }),
|
|
4432
|
+
ariaLabel: `Segment ${idx + 1} value`
|
|
4433
|
+
}
|
|
4434
|
+
) }) })
|
|
4435
|
+
] })
|
|
4436
|
+
] }, idx)),
|
|
4437
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addSegment, className: "self-start", children: [
|
|
4438
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
4439
|
+
" Add segment"
|
|
4440
|
+
] })
|
|
4441
|
+
] });
|
|
4442
|
+
}
|
|
3817
4443
|
function DividerEditor() {
|
|
3818
4444
|
return /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "A horizontal line that separates content. This block has no options to configure." });
|
|
3819
4445
|
}
|
|
@@ -5262,7 +5888,7 @@ var SUPPORTED_BLOCK_KINDS = /* @__PURE__ */ new Set([
|
|
|
5262
5888
|
"rich_text_preformatted"
|
|
5263
5889
|
]);
|
|
5264
5890
|
var SUPPORTED_INLINE_KINDS = /* @__PURE__ */ new Set(["text", "link", "emoji"]);
|
|
5265
|
-
var SUPPORTED_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set(["bold", "italic", "strike", "code"]);
|
|
5891
|
+
var SUPPORTED_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set(["bold", "italic", "strike", "underline", "code"]);
|
|
5266
5892
|
var MAX_LIST_INDENT = 8;
|
|
5267
5893
|
function detectLossy(block) {
|
|
5268
5894
|
const out = [];
|
|
@@ -5446,6 +6072,9 @@ function styleToMarks(style) {
|
|
|
5446
6072
|
if (style.strike) {
|
|
5447
6073
|
marks.push({ type: "strike" });
|
|
5448
6074
|
}
|
|
6075
|
+
if (style.underline) {
|
|
6076
|
+
marks.push({ type: "underline" });
|
|
6077
|
+
}
|
|
5449
6078
|
if (style.code) {
|
|
5450
6079
|
marks.push({ type: "code" });
|
|
5451
6080
|
}
|
|
@@ -5592,6 +6221,9 @@ function marksToStyle(marks) {
|
|
|
5592
6221
|
if (m.type === "strike") {
|
|
5593
6222
|
style.strike = true;
|
|
5594
6223
|
}
|
|
6224
|
+
if (m.type === "underline") {
|
|
6225
|
+
style.underline = true;
|
|
6226
|
+
}
|
|
5595
6227
|
if (m.type === "code") {
|
|
5596
6228
|
style.code = true;
|
|
5597
6229
|
}
|
|
@@ -5679,7 +6311,7 @@ var INLINE_LABEL = {
|
|
|
5679
6311
|
broadcast: "Broadcast",
|
|
5680
6312
|
usergroup: "User group"
|
|
5681
6313
|
};
|
|
5682
|
-
var STYLE_KEYS = ["bold", "italic", "strike", "code"];
|
|
6314
|
+
var STYLE_KEYS = ["bold", "italic", "strike", "underline", "code"];
|
|
5683
6315
|
function RichTextStructuredEditor({ block, onChange }) {
|
|
5684
6316
|
const elements = block.elements ?? [];
|
|
5685
6317
|
const replaceElements = (next) => {
|
|
@@ -6358,6 +6990,15 @@ function Toolbar({ editor }) {
|
|
|
6358
6990
|
Icon: Strikethrough
|
|
6359
6991
|
}
|
|
6360
6992
|
),
|
|
6993
|
+
/* @__PURE__ */ jsx(
|
|
6994
|
+
ToolbarButton,
|
|
6995
|
+
{
|
|
6996
|
+
label: "Underline",
|
|
6997
|
+
active: editor.isActive("underline"),
|
|
6998
|
+
onClick: () => editor.chain().focus().toggleUnderline().run(),
|
|
6999
|
+
Icon: Underline
|
|
7000
|
+
}
|
|
7001
|
+
),
|
|
6361
7002
|
/* @__PURE__ */ jsx(
|
|
6362
7003
|
ToolbarButton,
|
|
6363
7004
|
{
|
|
@@ -7240,6 +7881,10 @@ function dispatch(block, onChange) {
|
|
|
7240
7881
|
return /* @__PURE__ */ jsx(PlanEditor, { block, onChange: (next) => onChange(next) });
|
|
7241
7882
|
case "task_card":
|
|
7242
7883
|
return /* @__PURE__ */ jsx(TaskCardEditor, { block, onChange: (next) => onChange(next) });
|
|
7884
|
+
case "data_visualization":
|
|
7885
|
+
return /* @__PURE__ */ jsx(DataVisualizationEditor, { block, onChange: (next) => onChange(next) });
|
|
7886
|
+
case "container":
|
|
7887
|
+
return /* @__PURE__ */ jsx(ContainerEditor, { block, onChange: (next) => onChange(next) });
|
|
7243
7888
|
default:
|
|
7244
7889
|
return null;
|
|
7245
7890
|
}
|
|
@@ -7315,7 +7960,9 @@ var BLOCK_TYPE_LABELS = {
|
|
|
7315
7960
|
input: "Input",
|
|
7316
7961
|
video: "Video",
|
|
7317
7962
|
plan: "Plan",
|
|
7318
|
-
task_card: "Task Card"
|
|
7963
|
+
task_card: "Task Card",
|
|
7964
|
+
data_visualization: "Data Visualization",
|
|
7965
|
+
container: "Container"
|
|
7319
7966
|
};
|
|
7320
7967
|
function BlockRow({
|
|
7321
7968
|
builderBlock,
|