@tightknitai/block-kitchen 0.10.2 → 0.10.4
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 +21 -8
- package/dist/helpers.cjs +1 -8
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +17 -11
- package/dist/helpers.d.ts +17 -11
- package/dist/helpers.js +1 -8
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +483 -281
- 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 +484 -282
- package/dist/index.js.map +1 -1
- package/dist/{palette-BtSwlGUC.d.cts → palette-Sz27861i.d.cts} +15 -10
- package/dist/{palette-BtSwlGUC.d.ts → palette-Sz27861i.d.ts} +15 -10
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/styles.css +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -14,14 +14,14 @@ var nanoid = require('nanoid');
|
|
|
14
14
|
var reactSlot = require('@radix-ui/react-slot');
|
|
15
15
|
var classVarianceAuthority = require('class-variance-authority');
|
|
16
16
|
var LabelPrimitive = require('@radix-ui/react-label');
|
|
17
|
+
require('slack-blocks-to-jsx/dist/style.css');
|
|
18
|
+
var slackBlocksToJsx = require('slack-blocks-to-jsx');
|
|
17
19
|
var utilities = require('@dnd-kit/utilities');
|
|
18
20
|
var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
19
21
|
var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
|
|
20
22
|
var Link = require('@tiptap/extension-link');
|
|
21
23
|
var react = require('@tiptap/react');
|
|
22
24
|
var StarterKit = require('@tiptap/starter-kit');
|
|
23
|
-
require('slack-blocks-to-jsx/dist/style.css');
|
|
24
|
-
var slackBlocksToJsx = require('slack-blocks-to-jsx');
|
|
25
25
|
|
|
26
26
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
27
|
|
|
@@ -1987,14 +1987,7 @@ function sanitizeBlocks(blocks) {
|
|
|
1987
1987
|
|
|
1988
1988
|
// src/lib/to-slack-blocks.ts
|
|
1989
1989
|
function toSlackBlocks(blocks) {
|
|
1990
|
-
return blocks.map((block) =>
|
|
1991
|
-
const safe = sanitizeBlock(block);
|
|
1992
|
-
if (safe.type === "header" && "level" in safe) {
|
|
1993
|
-
const { level: _omit, ...rest } = safe;
|
|
1994
|
-
return rest;
|
|
1995
|
-
}
|
|
1996
|
-
return safe;
|
|
1997
|
-
});
|
|
1990
|
+
return blocks.map((block) => sanitizeBlock(block));
|
|
1998
1991
|
}
|
|
1999
1992
|
|
|
2000
1993
|
// src/lib/validation-sanitize.ts
|
|
@@ -3061,6 +3054,128 @@ var Label = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__
|
|
|
3061
3054
|
}
|
|
3062
3055
|
));
|
|
3063
3056
|
Label.displayName = LabelPrimitive__namespace.Root.displayName;
|
|
3057
|
+
function SlackBlockPreview({
|
|
3058
|
+
block,
|
|
3059
|
+
hooks,
|
|
3060
|
+
theme = "light"
|
|
3061
|
+
}) {
|
|
3062
|
+
const rootRef = React.useRef(null);
|
|
3063
|
+
const safeBlock = React.useMemo(() => sanitizeBlock(block), [block]);
|
|
3064
|
+
React.useEffect(() => {
|
|
3065
|
+
const root = rootRef.current;
|
|
3066
|
+
if (!root) return;
|
|
3067
|
+
for (const wrapper of root.querySelectorAll(
|
|
3068
|
+
".slack_blocks_to_jsx__image_media_trigger, .slack_blocks_to_jsx__video_title"
|
|
3069
|
+
)) {
|
|
3070
|
+
for (const btn of wrapper.querySelectorAll("button:not([aria-label])")) {
|
|
3071
|
+
const title = wrapper.querySelector(".slack_blocks_to_jsx__image_title")?.textContent?.trim();
|
|
3072
|
+
btn.setAttribute("aria-label", title ? `Toggle ${title}` : "Toggle media");
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
for (const a of root.querySelectorAll("a[href]")) {
|
|
3076
|
+
const href = a.getAttribute("href");
|
|
3077
|
+
if (!isSafeHref(href)) {
|
|
3078
|
+
a.setAttribute("href", "#");
|
|
3079
|
+
a.setAttribute("data-bk-blocked-href", "1");
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
for (const img of root.querySelectorAll("img[src]")) {
|
|
3083
|
+
const src = img.getAttribute("src");
|
|
3084
|
+
if (!isSafeImageSrc(src)) {
|
|
3085
|
+
img.removeAttribute("src");
|
|
3086
|
+
img.setAttribute("data-bk-blocked-src", "1");
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
});
|
|
3090
|
+
return (
|
|
3091
|
+
// The library scopes all of its CSS under `#slack_blocks_to_jsx` and
|
|
3092
|
+
// depends on the `slack_blocks_to_jsx styles_enabled` classes plus the
|
|
3093
|
+
// `data-theme` attribute for its button / mention / divider styling
|
|
3094
|
+
// (e.g. button reset + `bg-green-primary` for primary). `<Message
|
|
3095
|
+
// withoutWrapper>` skips that wrapper entirely, so we re-create it
|
|
3096
|
+
// here without the avatar / timestamp chrome.
|
|
3097
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, id: "slack_blocks_to_jsx", "data-theme": theme, className: "slack_blocks_to_jsx styles_enabled", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3098
|
+
slackBlocksToJsx.Message,
|
|
3099
|
+
{
|
|
3100
|
+
time: /* @__PURE__ */ new Date(),
|
|
3101
|
+
name: "",
|
|
3102
|
+
logo: "",
|
|
3103
|
+
withoutWrapper: true,
|
|
3104
|
+
theme,
|
|
3105
|
+
blocks: [safeBlock],
|
|
3106
|
+
hooks
|
|
3107
|
+
}
|
|
3108
|
+
) })
|
|
3109
|
+
);
|
|
3110
|
+
}
|
|
3111
|
+
var PLACEHOLDER_TIME = "10:37 AM";
|
|
3112
|
+
function SlackMessageFrame({
|
|
3113
|
+
workspaceName,
|
|
3114
|
+
authorName,
|
|
3115
|
+
authorIcon,
|
|
3116
|
+
time = PLACEHOLDER_TIME,
|
|
3117
|
+
isDark,
|
|
3118
|
+
children
|
|
3119
|
+
}) {
|
|
3120
|
+
const displayName = authorName ?? workspaceName ?? "Your app";
|
|
3121
|
+
const initial = displayName.slice(0, 1).toUpperCase();
|
|
3122
|
+
const safeIcon = authorIcon && isSafeImageSrc(authorIcon) ? authorIcon : null;
|
|
3123
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3124
|
+
"div",
|
|
3125
|
+
{
|
|
3126
|
+
className: cn(
|
|
3127
|
+
"flex flex-col overflow-hidden rounded-md border",
|
|
3128
|
+
isDark ? "border-[#2c2d30] bg-[#1a1d21]" : "border-[#e8e8e8] bg-white"
|
|
3129
|
+
),
|
|
3130
|
+
children: [
|
|
3131
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3132
|
+
"div",
|
|
3133
|
+
{
|
|
3134
|
+
className: cn("flex items-center gap-2 px-5 pt-3 pb-1 text-xs", isDark ? "text-white/60" : "text-[#616061]"),
|
|
3135
|
+
children: [
|
|
3136
|
+
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-7 w-7 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3137
|
+
"span",
|
|
3138
|
+
{
|
|
3139
|
+
className: cn(
|
|
3140
|
+
"inline-flex h-7 w-7 items-center justify-center rounded text-[12px] font-semibold",
|
|
3141
|
+
isDark ? "bg-white/10 text-white" : "bg-[#4a154b]/10 text-[#1d1c1d]"
|
|
3142
|
+
),
|
|
3143
|
+
children: initial
|
|
3144
|
+
}
|
|
3145
|
+
),
|
|
3146
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold text-sm", isDark ? "text-white" : "text-[#1d1c1d]"), children: displayName }),
|
|
3147
|
+
time ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: time }) : null
|
|
3148
|
+
]
|
|
3149
|
+
}
|
|
3150
|
+
),
|
|
3151
|
+
children
|
|
3152
|
+
]
|
|
3153
|
+
}
|
|
3154
|
+
);
|
|
3155
|
+
}
|
|
3156
|
+
function SlackMessagePreview({
|
|
3157
|
+
blocks,
|
|
3158
|
+
hooks,
|
|
3159
|
+
theme = "light",
|
|
3160
|
+
workspaceName,
|
|
3161
|
+
authorName,
|
|
3162
|
+
authorIcon,
|
|
3163
|
+
time,
|
|
3164
|
+
emptyLabel = "This message has no blocks to preview."
|
|
3165
|
+
}) {
|
|
3166
|
+
const isDark = theme === "dark";
|
|
3167
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3168
|
+
SlackMessageFrame,
|
|
3169
|
+
{
|
|
3170
|
+
workspaceName,
|
|
3171
|
+
authorName,
|
|
3172
|
+
authorIcon,
|
|
3173
|
+
time,
|
|
3174
|
+
isDark,
|
|
3175
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex min-w-0 flex-col gap-1 px-5 pb-3", isDark ? "bg-[#1a1d21]" : "bg-white"), children: blocks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("py-1 text-sm", isDark ? "text-white/60" : "text-[#616061]"), children: emptyLabel }) : blocks.map((block, index) => /* @__PURE__ */ jsxRuntime.jsx(SlackBlockPreview, { block, hooks, theme }, `${block.type}-${index}`)) })
|
|
3176
|
+
}
|
|
3177
|
+
);
|
|
3178
|
+
}
|
|
3064
3179
|
var POLL_INTERVAL_MS = 2500;
|
|
3065
3180
|
var MAX_POLLS = 24;
|
|
3066
3181
|
function useSlackSignIn(loadStatus, { open, enabled }) {
|
|
@@ -3134,6 +3249,12 @@ function SlackSignInButton({ onClick, polling }) {
|
|
|
3134
3249
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, {})
|
|
3135
3250
|
] }) });
|
|
3136
3251
|
}
|
|
3252
|
+
var LINK_DEBOUNCE_MS = 400;
|
|
3253
|
+
var LINK_HELP_TEXT = 'Click the \u2807menu while hovering over the message in Slack (or right-click), and select "Copy Link".';
|
|
3254
|
+
var TABS = [
|
|
3255
|
+
{ id: "recent", label: "Pick from Recent" },
|
|
3256
|
+
{ id: "link", label: "Direct Link" }
|
|
3257
|
+
];
|
|
3137
3258
|
function recentToResult(msg) {
|
|
3138
3259
|
return {
|
|
3139
3260
|
ok: true,
|
|
@@ -3158,6 +3279,16 @@ function previewText(m) {
|
|
|
3158
3279
|
}
|
|
3159
3280
|
return `${m.blocks.length} block${m.blocks.length === 1 ? "" : "s"}`;
|
|
3160
3281
|
}
|
|
3282
|
+
function formatTs(ts) {
|
|
3283
|
+
const seconds = Number(ts);
|
|
3284
|
+
if (!ts || !Number.isFinite(seconds) || seconds <= 0) {
|
|
3285
|
+
return "";
|
|
3286
|
+
}
|
|
3287
|
+
return new Date(seconds * 1e3).toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
3288
|
+
}
|
|
3289
|
+
function editableLabel(editableVia) {
|
|
3290
|
+
return editableVia === "user" ? "You" : "Bot";
|
|
3291
|
+
}
|
|
3161
3292
|
function LoadMessageDialog({
|
|
3162
3293
|
open,
|
|
3163
3294
|
onOpenChange,
|
|
@@ -3165,10 +3296,14 @@ function LoadMessageDialog({
|
|
|
3165
3296
|
loadRecentMessages,
|
|
3166
3297
|
loadChannels,
|
|
3167
3298
|
onLoaded,
|
|
3168
|
-
onOpenAsNew
|
|
3299
|
+
onOpenAsNew,
|
|
3300
|
+
previewHooks,
|
|
3301
|
+
previewTheme = "light"
|
|
3169
3302
|
}) {
|
|
3170
3303
|
const [link, setLink] = React.useState("");
|
|
3171
|
-
const [
|
|
3304
|
+
const [linkStatus, setLinkStatus] = React.useState({ kind: "idle" });
|
|
3305
|
+
const [emptyLinkError, setEmptyLinkError] = React.useState(null);
|
|
3306
|
+
const [committing, setCommitting] = React.useState(false);
|
|
3172
3307
|
const [channels, setChannels] = React.useState(null);
|
|
3173
3308
|
const [channelsError, setChannelsError] = React.useState(null);
|
|
3174
3309
|
const [channelId, setChannelId] = React.useState("");
|
|
@@ -3176,8 +3311,14 @@ function LoadMessageDialog({
|
|
|
3176
3311
|
const [recentError, setRecentError] = React.useState(null);
|
|
3177
3312
|
const [selectedRecent, setSelectedRecent] = React.useState(null);
|
|
3178
3313
|
const [signInPolling, setSignInPolling] = React.useState(false);
|
|
3314
|
+
const [tab, setTab] = React.useState("recent");
|
|
3179
3315
|
const inputRef = React.useRef(null);
|
|
3180
3316
|
const signInPollRef = React.useRef(null);
|
|
3317
|
+
const resolvedLinkRef = React.useRef(null);
|
|
3318
|
+
const linkRequestRef = React.useRef(0);
|
|
3319
|
+
const domId = React.useId();
|
|
3320
|
+
const tabDomId = (id) => `${domId}-${id}-tab`;
|
|
3321
|
+
const panelDomId = (id) => `${domId}-${id}-panel`;
|
|
3181
3322
|
const onLoadMessageRef = React.useRef(onLoadMessage);
|
|
3182
3323
|
const loadRecentMessagesRef = React.useRef(loadRecentMessages);
|
|
3183
3324
|
const loadChannelsRef = React.useRef(loadChannels);
|
|
@@ -3187,16 +3328,22 @@ function LoadMessageDialog({
|
|
|
3187
3328
|
loadChannelsRef.current = loadChannels;
|
|
3188
3329
|
});
|
|
3189
3330
|
const hasRecent = !!loadRecentMessages && !!loadChannels;
|
|
3331
|
+
const activeTab = hasRecent ? tab : "link";
|
|
3190
3332
|
React.useEffect(() => {
|
|
3191
3333
|
if (!open) {
|
|
3192
3334
|
return;
|
|
3193
3335
|
}
|
|
3194
3336
|
setLink("");
|
|
3195
|
-
|
|
3337
|
+
setLinkStatus({ kind: "idle" });
|
|
3338
|
+
setEmptyLinkError(null);
|
|
3339
|
+
setCommitting(false);
|
|
3196
3340
|
setChannelId("");
|
|
3197
3341
|
setRecent(null);
|
|
3198
3342
|
setRecentError(null);
|
|
3199
3343
|
setSelectedRecent(null);
|
|
3344
|
+
setTab("recent");
|
|
3345
|
+
resolvedLinkRef.current = null;
|
|
3346
|
+
linkRequestRef.current += 1;
|
|
3200
3347
|
}, [open]);
|
|
3201
3348
|
React.useEffect(() => {
|
|
3202
3349
|
const load = loadChannelsRef.current;
|
|
@@ -3255,27 +3402,71 @@ function LoadMessageDialog({
|
|
|
3255
3402
|
}
|
|
3256
3403
|
return stopSignInPoll;
|
|
3257
3404
|
}, [open, stopSignInPoll]);
|
|
3405
|
+
const resolveLink = React.useCallback(async (trimmed) => {
|
|
3406
|
+
const requestId = ++linkRequestRef.current;
|
|
3407
|
+
setLinkStatus({ kind: "loading" });
|
|
3408
|
+
try {
|
|
3409
|
+
const result = await onLoadMessageRef.current({ link: trimmed });
|
|
3410
|
+
if (linkRequestRef.current !== requestId) {
|
|
3411
|
+
return null;
|
|
3412
|
+
}
|
|
3413
|
+
resolvedLinkRef.current = trimmed;
|
|
3414
|
+
setLinkStatus(
|
|
3415
|
+
result.ok ? { kind: "ready", result } : { kind: "not-editable", reason: result.reason, blocks: result.blocks, oauthUrl: result.oauthUrl }
|
|
3416
|
+
);
|
|
3417
|
+
return result;
|
|
3418
|
+
} catch (e) {
|
|
3419
|
+
if (linkRequestRef.current !== requestId) {
|
|
3420
|
+
return null;
|
|
3421
|
+
}
|
|
3422
|
+
resolvedLinkRef.current = trimmed;
|
|
3423
|
+
setLinkStatus({ kind: "error", error: e instanceof Error ? e.message : "Failed to load message." });
|
|
3424
|
+
return null;
|
|
3425
|
+
}
|
|
3426
|
+
}, []);
|
|
3427
|
+
React.useEffect(() => {
|
|
3428
|
+
if (!open) {
|
|
3429
|
+
return;
|
|
3430
|
+
}
|
|
3431
|
+
const trimmed = link.trim();
|
|
3432
|
+
if (!trimmed) {
|
|
3433
|
+
linkRequestRef.current += 1;
|
|
3434
|
+
resolvedLinkRef.current = null;
|
|
3435
|
+
setLinkStatus({ kind: "idle" });
|
|
3436
|
+
return;
|
|
3437
|
+
}
|
|
3438
|
+
if (resolvedLinkRef.current === trimmed) {
|
|
3439
|
+
return;
|
|
3440
|
+
}
|
|
3441
|
+
const timer = setTimeout(() => {
|
|
3442
|
+
if (resolvedLinkRef.current !== trimmed) {
|
|
3443
|
+
void resolveLink(trimmed);
|
|
3444
|
+
}
|
|
3445
|
+
}, LINK_DEBOUNCE_MS);
|
|
3446
|
+
return () => clearTimeout(timer);
|
|
3447
|
+
}, [open, link, resolveLink]);
|
|
3258
3448
|
const handleLoad = async () => {
|
|
3259
3449
|
stopSignInPoll();
|
|
3260
|
-
if (
|
|
3261
|
-
|
|
3450
|
+
if (activeTab === "recent") {
|
|
3451
|
+
if (selectedRecent) {
|
|
3452
|
+
onLoaded(recentToResult(selectedRecent));
|
|
3453
|
+
}
|
|
3262
3454
|
return;
|
|
3263
3455
|
}
|
|
3264
3456
|
const trimmed = link.trim();
|
|
3265
3457
|
if (!trimmed) {
|
|
3266
|
-
|
|
3458
|
+
setEmptyLinkError("Paste a Slack message link first.");
|
|
3267
3459
|
return;
|
|
3268
3460
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
setStatus({ kind: "error", error: e instanceof Error ? e.message : "Failed to load message." });
|
|
3461
|
+
if (linkStatus.kind === "ready" && resolvedLinkRef.current === trimmed) {
|
|
3462
|
+
onLoaded(linkStatus.result);
|
|
3463
|
+
return;
|
|
3464
|
+
}
|
|
3465
|
+
setCommitting(true);
|
|
3466
|
+
const result = await resolveLink(trimmed);
|
|
3467
|
+
setCommitting(false);
|
|
3468
|
+
if (result?.ok) {
|
|
3469
|
+
onLoaded(result);
|
|
3279
3470
|
}
|
|
3280
3471
|
};
|
|
3281
3472
|
const startFindSignIn = (oauthUrl) => {
|
|
@@ -3307,191 +3498,288 @@ function LoadMessageDialog({
|
|
|
3307
3498
|
});
|
|
3308
3499
|
}, POLL_INTERVAL_MS2);
|
|
3309
3500
|
};
|
|
3310
|
-
const
|
|
3311
|
-
const
|
|
3501
|
+
const preview = activeTab === "recent" ? selectedRecent ? { kind: "ready", target: { ...selectedRecent, editableVia: selectedRecent.editableVia ?? "bot" } } : { kind: "empty" } : linkStatus.kind === "idle" ? { kind: "empty" } : linkStatus.kind === "ready" ? { kind: "ready", target: linkStatus.result } : linkStatus;
|
|
3502
|
+
const canLoad = activeTab === "recent" ? !!selectedRecent : !!link.trim();
|
|
3503
|
+
const panelProps = (id) => hasRecent ? { role: "tabpanel", id: panelDomId(id), "aria-labelledby": tabDomId(id) } : {};
|
|
3312
3504
|
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3313
3505
|
DialogContent,
|
|
3314
3506
|
{
|
|
3315
|
-
className: "w-[calc(100vw-1.5rem)]
|
|
3507
|
+
className: "flex max-h-[85svh] w-[calc(100vw-1.5rem)] flex-col rounded-lg lg:max-w-4xl",
|
|
3316
3508
|
onOpenAutoFocus: (e) => {
|
|
3509
|
+
if (hasRecent) {
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3317
3512
|
e.preventDefault();
|
|
3318
3513
|
inputRef.current?.focus();
|
|
3319
3514
|
},
|
|
3320
3515
|
children: [
|
|
3321
|
-
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
3516
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "shrink-0", children: [
|
|
3322
3517
|
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Find an existing message" }),
|
|
3323
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3324
|
-
/* @__PURE__ */ jsxRuntime.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.` }),
|
|
3325
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
3326
|
-
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3327
|
-
"button",
|
|
3328
|
-
{
|
|
3329
|
-
type: "button",
|
|
3330
|
-
"aria-label": "How to copy a message link",
|
|
3331
|
-
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",
|
|
3332
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3.5 w-3.5" })
|
|
3333
|
-
}
|
|
3334
|
-
) }),
|
|
3335
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { className: "max-w-xs leading-relaxed", children: [
|
|
3336
|
-
"In Slack, hover over the message and click the ",
|
|
3337
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "\u22EE More actions" }),
|
|
3338
|
-
" button (or right-click the message), then choose ",
|
|
3339
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Copy link" }),
|
|
3340
|
-
"."
|
|
3341
|
-
] })
|
|
3342
|
-
] })
|
|
3343
|
-
] })
|
|
3518
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: hasRecent ? "Pick a recent message your app posted, or paste a Slack message link. Preview it before loading." : `Paste a Slack message link (Slack's "Copy link") to preview it and load its blocks for editing.` })
|
|
3344
3519
|
] }),
|
|
3345
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
|
|
3346
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-
|
|
3347
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3348
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3349
|
-
|
|
3520
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "-mx-1 flex min-h-0 min-w-0 flex-1 flex-col gap-4 overflow-y-auto px-1 lg:flex-row lg:gap-5 lg:overflow-hidden", children: [
|
|
3521
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 shrink-0 flex-col gap-3 lg:min-h-0 lg:w-[19rem]", children: [
|
|
3522
|
+
hasRecent && /* @__PURE__ */ jsxRuntime.jsx(TabStrip, { activeTab, onSelect: setTab, tabDomId, panelDomId }),
|
|
3523
|
+
activeTab === "recent" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3524
|
+
"div",
|
|
3350
3525
|
{
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3526
|
+
...panelProps("recent"),
|
|
3527
|
+
className: "-mx-1 flex min-w-0 flex-col gap-2 px-1 lg:min-h-0 lg:flex-1 lg:overflow-hidden",
|
|
3528
|
+
children: [
|
|
3529
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-1.5", children: [
|
|
3530
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "recent-channel-picker", children: "Channel" }),
|
|
3531
|
+
channels === null && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading channels\u2026" }),
|
|
3532
|
+
channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: channelsError }),
|
|
3533
|
+
channels && channels.length === 0 && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No public channels available." }),
|
|
3534
|
+
channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3535
|
+
"select",
|
|
3536
|
+
{
|
|
3537
|
+
id: "recent-channel-picker",
|
|
3538
|
+
value: channelId,
|
|
3539
|
+
onChange: (e) => setChannelId(e.target.value),
|
|
3540
|
+
className: "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",
|
|
3541
|
+
children: [
|
|
3542
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select a channel\u2026" }),
|
|
3543
|
+
channels.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.id, children: [
|
|
3544
|
+
"#",
|
|
3545
|
+
c.name
|
|
3546
|
+
] }, c.id))
|
|
3547
|
+
]
|
|
3548
|
+
}
|
|
3549
|
+
)
|
|
3550
|
+
] }),
|
|
3551
|
+
!channelId && channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-muted-foreground", children: "Select a channel to see recent messages." }),
|
|
3552
|
+
channelId && recent === null && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-muted-foreground", children: "Loading recent messages\u2026" }),
|
|
3553
|
+
channelId && recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-destructive", children: recentError }),
|
|
3554
|
+
channelId && recent && recent.length === 0 && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-muted-foreground", children: "No recent messages from this app in this channel." }),
|
|
3555
|
+
channelId && recent && recent.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-h-60 min-h-0 min-w-0 flex-col gap-1 overflow-y-auto lg:max-h-none lg:flex-1", children: recent.map((m) => {
|
|
3556
|
+
const asUser = (m.editableVia ?? "bot") === "user";
|
|
3557
|
+
const authorName = m.username || (asUser ? "You" : "App bot");
|
|
3558
|
+
const safeIcon = isSafeImageSrc(m.iconUrl) ? m.iconUrl : void 0;
|
|
3559
|
+
const isSelected = selectedRecent?.channelId === m.channelId && selectedRecent?.ts === m.ts;
|
|
3560
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3561
|
+
"button",
|
|
3562
|
+
{
|
|
3563
|
+
type: "button",
|
|
3564
|
+
"aria-pressed": isSelected,
|
|
3565
|
+
onClick: () => {
|
|
3566
|
+
setSelectedRecent(m);
|
|
3567
|
+
},
|
|
3568
|
+
className: cn(
|
|
3569
|
+
// Inset rings so the scroll container's overflow clip
|
|
3570
|
+
// can't shave the corners off the selected outline.
|
|
3571
|
+
"flex min-w-0 items-start gap-2.5 rounded-md border border-input bg-background px-3 py-2 text-left hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
|
|
3572
|
+
isSelected && "border-primary! bg-accent ring-1 ring-inset ring-primary"
|
|
3573
|
+
),
|
|
3574
|
+
children: [
|
|
3575
|
+
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-9 w-9 shrink-0 rounded-md object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3576
|
+
"span",
|
|
3577
|
+
{
|
|
3578
|
+
"aria-hidden": true,
|
|
3579
|
+
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-muted text-sm font-semibold text-muted-foreground",
|
|
3580
|
+
children: authorName.charAt(0).toUpperCase()
|
|
3581
|
+
}
|
|
3582
|
+
),
|
|
3583
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
3584
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
3585
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-foreground", children: authorName }),
|
|
3586
|
+
/* @__PURE__ */ jsxRuntime.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" })
|
|
3587
|
+
] }),
|
|
3588
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3589
|
+
new Date(Number(m.ts) * 1e3).toLocaleString(),
|
|
3590
|
+
" ",
|
|
3591
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
|
|
3592
|
+
"(",
|
|
3593
|
+
m.ts,
|
|
3594
|
+
")"
|
|
3595
|
+
] })
|
|
3596
|
+
] }),
|
|
3597
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 text-sm text-foreground", children: previewText(m) })
|
|
3598
|
+
] })
|
|
3599
|
+
]
|
|
3600
|
+
},
|
|
3601
|
+
`${m.channelId}:${m.ts}`
|
|
3602
|
+
);
|
|
3603
|
+
}) })
|
|
3604
|
+
]
|
|
3605
|
+
}
|
|
3606
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3607
|
+
"div",
|
|
3608
|
+
{
|
|
3609
|
+
...panelProps("link"),
|
|
3610
|
+
className: "-mx-1 flex min-w-0 flex-col gap-2 px-1 lg:min-h-0 lg:flex-1 lg:overflow-y-auto",
|
|
3611
|
+
children: [
|
|
3612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
3613
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "message-link", children: "Message link" }),
|
|
3614
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3615
|
+
Input,
|
|
3616
|
+
{
|
|
3617
|
+
ref: inputRef,
|
|
3618
|
+
id: "message-link",
|
|
3619
|
+
value: link,
|
|
3620
|
+
onChange: (e) => {
|
|
3621
|
+
setLink(e.target.value);
|
|
3622
|
+
setEmptyLinkError(null);
|
|
3623
|
+
stopSignInPoll();
|
|
3624
|
+
},
|
|
3625
|
+
onKeyDown: (e) => {
|
|
3626
|
+
if (e.key === "Enter" && !committing) {
|
|
3627
|
+
e.preventDefault();
|
|
3628
|
+
handleLoad();
|
|
3629
|
+
}
|
|
3630
|
+
},
|
|
3631
|
+
placeholder: "https://your-workspace.slack.com/archives/C\u2026/p\u2026",
|
|
3632
|
+
autoComplete: "off",
|
|
3633
|
+
spellCheck: false
|
|
3634
|
+
}
|
|
3635
|
+
),
|
|
3636
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: LINK_HELP_TEXT })
|
|
3637
|
+
] }),
|
|
3638
|
+
emptyLinkError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: emptyLinkError })
|
|
3639
|
+
]
|
|
3371
3640
|
}
|
|
3372
3641
|
)
|
|
3373
3642
|
] }),
|
|
3374
|
-
|
|
3375
|
-
|
|
3643
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3644
|
+
PreviewPane,
|
|
3645
|
+
{
|
|
3646
|
+
state: preview,
|
|
3647
|
+
hooks: previewHooks,
|
|
3648
|
+
theme: previewTheme,
|
|
3649
|
+
emptyHint: activeTab === "recent" ? "Select a recent message to preview it here." : "Paste a message link to preview it here.",
|
|
3650
|
+
signInPolling,
|
|
3651
|
+
onSignIn: startFindSignIn,
|
|
3652
|
+
onOpenAsNew
|
|
3653
|
+
}
|
|
3654
|
+
)
|
|
3655
|
+
] }),
|
|
3656
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { className: "shrink-0", children: [
|
|
3657
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
3658
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", onClick: handleLoad, disabled: committing || !canLoad, children: committing ? "Loading\u2026" : "Load message" })
|
|
3659
|
+
] })
|
|
3660
|
+
]
|
|
3661
|
+
}
|
|
3662
|
+
) });
|
|
3663
|
+
}
|
|
3664
|
+
function TabStrip({
|
|
3665
|
+
activeTab,
|
|
3666
|
+
onSelect,
|
|
3667
|
+
tabDomId,
|
|
3668
|
+
panelDomId
|
|
3669
|
+
}) {
|
|
3670
|
+
const tabRefs = React.useRef({});
|
|
3671
|
+
const moveTo = (next) => {
|
|
3672
|
+
onSelect(next);
|
|
3673
|
+
tabRefs.current[next]?.focus();
|
|
3674
|
+
};
|
|
3675
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": "Message source", className: "flex shrink-0 gap-1 rounded-md bg-muted p-1", children: TABS.map((entry, index) => {
|
|
3676
|
+
const selected = entry.id === activeTab;
|
|
3677
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3678
|
+
"button",
|
|
3679
|
+
{
|
|
3680
|
+
ref: (node) => {
|
|
3681
|
+
tabRefs.current[entry.id] = node;
|
|
3682
|
+
},
|
|
3683
|
+
type: "button",
|
|
3684
|
+
role: "tab",
|
|
3685
|
+
id: tabDomId(entry.id),
|
|
3686
|
+
"aria-selected": selected,
|
|
3687
|
+
"aria-controls": panelDomId(entry.id),
|
|
3688
|
+
tabIndex: selected ? 0 : -1,
|
|
3689
|
+
onClick: () => onSelect(entry.id),
|
|
3690
|
+
onKeyDown: (e) => {
|
|
3691
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
3692
|
+
e.preventDefault();
|
|
3693
|
+
const delta = e.key === "ArrowRight" ? 1 : -1;
|
|
3694
|
+
moveTo(TABS[(index + delta + TABS.length) % TABS.length].id);
|
|
3695
|
+
} else if (e.key === "Home") {
|
|
3696
|
+
e.preventDefault();
|
|
3697
|
+
moveTo(TABS[0].id);
|
|
3698
|
+
} else if (e.key === "End") {
|
|
3699
|
+
e.preventDefault();
|
|
3700
|
+
moveTo(TABS[TABS.length - 1].id);
|
|
3701
|
+
}
|
|
3702
|
+
},
|
|
3703
|
+
className: cn(
|
|
3704
|
+
"flex-1 rounded-sm px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3705
|
+
selected ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
3706
|
+
),
|
|
3707
|
+
children: entry.label
|
|
3708
|
+
},
|
|
3709
|
+
entry.id
|
|
3710
|
+
);
|
|
3711
|
+
}) });
|
|
3712
|
+
}
|
|
3713
|
+
function PreviewPane({
|
|
3714
|
+
state,
|
|
3715
|
+
hooks,
|
|
3716
|
+
theme,
|
|
3717
|
+
emptyHint,
|
|
3718
|
+
signInPolling,
|
|
3719
|
+
onSignIn,
|
|
3720
|
+
onOpenAsNew
|
|
3721
|
+
}) {
|
|
3722
|
+
const target = state.kind === "ready" ? state.target : null;
|
|
3723
|
+
const signInUrl = state.kind === "not-editable" && state.oauthUrl && isSafeHref(state.oauthUrl) ? state.oauthUrl : null;
|
|
3724
|
+
const verdictBlocks = state.kind === "not-editable" ? state.blocks : void 0;
|
|
3725
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 shrink-0 flex-col gap-2 lg:min-h-0 lg:flex-1", children: [
|
|
3726
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: [
|
|
3727
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Preview" }),
|
|
3728
|
+
target?.channelName || target?.channelId ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded border px-1.5 py-px text-[10px] font-medium text-muted-foreground", children: target.channelName ? `#${target.channelName}` : target.channelId }) : null,
|
|
3729
|
+
target?.editableVia ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded border px-1.5 py-px text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: [
|
|
3730
|
+
"Editable as ",
|
|
3731
|
+
editableLabel(target.editableVia)
|
|
3732
|
+
] }) : null
|
|
3733
|
+
] }),
|
|
3734
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3735
|
+
"div",
|
|
3736
|
+
{
|
|
3737
|
+
role: "region",
|
|
3738
|
+
"aria-label": "Message preview",
|
|
3739
|
+
tabIndex: 0,
|
|
3740
|
+
className: "flex max-h-72 min-h-32 flex-1 flex-col gap-3 overflow-y-auto rounded-md border bg-muted/40 p-3 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring lg:max-h-none lg:min-h-0",
|
|
3741
|
+
children: [
|
|
3742
|
+
state.kind === "not-editable" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-2 rounded-md border border-amber-200! bg-amber-50 p-3 text-xs text-amber-800", children: [
|
|
3376
3743
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
|
|
3377
3744
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
|
|
3378
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children:
|
|
3745
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: state.reason })
|
|
3379
3746
|
] }),
|
|
3380
|
-
signInUrl && /* @__PURE__ */ jsxRuntime.jsx(SlackSignInButton, { onClick: () =>
|
|
3381
|
-
|
|
3747
|
+
signInUrl && /* @__PURE__ */ jsxRuntime.jsx(SlackSignInButton, { onClick: () => onSignIn(signInUrl), polling: signInPolling }),
|
|
3748
|
+
verdictBlocks && verdictBlocks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3382
3749
|
Button,
|
|
3383
3750
|
{
|
|
3384
3751
|
type: "button",
|
|
3385
3752
|
variant: "outline",
|
|
3386
3753
|
size: "sm",
|
|
3387
3754
|
className: "self-start",
|
|
3388
|
-
onClick: () => onOpenAsNew(
|
|
3755
|
+
onClick: () => onOpenAsNew(verdictBlocks),
|
|
3389
3756
|
children: "Open as a new message instead"
|
|
3390
3757
|
}
|
|
3391
3758
|
)
|
|
3392
3759
|
] }),
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
channels === null && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading channels\u2026" }),
|
|
3402
|
-
channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: channelsError }),
|
|
3403
|
-
channels && channels.length === 0 && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No public channels available." }),
|
|
3404
|
-
channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3405
|
-
"select",
|
|
3406
|
-
{
|
|
3407
|
-
id: "recent-channel-picker",
|
|
3408
|
-
value: channelId,
|
|
3409
|
-
onChange: (e) => setChannelId(e.target.value),
|
|
3410
|
-
className: "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",
|
|
3411
|
-
children: [
|
|
3412
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select a channel\u2026" }),
|
|
3413
|
-
channels.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.id, children: [
|
|
3414
|
-
"#",
|
|
3415
|
-
c.name
|
|
3416
|
-
] }, c.id))
|
|
3417
|
-
]
|
|
3418
|
-
}
|
|
3419
|
-
)
|
|
3420
|
-
] }),
|
|
3421
|
-
!channelId && channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Select a channel to see recent messages." }),
|
|
3422
|
-
channelId && recent === null && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading recent messages\u2026" }),
|
|
3423
|
-
channelId && recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: recentError }),
|
|
3424
|
-
channelId && recent && recent.length === 0 && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No recent messages from this app in this channel." }),
|
|
3425
|
-
channelId && recent && recent.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-h-48 min-w-0 flex-col gap-1 overflow-y-auto", children: recent.map((m) => {
|
|
3426
|
-
const asUser = (m.editableVia ?? "bot") === "user";
|
|
3427
|
-
const authorName = m.username || (asUser ? "You" : "App bot");
|
|
3428
|
-
const safeIcon = isSafeImageSrc(m.iconUrl) ? m.iconUrl : void 0;
|
|
3429
|
-
const isSelected = selectedRecent?.channelId === m.channelId && selectedRecent?.ts === m.ts;
|
|
3430
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3431
|
-
"button",
|
|
3432
|
-
{
|
|
3433
|
-
type: "button",
|
|
3434
|
-
"aria-pressed": isSelected,
|
|
3435
|
-
onClick: () => {
|
|
3436
|
-
setSelectedRecent(m);
|
|
3437
|
-
setLink("");
|
|
3438
|
-
if (status.kind !== "idle" && status.kind !== "loading") {
|
|
3439
|
-
setStatus({ kind: "idle" });
|
|
3440
|
-
}
|
|
3441
|
-
},
|
|
3442
|
-
className: cn(
|
|
3443
|
-
// Inset rings so the scroll container's overflow clip
|
|
3444
|
-
// can't shave the corners off the selected outline.
|
|
3445
|
-
"flex min-w-0 items-start gap-2.5 rounded-md border border-input bg-background px-3 py-2 text-left hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
|
|
3446
|
-
isSelected && "border-primary! bg-accent ring-1 ring-inset ring-primary"
|
|
3447
|
-
),
|
|
3448
|
-
children: [
|
|
3449
|
-
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-9 w-9 shrink-0 rounded-md object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3450
|
-
"span",
|
|
3451
|
-
{
|
|
3452
|
-
"aria-hidden": true,
|
|
3453
|
-
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-muted text-sm font-semibold text-muted-foreground",
|
|
3454
|
-
children: authorName.charAt(0).toUpperCase()
|
|
3455
|
-
}
|
|
3456
|
-
),
|
|
3457
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
3458
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
3459
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-foreground", children: authorName }),
|
|
3460
|
-
/* @__PURE__ */ jsxRuntime.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" })
|
|
3461
|
-
] }),
|
|
3462
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3463
|
-
new Date(Number(m.ts) * 1e3).toLocaleString(),
|
|
3464
|
-
" ",
|
|
3465
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
|
|
3466
|
-
"(",
|
|
3467
|
-
m.ts,
|
|
3468
|
-
")"
|
|
3469
|
-
] })
|
|
3470
|
-
] }),
|
|
3471
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 text-sm text-foreground", children: previewText(m) })
|
|
3472
|
-
] })
|
|
3473
|
-
]
|
|
3474
|
-
},
|
|
3475
|
-
`${m.channelId}:${m.ts}`
|
|
3476
|
-
);
|
|
3477
|
-
}) })
|
|
3478
|
-
] })
|
|
3479
|
-
] }),
|
|
3480
|
-
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
|
|
3481
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
3482
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3483
|
-
Button,
|
|
3760
|
+
state.kind === "error" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: state.error }),
|
|
3761
|
+
state.kind === "loading" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "m-auto flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
3762
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
3763
|
+
"Looking up that message\u2026"
|
|
3764
|
+
] }),
|
|
3765
|
+
state.kind === "empty" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-auto px-4 text-center text-sm text-muted-foreground", children: emptyHint }),
|
|
3766
|
+
target && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3767
|
+
SlackMessagePreview,
|
|
3484
3768
|
{
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3769
|
+
blocks: target.blocks,
|
|
3770
|
+
hooks,
|
|
3771
|
+
theme,
|
|
3772
|
+
workspaceName: target.workspaceName,
|
|
3773
|
+
authorName: target.username,
|
|
3774
|
+
authorIcon: target.iconUrl,
|
|
3775
|
+
time: formatTs(target.ts)
|
|
3489
3776
|
}
|
|
3490
|
-
)
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3777
|
+
) }),
|
|
3778
|
+
verdictBlocks && verdictBlocks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(SlackMessagePreview, { blocks: verdictBlocks, hooks, theme, time: "" }) })
|
|
3779
|
+
]
|
|
3780
|
+
}
|
|
3781
|
+
)
|
|
3782
|
+
] });
|
|
3495
3783
|
}
|
|
3496
3784
|
var PALETTE_DRAG_PREFIX = "palette:";
|
|
3497
3785
|
function parsePaletteDragId(id) {
|
|
@@ -5684,7 +5972,7 @@ function HeaderEditor({ block, onChange }) {
|
|
|
5684
5972
|
] })
|
|
5685
5973
|
}
|
|
5686
5974
|
),
|
|
5687
|
-
/* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Level", help: "Optional.
|
|
5975
|
+
/* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Level", help: "Optional. Sets the heading size Slack renders, from H1 (largest) to H4.", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5688
5976
|
RadioGroup,
|
|
5689
5977
|
{
|
|
5690
5978
|
value: level === void 0 ? "default" : String(level),
|
|
@@ -8714,60 +9002,6 @@ function dispatch(block, onChange) {
|
|
|
8714
9002
|
return null;
|
|
8715
9003
|
}
|
|
8716
9004
|
}
|
|
8717
|
-
function SlackBlockPreview({
|
|
8718
|
-
block,
|
|
8719
|
-
hooks,
|
|
8720
|
-
theme = "light"
|
|
8721
|
-
}) {
|
|
8722
|
-
const rootRef = React.useRef(null);
|
|
8723
|
-
const safeBlock = React.useMemo(() => sanitizeBlock(block), [block]);
|
|
8724
|
-
React.useEffect(() => {
|
|
8725
|
-
const root = rootRef.current;
|
|
8726
|
-
if (!root) return;
|
|
8727
|
-
for (const wrapper of root.querySelectorAll(
|
|
8728
|
-
".slack_blocks_to_jsx__image_media_trigger, .slack_blocks_to_jsx__video_title"
|
|
8729
|
-
)) {
|
|
8730
|
-
for (const btn of wrapper.querySelectorAll("button:not([aria-label])")) {
|
|
8731
|
-
const title = wrapper.querySelector(".slack_blocks_to_jsx__image_title")?.textContent?.trim();
|
|
8732
|
-
btn.setAttribute("aria-label", title ? `Toggle ${title}` : "Toggle media");
|
|
8733
|
-
}
|
|
8734
|
-
}
|
|
8735
|
-
for (const a of root.querySelectorAll("a[href]")) {
|
|
8736
|
-
const href = a.getAttribute("href");
|
|
8737
|
-
if (!isSafeHref(href)) {
|
|
8738
|
-
a.setAttribute("href", "#");
|
|
8739
|
-
a.setAttribute("data-bk-blocked-href", "1");
|
|
8740
|
-
}
|
|
8741
|
-
}
|
|
8742
|
-
for (const img of root.querySelectorAll("img[src]")) {
|
|
8743
|
-
const src = img.getAttribute("src");
|
|
8744
|
-
if (!isSafeImageSrc(src)) {
|
|
8745
|
-
img.removeAttribute("src");
|
|
8746
|
-
img.setAttribute("data-bk-blocked-src", "1");
|
|
8747
|
-
}
|
|
8748
|
-
}
|
|
8749
|
-
});
|
|
8750
|
-
return (
|
|
8751
|
-
// The library scopes all of its CSS under `#slack_blocks_to_jsx` and
|
|
8752
|
-
// depends on the `slack_blocks_to_jsx styles_enabled` classes plus the
|
|
8753
|
-
// `data-theme` attribute for its button / mention / divider styling
|
|
8754
|
-
// (e.g. button reset + `bg-green-primary` for primary). `<Message
|
|
8755
|
-
// withoutWrapper>` skips that wrapper entirely, so we re-create it
|
|
8756
|
-
// here without the avatar / timestamp chrome.
|
|
8757
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, id: "slack_blocks_to_jsx", "data-theme": theme, className: "slack_blocks_to_jsx styles_enabled", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8758
|
-
slackBlocksToJsx.Message,
|
|
8759
|
-
{
|
|
8760
|
-
time: /* @__PURE__ */ new Date(),
|
|
8761
|
-
name: "",
|
|
8762
|
-
logo: "",
|
|
8763
|
-
withoutWrapper: true,
|
|
8764
|
-
theme,
|
|
8765
|
-
blocks: [safeBlock],
|
|
8766
|
-
hooks
|
|
8767
|
-
}
|
|
8768
|
-
) })
|
|
8769
|
-
);
|
|
8770
|
-
}
|
|
8771
9005
|
var BLOCK_TYPE_LABELS = {
|
|
8772
9006
|
section: "Section",
|
|
8773
9007
|
header: "Header",
|
|
@@ -9390,50 +9624,16 @@ function Surface({
|
|
|
9390
9624
|
{
|
|
9391
9625
|
"aria-label": "Block preview",
|
|
9392
9626
|
className: cn("flex min-w-0 flex-1 flex-col overflow-y-auto bg-muted p-3 sm:p-6"),
|
|
9393
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
|
|
9403
|
-
}) {
|
|
9404
|
-
const displayName = authorName ?? workspaceName ?? "Your app";
|
|
9405
|
-
const initial = displayName.slice(0, 1).toUpperCase();
|
|
9406
|
-
const safeIcon = authorIcon && isSafeImageSrc(authorIcon) ? authorIcon : null;
|
|
9407
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9408
|
-
"div",
|
|
9409
|
-
{
|
|
9410
|
-
className: cn(
|
|
9411
|
-
"flex flex-col overflow-hidden rounded-md border",
|
|
9412
|
-
isDark ? "border-[#2c2d30] bg-[#1a1d21]" : "border-[#e8e8e8] bg-white"
|
|
9413
|
-
),
|
|
9414
|
-
children: [
|
|
9415
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9416
|
-
"div",
|
|
9417
|
-
{
|
|
9418
|
-
className: cn("flex items-center gap-2 px-5 pt-3 pb-1 text-xs", isDark ? "text-white/60" : "text-[#616061]"),
|
|
9419
|
-
children: [
|
|
9420
|
-
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-7 w-7 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9421
|
-
"span",
|
|
9422
|
-
{
|
|
9423
|
-
className: cn(
|
|
9424
|
-
"inline-flex h-7 w-7 items-center justify-center rounded text-[12px] font-semibold",
|
|
9425
|
-
isDark ? "bg-white/10 text-white" : "bg-[#4a154b]/10 text-[#1d1c1d]"
|
|
9426
|
-
),
|
|
9427
|
-
children: initial
|
|
9428
|
-
}
|
|
9429
|
-
),
|
|
9430
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold text-sm", isDark ? "text-white" : "text-[#1d1c1d]"), children: displayName }),
|
|
9431
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "10:37 AM" })
|
|
9432
|
-
]
|
|
9433
|
-
}
|
|
9434
|
-
),
|
|
9435
|
-
children
|
|
9436
|
-
]
|
|
9627
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9628
|
+
SlackMessageFrame,
|
|
9629
|
+
{
|
|
9630
|
+
workspaceName,
|
|
9631
|
+
authorName,
|
|
9632
|
+
authorIcon,
|
|
9633
|
+
isDark,
|
|
9634
|
+
children: blocksList
|
|
9635
|
+
}
|
|
9636
|
+
) })
|
|
9437
9637
|
}
|
|
9438
9638
|
);
|
|
9439
9639
|
}
|
|
@@ -10522,6 +10722,8 @@ function BlockKitchen(props) {
|
|
|
10522
10722
|
onLoadMessage: loading.onLoadMessage,
|
|
10523
10723
|
loadRecentMessages: loading.loadRecentMessages,
|
|
10524
10724
|
loadChannels: recentChannelSource,
|
|
10725
|
+
previewHooks: mergedPreviewHooks,
|
|
10726
|
+
previewTheme,
|
|
10525
10727
|
onLoaded: (result) => {
|
|
10526
10728
|
resetAll(result.blocks);
|
|
10527
10729
|
setEditTarget(toLoadedMessage(result));
|