@sesionario/blocks 1.11.0 → 1.12.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.d.cts CHANGED
@@ -378,14 +378,16 @@ interface EmojiPickerPopoverProps extends EmojiPickerProps {
378
378
  open?: boolean;
379
379
  onOpenChange?: (open: boolean) => void;
380
380
  /** Keep the popover open after choosing an emoji (e.g. to add several).
381
- * Default `false`. */
381
+ * Default `true` so multi-emoji insertion is one-click-away. Pass `false`
382
+ * to close on every selection. */
382
383
  keepOpenOnSelect?: boolean;
383
384
  }
384
385
  /**
385
386
  * Convenience wrapper: a `Smile` icon button that opens {@link EmojiPicker} in
386
387
  * a popover. Prefer {@link EmojiTextarea} / {@link EmojiInput} for in-field
387
388
  * adornment; use this when you need a standalone trigger. Uncontrolled by
388
- * default; pass `open`/`onOpenChange` to control it.
389
+ * default; pass `open`/`onOpenChange` to control it. Stays open across
390
+ * selections by default; closes on pointer-down outside or Escape.
389
391
  */
390
392
  declare function EmojiPickerPopover({ onSelect, triggerLabel, triggerClassName, disabled, side, align, open, onOpenChange, keepOpenOnSelect, locale, ...pickerProps }: EmojiPickerPopoverProps): React.JSX.Element;
391
393
 
@@ -935,20 +937,35 @@ type MessageComposerProps = Omit<React.ComponentProps<"textarea">, "children" |
935
937
  sendLabel: string;
936
938
  /**
937
939
  * Extra condition that disables send (e.g. connection closed).
938
- * Empty/whitespace drafts are always blocked.
940
+ * Empty/whitespace drafts are blocked unless {@link allowEmptySubmit}.
939
941
  */
940
942
  sendDisabled?: boolean;
941
- /** Called when the form submits a non-empty trimmed draft. */
943
+ /**
944
+ * When true, the submit button stays enabled with an empty draft
945
+ * (e.g. attachment-only feed posts). Default `false`.
946
+ */
947
+ allowEmptySubmit?: boolean;
948
+ /** Called when the form submits (and draft/guards allow it). */
942
949
  onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
943
950
  /** Extra classes for the submit button. */
944
951
  sendButtonClassName?: string;
945
952
  /** Submit button size. Default `"sm"`. */
946
953
  sendButtonSize?: React.ComponentProps<typeof Button>["size"];
954
+ /**
955
+ * When true (default), Enter submits and Shift+Enter inserts a newline.
956
+ * Set false for long-form composers (Enter = newline; submit via button).
957
+ */
958
+ submitOnEnter?: boolean;
959
+ /** Icon/tool buttons rendered next to the emoji trigger (left cluster). */
960
+ tools?: React.ReactNode;
961
+ /** Attachment previews rendered between the textarea and the toolbar. */
962
+ attachments?: React.ReactNode;
947
963
  };
948
964
  /**
949
965
  * Unified chat composer: bordered form with textarea, emoji picker, and send
950
- * button. Enter submits; Shift+Enter inserts a newline. IME composition Enter
951
- * is ignored.
966
+ * button. Enter submits by default; Shift+Enter inserts a newline. IME
967
+ * composition Enter is ignored. Pass `tools` / `attachments` to extend the
968
+ * toolbar and preview strip (e.g. feed post media controls).
952
969
  */
953
970
  declare const MessageComposer: React.ForwardRefExoticComponent<Omit<MessageComposerProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
954
971
 
package/dist/index.d.ts CHANGED
@@ -378,14 +378,16 @@ interface EmojiPickerPopoverProps extends EmojiPickerProps {
378
378
  open?: boolean;
379
379
  onOpenChange?: (open: boolean) => void;
380
380
  /** Keep the popover open after choosing an emoji (e.g. to add several).
381
- * Default `false`. */
381
+ * Default `true` so multi-emoji insertion is one-click-away. Pass `false`
382
+ * to close on every selection. */
382
383
  keepOpenOnSelect?: boolean;
383
384
  }
384
385
  /**
385
386
  * Convenience wrapper: a `Smile` icon button that opens {@link EmojiPicker} in
386
387
  * a popover. Prefer {@link EmojiTextarea} / {@link EmojiInput} for in-field
387
388
  * adornment; use this when you need a standalone trigger. Uncontrolled by
388
- * default; pass `open`/`onOpenChange` to control it.
389
+ * default; pass `open`/`onOpenChange` to control it. Stays open across
390
+ * selections by default; closes on pointer-down outside or Escape.
389
391
  */
