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/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
- var __create = Object.create;
1
+ "use strict";
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
7
  var __export = (target, all) => {
8
8
  for (var name in all)
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,53 +16,69 @@ var __copyProps = (to, from, except, desc) => {
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
28
21
 
29
22
  // src/index.ts
30
23
  var src_exports = {};
31
24
  __export(src_exports, {
32
- default: () => renderer_default
25
+ SlackblockValidationError: () => SlackblockValidationError,
26
+ blockKitBuilderUrl: () => blockKitBuilderUrl,
27
+ default: () => renderer_default,
28
+ escapeMrkdwn: () => escapeMrkdwn,
29
+ renderToBlocks: () => renderToBlocks,
30
+ renderToMessage: () => render
33
31
  });
34
32
  module.exports = __toCommonJS(src_exports);
35
33
 
36
- // src/utils/get-type.ts
37
- var getType = (element) => {
38
- if (typeof element === "string") {
39
- return "string";
34
+ // src/errors.ts
35
+ var SlackblockValidationError = class extends Error {
36
+ constructor(message, path, rule) {
37
+ super(`${path}: ${message}`);
38
+ __publicField(this, "path");
39
+ __publicField(this, "rule");
40
+ this.name = "SlackblockValidationError";
41
+ this.path = path;
42
+ this.rule = rule;
40
43
  }
41
- if (element === null || element === void 0 || typeof element === "boolean") {
42
- return "null";
43
- }
44
- if (Array.isArray(element)) {
45
- throw new TypeError("Cannot type arrays");
44
+ };
45
+
46
+ // src/utils/validation-context.ts
47
+ var context = {
48
+ mode: "warn",
49
+ path: []
50
+ };
51
+ var initContext = (mode) => {
52
+ context.mode = mode;
53
+ context.path = [];
54
+ };
55
+ var pushPath = (segment) => {
56
+ context.path.push(segment);
57
+ };
58
+ var popPath = () => {
59
+ context.path.pop();
60
+ };
61
+ var getPath = () => context.path.join(" > ");
62
+ var report = (message, rule) => {
63
+ if (context.mode === "off") {
64
+ return;
46
65
  }
47
- const { type } = element;
48
- if (typeof type === "string") {
49
- return type;
66
+ const path = getPath();
67
+ if (context.mode === "warn") {
68
+ console.warn(`[slackblock] ${path}: ${message}`);
69
+ return;
50
70
  }
51
- const { slackType, displayName, name } = type;
52
- return slackType || displayName || name || type;
71
+ throw new SlackblockValidationError(message, path, rule);
53
72
  };
54
- var get_type_default = getType;
55
73
 
56
74
  // src/utils/validation.ts
57
- var warn = (message) => {
58
- console.warn(message);
59
- };
75
+ var toKebab = (name) => name.replaceAll(/([A-Z])/g, "-$1").toLowerCase();
60
76
  var warnIfTooLong = (name, value, max) => {
61
77
  if (!value) {
62
78
  return;
63
79
  }
64
80
  if (value.length > max) {
65
- warn(`${name} exceeds ${max} characters.`);
81
+ report(`${name} exceeds ${max} characters.`, "value-too-long");
66
82
  }
67
83
  };
68
84
  var warnIfTooMany = (name, values, max) => {
@@ -70,20 +86,18 @@ var warnIfTooMany = (name, values, max) => {
70
86
  return;
71
87
  }
72
88
  if (values.length > max) {
73
- warn(`${name} exceeds ${max} items.`);
89
+ report(`${name} exceeds ${max} items.`, "too-many-items");
90
+ }
91
+ };
92
+ var requireField = (fieldName, value) => {
93
+ if (value === void 0 || value === null || value === "") {
94
+ report(`${fieldName} is required.`, `${toKebab(fieldName)}-required`);
74
95
  }
75
96
  };
76
97
 
77
98
  // src/transformers/block/text.ts
78
99
  var transformText = (element) => {
79
- const {
80
- props: {
81
- plainText,
82
- children,
83
- emoji,
84
- verbatim
85
- }
86
- } = element;
100
+ const { plainText, children, emoji, verbatim } = element.props;
87
101
  const res = {
88
102
  type: plainText ? "plain_text" : "mrkdwn",
89
103
  text: children
@@ -101,40 +115,116 @@ var transformText = (element) => {
101
115
  };
102
116
  var text_default = transformText;
103
117
 
104
- // src/transformers/block/confirmation.tsx
105
- var import_react2 = __toESM(require("react"));
118
+ // src/utils/get-type.ts
119
+ var getType = (element) => {
120
+ var _a, _b;
121
+ if (typeof element === "string") {
122
+ return "string";
123
+ }
124
+ if (element === null || element === void 0 || typeof element === "boolean") {
125
+ return "null";
126
+ }
127
+ if (Array.isArray(element)) {
128
+ throw new TypeError("Cannot type arrays");
129
+ }
130
+ const { type } = element;
131
+ if (typeof type === "string") {
132
+ return type;
133
+ }
134
+ const { slackType, displayName, name } = type;
135
+ return (_b = (_a = slackType != null ? slackType : displayName) != null ? _a : name) != null ? _b : type;
136
+ };
137
+ var get_type_default = getType;
138
+
139
+ // src/transformers/registry.ts
140
+ var Transformers = {};
141
+ var registry_default = Transformers;
142
+
143
+ // src/transformers/transform.ts
144
+ var transform = (element) => {
145
+ const type = get_type_default(element);
146
+ if (!registry_default[type]) {
147
+ report(`No transformer for component type '${type}'.`, "unknown-type");
148
+ return {};
149
+ }
150
+ pushPath(type);
151
+ try {
152
+ return registry_default[type](element);
153
+ } finally {
154
+ popPath();
155
+ }
156
+ };
106
157
 
107
158
  // src/components/block/text.tsx
108
- var import_react = __toESM(require("react"));
109
- var Text = class extends import_react.default.Component {
159
+ var Text = class {
110
160
  };
111
- Text.slackType = "Text";
161
+ __publicField(Text, "slackType", "Text");
162
+
163
+ // src/constants/limits.ts
164
+ var MAX_BLOCKS = 50;
165
+ var MAX_HEADER_TEXT = 150;
166
+ var MAX_SECTION_FIELDS = 10;
167
+ var MAX_SECTION_FIELD_TEXT = 2e3;
168
+ var MAX_ACTIONS_ELEMENTS = 25;
169
+ var MAX_CONTEXT_ELEMENTS = 10;
170
+ var MAX_CONFIRM_TITLE = 100;
171
+ var MAX_CONFIRM_TEXT = 300;
172
+ var MAX_BUTTON_TEXT = 75;
173
+ var MAX_BUTTON_VALUE = 2e3;
174
+ var MAX_OPTION_TEXT = 75;
175
+ var MAX_OPTION_VALUE = 150;
176
+ var MAX_OPTION_DESCRIPTION = 75;
177
+ var MAX_OPTION_URL = 3e3;
178
+ var MAX_OPTION_GROUP_LABEL = 75;
179
+ var MAX_OPTION_GROUP_OPTIONS = 100;
180
+ var MAX_IMAGE_URL = 3e3;
181
+ var MAX_IMAGE_ALT_TEXT = 2e3;
182
+ var MAX_IMAGE_TITLE = 2e3;
183
+ var MAX_VIDEO_DESCRIPTION = 200;
184
+ var MAX_BLOCK_ID_LENGTH = 255;
185
+ var MAX_MESSAGE_TEXT = 4e4;
186
+ var RECOMMENDED_MESSAGE_TEXT = 4e3;
187
+ var MAX_ACTION_ID_LENGTH = 255;
188
+ var MAX_PLACEHOLDER_LENGTH = 150;
189
+
190
+ // src/jsx-runtime.ts
191
+ function jsx(type, props) {
192
+ const { children } = props;
193
+ return {
194
+ type,
195
+ props,
196
+ children: Array.isArray(children) ? children : children === void 0 ? [] : [children]
197
+ };
198
+ }
112
199
 
113
200
  // src/transformers/block/confirmation.tsx
114
201
  var transformConfirmation = (child) => {
115
202
  const { title, confirm, deny, children } = child.props;
203
+ warnIfTooLong("Confirm title", title, MAX_CONFIRM_TITLE);
204
+ const text = transform(children);
205
+ warnIfTooLong("Confirm text", text.text, MAX_CONFIRM_TEXT);
116
206
  const res = {
117
- title: transform(/* @__PURE__ */ import_react2.default.createElement(Text, { plainText: true }, title)),
118
- text: transform(children),
119
- confirm: transform(/* @__PURE__ */ import_react2.default.createElement(Text, { plainText: true }, confirm)),
120
- deny: transform(/* @__PURE__ */ import_react2.default.createElement(Text, { plainText: true }, deny))
207
+ title: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title })),
208
+ text,
209
+ confirm: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: confirm })),
210
+ deny: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: deny }))
121
211
  };
122
212
  return res;
123
213
  };
