@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.
@@ -1,4 +1,4 @@
1
- import { ComponentType, SVGProps } from 'react';
1
+ import { ComponentType, SVGProps, ReactNode } from 'react';
2
2
  import { SectionBlock, HeaderBlock, DividerBlock, ContextBlock, ActionsBlock, ImageBlock, RichTextBlock, ImageElement, Button, ViewInputBlock } from 'slack-web-api-client';
3
3
 
4
4
  /**
@@ -571,6 +571,38 @@ interface SendPayload {
571
571
  channelId: string;
572
572
  blocks: SupportedBlock[];
573
573
  sendAsUser: boolean;
574
+ /**
575
+ * Values collected from the host's
576
+ * {@link BlockKitchenSendProps.renderSendExtras} fields, exactly as
577
+ * accumulated through {@link SendExtrasContext.setExtras}. Present
578
+ * (possibly `{}`) iff `renderSendExtras` is wired; absent otherwise, so
579
+ * existing consumers never see a new key.
580
+ */
581
+ extras?: Record<string, unknown>;
582
+ }
583
+ /**
584
+ * Context passed to {@link BlockKitchenSendProps.renderSendExtras} on every
585
+ * render of the send dialog. The `extras` object is owned by the dialog —
586
+ * it resets each time the dialog opens (alongside the channel and identity
587
+ * pickers) and is delivered on {@link SendPayload.extras} when the user
588
+ * confirms.
589
+ */
590
+ interface SendExtrasContext {
591
+ /**
592
+ * Destination channel currently selected in the dialog, or `null` while
593
+ * channels are still loading / none is selected. Lets extras react to the
594
+ * destination (e.g. only offer cross-posting for some channels).
595
+ */
596
+ channelId: string | null;
597
+ /** Whether "post as the user" (vs. the app bot) is currently selected. */
598
+ sendAsUser: boolean;
599
+ /** The values collected so far. Render controlled inputs from these. */
600
+ extras: Record<string, unknown>;
601
+ /**
602
+ * Shallow-merges `patch` into {@link SendExtrasContext.extras}. Keys you
603
+ * never set simply don't appear in the payload.
604
+ */
605
+ setExtras: (patch: Record<string, unknown>) => void;
574
606
  }
575
607
  /**
576
608
  * Result returned from {@link BlockKitchenProps.onSend}.
@@ -580,6 +612,66 @@ interface SendResult {
580
612
  ok: boolean;
581
613
  error?: string;
582
614
  }
615
+ /**
616
+ * Snapshot of the builder's validation verdict, reported through
617
+ * {@link BlockKitchenBaseProps.onValidationChange}. Mirrors exactly what the
618
+ * built-in issues chip / issues sheet show, so a host-owned CTA (e.g. in
619
+ * compose-only mode) can gate on the same verdict without re-running the
620
+ * validator and risking drift.
621
+ */
622
+ interface ValidationSummary {
623
+ /** True iff the current draft has zero validation errors. */
624
+ valid: boolean;
625
+ /** Total error count — the number the toolbar's issues chip displays. */
626
+ errorCount: number;
627
+ /**
628
+ * Raw validator messages, verbatim from
629
+ * `@tightknitai/slack-block-kit-validator`. Block-scoped messages are
630
+ * rooted at `blocks[N]`, indexing into the payload `toSlackBlocks` emits.
631
+ */
632
+ errors: readonly string[];
633
+ }
634
+ /**
635
+ * Context handed to {@link PrimaryActionConfig.onClick}: everything a
636
+ * host-owned commitment step needs, captured at click time.
637
+ */
638
+ interface PrimaryActionContext {
639
+ /**
640
+ * The current draft in the builder's native format — the same shape
641
+ * `onChange` reports and `initialBlocks` accepts. Persist this to re-open
642
+ * the draft later; run it through `toSlackBlocks` when you need the
643
+ * Slack-ready payload.
644
+ */
645
+ blocks: SupportedBlock[];
646
+ /**
647
+ * The validation verdict at click time — the same summary
648
+ * {@link BlockKitchenBaseProps.onValidationChange} reports.
649
+ */
650
+ validation: ValidationSummary;
651
+ }
652
+ /**
653
+ * A host-owned primary action for compose-only mode, rendered in the
654
+ * toolbar slot where the built-in "Review & send" button normally sits.
655
+ * Use it when the builder's commitment step belongs to your app — e.g. a
656
+ * message drafter whose CTA is "Save template" — but you still want the
657
+ * button inside the builder chrome. For a CTA outside the builder, skip
658
+ * this and use {@link BlockKitchenBaseProps.onChange} +
659
+ * {@link BlockKitchenBaseProps.onValidationChange} instead.
660
+ */
661
+ interface PrimaryActionConfig {
662
+ /** Label + accessible name for the toolbar button. */
663
+ label: string;
664
+ /** Called on click with the current draft and validation verdict. */
665
+ onClick: (context: PrimaryActionContext) => void;
666
+ /**
667
+ * Disable the button while the draft has validation errors, mirroring the
668
+ * built-in Send gating. Defaults to `false`: a drafter typically allows
669
+ * committing a work-in-progress draft and surfaces the verdict in its own
670
+ * flow instead. The button is never disabled for an empty draft — gate on
671
+ * `context.blocks.length` in `onClick` if you need that.
672
+ */
673
+ disableWhenInvalid?: boolean;
674
+ }
583
675
  /**
584
676
  * Which token can edit a loaded message, as computed by the host.
585
677
  * `chat.update` only edits a message authored by the calling token:
@@ -794,11 +886,15 @@ interface Template {
794
886
  blocks: SupportedBlock[];
795
887
  }
796
888
  /**
797
- * Props for the top-level {@link BlockKitchen} component.
889
+ * Props shared by every {@link BlockKitchen} configuration.
798
890
  * The package is integration-agnostic: every I/O concern is brokered
799
891
  * through these props. The component never makes a network call itself.
892
+ *
893
+ * Combined with either {@link BlockKitchenSendProps} (the built-in send
894
+ * flow) or {@link BlockKitchenComposeOnlyProps} (compose-only: no send
895
+ * button, the host owns the send flow) to form {@link BlockKitchenProps}.
800
896
  */
