slackblock 1.1.0 → 2.0.0-beta.1

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/CHANGELOG.md CHANGED
@@ -1,6 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0-beta.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2dc3b09: Fixes included files
8
+
9
+ ## 2.0.0-beta.0
10
+
11
+ ### Major Changes
12
+
13
+ - e243699: ---
14
+
15
+ React dependency removed — migrate jsxImportSource to "slackblock"
16
+
17
+ In your tsconfig.json, change:
18
+ "jsxImportSource": "react" → "jsxImportSource": "slackblock"
19
+
20
+ Remove react / react-dom from your dependencies. No JSX syntax changes required.
21
+
22
+ ***
23
+
24
+ Breaking changes:
25
+ - React peer dependency dropped; replaced with a zero-dependency custom JSX runtime
26
+ - @slack/web-api runtime dependency removed; Slack types are now bundled locally
27
+ - Node.js >=20 required (previously >=18 was tolerated in practice)
28
+ - render() now defaults to validate: 'warn', emitting console warnings when output
29
+ would violate Slack Block Kit limits (text too long, too many options, etc.).
30
+ Pass { validate: 'off' } to suppress all warnings.
31
+
32
+ New API:
33
+ - renderToBlocks(element, options?) — returns Block[] directly; use for modals and
34
+ home tabs where no <Message> wrapper is needed. Fragments are unwrapped transparently.
35
+ - renderToMessage(element, options?) — named alias for render(); both are equivalent.
36
+ - blockKitBuilderUrl(blocks) — generates a Block Kit Builder preview URL for a block array.
37
+ - escapeMrkdwn(text) — escapes Slack mrkdwn special characters in plain text strings.
38
+ - validate option on render() / renderToBlocks() / renderToMessage():
39
+ 'warn' (default) — console.warn on limit violations
40
+ 'strict' — throws SlackblockValidationError on any violation
41
+ 'off' — no validation
42
+ - SlackblockValidationError — structured error with .path, .rule, and .message fields.
43
+ - RenderOptions and ValidationMode types exported from package root.
44
+
45
+ Other improvements:
46
+ - strictNullChecks enabled; zero `any` types in source
47
+ - All public components and render functions have JSDoc
48
+ - Component reference at docs/components.md
49
+ - Validation guide at docs/validation.md
50
+ - Migration guides from jsx-slack and slack-block-builder at docs/migrating-\*.md
51
+ - 12 Block Kit JSON samples in examples/block-kit/ covering all validatable components
52
+ - Changesets-based release automation with npm provenance
53
+
3
54
  ### 1.1.0
55
+
4
56
  - Drop `@slack/web-api` runtime dependency; types replicated locally
5
57
  - Lower Node engine requirement to `>=20` (from `>=24`)
6
58
  - Add CI matrix for Node 20, 22, and 24
@@ -11,6 +63,7 @@
11
63
  - Fix publish hygiene: delete `.npmignore`, rename `prepublish` → `prepublishOnly`
12
64
 
13
65
  ### 1.0.1
66
+
14
67
  - Upgrade `@slack/web-api` to 7.14.1 (resolves CVE-2026-25639 via axios upgrade)
15
68
  - Bump `rollup` to 4.59.0 (resolves CVE-2026-27606)
16
69
  - Bump `minimatch` to 10.2.3+ (resolves CVE-2026-27904, CVE-2026-27903, CVE-2026-26996)
@@ -18,6 +71,7 @@
18
71
  - Resolve CVE-2026-25547 via minimatch 10.2.3+ (replaces @isaacs/brace-expansion)
19
72
 
20
73
  ### 1.0.0
74
+
21
75
  - Modernize tooling (Node 24, pnpm, tsup, Vitest, XO, Husky + lint-staged)
22
76
  - Stabilize parser/transformer routing and align output types to serialized JSON
23
77
  - Expand Block Kit coverage (header, rich_text, video, checkboxes, time/datetime pickers)
@@ -25,26 +79,34 @@
25
79
  - Add validation warnings for Slack limits
26
80
 
27
81
  ### 0.4.0
82
+
28
83
  - Allow for `<Section/>` blocks to have `null` components (useful for conditional renders)
29
84
 
30
85
  ### 0.3.1
86
+
31
87
  - Fix issue that caused an error to be thrown if a child is `null`
32
88
 
33
89
  ### 0.3.0
90
+
34
91
  - Add `Container` block to allow for better conditional rendering
35
92
 
36
93
  ### 0.2.0
94
+
37
95
  - Add ability to color messages
38
96
 
39
97
  ### 0.1.0
98
+
40
99
  - Add all additional props to the top level `<Message/>` component
41
100
  - Remove `token` / `channel` prop since they are out of scope for the component
42
101
 
43
102
  ### 0.0.4
