@livelayer/react 0.18.2 → 0.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/dist/styles.css CHANGED
@@ -582,43 +582,64 @@
582
582
  flex-direction: column;
583
583
  }
584
584
 
585
- .ll-expanded--desktop {
586
- width: 400px;
587
- height: 560px;
588
- border-radius: 20px;
589
- }
590
-
591
- .ll-expanded--mobile {
592
- /* Mobile thumbnail card matches the dimensions the LiveLayer
593
- landing page uses for ExperienceForkCard's embedded preview
594
- (components/landing/ExperienceFork.tsx — the canonical reference
595
- design the team has shipped on www.livelayer.studio). Visitors
596
- have explicitly asked us to match it exactly so the package
597
- behaves identically across LL's own marketing site and customer
598
- sites.
599
-
600
- LL demo dimensions (from ExperienceFork.tsx:36):
601
- mobile (default): w-[160px] h-[230px] ←──┐ matched
602
- sm+ (≥640px): w-[180px] h-[260px] ←──┘ matched
603
-
604
- Border radius: rounded-2xl in Tailwind = 16px.
605
-
606
- Width and height are explicit pixels (not aspect-ratio) because
607
- the reference uses explicit pixels preserving every detail of
608
- the design contract. The two breakpoints match LL exactly so the
609
- widget reads as the same component in both contexts. */
585
+ /* Sizing is media-query-driven, NOT JS-class-driven.
586
+ *
587
+ * Why: useIsMobile() is SSR-safe — it returns `false` on the server
588
+ * and on the very first client paint, then flips to `true` on the
589
+ * first useEffect tick. If sizing were keyed off the .ll-expanded--
590
+ * desktop / .ll-expanded--mobile class (which IS JS-driven), the
591
+ * first paint would render at desktop dimensions (400×560), then
592
+ * snap down to mobile dimensions (160×230) once the effect ran.
593
+ * Visitors on phones saw a visible flash of an oversized widget.
594
+ *
595
+ * The component still adds the .ll-expanded--desktop / --mobile
596
+ * class other styles (the compact-status pill positioning,
597
+ * topbar padding, PIP sizing, etc.) key off it. But the bounding-
598
+ * box dimensions live in the .ll-expanded base + the media query
599
+ * below, so the right size is applied at first paint regardless
600
+ * of JS readiness.
601
+ *
602
+ * Breakpoint: 640px (matches Tailwind's `sm`). When a consumer
603
+ * passes a custom mobileBreakpoint prop, the JS still computes
604
+ * isMobile against that custom value (drives layout / waveform /
605
+ * compactControls behavior) — but the CSS box dims stick to 640px.
606
+ * Acceptable tradeoff: the visual size flickers slightly when the
607
+ * custom breakpoint differs from 640, but the common case (every
608
+ * site using the default breakpoint) has zero flash.
609
+ *
610
+ * LL landing reference (components/landing/ExperienceFork.tsx:36):
611
+ * mobile (default): w-[160px] h-[230px]
612
+ * sm+ (≥640px): w-[180px] h-[260px]
613
+ * Desktop reference: 400 × 560, matches editor preview at app.livelayer.studio.
614
+ */
615
+ .ll-expanded {
616
+ /* Mobile-first: phones get the thumbnail card by default. The
617
+ desktop override below kicks in at ≥1024px where there's
618
+ actually room for the full 400 × 560 panel. */
610
619
  width: 160px;
611
620
  height: 230px;
612
621
  border-radius: 16px;
613
622
  }
614
623
 
615
- @media (min-width: 640px) {
616
- .ll-expanded--mobile {
624
+ @media (min-width: 640px) and (max-width: 1023px) {
625
+ .ll-expanded {
626
+ /* Sm-to-lg breakpoint — small tablets / large phones in
627
+ landscape. Slightly larger thumbnail. Matches the LL demo's
628
+ `sm:w-[180px] sm:h-[260px]` exactly. */
617
629
  width: 180px;
618
630
  height: 260px;
619
631
  }
620
632
  }
621
633
 
634
+ @media (min-width: 1024px) {
635
+ .ll-expanded {
636
+ /* Desktop card — full 400 × 560 with a softer 20px radius. */
637
+ width: 400px;
638
+ height: 560px;
639
+ border-radius: 20px;
640
+ }
641
+ }
642
+
622
643
  /* ── Background layers ───────────────────────────────────────── */
623
644
 
624
645
  .ll-expanded__bg,
@@ -1779,3 +1800,82 @@
1779
1800
  0%, 100% { opacity: 1; transform: scale(1); }
1780
1801
  50% { opacity: 0.55; transform: scale(0.7); }
1781
1802
  }
1803
+
1804
+ /* ── Drag + resize (0.19.0) ────────────────────────────────────────
1805
+ Lets the visitor move the floating widget off page content (phone
1806
+ number, CTA) and resize it. Geometry lives as an INLINE style
1807
+ override applied by useDragAndResize ONLY after the visitor actually
1808
+ drags/resizes (or a saved geometry is restored) — until then this
1809
+ stylesheet's media-query sizing + .ll-widget[data-position] corner
1810
+ anchoring stay in charge so there's no first-paint flash. These rules
1811
+ only style the handles + interaction affordances; they never set box
1812
+ dimensions or position. */
1813
+
1814
+ /* Drag handle = the expanded header row. `data-ll-drag-handle` is set by
1815
+ the hook only when dragging is enabled, so the grab cursor + page-scroll
1816
+ suppression apply exactly when a drag can actually start. */
1817
+ .ll-widget [data-ll-drag-handle] {
1818
+ cursor: grab;
1819
+ /* Stop touch-drag on the handle from scrolling the page. */
1820
+ touch-action: none;
1821
+ }
1822
+ .ll-widget.is-dragging [data-ll-drag-handle] {
1823
+ cursor: grabbing;
1824
+ }
1825
+
1826
+ /* While dragging OR resizing, kill text selection across the whole widget
1827
+ so a fast pointer drag doesn't paint a selection over the header copy /
1828
+ transcript pills, and drop transitions so the surface tracks the pointer
1829
+ 1:1 instead of easing behind it. */
1830
+ .ll-widget.is-dragging,
1831
+ .ll-widget.is-resizing,
1832
+ .ll-widget.is-dragging *,
1833
+ .ll-widget.is-resizing * {
1834
+ user-select: none;
1835
+ -webkit-user-select: none;
1836
+ }
1837
+ .ll-widget.is-dragging .ll-expanded,
1838
+ .ll-widget.is-resizing .ll-expanded {
1839
+ transition: none;
1840
+ }
1841
+
1842
+ /* Resize grip — bottom-right corner of the expanded surface. Conventional
1843
+ placement (opposite the top-left the box grows from) and the diagonal
1844
+ double-chevron glyph reads as "drag to resize" without a tooltip. The
1845
+ element sits above the bottom toolbar (z-index) but is small enough not
1846
+ to cover the end-call button. */
1847
+ .ll-expanded__resize-grip {
1848
+ position: absolute;
1849
+ right: 0;
1850
+ bottom: 0;
1851
+ z-index: 6;
1852
+ width: 22px;
1853
+ height: 22px;
1854
+ display: flex;
1855
+ align-items: flex-end;
1856
+ justify-content: flex-end;
1857
+ padding: 3px;
1858
+ color: rgba(255, 255, 255, 0.55);
1859
+ cursor: nwse-resize;
1860
+ /* Stop touch-drag on the grip from scrolling the page. */
1861
+ touch-action: none;
1862
+ /* The grip is a pointer-only nicety; never let it capture selection. */
1863
+ user-select: none;
1864
+ -webkit-user-select: none;
1865
+ transition: color 0.15s ease;
1866
+ }
1867
+ .ll-expanded__resize-grip:hover {
1868
+ color: rgba(255, 255, 255, 0.9);
1869
+ }
1870
+ .ll-expanded__resize-grip > svg {
1871
+ display: block;
1872
+ pointer-events: none;
1873
+ }
1874
+
1875
+ /* Once the visitor has set an explicit geometry, the inline width/height
1876
+ override the media-query box dims. We pin position:fixed inline too (the
1877
+ hook sets it) so this class is mostly a hook for host CSS / tests; no
1878
+ dimensional rules live here on purpose — geometry is the inline layer. */
1879
+ .ll-widget--has-geometry {
1880
+ /* intentionally empty — see comment above. */
1881
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livelayer/react",
3
- "version": "0.18.2",
3
+ "version": "0.19.0",
4
4
  "description": "LiveLayer agent widget for React — avatar video, team switching, responsive layouts, full-fidelity embed",
5
5
  "keywords": [
6
6
  "livelayer",