@tightknitai/block-kitchen 0.9.9 → 0.9.10
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 +176 -5
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +108 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -3
- package/dist/index.d.ts +83 -3
- package/dist/index.js +108 -17
- package/dist/index.js.map +1 -1
- package/dist/{palette-CKP8CK5Z.d.cts → palette-Duj901T6.d.cts} +188 -27
- package/dist/{palette-CKP8CK5Z.d.ts → palette-Duj901T6.d.ts} +188 -27
- 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.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { c as BlockKitchenProps, Z as SupportedBlock, k as ChannelOption, V as SendAsUserStatus, X as SendPayload, W as SendExtrasContext, a5 as Template, Q as PreviewSurface, R as PreviewTheme } from './palette-Duj901T6.cjs';
|
|
4
|
+
export { A as AlertBlock, a as AlertLevel, B as BlockKitchenBaseProps, b as BlockKitchenComposeOnlyProps, d as BlockKitchenSendProps, e as BrandPreset, f as BrandTheme, g as BrandTokens, h as BuilderBlock, C as CardBlock, i as CarouselBlock, j as CartesianChart, l as Chart, m as ChartAxisConfig, n as ChartDataPoint, o as ChartSeries, p as ChartType, q as ContainerBlock, r as ContainerChildBlock, s as ContextActionsBlock, t as ContextActionsElement, u as CustomEmoji, D as DataVisualizationBlock, E as EditableVia, v as EditingConfig, F as FeedbackButtonSubobject, w as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, x as IconButtonIcon, y as InputBlock, L as LoadMessageInput, z as LoadResult, M as MarkdownBlock, P as PaletteSection, G as PaletteVariant, J as PieChart, K as PieChartSegment, N as PlanBlock, O as PreviewHooks, S as PrimaryActionConfig, T as PrimaryActionContext, U as RecentMessage, Y as SendResult, _ as SupportedBlockType, $ as SupportedHeaderBlock, a0 as TableBlock, a1 as TableCell, a2 as TableColumnSetting, a3 as TaskCardBlock, a4 as TaskCardStatus, a6 as UpdatePayload, a7 as UpdateResult, a8 as UrlSourceElement, a9 as ValidationSummary, aa as VideoBlock, ac as defaultPalette, ad as extraAlertVariant, ae as legacyInputVariants } from './palette-Duj901T6.cjs';
|
|
4
5
|
export { decodeBlocksFromString, encodeBlocksToString, toSlackBlocks } from './helpers.cjs';
|
|
5
6
|
import 'slack-web-api-client';
|
|
6
7
|
|
|
@@ -14,6 +15,85 @@ import 'slack-web-api-client';
|
|
|
14
15
|
*/
|
|
15
16
|
declare function BlockKitchen(props: BlockKitchenProps): react.JSX.Element;
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Props for {@link SendDialog}. Exported so hosts building a bespoke send
|
|
20
|
+
* flow (compose-only mode) can reuse the built-in dialog standalone instead
|
|
21
|
+
* of rebuilding channel loading, identity, and sending states from scratch.
|
|
22
|
+
*/
|
|
23
|
+
interface SendDialogProps {
|
|
24
|
+
/** Whether the dialog is open. */
|
|
25
|
+
open: boolean;
|
|
26
|
+
/** Notified when the user closes the dialog. */
|
|
27
|
+
onOpenChange: (open: boolean) => void;
|
|
28
|
+
/** The draft blocks to send (builder-native format). */
|
|
29
|
+
blocks: SupportedBlock[];
|
|
30
|
+
/** Returns channels available to send to. Called when the dialog opens. */
|
|
31
|
+
loadChannels: () => Promise<ChannelOption[]>;
|
|
32
|
+
/** Returns user-token status + OAuth URL. */
|
|
33
|
+
loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
|
|
34
|
+
/** Terminal action; should return `{ ok }` or `{ ok: false, error }`. */
|
|
35
|
+
onSend: (payload: SendPayload) => Promise<{
|
|
36
|
+
ok: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Renders host-defined fields below the built-in pickers; collected
|
|
41
|
+
* values are delivered on {@link SendPayload.extras}.
|
|
42
|
+
*/
|
|
43
|
+
renderSendExtras?: (context: SendExtrasContext) => ReactNode;
|
|
44
|
+
/** Label for the final confirm button. Defaults to `'Send'`. */
|
|
45
|
+
confirmSendLabel?: string;
|
|
46
|
+
/** Total validation errors against the current draft. */
|
|
47
|
+
errorCount: number;
|
|
48
|
+
/** Asks the parent to open the global issues panel. */
|
|
49
|
+
onShowIssues?: () => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Modal dialog that collects the destination channel + send-as identity
|
|
53
|
+
* (plus any host-defined extras), then calls the consumer's `onSend`.
|
|
54
|
+
*
|
|
55
|
+
* Channels and user-token status are loaded async via callback props on open.
|
|
56
|
+
* The consumer brokers all I/O; the dialog never makes a network call.
|
|
57
|
+
* @param props - {@link SendDialogProps}
|
|
58
|
+
* @returns the rendered send dialog
|
|
59
|
+
*/
|
|
60
|
+
declare function SendDialog({ open, onOpenChange, blocks, loadChannels, loadSendAsUserStatus, onSend, renderSendExtras, confirmSendLabel, errorCount, onShowIssues }: SendDialogProps): react.JSX.Element;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Tracks the "act as the user" Slack token status for a dialog and drives the
|
|
64
|
+
* OAuth sign-in flow. Shared by {@link SendDialog} and {@link UpdateDialog}.
|
|
65
|
+
*
|
|
66
|
+
* While `open && enabled` it fetches status on open and refreshes on window
|
|
67
|
+
* focus. Once `startSignIn` opens the OAuth tab it also background-polls until
|
|
68
|
+
* the token appears or the retry cap is hit, so the dialog unlocks itself
|
|
69
|
+
* without a manual reload. All work stops when the dialog closes, the token
|
|
70
|
+
* path doesn't apply, or the component unmounts.
|
|
71
|
+
*
|
|
72
|
+
* @param loadStatus - consumer callback returning user-token status + OAuth URL
|
|
73
|
+
* @param options.open - whether the host dialog is open
|
|
74
|
+
* @param options.enabled - whether the user-token path applies (idle when false)
|
|
75
|
+
* @returns `{ userStatus, polling, startSignIn }`
|
|
76
|
+
*/
|
|
77
|
+
declare function useSlackSignIn(loadStatus: () => Promise<SendAsUserStatus>, { open, enabled }: {
|
|
78
|
+
open: boolean;
|
|
79
|
+
enabled: boolean;
|
|
80
|
+
}): {
|
|
81
|
+
userStatus: SendAsUserStatus | null;
|
|
82
|
+
polling: boolean;
|
|
83
|
+
startSignIn: () => void;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* The "Sign in with Slack" button used by both dialogs. Opens OAuth and shows a
|
|
87
|
+
* spinner while {@link useSlackSignIn} polls for the completed round-trip. The
|
|
88
|
+
* surrounding explanatory copy stays with each caller since it differs.
|
|
89
|
+
* @param props.onClick - starts the sign-in flow (typically `startSignIn`)
|
|
90
|
+
* @param props.polling - whether a background poll is in flight
|
|
91
|
+
*/
|
|
92
|
+
declare function SlackSignInButton({ onClick, polling }: {
|
|
93
|
+
onClick: () => void;
|
|
94
|
+
polling: boolean;
|
|
95
|
+
}): react.JSX.Element;
|
|
96
|
+
|
|
17
97
|
/**
|
|
18
98
|
* Standalone, page-sized picker that displays {@link Template}s as a
|
|
19
99
|
* grid of cards with live block previews, organized into category
|
|
@@ -51,4 +131,4 @@ declare function TemplatePicker({ templates, onSelect, surface, theme, heading,
|
|
|
51
131
|
className?: string;
|
|
52
132
|
}): react.JSX.Element;
|
|
53
133
|
|
|
54
|
-
export { BlockKitchen, BlockKitchenProps, PreviewSurface, PreviewTheme, Template, TemplatePicker };
|
|
134
|
+
export { BlockKitchen, BlockKitchenProps, ChannelOption, PreviewSurface, PreviewTheme, SendAsUserStatus, SendDialog, type SendDialogProps, SendExtrasContext, SendPayload, SlackSignInButton, SupportedBlock, Template, TemplatePicker, useSlackSignIn };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { c as BlockKitchenProps, Z as SupportedBlock, k as ChannelOption, V as SendAsUserStatus, X as SendPayload, W as SendExtrasContext, a5 as Template, Q as PreviewSurface, R as PreviewTheme } from './palette-Duj901T6.js';
|
|
4
|
+
export { A as AlertBlock, a as AlertLevel, B as BlockKitchenBaseProps, b as BlockKitchenComposeOnlyProps, d as BlockKitchenSendProps, e as BrandPreset, f as BrandTheme, g as BrandTokens, h as BuilderBlock, C as CardBlock, i as CarouselBlock, j as CartesianChart, l as Chart, m as ChartAxisConfig, n as ChartDataPoint, o as ChartSeries, p as ChartType, q as ContainerBlock, r as ContainerChildBlock, s as ContextActionsBlock, t as ContextActionsElement, u as CustomEmoji, D as DataVisualizationBlock, E as EditableVia, v as EditingConfig, F as FeedbackButtonSubobject, w as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, x as IconButtonIcon, y as InputBlock, L as LoadMessageInput, z as LoadResult, M as MarkdownBlock, P as PaletteSection, G as PaletteVariant, J as PieChart, K as PieChartSegment, N as PlanBlock, O as PreviewHooks, S as PrimaryActionConfig, T as PrimaryActionContext, U as RecentMessage, Y as SendResult, _ as SupportedBlockType, $ as SupportedHeaderBlock, a0 as TableBlock, a1 as TableCell, a2 as TableColumnSetting, a3 as TaskCardBlock, a4 as TaskCardStatus, a6 as UpdatePayload, a7 as UpdateResult, a8 as UrlSourceElement, a9 as ValidationSummary, aa as VideoBlock, ac as defaultPalette, ad as extraAlertVariant, ae as legacyInputVariants } from './palette-Duj901T6.js';
|
|
4
5
|
export { decodeBlocksFromString, encodeBlocksToString, toSlackBlocks } from './helpers.js';
|
|
5
6
|
import 'slack-web-api-client';
|
|
6
7
|
|
|
@@ -14,6 +15,85 @@ import 'slack-web-api-client';
|
|
|
14
15
|
*/
|
|
15
16
|
declare function BlockKitchen(props: BlockKitchenProps): react.JSX.Element;
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Props for {@link SendDialog}. Exported so hosts building a bespoke send
|
|
20
|
+
* flow (compose-only mode) can reuse the built-in dialog standalone instead
|
|
21
|
+
* of rebuilding channel loading, identity, and sending states from scratch.
|
|
22
|
+
*/
|
|
23
|
+
interface SendDialogProps {
|
|
24
|
+
/** Whether the dialog is open. */
|
|
25
|
+
open: boolean;
|
|
26
|
+
/** Notified when the user closes the dialog. */
|
|
27
|
+
onOpenChange: (open: boolean) => void;
|
|
28
|
+
/** The draft blocks to send (builder-native format). */
|
|
29
|
+
blocks: SupportedBlock[];
|
|
30
|
+
/** Returns channels available to send to. Called when the dialog opens. */
|
|
31
|
+
loadChannels: () => Promise<ChannelOption[]>;
|
|
32
|
+
/** Returns user-token status + OAuth URL. */
|
|
33
|
+
loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
|
|
34
|
+
/** Terminal action; should return `{ ok }` or `{ ok: false, error }`. */
|
|
35
|
+
onSend: (payload: SendPayload) => Promise<{
|
|
36
|
+
ok: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Renders host-defined fields below the built-in pickers; collected
|
|
41
|
+
* values are delivered on {@link SendPayload.extras}.
|
|
42
|
+
*/
|
|
43
|
+
renderSendExtras?: (context: SendExtrasContext) => ReactNode;
|
|
44
|
+
/** Label for the final confirm button. Defaults to `'Send'`. */
|
|
45
|
+
confirmSendLabel?: string;
|
|
46
|
+
/** Total validation errors against the current draft. */
|
|
47
|
+
errorCount: number;
|
|
48
|
+
/** Asks the parent to open the global issues panel. */
|
|
49
|
+
onShowIssues?: () => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Modal dialog that collects the destination channel + send-as identity
|
|
53
|
+
* (plus any host-defined extras), then calls the consumer's `onSend`.
|
|
54
|
+
*
|
|
55
|
+
* Channels and user-token status are loaded async via callback props on open.
|
|
56
|
+
* The consumer brokers all I/O; the dialog never makes a network call.
|
|
57
|
+
* @param props - {@link SendDialogProps}
|
|
58
|
+
* @returns the rendered send dialog
|
|
59
|
+
*/
|
|
60
|
+
declare function SendDialog({ open, onOpenChange, blocks, loadChannels, loadSendAsUserStatus, onSend, renderSendExtras, confirmSendLabel, errorCount, onShowIssues }: SendDialogProps): react.JSX.Element;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Tracks the "act as the user" Slack token status for a dialog and drives the
|
|
64
|
+
* OAuth sign-in flow. Shared by {@link SendDialog} and {@link UpdateDialog}.
|
|
65
|
+
*
|
|
66
|
+
* While `open && enabled` it fetches status on open and refreshes on window
|
|
67
|
+
* focus. Once `startSignIn` opens the OAuth tab it also background-polls until
|
|
68
|
+
* the token appears or the retry cap is hit, so the dialog unlocks itself
|
|
69
|
+
* without a manual reload. All work stops when the dialog closes, the token
|
|
70
|
+
* path doesn't apply, or the component unmounts.
|
|
71
|
+
*
|
|
72
|
+
* @param loadStatus - consumer callback returning user-token status + OAuth URL
|
|
73
|
+
* @param options.open - whether the host dialog is open
|
|
74
|
+
* @param options.enabled - whether the user-token path applies (idle when false)
|
|
75
|
+
* @returns `{ userStatus, polling, startSignIn }`
|
|
76
|
+
*/
|
|
77
|
+
declare function useSlackSignIn(loadStatus: () => Promise<SendAsUserStatus>, { open, enabled }: {
|
|
78
|
+
open: boolean;
|
|
79
|
+
enabled: boolean;
|
|
80
|
+
}): {
|
|
81
|
+
userStatus: SendAsUserStatus | null;
|
|
82
|
+
polling: boolean;
|
|
83
|
+
startSignIn: () => void;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* The "Sign in with Slack" button used by both dialogs. Opens OAuth and shows a
|
|
87
|
+
* spinner while {@link useSlackSignIn} polls for the completed round-trip. The
|
|
88
|
+
* surrounding explanatory copy stays with each caller since it differs.
|
|
89
|
+
* @param props.onClick - starts the sign-in flow (typically `startSignIn`)
|
|
90
|
+
* @param props.polling - whether a background poll is in flight
|
|
91
|
+
*/
|
|
92
|
+
declare function SlackSignInButton({ onClick, polling }: {
|
|
93
|
+
onClick: () => void;
|
|
94
|
+
polling: boolean;
|
|
95
|
+
}): react.JSX.Element;
|
|
96
|
+
|
|
17
97
|
/**
|
|
18
98
|
* Standalone, page-sized picker that displays {@link Template}s as a
|
|
19
99
|
* grid of cards with live block previews, organized into category
|
|
@@ -51,4 +131,4 @@ declare function TemplatePicker({ templates, onSelect, surface, theme, heading,
|
|
|
51
131
|
className?: string;
|
|
52
132
|
}): react.JSX.Element;
|
|
53
133
|
|
|
54
|
-
export { BlockKitchen, BlockKitchenProps, PreviewSurface, PreviewTheme, Template, TemplatePicker };
|
|
134
|
+
export { BlockKitchen, BlockKitchenProps, ChannelOption, PreviewSurface, PreviewTheme, SendAsUserStatus, SendDialog, type SendDialogProps, SendExtrasContext, SendPayload, SlackSignInButton, SupportedBlock, Template, TemplatePicker, useSlackSignIn };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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, MailSearch, Plus, ChevronDown, BookOpen,
|
|
3
|
+
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, ChartColumnBig, Container, Loader2, ExternalLink, AlertTriangle, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, MailSearch, Plus, ChevronDown, BookOpen, Trash2, Code2, Pencil, Send, Search, Check, Copy, Info, CheckCircle2, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, 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
|
-
import { createContext,
|
|
5
|
+
import { createContext, useState, useRef, useEffect, useCallback, useMemo, useId, useContext } from 'react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
8
8
|
import { clsx } from 'clsx';
|
|
@@ -2015,6 +2015,7 @@ function computeValidation(blocks, surface) {
|
|
|
2015
2015
|
const grouped = groupValidatorErrors(result.errors, blocks);
|
|
2016
2016
|
return {
|
|
2017
2017
|
valid: result.valid,
|
|
2018
|
+
errors: result.errors,
|
|
2018
2019
|
byBlockId: grouped.byBlockId,
|
|
2019
2020
|
general: grouped.general,
|
|
2020
2021
|
total: grouped.total
|
|
@@ -3532,6 +3533,7 @@ function SendDialog({
|
|
|
3532
3533
|
loadChannels,
|
|
3533
3534
|
loadSendAsUserStatus,
|
|
3534
3535
|
onSend,
|
|
3536
|
+
renderSendExtras,
|
|
3535
3537
|
confirmSendLabel = "Send",
|
|
3536
3538
|
errorCount,
|
|
3537
3539
|
onShowIssues
|
|
@@ -3541,6 +3543,10 @@ function SendDialog({
|
|
|
3541
3543
|
const [channelId, setChannelId] = useState("");
|
|
3542
3544
|
const [sendAs, setSendAs] = useState("bot");
|
|
3543
3545
|
const [status, setStatus] = useState({ kind: "idle" });
|
|
3546
|
+
const [extras, setExtrasState] = useState({});
|
|
3547
|
+
const setExtras = useCallback((patch) => {
|
|
3548
|
+
setExtrasState((prev) => ({ ...prev, ...patch }));
|
|
3549
|
+
}, []);
|
|
3544
3550
|
const { userStatus, polling, startSignIn } = useSlackSignIn(loadSendAsUserStatus, { open, enabled: true });
|
|
3545
3551
|
const loadChannelsRef = useRef(loadChannels);
|
|
3546
3552
|
useEffect(() => {
|
|
@@ -3555,6 +3561,7 @@ function SendDialog({
|
|
|
3555
3561
|
setChannelsError(null);
|
|
3556
3562
|
setChannelId("");
|
|
3557
3563
|
setSendAs("bot");
|
|
3564
|
+
setExtrasState({});
|
|
3558
3565
|
let cancelled = false;
|
|
3559
3566
|
loadChannelsRef.current().then((list) => {
|
|
3560
3567
|
if (cancelled) {
|
|
@@ -3582,7 +3589,10 @@ function SendDialog({
|
|
|
3582
3589
|
const result = await onSend({
|
|
3583
3590
|
channelId,
|
|
3584
3591
|
blocks: toSlackBlocks(blocks),
|
|
3585
|
-
sendAsUser: sendAs === "user"
|
|
3592
|
+
sendAsUser: sendAs === "user",
|
|
3593
|
+
// Only introduce the key when the extras slot is wired, so existing
|
|
3594
|
+
// consumers never see a new payload field.
|
|
3595
|
+
...renderSendExtras ? { extras } : {}
|
|
3586
3596
|
});
|
|
3587
3597
|
if (result.ok) {
|
|
3588
3598
|
setStatus({ kind: "idle" });
|
|
@@ -3649,6 +3659,12 @@ function SendDialog({
|
|
|
3649
3659
|
}
|
|
3650
3660
|
)
|
|
3651
3661
|
] }),
|
|
3662
|
+
renderSendExtras ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5", children: renderSendExtras({
|
|
3663
|
+
channelId: channelId || null,
|
|
3664
|
+
sendAsUser: sendAs === "user",
|
|
3665
|
+
extras,
|
|
3666
|
+
setExtras
|
|
3667
|
+
}) }) : null,
|
|
3652
3668
|
errorCount > 0 ? /* @__PURE__ */ jsxs(
|
|
3653
3669
|
"button",
|
|
3654
3670
|
{
|
|
@@ -9395,6 +9411,8 @@ function Toolbar2({
|
|
|
9395
9411
|
showThemeControl = true,
|
|
9396
9412
|
docsLink,
|
|
9397
9413
|
errorCount,
|
|
9414
|
+
showSend = true,
|
|
9415
|
+
primaryAction,
|
|
9398
9416
|
sendButtonLabel = "Review & send",
|
|
9399
9417
|
editingEnabled = false,
|
|
9400
9418
|
editBadge,
|
|
@@ -9529,7 +9547,24 @@ function Toolbar2({
|
|
|
9529
9547
|
/* @__PURE__ */ jsx(Code2, { className: "h-3.5 w-3.5" }),
|
|
9530
9548
|
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: "View JSON" })
|
|
9531
9549
|
] }),
|
|
9532
|
-
|
|
9550
|
+
!showSend ? primaryAction ? (
|
|
9551
|
+
// Compose-only mode with a host-owned primary action: same
|
|
9552
|
+
// placement and styling as the built-in send button. No icon —
|
|
9553
|
+
// the action's meaning is the host's, so the label always shows
|
|
9554
|
+
// (the send button can collapse to its icon on small screens;
|
|
9555
|
+
// an icon-less button can't).
|
|
9556
|
+
/* @__PURE__ */ jsx(
|
|
9557
|
+
Button,
|
|
9558
|
+
{
|
|
9559
|
+
type: "button",
|
|
9560
|
+
size: "sm",
|
|
9561
|
+
onClick: primaryAction.onClick,
|
|
9562
|
+
disabled: primaryAction.disabled,
|
|
9563
|
+
"aria-label": primaryAction.label,
|
|
9564
|
+
children: /* @__PURE__ */ jsx("span", { children: primaryAction.label })
|
|
9565
|
+
}
|
|
9566
|
+
)
|
|
9567
|
+
) : null : editBadge ? (
|
|
9533
9568
|
// A message is loaded: split button. Main action updates it in
|
|
9534
9569
|
// place; the menu also offers posting the blocks as a new message.
|
|
9535
9570
|
/* @__PURE__ */ jsxs("div", { className: "flex items-stretch", children: [
|
|
@@ -9772,12 +9807,15 @@ function BlockKitchen(props) {
|
|
|
9772
9807
|
workspaceName,
|
|
9773
9808
|
initialBlocks,
|
|
9774
9809
|
onChange,
|
|
9810
|
+
onValidationChange,
|
|
9775
9811
|
previewHooks,
|
|
9776
9812
|
customEmojis,
|
|
9777
9813
|
loadChannels,
|
|
9778
9814
|
loadSendAsUserStatus,
|
|
9779
9815
|
onSend,
|
|
9816
|
+
renderSendExtras,
|
|
9780
9817
|
editing,
|
|
9818
|
+
primaryAction,
|
|
9781
9819
|
loadButtonLabel,
|
|
9782
9820
|
updateButtonLabel,
|
|
9783
9821
|
confirmUpdateLabel,
|
|
@@ -9794,6 +9832,13 @@ function BlockKitchen(props) {
|
|
|
9794
9832
|
sendButtonLabel,
|
|
9795
9833
|
confirmSendLabel,
|
|
9796
9834
|
theme
|
|
9835
|
+
// Widen the all-or-nothing union so the branch-specific props
|
|
9836
|
+
// destructure as independent optionals: untyped JS consumers can still
|
|
9837
|
+
// pass partial wiring (handled by the runtime guards below), and the
|
|
9838
|
+
// correlated-union narrowing would otherwise flag those guards as
|
|
9839
|
+
// "always true". `primaryAction` is pulled from the compose-only branch
|
|
9840
|
+
// (where it carries a real type) rather than the send branch's
|
|
9841
|
+
// `undefined` pin, which would collapse the intersection to `undefined`.
|
|
9797
9842
|
} = props;
|
|
9798
9843
|
const paletteSections = useMemo(() => {
|
|
9799
9844
|
const sections = palette ?? defaultPalette;
|
|
@@ -9812,13 +9857,36 @@ function BlockKitchen(props) {
|
|
|
9812
9857
|
}, [palette, disabledBlockTypes]);
|
|
9813
9858
|
const variantById = useMemo(() => buildVariantById(paletteSections), [paletteSections]);
|
|
9814
9859
|
const allowedSurfaces = allowedSurfacesProp && allowedSurfacesProp.length > 0 ? allowedSurfacesProp : ["message"];
|
|
9815
|
-
const
|
|
9860
|
+
const sendEnabled = Boolean(loadChannels && loadSendAsUserStatus && onSend);
|
|
9861
|
+
const editingConfig = sendEnabled ? editing : void 0;
|
|
9862
|
+
const seededBlocks = editingConfig?.initialTarget?.blocks ?? initialBlocks;
|
|
9816
9863
|
useEffect(() => {
|
|
9817
|
-
if (
|
|
9864
|
+
if (editingConfig?.initialTarget && initialBlocks) {
|
|
9818
9865
|
console.warn(
|
|
9819
9866
|
"[BlockKitchen] Both `initialBlocks` and `editing.initialTarget` were provided; using the target\u2019s blocks and ignoring `initialBlocks`."
|
|
9820
9867
|
);
|
|
9821
9868
|
}
|
|
9869
|
+
const sendPropsProvided = [loadChannels, loadSendAsUserStatus, onSend].filter(Boolean).length;
|
|
9870
|
+
if (sendPropsProvided > 0 && sendPropsProvided < 3) {
|
|
9871
|
+
console.warn(
|
|
9872
|
+
"[BlockKitchen] Partial send wiring: `loadChannels`, `loadSendAsUserStatus`, and `onSend` are all-or-nothing. The send button is hidden until all three are provided."
|
|
9873
|
+
);
|
|
9874
|
+
}
|
|
9875
|
+
if (editing && !sendEnabled) {
|
|
9876
|
+
console.warn(
|
|
9877
|
+
"[BlockKitchen] `editing` requires the send integration (`loadChannels`, `loadSendAsUserStatus`, `onSend`); ignoring `editing`."
|
|
9878
|
+
);
|
|
9879
|
+
}
|
|
9880
|
+
if (renderSendExtras && !sendEnabled) {
|
|
9881
|
+
console.warn(
|
|
9882
|
+
"[BlockKitchen] `renderSendExtras` extends the built-in send dialog, which requires the send integration (`loadChannels`, `loadSendAsUserStatus`, `onSend`); ignoring `renderSendExtras`."
|
|
9883
|
+
);
|
|
9884
|
+
}
|
|
9885
|
+
if (primaryAction && sendEnabled) {
|
|
9886
|
+
console.warn(
|
|
9887
|
+
"[BlockKitchen] `primaryAction` is only available in compose-only mode \u2014 with the send integration wired, the built-in Send/Update flow owns the toolbar\u2019s primary action; ignoring `primaryAction`."
|
|
9888
|
+
);
|
|
9889
|
+
}
|
|
9822
9890
|
}, []);
|
|
9823
9891
|
const { blocks, addBlock, addChild, updateBlock, removeBlock, duplicateBlock, reorderBlock, moveBlock, replaceAll } = useBlockKitchenState({ initialBlocks: seededBlocks, onChange });
|
|
9824
9892
|
const childParentById = useMemo(() => {
|
|
@@ -9836,8 +9904,8 @@ function BlockKitchen(props) {
|
|
|
9836
9904
|
const [sendOpen, setSendOpen] = useState(false);
|
|
9837
9905
|
const [updateOpen, setUpdateOpen] = useState(false);
|
|
9838
9906
|
const [loadOpen, setLoadOpen] = useState(false);
|
|
9839
|
-
const [editTarget, setEditTarget] = useState(() =>
|
|
9840
|
-
const activeEditTarget =
|
|
9907
|
+
const [editTarget, setEditTarget] = useState(() => editingConfig?.initialTarget ?? null);
|
|
9908
|
+
const activeEditTarget = editingConfig ? editTarget : null;
|
|
9841
9909
|
const [issuesOpen, setIssuesOpen] = useState(false);
|
|
9842
9910
|
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
9843
9911
|
const [openBlockId, setOpenBlockId] = useState(null);
|
|
@@ -9855,6 +9923,22 @@ function BlockKitchen(props) {
|
|
|
9855
9923
|
return { emoji: makeEmojiHook(byName), ...previewHooks };
|
|
9856
9924
|
}, [customEmojis, previewHooks]);
|
|
9857
9925
|
const validation = useBlockKitValidation(blocks, "message");
|
|
9926
|
+
const validationSummary = useMemo(
|
|
9927
|
+
() => ({ valid: validation.valid, errorCount: validation.total, errors: validation.errors }),
|
|
9928
|
+
[validation]
|
|
9929
|
+
);
|
|
9930
|
+
const lastNotifiedValidationRef = useRef(null);
|
|
9931
|
+
useEffect(() => {
|
|
9932
|
+
if (!onValidationChange) {
|
|
9933
|
+
return;
|
|
9934
|
+
}
|
|
9935
|
+
const key = JSON.stringify([validationSummary.valid, validationSummary.errorCount, ...validationSummary.errors]);
|
|
9936
|
+
if (lastNotifiedValidationRef.current === key) {
|
|
9937
|
+
return;
|
|
9938
|
+
}
|
|
9939
|
+
lastNotifiedValidationRef.current = key;
|
|
9940
|
+
onValidationChange(validationSummary);
|
|
9941
|
+
}, [validationSummary, onValidationChange]);
|
|
9858
9942
|
const sensors = useSensors(
|
|
9859
9943
|
useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
|
|
9860
9944
|
useSensor(TouchSensor, { activationConstraint: { delay: 150, tolerance: 8 } }),
|
|
@@ -9958,8 +10042,14 @@ function BlockKitchen(props) {
|
|
|
9958
10042
|
allowedSurfaces,
|
|
9959
10043
|
showThemeControl: isPreviewThemeControlled ? false : showThemeControl,
|
|
9960
10044
|
docsLink,
|
|
10045
|
+
showSend: sendEnabled,
|
|
10046
|
+
primaryAction: !sendEnabled && primaryAction ? {
|
|
10047
|
+
label: primaryAction.label,
|
|
10048
|
+
onClick: () => primaryAction.onClick({ blocks: blockPayloads, validation: validationSummary }),
|
|
10049
|
+
disabled: primaryAction.disableWhenInvalid ? !validationSummary.valid : false
|
|
10050
|
+
} : null,
|
|
9961
10051
|
sendButtonLabel,
|
|
9962
|
-
editingEnabled: !!
|
|
10052
|
+
editingEnabled: !!editingConfig,
|
|
9963
10053
|
editBadge: activeEditTarget ? {
|
|
9964
10054
|
channelLabel: activeEditTarget.channelName ? `#${activeEditTarget.channelName}` : activeEditTarget.channelId,
|
|
9965
10055
|
ts: activeEditTarget.ts
|
|
@@ -10041,7 +10131,7 @@ function BlockKitchen(props) {
|
|
|
10041
10131
|
}
|
|
10042
10132
|
) }),
|
|
10043
10133
|
/* @__PURE__ */ jsx(JsonDrawer, { open: jsonOpen, onOpenChange: setJsonOpen, blocks: blockPayloads, onApply: replaceAll }),
|
|
10044
|
-
/* @__PURE__ */ jsx(
|
|
10134
|
+
loadChannels && loadSendAsUserStatus && onSend ? /* @__PURE__ */ jsx(
|
|
10045
10135
|
SendDialog,
|
|
10046
10136
|
{
|
|
10047
10137
|
open: sendOpen,
|
|
@@ -10050,6 +10140,7 @@ function BlockKitchen(props) {
|
|
|
10050
10140
|
loadChannels,
|
|
10051
10141
|
loadSendAsUserStatus,
|
|
10052
10142
|
onSend,
|
|
10143
|
+
renderSendExtras,
|
|
10053
10144
|
confirmSendLabel,
|
|
10054
10145
|
errorCount: validation.total,
|
|
10055
10146
|
onShowIssues: () => {
|
|
@@ -10057,8 +10148,8 @@ function BlockKitchen(props) {
|
|
|
10057
10148
|
setIssuesOpen(true);
|
|
10058
10149
|
}
|
|
10059
10150
|
}
|
|
10060
|
-
),
|
|
10061
|
-
activeEditTarget &&
|
|
10151
|
+
) : null,
|
|
10152
|
+
activeEditTarget && editingConfig && loadSendAsUserStatus ? /* @__PURE__ */ jsx(
|
|
10062
10153
|
UpdateDialog,
|
|
10063
10154
|
{
|
|
10064
10155
|
open: updateOpen,
|
|
@@ -10066,7 +10157,7 @@ function BlockKitchen(props) {
|
|
|
10066
10157
|
target: activeEditTarget,
|
|
10067
10158
|
blocks: blockPayloads,
|
|
10068
10159
|
loadSendAsUserStatus,
|
|
10069
|
-
onUpdate:
|
|
10160
|
+
onUpdate: editingConfig.onUpdate,
|
|
10070
10161
|
confirmUpdateLabel,
|
|
10071
10162
|
errorCount: validation.total,
|
|
10072
10163
|
onShowIssues: () => {
|
|
@@ -10075,13 +10166,13 @@ function BlockKitchen(props) {
|
|
|
10075
10166
|
}
|
|
10076
10167
|
}
|
|
10077
10168
|
) : null,
|
|
10078
|
-
|
|
10169
|
+
editingConfig && loadChannels ? /* @__PURE__ */ jsx(
|
|
10079
10170
|
LoadMessageDialog,
|
|
10080
10171
|
{
|
|
10081
10172
|
open: loadOpen,
|
|
10082
10173
|
onOpenChange: setLoadOpen,
|
|
10083
|
-
onLoadMessage:
|
|
10084
|
-
loadRecentMessages:
|
|
10174
|
+
onLoadMessage: editingConfig.onLoadMessage,
|
|
10175
|
+
loadRecentMessages: editingConfig.loadRecentMessages,
|
|
10085
10176
|
loadChannels,
|
|
10086
10177
|
onLoaded: (result) => {
|
|
10087
10178
|
replaceAll(result.blocks);
|
|
@@ -10275,6 +10366,6 @@ function fromBase64Url(b64url) {
|
|
|
10275
10366
|
return b64 + "=".repeat(padLen);
|
|
10276
10367
|
}
|
|
10277
10368
|
|
|
10278
|
-
export { BlockKitchen, TemplatePicker, decodeBlocksFromString, defaultPalette, encodeBlocksToString, extraAlertVariant, legacyInputVariants, toSlackBlocks };
|
|
10369
|
+
export { BlockKitchen, SendDialog, SlackSignInButton, TemplatePicker, decodeBlocksFromString, defaultPalette, encodeBlocksToString, extraAlertVariant, legacyInputVariants, toSlackBlocks, useSlackSignIn };
|
|
10279
10370
|
//# sourceMappingURL=index.js.map
|
|
10280
10371
|
//# sourceMappingURL=index.js.map
|