@tightknitai/block-kitchen 0.8.4 → 0.8.5

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.d.cts CHANGED
@@ -1,8 +1,7 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { B as BlockKitchenProps, E as Template, q as PreviewSurface, r as PreviewTheme } from './palette-Dco-CVMi.cjs';
3
3
  export { A as AlertBlock, a as AlertLevel, b as BrandPreset, c as BrandTheme, d as BrandTokens, e as BuilderBlock, C as CardBlock, f as CarouselBlock, g as ChannelOption, h as ContextActionsBlock, i as ContextActionsElement, j as CustomEmoji, F as FeedbackButtonSubobject, k as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, l as IconButtonIcon, m as InputBlock, M as MarkdownBlock, P as PaletteSection, n as PaletteVariant, o as PlanBlock, p as PreviewHooks, S as SendAsUserStatus, s as SendPayload, t as SendResult, u as SupportedBlock, v as SupportedBlockType, w as SupportedHeaderBlock, T as TableBlock, x as TableCell, y as TableColumnSetting, z as TaskCardBlock, D as TaskCardStatus, U as UrlSourceElement, V as VideoBlock, J as defaultPalette, K as extraAlertVariant, L as legacyInputVariants } from './palette-Dco-CVMi.cjs';
4
4
  export { decodeBlocksFromString, encodeBlocksToString, toSlackBlocks } from './helpers.cjs';
5
- import 'react';
6
5
  import 'slack-web-api-client';
7
6
 
8
7
  /**
@@ -13,7 +12,7 @@ import 'slack-web-api-client';
13
12
  * @param props - {@link BlockKitchenProps}
14
13
  * @returns the rendered Block Kit Builder
15
14
  */
16
- declare function BlockKitchen(props: BlockKitchenProps): react_jsx_runtime.JSX.Element;
15
+ declare function BlockKitchen(props: BlockKitchenProps): react.JSX.Element;
17
16
 
18
17
  /**
19
18
  * Standalone, page-sized picker that displays {@link Template}s as a
@@ -50,6 +49,6 @@ declare function TemplatePicker({ templates, onSelect, surface, theme, heading,
50
49
  heading?: string;
51
50
  emptyLabel?: string;
52
51
  className?: string;
53
- }): react_jsx_runtime.JSX.Element;
52
+ }): react.JSX.Element;
54
53
 
55
54
  export { BlockKitchen, BlockKitchenProps, PreviewSurface, PreviewTheme, Template, TemplatePicker };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { B as BlockKitchenProps, E as Template, q as PreviewSurface, r as PreviewTheme } from './palette-Dco-CVMi.js';
3
3
  export { A as AlertBlock, a as AlertLevel, b as BrandPreset, c as BrandTheme, d as BrandTokens, e as BuilderBlock, C as CardBlock, f as CarouselBlock, g as ChannelOption, h as ContextActionsBlock, i as ContextActionsElement, j as CustomEmoji, F as FeedbackButtonSubobject, k as FeedbackButtonsElement, H as HeaderLevel, I as IconButtonElement, l as IconButtonIcon, m as InputBlock, M as MarkdownBlock, P as PaletteSection, n as PaletteVariant, o as PlanBlock, p as PreviewHooks, S as SendAsUserStatus, s as SendPayload, t as SendResult, u as SupportedBlock, v as SupportedBlockType, w as SupportedHeaderBlock, T as TableBlock, x as TableCell, y as TableColumnSetting, z as TaskCardBlock, D as TaskCardStatus, U as UrlSourceElement, V as VideoBlock, J as defaultPalette, K as extraAlertVariant, L as legacyInputVariants } from './palette-Dco-CVMi.js';
4
4
  export { decodeBlocksFromString, encodeBlocksToString, toSlackBlocks } from './helpers.js';
5
- import 'react';
6
5
  import 'slack-web-api-client';
7
6
 
8
7
  /**
@@ -13,7 +12,7 @@ import 'slack-web-api-client';
13
12
  * @param props - {@link BlockKitchenProps}
14
13
  * @returns the rendered Block Kit Builder
15
14
  */
16
- declare function BlockKitchen(props: BlockKitchenProps): react_jsx_runtime.JSX.Element;
15
+ declare function BlockKitchen(props: BlockKitchenProps): react.JSX.Element;
17
16
 