390
392
  declare function EmojiPickerPopover({ onSelect, triggerLabel, triggerClassName, disabled, side, align, open, onOpenChange, keepOpenOnSelect, locale, ...pickerProps }: EmojiPickerPopoverProps): React.JSX.Element;
391
393
 
@@ -935,20 +937,35 @@ type MessageComposerProps = Omit<React.ComponentProps<"textarea">, "children" |
935
937
  sendLabel: string;
936
938
  /**
937
939
  * Extra condition that disables send (e.g. connection closed).
938
- * Empty/whitespace drafts are always blocked.
940
+ * Empty/whitespace drafts are blocked unless {@link allowEmptySubmit}.
939
941
  */
940
942
  sendDisabled?: boolean;
941
- /** Called when the form submits a non-empty trimmed draft. */
943
+ /**
944
+ * When true, the submit button stays enabled with an empty draft
945
+ * (e.g. attachment-only feed posts). Default `false`.
946
+ */
947
+ allowEmptySubmit?: boolean;
948
+ /** Called when the form submits (and draft/guards allow it). */
942
949
  onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
943
950
  /** Extra classes for the submit button. */
944
951
  sendButtonClassName?: string;
945
952
  /** Submit button size. Default `"sm"`. */
946
953
  sendButtonSize?: React.ComponentProps<typeof Button>["size"];
954
+ /**
955
+ * When true (default), Enter submits and Shift+Enter inserts a newline.
956
+ * Set false for long-form composers (Enter = newline; submit via button).
957
+ */
958
+ submitOnEnter?: boolean;
959
+ /** Icon/tool buttons rendered next to the emoji trigger (left cluster). */
960
+ tools?: React.ReactNode;
961
+ /** Attachment previews rendered between the textarea and the toolbar. */
962
+ attachments?: React.ReactNode;
947
963
  };
948
964
  /**
949
965
  * Unified chat composer: bordered form with textarea, emoji picker, and send
950
- * button. Enter submits; Shift+Enter inserts a newline. IME composition Enter
951
- * is ignored.
966
+ * button. Enter submits by default; Shift+Enter inserts a newline. IME
967
+ * composition Enter is ignored. Pass `tools` / `attachments` to extend the
968
+ * toolbar and preview strip (e.g. feed post media controls).
952
969
  */
953
970
  declare const MessageComposer: React.ForwardRefExoticComponent<Omit<MessageComposerProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
954
971
 
