@tightknitai/block-kitchen 0.9.9 → 0.10.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.
- package/README.md +255 -26
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +176 -42
- 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 +176 -45
- package/dist/index.js.map +1 -1
- package/dist/{palette-CKP8CK5Z.d.cts → palette-C8sPJuXx.d.cts} +309 -75
- package/dist/{palette-CKP8CK5Z.d.ts → palette-C8sPJuXx.d.ts} +309 -75
- 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/README.md
CHANGED
|
@@ -105,11 +105,15 @@ export function MyBuilderPage() {
|
|
|
105
105
|
| `workspaceName` | `string` | no | Shown in the preview chrome to mimic a real Slack message header. |
|
|
106
106
|
| `initialBlocks` | `SupportedBlock[]` | no | Starting draft. If omitted, the builder starts empty. |
|
|
107
107
|
| `onChange` | `(blocks: SupportedBlock[]) => void` | no | Fires on every state change. Use this to persist the draft (URL, localStorage, etc). |
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
108
|
+
| `onValidationChange` | `(summary: ValidationSummary) => void` | no | Fires when the draft's validation verdict changes (debounced alongside the builder's own validation pass — not on every keystroke). `summary` is `{ valid, errorCount, errors }`: the exact verdict the issues chip/sheet shows, always scoped to the `message` surface. Lets a host-owned CTA gate on validity in [compose-only mode](#compose-only-mode-bring-your-own-send-flow) without re-running the validator. |
|
|
109
|
+
| `loadChannels` | `() => Promise<{ id: string; name: string }[]>` | grouped\* | Returns channels available to send to. The package never makes Slack API calls itself. |
|
|
110
|
+
| `loadSendAsUserStatus` | `() => Promise<{ canSendAsUser: boolean; oauthUrl?: string }>` | grouped\* | Whether the current user has a Slack user-token and can post as themselves. If `canSendAsUser` is false, `oauthUrl` is shown as a "Sign in with Slack" link. |
|
|
111
|
+
| `onSend` | `(payload) => Promise<{ ok: boolean; error?: string }>` | grouped\* | Called when the user submits the send dialog. Payload is `{ channelId, blocks, sendAsUser, extras? }` (`extras` only when `renderSendExtras` is wired). |
|
|
112
|
+
| `renderSendExtras` | `(ctx: SendExtrasContext) => ReactNode` | no | Renders host-defined fields inside the built-in send dialog, below the channel and identity pickers. Collect values with `ctx.setExtras(patch)`; they arrive on `onSend` as `payload.extras`. Requires the send trio. See [Extending the send dialog](#extending-the-send-dialog-custom-fields). |
|
|
113
|
+
| `primaryAction` | `{ label, onClick, disableWhenInvalid? }` | no | Compose-only mode only: a host-owned button in the toolbar slot where "Review & send" normally sits. `onClick` receives `{ blocks, validation, loadedMessage }` — the current draft, the same verdict `onValidationChange` reports, and the currently [loaded message](#loading-an-existing-message-opt-in) (`null` unless `loading` is configured and one is loaded). See [Keeping the CTA in the toolbar](#keeping-the-cta-in-the-toolbar-primaryaction). |
|
|
114
|
+
| `loading` | `{ onLoadMessage, loadRecentMessages?, loadChannels?, initialTarget?, onLoadedMessageChange? }` | no | Opt-in: [load an existing message](#loading-an-existing-message-opt-in) into the editor. Adds a "Find message" toolbar entry — the user pastes a Slack permalink (or picks a recent message) and the draft is hydrated with its blocks. Loading is a *composition* concern, so it works in **both** send mode and compose-only mode. `onLoadedMessageChange` reports the loaded target (`null` on exit) so a host-owned commitment step can stay in sync. |
|
|
115
|
+
| `onUpdate` | `(payload) => Promise<{ ok: boolean; error?: string }>` | no | Opt-in update-in-place mode (send mode only); sibling to `onSend`, but the payload carries the source `channel + ts`. With `loading` configured, a loaded message flips the primary action to a "Review & update" split button wired to it (`chat.update`). |
|
|
116
|
+
| `loadButtonLabel` | `string` | no | Label + accessible name for the toolbar button that opens the load-message dialog. Defaults to `'Find message'`. Only shown when `loading` is configured. |
|
|
113
117
|
| `updateButtonLabel` | `string` | no | Label for the toolbar's primary button while a message is loaded for editing. It's a split button: clicking it updates the message in place; the menu beside it also offers "Send as a new message" (post the current blocks as new). Defaults to `'Review & update'`. |
|
|
114
118
|
| `confirmUpdateLabel` | `string` | no | Label for the update dialog's final confirm button. Defaults to `'Update message'` (shows `'Updating…'` while in flight). |
|
|
115
119
|
| `previewHooks` | `PreviewHooks` | no | Hooks forwarded to `slack-blocks-to-jsx`'s `<Message>` for resolving user / channel / emoji directives. |
|
|
@@ -127,17 +131,184 @@ export function MyBuilderPage() {
|
|
|
127
131
|
| `confirmSendLabel` | `string` | no | Label for the send dialog's final confirm button. Defaults to `'Send'` (shows `'Sending…'` while in flight). |
|
|
128
132
|
| `theme` | `BrandTheme \| BrandPreset` | no | Branding tokens applied to the builder chrome (toolbar, palette, popovers, dialogs). Accepts a `Partial<BrandTokens>` map and optional `light`/`dark` overrides. See [Styling](#styling) below. |
|
|
129
133
|
|
|
130
|
-
|
|
134
|
+
\* The send trio — `loadChannels`, `loadSendAsUserStatus`, `onSend` — is
|
|
135
|
+
all-or-nothing: provide all three for the built-in send flow, or omit all
|
|
136
|
+
three for [compose-only mode](#compose-only-mode-bring-your-own-send-flow)
|
|
137
|
+
(no send button; your app owns the send flow). Wiring only some of the three
|
|
138
|
+
is a type error. `onUpdate` and `renderSendExtras` require the trio;
|
|
139
|
+
`primaryAction` requires its absence (the built-in Send/Update flow owns the
|
|
140
|
+
toolbar's primary slot otherwise). `loading` is mode-agnostic — it works
|
|
141
|
+
with or without the trio.
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
## Compose-only mode (bring your own send flow)
|
|
144
|
+
|
|
145
|
+
Omit the send trio entirely and the builder renders no send button — it
|
|
146
|
+
becomes a pure Block Kit editor. This is the right shape when composing is
|
|
147
|
+
one step in a flow your app owns (a wizard, an audience picker, a scheduler):
|
|
148
|
+
the package owns *composition* (authoring, preview, validation UX) and your
|
|
149
|
+
app owns *distribution* (audiences, identity, scheduling, delivery). The
|
|
150
|
+
only thing that crosses the boundary is the blocks array.
|
|
151
|
+
|
|
152
|
+
Mirror the draft with `onChange`, gate your own CTA with
|
|
153
|
+
`onValidationChange`, and hand `toSlackBlocks(draft)` to whatever comes next:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { useState } from "react";
|
|
157
|
+
import {
|
|
158
|
+
BlockKitchen,
|
|
159
|
+
toSlackBlocks,
|
|
160
|
+
type SupportedBlock,
|
|
161
|
+
type ValidationSummary,
|
|
162
|
+
} from "@tightknitai/block-kitchen";
|
|
163
|
+
|
|
164
|
+
function ComposeStep({ onNext }: { onNext: (blocks: SupportedBlock[]) => void }) {
|
|
165
|
+
const [draft, setDraft] = useState<SupportedBlock[]>([]);
|
|
166
|
+
const [validation, setValidation] = useState<ValidationSummary | null>(null);
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<>
|
|
170
|
+
<BlockKitchen onChange={setDraft} onValidationChange={setValidation} />
|
|
171
|
+
{/* Your CTA, your copy, your placement — gated on the builder's own verdict. */}
|
|
172
|
+
<button
|
|
173
|
+
disabled={draft.length === 0 || validation?.valid === false}
|
|
174
|
+
onClick={() => onNext(toSlackBlocks(draft))}
|
|
175
|
+
>
|
|
176
|
+
Next: choose audience
|
|
177
|
+
</button>
|
|
178
|
+
</>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Notes:
|
|
184
|
+
|
|
185
|
+
- The rest of the toolbar (Clear, View JSON, the issues chip, theme/surface
|
|
186
|
+
controls) is unchanged — users can still inspect problems in the issues
|
|
187
|
+
sheet; only the moment of commitment moves into your app.
|
|
188
|
+
- `onValidationChange` reports the same verdict the issues sheet displays
|
|
189
|
+
(validated against the `message` surface, like Send), so your CTA and the
|
|
190
|
+
in-builder issue count can never disagree.
|
|
191
|
+
- [Loading an existing message](#loading-an-existing-message-opt-in) works
|
|
192
|
+
here too — pass `loading` and the "Find message" entry appears. The loaded
|
|
193
|
+
target (channel + ts + editability verdict) reaches your app via
|
|
194
|
+
`primaryAction`'s `loadedMessage` context and
|
|
195
|
+
`loading.onLoadedMessageChange`, so your own commitment step can offer
|
|
196
|
+
"update in place" alongside "post as new".
|
|
197
|
+
- The built-in *update* flow (`onUpdate`) is unavailable in compose-only
|
|
198
|
+
mode: dispatching a `chat.update` is inherently bound to a channel +
|
|
199
|
+
timestamp + token, so it only exists alongside the send integration.
|
|
200
|
+
|
|
201
|
+
### Keeping the CTA in the toolbar (`primaryAction`)
|
|
202
|
+
|
|
203
|
+
The example above renders its CTA outside the builder. If you want the button
|
|
204
|
+
to sit where "Review & send" normally sits — say a message drafter whose
|
|
205
|
+
primary action is "Save template" — pass `primaryAction`:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
<BlockKitchen
|
|
209
|
+
primaryAction={{
|
|
210
|
+
label: "Save template",
|
|
211
|
+
onClick: ({ blocks, validation }) => openSaveModal(blocks, validation),
|
|
212
|
+
// Send-style gating is opt-in. Default is enabled-while-invalid: a
|
|
213
|
+
// drafter usually allows committing a work-in-progress draft and
|
|
214
|
+
// surfaces the verdict in its own flow instead.
|
|
215
|
+
disableWhenInvalid: false,
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`onClick` receives the current draft in the builder's native format (the same
|
|
221
|
+
shape `onChange` reports — persist that to re-open the draft later; run it
|
|
222
|
+
through `toSlackBlocks` for the Slack-ready payload) plus the validation
|
|
223
|
+
verdict `onValidationChange` would report. The button is never disabled for
|
|
224
|
+
an empty draft; gate on `blocks.length` in `onClick` if you need that.
|
|
225
|
+
|
|
226
|
+
### Building a bespoke send flow from the exported primitives
|
|
227
|
+
|
|
228
|
+
If your custom flow ends in something send-shaped, you don't have to rebuild
|
|
229
|
+
the built-in dialog's machinery — the send-flow primitives are exported:
|
|
230
|
+
|
|
231
|
+
- `SendDialog` — the built-in dialog as a standalone component
|
|
232
|
+
(`SendDialogProps`): channel loading/error states, bot-vs-user identity
|
|
233
|
+
picker, OAuth hand-off, in-flight and failure states. Mount it against your
|
|
234
|
+
own trigger.
|
|
235
|
+
- `useSlackSignIn(loadStatus, { open, enabled })` — the OAuth sign-in state
|
|
236
|
+
machine behind the identity picker: fetches user-token status on open,
|
|
237
|
+
refreshes on window focus, and background-polls after the OAuth tab opens
|
|
238
|
+
until the token appears.
|
|
239
|
+
- `SlackSignInButton` — the "Sign in with Slack" button with its polling
|
|
240
|
+
spinner, for wiring `useSlackSignIn` into your own dialog.
|
|
241
|
+
|
|
242
|
+
## Extending the send dialog (custom fields)
|
|
243
|
+
|
|
244
|
+
When the built-in send flow is *almost* right — you want the channel picker,
|
|
245
|
+
identity picker, and sending states, plus a few controls of your own (a
|
|
246
|
+
cross-post toggle, a custom sender name) — pass `renderSendExtras` instead of
|
|
247
|
+
rebuilding the dialog. It renders below the built-in fields, and whatever you
|
|
248
|
+
collect via `setExtras` arrives on `onSend` as `payload.extras`:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
<BlockKitchen
|
|
252
|
+
loadChannels={loadChannels}
|
|
253
|
+
loadSendAsUserStatus={loadSendAsUserStatus}
|
|
254
|
+
renderSendExtras={({ extras, setExtras }) => (
|
|
255
|
+
<>
|
|
256
|
+
<label>
|
|
257
|
+
<input
|
|
258
|
+
type="checkbox"
|
|
259
|
+
checked={Boolean(extras.alsoPostToIntranet)}
|
|
260
|
+
onChange={(e) => setExtras({ alsoPostToIntranet: e.target.checked })}
|
|
261
|
+
/>
|
|
262
|
+
Also publish to the intranet
|
|
263
|
+
</label>
|
|
264
|
+
<label>
|
|
265
|
+
Custom sender name
|
|
266
|
+
<input
|
|
267
|
+
type="text"
|
|
268
|
+
value={String(extras.senderName ?? "")}
|
|
269
|
+
onChange={(e) => setExtras({ senderName: e.target.value })}
|
|
270
|
+
/>
|
|
271
|
+
</label>
|
|
272
|
+
</>
|
|
273
|
+
)}
|
|
274
|
+
onSend={async ({ channelId, blocks, sendAsUser, extras }) => {
|
|
275
|
+
await api.send({ channelId, blocks, sendAsUser, ...extras }); // your code
|
|
276
|
+
return { ok: true };
|
|
277
|
+
}}
|
|
278
|
+
/>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Notes:
|
|
282
|
+
|
|
283
|
+
- The `extras` object is owned by the dialog: it resets every time the dialog
|
|
284
|
+
opens (alongside the channel and identity pickers), and `setExtras(patch)`
|
|
285
|
+
shallow-merges. Render controlled inputs from `extras`.
|
|
286
|
+
- The context also carries the currently selected `channelId` (`null` until
|
|
287
|
+
channels load) and `sendAsUser`, so extras can react to them — e.g. only
|
|
288
|
+
offer cross-posting for certain channels.
|
|
289
|
+
- `payload.extras` is present iff `renderSendExtras` is wired, so existing
|
|
290
|
+
`onSend` handlers never see a new key.
|
|
291
|
+
- The dialog renders in a portal attached to `document.body`, so CSS that
|
|
292
|
+
relies on ancestor selectors from your app's DOM won't reach slot content —
|
|
293
|
+
style it directly (inline, CSS modules, utility classes).
|
|
294
|
+
- For customizations that generalize something the dialog already models
|
|
295
|
+
(identities, channels), prefer proposing a first-class prop over routing
|
|
296
|
+
them through extras; the slot is for genuinely host-specific concerns.
|
|
297
|
+
|
|
298
|
+
## Loading an existing message (opt-in)
|
|
299
|
+
|
|
300
|
+
By default the builder starts from a blank canvas. Pass `loading` to let
|
|
301
|
+
users load an already-posted message's blocks into the editor — paste a
|
|
302
|
+
permalink, or pick from a "recent messages from this app" list. Loading is a
|
|
303
|
+
*composition* concern, so it works in **both** send mode and
|
|
304
|
+
[compose-only mode](#compose-only-mode-bring-your-own-send-flow). The
|
|
134
305
|
package stays integration-agnostic: it makes no Slack calls and computes
|
|
135
306
|
nothing about who can edit; the host does both.
|
|
136
307
|
|
|
137
308
|
```tsx
|
|
138
309
|
<BlockKitchen
|
|
139
|
-
/* …send-only
|
|
140
|
-
|
|
310
|
+
/* …send trio, or nothing (compose-only)… */
|
|
311
|
+
loading={{
|
|
141
312
|
// Host parses the pasted permalink, fetches the message, and returns a
|
|
142
313
|
// verdict. `chat.update` only edits a message authored by the calling
|
|
143
314
|
// token, so the host decides: bot message → 'bot', the user's own
|
|
@@ -155,17 +326,11 @@ nothing about who can edit; the host does both.
|
|
|
155
326
|
return { ok: true, channelId: msg.channel, channelName: msg.channelName, ts: msg.ts, blocks: msg.blocks, editableVia: 'user', ...author };
|
|
156
327
|
return { ok: false, reason: 'Only messages your app or you posted can be edited.', blocks: msg.blocks };
|
|
157
328
|
},
|
|
158
|
-
// Sibling to onSend; carries the source channel + ts. `asUser` follows
|
|
159
|
-
// the verdict's `editableVia`.
|
|
160
|
-
onUpdate: async ({ channelId, ts, blocks, asUser }) => {
|
|
161
|
-
await chatUpdate({ channel: channelId, ts, blocks, asUser }); // your code
|
|
162
|
-
return { ok: true };
|
|
163
|
-
},
|
|
164
329
|
// Optional: adds a "recent messages from this app" picker beside the paste
|
|
165
|
-
// input. The user first picks a channel
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
330
|
+
// input. The user first picks a channel, then this is called with that
|
|
331
|
+
// `channelId` so the lookup scans only one channel. These are
|
|
332
|
+
// editable-by-construction (the app authored them), so picking one loads
|
|
333
|
+
// it directly (no verdict needed).
|
|
169
334
|
loadRecentMessages: async (channelId) => {
|
|
170
335
|
const msgs = await fetchRecentAppMessages(channelId); // your code
|
|
171
336
|
return msgs.map((m) => ({
|
|
@@ -177,17 +342,68 @@ nothing about who can edit; the host does both.
|
|
|
177
342
|
label: m.preview // one-line preview shown in the picker row
|
|
178
343
|
}));
|
|
179
344
|
}
|
|
345
|
+
// In send mode the recent picker's channel list reuses the send trio's
|
|
346
|
+
// `loadChannels`. In compose-only mode there is no trio — pass
|
|
347
|
+
// `loadChannels` here too, or the picker is hidden.
|
|
180
348
|
}}
|
|
181
349
|
/>
|
|
182
350
|
```
|
|
183
351
|
|
|
184
|
-
- On `ok`, the builder hydrates with `blocks
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
in with Slack" gate).
|
|
352
|
+
- On `ok`, the builder hydrates with `blocks` and shows a loaded banner
|
|
353
|
+
("References an existing message in #channel"), with the author's
|
|
354
|
+
name/avatar in the preview header.
|
|
188
355
|
- On `{ ok: false, reason }`, the load dialog renders the reason inline and
|
|
189
356
|
offers **Open as a new message instead**. Pass `blocks` on the failure
|
|
190
357
|
result to hydrate the draft for that fallback.
|
|
358
|
+
- `loading.onLoadedMessageChange` reports the loaded target — and `null`
|
|
359
|
+
when the user exits it — so host state stays in sync (most useful in
|
|
360
|
+
compose-only mode, where your app owns what happens next). It can
|
|
361
|
+
**re-fire for the same `channelId` + `ts`** when the host's verdict or
|
|
362
|
+
metadata changed (e.g. `editableVia` flipping after a Slack sign-in), so
|
|
363
|
+
key host state on the full target, not `ts` alone.
|
|
364
|
+
- The banner's **"Switch to a new message"** exit is mode-aware: in send
|
|
365
|
+
mode it clears the canvas and reopens the load dialog (the edit-centric
|
|
366
|
+
"pick a different message" flow); in compose-only mode it only detaches
|
|
367
|
+
the reference and **keeps the draft** — loading seeded a composition, and
|
|
368
|
+
a misclick must not destroy it.
|
|
369
|
+
|
|
370
|
+
### Updating it in place (send mode)
|
|
371
|
+
|
|
372
|
+
In send mode, pair `loading` with `onUpdate` to dispatch a `chat.update` for
|
|
373
|
+
the loaded message. The primary action flips to a "Review & update" split
|
|
374
|
+
button (the menu also offers "Send as a new message"), the destination is
|
|
375
|
+
locked to the source channel, and the post-as identity is fixed to the
|
|
376
|
+
verdict's `editableVia` (the `'user'` path reuses `loadSendAsUserStatus` for
|
|
377
|
+
the "Sign in with Slack" gate).
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
<BlockKitchen
|
|
381
|
+
/* …send trio… */
|
|
382
|
+
loading={{ onLoadMessage }}
|
|
383
|
+
// Sibling to onSend; carries the source channel + ts. `asUser` follows
|
|
384
|
+
// the verdict's `editableVia`.
|
|
385
|
+
onUpdate={async ({ channelId, ts, blocks, asUser }) => {
|
|
386
|
+
await chatUpdate({ channel: channelId, ts, blocks, asUser }); // your code
|
|
387
|
+
return { ok: true };
|
|
388
|
+
}}
|
|
389
|
+
/>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
With `loading` alone (no `onUpdate`), a loaded message can still be posted
|
|
393
|
+
as a brand-new message via the regular Send flow — there's just no in-place
|
|
394
|
+
update. In compose-only mode `onUpdate` doesn't exist; implement your own
|
|
395
|
+
update against the target from `loadedMessage` / `onLoadedMessageChange`.
|
|
396
|
+
|
|
397
|
+
> **Migrating from the pre-split `editing` bundle (≤ 0.9.x):** the load
|
|
398
|
+
> fields move to `loading` unchanged, and `onUpdate` becomes a top-level
|
|
399
|
+
> prop (the `editing` wrapper is gone).
|
|
400
|
+
>
|
|
401
|
+
> ```tsx
|
|
402
|
+
> // Before
|
|
403
|
+
> <BlockKitchen editing={{ onLoadMessage, onUpdate, loadRecentMessages }} />
|
|
404
|
+
> // After
|
|
405
|
+
> <BlockKitchen loading={{ onLoadMessage, loadRecentMessages }} onUpdate={onUpdate} />
|
|
406
|
+
> ```
|
|
191
407
|
|
|
192
408
|
## Customizing the palette
|
|
193
409
|
|
|
@@ -225,9 +441,9 @@ Variant `id`s must be unique across the array — the drag-drop lookup keys by i
|
|
|
225
441
|
|
|
226
442
|
## Boundary
|
|
227
443
|
|
|
228
|
-
The package is deliberately decoupled from any Slack SDK or backend. It does not import HTTP clients, OAuth libraries, or workspace-state systems. Everything I/O-shaped is brokered through props.
|
|
444
|
+
The package is deliberately decoupled from any Slack SDK or backend. It does not import HTTP clients, OAuth libraries, or workspace-state systems. Everything I/O-shaped is brokered through props — and the send flow itself is optional: see [compose-only mode](#compose-only-mode-bring-your-own-send-flow) when your app owns the moment of commitment.
|
|
229
445
|
|
|
230
|
-
Helpers also exported:
|
|
446
|
+
Helpers and send-flow primitives also exported:
|
|
231
447
|
|
|
232
448
|
```ts
|
|
233
449
|
import {
|
|
@@ -235,18 +451,31 @@ import {
|
|
|
235
451
|
encodeBlocksToString, // base64url-encode a blocks array (for URL state)
|
|
236
452
|
decodeBlocksFromString,
|
|
237
453
|
defaultPalette, // the built-in palette — spread to customize
|
|
454
|
+
SendDialog, // the built-in send dialog, standalone (bespoke send flows)
|
|
455
|
+
useSlackSignIn, // the OAuth sign-in state machine behind the identity picker
|
|
456
|
+
SlackSignInButton, // the "Sign in with Slack" button + polling spinner
|
|
238
457
|
} from "@tightknitai/block-kitchen";
|
|
239
458
|
|
|
240
459
|
import type {
|
|
241
460
|
SupportedBlock,
|
|
242
461
|
SupportedBlockType,
|
|
243
462
|
BlockKitchenProps,
|
|
463
|
+
BlockKitchenBaseProps, // shared props
|
|
464
|
+
BlockKitchenSendProps, // the send trio + `onUpdate` + `renderSendExtras`
|
|
465
|
+
LoadingConfig, // load an existing message (works in both modes)
|
|
466
|
+
LoadedMessage, // the loaded target: channel + ts + verdict
|
|
467
|
+
BlockKitchenComposeOnlyProps, // the trio explicitly absent + `primaryAction`
|
|
244
468
|
PaletteSection,
|
|
245
469
|
PaletteVariant,
|
|
246
470
|
SendPayload,
|
|
247
471
|
SendResult,
|
|
472
|
+
SendDialogProps,
|
|
473
|
+
SendExtrasContext,
|
|
474
|
+
PrimaryActionConfig,
|
|
475
|
+
PrimaryActionContext,
|
|
248
476
|
ChannelOption,
|
|
249
477
|
SendAsUserStatus,
|
|
478
|
+
ValidationSummary,
|
|
250
479
|
PreviewHooks,
|
|
251
480
|
} from "@tightknitai/block-kitchen";
|
|
252
481
|
```
|
package/dist/helpers.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { _ as SupportedBlock } from './palette-C8sPJuXx.cjs';
|
|
2
|
+
export { $ as SupportedBlockType } from './palette-C8sPJuXx.cjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'slack-web-api-client';
|
|
5
5
|
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { _ as SupportedBlock } from './palette-C8sPJuXx.js';
|
|
2
|
+
export { $ as SupportedBlockType } from './palette-C8sPJuXx.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'slack-web-api-client';
|
|
5
5
|
|