@sesionario/blocks 1.11.0 → 1.13.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.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
 
@@ -3422,6 +3431,20 @@ function kindForNative(input) {
3422
3431
  if (code === MEDIA_ERR_NETWORK) return "unavailable";
3423
3432
  return "generic";
3424
3433
  }
3434
+ function describeAvResync(input) {
3435
+ const lag = Number.isFinite(input.lagSeconds) ? input.lagSeconds : 0;
3436
+ return {
3437
+ summary: `av-resync lag=${lag.toFixed(3)}s (non-fatal)`,
3438
+ kind: "resync",
3439
+ detail: {
3440
+ source: input.context.source,
3441
+ kind: "resync",
3442
+ fatal: false,
3443
+ reason: `presented frame lag ${lag.toFixed(3)}s`,
3444
+ context: input.context
3445
+ }
3446
+ };
3447
+ }
3425
3448
  function describePlaybackError(input) {
3426
3449
  if (input.source === "unsupported") {
3427
3450
  return {
@@ -3480,6 +3503,10 @@ function describePlaybackError(input) {
3480
3503
  // src/components/video/useHlsPlayback.ts
3481
3504
  var RETRY_INTERVAL_MS = 3e3;
3482
3505
  var MAX_MEDIA_ERROR_RETRIES = 5;
3506
+ var DRIFT_THRESHOLD_S = 0.4;
3507
+ var DRIFT_CONSECUTIVE_SAMPLES = 3;
3508
+ var RESYNC_COOLDOWN_MS = 1e4;
3509
+ var LIVE_EDGE_RESYNC_THRESHOLD_S = 8;
3483
3510
  function useHlsPlayback({
3484
3511
  src,
3485
3512
  mode,
@@ -3519,6 +3546,7 @@ function useHlsPlayback({
3519
3546
  let retryTimer = null;
3520
3547
  let manifestParsed = false;
3521
3548
  let mediaErrorRetries = 0;
3549
+ let playbackSource = "hls";
3522
3550
  const teardown = [];
3523
3551
  media.muted = muted;
3524
3552
  setState("loading");
@@ -3527,7 +3555,13 @@ function useHlsPlayback({
3527
3555
  setQualities([]);
3528
3556
  setActiveLevel(-1);
3529
3557
  function baseContext() {
3530
- return { mode, src, manifestParsed, retryCount: mediaErrorRetries };
3558
+ return {
3559
+ mode,
3560
+ src,
3561
+ manifestParsed,
3562
+ retryCount: mediaErrorRetries,
3563
+ source: playbackSource
3564
+ };
3531
3565
  }
3532
3566
  function clearRetryTimer() {
3533
3567
  if (retryTimer !== null) {
@@ -3566,6 +3600,53 @@ function useHlsPlayback({
3566
3600
  if (!cancelled) retryFn();
3567
3601
  }, RETRY_INTERVAL_MS);
3568
3602
  }
3603
+ function startDriftWatchdog(el) {
3604
+ if (typeof el.requestVideoFrameCallback !== "function") return;
3605
+ let consecutiveLagSamples = 0;
3606
+ let lastResyncAt = 0;
3607
+ let handle = null;
3608
+ const tick = (_now, metadata) => {
3609
+ if (cancelled) return;
3610
+ handle = el.requestVideoFrameCallback(tick);
3611
+ if (el.paused || el.ended) {
3612
+ consecutiveLagSamples = 0;
3613
+ return;
3614
+ }
3615
+ const lag = el.currentTime - metadata.mediaTime;
3616
+ if (!(lag > DRIFT_THRESHOLD_S)) {
3617
+ consecutiveLagSamples = 0;
3618
+ return;
3619
+ }
3620
+ consecutiveLagSamples += 1;
3621
+ if (consecutiveLagSamples < DRIFT_CONSECUTIVE_SAMPLES) return;
3622
+ const nowMs = performance.now();
3623
+ if (nowMs - lastResyncAt < RESYNC_COOLDOWN_MS) return;
3624
+ lastResyncAt = nowMs;
3625
+ consecutiveLagSamples = 0;
3626
+ if (mode === "live" && el.seekable.length > 0) {
3627
+ const edge = el.seekable.end(el.seekable.length - 1);
3628
+ if (edge - el.currentTime > LIVE_EDGE_RESYNC_THRESHOLD_S) {
3629
+ el.currentTime = edge;
3630
+ } else {
3631
+ el.currentTime = el.currentTime + 1e-3;
3632
+ }
3633
+ } else {
3634
+ el.currentTime = el.currentTime + 1e-3;
3635
+ }
3636
+ onErrorRef.current?.(
3637
+ describeAvResync({
3638
+ lagSeconds: lag,
3639
+ context: baseContext()
3640
+ })
3641
+ );
3642
+ };
3643
+ handle = el.requestVideoFrameCallback(tick);
3644
+ teardown.push(() => {
3645
+ if (handle != null && typeof el.cancelVideoFrameCallback === "function") {
3646
+ el.cancelVideoFrameCallback(handle);
3647
+ }
3648
+ });
3649
+ }
3569
3650
  function onPlaying() {
3570
3651
  manifestParsed = true;
3571
3652
  mediaErrorRetries = 0;
@@ -3584,7 +3665,9 @@ function useHlsPlayback({
3584
3665
  media.removeEventListener("pause", onPaused);
3585
3666
  media.removeEventListener("ended", onPaused);
3586
3667
  });
3668
+ startDriftWatchdog(media);
3587
3669
  function initNative() {
3670
+ playbackSource = "native";
3588
3671
  manifestParsed = false;
3589
3672
  media.removeAttribute("src");
3590
3673
  media.load();
@@ -3600,7 +3683,7 @@ function useHlsPlayback({
3600
3683
  reportFatal({
3601
3684
  source: "native",
3602
3685
  mediaError: media.error,
3603
- context: { ...baseContext(), source: "native" }
3686
+ context: baseContext()
3604
3687
  });
3605
3688
  return;
3606
3689
  }
@@ -3608,7 +3691,7 @@ function useHlsPlayback({
3608
3691
  describePlaybackError({
3609
3692
  source: "native",
3610
3693
  mediaError: media.error,
3611
- context: { ...baseContext(), source: "native" }
3694
+ context: baseContext()
3612
3695
  })
3613
3696
  );
3614
3697
  scheduleRetry(() => {
@@ -3624,6 +3707,7 @@ function useHlsPlayback({
3624
3707
  });
3625
3708
  }
3626
3709
  function initHlsJs(Hls) {
3710
+ playbackSource = "hls";
3627
3711
  destroyHls();
3628
3712
  manifestParsed = false;
3629
3713
  const config = mode === "live" ? createLiveHlsConfig() : createVodHlsConfig();
@@ -3655,7 +3739,7 @@ function useHlsPlayback({
3655
3739
  response: data.response,
3656
3740
  reason: data.reason,
3657
3741
  error: data.error,
3658
- context: { ...baseContext(), source: "hls" }
3742
+ context: baseContext()
3659
3743
  })
3660
3744
  );
3661
3745
  if (!data.fatal) return;
@@ -3690,7 +3774,7 @@ function useHlsPlayback({
3690
3774
  response: data.response,
3691
3775
  reason: data.reason,
3692
3776
  error: data.error,
3693
- context: { ...baseContext(), source: "hls" }
3777
+ context: baseContext()
3694
3778
  });
3695
3779
  });
3696
3780
  }
@@ -3707,9 +3791,10 @@ function useHlsPlayback({
3707
3791
  } else if (media.canPlayType("application/vnd.apple.mpegurl")) {
3708
3792
  initNative();
3709
3793
  } else {
3794
+ playbackSource = "unsupported";
3710
3795
  reportFatal({
3711
3796
  source: "unsupported",
3712
- context: { ...baseContext(), source: "unsupported" }
3797
+ context: baseContext()
3713
3798
  });
3714
3799
  }
3715
3800
  }
@@ -4056,6 +4141,8 @@ function VideoPlayer({
4056
4141
  return t.errorMedia;
4057
4142
  case "unsupported":
4058
4143
  return t.errorUnsupported;
4144
+ case "resync":
4145
+ return t.errorMedia;
4059
4146
  case "generic":
4060
4147
  return t.errorGeneric;
4061
4148
  default: {
@@ -6136,8 +6223,12 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6136
6223
  onKeyDown,
6137
6224
  sendLabel,
6138
6225
  sendDisabled = false,
6226
+ allowEmptySubmit = false,
6139
6227
  sendButtonClassName,
6140
6228
  sendButtonSize = "sm",
6229
+ submitOnEnter = true,
6230
+ tools,
6231
+ attachments,
6141
6232
  triggerLabel,
6142
6233
  keepOpenOnSelect,
6143
6234
  open,
@@ -6156,7 +6247,7 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6156
6247
  const handleEmojiSelect = useEmojiInsert(fieldRef, value, onChange);
6157
6248
  const pickerDisabled = Boolean(disabled || readOnly);
6158
6249
  const draft = value !== void 0 && value !== null ? String(value) : "";
6159
- const canSubmit = Boolean(draft.trim()) && !sendDisabled && !disabled && !readOnly;
6250
+ const canSubmit = (allowEmptySubmit || Boolean(draft.trim())) && !sendDisabled && !disabled && !readOnly;
6160
6251
  const handleSubmit = React7.useCallback(
6161
6252
  (event) => {
6162
6253
  event.preventDefault();
@@ -6169,13 +6260,14 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6169
6260
  (event) => {
6170
6261
  onKeyDown?.(event);
6171
6262
  if (event.defaultPrevented) return;
6263
+ if (!submitOnEnter) return;
6172
6264
  if (event.key !== "Enter" || event.shiftKey) return;
6173
6265
  if (event.nativeEvent.isComposing || event.keyCode === 229) return;
6174
6266
  event.preventDefault();
6175
6267
  if (!canSubmit) return;
6176
6268
  formRef.current?.requestSubmit();
6177
6269
  },
6178
- [canSubmit, onKeyDown]
6270
+ [canSubmit, onKeyDown, submitOnEnter]
6179
6271
  );
6180
6272
  return /* @__PURE__ */ jsxs(
6181
6273
  "form",
@@ -6202,28 +6294,32 @@ var MessageComposer = React7.forwardRef(function MessageComposer2({
6202
6294
  ...props
6203
6295
  }
6204
6296
  ),
6297
+ attachments ? /* @__PURE__ */ jsx("div", { className: "border-t px-2 py-2", children: attachments }) : null,
6205
6298
  /* @__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
- ),
6299
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-0.5", children: [
6300
+ /* @__PURE__ */ jsx(
6301
+ EmojiPickerPopover,
6302
+ {
6303
+ locale,
6304
+ onSelect: handleEmojiSelect,
6305
+ disabled: pickerDisabled,
6306
+ triggerLabel,
6307
+ keepOpenOnSelect,
6308
+ open,
6309
+ onOpenChange,
6310
+ side,
6311
+ align,
6312
+ labels,
6313
+ recentLimit,
6314
+ storageKey,
6315
+ triggerClassName: cn(
6316
+ "size-7 text-muted-foreground",
6317
+ emojiTriggerClassName
6318
+ )
6319
+ }
6320
+ ),
6321
+ tools
6322
+ ] }),
6227
6323
  /* @__PURE__ */ jsx(
6228
6324
  Button,
6229
6325
  {
@@ -6856,7 +6952,106 @@ function createSupportChatClient(basePath = "/api/chat-svc") {
6856
6952
  }
6857
6953
  };
6858
6954
  }
6955
+ var DEFAULT_RECONNECT_MS = 2e3;
6956
+ var MAX_RECONNECT_MS = 3e4;
6957
+ function useRealtimeChannel({
6958
+ getWsUrl,
6959
+ onEvent,
6960
+ enabled = true,
6961
+ reconnectDelayMs = DEFAULT_RECONNECT_MS
6962
+ }) {
6963
+ const onEventRef = useRef(onEvent);
6964
+ onEventRef.current = onEvent;
6965
+ const getWsUrlRef = useRef(getWsUrl);
6966
+ getWsUrlRef.current = getWsUrl;
6967
+ useEffect(() => {
6968
+ if (!enabled) return;
6969
+ let cancelled = false;
6970
+ let socket = null;
6971
+ let reconnectTimer = null;
6972
+ let attempt = 0;
6973
+ const connectGen = { current: 0 };
6974
+ const clearReconnect = () => {
6975
+ if (reconnectTimer) {
6976
+ clearTimeout(reconnectTimer);
6977
+ reconnectTimer = null;
6978
+ }
6979
+ };
6980
+ const scheduleReconnect = () => {
6981
+ if (cancelled) return;
6982
+ clearReconnect();
6983
+ const delay = Math.min(reconnectDelayMs * 2 ** attempt, MAX_RECONNECT_MS);
6984
+ attempt += 1;
6985
+ reconnectTimer = setTimeout(() => {
6986
+ void connect();
6987
+ }, delay);
6988
+ };
6989
+ const connect = async () => {
6990
+ const gen = ++connectGen.current;
6991
+ clearReconnect();
6992
+ const url = await getWsUrlRef.current();
6993
+ if (cancelled || gen !== connectGen.current) return;
6994
+ if (!url) {
6995
+ scheduleReconnect();
6996
+ return;
6997
+ }
6998
+ if (socket) {
6999
+ try {
7000
+ socket.close();
7001
+ } catch {
7002
+ }
7003
+ socket = null;
7004
+ }
7005
+ const ws = new WebSocket(url);
7006
+ socket = ws;
7007
+ ws.onopen = () => {
7008
+ if (cancelled || gen !== connectGen.current) return;
7009
+ attempt = 0;
7010
+ };
7011
+ ws.onmessage = (msg) => {
7012
+ if (cancelled || gen !== connectGen.current) return;
7013
+ let data;
7014
+ try {
7015
+ data = JSON.parse(String(msg.data));
7016
+ } catch {
7017
+ return;
7018
+ }
7019
+ if (typeof data?.type !== "string") return;
7020
+ if (data.type === "pong") return;
7021
+ onEventRef.current(data);
7022
+ };
7023
+ ws.onclose = () => {
7024
+ if (cancelled || gen !== connectGen.current) return;
7025
+ socket = null;
7026
+ scheduleReconnect();
7027
+ };
7028
+ ws.onerror = () => {
7029
+ };
7030
+ };
7031
+ const onVisibility = () => {
7032
+ if (document.visibilityState !== "visible" || cancelled) return;
7033
+ if (!socket || socket.readyState === WebSocket.CLOSED) {
7034
+ void connect();
7035
+ }
7036
+ };
7037
+ void connect();
7038
+ document.addEventListener("visibilitychange", onVisibility);
7039
+ return () => {
7040
+ cancelled = true;
7041
+ connectGen.current += 1;
7042
+ clearReconnect();
7043
+ document.removeEventListener("visibilitychange", onVisibility);
7044
+ if (socket) {
7045
+ try {
7046
+ socket.close();
7047
+ } catch {
7048
+ }
7049
+ socket = null;
7050
+ }
7051
+ };
7052
+ }, [enabled, reconnectDelayMs]);
7053
+ }
6859
7054
 
6860
- export { AvatarEditor, AvatarEditorDialog, Bubble, BubbleContent, BubbleGroup, BubbleReactions, ChatMessageList, ConfirmDestructiveDialog, EmojiInput, EmojiPicker, EmojiPickerPopover, EmojiTextarea, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, ErrorState, ExpandableText, ImageLightbox, LanguageContext, LanguageSwitcher, LoadingState, MEXICO_STATES, MEXICO_STATE_PATHS, Marker, MarkerContent, MarkerIcon, Message, MessageAvatar, MessageComposer, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, MexicoMap, OrgSwitcher, PhoneInput, SearchCommand, SearchablePicker, SupportMessengerProvider, ThemeSwitcher, VerifiedProfessionalBadge, VideoPlayer, avatarFallbackStyle, bubbleVariants, cn, createLiveHlsConfig, createSupportChatClient, createVodHlsConfig, defaultLanguages, describePlaybackError, fuzzyMatch, getAvatarColors, getInitials, insertAtCaret, markerVariants, normalizeEmojiQuery, shouldRetryLiveEdge404, useDebouncedValue, useDebouncedValueStrict, useHlsPlayback, useLanguageContext, useMediaQuery2 as useMediaQuery, usePlaybackStats, useSearchHotkey, useSupportConversation, useSupportMessenger, useSupportMessengerOptional };
7055
+ export { AvatarEditor, AvatarEditorDialog, Bubble, BubbleContent, BubbleGroup, BubbleReactions, ChatMessageList, ConfirmDestructiveDialog, EmojiInput, EmojiPicker, EmojiPickerPopover, EmojiTextarea, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, ErrorState, ExpandableText, ImageLightbox, LanguageContext, LanguageSwitcher, LoadingState, MEXICO_STATES, MEXICO_STATE_PATHS, Marker, MarkerContent, MarkerIcon, Message, MessageAvatar, MessageComposer, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, MexicoMap, OrgSwitcher, PhoneInput, SearchCommand, SearchablePicker, SupportMessengerProvider, ThemeSwitcher, VerifiedProfessionalBadge, VideoPlayer, avatarFallbackStyle, bubbleVariants, cn, createLiveHlsConfig, createSupportChatClient, createVodHlsConfig, defaultLanguages, describeAvResync, describePlaybackError, fuzzyMatch, getAvatarColors, getInitials, insertAtCaret, markerVariants, normalizeEmojiQuery, shouldRetryLiveEdge404, useDebouncedValue, useDebouncedValueStrict, useHlsPlayback, useLanguageContext, useMediaQuery2 as useMediaQuery, usePlaybackStats, useRealtimeChannel, useSearchHotkey, useSupportConversation, useSupportMessenger, useSupportMessengerOptional };
6861
7056
  //# sourceMappingURL=index.js.map
6862
7057
  //# sourceMappingURL=index.js.map