slackblock 1.0.1 → 2.0.0-beta.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/CHANGELOG.md CHANGED
@@ -1,6 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0-beta.0
4
+
5
+ ### Major Changes
6
+
7
+ - e243699: ---
8
+
9
+ React dependency removed — migrate jsxImportSource to "slackblock"
10
+
11
+ In your tsconfig.json, change:
12
+ "jsxImportSource": "react" → "jsxImportSource": "slackblock"
13
+
14
+ Remove react / react-dom from your dependencies. No JSX syntax changes required.
15
+
16
+ ***
17
+
18
+ Breaking changes:
19
+ - React peer dependency dropped; replaced with a zero-dependency custom JSX runtime
20
+ - @slack/web-api runtime dependency removed; Slack types are now bundled locally
21
+ - Node.js >=20 required (previously >=18 was tolerated in practice)
22
+ - render() now defaults to validate: 'warn', emitting console warnings when output
23
+ would violate Slack Block Kit limits (text too long, too many options, etc.).
24
+ Pass { validate: 'off' } to suppress all warnings.
25
+
26
+ New API:
27
+ - renderToBlocks(element, options?) — returns Block[] directly; use for modals and
28
+ home tabs where no <Message> wrapper is needed. Fragments are unwrapped transparently.
29
+ - renderToMessage(element, options?) — named alias for render(); both are equivalent.
30
+ - blockKitBuilderUrl(blocks) — generates a Block Kit Builder preview URL for a block array.
31
+ - escapeMrkdwn(text) — escapes Slack mrkdwn special characters in plain text strings.
32
+ - validate option on render() / renderToBlocks() / renderToMessage():
33
+ 'warn' (default) — console.warn on limit violations
34
+ 'strict' — throws SlackblockValidationError on any violation
35
+ 'off' — no validation
36
+ - SlackblockValidationError — structured error with .path, .rule, and .message fields.
37
+ - RenderOptions and ValidationMode types exported from package root.
38
+
39
+ Other improvements:
40
+ - strictNullChecks enabled; zero `any` types in source
41
+ - All public components and render functions have JSDoc
42
+ - Component reference at docs/components.md
43
+ - Validation guide at docs/validation.md
44
+ - Migration guides from jsx-slack and slack-block-builder at docs/migrating-\*.md
45
+ - 12 Block Kit JSON samples in examples/block-kit/ covering all validatable components
46
+ - Changesets-based release automation with npm provenance
47
+
48
+ ### 1.1.0
49
+
50
+ - Drop `@slack/web-api` runtime dependency; types replicated locally
51
+ - Lower Node engine requirement to `>=20` (from `>=24`)
52
+ - Add CI matrix for Node 20, 22, and 24
53
+ - Break circular transformer import via mutable registry pattern
54
+ - Extract shared `normalizeChildren` utility
55
+ - Add `"sideEffects": false` for bundler tree-shaking
56
+ - Add end-to-end pipeline tests covering all major block/input/rich-text types
57
+ - Fix publish hygiene: delete `.npmignore`, rename `prepublish` → `prepublishOnly`
58
+
3
59
  ### 1.0.1
60
+
4
61
  - Upgrade `@slack/web-api` to 7.14.1 (resolves CVE-2026-25639 via axios upgrade)
5
62
  - Bump `rollup` to 4.59.0 (resolves CVE-2026-27606)
6
63
  - Bump `minimatch` to 10.2.3+ (resolves CVE-2026-27904, CVE-2026-27903, CVE-2026-26996)
@@ -8,6 +65,7 @@
8
65
  - Resolve CVE-2026-25547 via minimatch 10.2.3+ (replaces @isaacs/brace-expansion)
9
66
 
10
67
  ### 1.0.0
68
+
11
69
  - Modernize tooling (Node 24, pnpm, tsup, Vitest, XO, Husky + lint-staged)
12
70
  - Stabilize parser/transformer routing and align output types to serialized JSON
13
71
  - Expand Block Kit coverage (header, rich_text, video, checkboxes, time/datetime pickers)
@@ -15,26 +73,34 @@
15
73
  - Add validation warnings for Slack limits
16
74
 
17
75
  ### 0.4.0
76
+
18
77
  - Allow for `<Section/>` blocks to have `null` components (useful for conditional renders)
19
78
 
20
79
  ### 0.3.1
80
+
21
81
  - Fix issue that caused an error to be thrown if a child is `null`
22
82
 
23
83
  ### 0.3.0
84
+
24
85
  - Add `Container` block to allow for better conditional rendering
25
86
 
26
87
  ### 0.2.0
88
+
27
89
  - Add ability to color messages
28
90
 
29
91
  ### 0.1.0
92
+
30
93
  - Add all additional props to the top level `<Message/>` component
31
94
  - Remove `token` / `channel` prop since they are out of scope for the component
32
95
 
33
96
  ### 0.0.4
97
+
34
98
  - Fix issue where `<Actions/>` block would have incorrect type
35
99
 
36
100
  ### 0.0.3
101
+
37
102
  - Fix issue where `<Button/>` element was outputting `actionId` when it should be `action_id`
38
103
 
39
104
  ### 0.0.1 / 0.0.2
105
+
40
106
  - Initial release
package/README.md CHANGED
@@ -1,95 +1,254 @@
1
1
  # SlackBlock
2
- JSX-based Slack message renderer
3
2
 
4
- [![CircleCI](https://circleci.com/gh/kolyaventuri/block/tree/master.svg?style=svg)](https://circleci.com/gh/kolyaventuri/block/tree/master)
3
+ JSX-based Slack Block Kit message renderer
5
4
 
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.
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/)
8
9
 
9
- ## Getting started
10
- Install the library with your package manager, for example `pnpm add slackblock`.
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
11
 
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 */
12
+ ---
17
13
 
18
- const text = <Text plainText>Hello</Text>;
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
+ ---
35
+
36
+ ## TypeScript setup
37
+
38
+ Add the following options to your `tsconfig.json`:
39
+
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
54
+
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