@sesionario/blocks 1.17.1 → 1.19.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/README.md CHANGED
@@ -29,6 +29,19 @@ Peer dependencies (install in the consuming app as needed):
29
29
  - `react-phone-number-input` (PhoneInput — also import its CSS in your app layout)
30
30
  - `hls.js` (optional — VideoPlayer)
31
31
 
32
+ ### Payment icons (`PaymentIcon`)
33
+
34
+ `PaymentIcon` wraps [`react-svg-credit-card-payment-icons`](https://www.npmjs.com/package/react-svg-credit-card-payment-icons) (pulled in as a dependency of this package). Pass a Stripe `card.brand` code:
35
+
36
+ ```tsx
37
+ import { PaymentIcon, formatPaymentCardBrand } from "@sesionario/blocks";
38
+
39
+ <PaymentIcon brand="amex" />
40
+ <span>{formatPaymentCardBrand("amex")}</span> {/* American Express */}
41
+ ```
42
+
43
+ Unknown or null brands render the Generic mark. Icon artwork is Apache-2.0 (Aaron Fagan / upstream package).
44
+
32
45
  ### Chat UI (`MessageScroller`, `ChatMessageList`, …)
33
46
 
34
47
  Apps that render chat scrollers should define this utility in global CSS (used by `MessageScrollerViewport`):
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var cmdk = require('cmdk');
22
22
  var RPNInput = require('react-phone-number-input');
23
23
  var flags = require('react-phone-number-input/flags');
24
24
  var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
25
+ var reactSvgCreditCardPaymentIcons = require('react-svg-credit-card-payment-icons');
25
26
  var messageScroller = require('@shadcn/react/message-scroller');
26
27
 
27
28
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -3788,7 +3789,7 @@ function insertAtCaret(element, value, text) {
3788
3789
  }
3789
3790
 
3790
3791
  // src/components/emoji/emoji-field-shared.ts
3791
- var emojiFieldWrapperClassName = "relative w-full rounded-md border border-input bg-transparent shadow-xs transition-[color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:ring-destructive/20 has-[:disabled]:opacity-50 dark:bg-input/30 dark:has-[[aria-invalid=true]]:ring-destructive/40";
3792
+ var emojiFieldWrapperClassName = "relative w-full rounded-md border border-input bg-transparent shadow-xs transition-[color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:ring-destructive/20 has-[[data-slot=textarea]:disabled]:opacity-50 has-[[data-slot=input]:disabled]:opacity-50 dark:bg-input/30 dark:has-[[aria-invalid=true]]:ring-destructive/40";
3792
3793
  var emojiFieldResetClassName = "border-0 bg-transparent shadow-none focus-visible:border-transparent focus-visible:ring-0 dark:bg-transparent";
3793
3794
  function mergeRefs(...refs) {
3794
3795
  return (node) => {
@@ -4514,6 +4515,7 @@ function VideoPlayer({
4514
4515
  stats,
4515
4516
  labels,
4516
4517
  showQualitySelector = true,
4518
+ paused = false,
4517
4519
  onPlayingChange,
4518
4520
  onFirstPlay,
4519
4521
  onError,
@@ -4605,6 +4607,11 @@ function VideoPlayer({
4605
4607
  video.removeEventListener("ratechange", onRate);
4606
4608
  };
4607
4609
  }, [videoRef, active, mode]);
4610
+ React7__namespace.useEffect(() => {
4611
+ const video = videoRef.current;
4612
+ if (!paused || !video || !isPlaying) return;
4613
+ video.pause();
4614
+ }, [paused, videoRef, isPlaying]);
4608
4615
  React7__namespace.useEffect(() => {
4609
4616
  setWebkitFullscreenSupported(hasWebkitVideoFullscreen(videoRef.current));
4610
4617
  }, [videoRef, active]);
@@ -5112,6 +5119,106 @@ function MenuItem({
5112
5119
  }
5113
5120
  );
5114
5121
  }
5122
+
5123
+ // src/components/video/feedPlaybackCoordinator.ts
5124
+ var players = /* @__PURE__ */ new Map();
5125
+ function registerFeedPlayer(id, pause) {
5126
+ players.set(id, pause);
5127
+ return () => {
5128
+ if (players.get(id) === pause) {
5129
+ players.delete(id);
5130
+ }
5131
+ };
5132
+ }
5133
+ function claimFeedPlaying(id) {
5134
+ for (const [otherId, pause] of players) {
5135
+ if (otherId !== id) pause();
5136
+ }
5137
+ }
5138
+
5139
+ // src/components/video/useFeedExclusivePlayback.ts
5140
+ var VISIBILITY_THRESHOLDS = [0, 0.5, 1];
5141
+ var MIN_VISIBLE_RATIO = 0.5;
5142
+ function videoInPictureInPicture(container) {
5143
+ if (typeof document === "undefined" || !container) return false;
5144
+ const pip = document.pictureInPictureElement;
5145
+ if (!pip) return false;
5146
+ return container.contains(pip);
5147
+ }
5148
+ function useFeedExclusivePlayback(playbackId) {
5149
+ const containerRef = React7__namespace.useRef(null);
5150
+ const [forcePaused, setForcePaused] = React7__namespace.useState(false);
5151
+ const requestPause = React7__namespace.useCallback(() => {
5152
+ if (videoInPictureInPicture(containerRef.current)) return;
5153
+ setForcePaused(true);
5154
+ }, []);
5155
+ React7__namespace.useEffect(() => {
5156
+ return registerFeedPlayer(playbackId, requestPause);
5157
+ }, [playbackId, requestPause]);
5158
+ React7__namespace.useEffect(() => {
5159
+ const node = containerRef.current;
5160
+ if (!node || typeof IntersectionObserver === "undefined") return;
5161
+ const observer = new IntersectionObserver(
5162
+ (entries) => {
5163
+ const entry = entries[0];
5164
+ if (!entry) return;
5165
+ if (!entry.isIntersecting || entry.intersectionRatio < MIN_VISIBLE_RATIO) {
5166
+ requestPause();
5167
+ }
5168
+ },
5169
+ { threshold: [...VISIBILITY_THRESHOLDS] }
5170
+ );
5171
+ observer.observe(node);
5172
+ return () => observer.disconnect();
5173
+ }, [requestPause]);
5174
+ React7__namespace.useEffect(() => {
5175
+ const onVisibility = () => {
5176
+ if (document.hidden) requestPause();
5177
+ };
5178
+ document.addEventListener("visibilitychange", onVisibility);
5179
+ return () => document.removeEventListener("visibilitychange", onVisibility);
5180
+ }, [requestPause]);
5181
+ const onPlayingChange = React7__namespace.useCallback(
5182
+ (playing) => {
5183
+ if (!playing) return;
5184
+ setForcePaused(false);
5185
+ claimFeedPlaying(playbackId);
5186
+ },
5187
+ [playbackId]
5188
+ );
5189
+ return {
5190
+ containerRef,
5191
+ paused: forcePaused,
5192
+ onPlayingChange
5193
+ };
5194
+ }
5195
+ function FeedVideoPlayer({
5196
+ playbackId,
5197
+ onPlayingChange,
5198
+ paused: pausedProp,
5199
+ ...playerProps
5200
+ }) {
5201
+ const {
5202
+ containerRef,
5203
+ paused: exclusivePaused,
5204
+ onPlayingChange: onExclusivePlayingChange
5205
+ } = useFeedExclusivePlayback(playbackId);
5206
+ const handlePlayingChange = React7__namespace.useCallback(
5207
+ (playing) => {
5208
+ onExclusivePlayingChange(playing);
5209
+ onPlayingChange?.(playing);
5210
+ },
5211
+ [onExclusivePlayingChange, onPlayingChange]
5212
+ );
5213
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, "data-slot": "feed-video-player", children: /* @__PURE__ */ jsxRuntime.jsx(
5214
+ VideoPlayer,
5215
+ {
5216
+ ...playerProps,
5217
+ paused: pausedProp || exclusivePaused,
5218
+ onPlayingChange: handlePlayingChange
5219
+ }
5220
+ ) });
5221
+ }
5115
5222
  function usePlaybackStats(statsUrl, { intervalMs = 15e3, enabled = true } = {}) {
5116
5223
  const [stats, setStats] = React7__namespace.useState({});
5117
5224
  React7__namespace.useEffect(() => {
@@ -6404,6 +6511,63 @@ function MexicoMap({ selected, onToggle, className }) {
6404
6511
  }
6405
6512
  );
6406
6513
  }
6514
+
6515
+ // src/lib/paymentCardBrand.ts
6516
+ var CARD_BRAND_LABELS = {
6517
+ visa: "Visa",
6518
+ mastercard: "Mastercard",
6519
+ amex: "American Express",
6520
+ discover: "Discover",
6521
+ diners: "Diners Club",
6522
+ jcb: "JCB",
6523
+ unionpay: "UnionPay"
6524
+ };
6525
+ var STRIPE_TO_PAYMENT_TYPE = {
6526
+ visa: "Visa",
6527
+ mastercard: "Mastercard",
6528
+ amex: "AmericanExpress",
6529
+ discover: "Discover",
6530
+ diners: "DinersClub",
6531
+ jcb: "JCB",
6532
+ unionpay: "UnionPay"
6533
+ };
6534
+ function normalizePaymentCardBrand(brand) {
6535
+ if (!brand?.trim()) return null;
6536
+ return brand.trim().toLowerCase();
6537
+ }
6538
+ function formatPaymentCardBrand(brand) {
6539
+ if (!brand?.trim()) return "Card";
6540
+ const key = brand.trim().toLowerCase();
6541
+ const known = CARD_BRAND_LABELS[key];
6542
+ if (known) return known;
6543
+ return key.charAt(0).toUpperCase() + key.slice(1);
6544
+ }
6545
+ function paymentTypeFromStripeBrand(brand) {
6546
+ const key = normalizePaymentCardBrand(brand);
6547
+ if (!key) return "Generic";
6548
+ return STRIPE_TO_PAYMENT_TYPE[key] ?? "Generic";
6549
+ }
6550
+ var DEFAULT_FORMAT = "flatRounded";
6551
+ var DEFAULT_WIDTH = 36;
6552
+ function PaymentIcon({
6553
+ brand,
6554
+ format = DEFAULT_FORMAT,
6555
+ width = DEFAULT_WIDTH,
6556
+ height,
6557
+ className
6558
+ }) {
6559
+ return /* @__PURE__ */ jsxRuntime.jsx(
6560
+ reactSvgCreditCardPaymentIcons.PaymentIcon,
6561
+ {
6562
+ type: paymentTypeFromStripeBrand(brand),
6563
+ format,
6564
+ width,
6565
+ height,
6566
+ className: cn("inline-block shrink-0", className),
6567
+ "aria-hidden": true
6568
+ }
6569
+ );
6570
+ }
6407
6571
  function MessageGroup({ className, ...props }) {
6408
6572
  return /* @__PURE__ */ jsxRuntime.jsx(
6409
6573
  "div",
@@ -7769,6 +7933,7 @@ exports.EmptyState = EmptyState;
7769
7933
  exports.EmptyTitle = EmptyTitle;
7770
7934
  exports.ErrorState = ErrorState;
7771
7935
  exports.ExpandableText = ExpandableText;
7936
+ exports.FeedVideoPlayer = FeedVideoPlayer;
7772
7937
  exports.ImageLightbox = ImageLightbox;
7773
7938
  exports.LanguageContext = LanguageContext;
7774
7939
  exports.LanguageSwitcher = LanguageSwitcher;
@@ -7794,6 +7959,7 @@ exports.MessageScrollerViewport = MessageScrollerViewport;
7794
7959
  exports.MexicoMap = MexicoMap;
7795
7960
  exports.OrgSwitcher = OrgSwitcher;
7796
7961
  exports.PLATFORM_ACCOUNT_ORG_COLLAPSE_AT = PLATFORM_ACCOUNT_ORG_COLLAPSE_AT;
7962
+ exports.PaymentIcon = PaymentIcon;
7797
7963
  exports.PhoneInput = PhoneInput;
7798
7964
  exports.PlatformAccountMenu = PlatformAccountMenu;
7799
7965
  exports.PlatformNavbar = PlatformNavbar;
@@ -7812,6 +7978,7 @@ exports.createVodHlsConfig = createVodHlsConfig;
7812
7978
  exports.defaultLanguages = defaultLanguages;
7813
7979
  exports.describeAvResync = describeAvResync;
7814
7980
  exports.describePlaybackError = describePlaybackError;
7981
+ exports.formatPaymentCardBrand = formatPaymentCardBrand;
7815
7982
  exports.fuzzyMatch = fuzzyMatch;
7816
7983
  exports.getAvatarColors = getAvatarColors;
7817
7984
  exports.getInitials = getInitials;
@@ -7819,9 +7986,12 @@ exports.insertAtCaret = insertAtCaret;
7819
7986
  exports.markerVariants = markerVariants;
7820
7987
  exports.mergePlatformAccountOrgs = mergePlatformAccountOrgs;
7821
7988
  exports.normalizeEmojiQuery = normalizeEmojiQuery;
7989
+ exports.normalizePaymentCardBrand = normalizePaymentCardBrand;
7990
+ exports.paymentTypeFromStripeBrand = paymentTypeFromStripeBrand;
7822
7991
  exports.shouldRetryLiveEdge404 = shouldRetryLiveEdge404;
7823
7992
  exports.useDebouncedValue = useDebouncedValue;
7824
7993
  exports.useDebouncedValueStrict = useDebouncedValueStrict;
7994
+ exports.useFeedExclusivePlayback = useFeedExclusivePlayback;
7825
7995
  exports.useHlsPlayback = useHlsPlayback;
7826
7996
  exports.useLanguageContext = useLanguageContext;
7827
7997
  exports.useMediaQuery = useMediaQuery2;