@tightknitai/block-kitchen 0.8.6 → 0.8.7

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/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
- import { B as BlockKitchenProps, E as Template, q as PreviewSurface, r as PreviewTheme } from './palette-DToUE_3J.cjs';
3
- export { A as AlertBlock, a as AlertLevel, b as BrandPreset, c as BrandTheme, d as BrandTokens, e as BuilderBlock, C as CardBlock, f as CarouselBlock, g as ChannelOption, h as ContextActionsBlock, i as ContextActionsElement, j as CustomEmoji, F as FeedbackButtonSubobject, k as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, l as IconButtonIcon, m as InputBlock, M as MarkdownBlock, P as PaletteSection, n as PaletteVariant, o as PlanBlock, p as PreviewHooks, S as SendAsUserStatus, s as SendPayload, t as SendResult, u as SupportedBlock, v as SupportedBlockType, w as SupportedHeaderBlock, T as TableBlock, x as TableCell, y as TableColumnSetting, z as TaskCardBlock, D as TaskCardStatus, U as UrlSourceElement, V as VideoBlock, J as defaultPalette, K as extraAlertVariant, L as legacyInputVariants } from './palette-DToUE_3J.cjs';
2
+ import { B as BlockKitchenProps, U as Template, y as PreviewSurface, z as PreviewTheme } from './palette-WZCUVJTn.cjs';
3
+ export { A as AlertBlock, a as AlertLevel, b as BrandPreset, c as BrandTheme, d as BrandTokens, e as BuilderBlock, C as CardBlock, f as CarouselBlock, g as CartesianChart, h as ChannelOption, i as Chart, j as ChartAxisConfig, k as ChartDataPoint, l as ChartSeries, m as ChartType, n as ContextActionsBlock, o as ContextActionsElement, p as CustomEmoji, D as DataVisualizationBlock, F as FeedbackButtonSubobject, q as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, r as IconButtonIcon, s as InputBlock, M as MarkdownBlock, P as PaletteSection, t as PaletteVariant, u as PieChart, v as PieChartSegment, w as PlanBlock, x as PreviewHooks, S as SendAsUserStatus, E as SendPayload, G as SendResult, J as SupportedBlock, K as SupportedBlockType, L as SupportedHeaderBlock, T as TableBlock, N as TableCell, O as TableColumnSetting, Q as TaskCardBlock, R as TaskCardStatus, V as UrlSourceElement, W as VideoBlock, Y as defaultPalette, Z as extraAlertVariant, _ as legacyInputVariants } from './palette-WZCUVJTn.cjs';
4
4
  export { decodeBlocksFromString, encodeBlocksToString, toSlackBlocks } from './helpers.cjs';
5
5
  import 'slack-web-api-client';
6
6
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
- import { B as BlockKitchenProps, E as Template, q as PreviewSurface, r as PreviewTheme } from './palette-DToUE_3J.js';
3
- export { A as AlertBlock, a as AlertLevel, b as BrandPreset, c as BrandTheme, d as BrandTokens, e as BuilderBlock, C as CardBlock, f as CarouselBlock, g as ChannelOption, h as ContextActionsBlock, i as ContextActionsElement, j as CustomEmoji, F as FeedbackButtonSubobject, k as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, l as IconButtonIcon, m as InputBlock, M as MarkdownBlock, P as PaletteSection, n as PaletteVariant, o as PlanBlock, p as PreviewHooks, S as SendAsUserStatus, s as SendPayload, t as SendResult, u as SupportedBlock, v as SupportedBlockType, w as SupportedHeaderBlock, T as TableBlock, x as TableCell, y as TableColumnSetting, z as TaskCardBlock, D as TaskCardStatus, U as UrlSourceElement, V as VideoBlock, J as defaultPalette, K as extraAlertVariant, L as legacyInputVariants } from './palette-DToUE_3J.js';
2
+ import { B as BlockKitchenProps, U as Template, y as PreviewSurface, z as PreviewTheme } from './palette-WZCUVJTn.js';
3
+ export { A as AlertBlock, a as AlertLevel, b as BrandPreset, c as BrandTheme, d as BrandTokens, e as BuilderBlock, C as CardBlock, f as CarouselBlock, g as CartesianChart, h as ChannelOption, i as Chart, j as ChartAxisConfig, k as ChartDataPoint, l as ChartSeries, m as ChartType, n as ContextActionsBlock, o as ContextActionsElement, p as CustomEmoji, D as DataVisualizationBlock, F as FeedbackButtonSubobject, q as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, r as IconButtonIcon, s as InputBlock, M as MarkdownBlock, P as PaletteSection, t as PaletteVariant, u as PieChart, v as PieChartSegment, w as PlanBlock, x as PreviewHooks, S as SendAsUserStatus, E as SendPayload, G as SendResult, J as SupportedBlock, K as SupportedBlockType, L as SupportedHeaderBlock, T as TableBlock, N as TableCell, O as TableColumnSetting, Q as TaskCardBlock, R as TaskCardStatus, V as UrlSourceElement, W as VideoBlock, Y as defaultPalette, Z as extraAlertVariant, _ as legacyInputVariants } from './palette-WZCUVJTn.js';
4
4
  export { decodeBlocksFromString, encodeBlocksToString, toSlackBlocks } from './helpers.js';