801
- interface BlockKitchenProps {
897
+ interface BlockKitchenBaseProps {
802
898
  /**
803
899
  * Workspace name shown in the preview chrome to mimic a Slack message header.
804
900
  * Cosmetic only.
@@ -813,6 +909,15 @@ interface BlockKitchenProps {
813
909
  * (URL search param, localStorage, etc).
814
910
  */
815
911
  onChange?: (blocks: SupportedBlock[]) => void;
912
+ /**
913
+ * Fires when the draft's validation verdict changes (piggybacking on the
914
+ * builder's own debounced validation pass — not on every keystroke, and
915
+ * not when the verdict is unchanged). Always scoped to the `message`
916
+ * surface, matching what Send would post. Useful in compose-only mode: a
917
+ * host-rendered CTA can disable itself on `!valid` using the exact verdict
918
+ * the issues sheet displays.
919
+ */
920
+ onValidationChange?: (summary: ValidationSummary) => void;
816
921
  /**
817
922
  * Optional hooks forwarded to the underlying `<Message>` component for
818
923
  * resolving user / channel / emoji directives. If omitted, those
@@ -830,29 +935,6 @@ interface BlockKitchenProps {
830
935
  * is never serialized into the emitted Block Kit JSON.
831
936
  */
832
937
  customEmojis?: CustomEmoji[];
833
- /**
834
- * Returns channels available to send to. Called when the send dialog opens.
835
- */
836
- loadChannels: () => Promise<ChannelOption[]>;
837
- /**
838
- * Returns whether the current user can post as themselves and, if not, an
839
- * OAuth URL to start the install flow.
840
- */
841
- loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
842
- /**
843
- * Called when the user submits the send dialog. Should return
844
- * `{ ok: true }` on success or `{ ok: false, error }` on failure.
845
- */
846
- onSend: (payload: SendPayload) => Promise<SendResult>;
847
- /**
848
- * Opt-in edit mode. When provided, the toolbar exposes an "Edit existing
849
- * message" entry: the user pastes a Slack message link, the host loads it
850
- * and returns an editability verdict ({@link EditingConfig.onLoadMessage}),
851
- * and a successful load flips the primary action from Send to "Update
852
- * message" ({@link EditingConfig.onUpdate}). Omit to keep today's send-only
853
- * behavior. The user-token path reuses {@link BlockKitchenProps.loadSendAsUserStatus}.
854
- */
855
- editing?: EditingConfig;
856
938
  /**
857
939
  * Label + accessible name for the toolbar button that opens the
858
940
  * load-message dialog (the edit-mode entry point). Defaults to
@@ -1022,5 +1104,84 @@ interface BlockKitchenProps {
1022
1104
  */
1023
1105
  theme?: BrandTheme | BrandPreset;
1024
1106
  }
1107
+ /**
1108
+ * The send integration: the trio of I/O callbacks powering the built-in
1109
+ * send dialog, plus opt-in edit mode (which reuses them). All-or-nothing by
1110
+ * design — see {@link BlockKitchenComposeOnlyProps} for the alternative.
1111
+ */
1112
+ interface BlockKitchenSendProps {
1113
+ /**
1114
+ * Returns channels available to send to. Called when the send dialog opens.
1115
+ */
1116
+ loadChannels: () => Promise<ChannelOption[]>;
1117
+ /**
1118
+ * Returns whether the current user can post as themselves and, if not, an
1119
+ * OAuth URL to start the install flow.
1120
+ */
1121
+ loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
1122
+ /**
1123
+ * Called when the user submits the send dialog. Should return
1124
+ * `{ ok: true }` on success or `{ ok: false, error }` on failure.
1125
+ */
1126
+ onSend: (payload: SendPayload) => Promise<SendResult>;
1127
+ /**
1128
+ * Opt-in edit mode. When provided, the toolbar exposes an "Edit existing
1129
+ * message" entry: the user pastes a Slack message link, the host loads it
1130
+ * and returns an editability verdict ({@link EditingConfig.onLoadMessage}),
1131
+ * and a successful load flips the primary action from Send to "Update
1132
+ * message" ({@link EditingConfig.onUpdate}). Omit to keep send-only
1133
+ * behavior. The user-token path reuses {@link BlockKitchenSendProps.loadSendAsUserStatus}.
1134
+ */
1135
+ editing?: EditingConfig;
1136
+ /**
1137
+ * Renders host-defined fields inside the built-in send dialog, below the
1138
+ * channel and identity pickers. Values collected via
1139
+ * {@link SendExtrasContext.setExtras} are delivered on
1140
+ * {@link SendPayload.extras} when the user confirms. Use this when the
1141
+ * built-in flow is almost right and you need a few extra controls (a
1142
+ * cross-post toggle, a custom sender name) without rebuilding the dialog.
1143
+ */
1144
+ renderSendExtras?: (context: SendExtrasContext) => ReactNode;
1145
+ /**
1146
+ * Unavailable with the send integration: the built-in Send/Update flow
1147
+ * owns the toolbar's primary action. A host-owned
1148
+ * {@link PrimaryActionConfig} exists only in compose-only mode.
1149
+ */
1150
+ primaryAction?: undefined;
1151
+ }
1152
+ /**
1153
+ * Compose-only mode: omit the entire send integration and the builder
1154
+ * renders no send button — it becomes a pure editor. The host owns the
1155
+ * moment of commitment: mirror the draft via
1156
+ * {@link BlockKitchenBaseProps.onChange}, gate a host-rendered CTA via
1157
+ * {@link BlockKitchenBaseProps.onValidationChange}, and hand the finished
1158
+ * payload (`toSlackBlocks(draft)`) to your own audience/delivery flow.
1159
+ *
1160
+ * The explicit `undefined` members make the send trio all-or-nothing at the
1161
+ * type level: wiring only some of the three is a type error instead of a
1162
+ * silently dead send button.
1163
+ */
1164
+ interface BlockKitchenComposeOnlyProps {
1165
+ loadChannels?: undefined;
1166
+ loadSendAsUserStatus?: undefined;
1167
+ onSend?: undefined;
1168
+ /** Edit mode depends on the send integration, so it is unavailable too. */
1169
+ editing?: undefined;
1170
+ /** Extends the built-in send dialog, which doesn't exist in this mode. */
1171
+ renderSendExtras?: undefined;
1172
+ /**
1173
+ * Optional host-owned button rendered in the toolbar slot where the
1174
+ * built-in "Review & send" normally sits — e.g. "Save template" for a
1175
+ * message drafter. `onClick` receives the current draft and validation
1176
+ * verdict ({@link PrimaryActionContext}). Omit it to render no primary
1177
+ * action at all and place your CTA outside the builder.
1178
+ */
1179
+ primaryAction?: PrimaryActionConfig;
1180
+ }
1181
+ /**
1182
+ * Props for the top-level {@link BlockKitchen} component: the shared base
1183
+ * plus either the full send integration or none of it.
1184
+ */
1185
+ type BlockKitchenProps = BlockKitchenBaseProps & (BlockKitchenSendProps | BlockKitchenComposeOnlyProps);
1025
1186
 
1026
- export { type Template as $, type AlertBlock as A, type BlockKitchenProps as B, type CardBlock as C, type DataVisualizationBlock as D, type EditableVia as E, type FeedbackButtonSubobject as F, type PlanBlock as G, type HeaderLevel as H, type IconButtonElement as I, type PreviewHooks as J, type PreviewSurface as K, type LoadMessageInput as L, type MarkdownBlock as M, type PreviewTheme as N, type SendPayload as O, type PaletteSection as P, type SendResult as Q, type RecentMessage as R, type SendAsUserStatus as S, type SupportedBlock as T, type SupportedBlockType as U, type SupportedHeaderBlock as V, type TableBlock as W, type TableCell as X, type TableColumnSetting as Y, type TaskCardBlock as Z, type TaskCardStatus as _, type AlertLevel as a, type UpdatePayload as a0, type UpdateResult as a1, type UrlSourceElement as a2, type VideoBlock as a3, buildVariantById as a4, defaultPalette as a5, extraAlertVariant as a6, legacyInputVariants as a7, type BrandPreset as b, type BrandTheme as c, type BrandTokens as d, type BuilderBlock as e, type CarouselBlock as f, type CartesianChart as g, type ChannelOption as h, type Chart as i, type ChartAxisConfig as j, type ChartDataPoint as k, type ChartSeries as l, type ChartType as m, type ContainerBlock as n, type ContainerChildBlock as o, type ContextActionsBlock as p, type ContextActionsElement as q, type CustomEmoji as r, type EditingConfig as s, type FeedbackButtonsElement as t, type IconButtonIcon as u, type InputBlock as v, type LoadResult as w, type PaletteVariant as x, type PieChart as y, type PieChartSegment as z };
1187
+ export { type SupportedHeaderBlock as $, type AlertBlock as A, type BlockKitchenBaseProps as B, type CardBlock as C, type DataVisualizationBlock as D, type EditableVia as E, type FeedbackButtonSubobject as F, type PaletteVariant as G, type HeaderLevel as H, type IconButtonElement as I, type PieChart as J, type PieChartSegment as K, type LoadMessageInput as L, type MarkdownBlock as M, type PlanBlock as N, type PreviewHooks as O, type PaletteSection as P, type PreviewSurface as Q, type PreviewTheme as R, type PrimaryActionConfig as S, type PrimaryActionContext as T, type RecentMessage as U, type SendAsUserStatus as V, type SendExtrasContext as W, type SendPayload as X, type SendResult as Y, type SupportedBlock as Z, type SupportedBlockType as _, type AlertLevel as a, type TableBlock as a0, type TableCell as a1, type TableColumnSetting as a2, type TaskCardBlock as a3, type TaskCardStatus as a4, type Template as a5, type UpdatePayload as a6, type UpdateResult as a7, type UrlSourceElement as a8, type ValidationSummary as a9, type VideoBlock as aa, buildVariantById as ab, defaultPalette as ac, extraAlertVariant as ad, legacyInputVariants as ae, type BlockKitchenComposeOnlyProps as b, type BlockKitchenProps as c, type BlockKitchenSendProps as d, type BrandPreset as e, type BrandTheme as f, type BrandTokens as g, type BuilderBlock as h, type CarouselBlock as i, type CartesianChart as j, type ChannelOption as k, type Chart as l, type ChartAxisConfig as m, type ChartDataPoint as n, type ChartSeries as o, type ChartType as p, type ContainerBlock as q, type ContainerChildBlock as r, type ContextActionsBlock as s, type ContextActionsElement as t, type CustomEmoji as u, type EditingConfig as v, type FeedbackButtonsElement as w, type IconButtonIcon as x, type InputBlock as y, type LoadResult as z };
@@ -1,4 +1,4 @@
1
- import { ComponentType, SVGProps } from 'react';
1
+ import { ComponentType, SVGProps, ReactNode } from 'react';
2
2
  import { SectionBlock, HeaderBlock, DividerBlock, ContextBlock, ActionsBlock, ImageBlock, RichTextBlock, ImageElement, Button, ViewInputBlock } from 'slack-web-api-client';
3
3
 
4
4
  /**
@@ -571,6 +571,38 @@ interface SendPayload {
571
571
  channelId: string;
572
572
  blocks: SupportedBlock[];
573
573
  sendAsUser: boolean;
574
+ /**
575
+ * Values collected from the host's
576
+ * {@link BlockKitchenSendProps.renderSendExtras} fields, exactly as
577
+ * accumulated through {@link SendExtrasContext.setExtras}. Present
578
+ * (possibly `{}`) iff `renderSendExtras` is wired; absent otherwise, so
579
+ * existing consumers never see a new key.
580
+ */
581
+ extras?: Record<string, unknown>;
582
+ }
583
+ /**
584
+ * Context passed to {@link BlockKitchenSendProps.renderSendExtras} on every
585
+ * render of the send dialog. The `extras` object is owned by the dialog —
586
+ * it resets each time the dialog opens (alongside the channel and identity
587
+ * pickers) and is delivered on {@link SendPayload.extras} when the user
588
+ * confirms.
589
+ */
590
+ interface SendExtrasContext {
591
+ /**
592
+ * Destination channel currently selected in the dialog, or `null` while
593
+ * channels are still loading / none is selected. Lets extras react to the
594
+ * destination (e.g. only offer cross-posting for some channels).
595
+ */
596
+ channelId: string | null;
597
+ /** Whether "post as the user" (vs. the app bot) is currently selected. */
598
+ sendAsUser: boolean;
599
+ /** The values collected so far. Render controlled inputs from these. */
600
+ extras: Record<string, unknown>;
601
+ /**
602
+ * Shallow-merges `patch` into {@link SendExtrasContext.extras}. Keys you
603
+ * never set simply don't appear in the payload.
604
+ */
605
+ setExtras: (patch: Record<string, unknown>) => void;
574
606
  }