package/dist/index.js CHANGED
@@ -2957,8 +2957,8 @@ function EmojiPicker({
2957
2957
  {
2958
2958
  ref: scrollRef,
2959
2959
  onKeyDown: handleGridKeyDown,
2960
- className: "h-64 overflow-x-hidden overflow-y-auto p-2",
2961
- children: normalizedQuery ? searchResults.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground py-8 text-center text-sm", children: strings.noResults }) : /* @__PURE__ */ jsx(
2960
+ className: "h-64 overflow-x-hidden overflow-y-auto px-2 pb-2",
2961
+ children: normalizedQuery ? searchResults.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground py-8 text-center text-sm", children: strings.noResults }) : /* @__PURE__ */ jsx("div", { className: "pt-2", children: /* @__PURE__ */ jsx(
2962
2962
  EmojiGrid,
2963
2963
  {
2964
2964
  emojis: searchResults,
@@ -2967,7 +2967,7 @@ function EmojiPicker({
2967
2967
  skinTone,
2968
2968
  onSelect: handleSelect
2969
2969
  }
2970
- ) : sections.map((section) => {
2970
+ ) }) : sections.map((section) => {
2971
2971
  const startIndex = flatOffset;
2972
2972
  flatOffset += section.emojis.length;
2973
2973
  return /* @__PURE__ */ jsxs(
@@ -2978,7 +2978,7 @@ function EmojiPicker({
2978
2978
  },
2979
2979
  className: "mb-2",
2980
2980
  children: [
2981
- /* @__PURE__ */ jsx("h3", { className: "text-muted-foreground bg-popover sticky top-0 z-[1] px-1 py-1 text-xs font-medium", children: section.title }),
2981
+ /* @__PURE__ */ jsx("h3", { className: "text-muted-foreground bg-popover sticky top-0 z-[1] -mx-2 px-3 pt-2 pb-1 text-xs font-medium", children: section.title }),
2982
2982
  /* @__PURE__ */ jsx(
2983
2983
  "div",
2984
2984
  {
@@ -3099,7 +3099,7 @@ function EmojiPickerPopover({
3099
3099
  align = "end",
3100
3100
  open,
3101
3101
  onOpenChange,
3102
- keepOpenOnSelect = false,
3102
+ keepOpenOnSelect = true,
3103
3103
  locale = "en",
3104
3104
  ...pickerProps
3105
3105
  }) {
@@ -3133,7 +3133,16 @@ function EmojiPickerPopover({
3133
3133
  children: /* @__PURE__ */ jsx(Smile, { className: "size-5" })
3134
3134
  }
3135
3135
  ) }),
3136
- /* @__PURE__ */ jsx(PopoverContent, { side, align, className: "w-auto p-0", children: /* @__PURE__ */ jsx(EmojiPicker, { onSelect: handleSelect, locale, ...pickerProps }) })
3136
+ /* @__PURE__ */ jsx(
3137
+ PopoverContent,
3138
+ {
3139
+ side,
3140
+ align,
3141
+ className: "w-auto p-0",
3142
+ onFocusOutside: (e) => e.preventDefault(),
3143
+ children: /* @__PURE__ */ jsx(EmojiPicker, { onSelect: handleSelect, locale, ...pickerProps })
3144
+ }
3145
+ )
3137
3146
  ] });
3138
3147
  }
3139
3148
 
@@ -6136,8 +6145,12 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6136
6145
  onKeyDown,
6137
6146
  sendLabel,
6138
6147
  sendDisabled = false,
6148
+ allowEmptySubmit = false,
6139
6149
  sendButtonClassName,
6140
6150
  sendButtonSize = "sm",
6151
+ submitOnEnter = true,
6152
+ tools,
6153
+ attachments,
6141
6154
  triggerLabel,
6142
6155
  keepOpenOnSelect,
6143
6156
  open,
@@ -6156,7 +6169,7 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6156
6169
  const handleEmojiSelect = useEmojiInsert(fieldRef, value, onChange);
6157
6170
  const pickerDisabled = Boolean(disabled || readOnly);
6158
6171
  const draft = value !== void 0 && value !== null ? String(value) : "";
6159
- const canSubmit = Boolean(draft.trim()) && !sendDisabled && !disabled && !readOnly;
6172
+ const canSubmit = (allowEmptySubmit || Boolean(draft.trim())) && !sendDisabled && !disabled && !readOnly;
6160
6173
  const handleSubmit = React7.useCallback(
6161
6174
  (event) => {
6162
6175
  event.preventDefault();
@@ -6169,13 +6182,14 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6169
6182
  (event) => {
6170
6183
  onKeyDown?.(event);
6171
6184
  if (event.defaultPrevented) return;
6185
+ if (!submitOnEnter) return;
6172
6186
  if (event.key !== "Enter" || event.shiftKey) return;
6173
6187
  if (event.nativeEvent.isComposing || event.keyCode === 229) return;
6174
6188
  event.preventDefault();
6175
6189
  if (!canSubmit) return;
6176
6190
  formRef.current?.requestSubmit();
6177
6191
  },
6178
- [canSubmit, onKeyDown]
6192
+ [canSubmit, onKeyDown, submitOnEnter]
6179
6193
  );
6180
6194
  return /* @__PURE__ */ jsxs(
6181
6195
  "form",
@@ -6202,28 +6216,32 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6202
6216
  ...props
6203
6217
  }
6204
6218
  ),
6219
+ attachments ? /* @__PURE__ */ jsx("div", { className: "border-t px-2 py-2", children: attachments }) : null,
6205
6220
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-1.5 pb-1.5", children: [
6206
- /* @__PURE__ */ jsx(
6207
- EmojiPickerPopover,
6208
- {
6209
- locale,
6210
- onSelect: handleEmojiSelect,
6211
- disabled: pickerDisabled,
6212
- triggerLabel,
6213
- keepOpenOnSelect,
6214
- open,
6215
- onOpenChange,
6216
- side,
6217
- align,
6218
- labels,
6219
- recentLimit,
6220
- storageKey,
6221
- triggerClassName: cn(
6222
- "size-7 text-muted-foreground",
6223
- emojiTriggerClassName
6224
- )
6225
- }
6226
- ),
6221
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-0.5", children: [
6222
+ /* @__PURE__ */ jsx(
6223
+ EmojiPickerPopover,
6224
+ {
6225
+ locale,
6226
+ onSelect: handleEmojiSelect,
6227
+ disabled: pickerDisabled,
6228
+ triggerLabel,
6229
+ keepOpenOnSelect,
6230
+ open,
6231
+ onOpenChange,
6232
+ side,
6233
+ align,
6234
+ labels,
6235
+ recentLimit,
6236
+ storageKey,
6237
+ triggerClassName: cn(
6238
+ "size-7 text-muted-foreground",
6239
+ emojiTriggerClassName
6240
+ )
6241
+ }
6242
+ ),
6243
+ tools
6244
+ ] }),
6227
6245
  /* @__PURE__ */ jsx(
6228
6246
  Button,
6229
6247
  {