5
5
  import 'slack-web-api-client';
6
6
 
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, 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,143 @@ 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
+ ]
987
1124
  }
988
1125
  ];
989
1126
  var legacyInputVariants = [
@@ -1462,6 +1599,8 @@ function labelForBlockType(type) {
1462
1599
  return "Plan";
1463
1600
  case "task_card":
1464
1601
  return "Task Card";
1602
+ case "data_visualization":
1603
+ return "Data Visualization";
1465
1604
  }
1466
1605
  }
1467
1606
  function cn(...inputs) {
@@ -3814,6 +3953,294 @@ function ImageItemCard({
3814
3953
  ) })
3815
3954
  ] });
3816
3955
  }
3956
+ var CHART_TYPES = ["line", "bar", "area", "pie"];
3957
+ function isCartesian(chart) {
3958
+ return chart.type !== "pie";
3959
+ }
3960
+ function cartesianToSegments(chart) {
3961
+ return (chart.series[0]?.data ?? []).map((d) => ({ label: d.label, value: d.value }));
3962
+ }
3963
+ function segmentsToCartesian(type, segments) {
3964
+ return {
3965
+ type,
3966
+ series: [{ name: "Series 1", data: segments.map((s) => ({ label: s.label, value: s.value })) }],
3967
+ axis_config: { categories: segments.map((s) => s.label) }
3968
+ };
3969
+ }
3970
+ function convertChart(chart, nextType) {
3971
+ if (nextType === chart.type) {
3972
+ return chart;
3973
+ }
3974
+ if (nextType === "pie") {
3975
+ return { type: "pie", segments: isCartesian(chart) ? cartesianToSegments(chart) : chart.segments };
3976
+ }
3977
+ if (isCartesian(chart)) {
3978
+ return { ...chart, type: nextType };
3979
+ }
3980
+ return segmentsToCartesian(nextType, chart.segments);
3981
+ }
3982
+ function DataVisualizationEditor({ block, onChange }) {
3983
+ const { chart } = block;
3984
+ const setChart = (next) => onChange({ ...block, chart: next });
3985
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3986
+ /* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Heading shown above the chart.", htmlFor: "dataviz-title", children: /* @__PURE__ */ jsx(
3987
+ Input,
3988
+ {
3989
+ id: "dataviz-title",
3990
+ value: block.title,
3991
+ placeholder: "e.g. Weekly active users",
3992
+ onChange: (e) => onChange({ ...block, title: e.target.value })
3993
+ }
3994
+ ) }),
3995
+ /* @__PURE__ */ jsx(EditorField, { label: "Chart type", children: /* @__PURE__ */ jsx(
3996
+ RadioGroup,
3997
+ {
3998
+ value: chart.type,
3999
+ onValueChange: (v) => setChart(convertChart(chart, v)),
4000
+ className: "flex flex-row flex-wrap gap-3",
4001
+ children: CHART_TYPES.map((t) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
4002
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: t, id: `dataviz-type-${t}` }),
4003
+ /* @__PURE__ */ jsx(Label, { htmlFor: `dataviz-type-${t}`, className: "text-xs capitalize", children: t })
4004
+ ] }, t))
4005
+ }
4006
+ ) }),
4007
+ isCartesian(chart) ? /* @__PURE__ */ jsx(CartesianFields, { chart, onChange: setChart }) : /* @__PURE__ */ jsx(PieFields, { chart, onChange: setChart })
4008
+ ] });
4009
+ }
4010
+ function NumberInput({
4011
+ id,
4012
+ value,
4013
+ onCommit,
4014
+ ariaLabel,
4015
+ className
4016
+ }) {
4017
+ const [draft, setDraft] = useState(String(value));
4018
+ useEffect(() => {
4019
+ setDraft(String(value));
4020
+ }, [value]);
4021
+ return /* @__PURE__ */ jsx(
4022
+ Input,
4023
+ {
4024
+ id,
4025
+ type: "number",
4026
+ inputMode: "numeric",
4027
+ "aria-label": ariaLabel,
4028
+ value: draft,
4029
+ className,
4030
+ onChange: (e) => {
4031
+ const raw = e.target.value;
4032
+ setDraft(raw);
4033
+ if (raw === "" || raw === "-" || raw === "." || raw === "-.") {
4034
+ return;
4035
+ }
4036
+ const next = Number(raw);
4037
+ if (!Number.isNaN(next)) {
4038
+ onCommit(next);
4039
+ }
4040
+ },
4041
+ onBlur: () => {
4042
+ const next = Number(draft);
4043
+ const safe = draft.trim() === "" || Number.isNaN(next) ? 0 : next;
4044
+ onCommit(safe);
4045
+ setDraft(String(safe));
4046
+ }
4047
+ }
4048
+ );
4049
+ }
4050
+ function CartesianFields({ chart, onChange }) {
4051
+ const series = chart.series;
4052
+ const categories = chart.axis_config?.categories && chart.axis_config.categories.length > 0 ? chart.axis_config.categories : series[0]?.data.map((d) => d.label) ?? [];
4053
+ const xLabel = chart.axis_config?.x_label ?? "";
4054
+ const yLabel = chart.axis_config?.y_label ?? "";
4055
+ const commit = (nextCategories, nextSeries, axis) => {
4056
+ const aligned = nextSeries.map((s) => ({
4057
+ name: s.name,
4058
+ data: nextCategories.map((label, i) => ({ label, value: s.data[i]?.value ?? 0 }))
4059
+ }));
4060
+ const x = axis?.x_label ?? xLabel;
4061
+ const y = axis?.y_label ?? yLabel;
4062
+ onChange({
4063
+ type: chart.type,
4064
+ series: aligned,
4065
+ axis_config: {
4066
+ categories: nextCategories,
4067
+ ...x ? { x_label: x } : {},
4068
+ ...y ? { y_label: y } : {}
4069
+ }
4070
+ });
4071
+ };
4072
+ const setCategory = (col, label) => commit(
4073
+ categories.map((c, i) => i === col ? label : c),
4074
+ series
4075
+ );
4076
+ const addCategory = () => commit([...categories, `Cat ${categories.length + 1}`], series);
4077
+ const removeCategory = (col) => commit(
4078
+ categories.filter((_, i) => i !== col),
4079
+ series.map((s) => ({ name: s.name, data: s.data.filter((_, i) => i !== col) }))
4080
+ );
4081
+ const setCell = (seriesIdx, col, value) => commit(
4082
+ categories,
4083
+ series.map(
4084
+ (s, i) => i === seriesIdx ? { name: s.name, data: s.data.map((d, j) => j === col ? { ...d, value } : d) } : s
4085
+ )
4086
+ );
4087
+ const setSeriesName = (seriesIdx, name) => commit(
4088
+ categories,
4089
+ series.map((s, i) => i === seriesIdx ? { ...s, name } : s)
4090
+ );
4091
+ const addSeries = () => commit(categories, [
4092
+ ...series,
4093
+ { name: `Series ${series.length + 1}`, data: categories.map((label) => ({ label, value: 0 })) }
4094
+ ]);
4095
+ const removeSeries = (seriesIdx) => commit(
4096
+ categories,
4097
+ series.filter((_, i) => i !== seriesIdx)
4098
+ );
4099
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
4100
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
4101
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(EditorField, { label: "X-axis label", htmlFor: "dataviz-x-label", children: /* @__PURE__ */ jsx(
4102
+ Input,
4103
+ {
4104
+ id: "dataviz-x-label",
4105
+ value: xLabel,
4106
+ placeholder: "e.g. Day",
4107
+ onChange: (e) => commit(categories, series, { x_label: e.target.value })
4108
+ }
4109
+ ) }) }),
4110
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(EditorField, { label: "Y-axis label", htmlFor: "dataviz-y-label", children: /* @__PURE__ */ jsx(
4111
+ Input,
4112
+ {
4113
+ id: "dataviz-y-label",
4114
+ value: yLabel,
4115
+ placeholder: "e.g. Users",
4116
+ onChange: (e) => commit(categories, series, { y_label: e.target.value })
4117
+ }
4118
+ ) }) })
4119
+ ] }),
4120
+ /* @__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: [
4121
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
4122
+ /* @__PURE__ */ jsx("span", { className: "w-36 shrink-0", "aria-hidden": "true" }),
4123
+ categories.map((cat, c) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-[88px] flex-1 items-center gap-1", children: [
4124
+ /* @__PURE__ */ jsx(
4125
+ Input,
4126
+ {
4127
+ "aria-label": `Category ${c + 1}`,
4128
+ value: cat,
4129
+ placeholder: `Cat ${c + 1}`,
4130
+ onChange: (e) => setCategory(c, e.target.value),
4131
+ className: "h-8 text-xs"
4132
+ }
4133
+ ),
4134
+ /* @__PURE__ */ jsx(
4135
+ "button",
4136
+ {
4137
+ type: "button",
4138
+ "aria-label": `Remove category ${c + 1}`,
4139
+ onClick: () => removeCategory(c),
4140
+ className: "flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
4141
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
4142
+ }
4143
+ )
4144
+ ] }, c))
4145
+ ] }),
4146
+ series.map((s, si) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
4147
+ /* @__PURE__ */ jsxs("div", { className: "flex w-36 shrink-0 items-center gap-1", children: [
4148
+ /* @__PURE__ */ jsx(
4149
+ Input,
4150
+ {
4151
+ "aria-label": `Series ${si + 1} name`,
4152
+ value: s.name,
4153
+ placeholder: `Series ${si + 1}`,
4154
+ onChange: (e) => setSeriesName(si, e.target.value),
4155
+ className: "h-8 text-xs"
4156
+ }
4157
+ ),
4158
+ /* @__PURE__ */ jsx(
4159
+ "button",
4160
+ {
4161
+ type: "button",
4162
+ "aria-label": `Remove series ${si + 1}`,
4163
+ onClick: () => removeSeries(si),
4164
+ className: "flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
4165
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
4166
+ }
4167
+ )
4168
+ ] }),
4169
+ categories.map((cat, c) => /* @__PURE__ */ jsx("div", { className: "min-w-[88px] flex-1", children: /* @__PURE__ */ jsx(
4170
+ NumberInput,
4171
+ {
4172
+ value: s.data[c]?.value ?? 0,
4173
+ onCommit: (n) => setCell(si, c, n),
4174
+ ariaLabel: `${s.name || `Series ${si + 1}`} value for ${cat || `category ${c + 1}`}`,
4175
+ className: "h-8 text-xs"
4176
+ }
4177
+ ) }, c))
4178
+ ] }, si))
4179
+ ] }) }),
4180
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
4181
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addSeries, className: "self-start", children: [
4182
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
4183
+ " Add series"
4184
+ ] }),
4185
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addCategory, className: "self-start", children: [
4186
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
4187
+ " Add category"
4188
+ ] })
4189
+ ] })
4190
+ ] });
4191
+ }
4192
+ function PieFields({ chart, onChange }) {
4193
+ const segments = chart.segments;
4194
+ const setSegment = (idx, change) => onChange({ ...chart, segments: segments.map((s, i) => i === idx ? { ...s, ...change } : s) });
4195
+ const removeSegment = (idx) => onChange({ ...chart, segments: segments.filter((_, i) => i !== idx) });
4196
+ const addSegment = () => onChange({ ...chart, segments: [...segments, { label: `Segment ${segments.length + 1}`, value: 0 }] });
4197
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
4198
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: "Segments" }),
4199
+ segments.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "No segments. Add one to render a slice." }) : null,
4200
+ segments.map((seg, idx) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded border bg-background p-2", children: [
4201
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4202
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground", children: [
4203
+ "Segment ",
4204
+ idx + 1
4205
+ ] }),
4206
+ /* @__PURE__ */ jsx(
4207
+ "button",
4208
+ {
4209
+ type: "button",
4210
+ "aria-label": "Remove segment",
4211
+ onClick: () => removeSegment(idx),
4212
+ className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
4213
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
4214
+ }
4215
+ )
4216
+ ] }),
4217
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
4218
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(EditorField, { label: "Label", htmlFor: `pie-label-${idx}`, children: /* @__PURE__ */ jsx(
4219
+ Input,
4220
+ {
4221
+ id: `pie-label-${idx}`,
4222
+ value: seg.label,
4223
+ placeholder: "e.g. Free",
4224
+ onChange: (e) => setSegment(idx, { label: e.target.value })
4225
+ }
4226
+ ) }) }),
4227
+ /* @__PURE__ */ jsx("div", { className: "w-28", children: /* @__PURE__ */ jsx(EditorField, { label: "Value", htmlFor: `pie-value-${idx}`, children: /* @__PURE__ */ jsx(
4228
+ NumberInput,
4229
+ {
4230
+ id: `pie-value-${idx}`,
4231
+ value: seg.value,
4232
+ onCommit: (n) => setSegment(idx, { value: n }),
4233
+ ariaLabel: `Segment ${idx + 1} value`
4234
+ }
4235
+ ) }) })
4236
+ ] })
4237
+ ] }, idx)),
4238
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addSegment, className: "self-start", children: [
4239
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
4240
+ " Add segment"
4241
+ ] })
4242
+ ] });
4243
+ }
3817
4244
  function DividerEditor() {
3818
4245
  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
4246
  }