575
607
  /**
576
608
  * Result returned from {@link BlockKitchenProps.onSend}.
@@ -580,6 +612,66 @@ interface SendResult {
580
612
  ok: boolean;
581
613
  error?: string;
582
614
  }
615
+ /**
616
+ * Snapshot of the builder's validation verdict, reported through
617
+ * {@link BlockKitchenBaseProps.onValidationChange}. Mirrors exactly what the
618
+ * built-in issues chip / issues sheet show, so a host-owned CTA (e.g. in
619
+ * compose-only mode) can gate on the same verdict without re-running the
620
+ * validator and risking drift.
621
+ */
622
+ interface ValidationSummary {
623
+ /** True iff the current draft has zero validation errors. */
624
+ valid: boolean;
625
+ /** Total error count — the number the toolbar's issues chip displays. */
626
+ errorCount: number;
627
+ /**
628
+ * Raw validator messages, verbatim from
629
+ * `@tightknitai/slack-block-kit-validator`. Block-scoped messages are
630
+ * rooted at `blocks[N]`, indexing into the payload `toSlackBlocks` emits.
631
+ */
632
+ errors: readonly string[];
633
+ }
634
+ /**
635
+ * Context handed to {@link PrimaryActionConfig.onClick}: everything a
636
+ * host-owned commitment step needs, captured at click time.
637
+ */
638
+ interface PrimaryActionContext {
639
+ /**
640
+ * The current draft in the builder's native format — the same shape
641
+ * `onChange` reports and `initialBlocks` accepts. Persist this to re-open
642
+ * the draft later; run it through `toSlackBlocks` when you need the
643
+ * Slack-ready payload.
644
+ */
645
+ blocks: SupportedBlock[];
646
+ /**
647
+ * The validation verdict at click time — the same summary
648
+ * {@link BlockKitchenBaseProps.onValidationChange} reports.
649
+ */
650
+ validation: ValidationSummary;
651
+ }
652
+ /**
653
+ * A host-owned primary action for compose-only mode, rendered in the
654
+ * toolbar slot where the built-in "Review & send" button normally sits.
655
+ * Use it when the builder's commitment step belongs to your app — e.g. a
656
+ * message drafter whose CTA is "Save template" — but you still want the
657
+ * button inside the builder chrome. For a CTA outside the builder, skip
658
+ * this and use {@link BlockKitchenBaseProps.onChange} +
659
+ * {@link BlockKitchenBaseProps.onValidationChange} instead.
660
+ */
661
+ interface PrimaryActionConfig {
662
+ /** Label + accessible name for the toolbar button. */
663
+ label: string;
664
+ /** Called on click with the current draft and validation verdict. */
665
+ onClick: (context: PrimaryActionContext) => void;
666
+ /**
667
+ * Disable the button while the draft has validation errors, mirroring the
668
+ * built-in Send gating. Defaults to `false`: a drafter typically allows
669
+ * committing a work-in-progress draft and surfaces the verdict in its own
670
+ * flow instead. The button is never disabled for an empty draft — gate on
671
+ * `context.blocks.length` in `onClick` if you need that.
672
+ */
673
+ disableWhenInvalid?: boolean;
674
+ }
583
675
  /**
584
676
  * Which token can edit a loaded message, as computed by the host.
585
677
  * `chat.update` only edits a message authored by the calling token:
@@ -794,11 +886,15 @@ interface Template {
794
886
  blocks: SupportedBlock[];
795
887
  }
796
888
  /**
797
- * Props for the top-level {@link BlockKitchen} component.
889
+ * Props shared by every {@link BlockKitchen} configuration.
798
890
  * The package is integration-agnostic: every I/O concern is brokered
799
891
  * through these props. The component never makes a network call itself.
892
+ *
893
+ * Combined with either {@link BlockKitchenSendProps} (the built-in send
894
+ * flow) or {@link BlockKitchenComposeOnlyProps} (compose-only: no send
895
+ * button, the host owns the send flow) to form {@link BlockKitchenProps}.
800
896
  */