124
214
  var confirmation_default = transformConfirmation;
125
215
 
126
216
  // src/transformers/block/button.tsx
127
- var import_react3 = __toESM(require("react"));
128
217
  var transformButton = (child) => {
129
218
  const { actionId, children, url, value, style, confirm, accessibilityLabel } = child.props;
130
- warnIfTooLong("Button action_id", actionId, 255);
219
+ requireField("actionId", actionId);
220
+ warnIfTooLong("Button action_id", actionId, MAX_ACTION_ID_LENGTH);
131
221
  if (typeof children === "string") {
132
- warnIfTooLong("Button text", children, 75);
222
+ warnIfTooLong("Button text", children, MAX_BUTTON_TEXT);
133
223
  }
134
- warnIfTooLong("Button value", value, 2e3);
224
+ warnIfTooLong("Button value", value, MAX_BUTTON_VALUE);
135
225
  const res = {
136
226
  type: "button",
137
- text: transform(/* @__PURE__ */ import_react3.default.createElement(Text, { plainText: true }, children)),
227
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children })),
138
228
  action_id: actionId
139
229
  };
140
230
  if (url) {
@@ -167,7 +257,7 @@ var transformImage = (child) => {
167
257
  };
168
258
  var image_default = transformImage;
169
259
 
170
- // src/transformers/layout/container.ts
260
+ // src/utils/normalize-children.ts
171
261
  var normalizeChildren = (children) => {
172
262
  const result = [];
173
263
  const stack = Array.isArray(children) ? [...children] : [children];
@@ -184,24 +274,20 @@ var normalizeChildren = (children) => {
184
274
  }
185
275
  return result;
186
276
  };
277
+ var normalize_children_default = normalizeChildren;
278
+
279
+ // src/transformers/layout/container.ts
187
280
  var transformContainer = (child) => {
188
281
  const { children } = child.props;
189
- const elements = normalizeChildren(children);
282
+ const elements = normalize_children_default(children);
190
283
  return elements.map((element) => transform(element));
191
284
  };
192
285
  var container_default = transformContainer;
193
286
 
194
287
  // src/transformers/layout/section.ts
195
288
  var transformSection = (element) => {
196
- const {
197
- props: {
198
- text,
199
- blockId,
200
- children,
201
- accessory
202
- }
203
- } = element;
204
- warnIfTooLong("block_id", blockId, 255);
289
+ const { text, blockId, children, accessory } = element.props;
290
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
205
291
  const res = {
206
292
  type: "section",
207
293
  text: transform(text)
@@ -221,10 +307,11 @@ var transformSection = (element) => {
221
307
  for (const field of fields) {
222
308
  if (field) {
223
309
  const t = transform(field);
310
+ warnIfTooLong("Section field text", t.text, MAX_SECTION_FIELD_TEXT);
224
311
  res.fields.push(t);
225
312
  }
226
313
  }
227
- warnIfTooMany("Section fields", res.fields, 10);
314
+ warnIfTooMany("Section fields", res.fields, MAX_SECTION_FIELDS);
228
315
  }
229
316
  return res;
230
317
  };
@@ -233,7 +320,7 @@ var section_default = transformSection;
233
320
  // src/transformers/layout/actions.ts
234
321
  var transformActions = (child) => {
235
322
  const { children, blockId } = child.props;
236
- warnIfTooLong("block_id", blockId, 255);
323
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
237
324
  let elements = children;
238
325
  if (!Array.isArray(elements)) {
239
326
  elements = [elements];
@@ -245,7 +332,7 @@ var transformActions = (child) => {
245
332
  if (blockId) {
246
333
  res.block_id = blockId;
247
334
  }
248
- warnIfTooMany("Actions elements", res.elements, 25);
335
+ warnIfTooMany("Actions elements", res.elements, MAX_ACTIONS_ELEMENTS);
249
336
  return res;
250
337
  };
251
338
  var actions_default = transformActions;
@@ -253,7 +340,7 @@ var actions_default = transformActions;
253
340
  // src/transformers/layout/context.ts
254
341
  var transformContext = (child) => {
255
342
  const { children, blockId } = child.props;
256
- warnIfTooLong("block_id", blockId, 255);
343
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
257
344
  let elements = children;
258
345
  if (!Array.isArray(elements)) {
259
346
  elements = [elements];
@@ -265,7 +352,7 @@ var transformContext = (child) => {
265
352
  if (blockId) {
266
353
  res.block_id = blockId;
267
354
  }
268
- warnIfTooMany("Context elements", res.elements, 10);
355
+ warnIfTooMany("Context elements", res.elements, MAX_CONTEXT_ELEMENTS);
269
356
  return res;
270
357
  };
271
358
  var context_default = transformContext;
@@ -299,13 +386,14 @@ var transformFile = (child) => {
299
386
  var file_default = transformFile;
300
387
 
301
388
  // src/transformers/layout/header.tsx
302
- var import_react4 = __toESM(require("react"));
303
389
  var transformHeader = (child) => {
304
390
  const { text, blockId, emoji } = child.props;
305
- warnIfTooLong("block_id", blockId, 255);
391
+ requireField("text", text);
392
+ warnIfTooLong("Header text", text, MAX_HEADER_TEXT);
393
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
306
394
  const res = {
307
395
  type: "header",
308
- text: transform(/* @__PURE__ */ import_react4.default.createElement(Text, { plainText: true, emoji }, text))
396
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, emoji, children: text }))
309
397
  };
310
398
  if (blockId) {
311
399
  res.block_id = blockId;
@@ -315,17 +403,19 @@ var transformHeader = (child) => {
315
403
  var header_default = transformHeader;
316
404
 
317
405
  // src/transformers/layout/image.tsx
318
- var import_react5 = __toESM(require("react"));
319
406
  var transformImageLayout = (child) => {
320
407
  const { url, alt, title, blockId } = child.props;
321
- warnIfTooLong("block_id", blockId, 255);
408
+ warnIfTooLong("Image image_url", url, MAX_IMAGE_URL);
409
+ warnIfTooLong("Image alt_text", alt, MAX_IMAGE_ALT_TEXT);
410
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
322
411
  const res = {
323
412
  type: "image",
324
413
  image_url: url,
325
414
  alt_text: alt
326
415
  };
327
416
  if (title) {
328
- res.title = transform(/* @__PURE__ */ import_react5.default.createElement(Text, { plainText: true }, title));
417
+ warnIfTooLong("Image title", title, MAX_IMAGE_TITLE);
418
+ res.title = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title }));
329
419
  }
330
420
  if (blockId) {
331
421
  res.block_id = blockId;
@@ -335,17 +425,16 @@ var transformImageLayout = (child) => {
335
425
  var image_default2 = transformImageLayout;
336
426
 
337
427
  // src/transformers/layout/input.tsx
338
- var import_react6 = __toESM(require("react"));
339
428
  var transformInput = (child) => {
340
429
  const { label, element, hint, optional, blockId } = child.props;
341
430
  warnIfTooLong("block_id", blockId, 255);
342
431
  const res = {
343
432
  type: "input",
344
- label: transform(/* @__PURE__ */ import_react6.default.createElement(Text, { plainText: true }, label)),
433
+ label: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: label })),
345
434
  element: transform(element)
346
435
  };
347
436
  if (hint) {
348
- res.hint = transform(/* @__PURE__ */ import_react6.default.createElement(Text, { plainText: true }, hint));
437
+ res.hint = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: hint }));
349
438
  }
350
439
  if (optional) {
351
440
  res.optional = true;
@@ -412,7 +501,6 @@ var transformRichText = (child) => {
412
501
  var rich_text_default = transformRichText;
413
502
 
414
503
  // src/transformers/layout/video.tsx
415
- var import_react7 = __toESM(require("react"));
416
504
  var transformVideo = (child) => {
417
505
  const {
418
506
  title,
@@ -426,10 +514,10 @@ var transformVideo = (child) => {
426
514
  providerIconUrl,
427
515
  blockId
428
516
  } = child.props;
429
- warnIfTooLong("block_id", blockId, 255);
517
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
430
518
  const res = {
431
519
  type: "video",
432
- title: transform(/* @__PURE__ */ import_react7.default.createElement(Text, { plainText: true }, title)),
520
+ title: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title })),
433
521
  video_url: videoUrl,
434
522
  thumbnail_url: thumbnailUrl,
435
523
  alt_text: altText
@@ -438,7 +526,8 @@ var transformVideo = (child) => {
438
526
  res.title_url = titleUrl;
439
527
  }
440
528
  if (description) {
441
- res.description = transform(/* @__PURE__ */ import_react7.default.createElement(Text, { plainText: true }, description));
529
+ warnIfTooLong("Video description", description, MAX_VIDEO_DESCRIPTION);
530
+ res.description = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: description }));
442
531
  }
443
532
  if (authorName) {
444
533
  res.author_name = authorName;
@@ -457,7 +546,6 @@ var transformVideo = (child) => {
457
546
  var video_default = transformVideo;
458
547
 
459
548
  // src/transformers/input/text.tsx
460
- var import_react8 = __toESM(require("react"));
461
549
  var transformTextInput = (child) => {
462
550
  const {
463
551
  actionId,
@@ -478,7 +566,7 @@ var transformTextInput = (child) => {
478
566
  action_id: actionId
479
567
  };
480
568
  if (placeholder) {
481
- res.placeholder = transform(/* @__PURE__ */ import_react8.default.createElement(Text, { plainText: true }, placeholder));
569
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
482
570
  }
483
571
  if (initial) {
484
572
  res.initial_value = initial;
@@ -507,7 +595,8 @@ var text_default2 = transformTextInput;
507
595
  // src/transformers/input/date-time-picker.ts
508
596
  var transformDateTimePicker = (child) => {
509
597
  const { actionId, initialDateTime, confirm, focusOnLoad } = child.props;
510
- warnIfTooLong("DateTimePicker action_id", actionId, 255);
598
+ requireField("actionId", actionId);
599
+ warnIfTooLong("DateTimePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
511
600
  const res = {
512
601
  type: "datetimepicker",
513
602
  action_id: actionId
@@ -529,7 +618,6 @@ var transformDateTimePicker = (child) => {
529
618
  var date_time_picker_default = transformDateTimePicker;
530
619
 
531
620
  // src/transformers/input/date-picker.tsx
532
- var import_react9 = __toESM(require("react"));
533
621
  var isValidDateString = (value) => {
534
622
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
535
623
  if (!match) {
@@ -546,20 +634,21 @@ var isValidDateString = (value) => {
546
634
  };
547
635
  var transformDatePicker = (child) => {
548
636
  const { actionId, placeholder, initialDate, confirm, focusOnLoad } = child.props;
549
- warnIfTooLong("DatePicker action_id", actionId, 255);
637
+ requireField("actionId", actionId);
638
+ warnIfTooLong("DatePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
550
639
  if (placeholder) {
551
- warnIfTooLong("DatePicker placeholder", placeholder, 150);
640
+ warnIfTooLong("DatePicker placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
552
641
  }
553
642
  const res = {
554
643
  type: "datepicker",
555
644
  action_id: actionId
556
645
  };
557
646
  if (placeholder) {
558
- res.placeholder = transform(/* @__PURE__ */ import_react9.default.createElement(Text, { plainText: true }, placeholder));
647
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
559
648
  }
560
649
  if (initialDate) {
561
650
  if (!isValidDateString(initialDate)) {
562
- throw new Error("Date must be valid and in format YYYY-MM-DD.");
651
+ report("Date must be valid and in format YYYY-MM-DD.", "invalid-date-format");
563
652
  }
564
653
  res.initial_date = initialDate;
565
654
  }
@@ -576,7 +665,8 @@ var date_picker_default = transformDatePicker;
576
665
  // src/transformers/input/checkboxes.ts
577
666
  var transformCheckboxes = (child) => {
578
667
  const { actionId, children, initialOptions, confirm, focusOnLoad } = child.props;
579
- warnIfTooLong("Checkboxes action_id", actionId, 255);
668
+ requireField("actionId", actionId);
669
+ warnIfTooLong("Checkboxes action_id", actionId, MAX_ACTION_ID_LENGTH);
580
670
  let elements = children;
581
671
  if (!Array.isArray(elements)) {
582
672
  elements = [elements];
@@ -599,11 +689,7 @@ var transformCheckboxes = (child) => {
599
689
  };
600
690
  var checkboxes_default = transformCheckboxes;
601
691
 
602
- // src/transformers/input/select.tsx
603
- var import_react11 = __toESM(require("react"));
604
-
605
692
  // src/components/input/select.tsx
606
- var import_react10 = __toESM(require("react"));
607
693
  var selectTypes = {
608
694
  STATIC: "static",
609
695
  EXTERNAL: "external",
@@ -611,9 +697,6 @@ var selectTypes = {
611
697
  CONVERSATION: "conversation",
612
698
  CHANNEL: "channel"
613
699
  };
614
- var Select = class extends import_react10.default.Component {
615
- };
616
- Select.slackType = "Select";
617
700
 
618
701
  // src/transformers/input/select.tsx
619
702
  var OPTION = "Option";
@@ -643,11 +726,9 @@ var assignStaticOptions = (elements, result) => {
643
726
  throw new TypeError("Only allowed types are Option OR OptionGroup");
644
727
  }
645
728
  if (elementType === OPTION) {
646
- const options = elements;
647
- result.options = options.map((element) => transform(element));
729
+ result.options = elements.map((element) => transform(element));
648
730
  } else if (elementType === OPTION_GROUP) {
649
- const optionGroups = elements;
650
- result.option_groups = optionGroups.map((element) => transform(element));
731
+ result.option_groups = elements.map((element) => transform(element));
651
732
  }
652
733
  };
653
734
  var applyInitialSelections = (type, isMulti, result, initialValues) => {
@@ -718,11 +799,13 @@ var transformSelect = (child) => {
718
799
  } = child.props;
719
800
  const type = typeProperty != null ? typeProperty : selectTypes.STATIC;
720
801
  const typeString = `${multi ? MULTI_PREFIX : ""}${types[type]}`;
721
- warnIfTooLong("Select action_id", actionId, 255);
722
- warnIfTooLong("Select placeholder", placeholder, 150);
802
+ requireField("actionId", actionId);
803
+ requireField("placeholder", placeholder);
804
+ warnIfTooLong("Select action_id", actionId, MAX_ACTION_ID_LENGTH);
805
+ warnIfTooLong("Select placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
723
806
  const result = {
724
807
  type: typeString,
725
- placeholder: transform(/* @__PURE__ */ import_react11.default.createElement(Text, { plainText: true }, placeholder)),
808
+ placeholder: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder })),
726
809
  action_id: actionId
727
810
  };
728
811
  const elements = normalizeElements(children);
@@ -775,18 +858,19 @@ var transformSelect = (child) => {
775
858
  var select_default = transformSelect;
776
859
 
777
860
  // src/transformers/input/option.tsx
778
- var import_react12 = __toESM(require("react"));
779
861
  var transformOption = (child) => {
780
862
  const { children: text, value, url, description } = child.props;
781
- warnIfTooLong("Option text", text, 75);
782
- warnIfTooLong("Option value", value, 75);
783
- warnIfTooLong("Option description", description, 75);
863
+ requireField("value", value);
864
+ warnIfTooLong("Option text", text, MAX_OPTION_TEXT);
865
+ warnIfTooLong("Option value", value, MAX_OPTION_VALUE);
866
+ warnIfTooLong("Option description", description, MAX_OPTION_DESCRIPTION);
867
+ warnIfTooLong("Option url", url, MAX_OPTION_URL);
784
868
  const res = {
785
- text: transform(/* @__PURE__ */ import_react12.default.createElement(Text, { plainText: true }, text)),
869
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: text })),
786
870
  value
787
871
  };
788
872
  if (description) {
789
- res.description = transform(/* @__PURE__ */ import_react12.default.createElement(Text, { plainText: true }, description));
873
+ res.description = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: description }));
790
874
  }
791
875
  if (url) {
792
876
  res.url = url;
@@ -796,16 +880,16 @@ var transformOption = (child) => {
796
880
  var option_default = transformOption;
797
881
 
798
882
  // src/transformers/input/option-group.tsx
799
- var import_react13 = __toESM(require("react"));
800
883
  var transformOptionGroup = (child) => {
801
884
  const { label, children } = child.props;
802
- warnIfTooLong("OptionGroup label", label, 75);
885
+ warnIfTooLong("OptionGroup label", label, MAX_OPTION_GROUP_LABEL);
803
886
  let options = children;
804
887
  if (!Array.isArray(options)) {
805
888
  options = [options];
806
889
  }
890
+ warnIfTooMany("OptionGroup options", options, MAX_OPTION_GROUP_OPTIONS);
807
891
  return {
808
- label: transform(/* @__PURE__ */ import_react13.default.createElement(Text, { plainText: true }, label)),
892
+ label: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: label })),
809
893
  options: options.map((option) => transform(option))
810
894
  };
811
895
  };
@@ -834,7 +918,8 @@ var overflow_default = transformOverflow;
834
918
  // src/transformers/input/radio-group.ts
835
919
  var transformRadioGroup = (child) => {
836
920
  const { actionId, children, initialOption, confirm, focusOnLoad } = child.props;
837
- warnIfTooLong("RadioGroup action_id", actionId, 255);
921
+ requireField("actionId", actionId);
922
+ warnIfTooLong("RadioGroup action_id", actionId, MAX_ACTION_ID_LENGTH);
838
923
  let elements = children;
839
924
  if (!Array.isArray(elements)) {
840
925
  elements = [elements];
@@ -858,7 +943,6 @@ var transformRadioGroup = (child) => {
858
943
  var radio_group_default = transformRadioGroup;
859
944
 
860
945
  // src/transformers/input/time-picker.tsx
861
- var import_react14 = __toESM(require("react"));
862
946
  var isValidTimeString = (value) => {
863
947
  const match = /^(\d{2}):(\d{2})$/.exec(value);
864
948
  if (!match) {
@@ -870,20 +954,21 @@ var isValidTimeString = (value) => {
870
954
  };
871
955
  var transformTimePicker = (child) => {
872
956
  const { actionId, placeholder, initialTime, confirm, focusOnLoad } = child.props;
873
- warnIfTooLong("TimePicker action_id", actionId, 255);
957
+ requireField("actionId", actionId);
958
+ warnIfTooLong("TimePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
874
959
  if (placeholder) {
875
- warnIfTooLong("TimePicker placeholder", placeholder, 150);
960
+ warnIfTooLong("TimePicker placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
876
961
  }
877
962
  const res = {
878
963
  type: "timepicker",
879
964
  action_id: actionId
880
965
  };
881
966
  if (placeholder) {
882
- res.placeholder = transform(/* @__PURE__ */ import_react14.default.createElement(Text, { plainText: true }, placeholder));
967
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
883
968
  }
884
969
  if (initialTime) {
885
970
  if (!isValidTimeString(initialTime)) {
886
- throw new Error("Time must be valid and in format HH:MM.");
971
+ report("Time must be valid and in format HH:MM.", "invalid-time-format");
887
972
  }
888
973
  res.initial_time = initialTime;
889
974
  }
@@ -1008,17 +1093,13 @@ var emoji_default = transformRichTextEmoji;
1008
1093
 
1009
1094
  // src/transformers/rich-text/date.ts
1010
1095
  var transformRichTextDate = (child) => {
1011
- const { timestamp, format, fallback, link } = child.props;
1012
- const res = {
1096
+ const { timestamp, format, fallback } = child.props;
1097
+ return {
1013
1098
  type: "date",
1014
1099
  timestamp,
1015
1100
  format,
1016
1101
  fallback
1017
1102
  };
1018
- if (link) {
1019
- res.link = link;
1020
- }
1021
- return res;
1022
1103
  };
1023
1104
  var date_default = transformRichTextDate;
1024
1105
 
@@ -1043,7 +1124,7 @@ var transformRichTextUserGroup = (child) => {
1043
1124
  var user_group_default = transformRichTextUserGroup;
1044
1125
 
1045
1126
  // src/transformers/index.ts
1046
- var Transformers = {
1127
+ Object.assign(registry_default, {
1047
1128
  Container: container_default,
1048
1129
  Section: section_default,
1049
1130
  Actions: actions_default,
@@ -1081,33 +1162,9 @@ var Transformers = {
1081
1162
  RichTextDate: date_default,
1082
1163
  RichTextBroadcast: broadcast_default,
1083
1164
  RichTextUserGroup: user_group_default
1084
- };
1085
- var transformers_default = Transformers;
1086
- var transform = (element) => {
1087
- const type = get_type_default(element);
1088
- if (!Transformers[type]) {
1089
- throw new Error(`No transformer exists for type '${type}'`);
1090
- }
1091
- return Transformers[type](element);
1092
- };
1165
+ });
1093
1166
 
1094
1167
  // src/parser/index.ts
1095
- var normalizeChildren2 = (children) => {
1096
- const result = [];
1097
- const stack = Array.isArray(children) ? [...children] : [children];
1098
- while (stack.length > 0) {
1099
- const child = stack.shift();
1100
- if (child === null || child === void 0 || typeof child === "boolean") {
1101
- continue;
1102
- }
1103
- if (Array.isArray(child)) {
1104
- stack.unshift(...child);
1105
- continue;
1106
- }
1107
- result.push(child);
1108
- }
1109
- return result;
1110
- };
1111
1168
  var appendTransformed = (value, blocks) => {
1112
1169
  if (value === null || value === void 0 || typeof value === "boolean") {
1113
1170
  return;
@@ -1124,15 +1181,20 @@ var parseChildren = (children) => {
1124
1181
  if (typeof children === "string") {
1125
1182
  return { text: children };
1126
1183
  }
1127
- const normalizedChildren = normalizeChildren2(children);
1184
+ const normalizedChildren = normalize_children_default(children);
1128
1185
  const transformedBlocks = [];
1129
1186
  for (const child of normalizedChildren) {
1130
1187
  const type = get_type_default(child);
1131
- const transformer = transformers_default[type];
1188
+ const transformer = registry_default[type];
1132
1189
  if (transformer) {
1133
- appendTransformed(transformer(child), transformedBlocks);
1190
+ pushPath(type);
1191
+ try {
1192
+ appendTransformed(transformer(child), transformedBlocks);
1193
+ } finally {
1194
+ popPath();
1195
+ }
1134
1196
  } else if (type !== "null") {
1135
- console.warn(`No transformer for child type '${type}' exists and will be ignored.`);
1197
+ report(`No transformer for component type '${type}'.`, "unknown-type");
1136
1198
  }
1137
1199
  }
1138
1200
  if (transformedBlocks.length === 0) {
@@ -1143,23 +1205,14 @@ var parseChildren = (children) => {
1143
1205
  var parser_default = parseChildren;
1144
1206
 
1145
1207
  // src/renderer/index.ts
1146
- var render = (element) => {
1147
- const { props: properties = {} } = element || {};
1148
- const typeName = get_type_default(element);
1149
- if (typeName !== "Message") {
1150
- throw new TypeError("Provided top-level element must be a Message type.");
1151
- }
1152
- if (!properties.children) {
1153
- throw new Error("Cannot render a Message with no children.");
1154
- }
1155
- const json = { ...parser_default(properties.children) };
1156
- if (properties.replyTo) {
1157
- json.thread_ts = properties.replyTo;
1158
- }
1159
- if (properties.markdown !== void 0) {
1160
- json.mrkdwn = properties.markdown;
1161
- }
1162
- json.text = properties.text || "";
1208
+ var renderToBlocks = (element, options) => {
1209
+ var _a, _b;
1210
+ initContext((_a = options == null ? void 0 : options.validate) != null ? _a : "warn");
1211
+ const child = typeof element === "object" && element !== null && !Array.isArray(element) && element.type === "fragment" ? element.props.children : element;
1212
+ const result = parser_default(child);
1213
+ return (_b = result.blocks) != null ? _b : [];
1214
+ };
1215
+ var applyMessageMetadata = (json, properties) => {
1163
1216
  if (properties.iconEmoji) {
1164
1217
  json.icon_emoji = properties.iconEmoji;
1165
1218
  }
@@ -1184,20 +1237,66 @@ var render = (element) => {
1184
1237
  if (properties.unfurlMedia !== void 0) {
1185
1238
  json.unfurl_media = properties.unfurlMedia;
1186
1239
  }
1187
- if (properties.color && json.blocks) {
1188
- json.attachments = [
1189
- {
1190
- fallback: json.text,
1191
- color: properties.color,
1192
- blocks: json.blocks
1193
- }
1194
- ];
1195
- delete json.blocks;
1240
+ };
1241
+ var render = (element, options) => {
1242
+ var _a, _b;
1243
+ initContext((_a = options == null ? void 0 : options.validate) != null ? _a : "warn");
1244
+ const properties = element.props;
1245
+ const typeName = get_type_default(element);
1246
+ if (typeName !== "Message") {
1247
+ throw new TypeError("Provided top-level element must be a Message type.");
1196
1248
  }
1197
- if (json.blocks) {
1198
- warnIfTooMany("Message blocks", json.blocks, 50);
1249
+ if (!properties.children) {
1250
+ throw new Error("Cannot render a Message with no children.");
1251
+ }
1252
+ pushPath("Message");
1253
+ let json;
1254
+ try {
1255
+ json = { ...parser_default(properties.children) };
1256
+ if (properties.replyTo) {
1257
+ json.thread_ts = properties.replyTo;
1258
+ }
1259
+ if (properties.markdown !== void 0) {
1260
+ json.mrkdwn = properties.markdown;
1261
+ }
1262
+ json.text = (_b = properties.text) != null ? _b : "";
1263
+ if (properties.text && properties.text.length > MAX_MESSAGE_TEXT) {
1264
+ warnIfTooLong(`Message text (Slack will truncate beyond ${MAX_MESSAGE_TEXT} chars)`, properties.text, MAX_MESSAGE_TEXT);
1265
+ } else if (properties.text) {
1266
+ warnIfTooLong("Message text (recommended max for best results)", properties.text, RECOMMENDED_MESSAGE_TEXT);
1267
+ }
1268
+ applyMessageMetadata(json, properties);
1269
+ if (properties.color && json.blocks) {
1270
+ json.attachments = [
1271
+ {
1272
+ fallback: json.text,
1273
+ color: properties.color,
1274
+ blocks: json.blocks
1275
+ }
1276
+ ];
1277
+ delete json.blocks;
1278
+ }
1279
+ if (json.blocks) {
1280
+ warnIfTooMany("Message blocks", json.blocks, MAX_BLOCKS);
1281
+ }
1282
+ } finally {
1283
+ popPath();
1199
1284
  }
1200
1285
  return json;
1201
1286
  };
1202
1287
  var renderer_default = render;
1288
+
1289
+ // src/utils/escape-mrkdwn.ts
1290
+ var escapeMrkdwn = (text) => text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll(/[*_~`]/g, "\u200B$&");
1291
+
1292
+ // src/utils/block-kit-builder.ts
1293
+ var blockKitBuilderUrl = (blocks) => `https://app.slack.com/block-kit-builder#${JSON.stringify({ blocks })}`;
1294
+ // Annotate the CommonJS export names for ESM import in node:
1295
+ 0 && (module.exports = {
1296
+ SlackblockValidationError,
1297
+ blockKitBuilderUrl,
1298
+ escapeMrkdwn,
1299
+ renderToBlocks,
1300
+ renderToMessage
1301
+ });
1203
1302
  //# sourceMappingURL=index.cjs.map