@tightknitai/block-kitchen 0.10.19 → 0.10.21
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/README.md +13 -4
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +748 -231
- 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 +749 -232
- package/dist/index.js.map +1 -1
- package/dist/{palette-DNUiqoQK.d.cts → palette-CXXqlwIH.d.cts} +82 -15
- package/dist/{palette-DNUiqoQK.d.ts → palette-CXXqlwIH.d.ts} +82 -15
- package/dist/palette.cjs +52 -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 +52 -0
- package/dist/palette.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +4 -3
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, ChartColumnBig, Container, Loader2, ExternalLink, AlertTriangle, ChevronRight, ChevronLeft, GripVertical, ChevronsUpDown, Check, Sun, Moon, MessageSquare, AppWindow, Home, Plus, ChevronDown, BookOpen, Undo2, Redo2, Trash2, Code2, Pencil, Send, Search, Copy, Info, CheckCircle2, LayoutGrid, ArrowUp, ArrowDown, Type, Bold, Italic, Strikethrough, Underline, Code, AtSign, List, ListOrdered, Quote, Smile, Link as Link$1 } from 'lucide-react';
|
|
3
|
+
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, ChartColumnBig, Container, Loader2, ExternalLink, AlertTriangle, ChevronRight, ChevronLeft, GripVertical, ChevronsUpDown, Check, Sun, Moon, MessageSquare, AppWindow, Home, Plus, ChevronDown, BookOpen, Undo2, Redo2, Trash2, Code2, Pencil, Send, Search, Copy, Info, CheckCircle2, LayoutGrid, ArrowUp, ArrowDown, Type, Bold, Italic, Strikethrough, Underline, Code, AtSign, Hash, List, ListOrdered, Quote, Smile, Link as Link$1 } from 'lucide-react';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { createContext, useContext, useState, useRef, useEffect, useCallback, useMemo, useId } from 'react';
|
|
6
6
|
import { clsx } from 'clsx';
|
|
@@ -21,6 +21,7 @@ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
|
21
21
|
import Link from '@tiptap/extension-link';
|
|
22
22
|
import { Node as Node$1, ReactNodeViewRenderer, mergeAttributes, Extension, NodeViewWrapper, useEditor, EditorContent } from '@tiptap/react';
|
|
23
23
|
import StarterKit from '@tiptap/starter-kit';
|
|
24
|
+
import { PluginKey } from '@tiptap/pm/state';
|
|
24
25
|
import { Suggestion, exitSuggestion } from '@tiptap/suggestion';
|
|
25
26
|
|
|
26
27
|
// src/components/block-kitchen.tsx
|
|
@@ -1066,6 +1067,58 @@ var defaultPalette = [
|
|
|
1066
1067
|
]
|
|
1067
1068
|
]
|
|
1068
1069
|
})
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
// Slack's documented example.
|
|
1073
|
+
id: "data_table_basic",
|
|
1074
|
+
label: "Data table",
|
|
1075
|
+
factory: () => ({
|
|
1076
|
+
type: "data_table",
|
|
1077
|
+
caption: "A Fabulous Table",
|
|
1078
|
+
rows: [
|
|
1079
|
+
[
|
|
1080
|
+
{ type: "raw_text", text: "Name" },
|
|
1081
|
+
{ type: "raw_text", text: "Department" },
|
|
1082
|
+
{ type: "raw_text", text: "Badge" }
|
|
1083
|
+
],
|
|
1084
|
+
[
|
|
1085
|
+
{ type: "raw_text", text: "Data Refinement Department" },
|
|
1086
|
+
{ type: "raw_text", text: "MDR" },
|
|
1087
|
+
{
|
|
1088
|
+
type: "rich_text",
|
|
1089
|
+
elements: [
|
|
1090
|
+
{ type: "rich_text_section", elements: [{ type: "text", text: "Blue", style: { bold: true } }] }
|
|
1091
|
+
]
|
|
1092
|
+
}
|
|
1093
|
+
],
|
|
1094
|
+
[
|
|
1095
|
+
{ type: "raw_text", text: "Art Sourcing Department" },
|
|
1096
|
+
{ type: "raw_text", text: "O&D" },
|
|
1097
|
+
{
|
|
1098
|
+
type: "rich_text",
|
|
1099
|
+
elements: [
|
|
1100
|
+
{
|
|
1101
|
+
type: "rich_text_section",
|
|
1102
|
+
elements: [
|
|
1103
|
+
{ type: "text", text: "Green " },
|
|
1104
|
+
{ type: "text", text: "review", style: { italic: true } }
|
|
1105
|
+
]
|
|
1106
|
+
}
|
|
1107
|
+
]
|
|
1108
|
+
}
|
|
1109
|
+
],
|
|
1110
|
+
[
|
|
1111
|
+
{ type: "raw_text", text: "Wellness Department" },
|
|
1112
|
+
{ type: "raw_text", text: "Wellness Center" },
|
|
1113
|
+
{
|
|
1114
|
+
type: "rich_text",
|
|
1115
|
+
elements: [
|
|
1116
|
+
{ type: "rich_text_section", elements: [{ type: "text", text: "Limited", style: { bold: true } }] }
|
|
1117
|
+
]
|
|
1118
|
+
}
|
|
1119
|
+
]
|
|
1120
|
+
]
|
|
1121
|
+
})
|
|
1069
1122
|
}
|
|
1070
1123
|
]
|
|
1071
1124
|
},
|
|
@@ -1730,6 +1783,8 @@ function labelForBlockType(type) {
|
|
|
1730
1783
|
return "Data Visualization";
|
|
1731
1784
|
case "container":
|
|
1732
1785
|
return "Container";
|
|
1786
|
+
case "data_table":
|
|
1787
|
+
return "Data Table";
|
|
1733
1788
|
}
|
|
1734
1789
|
}
|
|
1735
1790
|
var Sheet = DialogPrimitive.Root;
|
|
@@ -5190,15 +5245,16 @@ function makeEmojiImportResolver(customByName, index = getEmojiIndex()) {
|
|
|
5190
5245
|
|
|
5191
5246
|
// src/lib/rich-text-tiptap.ts
|
|
5192
5247
|
var USER_MENTION_NODE = "userMention";
|
|
5248
|
+
var CHANNEL_MENTION_NODE = "channelMention";
|
|
5193
5249
|
var SUPPORTED_BLOCK_KINDS = /* @__PURE__ */ new Set([
|
|
5194
5250
|
"rich_text_section",
|
|
5195
5251
|
"rich_text_list",
|
|
5196
5252
|
"rich_text_quote",
|
|
5197
5253
|
"rich_text_preformatted"
|
|
5198
5254
|
]);
|
|
5199
|
-
var SUPPORTED_INLINE_KINDS = /* @__PURE__ */ new Set(["text", "link", "emoji", "user"]);
|
|
5255
|
+
var SUPPORTED_INLINE_KINDS = /* @__PURE__ */ new Set(["text", "link", "emoji", "user", "channel"]);
|
|
5200
5256
|
var SUPPORTED_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set(["bold", "italic", "strike", "underline", "code"]);
|
|
5201
|
-
var
|
|
5257
|
+
var SUPPORTED_MENTION_STYLE_KEYS = /* @__PURE__ */ new Set(["bold", "italic", "strike", "underline"]);
|
|
5202
5258
|
var MAX_LIST_INDENT = 8;
|
|
5203
5259
|
function detectLossy(block) {
|
|
5204
5260
|
const out = [];
|
|
@@ -5253,10 +5309,13 @@ function scanInlines(inlines, where, out) {
|
|
|
5253
5309
|
}
|
|
5254
5310
|
}
|
|
5255
5311
|
}
|
|
5256
|
-
if (inline.type === "user") {
|
|
5312
|
+
if (inline.type === "user" || inline.type === "channel") {
|
|
5313
|
+
if (inline.type === "channel" && !inline.channel_id) {
|
|
5314
|
+
out.push({ label: "Channel without id", where: sub });
|
|
5315
|
+
}
|
|
5257
5316
|
for (const k of Object.keys(inline.style ?? {})) {
|
|
5258
|
-
if (!
|
|
5259
|
-
out.push({ label:
|
|
5317
|
+
if (!SUPPORTED_MENTION_STYLE_KEYS.has(k)) {
|
|
5318
|
+
out.push({ label: `${inline.type === "channel" ? "Channel" : "Mention"} style: ${k}`, where: sub });
|
|
5260
5319
|
}
|
|
5261
5320
|
}
|
|
5262
5321
|
}
|
|
@@ -5382,6 +5441,20 @@ function inlinesToPM(inlines, resolveEmoji) {
|
|
|
5382
5441
|
node.marks = marks;
|
|
5383
5442
|
}
|
|
5384
5443
|
out.push(node);
|
|
5444
|
+
} else if (inline.type === "channel") {
|
|
5445
|
+
const channel = inline;
|
|
5446
|
+
if (!channel.channel_id) {
|
|
5447
|
+
continue;
|
|
5448
|
+
}
|
|
5449
|
+
const node = {
|
|
5450
|
+
type: CHANNEL_MENTION_NODE,
|
|
5451
|
+
attrs: { channelId: channel.channel_id, name: null }
|
|
5452
|
+
};
|
|
5453
|
+
const marks = styleToMarks(channel.style);
|
|
5454
|
+
if (marks.length > 0) {
|
|
5455
|
+
node.marks = marks;
|
|
5456
|
+
}
|
|
5457
|
+
out.push(node);
|
|
5385
5458
|
} else if (inline.type === "link") {
|
|
5386
5459
|
const link = inline;
|
|
5387
5460
|
const text = link.text || link.url || "";
|
|
@@ -5521,13 +5594,26 @@ function proseMirrorInlinesToRichTextElements(nodes) {
|
|
|
5521
5594
|
continue;
|
|
5522
5595
|
}
|
|
5523
5596
|
const user = { type: "user", user_id: userId };
|
|
5524
|
-
const style2 =
|
|
5597
|
+
const style2 = mentionStyle(node.marks ?? []);
|
|
5525
5598
|
if (Object.keys(style2).length > 0) {
|
|
5526
5599
|
user.style = style2;
|
|
5527
5600
|
}
|
|
5528
5601
|
out.push(user);
|
|
5529
5602
|
continue;
|
|
5530
5603
|
}
|
|
5604
|
+
if (node.type === CHANNEL_MENTION_NODE) {
|
|
5605
|
+
const channelId = String(node.attrs?.channelId ?? "");
|
|
5606
|
+
if (!channelId) {
|
|
5607
|
+
continue;
|
|
5608
|
+
}
|
|
5609
|
+
const channel = { type: "channel", channel_id: channelId };
|
|
5610
|
+
const style2 = mentionStyle(node.marks ?? []);
|
|
5611
|
+
if (Object.keys(style2).length > 0) {
|
|
5612
|
+
channel.style = style2;
|
|
5613
|
+
}
|
|
5614
|
+
out.push(channel);
|
|
5615
|
+
continue;
|
|
5616
|
+
}
|
|
5531
5617
|
if (node.type === "hardBreak") {
|
|
5532
5618
|
out.push({ type: "text", text: "\n" });
|
|
5533
5619
|
continue;
|
|
@@ -5582,10 +5668,10 @@ function marksToStyle(marks) {
|
|
|
5582
5668
|
}
|
|
5583
5669
|
return style;
|
|
5584
5670
|
}
|
|
5585
|
-
function
|
|
5671
|
+
function mentionStyle(marks) {
|
|
5586
5672
|
const style = {};
|
|
5587
5673
|
for (const [key, value] of Object.entries(marksToStyle(marks))) {
|
|
5588
|
-
if (
|
|
5674
|
+
if (SUPPORTED_MENTION_STYLE_KEYS.has(key)) {
|
|
5589
5675
|
style[key] = value;
|
|
5590
5676
|
}
|
|
5591
5677
|
}
|
|
@@ -5614,50 +5700,52 @@ function sameStyle(a, b) {
|
|
|
5614
5700
|
}
|
|
5615
5701
|
return ak.every((k, i) => k === bk[i]);
|
|
5616
5702
|
}
|
|
5617
|
-
function
|
|
5618
|
-
|
|
5619
|
-
const label = `:${name}:`;
|
|
5620
|
-
return /* @__PURE__ */ jsx(NodeViewWrapper, { as: "span", className: "bk-emoji-node", "data-emoji": name, title: label, children: src ? /* @__PURE__ */ jsx(
|
|
5621
|
-
"img",
|
|
5622
|
-
{
|
|
5623
|
-
src,
|
|
5624
|
-
alt: label,
|
|
5625
|
-
style: {
|
|
5626
|
-
display: "inline-block",
|
|
5627
|
-
width: "1.25em",
|
|
5628
|
-
height: "1.25em",
|
|
5629
|
-
verticalAlign: "-0.25em",
|
|
5630
|
-
objectFit: "contain"
|
|
5631
|
-
}
|
|
5632
|
-
}
|
|
5633
|
-
) : /* @__PURE__ */ jsx("span", { "aria-label": label, role: "img", children: unicode ? codepointsToGlyph(unicode) : label }) });
|
|
5703
|
+
function channelMentionLabel(attrs, getChannelName) {
|
|
5704
|
+
return getChannelName?.(attrs.channelId) ?? attrs.name ?? attrs.channelId;
|
|
5634
5705
|
}
|
|
5635
|
-
|
|
5636
|
-
|
|
5706
|
+
function ChannelMentionNodeView({ node }) {
|
|
5707
|
+
const mentions = useMentions();
|
|
5708
|
+
const attrs = node.attrs;
|
|
5709
|
+
return /* @__PURE__ */ jsxs(NodeViewWrapper, { as: "span", className: "bk-channel-mention", "data-channel-mention": attrs.channelId, children: [
|
|
5710
|
+
"#",
|
|
5711
|
+
channelMentionLabel(attrs, mentions?.getChannelName)
|
|
5712
|
+
] });
|
|
5713
|
+
}
|
|
5714
|
+
var ChannelMentionNode = Node$1.create({
|
|
5715
|
+
name: CHANNEL_MENTION_NODE,
|
|
5637
5716
|
group: "inline",
|
|
5638
5717
|
inline: true,
|
|
5639
5718
|
atom: true,
|
|
5640
5719
|
selectable: true,
|
|
5641
5720
|
addAttributes() {
|
|
5642
5721
|
return {
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5722
|
+
channelId: {
|
|
5723
|
+
default: "",
|
|
5724
|
+
parseHTML: (element) => element.getAttribute("data-channel-mention") ?? "",
|
|
5725
|
+
renderHTML: (attributes) => ({ "data-channel-mention": attributes.channelId })
|
|
5726
|
+
},
|
|
5727
|
+
name: {
|
|
5728
|
+
default: null,
|
|
5729
|
+
parseHTML: (element) => element.getAttribute("data-channel-name"),
|
|
5730
|
+
renderHTML: (attributes) => attributes.name ? { "data-channel-name": attributes.name } : {}
|
|
5731
|
+
}
|
|
5647
5732
|
};
|
|
5648
5733
|
},
|
|
5649
5734
|
parseHTML() {
|
|
5650
|
-
return [{ tag: "span[data-
|
|
5735
|
+
return [{ tag: "span[data-channel-mention]" }];
|
|
5651
5736
|
},
|
|
5652
|
-
renderHTML({ HTMLAttributes }) {
|
|
5653
|
-
|
|
5654
|
-
|
|
5737
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
5738
|
+
return ["span", mergeAttributes(HTMLAttributes), `#${channelMentionLabel(node.attrs)}`];
|
|
5739
|
+
},
|
|
5740
|
+
renderText({ node }) {
|
|
5741
|
+
return `#${channelMentionLabel(node.attrs)}`;
|
|
5655
5742
|
},
|
|
5656
5743
|
addNodeView() {
|
|
5657
|
-
return ReactNodeViewRenderer(
|
|
5744
|
+
return ReactNodeViewRenderer(ChannelMentionNodeView);
|
|
5658
5745
|
}
|
|
5659
5746
|
});
|
|
5660
5747
|
var MENTION_SEARCH_DEBOUNCE_MS = 200;
|
|
5748
|
+
var USER_MENTION_SUGGESTION_PLUGIN_KEY = new PluginKey("userMentionSuggestion");
|
|
5661
5749
|
function insertUserMention(editor, range, user) {
|
|
5662
5750
|
const to = editor.state.doc.textBetween(range.to, Math.min(range.to + 1, editor.state.doc.content.size)) === " " ? range.to + 1 : range.to;
|
|
5663
5751
|
editor.chain().focus().insertContentAt({ from: range.from, to }, [
|
|
@@ -5666,13 +5754,16 @@ function insertUserMention(editor, range, user) {
|
|
|
5666
5754
|
]).run();
|
|
5667
5755
|
}
|
|
5668
5756
|
function insertMentionTrigger(editor) {
|
|
5757
|
+
insertSuggestionTrigger(editor, "@");
|
|
5758
|
+
}
|
|
5759
|
+
function insertSuggestionTrigger(editor, char) {
|
|
5669
5760
|
const { from } = editor.state.selection;
|
|
5670
5761
|
const before = from > 1 ? editor.state.doc.textBetween(from - 1, from, void 0, "\uFFFC") : "";
|
|
5671
5762
|
const needsSpace = before !== "" && !/\s/.test(before);
|
|
5672
|
-
editor.chain().focus().insertContent(needsSpace ?
|
|
5763
|
+
editor.chain().focus().insertContent(needsSpace ? ` ${char}` : char).run();
|
|
5673
5764
|
}
|
|
5674
5765
|
function dismissMentionSuggestion(editor) {
|
|
5675
|
-
exitSuggestion(editor.view);
|
|
5766
|
+
exitSuggestion(editor.view, USER_MENTION_SUGGESTION_PLUGIN_KEY);
|
|
5676
5767
|
}
|
|
5677
5768
|
var MentionSuggestion = Extension.create({
|
|
5678
5769
|
name: "userMentionSuggestion",
|
|
@@ -5688,6 +5779,7 @@ var MentionSuggestion = Extension.create({
|
|
|
5688
5779
|
return [
|
|
5689
5780
|
Suggestion({
|
|
5690
5781
|
editor: this.editor,
|
|
5782
|
+
pluginKey: USER_MENTION_SUGGESTION_PLUGIN_KEY,
|
|
5691
5783
|
char: "@",
|
|
5692
5784
|
debounce: MENTION_SEARCH_DEBOUNCE_MS,
|
|
5693
5785
|
allow: () => isEnabled(),
|
|
@@ -5698,6 +5790,90 @@ var MentionSuggestion = Extension.create({
|
|
|
5698
5790
|
];
|
|
5699
5791
|
}
|
|
5700
5792
|
});
|
|
5793
|
+
|
|
5794
|
+
// src/lib/tiptap-channel-suggestion.ts
|
|
5795
|
+
var CHANNEL_MENTION_SUGGESTION_PLUGIN_KEY = new PluginKey("channelMentionSuggestion");
|
|
5796
|
+
function insertChannelMention(editor, range, channel) {
|
|
5797
|
+
const to = editor.state.doc.textBetween(range.to, Math.min(range.to + 1, editor.state.doc.content.size)) === " " ? range.to + 1 : range.to;
|
|
5798
|
+
editor.chain().focus().insertContentAt({ from: range.from, to }, [
|
|
5799
|
+
{ type: CHANNEL_MENTION_NODE, attrs: { channelId: channel.id, name: channel.name } },
|
|
5800
|
+
{ type: "text", text: " " }
|
|
5801
|
+
]).run();
|
|
5802
|
+
}
|
|
5803
|
+
function insertChannelTrigger(editor) {
|
|
5804
|
+
insertSuggestionTrigger(editor, "#");
|
|
5805
|
+
}
|
|
5806
|
+
function dismissChannelSuggestion(editor) {
|
|
5807
|
+
exitSuggestion(editor.view, CHANNEL_MENTION_SUGGESTION_PLUGIN_KEY);
|
|
5808
|
+
}
|
|
5809
|
+
var ChannelSuggestion = Extension.create({
|
|
5810
|
+
name: "channelMentionSuggestion",
|
|
5811
|
+
addOptions() {
|
|
5812
|
+
return {
|
|
5813
|
+
isEnabled: () => false,
|
|
5814
|
+
search: async () => [],
|
|
5815
|
+
render: () => ({})
|
|
5816
|
+
};
|
|
5817
|
+
},
|
|
5818
|
+
addProseMirrorPlugins() {
|
|
5819
|
+
const { isEnabled, search, render } = this.options;
|
|
5820
|
+
return [
|
|
5821
|
+
Suggestion({
|
|
5822
|
+
editor: this.editor,
|
|
5823
|
+
pluginKey: CHANNEL_MENTION_SUGGESTION_PLUGIN_KEY,
|
|
5824
|
+
char: "#",
|
|
5825
|
+
debounce: MENTION_SEARCH_DEBOUNCE_MS,
|
|
5826
|
+
allow: () => isEnabled(),
|
|
5827
|
+
items: ({ query, signal }) => search(query, signal),
|
|
5828
|
+
command: ({ editor, range, props }) => insertChannelMention(editor, range, props),
|
|
5829
|
+
render
|
|
5830
|
+
})
|
|
5831
|
+
];
|
|
5832
|
+
}
|
|
5833
|
+
});
|
|
5834
|
+
function EmojiNodeView({ node }) {
|
|
5835
|
+
const { name, src, unicode } = node.attrs;
|
|
5836
|
+
const label = `:${name}:`;
|
|
5837
|
+
return /* @__PURE__ */ jsx(NodeViewWrapper, { as: "span", className: "bk-emoji-node", "data-emoji": name, title: label, children: src ? /* @__PURE__ */ jsx(
|
|
5838
|
+
"img",
|
|
5839
|
+
{
|
|
5840
|
+
src,
|
|
5841
|
+
alt: label,
|
|
5842
|
+
style: {
|
|
5843
|
+
display: "inline-block",
|
|
5844
|
+
width: "1.25em",
|
|
5845
|
+
height: "1.25em",
|
|
5846
|
+
verticalAlign: "-0.25em",
|
|
5847
|
+
objectFit: "contain"
|
|
5848
|
+
}
|
|
5849
|
+
}
|
|
5850
|
+
) : /* @__PURE__ */ jsx("span", { "aria-label": label, role: "img", children: unicode ? codepointsToGlyph(unicode) : label }) });
|
|
5851
|
+
}
|
|
5852
|
+
var EmojiNode = Node$1.create({
|
|
5853
|
+
name: "emoji",
|
|
5854
|
+
group: "inline",
|
|
5855
|
+
inline: true,
|
|
5856
|
+
atom: true,
|
|
5857
|
+
selectable: true,
|
|
5858
|
+
addAttributes() {
|
|
5859
|
+
return {
|
|
5860
|
+
name: { default: "" },
|
|
5861
|
+
src: { default: null },
|
|
5862
|
+
unicode: { default: null },
|
|
5863
|
+
skinTone: { default: null }
|
|
5864
|
+
};
|
|
5865
|
+
},
|
|
5866
|
+
parseHTML() {
|
|
5867
|
+
return [{ tag: "span[data-emoji]" }];
|
|
5868
|
+
},
|
|
5869
|
+
renderHTML({ HTMLAttributes }) {
|
|
5870
|
+
const name = HTMLAttributes.name ?? "";
|
|
5871
|
+
return ["span", mergeAttributes({ "data-emoji": name }, HTMLAttributes), `:${name}:`];
|
|
5872
|
+
},
|
|
5873
|
+
addNodeView() {
|
|
5874
|
+
return ReactNodeViewRenderer(EmojiNodeView);
|
|
5875
|
+
}
|
|
5876
|
+
});
|
|
5701
5877
|
function userMentionLabel(attrs, getUserName) {
|
|
5702
5878
|
return getUserName?.(attrs.userId) ?? attrs.name ?? attrs.userId;
|
|
5703
5879
|
}
|
|
@@ -6033,6 +6209,7 @@ function nextMentionPickerState(props, prev) {
|
|
|
6033
6209
|
}
|
|
6034
6210
|
function MentionPicker({
|
|
6035
6211
|
editor,
|
|
6212
|
+
kind,
|
|
6036
6213
|
state,
|
|
6037
6214
|
keyHandlerRef,
|
|
6038
6215
|
onDismiss
|
|
@@ -6045,6 +6222,27 @@ function MentionPicker({
|
|
|
6045
6222
|
setActiveIndex(0);
|
|
6046
6223
|
}
|
|
6047
6224
|
const listRef = useRef(null);
|
|
6225
|
+
const listboxId = useId();
|
|
6226
|
+
const activeOptionId = items[activeIndex] ? `${listboxId}-${activeIndex}` : void 0;
|
|
6227
|
+
useEffect(() => {
|
|
6228
|
+
const root = editor.view.dom;
|
|
6229
|
+
root.setAttribute("role", "combobox");
|
|
6230
|
+
root.setAttribute("aria-autocomplete", "list");
|
|
6231
|
+
root.setAttribute("aria-expanded", "true");
|
|
6232
|
+
root.setAttribute("aria-controls", listboxId);
|
|
6233
|
+
if (activeOptionId) {
|
|
6234
|
+
root.setAttribute("aria-activedescendant", activeOptionId);
|
|
6235
|
+
} else {
|
|
6236
|
+
root.removeAttribute("aria-activedescendant");
|
|
6237
|
+
}
|
|
6238
|
+
return () => {
|
|
6239
|
+
root.removeAttribute("role");
|
|
6240
|
+
root.removeAttribute("aria-autocomplete");
|
|
6241
|
+
root.removeAttribute("aria-expanded");
|
|
6242
|
+
root.removeAttribute("aria-controls");
|
|
6243
|
+
root.removeAttribute("aria-activedescendant");
|
|
6244
|
+
};
|
|
6245
|
+
}, [activeOptionId, editor, listboxId]);
|
|
6048
6246
|
useEffect(() => {
|
|
6049
6247
|
keyHandlerRef.current = (event) => {
|
|
6050
6248
|
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
@@ -6055,11 +6253,11 @@ function MentionPicker({
|
|
|
6055
6253
|
return true;
|
|
6056
6254
|
}
|
|
6057
6255
|
if (event.key === "Enter" || event.key === "Tab") {
|
|
6058
|
-
const
|
|
6059
|
-
if (!
|
|
6256
|
+
const item = items[activeIndex];
|
|
6257
|
+
if (!item) {
|
|
6060
6258
|
return false;
|
|
6061
6259
|
}
|
|
6062
|
-
command(
|
|
6260
|
+
command(item);
|
|
6063
6261
|
return true;
|
|
6064
6262
|
}
|
|
6065
6263
|
return false;
|
|
@@ -6106,29 +6304,39 @@ function MentionPicker({
|
|
|
6106
6304
|
e.preventDefault();
|
|
6107
6305
|
}
|
|
6108
6306
|
},
|
|
6109
|
-
children: /* @__PURE__ */ jsx(
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6307
|
+
children: /* @__PURE__ */ jsx(
|
|
6308
|
+
"div",
|
|
6309
|
+
{
|
|
6310
|
+
ref: listRef,
|
|
6311
|
+
id: listboxId,
|
|
6312
|
+
role: "listbox",
|
|
6313
|
+
"aria-label": kind === "channel" ? "Channels to mention" : "People to mention",
|
|
6314
|
+
children: items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-center text-xs text-muted-foreground", children: loading ? "Searching\u2026" : `No ${kind === "channel" ? "channels" : "people"} match that search.` }) : items.map((item, index) => (
|
|
6315
|
+
// biome-ignore lint/a11y/useFocusableInteractive: focus stays in the editor, which drives this list through the suggestion plugin's key handling.
|
|
6316
|
+
// biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard path is the editor's, forwarded via keyHandlerRef.
|
|
6317
|
+
/* @__PURE__ */ jsxs(
|
|
6318
|
+
"div",
|
|
6319
|
+
{
|
|
6320
|
+
id: `${listboxId}-${index}`,
|
|
6321
|
+
role: "option",
|
|
6322
|
+
"aria-selected": index === activeIndex,
|
|
6323
|
+
onPointerDown: (e) => e.preventDefault(),
|
|
6324
|
+
onClick: () => command(item),
|
|
6325
|
+
onMouseMove: () => setActiveIndex(index),
|
|
6326
|
+
className: cn(
|
|
6327
|
+
"flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-foreground",
|
|
6328
|
+
index === activeIndex && "bg-accent"
|
|
6329
|
+
),
|
|
6330
|
+
children: [
|
|
6331
|
+
kind === "channel" ? /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx(Hash, { className: "h-3.5 w-3.5" }) }) : /* @__PURE__ */ jsx(MentionAvatar, { user: item }),
|
|
6332
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: kind === "channel" ? `#${item.name}` : item.name })
|
|
6333
|
+
]
|
|
6334
|
+
},
|
|
6335
|
+
item.id
|
|
6336
|
+
)
|
|
6337
|
+
))
|
|
6338
|
+
}
|
|
6339
|
+
)
|
|
6132
6340
|
}
|
|
6133
6341
|
)
|
|
6134
6342
|
]
|
|
@@ -6725,7 +6933,7 @@ function LossyBanner({ reasons }) {
|
|
|
6725
6933
|
] });
|
|
6726
6934
|
}
|
|
6727
6935
|
var RICH_TEXT_INPUT_RULE_ALLOWLIST = ["bold", "italic", "strike", "code"];
|
|
6728
|
-
function buildRichTextExtensions(mentionSuggestion) {
|
|
6936
|
+
function buildRichTextExtensions(mentionSuggestion, channelSuggestion) {
|
|
6729
6937
|
return [
|
|
6730
6938
|
StarterKit.configure({
|
|
6731
6939
|
heading: false,
|
|
@@ -6759,10 +6967,11 @@ function buildRichTextExtensions(mentionSuggestion) {
|
|
|
6759
6967
|
shouldAutoLink: hasExplicitSafeScheme,
|
|
6760
6968
|
HTMLAttributes: { rel: "noreferrer noopener", target: "_blank" }
|
|
6761
6969
|
}),
|
|
6762
|
-
// Always registered, so mentions already in the content round-trip with
|
|
6763
|
-
// or without the picker.
|
|
6970
|
+
// Always registered, so mentions already in the content round-trip with or without pickers.
|
|
6764
6971
|
UserMentionNode,
|
|
6765
|
-
|
|
6972
|
+
ChannelMentionNode,
|
|
6973
|
+
...mentionSuggestion ? [MentionSuggestion.configure(mentionSuggestion)] : [],
|
|
6974
|
+
...channelSuggestion ? [ChannelSuggestion.configure(channelSuggestion)] : []
|
|
6766
6975
|
];
|
|
6767
6976
|
}
|
|
6768
6977
|
function RichTextWysiwygEditor({ block, onChange }) {
|
|
@@ -6790,24 +6999,39 @@ function RichTextWysiwygEditor({ block, onChange }) {
|
|
|
6790
6999
|
[onChange]
|
|
6791
7000
|
);
|
|
6792
7001
|
const mentions = useMentions();
|
|
6793
|
-
const
|
|
7002
|
+
const userMentionsEnabled = mentions !== null;
|
|
7003
|
+
const channelMentionsEnabled = mentions?.searchChannels !== void 0;
|
|
6794
7004
|
const mentionsRef = useRef(mentions);
|
|
6795
7005
|
useEffect(() => {
|
|
6796
7006
|
mentionsRef.current = mentions;
|
|
6797
7007
|
}, [mentions]);
|
|
6798
7008
|
const [mentionPicker, setMentionPicker] = useState(null);
|
|
6799
7009
|
const mentionKeyHandlerRef = useRef(() => false);
|
|
7010
|
+
const [channelPicker, setChannelPicker] = useState(null);
|
|
7011
|
+
const channelKeyHandlerRef = useRef(() => false);
|
|
6800
7012
|
const editor = useEditor({
|
|
6801
|
-
extensions: buildRichTextExtensions(
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
7013
|
+
extensions: buildRichTextExtensions(
|
|
7014
|
+
{
|
|
7015
|
+
isEnabled: () => mentionsRef.current !== null,
|
|
7016
|
+
search: async (query, signal) => await mentionsRef.current?.searchUsers(query, { signal }) ?? [],
|
|
7017
|
+
render: () => ({
|
|
7018
|
+
onStart: (props) => setMentionPicker((prev) => nextMentionPickerState(props, prev)),
|
|
7019
|
+
onUpdate: (props) => setMentionPicker((prev) => nextMentionPickerState(props, prev)),
|
|
7020
|
+
onExit: () => setMentionPicker(null),
|
|
7021
|
+
onKeyDown: ({ event }) => mentionKeyHandlerRef.current(event)
|
|
7022
|
+
})
|
|
7023
|
+
},
|
|
7024
|
+
{
|
|
7025
|
+
isEnabled: () => mentionsRef.current?.searchChannels !== void 0,
|
|
7026
|
+
search: async (query, signal) => await mentionsRef.current?.searchChannels?.(query, { signal }) ?? [],
|
|
7027
|
+
render: () => ({
|
|
7028
|
+
onStart: (props) => setChannelPicker((prev) => nextMentionPickerState(props, prev)),
|
|
7029
|
+
onUpdate: (props) => setChannelPicker((prev) => nextMentionPickerState(props, prev)),
|
|
7030
|
+
onExit: () => setChannelPicker(null),
|
|
7031
|
+
onKeyDown: ({ event }) => channelKeyHandlerRef.current(event)
|
|
7032
|
+
})
|
|
7033
|
+
}
|
|
7034
|
+
),
|
|
6811
7035
|
enableInputRules: RICH_TEXT_INPUT_RULE_ALLOWLIST,
|
|
6812
7036
|
content: richTextToProseMirror(block, resolveEmoji),
|
|
6813
7037
|
editorProps: {
|
|
@@ -6842,7 +7066,8 @@ function RichTextWysiwygEditor({ block, onChange }) {
|
|
|
6842
7066
|
Toolbar,
|
|
6843
7067
|
{
|
|
6844
7068
|
editor,
|
|
6845
|
-
mention:
|
|
7069
|
+
mention: userMentionsEnabled ? { active: mentionPicker !== null, insert: () => insertMentionTrigger(editor) } : null,
|
|
7070
|
+
channel: channelMentionsEnabled ? { active: channelPicker !== null, insert: () => insertChannelTrigger(editor) } : null
|
|
6846
7071
|
}
|
|
6847
7072
|
),
|
|
6848
7073
|
/* @__PURE__ */ jsx(EditorContent, { editor }),
|
|
@@ -6850,14 +7075,29 @@ function RichTextWysiwygEditor({ block, onChange }) {
|
|
|
6850
7075
|
MentionPicker,
|
|
6851
7076
|
{
|
|
6852
7077
|
editor,
|
|
7078
|
+
kind: "user",
|
|
6853
7079
|
state: mentionPicker,
|
|
6854
7080
|
keyHandlerRef: mentionKeyHandlerRef,
|
|
6855
7081
|
onDismiss: () => dismissMentionSuggestion(editor)
|
|
6856
7082
|
}
|
|
7083
|
+
),
|
|
7084
|
+
channelPicker && /* @__PURE__ */ jsx(
|
|
7085
|
+
MentionPicker,
|
|
7086
|
+
{
|
|
7087
|
+
editor,
|
|
7088
|
+
kind: "channel",
|
|
7089
|
+
state: channelPicker,
|
|
7090
|
+
keyHandlerRef: channelKeyHandlerRef,
|
|
7091
|
+
onDismiss: () => dismissChannelSuggestion(editor)
|
|
7092
|
+
}
|
|
6857
7093
|
)
|
|
6858
7094
|
] });
|
|
6859
7095
|
}
|
|
6860
|
-
function Toolbar({
|
|
7096
|
+
function Toolbar({
|
|
7097
|
+
editor,
|
|
7098
|
+
mention,
|
|
7099
|
+
channel
|
|
7100
|
+
}) {
|
|
6861
7101
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-0.5 rounded-md border bg-muted/30 p-1", children: [
|
|
6862
7102
|
/* @__PURE__ */ jsx(
|
|
6863
7103
|
ToolbarButton,
|
|
@@ -6917,6 +7157,7 @@ function Toolbar({ editor, mention }) {
|
|
|
6917
7157
|
}
|
|
6918
7158
|
),
|
|
6919
7159
|
mention && /* @__PURE__ */ jsx(ToolbarButton, { label: "Mention", active: mention.active, onClick: mention.insert, Icon: AtSign }),
|
|
7160
|
+
channel && /* @__PURE__ */ jsx(ToolbarButton, { label: "Channel", active: channel.active, onClick: channel.insert, Icon: Hash }),
|
|
6920
7161
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
6921
7162
|
/* @__PURE__ */ jsx(
|
|
6922
7163
|
ToolbarButton,
|
|
@@ -7780,6 +8021,387 @@ function ImageItemCard({
|
|
|
7780
8021
|
) })
|
|
7781
8022
|
] });
|
|
7782
8023
|
}
|
|
8024
|
+
var REMOVE_BUTTON_CLASS = "flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive disabled:cursor-not-allowed disabled:opacity-40";
|
|
8025
|
+
function CellGrid({
|
|
8026
|
+
label,
|
|
8027
|
+
help,
|
|
8028
|
+
rows,
|
|
8029
|
+
minRows,
|
|
8030
|
+
maxRows,
|
|
8031
|
+
maxColumns,
|
|
8032
|
+
lockFirstRow = false,
|
|
8033
|
+
blankCell,
|
|
8034
|
+
renderCell,
|
|
8035
|
+
renderColumnControl,
|
|
8036
|
+
onChange
|
|
8037
|
+
}) {
|
|
8038
|
+
const columnCount = rows[0]?.length ?? 0;
|
|
8039
|
+
const setCell = (rowIdx, colIdx, next) => {
|
|
8040
|
+
onChange(rows.map((row, r) => r === rowIdx ? row.map((cell, c) => c === colIdx ? next : cell) : row));
|
|
8041
|
+
};
|
|
8042
|
+
const addRow = () => {
|
|
8043
|
+
onChange([...rows, Array.from({ length: columnCount || 1 }, blankCell)]);
|
|
8044
|
+
};
|
|
8045
|
+
const removeRow = (rowIdx) => {
|
|
8046
|
+
if (rows.length <= minRows) {
|
|
8047
|
+
return;
|
|
8048
|
+
}
|
|
8049
|
+
onChange(rows.filter((_, r) => r !== rowIdx));
|
|
8050
|
+
};
|
|
8051
|
+
const addColumn = () => {
|
|
8052
|
+
onChange(
|
|
8053
|
+
rows.map((row) => [...row, blankCell()]),
|
|
8054
|
+
{ kind: "add" }
|
|
8055
|
+
);
|
|
8056
|
+
};
|
|
8057
|
+
const removeColumn = (colIdx) => {
|
|
8058
|
+
if (columnCount <= 1) {
|
|
8059
|
+
return;
|
|
8060
|
+
}
|
|
8061
|
+
onChange(
|
|
8062
|
+
rows.map((row) => row.filter((_, c) => c !== colIdx)),
|
|
8063
|
+
{ kind: "remove", index: colIdx }
|
|
8064
|
+
);
|
|
8065
|
+
};
|
|
8066
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
8067
|
+
/* @__PURE__ */ jsx(EditorField, { label, help, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 overflow-x-auto", children: [
|
|
8068
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8069
|
+
/* @__PURE__ */ jsx("span", { className: "w-6 shrink-0", "aria-hidden": "true" }),
|
|
8070
|
+
Array.from({ length: columnCount }, (_, c) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-[120px] flex-1 items-center gap-1", children: [
|
|
8071
|
+
renderColumnControl ? renderColumnControl(c) : /* @__PURE__ */ jsxs("span", { className: "flex-1 truncate px-1.5 text-[11px] text-muted-foreground", children: [
|
|
8072
|
+
"Column ",
|
|
8073
|
+
c + 1
|
|
8074
|
+
] }),
|
|
8075
|
+
/* @__PURE__ */ jsx(
|
|
8076
|
+
"button",
|
|
8077
|
+
{
|
|
8078
|
+
type: "button",
|
|
8079
|
+
"aria-label": `Remove column ${c + 1}`,
|
|
8080
|
+
onClick: () => removeColumn(c),
|
|
8081
|
+
disabled: columnCount <= 1,
|
|
8082
|
+
className: REMOVE_BUTTON_CLASS,
|
|
8083
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
8084
|
+
}
|
|
8085
|
+
)
|
|
8086
|
+
] }, c))
|
|
8087
|
+
] }),
|
|
8088
|
+
rows.map((row, r) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8089
|
+
lockFirstRow && r === 0 ? /* @__PURE__ */ jsx("span", { className: "w-6 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(
|
|
8090
|
+
"button",
|
|
8091
|
+
{
|
|
8092
|
+
type: "button",
|
|
8093
|
+
"aria-label": `Remove row ${r + 1}`,
|
|
8094
|
+
onClick: () => removeRow(r),
|
|
8095
|
+
disabled: rows.length <= minRows,
|
|
8096
|
+
className: REMOVE_BUTTON_CLASS,
|
|
8097
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
8098
|
+
}
|
|
8099
|
+
),
|
|
8100
|
+
row.map((cell, c) => /* @__PURE__ */ jsx("div", { className: "flex min-w-[120px] flex-1 flex-col gap-0.5", children: renderCell(
|
|
8101
|
+
cell,
|
|
8102
|
+
{ row: r, col: c, label: `Row ${r + 1}, column ${c + 1}` },
|
|
8103
|
+
(next) => setCell(r, c, next)
|
|
8104
|
+
) }, c))
|
|
8105
|
+
] }, r))
|
|
8106
|
+
] }) }),
|
|
8107
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
8108
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addRow, disabled: rows.length >= maxRows, children: [
|
|
8109
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
8110
|
+
" Add row"
|
|
8111
|
+
] }),
|
|
8112
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addColumn, disabled: columnCount >= maxColumns, children: [
|
|
8113
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
8114
|
+
" Add column"
|
|
8115
|
+
] })
|
|
8116
|
+
] })
|
|
8117
|
+
] });
|
|
8118
|
+
}
|
|
8119
|
+
function CellTextInput({
|
|
8120
|
+
cell,
|
|
8121
|
+
label,
|
|
8122
|
+
placeholder,
|
|
8123
|
+
leading,
|
|
8124
|
+
richTextNote = "Was rich-text; editing replaces with plain text.",
|
|
8125
|
+
onChange
|
|
8126
|
+
}) {
|
|
8127
|
+
const input = /* @__PURE__ */ jsx(
|
|
8128
|
+
Input,
|
|
8129
|
+
{
|
|
8130
|
+
"aria-label": label,
|
|
8131
|
+
value: cell.type === "raw_text" ? cell.text : "[rich_text]",
|
|
8132
|
+
placeholder,
|
|
8133
|
+
onChange: (e) => onChange({ type: "raw_text", text: e.target.value }),
|
|
8134
|
+
className: "h-8 text-xs"
|
|
8135
|
+
}
|
|
8136
|
+
);
|
|
8137
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8138
|
+
leading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8139
|
+
leading,
|
|
8140
|
+
input
|
|
8141
|
+
] }) : input,
|
|
8142
|
+
cell.type === "rich_text" ? /* @__PURE__ */ jsx("span", { className: cn("text-[10px] text-muted-foreground", leading && "pl-7"), children: richTextNote }) : null
|
|
8143
|
+
] });
|
|
8144
|
+
}
|
|
8145
|
+
function NumberInput({
|
|
8146
|
+
id,
|
|
8147
|
+
value,
|
|
8148
|
+
onCommit,
|
|
8149
|
+
ariaLabel,
|
|
8150
|
+
className
|
|
8151
|
+
}) {
|
|
8152
|
+
const [draft, setDraft] = useState(String(value));
|
|
8153
|
+
useEffect(() => {
|
|
8154
|
+
setDraft(String(value));
|
|
8155
|
+
}, [value]);
|
|
8156
|
+
return /* @__PURE__ */ jsx(
|
|
8157
|
+
Input,
|
|
8158
|
+
{
|
|
8159
|
+
id,
|
|
8160
|
+
type: "number",
|
|
8161
|
+
inputMode: "numeric",
|
|
8162
|
+
"aria-label": ariaLabel,
|
|
8163
|
+
value: draft,
|
|
8164
|
+
className,
|
|
8165
|
+
onChange: (e) => {
|
|
8166
|
+
const raw = e.target.value;
|
|
8167
|
+
setDraft(raw);
|
|
8168
|
+
if (raw === "" || raw === "-" || raw === "." || raw === "-.") {
|
|
8169
|
+
return;
|
|
8170
|
+
}
|
|
8171
|
+
const next = Number(raw);
|
|
8172
|
+
if (!Number.isNaN(next)) {
|
|
8173
|
+
onCommit(next);
|
|
8174
|
+
}
|
|
8175
|
+
},
|
|
8176
|
+
onBlur: () => {
|
|
8177
|
+
const next = Number(draft);
|
|
8178
|
+
const safe = draft.trim() === "" || Number.isNaN(next) ? 0 : next;
|
|
8179
|
+
onCommit(safe);
|
|
8180
|
+
setDraft(String(safe));
|
|
8181
|
+
}
|
|
8182
|
+
}
|
|
8183
|
+
);
|
|
8184
|
+
}
|
|
8185
|
+
var MAX_ROWS = 201;
|
|
8186
|
+
var MIN_ROWS = 2;
|
|
8187
|
+
var MAX_COLUMNS = 20;
|
|
8188
|
+
var MAX_PAGE_SIZE = 100;
|
|
8189
|
+
var SELECT_CLASS = "flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
|
|
8190
|
+
function withOptional(block, key, value) {
|
|
8191
|
+
const next = { ...block };
|
|
8192
|
+
if (value === void 0) {
|
|
8193
|
+
delete next[key];
|
|
8194
|
+
} else {
|
|
8195
|
+
next[key] = value;
|
|
8196
|
+
}
|
|
8197
|
+
return next;
|
|
8198
|
+
}
|
|
8199
|
+
function realignRowHeader(index, edit) {
|
|
8200
|
+
if (index === void 0 || edit.kind === "add" || edit.index > index) {
|
|
8201
|
+
return index;
|
|
8202
|
+
}
|
|
8203
|
+
return edit.index === index ? void 0 : index - 1;
|
|
8204
|
+
}
|
|
8205
|
+
function cellText(cell) {
|
|
8206
|
+
switch (cell?.type) {
|
|
8207
|
+
case "raw_text":
|
|
8208
|
+
return cell.text;
|
|
8209
|
+
case "raw_number":
|
|
8210
|
+
return cell.text ?? String(cell.value);
|
|
8211
|
+
case "action_cell":
|
|
8212
|
+
return cell.element.text.text;
|
|
8213
|
+
default:
|
|
8214
|
+
return "";
|
|
8215
|
+
}
|
|
8216
|
+
}
|
|
8217
|
+
function toNumberCell(cell) {
|
|
8218
|
+
const text = cell.text.trim();
|
|
8219
|
+
const parsed = text === "" ? Number.NaN : Number(text.replace(/,/g, ""));
|
|
8220
|
+
if (Number.isFinite(parsed)) {
|
|
8221
|
+
return String(parsed) === text ? { type: "raw_number", value: parsed } : { type: "raw_number", value: parsed, text };
|
|
8222
|
+
}
|
|
8223
|
+
return text ? { type: "raw_number", value: 0, text } : { type: "raw_number", value: 0 };
|
|
8224
|
+
}
|
|
8225
|
+
function toTextCell(cell) {
|
|
8226
|
+
return { type: "raw_text", text: cell.text ?? String(cell.value) };
|
|
8227
|
+
}
|
|
8228
|
+
function DataTableEditor({ block, onChange }) {
|
|
8229
|
+
const rows = block.rows ?? [];
|
|
8230
|
+
const header = rows[0] ?? [];
|
|
8231
|
+
const rowHeader = block.row_header_column_index ?? 0;
|
|
8232
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
8233
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Caption", help: "Required. Names the table for screen readers.", htmlFor: "data-table-caption", children: /* @__PURE__ */ jsx(
|
|
8234
|
+
Input,
|
|
8235
|
+
{
|
|
8236
|
+
id: "data-table-caption",
|
|
8237
|
+
value: block.caption,
|
|
8238
|
+
placeholder: "e.g. Open deals by stage",
|
|
8239
|
+
onChange: (e) => onChange({ ...block, caption: e.target.value })
|
|
8240
|
+
}
|
|
8241
|
+
) }),
|
|
8242
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
8243
|
+
/* @__PURE__ */ jsx(
|
|
8244
|
+
EditorField,
|
|
8245
|
+
{
|
|
8246
|
+
label: "Rows per page",
|
|
8247
|
+
help: "Optional, 1-100. Slack shows 5 when empty.",
|
|
8248
|
+
htmlFor: "data-table-page-size",
|
|
8249
|
+
children: /* @__PURE__ */ jsx(
|
|
8250
|
+
Input,
|
|
8251
|
+
{
|
|
8252
|
+
id: "data-table-page-size",
|
|
8253
|
+
type: "number",
|
|
8254
|
+
min: 1,
|
|
8255
|
+
max: MAX_PAGE_SIZE,
|
|
8256
|
+
value: block.page_size ?? "",
|
|
8257
|
+
placeholder: "5",
|
|
8258
|
+
onChange: (e) => {
|
|
8259
|
+
const n = Math.trunc(Number(e.target.value));
|
|
8260
|
+
const next = e.target.value === "" || Number.isNaN(n) ? void 0 : Math.min(MAX_PAGE_SIZE, Math.max(1, n));
|
|
8261
|
+
onChange(withOptional(block, "page_size", next));
|
|
8262
|
+
}
|
|
8263
|
+
}
|
|
8264
|
+
)
|
|
8265
|
+
}
|
|
8266
|
+
),
|
|
8267
|
+
/* @__PURE__ */ jsx(
|
|
8268
|
+
EditorField,
|
|
8269
|
+
{
|
|
8270
|
+
label: "Row header column",
|
|
8271
|
+
help: "The column that identifies each row for screen readers.",
|
|
8272
|
+
htmlFor: "data-table-row-header",
|
|
8273
|
+
children: /* @__PURE__ */ jsxs(
|
|
8274
|
+
"select",
|
|
8275
|
+
{
|
|
8276
|
+
id: "data-table-row-header",
|
|
8277
|
+
value: rowHeader,
|
|
8278
|
+
disabled: header.length === 0,
|
|
8279
|
+
onChange: (e) => {
|
|
8280
|
+
const index = Number(e.target.value);
|
|
8281
|
+
onChange(withOptional(block, "row_header_column_index", index === 0 ? void 0 : index));
|
|
8282
|
+
},
|
|
8283
|
+
className: SELECT_CLASS,
|
|
8284
|
+
children: [
|
|
8285
|
+
header.map((cell, c) => {
|
|
8286
|
+
const text = cellText(cell);
|
|
8287
|
+
return /* @__PURE__ */ jsx("option", { value: c, children: text ? `Column ${c + 1}: ${text}` : `Column ${c + 1}` }, c);
|
|
8288
|
+
}),
|
|
8289
|
+
rowHeader >= header.length ? /* @__PURE__ */ jsxs("option", { value: rowHeader, children: [
|
|
8290
|
+
"Column ",
|
|
8291
|
+
rowHeader + 1,
|
|
8292
|
+
" (missing)"
|
|
8293
|
+
] }) : null
|
|
8294
|
+
]
|
|
8295
|
+
}
|
|
8296
|
+
)
|
|
8297
|
+
}
|
|
8298
|
+
)
|
|
8299
|
+
] }),
|
|
8300
|
+
/* @__PURE__ */ jsx(
|
|
8301
|
+
CellGrid,
|
|
8302
|
+
{
|
|
8303
|
+
label: "Cells",
|
|
8304
|
+
help: "The first row is the header. Up to 200 more rows and 20 columns. Use # to make a cell a number; a column of only numbers sorts numerically.",
|
|
8305
|
+
rows,
|
|
8306
|
+
minRows: MIN_ROWS,
|
|
8307
|
+
maxRows: MAX_ROWS,
|
|
8308
|
+
maxColumns: MAX_COLUMNS,
|
|
8309
|
+
lockFirstRow: true,
|
|
8310
|
+
blankCell: () => ({ type: "raw_text", text: "" }),
|
|
8311
|
+
onChange: (nextRows, edit) => {
|
|
8312
|
+
const next = { ...block, rows: nextRows };
|
|
8313
|
+
onChange(
|
|
8314
|
+
edit ? withOptional(next, "row_header_column_index", realignRowHeader(block.row_header_column_index, edit)) : next
|
|
8315
|
+
);
|
|
8316
|
+
},
|
|
8317
|
+
renderCell: (cell, position, update) => /* @__PURE__ */ jsx(DataTableCellField, { cell, position, onChange: update })
|
|
8318
|
+
}
|
|
8319
|
+
)
|
|
8320
|
+
] });
|
|
8321
|
+
}
|
|
8322
|
+
function DataTableCellField({
|
|
8323
|
+
cell,
|
|
8324
|
+
position,
|
|
8325
|
+
onChange
|
|
8326
|
+
}) {
|
|
8327
|
+
const { row, col, label } = position;
|
|
8328
|
+
if (cell.type === "action_cell") {
|
|
8329
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8330
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8331
|
+
/* @__PURE__ */ jsx(ToggleSpacer, {}),
|
|
8332
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-8 min-w-0 flex-1 items-center gap-1.5 rounded-md border border-dashed px-2 text-xs text-muted-foreground", children: [
|
|
8333
|
+
/* @__PURE__ */ jsx(MousePointerClick, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
|
|
8334
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: cellText(cell) || "Button" })
|
|
8335
|
+
] })
|
|
8336
|
+
] }),
|
|
8337
|
+
/* @__PURE__ */ jsx("span", { className: "pl-7 text-[10px] text-muted-foreground", children: "Button cell. Edit it via View JSON." })
|
|
8338
|
+
] });
|
|
8339
|
+
}
|
|
8340
|
+
if (cell.type === "raw_number") {
|
|
8341
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8342
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8343
|
+
/* @__PURE__ */ jsx(NumberToggle, { label, pressed: true, onClick: () => onChange(toTextCell(cell)) }),
|
|
8344
|
+
/* @__PURE__ */ jsx(
|
|
8345
|
+
NumberInput,
|
|
8346
|
+
{
|
|
8347
|
+
value: cell.value,
|
|
8348
|
+
ariaLabel: `${label} value`,
|
|
8349
|
+
onCommit: (value) => onChange({ ...cell, value }),
|
|
8350
|
+
className: "h-8 text-xs"
|
|
8351
|
+
}
|
|
8352
|
+
)
|
|
8353
|
+
] }),
|
|
8354
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8355
|
+
/* @__PURE__ */ jsx(ToggleSpacer, {}),
|
|
8356
|
+
/* @__PURE__ */ jsx(
|
|
8357
|
+
Input,
|
|
8358
|
+
{
|
|
8359
|
+
"aria-label": `${label} display text`,
|
|
8360
|
+
value: cell.text ?? "",
|
|
8361
|
+
placeholder: "Display as (optional)",
|
|
8362
|
+
onChange: (e) => {
|
|
8363
|
+
const { text: _omit, ...rest } = cell;
|
|
8364
|
+
onChange(e.target.value ? { ...rest, text: e.target.value } : rest);
|
|
8365
|
+
},
|
|
8366
|
+
className: "h-7 text-[11px]"
|
|
8367
|
+
}
|
|
8368
|
+
)
|
|
8369
|
+
] })
|
|
8370
|
+
] });
|
|
8371
|
+
}
|
|
8372
|
+
const isHeader = row === 0;
|
|
8373
|
+
return /* @__PURE__ */ jsx(
|
|
8374
|
+
CellTextInput,
|
|
8375
|
+
{
|
|
8376
|
+
cell,
|
|
8377
|
+
label,
|
|
8378
|
+
placeholder: isHeader ? `Header ${col + 1}` : "Cell text",
|
|
8379
|
+
richTextNote: isHeader ? "Header cells can't be rich text. Type to replace it." : void 0,
|
|
8380
|
+
leading: !isHeader && cell.type === "raw_text" ? /* @__PURE__ */ jsx(NumberToggle, { label, pressed: false, onClick: () => onChange(toNumberCell(cell)) }) : /* @__PURE__ */ jsx(ToggleSpacer, {}),
|
|
8381
|
+
onChange
|
|
8382
|
+
}
|
|
8383
|
+
);
|
|
8384
|
+
}
|
|
8385
|
+
function ToggleSpacer() {
|
|
8386
|
+
return /* @__PURE__ */ jsx("span", { className: "h-6 w-6 shrink-0", "aria-hidden": "true" });
|
|
8387
|
+
}
|
|
8388
|
+
function NumberToggle({ label, pressed, onClick }) {
|
|
8389
|
+
return /* @__PURE__ */ jsx(
|
|
8390
|
+
"button",
|
|
8391
|
+
{
|
|
8392
|
+
type: "button",
|
|
8393
|
+
"aria-label": `${label} as number`,
|
|
8394
|
+
"aria-pressed": pressed,
|
|
8395
|
+
title: pressed ? "Number cell. Click to make it text." : "Text cell. Click to make it a number.",
|
|
8396
|
+
onClick,
|
|
8397
|
+
className: cn(
|
|
8398
|
+
"flex h-6 w-6 shrink-0 items-center justify-center rounded transition-colors",
|
|
8399
|
+
pressed ? "bg-primary/10 text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
8400
|
+
),
|
|
8401
|
+
children: /* @__PURE__ */ jsx(Hash, { className: "h-3 w-3" })
|
|
8402
|
+
}
|
|
8403
|
+
);
|
|
8404
|
+
}
|
|
7783
8405
|
var CHART_TYPES = ["line", "bar", "area", "pie"];
|
|
7784
8406
|
function isCartesian(chart) {
|
|
7785
8407
|
return chart.type !== "pie";
|
|
@@ -7834,46 +8456,6 @@ function DataVisualizationEditor({ block, onChange }) {
|
|
|
7834
8456
|
isCartesian(chart) ? /* @__PURE__ */ jsx(CartesianFields, { chart, onChange: setChart }) : /* @__PURE__ */ jsx(PieFields, { chart, onChange: setChart })
|
|
7835
8457
|
] });
|
|
7836
8458
|
}
|
|
7837
|
-
function NumberInput({
|
|
7838
|
-
id,
|
|
7839
|
-
value,
|
|
7840
|
-
onCommit,
|
|
7841
|
-
ariaLabel,
|
|
7842
|
-
className
|
|
7843
|
-
}) {
|
|
7844
|
-
const [draft, setDraft] = useState(String(value));
|
|
7845
|
-
useEffect(() => {
|
|
7846
|
-
setDraft(String(value));
|
|
7847
|
-
}, [value]);
|
|
7848
|
-
return /* @__PURE__ */ jsx(
|
|
7849
|
-
Input,
|
|
7850
|
-
{
|
|
7851
|
-
id,
|
|
7852
|
-
type: "number",
|
|
7853
|
-
inputMode: "numeric",
|
|
7854
|
-
"aria-label": ariaLabel,
|
|
7855
|
-
value: draft,
|
|
7856
|
-
className,
|
|
7857
|
-
onChange: (e) => {
|
|
7858
|
-
const raw = e.target.value;
|
|
7859
|
-
setDraft(raw);
|
|
7860
|
-
if (raw === "" || raw === "-" || raw === "." || raw === "-.") {
|
|
7861
|
-
return;
|
|
7862
|
-
}
|
|
7863
|
-
const next = Number(raw);
|
|
7864
|
-
if (!Number.isNaN(next)) {
|
|
7865
|
-
onCommit(next);
|
|
7866
|
-
}
|
|
7867
|
-
},
|
|
7868
|
-
onBlur: () => {
|
|
7869
|
-
const next = Number(draft);
|
|
7870
|
-
const safe = draft.trim() === "" || Number.isNaN(next) ? 0 : next;
|
|
7871
|
-
onCommit(safe);
|
|
7872
|
-
setDraft(String(safe));
|
|
7873
|
-
}
|
|
7874
|
-
}
|
|
7875
|
-
);
|
|
7876
|
-
}
|
|
7877
8459
|
function CartesianFields({ chart, onChange }) {
|
|
7878
8460
|
const series = chart.series;
|
|
7879
8461
|
const categories = chart.axis_config?.categories && chart.axis_config.categories.length > 0 ? chart.axis_config.categories : series[0]?.data.map((d) => d.label) ?? [];
|
|
@@ -9416,45 +9998,13 @@ function ImageAccessoryFields({ image, onChange }) {
|
|
|
9416
9998
|
] });
|
|
9417
9999
|
}
|
|
9418
10000
|
var ALIGN_OPTIONS = ["left", "center", "right"];
|
|
9419
|
-
function
|
|
9420
|
-
|
|
9421
|
-
return cell.text;
|
|
9422
|
-
}
|
|
9423
|
-
return "[rich_text]";
|
|
10001
|
+
function alignColumnSettings(settings, edit) {
|
|
10002
|
+
return edit.kind === "add" ? [...settings, null] : settings.filter((_, c) => c !== edit.index);
|
|
9424
10003
|
}
|
|
9425
10004
|
function TableEditor({ block, onChange }) {
|
|
9426
10005
|
const rows = block.rows ?? [];
|
|
9427
10006
|
const columnCount = rows[0]?.length ?? 0;
|
|
9428
10007
|
const columnSettings = block.column_settings ?? [];
|
|
9429
|
-
const setCell = (rowIdx, colIdx, text) => {
|
|
9430
|
-
const nextRows = rows.map(
|
|
9431
|
-
(row, r) => r === rowIdx ? row.map((cell, c) => c === colIdx ? { type: "raw_text", text } : cell) : row
|
|
9432
|
-
);
|
|
9433
|
-
onChange({ ...block, rows: nextRows });
|
|
9434
|
-
};
|
|
9435
|
-
const addRow = () => {
|
|
9436
|
-
const blankRow = Array.from({ length: columnCount || 1 }, () => ({ type: "raw_text", text: "" }));
|
|
9437
|
-
onChange({ ...block, rows: [...rows, blankRow] });
|
|
9438
|
-
};
|
|
9439
|
-
const removeRow = (rowIdx) => {
|
|
9440
|
-
if (rows.length <= 1) {
|
|
9441
|
-
return;
|
|
9442
|
-
}
|
|
9443
|
-
onChange({ ...block, rows: rows.filter((_, r) => r !== rowIdx) });
|
|
9444
|
-
};
|
|
9445
|
-
const addColumn = () => {
|
|
9446
|
-
const nextRows = rows.map((row) => [...row, { type: "raw_text", text: "" }]);
|
|
9447
|
-
const nextSettings = [...columnSettings, null];
|
|
9448
|
-
onChange({ ...block, rows: nextRows, column_settings: nextSettings });
|
|
9449
|
-
};
|
|
9450
|
-
const removeColumn = (colIdx) => {
|
|
9451
|
-
if (columnCount <= 1) {
|
|
9452
|
-
return;
|
|
9453
|
-
}
|
|
9454
|
-
const nextRows = rows.map((row) => row.filter((_, c) => c !== colIdx));
|
|
9455
|
-
const nextSettings = columnSettings.filter((_, c) => c !== colIdx);
|
|
9456
|
-
onChange({ ...block, rows: nextRows, column_settings: nextSettings });
|
|
9457
|
-
};
|
|
9458
10008
|
const setColumnAlign = (colIdx, align) => {
|
|
9459
10009
|
const next = Array.from({ length: columnCount }, (_, i) => columnSettings[i] ?? null);
|
|
9460
10010
|
if (align === "") {
|
|
@@ -9465,81 +10015,45 @@ function TableEditor({ block, onChange }) {
|
|
|
9465
10015
|
}
|
|
9466
10016
|
onChange({ ...block, column_settings: next });
|
|
9467
10017
|
};
|
|
9468
|
-
return /* @__PURE__ */
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
|
|
9486
|
-
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
|
|
9490
|
-
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
type: "button",
|
|
9508
|
-
"aria-label": `Remove row ${r + 1}`,
|
|
9509
|
-
onClick: () => removeRow(r),
|
|
9510
|
-
disabled: rows.length <= 1,
|
|
9511
|
-
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive disabled:cursor-not-allowed disabled:opacity-40",
|
|
9512
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
9513
|
-
}
|
|
9514
|
-
),
|
|
9515
|
-
row.map((cell, c) => {
|
|
9516
|
-
const isRichText = cell.type === "rich_text";
|
|
9517
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-[120px] flex-1 flex-col gap-0.5", children: [
|
|
9518
|
-
/* @__PURE__ */ jsx(
|
|
9519
|
-
Input,
|
|
9520
|
-
{
|
|
9521
|
-
value: cellAsText(cell),
|
|
9522
|
-
placeholder: r === 0 ? `Header ${c + 1}` : "Cell text",
|
|
9523
|
-
onChange: (e) => setCell(r, c, e.target.value),
|
|
9524
|
-
className: "h-8 text-xs"
|
|
9525
|
-
}
|
|
9526
|
-
),
|
|
9527
|
-
isRichText ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "Was rich-text; editing replaces with plain text." }) : null
|
|
9528
|
-
] }, c);
|
|
9529
|
-
})
|
|
9530
|
-
] }, r))
|
|
9531
|
-
] }) }),
|
|
9532
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
9533
|
-
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addRow, disabled: rows.length >= 100, children: [
|
|
9534
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
9535
|
-
" Add row"
|
|
9536
|
-
] }),
|
|
9537
|
-
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addColumn, disabled: columnCount >= 20, children: [
|
|
9538
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
9539
|
-
" Add column"
|
|
9540
|
-
] })
|
|
9541
|
-
] })
|
|
9542
|
-
] });
|
|
10018
|
+
return /* @__PURE__ */ jsx(
|
|
10019
|
+
CellGrid,
|
|
10020
|
+
{
|
|
10021
|
+
label: "Cells",
|
|
10022
|
+
help: "Up to 100 rows and 20 columns. Slack allows one table per message.",
|
|
10023
|
+
rows,
|
|
10024
|
+
minRows: 1,
|
|
10025
|
+
maxRows: 100,
|
|
10026
|
+
maxColumns: 20,
|
|
10027
|
+
blankCell: () => ({ type: "raw_text", text: "" }),
|
|
10028
|
+
onChange: (nextRows, edit) => onChange({
|
|
10029
|
+
...block,
|
|
10030
|
+
rows: nextRows,
|
|
10031
|
+
...edit ? { column_settings: alignColumnSettings(columnSettings, edit) } : {}
|
|
10032
|
+
}),
|
|
10033
|
+
renderColumnControl: (c) => /* @__PURE__ */ jsxs(
|
|
10034
|
+
"select",
|
|
10035
|
+
{
|
|
10036
|
+
"aria-label": `Column ${c + 1} alignment`,
|
|
10037
|
+
value: columnSettings[c]?.align ?? "",
|
|
10038
|
+
onChange: (e) => setColumnAlign(c, e.target.value),
|
|
10039
|
+
className: "h-7 flex-1 rounded-sm border border-input bg-background px-1.5 text-[11px] text-muted-foreground",
|
|
10040
|
+
children: [
|
|
10041
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Default" }),
|
|
10042
|
+
ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx("option", { value: a, children: a }, a))
|
|
10043
|
+
]
|
|
10044
|
+
}
|
|
10045
|
+
),
|
|
10046
|
+
renderCell: (cell, { row, col, label }, update) => /* @__PURE__ */ jsx(
|
|
10047
|
+
CellTextInput,
|
|
10048
|
+
{
|
|
10049
|
+
cell,
|
|
10050
|
+
label,
|
|
10051
|
+
placeholder: row === 0 ? `Header ${col + 1}` : "Cell text",
|
|
10052
|
+
onChange: update
|
|
10053
|
+
}
|
|
10054
|
+
)
|
|
10055
|
+
}
|
|
10056
|
+
);
|
|
9543
10057
|
}
|
|
9544
10058
|
var STATUSES2 = ["pending", "in_progress", "complete", "error"];
|
|
9545
10059
|
function TaskCardEditor({ block, onChange }) {
|
|
@@ -9880,6 +10394,8 @@ function dispatch(block, onChange) {
|
|
|
9880
10394
|
return /* @__PURE__ */ jsx(DataVisualizationEditor, { block, onChange: (next) => onChange(next) });
|
|
9881
10395
|
case "container":
|
|
9882
10396
|
return /* @__PURE__ */ jsx(ContainerEditor, { block, onChange: (next) => onChange(next) });
|
|
10397
|
+
case "data_table":
|
|
10398
|
+
return /* @__PURE__ */ jsx(DataTableEditor, { block, onChange: (next) => onChange(next) });
|
|
9883
10399
|
default:
|
|
9884
10400
|
return null;
|
|
9885
10401
|
}
|
|
@@ -9903,7 +10419,8 @@ var BLOCK_TYPE_LABELS = {
|
|
|
9903
10419
|
plan: "Plan",
|
|
9904
10420
|
task_card: "Task Card",
|
|
9905
10421
|
data_visualization: "Data Visualization",
|
|
9906
|
-
container: "Container"
|
|
10422
|
+
container: "Container",
|
|
10423
|
+
data_table: "Data Table"
|
|
9907
10424
|
};
|
|
9908
10425
|
function BlockRow({
|
|
9909
10426
|
builderBlock,
|