801
- interface BlockKitchenProps {
897
+ interface BlockKitchenBaseProps {
802
898
  /**
803
899
  * Workspace name shown in the preview chrome to mimic a Slack message header.
804
900
  * Cosmetic only.
@@ -813,6 +909,15 @@ interface BlockKitchenProps {
813
909
  * (URL search param, localStorage, etc).
814
910
  */
815
911
  onChange?: (blocks: SupportedBlock[]) => void;
912
+ /**
913
+ * Fires when the draft's validation verdict changes (piggybacking on the
914
+ * builder's own debounced validation pass — not on every keystroke, and
915
+ * not when the verdict is unchanged). Always scoped to the `message`
916
+ * surface, matching what Send would post. Useful in compose-only mode: a
917
+ * host-rendered CTA can disable itself on `!valid` using the exact verdict
918
+ * the issues sheet displays.
919
+ */
920
+ onValidationChange?: (summary: ValidationSummary) => void;
816
921
  /**
817
922
  * Optional hooks forwarded to the underlying `<Message>` component for
818
923
  * resolving user / channel / emoji directives. If omitted, those
@@ -830,29 +935,6 @@ interface BlockKitchenProps {
830
935
  * is never serialized into the emitted Block Kit JSON.
831
936
  */
832
937
  customEmojis?: CustomEmoji[];
833
- /**
834
- * Returns channels available to send to. Called when the send dialog opens.
835
- */
836
- loadChannels: () => Promise<ChannelOption[]>;
837
- /**
838
- * Returns whether the current user can post as themselves and, if not, an
839
- * OAuth URL to start the install flow.
840
- */
841
- loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
842
- /**
843
- * Called when the user submits the send dialog. Should return
844
- * `{ ok: true }` on success or `{ ok: false, error }` on failure.
845
- */
846
- onSend: (payload: SendPayload) => Promise<SendResult>;
847
- /**
848
- * Opt-in edit mode. When provided, the toolbar exposes an "Edit existing
849
- * message" entry: the user pastes a Slack message link, the host loads it
850
- * and returns an editability verdict ({@link EditingConfig.onLoadMessage}),
851
- * and a successful load flips the primary action from Send to "Update
852
- * message" ({@link EditingConfig.onUpdate}). Omit to keep today's send-only
853
- * behavior. The user-token path reuses {@link BlockKitchenProps.loadSendAsUserStatus}.
854
- */
855
- editing?: EditingConfig;
856
938
  /**
857
939
  * Label + accessible name for the toolbar button that opens the
858
940
  * load-message dialog (the edit-mode entry point). Defaults to
@@ -1022,5 +1104,84 @@ interface BlockKitchenProps {
1022
1104
  */
1023
1105
  theme?: BrandTheme | BrandPreset;
1024
1106
  }
1107
+ /**
1108
+ * The send integration: the trio of I/O callbacks powering the built-in
1109
+ * send dialog, plus opt-in edit mode (which reuses them). All-or-nothing by
1110
+ * design — see {@link BlockKitchenComposeOnlyProps} for the alternative.
1111
+ */
1112
+ interface BlockKitchenSendProps {
1113
+ /**
1114
+ * Returns channels available to send to. Called when the send dialog opens.
1115
+ */
1116
+ loadChannels: () => Promise<ChannelOption[]>;
1117
+ /**
1118
+ * Returns whether the current user can post as themselves and, if not, an
1119
+ * OAuth URL to start the install flow.
1120
+ */
1121
+ loadSendAsUserStatus: () => Promise<SendAsUserStatus>;
1122
+ /**
1123
+ * Called when the user submits the send dialog. Should return
1124
+ * `{ ok: true }` on success or `{ ok: false, error }` on failure.
1125
+ */
1126
+ onSend: (payload: SendPayload) => Promise<SendResult>;
1127
+ /**
1128
+ * Opt-in edit mode. When provided, the toolbar exposes an "Edit existing
1129
+ * message" entry: the user pastes a Slack message link, the host loads it
1130
+ * and returns an editability verdict ({@link EditingConfig.onLoadMessage}),
1131
+ * and a successful load flips the primary action from Send to "Update
1132
+ * message" ({@link EditingConfig.onUpdate}). Omit to keep send-only
1133
+ * behavior. The user-token path reuses {@link BlockKitchenSendProps.loadSendAsUserStatus}.
1134
+ */
1135
+ editing?: EditingConfig;
1136
+ /**
1137
+ * Renders host-defined fields inside the built-in send dialog, below the
1138
+ * channel and identity pickers. Values collected via
1139
+ * {@link SendExtrasContext.setExtras} are delivered on
1140
+ * {@link SendPayload.extras} when the user confirms. Use this when the
1141
+ * built-in flow is almost right and you need a few extra controls (a
1142
+ * cross-post toggle, a custom sender name) without rebuilding the dialog.
1143
+ */
1144
+ renderSendExtras?: (context: SendExtrasContext) => ReactNode;
1145
+ /**
1146
+ * Unavailable with the send integration: the built-in Send/Update flow
1147
+ * owns the toolbar's primary action. A host-owned
1148
+ * {@link PrimaryActionConfig} exists only in compose-only mode.
1149
+ */
1150
+ primaryAction?: undefined;
1151
+ }
1152
+ /**
1153
+ * Compose-only mode: omit the entire send integration and the builder
1154
+ * renders no send button — it becomes a pure editor. The host owns the
1155
+ * moment of commitment: mirror the draft via
1156
+ * {@link BlockKitchenBaseProps.onChange}, gate a host-rendered CTA via
1157
+ * {@link BlockKitchenBaseProps.onValidationChange}, and hand the finished
1158
+ * payload (`toSlackBlocks(draft)`) to your own audience/delivery flow.
1159
+ *
1160
+ * The explicit `undefined` members make the send trio all-or-nothing at the
1161
+ * type level: wiring only some of the three is a type error instead of a
1162
+ * silently dead send button.
1163
+ */
1164
+ interface BlockKitchenComposeOnlyProps {
1165
+ loadChannels?: undefined;
1166
+ loadSendAsUserStatus?: undefined;
1167
+ onSend?: undefined;
1168
+ /** Edit mode depends on the send integration, so it is unavailable too. */
1169
+ editing?: undefined;
1170
+ /** Extends the built-in send dialog, which doesn't exist in this mode. */
1171
+ renderSendExtras?: undefined;
1172
+ /**
1173
+ * Optional host-owned button rendered in the toolbar slot where the
1174
+ * built-in "Review & send" normally sits — e.g. "Save template" for a
1175
+ * message drafter. `onClick` receives the current draft and validation
1176
+ * verdict ({@link PrimaryActionContext}). Omit it to render no primary
1177
+ * action at all and place your CTA outside the builder.
1178
+ */
1179
+ primaryAction?: PrimaryActionConfig;
1180
+ }
1181
+ /**
1182
+ * Props for the top-level {@link BlockKitchen} component: the shared base
1183
+ * plus either the full send integration or none of it.
1184
+ */
1185
+ type BlockKitchenProps = BlockKitchenBaseProps & (BlockKitchenSendProps | BlockKitchenComposeOnlyProps);
1025
1186
 
1026
- export { type Template as $, type AlertBlock as A, type BlockKitchenProps as B, type CardBlock as C, type DataVisualizationBlock as D, type EditableVia as E, type FeedbackButtonSubobject as F, type PlanBlock as G, type HeaderLevel as H, type IconButtonElement as I, type PreviewHooks as J, type PreviewSurface as K, type LoadMessageInput as L, type MarkdownBlock as M, type PreviewTheme as N, type SendPayload as O, type PaletteSection as P, type SendResult as Q, type RecentMessage as R, type SendAsUserStatus as S, type SupportedBlock as T, type SupportedBlockType as U, type SupportedHeaderBlock as V, type TableBlock as W, type TableCell as X, type TableColumnSetting as Y, type TaskCardBlock as Z, type TaskCardStatus as _, type AlertLevel as a, type UpdatePayload as a0, type UpdateResult as a1, type UrlSourceElement as a2, type VideoBlock as a3, buildVariantById as a4, defaultPalette as a5, extraAlertVariant as a6, legacyInputVariants as a7, type BrandPreset as b, type BrandTheme as c, type BrandTokens as d, type BuilderBlock as e, type CarouselBlock as f, type CartesianChart as g, type ChannelOption as h, type Chart as i, type ChartAxisConfig as j, type ChartDataPoint as k, type ChartSeries as l, type ChartType as m, type ContainerBlock as n, type ContainerChildBlock as o, type ContextActionsBlock as p, type ContextActionsElement as q, type CustomEmoji as r, type EditingConfig as s, type FeedbackButtonsElement as t, type IconButtonIcon as u, type InputBlock as v, type LoadResult as w, type PaletteVariant as x, type PieChart as y, type PieChartSegment as z };
1187
+ export { type SupportedHeaderBlock as $, type AlertBlock as A, type BlockKitchenBaseProps as B, type CardBlock as C, type DataVisualizationBlock as D, type EditableVia as E, type FeedbackButtonSubobject as F, type PaletteVariant as G, type HeaderLevel as H, type IconButtonElement as I, type PieChart as J, type PieChartSegment as K, type LoadMessageInput as L, type MarkdownBlock as M, type PlanBlock as N, type PreviewHooks as O, type PaletteSection as P, type PreviewSurface as Q, type PreviewTheme as R, type PrimaryActionConfig as S, type PrimaryActionContext as T, type RecentMessage as U, type SendAsUserStatus as V, type SendExtrasContext as W, type SendPayload as X, type SendResult as Y, type SupportedBlock as Z, type SupportedBlockType as _, type AlertLevel as a, type TableBlock as a0, type TableCell as a1, type TableColumnSetting as a2, type TaskCardBlock as a3, type TaskCardStatus as a4, type Template as a5, type UpdatePayload as a6, type UpdateResult as a7, type UrlSourceElement as a8, type ValidationSummary as a9, type VideoBlock as aa, buildVariantById as ab, defaultPalette as ac, extraAlertVariant as ad, legacyInputVariants as ae, type BlockKitchenComposeOnlyProps as b, type BlockKitchenProps as c, type BlockKitchenSendProps as d, type BrandPreset as e, type BrandTheme as f, type BrandTokens as g, type BuilderBlock as h, type CarouselBlock as i, type CartesianChart as j, type ChannelOption as k, type Chart as l, type ChartAxisConfig as m, type ChartDataPoint as n, type ChartSeries as o, type ChartType as p, type ContainerBlock as q, type ContainerChildBlock as r, type ContextActionsBlock as s, type ContextActionsElement as t, type CustomEmoji as u, type EditingConfig as v, type FeedbackButtonsElement as w, type IconButtonIcon as x, type InputBlock as y, type LoadResult as z };
@@ -1,3 +1,3 @@
1
- export { P as PaletteSection, x as PaletteVariant, T as SupportedBlock, U as SupportedBlockType, a4 as buildVariantById, a5 as defaultPalette, a6 as extraAlertVariant, a7 as legacyInputVariants } from './palette-CKP8CK5Z.cjs';
1
+ export { P as PaletteSection, G as PaletteVariant, Z as SupportedBlock, _ as SupportedBlockType, ab as buildVariantById, ac as defaultPalette, ad as extraAlertVariant, ae as legacyInputVariants } from './palette-Duj901T6.cjs';
2
2
  import 'react';
3
3
  import 'slack-web-api-client';
package/dist/palette.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { P as PaletteSection, x as PaletteVariant, T as SupportedBlock, U as SupportedBlockType, a4 as buildVariantById, a5 as defaultPalette, a6 as extraAlertVariant, a7 as legacyInputVariants } from './palette-CKP8CK5Z.js';
1
+ export { P as PaletteSection, G as PaletteVariant, Z as SupportedBlock, _ as SupportedBlockType, ab as buildVariantById, ac as defaultPalette, ad as extraAlertVariant, ae as legacyInputVariants } from './palette-Duj901T6.js';
2
2
  import 'react';
3
3
  import 'slack-web-api-client';