@nkootstra/block-kit 0.2.0 → 0.3.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.
@@ -580,6 +580,20 @@ interface PayloadContext {
580
580
  }
581
581
  /** What `onSubmit` may return: Slack's `response_action` ack, or nothing to just close the modal. */
582
582
  type SubmitResult = ViewResponseAction | undefined | void;
583
+ /** What block-kit passes to a `linkComponent`: an anchor's props, ready to spread. */
584
+ interface LinkProps {
585
+ href: string;
586
+ className?: string;
587
+ target?: string;
588
+ rel?: string;
589
+ children?: ReactNode;
590
+ }
591
+ /** A resolved mention, as `mentionHref` gets it. */
592
+ interface MentionRef {
593
+ type: "user" | "channel" | "usergroup";
594
+ /** Slack id, e.g. `U0123ABC`, `C0123ABC` or `S0123ABC`. */
595
+ id: string;
596
+ }
583
597
  interface BlockKitContextValue {
584
598
  surface: Surface;
585
599
  /** The provider's `theme`. Popovers, tooltips and dialogs render outside its wrapper, so they set it themselves. */
@@ -594,6 +608,10 @@ interface BlockKitContextValue {
594
608
  /** Called with a `view_closed` payload when a `<Modal>`'s close (X) button is pressed. */
595
609
  onClose?: (payload: ReturnType<typeof buildViewClosedPayload>) => void;
596
610
  resolvers: Resolvers;
611
+ /** Renders links from the payload; an `<a>` unless the provider's `linkComponent` says otherwise. */
612
+ linkComponent?: ComponentType<LinkProps>;
613
+ /** The app's page for a mention, if it has one. */
614
+ mentionHref?: (mention: MentionRef) => string | undefined;
597
615
  emoji: EmojiOptions;
598
616
  /** Validation errors keyed by block_id, as returned in `response_action: "errors"`. */
599
617
  errors: Record<string, string>;
@@ -656,6 +674,20 @@ interface BlockKitProviderProps {
656
674
  /** Called whenever an input value changes, with the full `state.values`. */
657
675
  onStateChange?: (state: StateValues) => void;
658
676
  resolvers?: Resolvers;
677
+ /**
678
+ * Renders every link that comes from the payload, e.g. a router's `<Link>` for client-side
679
+ * navigation or a component that rewrites URLs: links in mrkdwn, rich text, markdown and dates,
680
+ * data tables, plan and task card sources, video titles, attachment authors and titles, and
681
+ * mentions linked by `mentionHref`. It gets an anchor's props to spread: `href`, `className`,
682
+ * `children`, and `target`/`rel` for links that open a new tab, as Slack's do.
683
+ */
684
+ linkComponent?: ComponentType<LinkProps>;
685
+ /**
686
+ * Links resolved mentions to the app's own pages: return a URL for a user, channel or user
687
+ * group, or `undefined` to leave it unlinked. Mention links open in the same tab and render
688
+ * through `linkComponent`.
689
+ */
690
+ mentionHref?: (mention: MentionRef) => string | undefined;
659
691
  emoji?: EmojiOptions;
660
692
  errors?: Record<string, string>;
661
693
  timeZone?: string;
@@ -907,5 +939,5 @@ declare const VALIDATION_MESSAGES: {
907
939
  */
908
940
  declare function validateView(blocks: readonly Json[] | readonly unknown[], state: StateValues): Record<string, string>;
909
941
  //#endregion
910
- export { BlockSuggestionPayload as $, BlockAction as A, StackedView as B, SlackAttachment as C, BlockProps as Ct, elementComponents as D, SlackReaction as E, EmojiOptions as F, SurfaceScopeProps as G, SubmitResult as H, MessageApi as I, ViewsApi as J, SurfaceScopeValue as K, MessageUpdate as L, BlockKitProvider as M, BlockKitProviderProps as N, Element as O, ElementState as P, BlockActionsPayload as Q, PayloadContext as R, MessageProps as S, Blocks as St, SlackMessageLike as T, Json as Tt, Surface as U, StateValues as V, SurfaceScope as W, useContainer as X, useBlockKit as Y, useLiveView as Z, HomeTabView as _, buildBlockSuggestionPayload as _t, Tooltip as a, MessageBlockActionsPayload as at, Message as b, blockComponents as bt, TextObject as c, PayloadIdentity as ct, ViewProps as d, SuggestionOption as dt, BuildBlockActionsPayloadOptions as et, Modal as f, ViewBlockActionsPayload as ft, HomeTabProps as g, buildBlockActionsPayload as gt, HomeTab as h, ViewResponseAction as ht, UserMentionProps as i, Container as it, BlockKitContextValue as j, ActionContext as k, AnyView as l, PayloadTeam as lt, ModalView as m, ViewLike as mt, validateView as n, BuildViewClosedPayloadOptions as nt, TooltipProps as o, MessageContainer as ot, ModalProps as p, ViewContainer as pt, UserProfile as q, UserMention as r, BuildViewSubmissionPayloadOptions as rt, Text as s, OptionsResponse as st, VALIDATION_MESSAGES as t, BuildBlockSuggestionPayloadOptions as tt, View as u, PayloadUser as ut, Mrkdwn as v, buildViewClosedPayload as vt, SlackAttachmentField as w, ElementProps as wt, MessageApp as x, Block as xt, MrkdwnProps as y, buildViewSubmissionPayload as yt, Resolvers as z };
911
- //# sourceMappingURL=index-FPjJcmn3.d.ts.map
942
+ export { useLiveView as $, BlockAction as A, PayloadContext as B, SlackAttachment as C, Block as Ct, elementComponents as D, Json as Dt, SlackReaction as E, ElementProps as Et, EmojiOptions as F, Surface as G, StackedView as H, LinkProps as I, SurfaceScopeValue as J, SurfaceScope as K, MentionRef as L, BlockKitProvider as M, BlockKitProviderProps as N, Element as O, ElementState as P, useContainer as Q, MessageApi as R, MessageProps as S, blockComponents as St, SlackMessageLike as T, BlockProps as Tt, StateValues as U, Resolvers as V, SubmitResult as W, ViewsApi as X, UserProfile as Y, useBlockKit as Z, HomeTabView as _, ViewResponseAction as _t, Tooltip as a, BuildViewSubmissionPayloadOptions as at, Message as b, buildViewClosedPayload as bt, TextObject as c, MessageContainer as ct, ViewProps as d, PayloadTeam as dt, BlockActionsPayload as et, Modal as f, PayloadUser as ft, HomeTabProps as g, ViewLike as gt, HomeTab as h, ViewContainer as ht, UserMentionProps as i, BuildViewClosedPayloadOptions as it, BlockKitContextValue as j, ActionContext as k, AnyView as l, OptionsResponse as lt, ModalView as m, ViewBlockActionsPayload as mt, validateView as n, BuildBlockActionsPayloadOptions as nt, TooltipProps as o, Container as ot, ModalProps as p, SuggestionOption as pt, SurfaceScopeProps as q, UserMention as r, BuildBlockSuggestionPayloadOptions as rt, Text as s, MessageBlockActionsPayload as st, VALIDATION_MESSAGES as t, BlockSuggestionPayload as tt, View as u, PayloadIdentity as ut, Mrkdwn as v, buildBlockActionsPayload as vt, SlackAttachmentField as w, Blocks as wt, MessageApp as x, buildViewSubmissionPayload as xt, MrkdwnProps as y, buildBlockSuggestionPayload as yt, MessageUpdate as z };
943
+ //# sourceMappingURL=index-D139DZfD.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- import { $ as BlockSuggestionPayload, A as BlockAction, B as StackedView, C as SlackAttachment, Ct as BlockProps, D as elementComponents, E as SlackReaction, F as EmojiOptions, G as SurfaceScopeProps, H as SubmitResult, I as MessageApi, J as ViewsApi, K as SurfaceScopeValue, L as MessageUpdate, M as BlockKitProvider, N as BlockKitProviderProps, O as Element, P as ElementState, Q as BlockActionsPayload, R as PayloadContext, S as MessageProps, St as Blocks, T as SlackMessageLike, Tt as Json, U as Surface, V as StateValues, W as SurfaceScope, X as useContainer, Y as useBlockKit, Z as useLiveView, _ as HomeTabView, _t as buildBlockSuggestionPayload, a as Tooltip, at as MessageBlockActionsPayload, b as Message, bt as blockComponents, c as TextObject, ct as PayloadIdentity, d as ViewProps, dt as SuggestionOption, et as BuildBlockActionsPayloadOptions, f as Modal, ft as ViewBlockActionsPayload, g as HomeTabProps, gt as buildBlockActionsPayload, h as HomeTab, ht as ViewResponseAction, i as UserMentionProps, it as Container, j as BlockKitContextValue, k as ActionContext, l as AnyView, lt as PayloadTeam, m as ModalView, mt as ViewLike, n as validateView, nt as BuildViewClosedPayloadOptions, o as TooltipProps, ot as MessageContainer, p as ModalProps, pt as ViewContainer, q as UserProfile, r as UserMention, rt as BuildViewSubmissionPayloadOptions, s as Text, st as OptionsResponse, t as VALIDATION_MESSAGES, tt as BuildBlockSuggestionPayloadOptions, u as View, ut as PayloadUser, v as Mrkdwn, vt as buildViewClosedPayload, w as SlackAttachmentField, wt as ElementProps, x as MessageApp, xt as Block, y as MrkdwnProps, yt as buildViewSubmissionPayload, z as Resolvers } from "./index-FPjJcmn3.js";
3
- export { type ActionContext, type AnyView, Block, type BlockAction, type BlockActionsPayload, type BlockKitContextValue, BlockKitProvider, type BlockKitProviderProps, type BlockProps, type BlockSuggestionPayload, Blocks, type BuildBlockActionsPayloadOptions, type BuildBlockSuggestionPayloadOptions, type BuildViewClosedPayloadOptions, type BuildViewSubmissionPayloadOptions, type Container, Element, type ElementProps, type ElementState, type EmojiOptions, HomeTab, type HomeTabProps, type HomeTabView, type Json, Message, type MessageApi, type MessageApp, type MessageBlockActionsPayload, type MessageContainer, type MessageProps, type MessageUpdate, Modal, type ModalProps, type ModalView, Mrkdwn, type MrkdwnProps, type OptionsResponse, type PayloadContext, type PayloadIdentity, type PayloadTeam, type PayloadUser, type Resolvers, type SlackAttachment, type SlackAttachmentField, type SlackMessageLike, type SlackReaction, type StackedView, type StateValues, type SubmitResult, type SuggestionOption, type Surface, SurfaceScope, type SurfaceScopeProps, type SurfaceScopeValue, Text, type TextObject, Tooltip, type TooltipProps, UserMention, type UserMentionProps, type UserProfile, VALIDATION_MESSAGES, View, type ViewBlockActionsPayload, type ViewContainer, type ViewLike, type ViewProps, type ViewResponseAction, type ViewsApi, blockComponents, buildBlockActionsPayload, buildBlockSuggestionPayload, buildViewClosedPayload, buildViewSubmissionPayload, elementComponents, useBlockKit, useContainer, useLiveView, validateView };
2
+ import { $ as useLiveView, A as BlockAction, B as PayloadContext, C as SlackAttachment, Ct as Block, D as elementComponents, Dt as Json, E as SlackReaction, Et as ElementProps, F as EmojiOptions, G as Surface, H as StackedView, I as LinkProps, J as SurfaceScopeValue, K as SurfaceScope, L as MentionRef, M as BlockKitProvider, N as BlockKitProviderProps, O as Element, P as ElementState, Q as useContainer, R as MessageApi, S as MessageProps, St as blockComponents, T as SlackMessageLike, Tt as BlockProps, U as StateValues, V as Resolvers, W as SubmitResult, X as ViewsApi, Y as UserProfile, Z as useBlockKit, _ as HomeTabView, _t as ViewResponseAction, a as Tooltip, at as BuildViewSubmissionPayloadOptions, b as Message, bt as buildViewClosedPayload, c as TextObject, ct as MessageContainer, d as ViewProps, dt as PayloadTeam, et as BlockActionsPayload, f as Modal, ft as PayloadUser, g as HomeTabProps, gt as ViewLike, h as HomeTab, ht as ViewContainer, i as UserMentionProps, it as BuildViewClosedPayloadOptions, j as BlockKitContextValue, k as ActionContext, l as AnyView, lt as OptionsResponse, m as ModalView, mt as ViewBlockActionsPayload, n as validateView, nt as BuildBlockActionsPayloadOptions, o as TooltipProps, ot as Container, p as ModalProps, pt as SuggestionOption, q as SurfaceScopeProps, r as UserMention, rt as BuildBlockSuggestionPayloadOptions, s as Text, st as MessageBlockActionsPayload, t as VALIDATION_MESSAGES, tt as BlockSuggestionPayload, u as View, ut as PayloadIdentity, v as Mrkdwn, vt as buildBlockActionsPayload, w as SlackAttachmentField, wt as Blocks, x as MessageApp, xt as buildViewSubmissionPayload, y as MrkdwnProps, yt as buildBlockSuggestionPayload, z as MessageUpdate } from "./index-D139DZfD.js";
3
+ export { type ActionContext, type AnyView, Block, type BlockAction, type BlockActionsPayload, type BlockKitContextValue, BlockKitProvider, type BlockKitProviderProps, type BlockProps, type BlockSuggestionPayload, Blocks, type BuildBlockActionsPayloadOptions, type BuildBlockSuggestionPayloadOptions, type BuildViewClosedPayloadOptions, type BuildViewSubmissionPayloadOptions, type Container, Element, type ElementProps, type ElementState, type EmojiOptions, HomeTab, type HomeTabProps, type HomeTabView, type Json, type LinkProps, type MentionRef, Message, type MessageApi, type MessageApp, type MessageBlockActionsPayload, type MessageContainer, type MessageProps, type MessageUpdate, Modal, type ModalProps, type ModalView, Mrkdwn, type MrkdwnProps, type OptionsResponse, type PayloadContext, type PayloadIdentity, type PayloadTeam, type PayloadUser, type Resolvers, type SlackAttachment, type SlackAttachmentField, type SlackMessageLike, type SlackReaction, type StackedView, type StateValues, type SubmitResult, type SuggestionOption, type Surface, SurfaceScope, type SurfaceScopeProps, type SurfaceScopeValue, Text, type TextObject, Tooltip, type TooltipProps, UserMention, type UserMentionProps, type UserProfile, VALIDATION_MESSAGES, View, type ViewBlockActionsPayload, type ViewContainer, type ViewLike, type ViewProps, type ViewResponseAction, type ViewsApi, blockComponents, buildBlockActionsPayload, buildBlockSuggestionPayload, buildViewClosedPayload, buildViewSubmissionPayload, elementComponents, useBlockKit, useContainer, useLiveView, validateView };
package/dist/index.js CHANGED
@@ -865,7 +865,7 @@ function newHash() {
865
865
  return `${Math.floor(Date.now() / 1e3)}.${Math.random().toString(36).slice(2, 10)}`;
866
866
  }
867
867
  function BlockKitProvider(props) {
868
- const { children, surface = "message", onAction, onPayload, onSubmit, onClose, onOptions, onStateChange, resolvers, emoji, errors, timeZone, identity, theme } = props;
868
+ const { children, surface = "message", onAction, onPayload, onSubmit, onClose, onOptions, onStateChange, resolvers, linkComponent, mentionHref, emoji, errors, timeZone, identity, theme } = props;
869
869
  const [state, setState] = useState({});
870
870
  const stateRef = useRef(state);
871
871
  const containerRef = useRef(void 0);
@@ -1041,6 +1041,8 @@ function BlockKitProvider(props) {
1041
1041
  onSubmit,
1042
1042
  onClose,
1043
1043
  resolvers: resolvers ?? {},
1044
+ linkComponent,
1045
+ mentionHref,
1044
1046
  emoji: emoji ?? {},
1045
1047
  errors: stackedView?.errors ?? errors ?? {},
1046
1048
  timeZone,
@@ -1061,6 +1063,8 @@ function BlockKitProvider(props) {
1061
1063
  onSubmit,
1062
1064
  onClose,
1063
1065
  resolvers,
1066
+ linkComponent,
1067
+ mentionHref,
1064
1068
  emoji,
1065
1069
  errors,
1066
1070
  timeZone,
@@ -5606,6 +5610,44 @@ function Emoji({ name, skinTone, size = 22 }) {
5606
5610
  });
5607
5611
  }
5608
5612
  //#endregion
5613
+ //#region src/Link.tsx
5614
+ /**
5615
+ * A link from the payload, rendered by the provider's `linkComponent` when it has one. Without an
5616
+ * `href` (a payload missing its URL) it stays a plain `<a>`, so the app's component always gets one.
5617
+ */
5618
+ function Link({ href, children, ...props }) {
5619
+ const { linkComponent: Component } = useBlockKit();
5620
+ if (Component && href !== void 0) return /* @__PURE__ */ jsx(Component, {
5621
+ href,
5622
+ ...props,
5623
+ children
5624
+ });
5625
+ return /* @__PURE__ */ jsx("a", {
5626
+ href,
5627
+ ...props,
5628
+ children
5629
+ });
5630
+ }
5631
+ /**
5632
+ * A resolved channel or user group mention: a link to the app's page for it when `mentionHref`
5633
+ * returns one, otherwise the plain pill. Both keep the pill's class, so they look the same.
5634
+ */
5635
+ function MentionLink({ type, id, children }) {
5636
+ const { mentionHref } = useBlockKit();
5637
+ const href = mentionHref?.({
5638
+ type,
5639
+ id
5640
+ });
5641
+ return href === void 0 ? /* @__PURE__ */ jsx("span", {
5642
+ className: "sbk-mention",
5643
+ children
5644
+ }) : /* @__PURE__ */ jsx(Link, {
5645
+ className: "sbk-mention",
5646
+ href,
5647
+ children
5648
+ });
5649
+ }
5650
+ //#endregion
5609
5651
  //#region src/UserMention.tsx
5610
5652
  function localTime(timeZone) {
5611
5653
  try {
@@ -5624,7 +5666,7 @@ function localTime(timeZone) {
5624
5666
  * `resolvers.userProfile` and falling back to the display name alone.
5625
5667
  */
5626
5668
  function UserMention({ id, name }) {
5627
- const { resolvers, theme } = useBlockKit();
5669
+ const { resolvers, theme, mentionHref } = useBlockKit();
5628
5670
  const [open, setOpen] = useState(false);
5629
5671
  const [position, setPosition] = useState(null);
5630
5672
  const anchorRef = useRef(null);
@@ -5675,6 +5717,10 @@ function UserMention({ id, name }) {
5675
5717
  }
5676
5718
  const profile = open ? resolvers.userProfile?.(id) ?? { name } : void 0;
5677
5719
  const time = profile?.timeZone ? localTime(profile.timeZone) : void 0;
5720
+ const href = profile ? mentionHref?.({
5721
+ type: "user",
5722
+ id
5723
+ }) : void 0;
5678
5724
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
5679
5725
  ref: anchorRef,
5680
5726
  className: "sbk-mention sbk-mention--user",
@@ -5714,7 +5760,11 @@ function UserMention({ id, name }) {
5714
5760
  children: [
5715
5761
  /* @__PURE__ */ jsxs("div", {
5716
5762
  className: "sbk-profile-card__name",
5717
- children: [profile.name, profile.pronouns && /* @__PURE__ */ jsx("span", {
5763
+ children: [href === void 0 ? profile.name : /* @__PURE__ */ jsx(Link, {
5764
+ className: "sbk-profile-card__name-link",
5765
+ href,
5766
+ children: profile.name
5767
+ }), profile.pronouns && /* @__PURE__ */ jsx("span", {
5718
5768
  className: "sbk-profile-card__pronouns",
5719
5769
  children: profile.pronouns
5720
5770
  })]
@@ -5774,7 +5824,7 @@ function renderNode(node, resolvers, timeZone, emojiSize) {
5774
5824
  className: "sbk-mrkdwn__quote",
5775
5825
  children: renderNodes(node.children, resolvers, timeZone, emojiSize)
5776
5826
  });
5777
- case "link": return /* @__PURE__ */ jsx("a", {
5827
+ case "link": return /* @__PURE__ */ jsx(Link, {
5778
5828
  className: "sbk-link",
5779
5829
  href: node.url,
5780
5830
  target: "_blank",
@@ -5790,8 +5840,9 @@ function renderNode(node, resolvers, timeZone, emojiSize) {
5790
5840
  }
5791
5841
  case "usergroup": {
5792
5842
  const name = resolvers.usergroup?.(node.id);
5793
- return name ? /* @__PURE__ */ jsxs("span", {
5794
- className: "sbk-mention",
5843
+ return name ? /* @__PURE__ */ jsxs(MentionLink, {
5844
+ type: "usergroup",
5845
+ id: node.id,
5795
5846
  children: ["@", name]
5796
5847
  }) : /* @__PURE__ */ jsx("span", {
5797
5848
  className: "sbk-mention--loading",
@@ -5800,8 +5851,9 @@ function renderNode(node, resolvers, timeZone, emojiSize) {
5800
5851
  }
5801
5852
  case "channel": {
5802
5853
  const name = resolvers.channel?.(node.id) ?? node.label;
5803
- return name ? /* @__PURE__ */ jsxs("span", {
5804
- className: "sbk-mention",
5854
+ return name ? /* @__PURE__ */ jsxs(MentionLink, {
5855
+ type: "channel",
5856
+ id: node.id,
5805
5857
  children: ["#", name]
5806
5858
  }) : /* @__PURE__ */ jsxs("span", {
5807
5859
  className: "sbk-mention--private",
@@ -5814,7 +5866,7 @@ function renderNode(node, resolvers, timeZone, emojiSize) {
5814
5866
  });
5815
5867
  case "date": {
5816
5868
  const text = formatSlackDate(node.timestamp, node.format, { timeZone });
5817
- return node.url ? /* @__PURE__ */ jsx("a", {
5869
+ return node.url ? /* @__PURE__ */ jsx(Link, {
5818
5870
  className: "sbk-link",
5819
5871
  href: node.url,
5820
5872
  target: "_blank",
@@ -8364,7 +8416,7 @@ function RichTextMiniSection({ section }) {
8364
8416
  function RichTextMiniLeaf({ element }) {
8365
8417
  if (element.type === "link") {
8366
8418
  const text = typeof element.text === "string" ? element.text : String(element.url ?? "");
8367
- return /* @__PURE__ */ jsx("a", {
8419
+ return /* @__PURE__ */ jsx(Link, {
8368
8420
  className: "sbk-rtmini__link",
8369
8421
  href: typeof element.url === "string" ? element.url : void 0,
8370
8422
  target: "_blank",
@@ -8399,7 +8451,7 @@ function DataTableCell({ cell }) {
8399
8451
  if (!cell || typeof cell !== "object") return null;
8400
8452
  switch (cell.type) {
8401
8453
  case "rich_text": return /* @__PURE__ */ jsx(RichTextMini, { value: cell });
8402
- case "url": return /* @__PURE__ */ jsx("a", {
8454
+ case "url": return /* @__PURE__ */ jsx(Link, {
8403
8455
  className: "sbk-rtmini__link",
8404
8456
  href: typeof cell.url === "string" ? cell.url : void 0,
8405
8457
  target: "_blank",
@@ -9712,7 +9764,7 @@ function renderInlineNode(node) {
9712
9764
  });
9713
9765
  case "link": {
9714
9766
  const link = node;
9715
- return /* @__PURE__ */ jsx("a", {
9767
+ return /* @__PURE__ */ jsx(Link, {
9716
9768
  className: "sbk-link",
9717
9769
  href: link.url,
9718
9770
  target: "_blank",
@@ -9820,6 +9872,24 @@ function DotIcon({ status }) {
9820
9872
  children: /* @__PURE__ */ jsx("path", { d: "M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0" })
9821
9873
  });
9822
9874
  }
9875
+ /** How a status reads aloud. The icons are hidden from assistive technology, so this stands in. */
9876
+ const STATUS_LABELS = {
9877
+ complete: "complete",
9878
+ in_progress: "in progress",
9879
+ pending: "pending",
9880
+ error: "failed"
9881
+ };
9882
+ /**
9883
+ * A status as text that only screen readers get, set after a title (", in progress"), so a toggle
9884
+ * or task header is announced with the state its icon shows. An unknown status says nothing.
9885
+ */
9886
+ function StatusText({ status }) {
9887
+ const label = STATUS_LABELS[status];
9888
+ return label ? /* @__PURE__ */ jsx("span", {
9889
+ className: "sbk-visually-hidden",
9890
+ children: `, ${label}`
9891
+ }) : null;
9892
+ }
9823
9893
  /** The glyph on a toggle bar (the plan's or a task_card's): check, warning or spinner. */
9824
9894
  function StatusIcon({ status }) {
9825
9895
  if (status === "complete") return /* @__PURE__ */ jsx(CheckCircleIcon, {});
@@ -9846,7 +9916,8 @@ function aggregateStatus(statuses) {
9846
9916
  /**
9847
9917
  * One step of the plan. As in Slack, a thin line joins each step's icon to the next, its details
9848
9918
  * start open, and the title is a button that hides and shows them instantly; a task with nothing
9849
- * to reveal gets a disabled header and no caret.
9919
+ * to reveal gets the same header as plain text, with no caret. The status, shown as an icon, is
9920
+ * also in the header as text for screen readers.
9850
9921
  */
9851
9922
  function TaskRow({ task }) {
9852
9923
  const [open, setOpen] = useState(true);
@@ -9867,21 +9938,28 @@ function TaskRow({ task }) {
9867
9938
  ]
9868
9939
  }), /* @__PURE__ */ jsxs("div", {
9869
9940
  className: "sbk-plan__task-content",
9870
- children: [/* @__PURE__ */ jsxs("button", {
9941
+ children: [expandable ? /* @__PURE__ */ jsxs("button", {
9871
9942
  type: "button",
9872
9943
  className: "sbk-plan__task-header",
9873
9944
  "aria-expanded": open,
9874
- "aria-disabled": expandable ? void 0 : true,
9875
- onClick: () => {
9876
- if (expandable) setOpen((value) => !value);
9877
- },
9945
+ onClick: () => setOpen((value) => !value),
9946
+ children: [
9947
+ /* @__PURE__ */ jsx("span", {
9948
+ className: "sbk-plan__task-title",
9949
+ children: task.title
9950
+ }),
9951
+ /* @__PURE__ */ jsx(StatusText, { status: task.status }),
9952
+ /* @__PURE__ */ jsx("span", {
9953
+ className: "sbk-plan__task-caret",
9954
+ children: /* @__PURE__ */ jsx(CaretIcon, { direction: open ? "down" : "right" })
9955
+ })
9956
+ ]
9957
+ }) : /* @__PURE__ */ jsxs("div", {
9958
+ className: "sbk-plan__task-header",
9878
9959
  children: [/* @__PURE__ */ jsx("span", {
9879
9960
  className: "sbk-plan__task-title",
9880
9961
  children: task.title
9881
- }), expandable ? /* @__PURE__ */ jsx("span", {
9882
- className: "sbk-plan__task-caret",
9883
- children: /* @__PURE__ */ jsx(CaretIcon, { direction: open ? "down" : "right" })
9884
- }) : null]
9962
+ }), /* @__PURE__ */ jsx(StatusText, { status: task.status })]
9885
9963
  }), open && expandable ? /* @__PURE__ */ jsxs("div", {
9886
9964
  className: "sbk-plan__task-body",
9887
9965
  children: [
@@ -9895,7 +9973,7 @@ function TaskRow({ task }) {
9895
9973
  }) : null,
9896
9974
  sources.length > 0 ? /* @__PURE__ */ jsx("ul", {
9897
9975
  className: "sbk-plan__task-sources",
9898
- children: sources.map((source, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", {
9976
+ children: sources.map((source, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Link, {
9899
9977
  className: "sbk-plan__task-source-link",
9900
9978
  href: source.url,
9901
9979
  target: "_blank",
@@ -9930,6 +10008,7 @@ function Plan({ block }) {
9930
10008
  className: "sbk-plan__pill-title",
9931
10009
  children: block.title
9932
10010
  }),
10011
+ /* @__PURE__ */ jsx(StatusText, { status }),
9933
10012
  /* @__PURE__ */ jsx("span", {
9934
10013
  className: "sbk-plan__pill-chevron",
9935
10014
  children: /* @__PURE__ */ jsx(CaretIcon, { direction: expanded ? "down" : "right" })
@@ -10032,7 +10111,7 @@ function renderLeaf(el, ctx, emojiSize, isFirst = false) {
10032
10111
  content = renderTextWithBreaks(el.text, isFirst);
10033
10112
  break;
10034
10113
  case "link":
10035
- content = /* @__PURE__ */ jsx("a", {
10114
+ content = /* @__PURE__ */ jsx(Link, {
10036
10115
  className: "sbk-link",
10037
10116
  href: el.url,
10038
10117
  target: "_blank",
@@ -10062,8 +10141,9 @@ function renderLeaf(el, ctx, emojiSize, isFirst = false) {
10062
10141
  }
10063
10142
  case "usergroup": {
10064
10143
  const name = ctx.resolvers.usergroup?.(el.usergroup_id);
10065
- content = name ? /* @__PURE__ */ jsxs("span", {
10066
- className: "sbk-mention",
10144
+ content = name ? /* @__PURE__ */ jsxs(MentionLink, {
10145
+ type: "usergroup",
10146
+ id: el.usergroup_id,
10067
10147
  children: ["@", name]
10068
10148
  }) : /* @__PURE__ */ jsx("span", {
10069
10149
  className: "sbk-mention--loading",
@@ -10073,8 +10153,9 @@ function renderLeaf(el, ctx, emojiSize, isFirst = false) {
10073
10153
  }
10074
10154
  case "channel": {
10075
10155
  const name = ctx.resolvers.channel?.(el.channel_id);
10076
- content = name ? /* @__PURE__ */ jsxs("span", {
10077
- className: "sbk-mention",
10156
+ content = name ? /* @__PURE__ */ jsxs(MentionLink, {
10157
+ type: "channel",
10158
+ id: el.channel_id,
10078
10159
  children: ["#", name]
10079
10160
  }) : /* @__PURE__ */ jsxs("span", {
10080
10161
  className: "sbk-mention--private",
@@ -10090,7 +10171,7 @@ function renderLeaf(el, ctx, emojiSize, isFirst = false) {
10090
10171
  break;
10091
10172
  case "date": {
10092
10173
  const text = formatSlackDate(el.timestamp, el.format, { timeZone: ctx.timeZone });
10093
- content = el.url ? /* @__PURE__ */ jsx("a", {
10174
+ content = el.url ? /* @__PURE__ */ jsx(Link, {
10094
10175
  className: "sbk-link",
10095
10176
  href: el.url,
10096
10177
  target: "_blank",
@@ -10164,7 +10245,7 @@ function renderTextWithBreaks(value, isFirst) {
10164
10245
  */
10165
10246
  function renderPreformattedLines(elements) {
10166
10247
  return elements.map((el, i) => {
10167
- if (el.type === "link") return /* @__PURE__ */ jsx(Fragment$1, { children: applyStyle(/* @__PURE__ */ jsx("a", {
10248
+ if (el.type === "link") return /* @__PURE__ */ jsx(Fragment$1, { children: applyStyle(/* @__PURE__ */ jsx(Link, {
10168
10249
  className: "sbk-link",
10169
10250
  href: el.url,
10170
10251
  target: "_blank",
@@ -10341,33 +10422,35 @@ function TaskCard({ block }) {
10341
10422
  const [expanded, setExpanded] = useState(false);
10342
10423
  const sources = Array.isArray(block.sources) ? block.sources : [];
10343
10424
  const expandable = Boolean(block.details || block.output || sources.length > 0);
10425
+ const pillContent = /* @__PURE__ */ jsxs("span", {
10426
+ className: "sbk-task-card__pill-content",
10427
+ children: [
10428
+ /* @__PURE__ */ jsx("span", {
10429
+ className: "sbk-task-card__pill-icon",
10430
+ children: /* @__PURE__ */ jsx(StatusIcon, { status: block.status })
10431
+ }),
10432
+ /* @__PURE__ */ jsx("span", {
10433
+ className: "sbk-task-card__pill-title",
10434
+ children: block.title
10435
+ }),
10436
+ /* @__PURE__ */ jsx(StatusText, { status: block.status }),
10437
+ expandable ? /* @__PURE__ */ jsx("span", {
10438
+ className: "sbk-task-card__pill-chevron",
10439
+ children: /* @__PURE__ */ jsx(CaretIcon, { direction: expanded ? "down" : "right" })
10440
+ }) : null
10441
+ ]
10442
+ });
10344
10443
  return /* @__PURE__ */ jsxs("div", {
10345
10444
  className: "sbk-task-card",
10346
- children: [/* @__PURE__ */ jsx("button", {
10445
+ children: [expandable ? /* @__PURE__ */ jsx("button", {
10347
10446
  type: "button",
10348
10447
  className: "sbk-task-card__pill",
10349
10448
  "aria-expanded": expanded,
10350
- "aria-disabled": expandable ? void 0 : true,
10351
- onClick: () => {
10352
- if (expandable) setExpanded((value) => !value);
10353
- },
10354
- children: /* @__PURE__ */ jsxs("span", {
10355
- className: "sbk-task-card__pill-content",
10356
- children: [
10357
- /* @__PURE__ */ jsx("span", {
10358
- className: "sbk-task-card__pill-icon",
10359
- children: /* @__PURE__ */ jsx(StatusIcon, { status: block.status })
10360
- }),
10361
- /* @__PURE__ */ jsx("span", {
10362
- className: "sbk-task-card__pill-title",
10363
- children: block.title
10364
- }),
10365
- expandable ? /* @__PURE__ */ jsx("span", {
10366
- className: "sbk-task-card__pill-chevron",
10367
- children: /* @__PURE__ */ jsx(CaretIcon, { direction: expanded ? "down" : "right" })
10368
- }) : null
10369
- ]
10370
- })
10449
+ onClick: () => setExpanded((value) => !value),
10450
+ children: pillContent
10451
+ }) : /* @__PURE__ */ jsx("div", {
10452
+ className: "sbk-task-card__pill",
10453
+ children: pillContent
10371
10454
  }), /* @__PURE__ */ jsx(Collapse, {
10372
10455
  open: expanded,
10373
10456
  children: /* @__PURE__ */ jsxs("div", {
@@ -10390,7 +10473,7 @@ function TaskCard({ block }) {
10390
10473
  children: /* @__PURE__ */ jsx(RichTextMini, { value: block.output })
10391
10474
  }) : null, sources.length > 0 ? /* @__PURE__ */ jsx("ul", {
10392
10475
  className: "sbk-task-card__sources",
10393
- children: sources.map((source, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", {
10476
+ children: sources.map((source, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Link, {
10394
10477
  className: "sbk-task-card__source-link",
10395
10478
  href: source.url,
10396
10479
  target: "_blank",
@@ -10476,7 +10559,7 @@ function Video({ block }) {
10476
10559
  }),
10477
10560
  title && /* @__PURE__ */ jsxs("div", {
10478
10561
  className: "sbk-video__title",
10479
- children: [titleUrl ? /* @__PURE__ */ jsx("a", {
10562
+ children: [titleUrl ? /* @__PURE__ */ jsx(Link, {
10480
10563
  href: titleUrl,
10481
10564
  target: "_blank",
10482
10565
  rel: "noreferrer",
@@ -10487,7 +10570,7 @@ function Video({ block }) {
10487
10570
  children: /* @__PURE__ */ jsx(CaretDownIcon, {})
10488
10571
  })]
10489
10572
  }),
10490
- /* @__PURE__ */ jsxs("a", {
10573
+ /* @__PURE__ */ jsxs(Link, {
10491
10574
  className: "sbk-video__frame",
10492
10575
  href: typeof json.video_url === "string" ? json.video_url : titleUrl,
10493
10576
  target: "_blank",
@@ -10754,7 +10837,7 @@ function Attachment({ attachment }) {
10754
10837
  className: "sbk-attachment__author-icon",
10755
10838
  src: attachment.author_icon,
10756
10839
  alt: ""
10757
- }), attachment.author_link ? /* @__PURE__ */ jsx("a", {
10840
+ }), attachment.author_link ? /* @__PURE__ */ jsx(Link, {
10758
10841
  className: "sbk-link",
10759
10842
  href: attachment.author_link,
10760
10843
  target: "_blank",
@@ -10764,7 +10847,7 @@ function Attachment({ attachment }) {
10764
10847
  }),
10765
10848
  attachment.title && /* @__PURE__ */ jsx("div", {
10766
10849
  className: "sbk-attachment__title",
10767
- children: attachment.title_link ? /* @__PURE__ */ jsx("a", {
10850
+ children: attachment.title_link ? /* @__PURE__ */ jsx(Link, {
10768
10851
  className: "sbk-link",
10769
10852
  href: attachment.title_link,
10770
10853
  target: "_blank",