@tightknitai/block-kitchen 0.8.9 → 0.8.11
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 +65 -1
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +733 -365
- 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 +734 -366
- package/dist/index.js.map +1 -1
- package/dist/{palette-DBTHRygt.d.cts → palette-Bup05opK.d.cts} +152 -4
- package/dist/{palette-DBTHRygt.d.ts → palette-Bup05opK.d.ts} +152 -4
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
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, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, Plus, ChevronDown, BookOpen, ExternalLink, AlertTriangle, Trash2, Code2,
|
|
3
|
+
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, ChartColumnBig, Container, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, Pencil, Plus, ChevronDown, BookOpen, ExternalLink, AlertTriangle, Trash2, Code2, Send, Search, Info, CheckCircle2, Check, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, Copy, Type, Bold, Italic, Strikethrough, Underline, Code, List, ListOrdered, Quote, Undo2, Redo2, Smile, Link as Link$1 } 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';
|
|
@@ -2694,6 +2694,91 @@ function JsonDrawer({
|
|
|
2694
2694
|
] })
|
|
2695
2695
|
] }) });
|
|
2696
2696
|
}
|
|
2697
|
+
var buttonVariants = cva(
|
|
2698
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
2699
|
+
{
|
|
2700
|
+
variants: {
|
|
2701
|
+
variant: {
|
|
2702
|
+
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
2703
|
+
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
2704
|
+
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
2705
|
+
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
2706
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
2707
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
2708
|
+
},
|
|
2709
|
+
size: {
|
|
2710
|
+
default: "h-9 px-4 py-2",
|
|
2711
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
2712
|
+
lg: "h-10 rounded-md px-8",
|
|
2713
|
+
icon: "h-9 w-9"
|
|
2714
|
+
}
|
|
2715
|
+
},
|
|
2716
|
+
defaultVariants: {
|
|
2717
|
+
variant: "default",
|
|
2718
|
+
size: "default"
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
);
|
|
2722
|
+
var Button = React.forwardRef(
|
|
2723
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
2724
|
+
const Comp = asChild ? Slot : "button";
|
|
2725
|
+
return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
|
|
2726
|
+
}
|
|
2727
|
+
);
|
|
2728
|
+
Button.displayName = "Button";
|
|
2729
|
+
var Dialog = DialogPrimitive.Root;
|
|
2730
|
+
var DialogPortal = DialogPrimitive.Portal;
|
|
2731
|
+
var DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2732
|
+
DialogPrimitive.Overlay,
|
|
2733
|
+
{
|
|
2734
|
+
ref,
|
|
2735
|
+
className: cn(
|
|
2736
|
+
"bk-portal-content fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
2737
|
+
className
|
|
2738
|
+
),
|
|
2739
|
+
...props
|
|
2740
|
+
}
|
|
2741
|
+
));
|
|
2742
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
2743
|
+
var DialogContent = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
2744
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
2745
|
+
/* @__PURE__ */ jsxs(
|
|
2746
|
+
DialogPrimitive.Content,
|
|
2747
|
+
{
|
|
2748
|
+
ref,
|
|
2749
|
+
className: cn(
|
|
2750
|
+
"bk-portal-content fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg",
|
|
2751
|
+
className
|
|
2752
|
+
),
|
|
2753
|
+
...props,
|
|
2754
|
+
children: [
|
|
2755
|
+
children,
|
|
2756
|
+
/* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-1 focus:ring-ring", children: [
|
|
2757
|
+
/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
|
|
2758
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
2759
|
+
] })
|
|
2760
|
+
]
|
|
2761
|
+
}
|
|
2762
|
+
)
|
|
2763
|
+
] }));
|
|
2764
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
2765
|
+
function DialogHeader({ className, ...props }) {
|
|
2766
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
|
|
2767
|
+
}
|
|
2768
|
+
function DialogFooter({ className, ...props }) {
|
|
2769
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props });
|
|
2770
|
+
}
|
|
2771
|
+
var DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2772
|
+
DialogPrimitive.Title,
|
|
2773
|
+
{
|
|
2774
|
+
ref,
|
|
2775
|
+
className: cn("text-lg font-semibold leading-none tracking-tight", className),
|
|
2776
|
+
...props
|
|
2777
|
+
}
|
|
2778
|
+
));
|
|
2779
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
2780
|
+
var DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
2781
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
2697
2782
|
var Input = React.forwardRef(
|
|
2698
2783
|
({ className, type, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2699
2784
|
"input",
|
|
@@ -2709,6 +2794,213 @@ var Input = React.forwardRef(
|
|
|
2709
2794
|
)
|
|
2710
2795
|
);
|
|
2711
2796
|
Input.displayName = "Input";
|
|
2797
|
+
var Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2798
|
+
LabelPrimitive.Root,
|
|
2799
|
+
{
|
|
2800
|
+
ref,
|
|
2801
|
+
className: cn("text-sm font-medium leading-none text-foreground", className),
|
|
2802
|
+
...props
|
|
2803
|
+
}
|
|
2804
|
+
));
|
|
2805
|
+
Label.displayName = LabelPrimitive.Root.displayName;
|
|
2806
|
+
function recentToResult(msg) {
|
|
2807
|
+
return {
|
|
2808
|
+
ok: true,
|
|
2809
|
+
channelId: msg.channelId,
|
|
2810
|
+
channelName: msg.channelName,
|
|
2811
|
+
ts: msg.ts,
|
|
2812
|
+
blocks: msg.blocks,
|
|
2813
|
+
editableVia: msg.editableVia ?? "bot",
|
|
2814
|
+
workspaceName: msg.workspaceName,
|
|
2815
|
+
username: msg.username,
|
|
2816
|
+
iconUrl: msg.iconUrl
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
function LoadMessageDialog({
|
|
2820
|
+
open,
|
|
2821
|
+
onOpenChange,
|
|
2822
|
+
onLoadMessage,
|
|
2823
|
+
loadRecentMessages,
|
|
2824
|
+
onLoaded,
|
|
2825
|
+
onOpenAsNew
|
|
2826
|
+
}) {
|
|
2827
|
+
const [link, setLink] = useState("");
|
|
2828
|
+
const [status, setStatus] = useState({ kind: "idle" });
|
|
2829
|
+
const [recent, setRecent] = useState(null);
|
|
2830
|
+
const [recentError, setRecentError] = useState(null);
|
|
2831
|
+
const inputRef = useRef(null);
|
|
2832
|
+
const onLoadMessageRef = useRef(onLoadMessage);
|
|
2833
|
+
const loadRecentMessagesRef = useRef(loadRecentMessages);
|
|
2834
|
+
useEffect(() => {
|
|
2835
|
+
onLoadMessageRef.current = onLoadMessage;
|
|
2836
|
+
loadRecentMessagesRef.current = loadRecentMessages;
|
|
2837
|
+
});
|
|
2838
|
+
const hasRecent = !!loadRecentMessages;
|
|
2839
|
+
useEffect(() => {
|
|
2840
|
+
if (!open) {
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
setLink("");
|
|
2844
|
+
setStatus({ kind: "idle" });
|
|
2845
|
+
if (!loadRecentMessagesRef.current) {
|
|
2846
|
+
setRecent([]);
|
|
2847
|
+
setRecentError(null);
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
setRecent(null);
|
|
2851
|
+
setRecentError(null);
|
|
2852
|
+
let cancelled = false;
|
|
2853
|
+
loadRecentMessagesRef.current().then((list) => {
|
|
2854
|
+
if (!cancelled) {
|
|
2855
|
+
setRecent(list);
|
|
2856
|
+
}
|
|
2857
|
+
}).catch((e) => {
|
|
2858
|
+
if (!cancelled) {
|
|
2859
|
+
setRecentError(e instanceof Error ? e.message : "Failed to load recent messages.");
|
|
2860
|
+
}
|
|
2861
|
+
});
|
|
2862
|
+
return () => {
|
|
2863
|
+
cancelled = true;
|
|
2864
|
+
};
|
|
2865
|
+
}, [open]);
|
|
2866
|
+
const handleLoad = async () => {
|
|
2867
|
+
const trimmed = link.trim();
|
|
2868
|
+
if (!trimmed) {
|
|
2869
|
+
setStatus({ kind: "error", error: "Paste a Slack message link first." });
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
setStatus({ kind: "loading" });
|
|
2873
|
+
try {
|
|
2874
|
+
const result = await onLoadMessageRef.current({ link: trimmed });
|
|
2875
|
+
if (result.ok) {
|
|
2876
|
+
onLoaded(result);
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
setStatus({ kind: "not-editable", reason: result.reason, blocks: result.blocks });
|
|
2880
|
+
} catch (e) {
|
|
2881
|
+
setStatus({ kind: "error", error: e instanceof Error ? e.message : "Failed to load message." });
|
|
2882
|
+
}
|
|
2883
|
+
};
|
|
2884
|
+
const notEditable = status.kind === "not-editable" ? status : null;
|
|
2885
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
|
|
2886
|
+
DialogContent,
|
|
2887
|
+
{
|
|
2888
|
+
className: "w-[calc(100vw-1.5rem)] max-w-lg rounded-lg",
|
|
2889
|
+
onOpenAutoFocus: (e) => {
|
|
2890
|
+
e.preventDefault();
|
|
2891
|
+
inputRef.current?.focus();
|
|
2892
|
+
},
|
|
2893
|
+
children: [
|
|
2894
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2895
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Edit an existing message" }),
|
|
2896
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5", children: [
|
|
2897
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: hasRecent ? "Paste a Slack message link, or pick a recent message your app posted." : `Paste a Slack message link (Slack's "Copy link") to load its blocks for editing.` }),
|
|
2898
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
2899
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
2900
|
+
"button",
|
|
2901
|
+
{
|
|
2902
|
+
type: "button",
|
|
2903
|
+
"aria-label": "How to copy a message link",
|
|
2904
|
+
className: "mt-0.5 shrink-0 rounded text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2905
|
+
children: /* @__PURE__ */ jsx(Info, { className: "h-3.5 w-3.5" })
|
|
2906
|
+
}
|
|
2907
|
+
) }),
|
|
2908
|
+
/* @__PURE__ */ jsxs(TooltipContent, { className: "max-w-xs leading-relaxed", children: [
|
|
2909
|
+
"In Slack, hover over the message and click the ",
|
|
2910
|
+
/* @__PURE__ */ jsx("strong", { children: "\u22EE More actions" }),
|
|
2911
|
+
" button (or right-click the message), then choose ",
|
|
2912
|
+
/* @__PURE__ */ jsx("strong", { children: "Copy link" }),
|
|
2913
|
+
"."
|
|
2914
|
+
] })
|
|
2915
|
+
] })
|
|
2916
|
+
] })
|
|
2917
|
+
] }),
|
|
2918
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
2919
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
2920
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "message-link", children: "Message link" }),
|
|
2921
|
+
/* @__PURE__ */ jsx(
|
|
2922
|
+
Input,
|
|
2923
|
+
{
|
|
2924
|
+
ref: inputRef,
|
|
2925
|
+
id: "message-link",
|
|
2926
|
+
value: link,
|
|
2927
|
+
onChange: (e) => {
|
|
2928
|
+
setLink(e.target.value);
|
|
2929
|
+
if (status.kind !== "idle" && status.kind !== "loading") {
|
|
2930
|
+
setStatus({ kind: "idle" });
|
|
2931
|
+
}
|
|
2932
|
+
},
|
|
2933
|
+
onKeyDown: (e) => {
|
|
2934
|
+
if (e.key === "Enter" && status.kind !== "loading") {
|
|
2935
|
+
e.preventDefault();
|
|
2936
|
+
handleLoad();
|
|
2937
|
+
}
|
|
2938
|
+
},
|
|
2939
|
+
placeholder: "https://your-workspace.slack.com/archives/C\u2026/p\u2026",
|
|
2940
|
+
autoComplete: "off",
|
|
2941
|
+
spellCheck: false
|
|
2942
|
+
}
|
|
2943
|
+
)
|
|
2944
|
+
] }),
|
|
2945
|
+
status.kind === "error" && /* @__PURE__ */ jsx("p", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: status.error }),
|
|
2946
|
+
notEditable && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border border-amber-200! bg-amber-50 p-3 text-xs text-amber-800", children: [
|
|
2947
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
2948
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
|
|
2949
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: notEditable.reason })
|
|
2950
|
+
] }),
|
|
2951
|
+
/* @__PURE__ */ jsx(
|
|
2952
|
+
Button,
|
|
2953
|
+
{
|
|
2954
|
+
type: "button",
|
|
2955
|
+
variant: "outline",
|
|
2956
|
+
size: "sm",
|
|
2957
|
+
className: "self-start",
|
|
2958
|
+
onClick: () => onOpenAsNew(notEditable.blocks),
|
|
2959
|
+
children: "Open as a new message instead"
|
|
2960
|
+
}
|
|
2961
|
+
)
|
|
2962
|
+
] }),
|
|
2963
|
+
hasRecent && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2964
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
2965
|
+
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
|
|
2966
|
+
"or pick a recent message",
|
|
2967
|
+
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
|
|
2968
|
+
] }),
|
|
2969
|
+
recent === null && !recentError && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Loading recent messages\u2026" }),
|
|
2970
|
+
recentError && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: recentError }),
|
|
2971
|
+
recent && recent.length === 0 && !recentError && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "No recent messages from this app." }),
|
|
2972
|
+
recent && recent.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex max-h-48 flex-col gap-1 overflow-y-auto", children: recent.map((m) => {
|
|
2973
|
+
const asUser = (m.editableVia ?? "bot") === "user";
|
|
2974
|
+
return /* @__PURE__ */ jsxs(
|
|
2975
|
+
"button",
|
|
2976
|
+
{
|
|
2977
|
+
type: "button",
|
|
2978
|
+
onClick: () => onLoaded(recentToResult(m)),
|
|
2979
|
+
className: "flex flex-col gap-0.5 rounded-md border border-input bg-background px-3 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2980
|
+
children: [
|
|
2981
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-baseline justify-between gap-2", children: [
|
|
2982
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-baseline gap-1.5", children: [
|
|
2983
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: m.channelName ? `#${m.channelName}` : m.channelId }),
|
|
2984
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 rounded border px-1 py-px text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: asUser ? "You" : "Bot" })
|
|
2985
|
+
] }),
|
|
2986
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: m.ts })
|
|
2987
|
+
] }),
|
|
2988
|
+
m.label && /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: m.label })
|
|
2989
|
+
]
|
|
2990
|
+
},
|
|
2991
|
+
`${m.channelId}:${m.ts}`
|
|
2992
|
+
);
|
|
2993
|
+
}) })
|
|
2994
|
+
] })
|
|
2995
|
+
] }),
|
|
2996
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
2997
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
2998
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: handleLoad, disabled: status.kind === "loading" || !link.trim(), children: status.kind === "loading" ? "Loading\u2026" : "Load message" })
|
|
2999
|
+
] })
|
|
3000
|
+
]
|
|
3001
|
+
}
|
|
3002
|
+
) });
|
|
3003
|
+
}
|
|
2712
3004
|
var PALETTE_DRAG_PREFIX = "palette:";
|
|
2713
3005
|
function parsePaletteDragId(id) {
|
|
2714
3006
|
if (typeof id !== "string" || !id.startsWith(PALETTE_DRAG_PREFIX)) {
|
|
@@ -2908,100 +3200,6 @@ function PaletteItem({
|
|
|
2908
3200
|
}
|
|
2909
3201
|
);
|
|
2910
3202
|
}
|
|
2911
|
-
var buttonVariants = cva(
|
|
2912
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
2913
|
-
{
|
|
2914
|
-
variants: {
|
|
2915
|
-
variant: {
|
|
2916
|
-
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
2917
|
-
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
2918
|
-
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
2919
|
-
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
2920
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
2921
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
2922
|
-
},
|
|
2923
|
-
size: {
|
|
2924
|
-
default: "h-9 px-4 py-2",
|
|
2925
|
-
sm: "h-8 rounded-md px-3 text-xs",
|
|
2926
|
-
lg: "h-10 rounded-md px-8",
|
|
2927
|
-
icon: "h-9 w-9"
|
|
2928
|
-
}
|
|
2929
|
-
},
|
|
2930
|
-
defaultVariants: {
|
|
2931
|
-
variant: "default",
|
|
2932
|
-
size: "default"
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
);
|
|
2936
|
-
var Button = React.forwardRef(
|
|
2937
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
2938
|
-
const Comp = asChild ? Slot : "button";
|
|
2939
|
-
return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
|
|
2940
|
-
}
|
|
2941
|
-
);
|
|
2942
|
-
Button.displayName = "Button";
|
|
2943
|
-
var Dialog = DialogPrimitive.Root;
|
|
2944
|
-
var DialogPortal = DialogPrimitive.Portal;
|
|
2945
|
-
var DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2946
|
-
DialogPrimitive.Overlay,
|
|
2947
|
-
{
|
|
2948
|
-
ref,
|
|
2949
|
-
className: cn(
|
|
2950
|
-
"bk-portal-content fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
2951
|
-
className
|
|
2952
|
-
),
|
|
2953
|
-
...props
|
|
2954
|
-
}
|
|
2955
|
-
));
|
|
2956
|
-
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
2957
|
-
var DialogContent = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
2958
|
-
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
2959
|
-
/* @__PURE__ */ jsxs(
|
|
2960
|
-
DialogPrimitive.Content,
|
|
2961
|
-
{
|
|
2962
|
-
ref,
|
|
2963
|
-
className: cn(
|
|
2964
|
-
"bk-portal-content fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg",
|
|
2965
|
-
className
|
|
2966
|
-
),
|
|
2967
|
-
...props,
|
|
2968
|
-
children: [
|
|
2969
|
-
children,
|
|
2970
|
-
/* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-1 focus:ring-ring", children: [
|
|
2971
|
-
/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
|
|
2972
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
2973
|
-
] })
|
|
2974
|
-
]
|
|
2975
|
-
}
|
|
2976
|
-
)
|
|
2977
|
-
] }));
|
|
2978
|
-
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
2979
|
-
function DialogHeader({ className, ...props }) {
|
|
2980
|
-
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
|
|
2981
|
-
}
|
|
2982
|
-
function DialogFooter({ className, ...props }) {
|
|
2983
|
-
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props });
|
|
2984
|
-
}
|
|
2985
|
-
var DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2986
|
-
DialogPrimitive.Title,
|
|
2987
|
-
{
|
|
2988
|
-
ref,
|
|
2989
|
-
className: cn("text-lg font-semibold leading-none tracking-tight", className),
|
|
2990
|
-
...props
|
|
2991
|
-
}
|
|
2992
|
-
));
|
|
2993
|
-
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
2994
|
-
var DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
2995
|
-
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
2996
|
-
var Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
2997
|
-
LabelPrimitive.Root,
|
|
2998
|
-
{
|
|
2999
|
-
ref,
|
|
3000
|
-
className: cn("text-sm font-medium leading-none text-foreground", className),
|
|
3001
|
-
...props
|
|
3002
|
-
}
|
|
3003
|
-
));
|
|
3004
|
-
Label.displayName = LabelPrimitive.Root.displayName;
|
|
3005
3203
|
function SendDialog({
|
|
3006
3204
|
open,
|
|
3007
3205
|
onOpenChange,
|
|
@@ -3395,12 +3593,16 @@ function AlertEditor({ block, onChange }) {
|
|
|
3395
3593
|
) })
|
|
3396
3594
|
] });
|
|
3397
3595
|
}
|
|
3398
|
-
function CardEditor({
|
|
3596
|
+
function CardEditor({
|
|
3597
|
+
block,
|
|
3598
|
+
onChange,
|
|
3599
|
+
idPrefix = "card"
|
|
3600
|
+
}) {
|
|
3399
3601
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
3400
|
-
/* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Up to 150 characters. Supports mrkdwn formatting.", htmlFor:
|
|
3602
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Up to 150 characters. Supports mrkdwn formatting.", htmlFor: `${idPrefix}-title`, children: /* @__PURE__ */ jsx(
|
|
3401
3603
|
Input,
|
|
3402
3604
|
{
|
|
3403
|
-
id:
|
|
3605
|
+
id: `${idPrefix}-title`,
|
|
3404
3606
|
value: block.title?.text ?? "",
|
|
3405
3607
|
maxLength: 150,
|
|
3406
3608
|
placeholder: "e.g. New launch update",
|
|
@@ -3410,10 +3612,10 @@ function CardEditor({ block, onChange }) {
|
|
|
3410
3612
|
})
|
|
3411
3613
|
}
|
|
3412
3614
|
) }),
|
|
3413
|
-
/* @__PURE__ */ jsx(EditorField, { label: "Subtitle", help: "Up to 150 characters.", htmlFor:
|
|
3615
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Subtitle", help: "Up to 150 characters.", htmlFor: `${idPrefix}-subtitle`, children: /* @__PURE__ */ jsx(
|
|
3414
3616
|
Input,
|
|
3415
3617
|
{
|
|
3416
|
-
id:
|
|
3618
|
+
id: `${idPrefix}-subtitle`,
|
|
3417
3619
|
value: block.subtitle?.text ?? "",
|
|
3418
3620
|
maxLength: 150,
|
|
3419
3621
|
placeholder: "e.g. Released April 28",
|
|
@@ -3423,10 +3625,10 @@ function CardEditor({ block, onChange }) {
|
|
|
3423
3625
|
})
|
|
3424
3626
|
}
|
|
3425
3627
|
) }),
|
|
3426
|
-
/* @__PURE__ */ jsx(EditorField, { label: "Body", help: "Up to 200 characters. Supports mrkdwn formatting.", htmlFor:
|
|
3628
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Body", help: "Up to 200 characters. Supports mrkdwn formatting.", htmlFor: `${idPrefix}-body`, children: /* @__PURE__ */ jsx(
|
|
3427
3629
|
Textarea,
|
|
3428
3630
|
{
|
|
3429
|
-
id:
|
|
3631
|
+
id: `${idPrefix}-body`,
|
|
3430
3632
|
value: block.body?.text ?? "",
|
|
3431
3633
|
maxLength: 200,
|
|
3432
3634
|
rows: 3,
|
|
@@ -3442,7 +3644,7 @@ function CardEditor({ block, onChange }) {
|
|
|
3442
3644
|
{
|
|
3443
3645
|
label: "Hero image",
|
|
3444
3646
|
help: "Wide image displayed at the top of the card.",
|
|
3445
|
-
idPrefix:
|
|
3647
|
+
idPrefix: `${idPrefix}-hero`,
|
|
3446
3648
|
image: block.hero_image,
|
|
3447
3649
|
onChange: (next) => onChange({ ...block, hero_image: next })
|
|
3448
3650
|
}
|
|
@@ -3452,7 +3654,7 @@ function CardEditor({ block, onChange }) {
|
|
|
3452
3654
|
{
|
|
3453
3655
|
label: "Icon",
|
|
3454
3656
|
help: "Small image shown next to the title.",
|
|
3455
|
-
idPrefix:
|
|
3657
|
+
idPrefix: `${idPrefix}-icon`,
|
|
3456
3658
|
image: block.icon,
|
|
3457
3659
|
onChange: (next) => onChange({ ...block, icon: next })
|
|
3458
3660
|
}
|
|
@@ -3460,6 +3662,7 @@ function CardEditor({ block, onChange }) {
|
|
|
3460
3662
|
/* @__PURE__ */ jsx(
|
|
3461
3663
|
ButtonsField,
|
|
3462
3664
|
{
|
|
3665
|
+
idPrefix,
|
|
3463
3666
|
buttons: block.actions ?? [],
|
|
3464
3667
|
onChange: (next) => onChange({ ...block, actions: next.length > 0 ? next : void 0 })
|
|
3465
3668
|
}
|
|
@@ -3516,7 +3719,11 @@ function ImageFields({
|
|
|
3516
3719
|
) })
|
|
3517
3720
|
] });
|
|
3518
3721
|
}
|
|
3519
|
-
function ButtonsField({
|
|
3722
|
+
function ButtonsField({
|
|
3723
|
+
buttons,
|
|
3724
|
+
onChange,
|
|
3725
|
+
idPrefix = "card"
|
|
3726
|
+
}) {
|
|
3520
3727
|
const update = (idx, change) => {
|
|
3521
3728
|
onChange(buttons.map((b, i) => i === idx ? { ...b, ...change } : b));
|
|
3522
3729
|
};
|
|
@@ -3559,10 +3766,10 @@ function ButtonsField({ buttons, onChange }) {
|
|
|
3559
3766
|
}
|
|
3560
3767
|
)
|
|
3561
3768
|
] }),
|
|
3562
|
-
/* @__PURE__ */ jsx(EditorField, { label: "Label", htmlFor:
|
|
3769
|
+
/* @__PURE__ */ jsx(EditorField, { label: "Label", htmlFor: `${idPrefix}-btn-label-${idx}`, children: /* @__PURE__ */ jsx(
|
|
3563
3770
|
Input,
|
|
3564
3771
|
{
|
|
3565
|
-
id:
|
|
3772
|
+
id: `${idPrefix}-btn-label-${idx}`,
|
|
3566
3773
|
value: label,
|
|
3567
3774
|
placeholder: "e.g. Open",
|
|
3568
3775
|
onChange: (e) => update(idx, {
|
|
@@ -3579,11 +3786,11 @@ function ButtonsField({ buttons, onChange }) {
|
|
|
3579
3786
|
{
|
|
3580
3787
|
label: "Link URL",
|
|
3581
3788
|
help: "Optional. If set, the button opens this link.",
|
|
3582
|
-
htmlFor:
|
|
3789
|
+
htmlFor: `${idPrefix}-btn-url-${idx}`,
|
|
3583
3790
|
children: /* @__PURE__ */ jsx(
|
|
3584
3791
|
Input,
|
|
3585
3792
|
{
|
|
3586
|
-
id:
|
|
3793
|
+
id: `${idPrefix}-btn-url-${idx}`,
|
|
3587
3794
|
type: "url",
|
|
3588
3795
|
value: url,
|
|
3589
3796
|
placeholder: "e.g. https://example.com",
|
|
@@ -3602,8 +3809,8 @@ function ButtonsField({ buttons, onChange }) {
|
|
|
3602
3809
|
},
|
|
3603
3810
|
className: "flex flex-row gap-3",
|
|
3604
3811
|
children: ["default", "primary", "danger"].map((s) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3605
|
-
/* @__PURE__ */ jsx(RadioGroupItem, { value: s, id:
|
|
3606
|
-
/* @__PURE__ */ jsx(Label, { htmlFor:
|
|
3812
|
+
/* @__PURE__ */ jsx(RadioGroupItem, { value: s, id: `${idPrefix}-btn-style-${idx}-${s}` }),
|
|
3813
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `${idPrefix}-btn-style-${idx}-${s}`, className: "text-xs capitalize", children: s })
|
|
3607
3814
|
] }, s))
|
|
3608
3815
|
}
|
|
3609
3816
|
) })
|
|
@@ -3652,8 +3859,8 @@ function CarouselEditor({ block, onChange }) {
|
|
|
3652
3859
|
});
|
|
3653
3860
|
};
|
|
3654
3861
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
3655
|
-
/* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "Carousels hold 1-10 cards.
|
|
3656
|
-
elements.map((card, idx) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-
|
|
3862
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "Carousels hold 1-10 cards." }),
|
|
3863
|
+
elements.map((card, idx) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-md border bg-muted/20 p-3", children: [
|
|
3657
3864
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
3658
3865
|
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground", children: [
|
|
3659
3866
|
"Card ",
|
|
@@ -3671,33 +3878,7 @@ function CarouselEditor({ block, onChange }) {
|
|
|
3671
3878
|
}
|
|
3672
3879
|
)
|
|
3673
3880
|
] }),
|
|
3674
|
-
/* @__PURE__ */ jsx(
|
|
3675
|
-
Input,
|
|
3676
|
-
{
|
|
3677
|
-
id: `carousel-card-title-${idx}`,
|
|
3678
|
-
value: card.title?.text ?? "",
|
|
3679
|
-
maxLength: 150,
|
|
3680
|
-
placeholder: "e.g. Card title",
|
|
3681
|
-
onChange: (e) => updateCard(idx, {
|
|
3682
|
-
...card,
|
|
3683
|
-
title: e.target.value ? { type: "mrkdwn", text: e.target.value } : void 0
|
|
3684
|
-
})
|
|
3685
|
-
}
|
|
3686
|
-
) }),
|
|
3687
|
-
/* @__PURE__ */ jsx(EditorField, { label: "Body", htmlFor: `carousel-card-body-${idx}`, children: /* @__PURE__ */ jsx(
|
|
3688
|
-
Textarea,
|
|
3689
|
-
{
|
|
3690
|
-
id: `carousel-card-body-${idx}`,
|
|
3691
|
-
value: card.body?.text ?? "",
|
|
3692
|
-
maxLength: 200,
|
|
3693
|
-
rows: 2,
|
|
3694
|
-
placeholder: "e.g. Short card description.",
|
|
3695
|
-
onChange: (e) => updateCard(idx, {
|
|
3696
|
-
...card,
|
|
3697
|
-
body: e.target.value ? { type: "mrkdwn", text: e.target.value } : void 0
|
|
3698
|
-
})
|
|
3699
|
-
}
|
|
3700
|
-
) })
|
|
3881
|
+
/* @__PURE__ */ jsx(CardEditor, { block: card, idPrefix: `carousel-card-${idx}`, onChange: (next) => updateCard(idx, next) })
|
|
3701
3882
|
] }, idx)),
|
|
3702
3883
|
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addCard, disabled: elements.length >= MAX_CARDS, className: "self-start", children: [
|
|
3703
3884
|
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
@@ -4159,7 +4340,7 @@ function TextItemCard({
|
|
|
4159
4340
|
id: `ctx-text-${index}`,
|
|
4160
4341
|
value: element.text,
|
|
4161
4342
|
rows: 2,
|
|
4162
|
-
placeholder: "e.g. Posted by @
|
|
4343
|
+
placeholder: "e.g. Posted by @riley",
|
|
4163
4344
|
onChange: (e) => onChange({ ...element, text: e.target.value })
|
|
4164
4345
|
}
|
|
4165
4346
|
) }),
|
|
@@ -4244,7 +4425,7 @@ function ImageItemCard({
|
|
|
4244
4425
|
{
|
|
4245
4426
|
id: `ctx-img-alt-${index}`,
|
|
4246
4427
|
value: element.alt_text,
|
|
4247
|
-
placeholder: "e.g.
|
|
4428
|
+
placeholder: "e.g. Riley's avatar",
|
|
4248
4429
|
onChange: (e) => onChange({ ...element, alt_text: e.target.value })
|
|
4249
4430
|
}
|
|
4250
4431
|
) })
|
|
@@ -8577,6 +8758,8 @@ var SURFACE_DROPPABLE_ID = "builder-surface";
|
|
|
8577
8758
|
function Surface({
|
|
8578
8759
|
blocks,
|
|
8579
8760
|
workspaceName,
|
|
8761
|
+
authorName,
|
|
8762
|
+
authorIcon,
|
|
8580
8763
|
previewHooks,
|
|
8581
8764
|
previewTheme,
|
|
8582
8765
|
previewSurface = "message",
|
|
@@ -8652,16 +8835,20 @@ function Surface({
|
|
|
8652
8835
|
{
|
|
8653
8836
|
"aria-label": "Block preview",
|
|
8654
8837
|
className: cn("flex min-w-0 flex-1 flex-col overflow-y-auto bg-muted p-3 sm:p-6"),
|
|
8655
|
-
children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsx(MessageFrame, { workspaceName, isDark, children: blocksList }) })
|
|
8838
|
+
children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsx(MessageFrame, { workspaceName, authorName, authorIcon, isDark, children: blocksList }) })
|
|
8656
8839
|
}
|
|
8657
8840
|
);
|
|
8658
8841
|
}
|
|
8659
8842
|
function MessageFrame({
|
|
8660
8843
|
workspaceName,
|
|
8844
|
+
authorName,
|
|
8845
|
+
authorIcon,
|
|
8661
8846
|
isDark,
|
|
8662
8847
|
children
|
|
8663
8848
|
}) {
|
|
8664
|
-
const
|
|
8849
|
+
const displayName = authorName ?? workspaceName ?? "Your app";
|
|
8850
|
+
const initial = displayName.slice(0, 1).toUpperCase();
|
|
8851
|
+
const safeIcon = authorIcon && isSafeImageSrc(authorIcon) ? authorIcon : null;
|
|
8665
8852
|
return /* @__PURE__ */ jsxs(
|
|
8666
8853
|
"div",
|
|
8667
8854
|
{
|
|
@@ -8675,7 +8862,7 @@ function MessageFrame({
|
|
|
8675
8862
|
{
|
|
8676
8863
|
className: cn("flex items-center gap-2 px-5 pt-3 pb-1 text-xs", isDark ? "text-white/60" : "text-[#616061]"),
|
|
8677
8864
|
children: [
|
|
8678
|
-
/* @__PURE__ */ jsx(
|
|
8865
|
+
safeIcon ? /* @__PURE__ */ jsx("img", { src: safeIcon, alt: "", className: "h-7 w-7 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsx(
|
|
8679
8866
|
"span",
|
|
8680
8867
|
{
|
|
8681
8868
|
className: cn(
|
|
@@ -8685,17 +8872,7 @@ function MessageFrame({
|
|
|
8685
8872
|
children: initial
|
|
8686
8873
|
}
|
|
8687
8874
|
),
|
|
8688
|
-
/* @__PURE__ */ jsx("span", { className: cn("font-bold text-sm", isDark ? "text-white" : "text-[#1d1c1d]"), children:
|
|
8689
|
-
/* @__PURE__ */ jsx(
|
|
8690
|
-
"span",
|
|
8691
|
-
{
|
|
8692
|
-
className: cn(
|
|
8693
|
-
"rounded px-1 text-[10px] font-semibold",
|
|
8694
|
-
isDark ? "bg-white/10 text-white/70" : "bg-[#f3f3f3] text-[#616061]"
|
|
8695
|
-
),
|
|
8696
|
-
children: "APP"
|
|
8697
|
-
}
|
|
8698
|
-
),
|
|
8875
|
+
/* @__PURE__ */ jsx("span", { className: cn("font-bold text-sm", isDark ? "text-white" : "text-[#1d1c1d]"), children: displayName }),
|
|
8699
8876
|
/* @__PURE__ */ jsx("span", { children: "10:37 AM" })
|
|
8700
8877
|
]
|
|
8701
8878
|
}
|
|
@@ -8897,6 +9074,14 @@ var SURFACE_OPTIONS = [
|
|
|
8897
9074
|
];
|
|
8898
9075
|
var DEFAULT_DOCS_HREF = "https://docs.slack.dev/reference/block-kit/blocks";
|
|
8899
9076
|
var DEFAULT_DOCS_LABEL = "Docs";
|
|
9077
|
+
function formatMessageTs(ts) {
|
|
9078
|
+
const seconds = Number.parseFloat(ts);
|
|
9079
|
+
if (!Number.isFinite(seconds)) return ts;
|
|
9080
|
+
const date = new Date(seconds * 1e3);
|
|
9081
|
+
if (Number.isNaN(date.getTime())) return ts;
|
|
9082
|
+
return date.toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
|
|
9083
|
+
}
|
|
9084
|
+
var SEND_MENU_ITEM = "flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50";
|
|
8900
9085
|
function Toolbar2({
|
|
8901
9086
|
onClear,
|
|
8902
9087
|
onOpenJson,
|
|
@@ -8913,7 +9098,14 @@ function Toolbar2({
|
|
|
8913
9098
|
showThemeControl = true,
|
|
8914
9099
|
docsLink,
|
|
8915
9100
|
errorCount,
|
|
8916
|
-
sendButtonLabel = "
|
|
9101
|
+
sendButtonLabel = "Review & send",
|
|
9102
|
+
editingEnabled = false,
|
|
9103
|
+
editBadge,
|
|
9104
|
+
onOpenLoad,
|
|
9105
|
+
onOpenUpdate,
|
|
9106
|
+
onExitEdit,
|
|
9107
|
+
loadButtonLabel = "Load message",
|
|
9108
|
+
updateButtonLabel = "Review & update"
|
|
8917
9109
|
}) {
|
|
8918
9110
|
const activeTheme = THEME_OPTIONS.find((t) => t.value === previewTheme) ?? THEME_OPTIONS[0];
|
|
8919
9111
|
const activeSurface = SURFACE_OPTIONS.find((s) => s.value === previewSurface) ?? SURFACE_OPTIONS[0];
|
|
@@ -8923,184 +9115,210 @@ function Toolbar2({
|
|
|
8923
9115
|
const docsLabel = docsLink === false ? null : docsLink?.label ?? DEFAULT_DOCS_LABEL;
|
|
8924
9116
|
const [surfaceMenuOpen, setSurfaceMenuOpen] = useState(false);
|
|
8925
9117
|
const [themeMenuOpen, setThemeMenuOpen] = useState(false);
|
|
8926
|
-
const [
|
|
8927
|
-
return /* @__PURE__ */ jsxs(
|
|
8928
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
8929
|
-
|
|
8930
|
-
Button,
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
className: "md:hidden",
|
|
8937
|
-
"aria-label": "Add a block",
|
|
8938
|
-
children: [
|
|
8939
|
-
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
|
|
8940
|
-
/* @__PURE__ */ jsx("span", { children: "Blocks" })
|
|
8941
|
-
]
|
|
8942
|
-
}
|
|
8943
|
-
) : null,
|
|
8944
|
-
showSurfaceControl ? /* @__PURE__ */ jsxs(Popover, { open: surfaceMenuOpen, onOpenChange: setSurfaceMenuOpen, children: [
|
|
8945
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview surface: ${activeSurface.label}`, children: [
|
|
8946
|
-
/* @__PURE__ */ jsx(activeSurface.Icon, { className: "h-3.5 w-3.5" }),
|
|
8947
|
-
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: activeSurface.label }),
|
|
8948
|
-
/* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
|
|
8949
|
-
] }) }),
|
|
8950
|
-
/* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-36 p-1", children: /* @__PURE__ */ jsx(
|
|
8951
|
-
Menu,
|
|
9118
|
+
const [sendMenuOpen, setSendMenuOpen] = useState(false);
|
|
9119
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9120
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-x-2 gap-y-1 border-b bg-background px-2 py-1.5 sm:px-3 sm:py-2", children: [
|
|
9121
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1 sm:gap-2", children: [
|
|
9122
|
+
editingEnabled && !editBadge ? /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: onOpenLoad, "aria-label": loadButtonLabel, children: [
|
|
9123
|
+
/* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" }),
|
|
9124
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: loadButtonLabel })
|
|
9125
|
+
] }) : null,
|
|
9126
|
+
onOpenPalette ? /* @__PURE__ */ jsxs(
|
|
9127
|
+
Button,
|
|
8952
9128
|
{
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
|
|
9129
|
+
type: "button",
|
|
9130
|
+
variant: "ghost",
|
|
9131
|
+
size: "sm",
|
|
9132
|
+
onClick: onOpenPalette,
|
|
9133
|
+
className: "md:hidden",
|
|
9134
|
+
"aria-label": "Add a block",
|
|
9135
|
+
children: [
|
|
9136
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
|
|
9137
|
+
/* @__PURE__ */ jsx("span", { children: "Blocks" })
|
|
9138
|
+
]
|
|
9139
|
+
}
|
|
9140
|
+
) : null,
|
|
9141
|
+
showSurfaceControl ? /* @__PURE__ */ jsxs(Popover, { open: surfaceMenuOpen, onOpenChange: setSurfaceMenuOpen, children: [
|
|
9142
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview surface: ${activeSurface.label}`, children: [
|
|
9143
|
+
/* @__PURE__ */ jsx(activeSurface.Icon, { className: "h-3.5 w-3.5" }),
|
|
9144
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: activeSurface.label }),
|
|
9145
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "hidden h-3.5 w-3.5 opacity-60 md:inline" })
|
|
9146
|
+
] }) }),
|
|
9147
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-36 p-1", children: /* @__PURE__ */ jsx(
|
|
9148
|
+
Menu,
|
|
9149
|
+
{
|
|
9150
|
+
ariaLabel: "Preview surface",
|
|
9151
|
+
options: surfaceOptions,
|
|
9152
|
+
value: previewSurface,
|
|
9153
|
+
onChange: (next) => {
|
|
9154
|
+
onPreviewSurfaceChange(next);
|
|
9155
|
+
setSurfaceMenuOpen(false);
|
|
9156
|
+
}
|
|
9157
|
+
}
|
|
9158
|
+
) })
|
|
9159
|
+
] }) : null,
|
|
9160
|
+
showThemeControl ? /* @__PURE__ */ jsxs(Popover, { open: themeMenuOpen, onOpenChange: setThemeMenuOpen, children: [
|
|
9161
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview theme: ${activeTheme.label}`, children: [
|
|
9162
|
+
/* @__PURE__ */ jsx(activeTheme.Icon, { className: "h-3.5 w-3.5" }),
|
|
9163
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: activeTheme.label }),
|
|
9164
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
|
|
9165
|
+
] }) }),
|
|
9166
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-32 p-1", children: /* @__PURE__ */ jsx(
|
|
9167
|
+
Menu,
|
|
9168
|
+
{
|
|
9169
|
+
ariaLabel: "Preview theme",
|
|
9170
|
+
options: THEME_OPTIONS,
|
|
9171
|
+
value: previewTheme,
|
|
9172
|
+
onChange: (next) => {
|
|
9173
|
+
onPreviewThemeChange(next);
|
|
9174
|
+
setThemeMenuOpen(false);
|
|
9175
|
+
}
|
|
8959
9176
|
}
|
|
9177
|
+
) })
|
|
9178
|
+
] }) : null,
|
|
9179
|
+
docsHref ? /* @__PURE__ */ jsxs(
|
|
9180
|
+
"a",
|
|
9181
|
+
{
|
|
9182
|
+
href: docsHref,
|
|
9183
|
+
target: "_blank",
|
|
9184
|
+
rel: "noreferrer noopener",
|
|
9185
|
+
className: "inline-flex h-8 items-center gap-1.5 rounded-md px-2 text-xs font-medium text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
9186
|
+
"aria-label": `${docsLabel} (opens in a new tab)`,
|
|
9187
|
+
children: [
|
|
9188
|
+
/* @__PURE__ */ jsx(BookOpen, { className: "h-3.5 w-3.5" }),
|
|
9189
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: docsLabel }),
|
|
9190
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "hidden h-3 w-3 opacity-50 md:inline" })
|
|
9191
|
+
]
|
|
8960
9192
|
}
|
|
8961
|
-
)
|
|
8962
|
-
] })
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: activeTheme.label }),
|
|
8967
|
-
/* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
|
|
8968
|
-
] }) }),
|
|
8969
|
-
/* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-32 p-1", children: /* @__PURE__ */ jsx(
|
|
8970
|
-
Menu,
|
|
9193
|
+
) : null
|
|
9194
|
+
] }),
|
|
9195
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
9196
|
+
errorCount > 0 ? /* @__PURE__ */ jsxs(
|
|
9197
|
+
Button,
|
|
8971
9198
|
{
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
9199
|
+
type: "button",
|
|
9200
|
+
variant: "ghost",
|
|
9201
|
+
size: "sm",
|
|
9202
|
+
onClick: onOpenIssues,
|
|
9203
|
+
className: "border border-red-200! bg-red-50 text-red-700 hover:bg-red-100 hover:text-red-700",
|
|
9204
|
+
"aria-label": `${errorCount} ${errorCount === 1 ? "issue" : "issues"}`,
|
|
9205
|
+
children: [
|
|
9206
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5" }),
|
|
9207
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
9208
|
+
errorCount,
|
|
9209
|
+
" ",
|
|
9210
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: errorCount === 1 ? "issue" : "issues" })
|
|
9211
|
+
] })
|
|
9212
|
+
]
|
|
8979
9213
|
}
|
|
8980
|
-
)
|
|
8981
|
-
|
|
8982
|
-
docsHref ? /* @__PURE__ */ jsxs(
|
|
8983
|
-
"a",
|
|
8984
|
-
{
|
|
8985
|
-
href: docsHref,
|
|
8986
|
-
target: "_blank",
|
|
8987
|
-
rel: "noreferrer noopener",
|
|
8988
|
-
className: "hidden h-8 items-center gap-1.5 rounded-md px-2 py-1 text-sm text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:inline-flex",
|
|
8989
|
-
"aria-label": `${docsLabel} (opens in a new tab)`,
|
|
8990
|
-
children: [
|
|
8991
|
-
/* @__PURE__ */ jsx(BookOpen, { className: "h-3.5 w-3.5" }),
|
|
8992
|
-
docsLabel,
|
|
8993
|
-
/* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 opacity-50" })
|
|
8994
|
-
]
|
|
8995
|
-
}
|
|
8996
|
-
) : null
|
|
8997
|
-
] }),
|
|
8998
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
8999
|
-
errorCount > 0 ? /* @__PURE__ */ jsxs(
|
|
9000
|
-
Button,
|
|
9001
|
-
{
|
|
9002
|
-
type: "button",
|
|
9003
|
-
variant: "ghost",
|
|
9004
|
-
size: "sm",
|
|
9005
|
-
onClick: onOpenIssues,
|
|
9006
|
-
className: "border border-red-200! bg-red-50 text-red-700 hover:bg-red-100 hover:text-red-700",
|
|
9007
|
-
"aria-label": `${errorCount} ${errorCount === 1 ? "issue" : "issues"}`,
|
|
9008
|
-
children: [
|
|
9009
|
-
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5" }),
|
|
9010
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
9011
|
-
errorCount,
|
|
9012
|
-
" ",
|
|
9013
|
-
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: errorCount === 1 ? "issue" : "issues" })
|
|
9014
|
-
] })
|
|
9015
|
-
]
|
|
9016
|
-
}
|
|
9017
|
-
) : null,
|
|
9018
|
-
/* @__PURE__ */ jsxs(
|
|
9019
|
-
Button,
|
|
9020
|
-
{
|
|
9021
|
-
type: "button",
|
|
9022
|
-
variant: "ghost",
|
|
9023
|
-
size: "sm",
|
|
9024
|
-
onClick: onClear,
|
|
9025
|
-
disabled: !canClear,
|
|
9026
|
-
className: "hidden hover:bg-destructive/10 hover:text-destructive sm:inline-flex",
|
|
9027
|
-
"aria-label": "Clear all blocks",
|
|
9028
|
-
children: [
|
|
9029
|
-
/* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
|
|
9030
|
-
"Clear"
|
|
9031
|
-
]
|
|
9032
|
-
}
|
|
9033
|
-
),
|
|
9034
|
-
/* @__PURE__ */ jsxs(
|
|
9035
|
-
Button,
|
|
9036
|
-
{
|
|
9037
|
-
type: "button",
|
|
9038
|
-
variant: "ghost",
|
|
9039
|
-
size: "sm",
|
|
9040
|
-
onClick: onOpenJson,
|
|
9041
|
-
"aria-label": "View JSON",
|
|
9042
|
-
className: "hidden sm:inline-flex",
|
|
9043
|
-
children: [
|
|
9044
|
-
/* @__PURE__ */ jsx(Code2, { className: "h-3.5 w-3.5" }),
|
|
9045
|
-
"View JSON"
|
|
9046
|
-
]
|
|
9047
|
-
}
|
|
9048
|
-
),
|
|
9049
|
-
/* @__PURE__ */ jsxs(Popover, { open: moreMenuOpen, onOpenChange: setMoreMenuOpen, children: [
|
|
9050
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
9214
|
+
) : null,
|
|
9215
|
+
/* @__PURE__ */ jsxs(
|
|
9051
9216
|
Button,
|
|
9052
9217
|
{
|
|
9053
9218
|
type: "button",
|
|
9054
9219
|
variant: "ghost",
|
|
9055
9220
|
size: "sm",
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
className: "
|
|
9059
|
-
|
|
9221
|
+
onClick: onClear,
|
|
9222
|
+
disabled: !canClear,
|
|
9223
|
+
className: "hover:bg-destructive/10 hover:text-destructive",
|
|
9224
|
+
"aria-label": "Clear all blocks",
|
|
9225
|
+
children: [
|
|
9226
|
+
/* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
|
|
9227
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: "Clear" })
|
|
9228
|
+
]
|
|
9060
9229
|
}
|
|
9061
|
-
)
|
|
9062
|
-
/* @__PURE__ */
|
|
9063
|
-
/* @__PURE__ */ jsx(
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
}
|
|
9084
|
-
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9230
|
+
),
|
|
9231
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: onOpenJson, "aria-label": "View JSON", children: [
|
|
9232
|
+
/* @__PURE__ */ jsx(Code2, { className: "h-3.5 w-3.5" }),
|
|
9233
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: "View JSON" })
|
|
9234
|
+
] }),
|
|
9235
|
+
editBadge ? (
|
|
9236
|
+
// A message is loaded: split button. Main action updates it in
|
|
9237
|
+
// place; the menu also offers posting the blocks as a new message.
|
|
9238
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-stretch", children: [
|
|
9239
|
+
/* @__PURE__ */ jsxs(
|
|
9240
|
+
Button,
|
|
9241
|
+
{
|
|
9242
|
+
type: "button",
|
|
9243
|
+
size: "sm",
|
|
9244
|
+
onClick: onOpenUpdate,
|
|
9245
|
+
disabled: !canSend,
|
|
9246
|
+
"aria-label": updateButtonLabel,
|
|
9247
|
+
className: "rounded-r-none",
|
|
9248
|
+
children: [
|
|
9249
|
+
/* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" }),
|
|
9250
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: updateButtonLabel })
|
|
9251
|
+
]
|
|
9252
|
+
}
|
|
9253
|
+
),
|
|
9254
|
+
/* @__PURE__ */ jsxs(Popover, { open: sendMenuOpen, onOpenChange: setSendMenuOpen, children: [
|
|
9255
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
9256
|
+
Button,
|
|
9257
|
+
{
|
|
9258
|
+
type: "button",
|
|
9259
|
+
size: "sm",
|
|
9260
|
+
"aria-label": "More message options",
|
|
9261
|
+
"aria-haspopup": "menu",
|
|
9262
|
+
className: "rounded-l-none border-l border-l-primary-foreground/30! px-1.5",
|
|
9263
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5" })
|
|
9264
|
+
}
|
|
9265
|
+
) }),
|
|
9266
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "end", className: "w-56 p-1", children: /* @__PURE__ */ jsxs("div", { role: "menu", "aria-label": "Message options", className: "flex flex-col", children: [
|
|
9267
|
+
/* @__PURE__ */ jsxs(
|
|
9268
|
+
"button",
|
|
9269
|
+
{
|
|
9270
|
+
type: "button",
|
|
9271
|
+
role: "menuitem",
|
|
9272
|
+
disabled: !canSend,
|
|
9273
|
+
onClick: () => {
|
|
9274
|
+
setSendMenuOpen(false);
|
|
9275
|
+
onOpenUpdate?.();
|
|
9276
|
+
},
|
|
9277
|
+
className: SEND_MENU_ITEM,
|
|
9278
|
+
children: [
|
|
9279
|
+
/* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" }),
|
|
9280
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: "Update message" })
|
|
9281
|
+
]
|
|
9282
|
+
}
|
|
9283
|
+
),
|
|
9284
|
+
/* @__PURE__ */ jsxs(
|
|
9285
|
+
"button",
|
|
9286
|
+
{
|
|
9287
|
+
type: "button",
|
|
9288
|
+
role: "menuitem",
|
|
9289
|
+
disabled: !canSend,
|
|
9290
|
+
onClick: () => {
|
|
9291
|
+
setSendMenuOpen(false);
|
|
9292
|
+
onOpenSend();
|
|
9293
|
+
},
|
|
9294
|
+
className: SEND_MENU_ITEM,
|
|
9295
|
+
children: [
|
|
9296
|
+
/* @__PURE__ */ jsx(Send, { className: "h-3.5 w-3.5" }),
|
|
9297
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: "Send as a new message" })
|
|
9298
|
+
]
|
|
9299
|
+
}
|
|
9300
|
+
)
|
|
9301
|
+
] }) })
|
|
9302
|
+
] })
|
|
9303
|
+
] })
|
|
9304
|
+
) : /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: onOpenSend, disabled: !canSend, "aria-label": sendButtonLabel, children: [
|
|
9305
|
+
/* @__PURE__ */ jsx(Send, { className: "h-3.5 w-3.5" }),
|
|
9306
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: sendButtonLabel })
|
|
9307
|
+
] })
|
|
9308
|
+
] })
|
|
9309
|
+
] }),
|
|
9310
|
+
editingEnabled && editBadge ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 border-b bg-muted px-2 py-2 text-foreground sm:px-3", children: [
|
|
9311
|
+
/* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4 shrink-0 text-primary" }),
|
|
9312
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 text-sm", children: [
|
|
9313
|
+
"References an existing message in ",
|
|
9314
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold", children: editBadge.channelLabel }),
|
|
9315
|
+
/* @__PURE__ */ jsx("span", { className: "ml-1 text-xs opacity-70", title: editBadge.ts, children: formatMessageTs(editBadge.ts) })
|
|
9098
9316
|
] }),
|
|
9099
|
-
/* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick:
|
|
9100
|
-
/* @__PURE__ */ jsx(
|
|
9101
|
-
|
|
9317
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: onExitEdit, className: "shrink-0", children: [
|
|
9318
|
+
/* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" }),
|
|
9319
|
+
"Switch to a new message"
|
|
9102
9320
|
] })
|
|
9103
|
-
] })
|
|
9321
|
+
] }) : null
|
|
9104
9322
|
] });
|
|
9105
9323
|
}
|
|
9106
9324
|
function Menu({
|
|
@@ -9158,52 +9376,132 @@ function Menu({
|
|
|
9158
9376
|
);
|
|
9159
9377
|
}) });
|
|
9160
9378
|
}
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9379
|
+
function UpdateDialog({
|
|
9380
|
+
open,
|
|
9381
|
+
onOpenChange,
|
|
9382
|
+
target,
|
|
9383
|
+
blocks,
|
|
9384
|
+
loadSendAsUserStatus,
|
|
9385
|
+
onUpdate,
|
|
9386
|
+
confirmUpdateLabel = "Update message",
|
|
9387
|
+
errorCount,
|
|
9388
|
+
onShowIssues
|
|
9168
9389
|
}) {
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9390
|
+
const asUser = target.editableVia === "user";
|
|
9391
|
+
const [userStatus, setUserStatus] = useState(null);
|
|
9392
|
+
const [status, setStatus] = useState({ kind: "idle" });
|
|
9393
|
+
const loadSendAsUserStatusRef = useRef(loadSendAsUserStatus);
|
|
9394
|
+
useEffect(() => {
|
|
9395
|
+
loadSendAsUserStatusRef.current = loadSendAsUserStatus;
|
|
9396
|
+
});
|
|
9397
|
+
const refreshSendAsUser = useCallback(() => {
|
|
9398
|
+
loadSendAsUserStatusRef.current().then(setUserStatus).catch(() => setUserStatus({ canSendAsUser: false }));
|
|
9399
|
+
}, []);
|
|
9400
|
+
useEffect(() => {
|
|
9401
|
+
if (!open) {
|
|
9402
|
+
return;
|
|
9181
9403
|
}
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
icon,
|
|
9187
|
-
trailingIcon,
|
|
9188
|
-
children,
|
|
9189
|
-
onSelect
|
|
9190
|
-
}) {
|
|
9191
|
-
return /* @__PURE__ */ jsxs(
|
|
9192
|
-
"a",
|
|
9193
|
-
{
|
|
9194
|
-
role: "menuitem",
|
|
9195
|
-
href,
|
|
9196
|
-
target: "_blank",
|
|
9197
|
-
rel: "noreferrer noopener",
|
|
9198
|
-
onClick: onSelect,
|
|
9199
|
-
className: ACTION_ITEM_BASE,
|
|
9200
|
-
children: [
|
|
9201
|
-
icon,
|
|
9202
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1", children }),
|
|
9203
|
-
trailingIcon
|
|
9204
|
-
]
|
|
9404
|
+
setStatus({ kind: "idle" });
|
|
9405
|
+
if (asUser) {
|
|
9406
|
+
setUserStatus(null);
|
|
9407
|
+
refreshSendAsUser();
|
|
9205
9408
|
}
|
|
9206
|
-
);
|
|
9409
|
+
}, [open, asUser, refreshSendAsUser]);
|
|
9410
|
+
useEffect(() => {
|
|
9411
|
+
if (!open || !asUser) {
|
|
9412
|
+
return;
|
|
9413
|
+
}
|
|
9414
|
+
const handler = () => refreshSendAsUser();
|
|
9415
|
+
window.addEventListener("focus", handler);
|
|
9416
|
+
return () => window.removeEventListener("focus", handler);
|
|
9417
|
+
}, [open, asUser, refreshSendAsUser]);
|
|
9418
|
+
const needsSignIn = asUser && userStatus !== null && !userStatus.canSendAsUser;
|
|
9419
|
+
const handleSubmit = async () => {
|
|
9420
|
+
setStatus({ kind: "updating" });
|
|
9421
|
+
try {
|
|
9422
|
+
const result = await onUpdate({
|
|
9423
|
+
channelId: target.channelId,
|
|
9424
|
+
ts: target.ts,
|
|
9425
|
+
blocks: toSlackBlocks(blocks),
|
|
9426
|
+
asUser
|
|
9427
|
+
});
|
|
9428
|
+
if (result.ok) {
|
|
9429
|
+
setStatus({ kind: "idle" });
|
|
9430
|
+
onOpenChange(false);
|
|
9431
|
+
return;
|
|
9432
|
+
}
|
|
9433
|
+
setStatus({ kind: "error", error: result.error ?? "Update failed." });
|
|
9434
|
+
} catch (e) {
|
|
9435
|
+
setStatus({ kind: "error", error: e instanceof Error ? e.message : "Update failed." });
|
|
9436
|
+
}
|
|
9437
|
+
};
|
|
9438
|
+
const channelLabel = target.channelName ? `#${target.channelName}` : target.channelId;
|
|
9439
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[calc(100vw-1.5rem)] max-w-lg rounded-lg", children: [
|
|
9440
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
9441
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Update message" }),
|
|
9442
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "This replaces the message that's already posted. It stays in the same channel and can't be moved." })
|
|
9443
|
+
] }),
|
|
9444
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
9445
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
9446
|
+
/* @__PURE__ */ jsx(Label, { children: "Channel" }),
|
|
9447
|
+
/* @__PURE__ */ jsx("p", { className: "flex h-9 items-center rounded-md border border-input bg-muted px-3 text-sm text-muted-foreground", children: channelLabel })
|
|
9448
|
+
] }),
|
|
9449
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
9450
|
+
/* @__PURE__ */ jsx(Label, { children: "Posting as" }),
|
|
9451
|
+
/* @__PURE__ */ jsx("p", { className: "flex h-9 items-center rounded-md border border-input bg-muted px-3 text-sm text-muted-foreground", children: asUser ? "Your account" : "App bot" }),
|
|
9452
|
+
needsSignIn && userStatus?.oauthUrl && isSafeHref(userStatus.oauthUrl) && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
9453
|
+
/* @__PURE__ */ jsxs(
|
|
9454
|
+
"a",
|
|
9455
|
+
{
|
|
9456
|
+
href: userStatus.oauthUrl,
|
|
9457
|
+
target: "_blank",
|
|
9458
|
+
rel: "noopener noreferrer",
|
|
9459
|
+
className: "inline-flex items-center gap-1 text-primary hover:underline",
|
|
9460
|
+
children: [
|
|
9461
|
+
"Sign in with Slack ",
|
|
9462
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
|
|
9463
|
+
]
|
|
9464
|
+
}
|
|
9465
|
+
),
|
|
9466
|
+
" ",
|
|
9467
|
+
"to update your own message."
|
|
9468
|
+
] }),
|
|
9469
|
+
needsSignIn && !userStatus?.oauthUrl && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Sign in with Slack to update your own message." })
|
|
9470
|
+
] }),
|
|
9471
|
+
errorCount > 0 ? /* @__PURE__ */ jsxs(
|
|
9472
|
+
"button",
|
|
9473
|
+
{
|
|
9474
|
+
type: "button",
|
|
9475
|
+
onClick: onShowIssues,
|
|
9476
|
+
className: "flex items-center gap-2 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-left text-xs text-destructive hover:bg-destructive/10",
|
|
9477
|
+
children: [
|
|
9478
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
9479
|
+
/* @__PURE__ */ jsxs("span", { className: "flex-1", children: [
|
|
9480
|
+
"Fix ",
|
|
9481
|
+
errorCount,
|
|
9482
|
+
" ",
|
|
9483
|
+
errorCount === 1 ? "issue" : "issues",
|
|
9484
|
+
" before updating."
|
|
9485
|
+
] }),
|
|
9486
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 underline", children: "Show issues" })
|
|
9487
|
+
]
|
|
9488
|
+
}
|
|
9489
|
+
) : null,
|
|
9490
|
+
status.kind === "error" && /* @__PURE__ */ jsx("p", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: status.error })
|
|
9491
|
+
] }),
|
|
9492
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
9493
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
9494
|
+
/* @__PURE__ */ jsx(
|
|
9495
|
+
Button,
|
|
9496
|
+
{
|
|
9497
|
+
type: "button",
|
|
9498
|
+
onClick: handleSubmit,
|
|
9499
|
+
disabled: status.kind === "updating" || blocks.length === 0 || errorCount > 0 || needsSignIn,
|
|
9500
|
+
children: status.kind === "updating" ? "Updating\u2026" : confirmUpdateLabel
|
|
9501
|
+
}
|
|
9502
|
+
)
|
|
9503
|
+
] })
|
|
9504
|
+
] }) });
|
|
9207
9505
|
}
|
|
9208
9506
|
function BlockKitchen(props) {
|
|
9209
9507
|
const {
|
|
@@ -9215,6 +9513,10 @@ function BlockKitchen(props) {
|
|
|
9215
9513
|
loadChannels,
|
|
9216
9514
|
loadSendAsUserStatus,
|
|
9217
9515
|
onSend,
|
|
9516
|
+
editing,
|
|
9517
|
+
loadButtonLabel,
|
|
9518
|
+
updateButtonLabel,
|
|
9519
|
+
confirmUpdateLabel,
|
|
9218
9520
|
palette,
|
|
9219
9521
|
disabledBlockTypes,
|
|
9220
9522
|
showPaletteSearch,
|
|
@@ -9260,6 +9562,10 @@ function BlockKitchen(props) {
|
|
|
9260
9562
|
}, [blocks]);
|
|
9261
9563
|
const [jsonOpen, setJsonOpen] = useState(false);
|
|
9262
9564
|
const [sendOpen, setSendOpen] = useState(false);
|
|
9565
|
+
const [updateOpen, setUpdateOpen] = useState(false);
|
|
9566
|
+
const [loadOpen, setLoadOpen] = useState(false);
|
|
9567
|
+
const [editTarget, setEditTarget] = useState(null);
|
|
9568
|
+
const activeEditTarget = editing ? editTarget : null;
|
|
9263
9569
|
const [issuesOpen, setIssuesOpen] = useState(false);
|
|
9264
9570
|
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
9265
9571
|
const [openBlockId, setOpenBlockId] = useState(null);
|
|
@@ -9380,7 +9686,21 @@ function BlockKitchen(props) {
|
|
|
9380
9686
|
allowedSurfaces,
|
|
9381
9687
|
showThemeControl: isPreviewThemeControlled ? false : showThemeControl,
|
|
9382
9688
|
docsLink,
|
|
9383
|
-
sendButtonLabel
|
|
9689
|
+
sendButtonLabel,
|
|
9690
|
+
editingEnabled: !!editing,
|
|
9691
|
+
editBadge: activeEditTarget ? {
|
|
9692
|
+
channelLabel: activeEditTarget.channelName ? `#${activeEditTarget.channelName}` : activeEditTarget.channelId,
|
|
9693
|
+
ts: activeEditTarget.ts
|
|
9694
|
+
} : null,
|
|
9695
|
+
onOpenLoad: () => setLoadOpen(true),
|
|
9696
|
+
onOpenUpdate: () => setUpdateOpen(true),
|
|
9697
|
+
onExitEdit: () => {
|
|
9698
|
+
setEditTarget(null);
|
|
9699
|
+
replaceAll([]);
|
|
9700
|
+
setLoadOpen(true);
|
|
9701
|
+
},
|
|
9702
|
+
loadButtonLabel,
|
|
9703
|
+
updateButtonLabel
|
|
9384
9704
|
}
|
|
9385
9705
|
),
|
|
9386
9706
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 items-stretch", children: [
|
|
@@ -9399,6 +9719,8 @@ function BlockKitchen(props) {
|
|
|
9399
9719
|
{
|
|
9400
9720
|
blocks,
|
|
9401
9721
|
workspaceName,
|
|
9722
|
+
authorName: activeEditTarget?.username,
|
|
9723
|
+
authorIcon: activeEditTarget?.iconUrl,
|
|
9402
9724
|
previewHooks: mergedPreviewHooks,
|
|
9403
9725
|
previewTheme,
|
|
9404
9726
|
previewSurface,
|
|
@@ -9464,6 +9786,52 @@ function BlockKitchen(props) {
|
|
|
9464
9786
|
}
|
|
9465
9787
|
}
|
|
9466
9788
|
),
|
|
9789
|
+
activeEditTarget && editing ? /* @__PURE__ */ jsx(
|
|
9790
|
+
UpdateDialog,
|
|
9791
|
+
{
|
|
9792
|
+
open: updateOpen,
|
|
9793
|
+
onOpenChange: setUpdateOpen,
|
|
9794
|
+
target: activeEditTarget,
|
|
9795
|
+
blocks: blockPayloads,
|
|
9796
|
+
loadSendAsUserStatus,
|
|
9797
|
+
onUpdate: editing.onUpdate,
|
|
9798
|
+
confirmUpdateLabel,
|
|
9799
|
+
errorCount: validation.total,
|
|
9800
|
+
onShowIssues: () => {
|
|
9801
|
+
setUpdateOpen(false);
|
|
9802
|
+
setIssuesOpen(true);
|
|
9803
|
+
}
|
|
9804
|
+
}
|
|
9805
|
+
) : null,
|
|
9806
|
+
editing ? /* @__PURE__ */ jsx(
|
|
9807
|
+
LoadMessageDialog,
|
|
9808
|
+
{
|
|
9809
|
+
open: loadOpen,
|
|
9810
|
+
onOpenChange: setLoadOpen,
|
|
9811
|
+
onLoadMessage: editing.onLoadMessage,
|
|
9812
|
+
loadRecentMessages: editing.loadRecentMessages,
|
|
9813
|
+
onLoaded: (result) => {
|
|
9814
|
+
replaceAll(result.blocks);
|
|
9815
|
+
setEditTarget({
|
|
9816
|
+
channelId: result.channelId,
|
|
9817
|
+
channelName: result.channelName,
|
|
9818
|
+
ts: result.ts,
|
|
9819
|
+
editableVia: result.editableVia,
|
|
9820
|
+
workspaceName: result.workspaceName,
|
|
9821
|
+
username: result.username,
|
|
9822
|
+
iconUrl: result.iconUrl
|
|
9823
|
+
});
|
|
9824
|
+
setLoadOpen(false);
|
|
9825
|
+
},
|
|
9826
|
+
onOpenAsNew: (loadedBlocks) => {
|
|
9827
|
+
if (loadedBlocks) {
|
|
9828
|
+
replaceAll(loadedBlocks);
|
|
9829
|
+
}
|
|
9830
|
+
setEditTarget(null);
|
|
9831
|
+
setLoadOpen(false);
|
|
9832
|
+
}
|
|
9833
|
+
}
|
|
9834
|
+
) : null,
|
|
9467
9835
|
/* @__PURE__ */ jsx(
|
|
9468
9836
|
IssuesSheet,
|
|
9469
9837
|
{
|