103
+
44
104
  - Fix issue where `<Actions/>` block would have incorrect type
45
105
 
46
106
  ### 0.0.3
107
+
47
108
  - Fix issue where `<Button/>` element was outputting `actionId` when it should be `action_id`
48
109
 
49
110
  ### 0.0.1 / 0.0.2
111
+
50
112
  - Initial release
package/README.md CHANGED
@@ -1,95 +1,254 @@
1
1
  # SlackBlock
2
- JSX-based Slack message renderer
2
+
3
+ JSX-based Slack Block Kit message renderer
3
4
 
4
5
  [![CI](https://github.com/kolyaventuri/block/actions/workflows/ci.yml/badge.svg)](https://github.com/kolyaventuri/block/actions/workflows/ci.yml)
6
+ [![npm](https://img.shields.io/npm/v/slackblock)](https://www.npmjs.com/package/slackblock)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+ [![TypeScript](https://img.shields.io/badge/types-included-blue)](https://www.typescriptlang.org/)
9
+
10
+ Build Slack messages with JSX. No React required — SlackBlock ships its own lightweight JSX runtime. Write your blocks as components, call `render()`, and post the result straight to the Slack API.
11
+
12
+ ---
13
+
14
+ ## Compatibility
15
+
16
+ | | Supported |
17
+ |---|---|
18
+ | Node.js | `>= 20` |
19
+ | TypeScript | `>= 5.0` |
20
+ | React | Not required — uses a built-in JSX runtime |
21
+
22
+ ---
23
+
24
+ ## Install
25
+
26
+ ```sh
27
+ npm install slackblock
28
+ # or
29
+ pnpm add slackblock
30
+ # or
31
+ yarn add slackblock
32
+ ```
33
+
34
+ ---
5
35
 
6
- ## What
7
- A message builder for Slack bots, using JSX with a React-compatible API. Generally follows the [Block Kit](https://api.slack.com/block-kit) naming and options.
36
+ ## TypeScript setup
8
37
 
9
- ## Getting started
10
- Install the library with your package manager, for example `pnpm add slackblock`.
38
+ Add the following options to your `tsconfig.json`:
11
39
 
12
- - Import the renderer with `import render from 'slackblock';`
13
- - Import the top level `Message` block, along with any blocks you need from `import { Message, Section, Text, ... } from 'slackblock/block';`
14
- - Build your message!
15
- ```jsx
16
- /* example */
40
+ ```json
41
+ {
42
+ "compilerOptions": {
43
+ "jsx": "react-jsx",
44
+ "jsxImportSource": "slackblock"
45
+ }
46
+ }
47
+ ```
48
+
49
+ This tells TypeScript to use SlackBlock's built-in JSX runtime instead of React.
50
+
51
+ ---
52
+
53
+ ## Quick start
17
54
 
18
- const text = <Text plainText>Hello</Text>;
55
+ ```tsx
56
+ import render from 'slackblock';
57
+ import { Message, Section, Text, Header, Divider, Actions, Button } from 'slackblock/block';
19
58
 
20
59
  const message = render(
21
- <Message>
22
- <Section text={text}>
23
- <Text>Some *message* for _Slack_.</Text>
24
- </Section>
60
+ <Message text="Deployment complete">
61
+ <Header text="Deploy finished" />
62
+ <Section text={<Text>Service *api* deployed to production.</Text>} />
63
+ <Divider />
64
+ <Actions>
65
+ <Button actionId="view_logs" url="https://example.com/logs">View logs</Button>
66
+ <Button actionId="rollback" style="danger">Rollback</Button>
67
+ </Actions>
25
68
  </Message>
26
69
  );
27
70
 
28
- console.log(message);
29
- /*
30
- {
31
- "blocks": [
32
- {
33
- "type": "section",
34
- "text": {
35
- "type": "plain_text",
36
- "text": "Hello"
37
- },
38
- "fields": [
39
- {
40
- "type": "mrkdwn",
41
- "text": "Some *message* for _Slack_."
42
- }
43
- ]
44
- }
45
- ]
71
+ // message is ready to post — just add your channel:
72
+ await slackClient.chat.postMessage({ channel: '#deploys', ...message });
73
+ ```
74
+
75
+ The rendered output is a plain object you can spread directly into `chat.postMessage`.
76
+
77
+ ---
78
+
79
+ ## API
80
+
81
+ ### `render(element, options?)` — default export
82
+
83
+ Renders a `<Message>` tree to a full Slack message payload.
84
+
85
+ ```ts
86
+ import render from 'slackblock';
87
+
88
+ const message = render(<Message text="Hello">...</Message>);
89
+ // → { text: "Hello", blocks: [...] }
90
+ ```
91
+
92
+ The top-level element must be a `<Message>`. Throws a `TypeError` otherwise.
93
+
94
+ ### `renderToMessage(element, options?)`
95
+
96
+ Named alias for `render`. Use whichever reads more naturally in your codebase.
97
+
98
+ ```ts
99
+ import { renderToMessage } from 'slackblock';
100
+ ```
101
+
102
+ ### `renderToBlocks(element, options?)`
103
+
104
+ Renders any JSX element (or fragment) directly to a `Block[]` array, without a `<Message>` wrapper. Useful for modals and home tabs, which accept a `blocks` array rather than a full message payload.
105
+
106
+ ```tsx
107
+ import { renderToBlocks } from 'slackblock';
108
+ import { Section, Text } from 'slackblock/block';
109
+
110
+ const blocks = renderToBlocks(
111
+ <>
112
+ <Section text={<Text>Hello from a modal</Text>} />
113
+ </>
114
+ );
115
+ // → [{ type: "section", text: { type: "mrkdwn", text: "Hello from a modal" } }]
116
+ ```
117
+
118
+ ### `blockKitBuilderUrl(blocks)`
119
+
120
+ Returns a [Block Kit Builder](https://app.slack.com/block-kit-builder) URL for the given blocks. Open it in a browser to preview layout and interactivity during development.
121
+
122
+ ```ts
123
+ import { renderToBlocks, blockKitBuilderUrl } from 'slackblock';
124
+
125
+ const blocks = renderToBlocks(<Section text={<Text>Hello</Text>} />);
126
+ console.log(blockKitBuilderUrl(blocks));
127
+ // → https://app.slack.com/block-kit-builder#{"blocks":[...]}
128
+ ```
129
+
130
+ ### `escapeMrkdwn(text)`
131
+
132
+ Escapes Slack mrkdwn special characters (`*`, `_`, `~`, `` ` ``, `>`, `&`, `<`, `>`) in a string. Use this when inserting untrusted user content into a mrkdwn text field.
133
+
134
+ ```ts
135
+ import { escapeMrkdwn } from 'slackblock';
136
+
137
+ const safe = escapeMrkdwn(userInput); // "hello *world*" → "hello \*world\*"
138
+ ```
139
+
140
+ ### Options
141
+
142
+ Both `render` / `renderToMessage` / `renderToBlocks` accept an optional `options` object:
143
+
144
+ ```ts
145
+ type RenderOptions = {
146
+ validate?: 'off' | 'warn' | 'strict'; // default: 'warn'
147
+ };
148
+ ```
149
+
150
+ See [docs/validation.md](docs/validation.md) for details.
151
+
152
+ ---
153
+
154
+ ## Validation
155
+
156
+ SlackBlock validates your message against Slack's documented limits and required fields. The `validate` option controls what happens when a violation is detected:
157
+
158
+ | Mode | Behavior |
159
+ |------|----------|
160
+ | `'warn'` (default) | Logs a warning to `console.warn`; rendering continues |
161
+ | `'strict'` | Throws a `SlackblockValidationError` |
162
+ | `'off'` | No validation |
163
+
164
+ ```tsx
165
+ // Throw on any violation — recommended for tests
166
+ const message = render(<Message>...</Message>, { validate: 'strict' });
167
+ ```
168
+
169
+ ```ts
170
+ import { SlackblockValidationError } from 'slackblock';
171
+
172
+ try {
173
+ render(<Message>...</Message>, { validate: 'strict' });
174
+ } catch (err) {
175
+ if (err instanceof SlackblockValidationError) {
176
+ console.error(err.message); // "Message > Header: Header text exceeds 150 characters."
177
+ console.error(err.path); // ["Message", "Header"]
178
+ console.error(err.rule); // "too-long"
46
179
  }
47
- */
180
+ }
181
+ ```
182
+
183
+ See [docs/validation.md](docs/validation.md) for the full rule reference.
184
+
185
+ ---
186
+
187
+ ## Conventions
188
+
189
+ **camelCase props** — Slack's API uses `snake_case`; SlackBlock uses `camelCase` props that map to the correct API fields:
190
+
191
+ ```tsx
192
+ // Slack API: { "block_id": "...", "action_id": "..." }
193
+ <Button blockId="my_block" actionId="my_action">Click me</Button>
194
+ ```
195
+
196
+ **Children as fields** — When Slack expects an array (e.g. select options, section fields), pass them as JSX children:
197
+
198
+ ```tsx
199
+ <Select placeholder="Pick one" actionId="pick">
200
+ <Option value="a">Option A</Option>
201
+ <Option value="b">Option B</Option>
202
+ </Select>
48
203
  ```
49
204
 
50
- There is a `<Container/>` component, which allows for conditional rendering by passing through the children as though it didn't exist.
51
- ```jsx
52
- const elem = (
205
+ **Conditional rendering** Use `<Container>` to wrap elements that may or may not render, or use standard JS short-circuit expressions:
206
+
207
+ ```tsx
208
+ <Message text="Hello">
209
+ {isAdmin && <Section text={<Text>Admin panel</Text>} />}
53
210
  <Container>
54
- <Text>Test</Text>
211
+ {items.map(item => <Section key={item.id} text={<Text>{item.name}</Text>} />)}
55
212
  </Container>
56
- );
213
+ </Message>
214
+ ```
57
215
 
58
- const shouldDoThing = ...;
216
+ **Color / attachment** — Setting `color` on `<Message>` wraps blocks in a legacy attachment for the colored left border. `color` accepts any hex value or Slack named colors:
59
217
 
60
- const message = render(
61
- <Message>
62
- {shouldDoThing && elem}
63
- </Message>
64
- );
218
+ ```tsx
219
+ <Message text="Alert" color="#ff0000">
220
+ <Section text={<Text>Something went wrong.</Text>} />
221
+ </Message>
65
222
  ```
66
223
 
67
- ## Things to note
68
- - The outputted message only needs to have your `token` and desired `channel_id` added, and it will be ready to send to the slack API!
69
- - React is a peer dependency and used only as a JSX runtime (no DOM renderer required).
70
- - There is limited input validation (for example, date/time formats and select constraints). Warnings are emitted for common Slack limits (IDs, text lengths, block counts). Non-recognized blocks will be ignored, but Slack will be the ultimate decider if your message is valid. Validation is on the roadmap.
71
- - There is currently almost no documentation. This will be resolved, but in general...
72
- - If a Slack message wants a property in format `foo_bar`, you will add it as a `fooBar` property in your message(ex: `<Element fooBar='blah'/>`)
73
- - If a component such as a `<Section/>` wants fields which seem like children, they probably are for the sake of rendering. This is especially important with `select` menus, as your `<Option/>` tags will be passed as children
74
- - ex:
75
- ```jsx
76
- <Select ...>
77
- <Option value="val">text</Option>
78
- <Option value="val2">text2</Option>
79
- </Select>
80
- ```
224
+ ---
225
+
226
+ ## Supported components
227
+
228
+ **Layout blocks:** `Message`, `Section`, `Actions`, `Context`, `Divider`, `File`, `Header`, `Image` (block), `Input`, `RichText`, `Video`
229
+
230
+ **Block elements:** `Text`, `Image` (element), `Button`, `Confirmation`
231
+
232
+ **Input elements:** `Select`, `Option`, `OptionGroup`, `Overflow`, `Checkboxes`, `RadioGroup`, `TextInput`, `DatePicker`, `TimePicker`, `DateTimePicker`
233
+
234
+ **Rich text helpers:** `RichTextSection`, `RichTextList`, `RichTextQuote`, `RichTextPreformatted`, `RichTextText`, `RichTextLink`, `RichTextUser`, `RichTextChannel`, `RichTextEmoji`, `RichTextDate`, `RichTextBroadcast`, `RichTextUserGroup`
235
+
236
+ **Utility:** `Container`
237
+
238
+ See [docs/components.md](docs/components.md) for the full props reference.
81
239
 
82
- ## Supported blocks and elements
83
- Blocks: `Message` (top-level), `Section`, `Actions`, `Context`, `Divider`, `File`, `Image` (block), `Header`, `Input`, `RichText`, `Video`.
240
+ ---
84
241
 
85
- Elements: `Text`, `Image` (element), `Button`, `Confirmation`, `Select`, `Option`, `OptionGroup`, `Overflow`, `RadioGroup`, `Checkboxes`, `DatePicker`, `TimePicker`, `DateTimePicker`, `TextInput`.
242
+ ## Further reading
86
243
 
87
- Rich text helpers: `RichTextSection`, `RichTextList`, `RichTextQuote`, `RichTextPreformatted`, `RichTextText`, `RichTextLink`, `RichTextUser`, `RichTextChannel`, `RichTextEmoji`, `RichTextDate`, `RichTextBroadcast`, `RichTextUserGroup`.
244
+ - [Component reference](docs/components.md) all components with props tables
245
+ - [Validation guide](docs/validation.md) — validation modes and error handling
246
+ - [Migrating from jsx-slack](docs/migrating-from-jsx-slack.md)
247
+ - [Migrating from slack-block-builder](docs/migrating-from-slack-block-builder.md)
248
+ - [Slack Block Kit reference](https://api.slack.com/block-kit)
88
249
 
89
- Field support highlights: `select` filters/min query length, `option` description, `focusOnLoad` for inputs, `dispatchActionConfig` for text inputs, and `accessibilityLabel` on buttons.
250
+ ---
90
251
 
252
+ ## License
91
253
 
92
- ## TODO
93
- - Add real documentation
94
- - Add validation
95
- - Add richer rich_text validation
254
+ MIT