@@ -5262,7 +5689,7 @@ var SUPPORTED_BLOCK_KINDS = /* @__PURE__ */ new Set([
5262
5689
  "rich_text_preformatted"
5263
5690
  ]);
5264
5691
  var SUPPORTED_INLINE_KINDS = /* @__PURE__ */ new Set(["text", "link", "emoji"]);
5265
- var SUPPORTED_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set(["bold", "italic", "strike", "code"]);
5692
+ var SUPPORTED_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set(["bold", "italic", "strike", "underline", "code"]);
5266
5693
  var MAX_LIST_INDENT = 8;
5267
5694
  function detectLossy(block) {
5268
5695
  const out = [];
@@ -5446,6 +5873,9 @@ function styleToMarks(style) {
5446
5873
  if (style.strike) {
5447
5874
  marks.push({ type: "strike" });
5448
5875
  }
5876
+ if (style.underline) {
5877
+ marks.push({ type: "underline" });
5878
+ }
5449
5879
  if (style.code) {
5450
5880
  marks.push({ type: "code" });
5451
5881
  }
@@ -5592,6 +6022,9 @@ function marksToStyle(marks) {
5592
6022
  if (m.type === "strike") {
5593
6023
  style.strike = true;
5594
6024
  }
6025
+ if (m.type === "underline") {
6026
+ style.underline = true;
6027
+ }
5595
6028
  if (m.type === "code") {
5596
6029
  style.code = true;
5597
6030
  }
@@ -5679,7 +6112,7 @@ var INLINE_LABEL = {
5679
6112
  broadcast: "Broadcast",
5680
6113
  usergroup: "User group"
5681
6114
  };
5682
- var STYLE_KEYS = ["bold", "italic", "strike", "code"];
6115
+ var STYLE_KEYS = ["bold", "italic", "strike", "underline", "code"];
5683
6116
  function RichTextStructuredEditor({ block, onChange }) {
5684
6117
  const elements = block.elements ?? [];
5685
6118
  const replaceElements = (next) => {
@@ -6358,6 +6791,15 @@ function Toolbar({ editor }) {
6358
6791
  Icon: Strikethrough
6359
6792
  }
6360
6793
  ),
6794
+ /* @__PURE__ */ jsx(
6795
+ ToolbarButton,
6796
+ {
6797
+ label: "Underline",
6798
+ active: editor.isActive("underline"),
6799
+ onClick: () => editor.chain().focus().toggleUnderline().run(),
6800
+ Icon: Underline
6801
+ }
6802
+ ),
6361
6803
  /* @__PURE__ */ jsx(
6362
6804
  ToolbarButton,
6363
6805
  {
@@ -7240,6 +7682,8 @@ function dispatch(block, onChange) {
7240
7682
  return /* @__PURE__ */ jsx(PlanEditor, { block, onChange: (next) => onChange(next) });
7241
7683
  case "task_card":
7242
7684
  return /* @__PURE__ */ jsx(TaskCardEditor, { block, onChange: (next) => onChange(next) });
7685
+ case "data_visualization":
7686
+ return /* @__PURE__ */ jsx(DataVisualizationEditor, { block, onChange: (next) => onChange(next) });
7243
7687
  default:
7244
7688
  return null;
7245
7689
  }
@@ -7315,7 +7759,8 @@ var BLOCK_TYPE_LABELS = {
7315
7759
  input: "Input",
7316
7760
  video: "Video",
7317
7761
  plan: "Plan",
7318
- task_card: "Task Card"
7762
+ task_card: "Task Card",
7763
+ data_visualization: "Data Visualization"
7319
7764
  };
7320
7765
  function BlockRow({
7321
7766
  builderBlock,