18
17
  /**
19
18
  * Standalone, page-sized picker that displays {@link Template}s as a
@@ -50,6 +49,6 @@ declare function TemplatePicker({ templates, onSelect, surface, theme, heading,
50
49
  heading?: string;
51
50
  emptyLabel?: string;
52
51
  className?: string;
53
- }): react_jsx_runtime.JSX.Element;
52
+ }): react.JSX.Element;
54
53
 
55
54
  export { BlockKitchen, BlockKitchenProps, PreviewSurface, PreviewTheme, Template, TemplatePicker };
package/dist/index.js CHANGED
@@ -1640,6 +1640,12 @@ function isSafeHref(value) {
1640
1640
  }
1641
1641
  return SAFE_LINK_PROTOCOLS.test(scheme);
1642
1642
  }
1643
+ function hasExplicitSafeScheme(value) {
1644
+ if (typeof value !== "string" || value.length === 0) {
1645
+ return false;
1646
+ }
1647
+ return getScheme(value) !== null && isSafeHref(value);
1648
+ }
1643
1649
  function isSafeImageSrc(value) {
1644
1650
  if (value === null || value === void 0) {
1645
1651
  return false;
@@ -5372,6 +5378,17 @@ function blockElementToPM(el, resolveEmoji) {
5372
5378
  }
5373
5379
  return null;
5374
5380
  }
5381
+ function pushTextWithHardBreaks(out, text, marks) {
5382
+ const segments = text.split("\n");
5383
+ segments.forEach((segment, i) => {
5384
+ if (i > 0) {
5385
+ out.push({ type: "hardBreak" });
5386
+ }
5387
+ if (segment) {
5388
+ out.push({ type: "text", text: segment, marks });
5389
+ }
5390
+ });
5391
+ }
5375
5392
  function inlinesToPM(inlines, resolveEmoji) {
5376
5393
  const out = [];
5377
5394
  for (const inline of inlines) {
@@ -5379,8 +5396,7 @@ function inlinesToPM(inlines, resolveEmoji) {
5379
5396
  if (!inline.text) {
5380
5397
  continue;
5381
5398
  }
5382
- const marks = styleToMarks(inline.style);
5383
- out.push({ type: "text", text: inline.text, marks });
5399
+ pushTextWithHardBreaks(out, inline.text, styleToMarks(inline.style));
5384
5400
  } else if (inline.type === "emoji") {
5385
5401
  const attrs = resolveEmoji(inline);
5386
5402
  if (!attrs.name) {
@@ -5517,6 +5533,10 @@ function proseMirrorInlinesToRichTextElements(nodes) {
5517
5533
  out.push(emoji);
5518
5534
  continue;
5519
5535
  }
5536
+ if (node.type === "hardBreak") {
5537
+ out.push({ type: "text", text: "\n" });
5538
+ continue;
5539
+ }
5520
5540
  if (node.type !== "text" || !node.text) {
5521
5541
  continue;
5522
5542
  }
@@ -6204,6 +6224,43 @@ function LossyBanner({ reasons }) {
6204
6224
  ] })
6205
6225
  ] });
6206
6226
  }
6227
+ var RICH_TEXT_INPUT_RULE_ALLOWLIST = ["bold", "italic", "strike", "code"];
6228
+ function buildRichTextExtensions() {
6229
+ return [
6230
+ StarterKit.configure({
6231
+ heading: false,
6232
+ horizontalRule: false,
6233
+ // StarterKit bundles its own Link extension (enabled by default),
6234
+ // which would register a second, unconfigured `link` mark and a
6235
+ // duplicate autolinker alongside the hardened one we add below.
6236
+ // Disable it so our single, security-configured Link is the only
6237
+ // link extension in the schema.
6238
+ link: false
6239
+ }),
6240
+ EmojiNode,
6241
+ Link.configure({
6242
+ openOnClick: false,
6243
+ autolink: true,
6244
+ defaultProtocol: "https",
6245
+ // Pin TipTap's link allowlist to the same set as our shared
6246
+ // `isSafeHref` helper. The upstream default also includes
6247
+ // ftp/cid/callto which we don't expect inside Slack content.
6248
+ protocols: ["http", "https", "mailto", "tel", "sms", "xmpp"],
6249
+ // Belt-and-suspenders: even if a downstream contributor widens
6250
+ // `protocols` later, our isSafeHref guard rejects everything
6251
+ // outside the safe-link set. setLink and toggleLink both gate
6252
+ // on this hook before applying the mark.
6253
+ isAllowedUri: (url) => isSafeHref(url),
6254
+ // Only auto-link tokens that carry an explicit, safe scheme. TipTap's
6255
+ // default would link any `host.tld` (e.g. `2.xyz`, `report.zip`,
6256
+ // `logo.png`) because the suffix is a real gTLD, which is wrong for
6257
+ // free-form Slack message text. Deliberate links can still be added
6258
+ // via the link button.
6259
+ shouldAutoLink: hasExplicitSafeScheme,
6260
+ HTMLAttributes: { rel: "noreferrer noopener", target: "_blank" }
6261
+ })
6262
+ ];
6263
+ }
6207
6264
  function RichTextWysiwygEditor({ block, onChange }) {
6208
6265
  const lastEmittedRef = useRef(null);
6209
6266
  const { byName: customByName } = useCustomEmojis();
@@ -6229,28 +6286,8 @@ function RichTextWysiwygEditor({ block, onChange }) {
6229
6286
  [onChange]
6230
6287
  );
6231
6288
  const editor = useEditor({
6232
- extensions: [
6233
- StarterKit.configure({
6234
- heading: false,
6235
- horizontalRule: false
6236
- }),
6237
- EmojiNode,
6238
- Link.configure({
6239
- openOnClick: false,
6240
- autolink: true,
6241
- defaultProtocol: "https",
6242
- // Pin TipTap's link allowlist to the same set as our shared
6243
- // `isSafeHref` helper. The upstream default also includes
6244
- // ftp/cid/callto which we don't expect inside Slack content.
6245
- protocols: ["http", "https", "mailto", "tel", "sms", "xmpp"],
6246
- // Belt-and-suspenders: even if a downstream contributor widens
6247
- // `protocols` later, our isSafeHref guard rejects everything
6248
- // outside the safe-link set. setLink and toggleLink both gate
6249
- // on this hook before applying the mark.
6250
- isAllowedUri: (url) => isSafeHref(url),
6251
- HTMLAttributes: { rel: "noreferrer noopener", target: "_blank" }
6252
- })
6253
- ],
6289
+ extensions: buildRichTextExtensions(),
6290
+ enableInputRules: RICH_TEXT_INPUT_RULE_ALLOWLIST,
6254
6291
  content: richTextToProseMirror(block, resolveEmoji),
6255
6292
  editorProps: {
6256
6293
  attributes: {