@tightknitai/block-kitchen 0.6.1-alpha.0

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