@nkootstra/block-kit 0.3.2 → 0.3.3

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.js CHANGED
@@ -6325,6 +6325,19 @@ const InputBlockContext = createContext(false);
6325
6325
  function useInInputBlock() {
6326
6326
  return useContext(InputBlockContext);
6327
6327
  }
6328
+ /** The id of the error shown under an `input` block's element, while it has one. */
6329
+ const InputErrorContext = createContext(void 0);
6330
+ /**
6331
+ * Props for the element's focusable control: an `input` block with an error marks it invalid,
6332
+ * which also gives it Slack's red focus ring, and describes it with the error text.
6333
+ */
6334
+ function useInvalidProps() {
6335
+ const errorId = useContext(InputErrorContext);
6336
+ return errorId ? {
6337
+ "aria-invalid": true,
6338
+ "aria-describedby": errorId
6339
+ } : {};
6340
+ }
6328
6341
  //#endregion
6329
6342
  //#region src/elements/Popover.tsx
6330
6343
  /** Space between the anchor and the popover, as in Slack's menus. */
@@ -6419,6 +6432,7 @@ function DatePicker({ element, blockId }) {
6419
6432
  const [open, setOpen] = useState(false);
6420
6433
  const rootRef = useRef(null);
6421
6434
  const inputRef = useFocusOnLoad(element);
6435
+ const invalid = useInvalidProps();
6422
6436
  const loadFocus = useRef(element.focus_on_load === true);
6423
6437
  const actionId = element.action_id ?? "";
6424
6438
  useEffect(() => {
@@ -6472,6 +6486,7 @@ function DatePicker({ element, blockId }) {
6472
6486
  placeholder: element.placeholder?.text ?? "Select a date",
6473
6487
  "aria-haspopup": "dialog",
6474
6488
  "aria-expanded": open,
6489
+ ...invalid,
6475
6490
  ref: inputRef,
6476
6491
  onFocus: () => {
6477
6492
  if (loadFocus.current) loadFocus.current = false;
@@ -7097,6 +7112,7 @@ function RichTextInput({ element, blockId }) {
7097
7112
  const { setValue, dispatch } = useBlockKit();
7098
7113
  const ref = useRef(null);
7099
7114
  useFocusOnLoad(element, ref);
7115
+ const invalid = useInvalidProps();
7100
7116
  const actionId = element.action_id ?? "";
7101
7117
  const initialText = fromRichText(element.initial_value);
7102
7118
  useEffect(() => {
@@ -7127,6 +7143,7 @@ function RichTextInput({ element, blockId }) {
7127
7143
  suppressContentEditableWarning: true,
7128
7144
  role: "textbox",
7129
7145
  "aria-multiline": "true",
7146
+ ...invalid,
7130
7147
  "aria-label": element.placeholder?.text ?? actionId,
7131
7148
  "data-placeholder": element.placeholder?.text,
7132
7149
  onInput,
@@ -7209,6 +7226,7 @@ function Select({ element, blockId }) {
7209
7226
  const rootRef = useRef(null);
7210
7227
  const triggerRef = useRef(null);
7211
7228
  useFocusOnLoad(element, triggerRef);
7229
+ const invalid = useInvalidProps();
7212
7230
  const listRef = useRef(null);
7213
7231
  const remote = source === "external" && loadOptions !== void 0;
7214
7232
  const minQueryLength = element.min_query_length ?? DEFAULT_MIN_QUERY_LENGTH;
@@ -7367,6 +7385,7 @@ function Select({ element, blockId }) {
7367
7385
  onClick: () => setOpen((o) => !o),
7368
7386
  "aria-haspopup": "listbox",
7369
7387
  "aria-expanded": open,
7388
+ ...invalid,
7370
7389
  children: [multi ? items.length > 0 ? /* @__PURE__ */ jsx("span", {
7371
7390
  className: "sbk-select__chips",
7372
7391
  children: items.map((item) => /* @__PURE__ */ jsxs("span", {
@@ -7386,6 +7405,12 @@ function Select({ element, blockId }) {
7386
7405
  e.stopPropagation();
7387
7406
  removeItem(item.id);
7388
7407
  },
7408
+ onKeyDown: (e) => {
7409
+ if (e.key !== "Enter" && e.key !== " ") return;
7410
+ e.preventDefault();
7411
+ e.stopPropagation();
7412
+ removeItem(item.id);
7413
+ },
7389
7414
  children: /* @__PURE__ */ jsx(CloseIcon, {})
7390
7415
  })]
7391
7416
  }, item.id))
@@ -7496,6 +7521,7 @@ function TextInput({ element, blockId }) {
7496
7521
  const { setValue, dispatch, surface } = useBlockKit();
7497
7522
  const sizeClass = surface === "message" ? "" : " sbk-text-input--medium";
7498
7523
  const [value, setLocalValue] = useState(element.initial_value ?? "");
7524
+ const invalid = useInvalidProps();
7499
7525
  const focusRef = useFocusOnLoad(element);
7500
7526
  const actionId = element.action_id ?? "";
7501
7527
  const dispatchEnabled = element.__dispatchAction === true;
@@ -7539,7 +7565,8 @@ function TextInput({ element, blockId }) {
7539
7565
  placeholder,
7540
7566
  onKeyDown,
7541
7567
  ref: focusRef,
7542
- "aria-label": element.action_id
7568
+ "aria-label": element.action_id,
7569
+ ...invalid
7543
7570
  };
7544
7571
  const leadingIcon = element.type === "email_text_input" ? /* @__PURE__ */ jsx(EmailIcon, { className: "sbk-text-input__icon" }) : element.type === "url_text_input" ? /* @__PURE__ */ jsx(LinkGlyphIcon, { className: "sbk-text-input__icon" }) : null;
7545
7572
  if (element.multiline) return /* @__PURE__ */ jsx("textarea", {
@@ -7583,6 +7610,7 @@ function TimePicker({ element, blockId }) {
7583
7610
  const rootRef = useRef(null);
7584
7611
  const triggerRef = useRef(null);
7585
7612
  useFocusOnLoad(element, triggerRef);
7613
+ const invalid = useInvalidProps();
7586
7614
  const listRef = useRef(null);
7587
7615
  const actionId = element.action_id ?? "";
7588
7616
  useEffect(() => {
@@ -7634,6 +7662,7 @@ function TimePicker({ element, blockId }) {
7634
7662
  onClick: () => setOpen((o) => !o),
7635
7663
  "aria-haspopup": "listbox",
7636
7664
  "aria-expanded": open,
7665
+ ...invalid,
7637
7666
  children: [
7638
7667
  /* @__PURE__ */ jsx(ClockIcon, { className: "sbk-timepicker__icon" }),
7639
7668
  /* @__PURE__ */ jsx("span", {
@@ -9491,6 +9520,7 @@ function Input({ block, blockId }) {
9491
9520
  __dispatchAction: block.dispatch_action === true
9492
9521
  };
9493
9522
  const error = errors[blockId];
9523
+ const errorId = useId();
9494
9524
  const showDispatchHint = dispatchHint(block);
9495
9525
  const showOptional = block.optional && surface !== "message";
9496
9526
  return /* @__PURE__ */ jsxs("div", {
@@ -9507,13 +9537,16 @@ function Input({ block, blockId }) {
9507
9537
  className: "sbk-input__element",
9508
9538
  children: /* @__PURE__ */ jsx(InputBlockContext.Provider, {
9509
9539
  value: true,
9510
- children: block.dispatch_action === true ? /* @__PURE__ */ jsx(Element, {
9511
- element,
9512
- blockId
9513
- }) : /* @__PURE__ */ jsx(SuppressActions, { children: /* @__PURE__ */ jsx(Element, {
9514
- element,
9515
- blockId
9516
- }) })
9540
+ children: /* @__PURE__ */ jsx(InputErrorContext.Provider, {
9541
+ value: error ? errorId : void 0,
9542
+ children: block.dispatch_action === true ? /* @__PURE__ */ jsx(Element, {
9543
+ element,
9544
+ blockId
9545
+ }) : /* @__PURE__ */ jsx(SuppressActions, { children: /* @__PURE__ */ jsx(Element, {
9546
+ element,
9547
+ blockId
9548
+ }) })
9549
+ })
9517
9550
  })
9518
9551
  }),
9519
9552
  block.hint && /* @__PURE__ */ jsx("div", {
@@ -9539,6 +9572,7 @@ function Input({ block, blockId }) {
9539
9572
  }),
9540
9573
  error && /* @__PURE__ */ jsx("div", {
9541
9574
  className: "sbk-input__error",
9575
+ id: errorId,
9542
9576
  children: error
9543
9577
  })
9544
9578
  ]