@tightknitai/block-kitchen 0.6.1-alpha.0 → 0.8.2
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 +122 -3
- package/dist/helpers.cjs +171 -0
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.cts +38 -0
- package/dist/helpers.d.ts +38 -0
- package/dist/helpers.js +167 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.cjs +1374 -422
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -610
- package/dist/index.d.ts +6 -610
- package/dist/index.js +1312 -360
- package/dist/index.js.map +1 -1
- package/dist/palette-CTUROcUC.d.cts +674 -0
- package/dist/palette-CTUROcUC.d.ts +674 -0
- package/dist/palette.cjs +1386 -0
- package/dist/palette.cjs.map +1 -0
- package/dist/palette.d.cts +3 -0
- package/dist/palette.d.ts +3 -0
- package/dist/palette.js +1381 -0
- package/dist/palette.js.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +51 -31
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
import { ComponentType, SVGProps } from 'react';
|
|
2
|
+
import { SectionBlock, HeaderBlock, DividerBlock, ContextBlock, ActionsBlock, ImageBlock, RichTextBlock, ImageElement, Button, ViewInputBlock } from 'slack-web-api-client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Brand theme resolver for the BlockKitchen chrome.
|
|
6
|
+
*
|
|
7
|
+
* Consumers can already brand the builder by overriding the shadcn/ui
|
|
8
|
+
* CSS custom properties declared in `styles.src.css` (the lower-level
|
|
9
|
+
* contract). This module wraps that contract in a typed, ergonomic prop
|
|
10
|
+
* — a preset name and/or a `Partial<BrandTokens>` map — and resolves it
|
|
11
|
+
* to the `cssVarName -> value` pairs that `BrandThemeScope` then writes
|
|
12
|
+
* to a scoped `<style>` block around the builder.
|
|
13
|
+
*
|
|
14
|
+
* Scope is intentionally limited to the builder chrome. The Slack
|
|
15
|
+
* preview is rendered by `slack-blocks-to-jsx` under its own
|
|
16
|
+
* `#slack_blocks_to_jsx` CSS namespace and does not consume these vars,
|
|
17
|
+
* so brand tokens never leak into Slack content rendering.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Tokens consumers may override. Mirrors the shadcn/ui token set
|
|
21
|
+
* already defined in `src/styles.src.css`. Color values are HSL
|
|
22
|
+
* component strings ("231.7 48.6% 54.1%") — matching the existing
|
|
23
|
+
* `hsl(var(--token, ...))` contract. `radius` takes a CSS length
|
|
24
|
+
* such as `"0.5rem"`.
|
|
25
|
+
*/
|
|
26
|
+
type BrandTokens = Partial<{
|
|
27
|
+
background: string;
|
|
28
|
+
foreground: string;
|
|
29
|
+
card: string;
|
|
30
|
+
cardForeground: string;
|
|
31
|
+
popover: string;
|
|
32
|
+
popoverForeground: string;
|
|
33
|
+
primary: string;
|
|
34
|
+
primaryForeground: string;
|
|
35
|
+
secondary: string;
|
|
36
|
+
secondaryForeground: string;
|
|
37
|
+
muted: string;
|
|
38
|
+
mutedForeground: string;
|
|
39
|
+
accent: string;
|
|
40
|
+
accentForeground: string;
|
|
41
|
+
destructive: string;
|
|
42
|
+
destructiveForeground: string;
|
|
43
|
+
border: string;
|
|
44
|
+
input: string;
|
|
45
|
+
ring: string;
|
|
46
|
+
radius: string;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Curated preset names. `'default'` is a no-op (relies on the
|
|
50
|
+
* `styles.src.css` fallbacks). The other entries each define their own
|
|
51
|
+
* color palette and `radius`, demonstrating that brand presets can vary
|
|
52
|
+
* stylistic axes beyond color. Adding more later is non-breaking —
|
|
53
|
+
* extend the string union and add an entry to `PRESETS`.
|
|
54
|
+
*/
|
|
55
|
+
type BrandPreset = 'default' | 'slack' | 'ocean' | 'sunset' | 'mono' | 'cyberpunk';
|
|
56
|
+
/**
|
|
57
|
+
* Brand theme shape.
|
|
58
|
+
*
|
|
59
|
+
* - `preset` seeds the token map (currently a no-op for `'default'`).
|
|
60
|
+
* - `tokens` applies in both light and dark.
|
|
61
|
+
* - `light`/`dark` apply only when the matching dark-mode class is
|
|
62
|
+
* present on an ancestor (or on the scope itself).
|
|
63
|
+
*
|
|
64
|
+
* Merge precedence (later wins): preset → tokens → light/dark.
|
|
65
|
+
*/
|
|
66
|
+
interface BrandTheme {
|
|
67
|
+
preset?: BrandPreset;
|
|
68
|
+
tokens?: BrandTokens;
|
|
69
|
+
light?: BrandTokens;
|
|
70
|
+
dark?: BrandTokens;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* One pre-built block example shown as a draggable item in the palette.
|
|
75
|
+
* Modeled on Slack's real Block Kit Builder ("All selects", "Datepickers",
|
|
76
|
+
* "Filtered conversation", etc).
|
|
77
|
+
*/
|
|
78
|
+
interface PaletteVariant {
|
|
79
|
+
/** Stable id used as the DnD draggable id (`palette:${id}`). */
|
|
80
|
+
id: string;
|
|
81
|
+
/** Visible label shown next to the `+` icon. */
|
|
82
|
+
label: string;
|
|
83
|
+
/** Builds a fresh block payload when this variant is dropped. */
|
|
84
|
+
factory: () => SupportedBlock;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* One section in the palette. Sections group related variants under a
|
|
88
|
+
* single heading + icon, matching Slack's Block Kit Builder sidebar
|
|
89
|
+
* (Agents, Markdown, Section, Actions, Input, Structure, Rich Text,
|
|
90
|
+
* Image, Card and Carousel, Table).
|
|
91
|
+
*
|
|
92
|
+
* Variant ids must be unique across the entire palette — the drag-drop
|
|
93
|
+
* variant lookup keys by id, so a duplicate would shadow the earlier one.
|
|
94
|
+
*/
|
|
95
|
+
interface PaletteSection {
|
|
96
|
+
/** Visible heading for the section. */
|
|
97
|
+
name: string;
|
|
98
|
+
/** Lucide icon component rendered next to the section heading. */
|
|
99
|
+
icon: ComponentType<SVGProps<SVGSVGElement>>;
|
|
100
|
+
variants: PaletteVariant[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The built-in palette. Mirrors Slack's real Block Kit Builder: related
|
|
104
|
+
* variants (e.g. every select type) are combined into single showcase
|
|
105
|
+
* `actions` blocks ("All selects", "Datepickers") rather than each
|
|
106
|
+
* variant being its own row. The full set of single-element `input`
|
|
107
|
+
* variants is still available via {@link legacyInputVariants}.
|
|
108
|
+
*/
|
|
109
|
+
declare const defaultPalette: readonly PaletteSection[];
|
|
110
|
+
/**
|
|
111
|
+
* The single-element `input`-block variants that used to ship in
|
|
112
|
+
* `defaultPalette` before it was consolidated to mirror Slack's Block
|
|
113
|
+
* Kit Builder. Kept reachable so consumers who referenced these ids via
|
|
114
|
+
* the `palette` prop can spread them back into a custom palette.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```tsx
|
|
118
|
+
* import { defaultPalette, legacyInputVariants } from '@tightknitai/block-kitchen';
|
|
119
|
+
* import { TextCursorInput } from 'lucide-react';
|
|
120
|
+
*
|
|
121
|
+
* const palette = [
|
|
122
|
+
* ...defaultPalette,
|
|
123
|
+
* { name: 'All inputs', icon: TextCursorInput, variants: [...legacyInputVariants] }
|
|
124
|
+
* ];
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* Note: some ids here (`input_plain_text`, `input_date`, etc.) collide
|
|
128
|
+
* with curated ids in the new `defaultPalette`. `buildVariantById`
|
|
129
|
+
* keeps the last entry for a given id, so spread `legacyInputVariants`
|
|
130
|
+
* after `defaultPalette` to use the legacy factory.
|
|
131
|
+
*/
|
|
132
|
+
declare const legacyInputVariants: readonly PaletteVariant[];
|
|
133
|
+
/**
|
|
134
|
+
* Standalone `alert` block variant. The full set of severity-level alert
|
|
135
|
+
* variants ships in `defaultPalette` under the "Alert" section; this
|
|
136
|
+
* export is retained for backward compatibility with consumers who
|
|
137
|
+
* previously spread it onto a custom palette. Shares the `alert_warning`
|
|
138
|
+
* id with its counterpart in `defaultPalette` — spread after
|
|
139
|
+
* `defaultPalette` (or omit it entirely) to avoid duplicate-id lookups.
|
|
140
|
+
*/
|
|
141
|
+
declare const extraAlertVariant: PaletteVariant;
|
|
142
|
+
/**
|
|
143
|
+
* Builds a lookup table mapping a variant id to its definition for a
|
|
144
|
+
* resolved palette. Used by the DnD drop handler to resolve a
|
|
145
|
+
* `palette:${id}` drag back to a factory.
|
|
146
|
+
* @param sections - the palette in use (defaults or a consumer-provided one)
|
|
147
|
+
* @returns a map keyed by variant id
|
|
148
|
+
*/
|
|
149
|
+
declare function buildVariantById(sections: readonly PaletteSection[]): ReadonlyMap<string, PaletteVariant>;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The Slack Block Kit block types supported by the builder in v1.
|
|
153
|
+
*/
|
|
154
|
+
type SupportedBlockType = 'section' | 'header' | 'divider' | 'context' | 'actions' | 'image' | 'markdown' | 'rich_text' | 'table' | 'alert' | 'card' | 'carousel' | 'context_actions' | 'input' | 'video' | 'plan' | 'task_card';
|
|
155
|
+
/**
|
|
156
|
+
* Slack `markdown` block payload. Renders standard markdown (GFM)
|
|
157
|
+
* via `slack-blocks-to-jsx`'s react-markdown integration.
|
|
158
|
+
* `slack-web-api-client` doesn't ship this type yet, so we declare
|
|
159
|
+
* the minimal shape ourselves.
|
|
160
|
+
*/
|
|
161
|
+
interface MarkdownBlock {
|
|
162
|
+
type: 'markdown';
|
|
163
|
+
text: string;
|
|
164
|
+
block_id?: string;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* One cell in a {@link TableBlock} row. Slack accepts either a raw text
|
|
168
|
+
* cell or a rich-text cell; the visual editor only emits raw text in v1
|
|
169
|
+
* but preserves rich-text cells on edit.
|
|
170
|
+
*/
|
|
171
|
+
type TableCell = {
|
|
172
|
+
type: 'raw_text';
|
|
173
|
+
text: string;
|
|
174
|
+
} | {
|
|
175
|
+
type: 'rich_text';
|
|
176
|
+
elements: unknown[];
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* Per-column setting in a {@link TableBlock}. May be null to skip a
|
|
180
|
+
* column. Matches Slack's `table_column_setting` schema.
|
|
181
|
+
*/
|
|
182
|
+
type TableColumnSetting = null | {
|
|
183
|
+
align?: 'left' | 'center' | 'right';
|
|
184
|
+
is_wrapped?: boolean;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Slack `table` block payload. Up to 100 rows, 20 cells per row.
|
|
188
|
+
* `slack-web-api-client` doesn't ship this type, so we declare it.
|
|
189
|
+
*/
|
|
190
|
+
interface TableBlock {
|
|
191
|
+
type: 'table';
|
|
192
|
+
rows: TableCell[][];
|
|
193
|
+
column_settings?: TableColumnSetting[];
|
|
194
|
+
block_id?: string;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Severity level for an {@link AlertBlock}. Controls the icon and color
|
|
198
|
+
* accent rendered by Slack. Defaults to `default` when omitted.
|
|
199
|
+
*/
|
|
200
|
+
type AlertLevel = 'default' | 'info' | 'warning' | 'error' | 'success';
|
|
201
|
+
/**
|
|
202
|
+
* Slack `alert` block payload. Single-line status notification with an
|
|
203
|
+
* optional severity level. Per Slack's surface compatibility rules, alert
|
|
204
|
+
* blocks render on modal surfaces only (not messages or home tabs).
|
|
205
|
+
* `slack-web-api-client` doesn't ship this type yet, so we declare it.
|
|
206
|
+
*/
|
|
207
|
+
interface AlertBlock {
|
|
208
|
+
type: 'alert';
|
|
209
|
+
text: {
|
|
210
|
+
type: 'plain_text' | 'mrkdwn';
|
|
211
|
+
text: string;
|
|
212
|
+
emoji?: boolean;
|
|
213
|
+
verbatim?: boolean;
|
|
214
|
+
};
|
|
215
|
+
level?: AlertLevel;
|
|
216
|
+
block_id?: string;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Slack `card` block payload. Renders a media-rich card with optional
|
|
220
|
+
* hero image, icon, title, subtitle, body, and action buttons. At least
|
|
221
|
+
* one of `hero_image`, `title`, `actions`, or `body` is required.
|
|
222
|
+
* `slack-web-api-client` doesn't ship this type yet, so we declare it.
|
|
223
|
+
*/
|
|
224
|
+
interface CardBlock {
|
|
225
|
+
type: 'card';
|
|
226
|
+
block_id?: string;
|
|
227
|
+
hero_image?: ImageElement;
|
|
228
|
+
icon?: ImageElement;
|
|
229
|
+
title?: {
|
|
230
|
+
type: 'plain_text' | 'mrkdwn';
|
|
231
|
+
text: string;
|
|
232
|
+
emoji?: boolean;
|
|
233
|
+
verbatim?: boolean;
|
|
234
|
+
};
|
|
235
|
+
subtitle?: {
|
|
236
|
+
type: 'plain_text' | 'mrkdwn';
|
|
237
|
+
text: string;
|
|
238
|
+
emoji?: boolean;
|
|
239
|
+
verbatim?: boolean;
|
|
240
|
+
};
|
|
241
|
+
body?: {
|
|
242
|
+
type: 'plain_text' | 'mrkdwn';
|
|
243
|
+
text: string;
|
|
244
|
+
emoji?: boolean;
|
|
245
|
+
verbatim?: boolean;
|
|
246
|
+
};
|
|
247
|
+
actions?: Button[];
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Slack `carousel` block payload. A horizontally scrollable group of
|
|
251
|
+
* 1-10 {@link CardBlock} elements. `slack-web-api-client` doesn't ship
|
|
252
|
+
* this type yet, so we declare it.
|
|
253
|
+
*/
|
|
254
|
+
interface CarouselBlock {
|
|
255
|
+
type: 'carousel';
|
|
256
|
+
elements: CardBlock[];
|
|
257
|
+
block_id?: string;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Sub-button used inside a {@link FeedbackButtonsElement}.
|
|
261
|
+
*/
|
|
262
|
+
interface FeedbackButtonSubobject {
|
|
263
|
+
text: {
|
|
264
|
+
type: 'plain_text';
|
|
265
|
+
text: string;
|
|
266
|
+
emoji?: boolean;
|
|
267
|
+
};
|
|
268
|
+
value: string;
|
|
269
|
+
accessibility_label?: string;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* `feedback_buttons` element. Pair of positive/negative buttons used
|
|
273
|
+
* inside a {@link ContextActionsBlock} (e.g. "Good Response" / "Bad
|
|
274
|
+
* Response" thumbs).
|
|
275
|
+
*/
|
|
276
|
+
interface FeedbackButtonsElement {
|
|
277
|
+
type: 'feedback_buttons';
|
|
278
|
+
positive_button: FeedbackButtonSubobject;
|
|
279
|
+
negative_button: FeedbackButtonSubobject;
|
|
280
|
+
action_id?: string;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Slack icon names valid on an {@link IconButtonElement}. Slack only
|
|
284
|
+
* ships `trash` today; widen as Slack adds more.
|
|
285
|
+
*/
|
|
286
|
+
type IconButtonIcon = 'trash';
|
|
287
|
+
/**
|
|
288
|
+
* `icon_button` element. Compact icon-with-label button used inside a
|
|
289
|
+
* {@link ContextActionsBlock} (e.g. a "Remove" trash-icon button).
|
|
290
|
+
*/
|
|
291
|
+
interface IconButtonElement {
|
|
292
|
+
type: 'icon_button';
|
|
293
|
+
icon: IconButtonIcon;
|
|
294
|
+
text: {
|
|
295
|
+
type: 'plain_text';
|
|
296
|
+
text: string;
|
|
297
|
+
emoji?: boolean;
|
|
298
|
+
};
|
|
299
|
+
action_id?: string;
|
|
300
|
+
value?: string;
|
|
301
|
+
accessibility_label?: string;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Element accepted by a {@link ContextActionsBlock}.
|
|
305
|
+
*/
|
|
306
|
+
type ContextActionsElement = FeedbackButtonsElement | IconButtonElement;
|
|
307
|
+
/**
|
|
308
|
+
* Slack `context_actions` block payload. Renders a row of contextual
|
|
309
|
+
* action buttons (1-5 elements) attached to a message. Only valid on
|
|
310
|
+
* the message surface; the validator already encodes that.
|
|
311
|
+
* `slack-web-api-client` doesn't ship this type yet, so we declare it.
|
|
312
|
+
*/
|
|
313
|
+
interface ContextActionsBlock {
|
|
314
|
+
type: 'context_actions';
|
|
315
|
+
elements: ContextActionsElement[];
|
|
316
|
+
block_id?: string;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Slack `input` block payload. Aliased to `ViewInputBlock` from
|
|
320
|
+
* `slack-web-api-client`, which is the superset that accepts every
|
|
321
|
+
* supported input element (including `rich_text_input` and `file_input`).
|
|
322
|
+
* Surface compatibility (input is valid on modal and home tab; some
|
|
323
|
+
* elements are modal-only) is enforced by the validator, not the type.
|
|
324
|
+
*/
|
|
325
|
+
type InputBlock = ViewInputBlock;
|
|
326
|
+
/**
|
|
327
|
+
* Slack `video` block payload. Renders an embedded video player with
|
|
328
|
+
* thumbnail, title, optional description, and provider metadata. Sending
|
|
329
|
+
* requires the `links.embed:write` OAuth scope and `video_url` to live in
|
|
330
|
+
* the app's configured unfurl domains. `slack-web-api-client` doesn't ship
|
|
331
|
+
* this type yet, so we declare it.
|
|
332
|
+
*/
|
|
333
|
+
interface VideoBlock {
|
|
334
|
+
type: 'video';
|
|
335
|
+
alt_text: string;
|
|
336
|
+
title: {
|
|
337
|
+
type: 'plain_text';
|
|
338
|
+
text: string;
|
|
339
|
+
emoji?: boolean;
|
|
340
|
+
};
|
|
341
|
+
thumbnail_url: string;
|
|
342
|
+
video_url: string;
|
|
343
|
+
author_name?: string;
|
|
344
|
+
description?: {
|
|
345
|
+
type: 'plain_text';
|
|
346
|
+
text: string;
|
|
347
|
+
emoji?: boolean;
|
|
348
|
+
};
|
|
349
|
+
provider_icon_url?: string;
|
|
350
|
+
provider_name?: string;
|
|
351
|
+
title_url?: string;
|
|
352
|
+
block_id?: string;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Status of a {@link TaskCardBlock} as shown by Slack. `pending`,
|
|
356
|
+
* `in_progress`, and `complete` render distinct status chips; `error`
|
|
357
|
+
* renders a failure state.
|
|
358
|
+
*/
|
|
359
|
+
type TaskCardStatus = 'pending' | 'in_progress' | 'complete' | 'error';
|
|
360
|
+
/**
|
|
361
|
+
* URL source attached to a {@link TaskCardBlock}. Rendered as a labeled
|
|
362
|
+
* link below the task body so agents can cite which document, ticket, or
|
|
363
|
+
* page their step consulted.
|
|
364
|
+
*/
|
|
365
|
+
interface UrlSourceElement {
|
|
366
|
+
type: 'url';
|
|
367
|
+
url: string;
|
|
368
|
+
text: string;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Slack `task_card` block payload. Renders an agent-facing card showing a
|
|
372
|
+
* tracked task with optional details (rich text), output (rich text), and
|
|
373
|
+
* cited sources. Valid on message surfaces only.
|
|
374
|
+
* `slack-web-api-client` doesn't ship this type yet, so we declare it.
|
|
375
|
+
*/
|
|
376
|
+
interface TaskCardBlock {
|
|
377
|
+
type: 'task_card';
|
|
378
|
+
task_id: string;
|
|
379
|
+
title: string;
|
|
380
|
+
details?: RichTextBlock;
|
|
381
|
+
output?: RichTextBlock;
|
|
382
|
+
sources?: UrlSourceElement[];
|
|
383
|
+
status?: TaskCardStatus;
|
|
384
|
+
block_id?: string;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Slack `plan` block payload. Renders a titled checklist of tasks an
|
|
388
|
+
* agent is executing. Each task is an inline {@link TaskCardBlock}.
|
|
389
|
+
* Valid on message surfaces only. `slack-web-api-client` doesn't ship
|
|
390
|
+
* this type yet, so we declare it.
|
|
391
|
+
*/
|
|
392
|
+
interface PlanBlock {
|
|
393
|
+
type: 'plan';
|
|
394
|
+
title: string | {
|
|
395
|
+
type: 'plain_text';
|
|
396
|
+
text: string;
|
|
397
|
+
emoji?: boolean;
|
|
398
|
+
};
|
|
399
|
+
tasks?: TaskCardBlock[];
|
|
400
|
+
block_id?: string;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Header heading level shown in the preview. Slack's API has no
|
|
404
|
+
* `level` field on header blocks, so this is a builder-only extension
|
|
405
|
+
* that round-trips on the block payload but is otherwise cosmetic.
|
|
406
|
+
*/
|
|
407
|
+
type HeaderLevel = 1 | 2 | 3 | 4;
|
|
408
|
+
/**
|
|
409
|
+
* Header block as edited by the builder. Extends Slack's HeaderBlock
|
|
410
|
+
* with an optional {@link HeaderLevel}.
|
|
411
|
+
*/
|
|
412
|
+
type SupportedHeaderBlock = HeaderBlock & {
|
|
413
|
+
level?: HeaderLevel;
|
|
414
|
+
};
|
|
415
|
+
/**
|
|
416
|
+
* Discriminated union of supported block payload shapes.
|
|
417
|
+
* Subset of {@link AnyMessageBlock} from `slack-web-api-client`,
|
|
418
|
+
* plus a header `level` extension.
|
|
419
|
+
*/
|
|
420
|
+
type SupportedBlock = SectionBlock | SupportedHeaderBlock | DividerBlock | ContextBlock | ActionsBlock | ImageBlock | MarkdownBlock | RichTextBlock | TableBlock | AlertBlock | CardBlock | CarouselBlock | ContextActionsBlock | InputBlock | VideoBlock | PlanBlock | TaskCardBlock;
|
|
421
|
+
/**
|
|
422
|
+
* A block as represented inside the builder's working state.
|
|
423
|
+
* `id` is an ephemeral client-side identifier used by DnD and selection.
|
|
424
|
+
* It is stripped before serialization to Slack.
|
|
425
|
+
*/
|
|
426
|
+
interface BuilderBlock {
|
|
427
|
+
id: string;
|
|
428
|
+
block: SupportedBlock;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Channel record returned by {@link BlockKitchenProps.loadChannels}.
|
|
432
|
+
*/
|
|
433
|
+
interface ChannelOption {
|
|
434
|
+
id: string;
|
|
435
|
+
name: string;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* User-token status returned by {@link BlockKitchenProps.loadSendAsUserStatus}.
|
|
439
|
+
* If `canSendAsUser` is false, `oauthUrl` is required so the UI can show a
|
|
440
|
+
* "Sign in with Slack" link.
|
|
441
|
+
*/
|
|
442
|
+
interface SendAsUserStatus {
|
|
443
|
+
canSendAsUser: boolean;
|
|
444
|
+
oauthUrl?: string;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Payload passed to {@link BlockKitchenProps.onSend}.
|
|
448
|
+
*/
|
|
449
|
+
interface SendPayload {
|
|
450
|
+
channelId: string;
|
|
451
|
+
blocks: SupportedBlock[];
|
|
452
|
+
sendAsUser: boolean;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Result returned from {@link BlockKitchenProps.onSend}.
|
|
456
|
+
* `error` is a human-readable message; the dialog renders it as-is.
|
|
457
|
+
*/
|
|
458
|
+
interface SendResult {
|
|
459
|
+
ok: boolean;
|
|
460
|
+
error?: string;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Hooks forwarded to `slack-blocks-to-jsx`'s `<Message>` so the consumer can
|
|
464
|
+
* resolve user mentions, channel mentions, custom emojis, and links to
|
|
465
|
+
* application-specific UI. See the upstream library for the full hook shape.
|
|
466
|
+
* Marked as `unknown`-keyed at this layer to avoid leaking the upstream
|
|
467
|
+
* library's internal types into our public API.
|
|
468
|
+
*/
|
|
469
|
+
type PreviewHooks = Record<string, unknown>;
|
|
470
|
+
/**
|
|
471
|
+
* Light or dark theme for the rendered Slack preview. Wired to
|
|
472
|
+
* `slack-blocks-to-jsx`'s `theme` prop and `data-theme` attribute.
|
|
473
|
+
*/
|
|
474
|
+
type PreviewTheme = 'light' | 'dark';
|
|
475
|
+
/**
|
|
476
|
+
* Which Slack surface the preview is approximating. Affects the
|
|
477
|
+
* chrome rendered around the block list (message header, modal frame,
|
|
478
|
+
* or app home tab).
|
|
479
|
+
*/
|
|
480
|
+
type PreviewSurface = 'message' | 'modal' | 'app_home';
|
|
481
|
+
/**
|
|
482
|
+
* A reusable block layout the user can apply as a starting point.
|
|
483
|
+
* Consumed by the standalone `<TemplatePicker>` component, which renders
|
|
484
|
+
* a categorized grid of template cards (modeled on Slack's own Block
|
|
485
|
+
* Kit Builder templates page) and emits the selected one. The picker
|
|
486
|
+
* is decoupled from {@link BlockKitchen} — wire `onSelect` to whatever
|
|
487
|
+
* state owns the draft blocks (e.g. lift `initialBlocks` into your own
|
|
488
|
+
* state and reset it from the handler).
|
|
489
|
+
*/
|
|
490
|
+
interface Template {
|
|
491
|
+
/** Stable identifier used as the React key and for persistence. */
|
|
492
|
+
id: string;
|
|
493
|
+
/** Display name shown on the template card. */
|
|
494
|
+
name: string;
|
|
495
|
+
/** Optional one-line description shown under the name on the card. */
|
|
496
|
+
description?: string;
|
|
497
|
+
/**
|
|
498
|
+
* Which Slack surface this template was authored for. The picker can
|
|
499
|
+
* filter to a single surface via its `surface` prop; the field is also
|
|
500
|
+
* available to consumers who render templates in their own UI.
|
|
501
|
+
*/
|
|
502
|
+
surface: PreviewSurface;
|
|
503
|
+
/**
|
|
504
|
+
* Optional category name used to group templates into sections in the
|
|
505
|
+
* picker (e.g. `"Approvals"`, `"Notifications"`, `"Onboarding"`).
|
|
506
|
+
* Templates without a category fall into a trailing "Other" section
|
|
507
|
+
* when at least one other template specifies one; otherwise the grid
|
|
508
|
+
* is rendered flat without section headers.
|
|
509
|
+
*/
|
|
510
|
+
category?: string;
|
|
511
|
+
/** Block payloads applied to the draft when the template is selected. */
|
|
512
|
+
blocks: SupportedBlock[];
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Props for the top-level {@link BlockKitchen} component.
|
|
516
|
+
* The package is integration-agnostic: every I/O concern is brokered
|
|
517
|
+
* through these props. The component never makes a network call itself.
|
|
518
|
+
*/
|
|
519
|
+
interface BlockKitchenProps {
|
|
520
|
+
/**
|
|
521
|
+
* Workspace name shown in the preview chrome to mimic a Slack message header.
|
|
522
|
+
* Cosmetic only.
|
|
523
|
+
*/
|
|
524
|
+
workspaceName?: string;
|
|
525
|
+
/**
|
|
526
|
+
* Initial draft blocks. If omitted the builder starts empty.
|
|
527
|
+
*/
|
|
528
|
+
initialBlocks?: SupportedBlock[];
|
|
529
|
+
/**
|
|
530
|
+
* Fires whenever the draft state changes. Use to persist the draft
|
|
531
|
+
* (URL search param, localStorage, etc).
|
|
532
|
+
*/
|
|
533
|
+
onChange?: (blocks: SupportedBlock[]) => void;
|
|
534
|
+
/**
|
|
535
|
+
* Optional hooks forwarded to the underlying `<Message>` component for
|
|
536
|
+
* resolving user / channel / emoji directives. If omitted, those
|
|
537
|
+
* directives render with the library's defaults.
|
|
538
|
+
*/
|
|
539
|
+
previewHooks?: PreviewHooks;
|
|
540
|
+
/**
|
|
541
|
+
* Returns channels available to send to. Called when the send dialog opens.
|
|
542
|
+
*/
|
|
543
|
+
loadChannels: () => Promise<ChannelOption[]>;
|
|
544
|
+
/**
|
|
545
|
+
* Returns whether the current user can post as themselves and, if not, an
|
|
546
|
+
* OAuth URL to start the install flow.
|
|
547
|
+
*/
|
|
548
|
+
loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
|
|
549
|
+
/**
|
|
550
|
+
* Called when the user submits the send dialog. Should return
|
|
551
|
+
* `{ ok: true }` on success or `{ ok: false, error }` on failure.
|
|
552
|
+
*/
|
|
553
|
+
onSend: (payload: SendPayload) => Promise<SendResult>;
|
|
554
|
+
/**
|
|
555
|
+
* The palette shown on the left-hand side. When omitted, the built-in
|
|
556
|
+
* `defaultPalette` is used. Pass a custom array (typically built by
|
|
557
|
+
* spreading and filtering `defaultPalette`, plus your own sections) to
|
|
558
|
+
* curate the variants and pre-configured presets your users can drag
|
|
559
|
+
* onto the surface. An empty array renders an empty palette.
|
|
560
|
+
*
|
|
561
|
+
* The `defaultPalette` mirrors Slack's Block Kit Builder, which
|
|
562
|
+
* consolidates related variants into single showcase entries (e.g.
|
|
563
|
+
* **All selects** is one `actions` block with every select type). If
|
|
564
|
+
* you previously relied on the long flat list of single-element
|
|
565
|
+
* `input` variants (`input_users_select`, `input_multi_users_select`,
|
|
566
|
+
* `input_radio_buttons`, etc.), import `legacyInputVariants` and
|
|
567
|
+
* spread them into a custom section.
|
|
568
|
+
*
|
|
569
|
+
* Variant ids must be unique across the array — the drag-drop lookup
|
|
570
|
+
* keys by id, so duplicates would shadow each other. The palette is
|
|
571
|
+
* also expected to be referentially stable across renders (wrap in
|
|
572
|
+
* `useMemo` or define at module scope).
|
|
573
|
+
*/
|
|
574
|
+
palette?: readonly PaletteSection[];
|
|
575
|
+
/**
|
|
576
|
+
* Block types to hide from the palette without rebuilding it. Each
|
|
577
|
+
* palette section is keyed by a `blockType`; any section whose
|
|
578
|
+
* `blockType` matches an entry here is filtered out before render.
|
|
579
|
+
* Convenient when you want the default palette minus a few block
|
|
580
|
+
* types (e.g. `disabledBlockTypes: ['image', 'table']` for a
|
|
581
|
+
* text-only builder). For finer-grained control (filtering
|
|
582
|
+
* individual variants, reordering, or adding custom presets), pass
|
|
583
|
+
* a custom `palette` array instead.
|
|
584
|
+
*/
|
|
585
|
+
disabledBlockTypes?: readonly SupportedBlockType[];
|
|
586
|
+
/**
|
|
587
|
+
* Whether the palette renders a quick-search input above the section
|
|
588
|
+
* list. Defaults to `true`. Set `false` for compact palettes (e.g.
|
|
589
|
+
* when you've passed a small custom `palette`) where scanning by eye
|
|
590
|
+
* is faster than typing.
|
|
591
|
+
*/
|
|
592
|
+
showPaletteSearch?: boolean;
|
|
593
|
+
/**
|
|
594
|
+
* Placeholder text for the palette search input. Defaults to
|
|
595
|
+
* `'Search blocks…'`. Useful for localization.
|
|
596
|
+
*/
|
|
597
|
+
paletteSearchPlaceholder?: string;
|
|
598
|
+
/**
|
|
599
|
+
* Controls which palette section headers are expanded on first paint.
|
|
600
|
+
* - `true` (default) — every section starts open
|
|
601
|
+
* - `false` — every section starts closed (Slack-style)
|
|
602
|
+
* - array of section names — only sections whose `name` is in the
|
|
603
|
+
* list start open (e.g. `['Section', 'Actions']`); matched
|
|
604
|
+
* case-sensitively against `PaletteSection.name` so consumer-defined
|
|
605
|
+
* sections are addressable too.
|
|
606
|
+
*
|
|
607
|
+
* After mount, each section owns its own collapse state, so users can
|
|
608
|
+
* still toggle headers freely. An active palette search overrides the
|
|
609
|
+
* collapse state for matching sections.
|
|
610
|
+
*/
|
|
611
|
+
defaultOpenSections?: boolean | readonly string[];
|
|
612
|
+
/**
|
|
613
|
+
* Which Slack preview surfaces the toolbar exposes. Defaults to
|
|
614
|
+
* `['message']`, which locks the preview to Message and hides the
|
|
615
|
+
* surface dropdown. Pass two or more to show the dropdown with those
|
|
616
|
+
* options; the first entry becomes the initial selection.
|
|
617
|
+
*/
|
|
618
|
+
allowedSurfaces?: readonly PreviewSurface[];
|
|
619
|
+
/**
|
|
620
|
+
* Whether the toolbar exposes the light/dark theme dropdown.
|
|
621
|
+
* Defaults to `true`. When `false`, the theme is locked to
|
|
622
|
+
* {@link PreviewTheme} `'light'`.
|
|
623
|
+
*/
|
|
624
|
+
showThemeControl?: boolean;
|
|
625
|
+
/**
|
|
626
|
+
* Customizes or hides the "Docs" link in the toolbar.
|
|
627
|
+
* - `undefined` (default) — links to the Slack Block Kit reference docs
|
|
628
|
+
* - `false` — hides the link entirely
|
|
629
|
+
* - `{ href }` — overrides the URL (label defaults to `'Docs'`)
|
|
630
|
+
* - `{ href, label }` — overrides both
|
|
631
|
+
*
|
|
632
|
+
* Useful when embedding Block Kitchen inside a product that ships its
|
|
633
|
+
* own documentation, or for localizing the label.
|
|
634
|
+
*/
|
|
635
|
+
docsLink?: false | {
|
|
636
|
+
href?: string;
|
|
637
|
+
label?: string;
|
|
638
|
+
};
|
|
639
|
+
/**
|
|
640
|
+
* Initial preview theme. Defaults to `'light'`. Pass the host app's
|
|
641
|
+
* current theme (e.g. from `next-themes` or your own theme hook) so
|
|
642
|
+
* the preview opens matched to the consuming app's appearance. The
|
|
643
|
+
* user can still override via the toolbar dropdown if
|
|
644
|
+
* {@link BlockKitchenProps.showThemeControl} is `true`.
|
|
645
|
+
*/
|
|
646
|
+
defaultPreviewTheme?: PreviewTheme;
|
|
647
|
+
/**
|
|
648
|
+
* Branding tokens applied to the builder chrome (toolbar, palette,
|
|
649
|
+
* popover editors, send dialog, JSON drawer, issues sheet). The
|
|
650
|
+
* Slack preview itself is rendered by `slack-blocks-to-jsx` with its
|
|
651
|
+
* native Slack styling regardless — use {@link BlockKitchenProps.defaultPreviewTheme}
|
|
652
|
+
* for preview light/dark.
|
|
653
|
+
*
|
|
654
|
+
* Pass a preset name as sugar for `{ preset }`, or an object with
|
|
655
|
+
* `tokens` (applied in both modes) and optional `light`/`dark`
|
|
656
|
+
* overrides. The existing CSS-variable override path (importing the
|
|
657
|
+
* stylesheet and setting `--primary`, etc. on your own selector)
|
|
658
|
+
* continues to work; this prop is a typed shortcut on top of it.
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* ```tsx
|
|
662
|
+
* <BlockKitchen
|
|
663
|
+
* theme={{
|
|
664
|
+
* tokens: { primary: '262 83% 58%', radius: '0.75rem' },
|
|
665
|
+
* dark: { primary: '263 70% 65%' }
|
|
666
|
+
* }}
|
|
667
|
+
* {...rest}
|
|
668
|
+
* />
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
theme?: BrandTheme | BrandPreset;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export { type AlertBlock as A, type BlockKitchenProps as B, type CardBlock as C, type Template as D, buildVariantById as E, type FeedbackButtonSubobject as F, defaultPalette as G, type HeaderLevel as H, type IconButtonElement as I, extraAlertVariant as J, legacyInputVariants as K, type MarkdownBlock as M, type PaletteSection as P, type SendAsUserStatus as S, type TableBlock as T, type UrlSourceElement as U, type VideoBlock as V, type AlertLevel as a, type BrandPreset as b, type BrandTheme as c, type BrandTokens as d, type BuilderBlock as e, type CarouselBlock as f, type ChannelOption as g, type ContextActionsBlock as h, type ContextActionsElement as i, type FeedbackButtonsElement as j, type IconButtonIcon as k, type InputBlock as l, type PaletteVariant as m, type PlanBlock as n, type PreviewHooks as o, type PreviewSurface as p, type PreviewTheme as q, type SendPayload as r, type SendResult as s, type SupportedBlock as t, type SupportedBlockType as u, type SupportedHeaderBlock as v, type TableCell as w, type TableColumnSetting as x, type TaskCardBlock as y, type TaskCardStatus as z };
|