@algenium/blocks 1.13.0 → 1.14.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.
package/README.md CHANGED
@@ -20,6 +20,13 @@ This package requires the following peer dependencies:
20
20
  pnpm add react react-dom next-themes lucide-react motion
21
21
  ```
22
22
 
23
+ `hls.js` (`>=1.5`) is an **optional** peer dependency required only by
24
+ `VideoPlayer`; install it in apps that use the player:
25
+
26
+ ```bash
27
+ pnpm add hls.js
28
+ ```
29
+
23
30
  ## Configuration
24
31
 
25
32
  ### Tailwind CSS
@@ -415,6 +422,159 @@ interface Notification {
415
422
 
416
423
  ---
417
424
 
425
+ ### EmojiPicker
426
+
427
+ A zero-dependency emoji picker with bilingual (English + Spanish) search,
428
+ category navigation, a persisted "frequently used" section, a global skin-tone
429
+ preference, and desktop-first keyboard navigation. The emoji dataset (~1,900
430
+ emoji, Unicode ≤ 15.1) is generated at build time from Unicode CLDR annotations
431
+ and committed to the repo, so consuming apps ship **no** extra runtime
432
+ dependencies. Because the package is `sideEffects: false` and tree-shaken, apps
433
+ that never import `EmojiPicker` don't bundle the data at all.
434
+
435
+ **Features:**
436
+
437
+ - Bilingual search: "corazón", "corazon" and "heart" all match ❤️
438
+ - 9 categories with an icon tab bar and scroll-to-section
439
+ - "Frequently used" recents, persisted in `localStorage`
440
+ - Global skin-tone selector (applied to capable emoji), persisted
441
+ - Keyboard navigation: arrows move, Enter/Space selects
442
+ - `labels` + `locale` props for i18n; search is always bilingual
443
+
444
+ **Usage:**
445
+
446
+ ```tsx
447
+ import { useRef, useState } from "react";
448
+ import { EmojiPickerPopover } from "@algenium/blocks";
449
+
450
+ function Composer() {
451
+ const ref = useRef<HTMLTextAreaElement>(null);
452
+ const [value, setValue] = useState("");
453
+
454
+ function insert(emoji: string) {
455
+ const el = ref.current;
456
+ if (!el) return setValue((v) => v + emoji);
457
+ const start = el.selectionStart ?? value.length;
458
+ const end = el.selectionEnd ?? value.length;
459
+ setValue(value.slice(0, start) + emoji + value.slice(end));
460
+ }
461
+
462
+ return (
463
+ <div className="flex items-end gap-2">
464
+ <textarea
465
+ ref={ref}
466
+ value={value}
467
+ onChange={(e) => setValue(e.target.value)}
468
+ />
469
+ <EmojiPickerPopover locale="es" onSelect={insert} />
470
+ </div>
471
+ );
472
+ }
473
+ ```
474
+
475
+ Use the standalone panel when you want to place it inside your own anchor:
476
+
477
+ ```tsx
478
+ import { EmojiPicker } from "@algenium/blocks";
479
+
480
+ <EmojiPicker locale="es" onSelect={(emoji) => insert(emoji)} />;
481
+ ```
482
+
483
+ **Props (`EmojiPicker`):**
484
+
485
+ ```typescript
486
+ interface EmojiPickerProps {
487
+ onSelect: (emoji: string) => void;
488
+ locale?: "en" | "es"; // Section titles + skin-tone names. Default "en"
489
+ labels?: EmojiPickerLabels; // Overrides individual strings / category titles
490
+ className?: string;
491
+ recentLimit?: number; // Default 24
492
+ storageKey?: string | null; // localStorage namespace; null disables persistence
493
+ }
494
+ ```
495
+
496
+ `EmojiPickerPopover` accepts every `EmojiPicker` prop plus `triggerLabel`,
497
+ `triggerClassName`, `side`, `align`, `open`/`onOpenChange` (controlled), and
498
+ `keepOpenOnSelect`.
499
+
500
+ ---
501
+
502
+ ### VideoPlayer
503
+
504
+ A standardized HLS video player with a fully custom control bar (no native
505
+ `controls`), for both live streams and on-demand recordings. `hls.js` is an
506
+ **optional peer dependency** loaded on demand via dynamic import — apps that
507
+ already depend on it (`app`, `admin`, `media`) bundle nothing new, and Safari
508
+ falls back to native HLS.
509
+
510
+ **Features:**
511
+
512
+ - Click-to-play poster (attaches HLS only after the user gesture)
513
+ - Play/pause, mute + hover volume slider, keyboard shortcuts
514
+ - Resolution picker (Auto + hls.js levels), playback speed (VOD)
515
+ - Picture-in-Picture and fullscreen (menus stay usable in fullscreen)
516
+ - VOD: seekbar with buffered ranges + current/total time
517
+ - Live: red pulsing badge, **no seekbar**, and a "go live" affordance when the
518
+ playhead drifts behind the edge
519
+ - `stats` prop renders live viewer / VOD reproduction counts
520
+ - Loading / waiting / error states with retry; errors surfaced via `onError`
521
+ (no bundled reporting) and localized via `labels`
522
+
523
+ **Usage:**
524
+
525
+ ```tsx
526
+ import { VideoPlayer, usePlaybackStats } from "@algenium/blocks";
527
+
528
+ function Recording({ mediaId, src, poster }: Props) {
529
+ const stats = usePlaybackStats(
530
+ `https://media.example.com/playback/${mediaId}/stats`,
531
+ );
532
+
533
+ return (
534
+ <VideoPlayer
535
+ src={src}
536
+ mode="vod"
537
+ poster={poster}
538
+ stats={stats}
539
+ labels={{ live: "EN VIVO", formatViews: (n) => `${n} reproducciones` }}
540
+ onFirstPlay={() => {
541
+ void fetch(`https://media.example.com/playback/${mediaId}/view`, {
542
+ method: "POST",
543
+ });
544
+ }}
545
+ onError={(e) => reportToSentry(e)}
546
+ />
547
+ );
548
+ }
549
+ ```
550
+
551
+ For live playback pass `mode="live"` and, typically, `autoPlay muted`.
552
+
553
+ **Props:**
554
+
555
+ ```typescript
556
+ interface VideoPlayerProps {
557
+ src: string;
558
+ mode: "live" | "vod";
559
+ poster?: string;
560
+ autoPlay?: boolean;
561
+ muted?: boolean;
562
+ stats?: { viewers?: number; views?: number };
563
+ labels?: VideoPlayerLabels;
564
+ showQualitySelector?: boolean; // Default true
565
+ onPlayingChange?: (playing: boolean) => void;
566
+ onFirstPlay?: () => void; // Fires once — wire your view beacon here
567
+ onError?: (error: DescribedPlaybackError) => void;
568
+ className?: string;
569
+ }
570
+ ```
571
+
572
+ Also exported: `useHlsPlayback` (the attach/detach hook), `usePlaybackStats`
573
+ (polls a stats endpoint), `createLiveHlsConfig` / `createVodHlsConfig`, and
574
+ `describePlaybackError`.
575
+
576
+ ---
577
+
418
578
  ## UI Primitives
419
579
 
420
580
  The package also exports underlying UI primitives that can be used independently: