@retor/react-native 0.4.2 → 0.4.4

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.mts CHANGED
@@ -21,6 +21,8 @@ interface RetorTag {
21
21
  progress?: number;
22
22
  /** Profile image URL. For notes rendered with `icon` tag type, replaces the icon with a circular avatar. */
23
23
  avatarUrl?: string;
24
+ /** Display name of the note's author. Used for the initial-letter fallback when `avatarUrl` is absent. */
25
+ authorName?: string;
24
26
  }
25
27
  interface RetorLine {
26
28
  _id: string;
@@ -61,6 +63,8 @@ interface ViewerHandle {
61
63
  openLine: (lineId: string) => void;
62
64
  exitLine: () => void;
63
65
  scrollToTag: (tagId: string) => void;
66
+ /** Scroll the active line's camera to a 0..1 position. Use for notes (which aren't indexed by tagId on the server). */
67
+ scrollToProgress: (t: number) => void;
64
68
  toggleAutoplay: () => void;
65
69
  setAutoplay: (playing: boolean) => void;
66
70
  }
package/dist/index.d.ts CHANGED
@@ -21,6 +21,8 @@ interface RetorTag {
21
21
  progress?: number;
22
22
  /** Profile image URL. For notes rendered with `icon` tag type, replaces the icon with a circular avatar. */
23
23
  avatarUrl?: string;
24
+ /** Display name of the note's author. Used for the initial-letter fallback when `avatarUrl` is absent. */
25
+ authorName?: string;
24
26
  }
25
27
  interface RetorLine {
26
28
  _id: string;
@@ -61,6 +63,8 @@ interface ViewerHandle {
61
63
  openLine: (lineId: string) => void;
62
64
  exitLine: () => void;
63
65
  scrollToTag: (tagId: string) => void;
66
+ /** Scroll the active line's camera to a 0..1 position. Use for notes (which aren't indexed by tagId on the server). */
67
+ scrollToProgress: (t: number) => void;
64
68
  toggleAutoplay: () => void;
65
69
  setAutoplay: (playing: boolean) => void;
66
70
  }
package/dist/index.js CHANGED
@@ -67,6 +67,7 @@ var noopHandle = {
67
67
  openLine: noop,
68
68
  exitLine: noop,
69
69
  scrollToTag: noop,
70
+ scrollToProgress: noop,
70
71
  toggleAutoplay: noop,
71
72
  setAutoplay: noop
72
73
  };
@@ -176,6 +177,9 @@ function useViewer(target = "default") {
176
177
  scrollToTag: (tagId) => {
177
178
  resolve()?.scrollToTag(tagId);
178
179
  },
180
+ scrollToProgress: (t) => {
181
+ resolve()?.scrollToProgress(t);
182
+ },
179
183
  toggleAutoplay: () => {
180
184
  resolve()?.toggleAutoplay();
181
185
  },
@@ -236,6 +240,7 @@ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "d
236
240
  openLine: (lineId) => send("open-line", { lineId }),
237
241
  exitLine: () => send("exit-line"),
238
242
  scrollToTag: (tagId) => send("scroll-to-tag", { tagId }),
243
+ scrollToProgress: (t) => send("scroll-to-progress", { t }),
239
244
  // Bridge owns autoplay state — it'll emit `autoplay-state` back, which
240
245
  // we use to update isPlaying. No optimistic local update.
241
246
  toggleAutoplay: () => send("toggle-autoplay"),
@@ -579,12 +584,9 @@ var import_lucide_react_native2 = require("lucide-react-native");
579
584
 
580
585
  // src/lineProgress.ts
581
586
  function mergeLineTagsByProgress(controls, notes) {
582
- const sortedControls = [...controls].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
583
- const lastIdx = Math.max(1, sortedControls.length - 1);
584
587
  const merged = [];
585
- for (const c of sortedControls) {
586
- const idx = c.index ?? 0;
587
- merged.push({ ...c, _isNote: false, progress: idx / lastIdx });
588
+ for (const c of controls) {
589
+ merged.push({ ...c, _isNote: false, progress: c.progress ?? 0 });
588
590
  }
589
591
  for (const n of notes) {
590
592
  merged.push({ ...n, _isNote: true, progress: n.progress ?? 0 });
@@ -733,12 +735,18 @@ function DefaultLineTagList({ listHeader }) {
733
735
  }
734
736
  function DefaultTagItem({ tag, isActive }) {
735
737
  const { controls, openAddNote } = useRetorBridge();
738
+ const initial = tag.authorName?.trim().charAt(0).toUpperCase();
739
+ const handlePress = () => {
740
+ if (typeof tag.progress === "number") controls.scrollToProgress(tag.progress);
741
+ else controls.scrollToTag(tag._id);
742
+ };
736
743
  return /* @__PURE__ */ import_react6.default.createElement(
737
744
  import_react_native5.Pressable,
738
745
  {
739
- onPress: () => controls.scrollToTag(tag._id),
746
+ onPress: handlePress,
740
747
  style: [styles3.tagItem, isActive && styles3.tagItemActive]
741
748
  },
749
+ tag.avatarUrl ? /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Image, { source: { uri: tag.avatarUrl }, style: styles3.tagAvatar }) : initial ? /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: styles3.tagInitial }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles3.tagInitialText }, initial)) : null,
742
750
  /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: 1 }, tag.name), isActive && tag.description && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles3.tagDescription, numberOfLines: 2 }, tag.description)),
743
751
  tag.subtitle && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle),
744
752
  isActive && /* @__PURE__ */ import_react6.default.createElement(
@@ -788,6 +796,16 @@ var styles3 = import_react_native5.StyleSheet.create({
788
796
  gap: 8
789
797
  },
790
798
  tagItemActive: { backgroundColor: "rgba(255,255,255,0.1)" },
799
+ tagAvatar: { width: 22, height: 22, borderRadius: 11 },
800
+ tagInitial: {
801
+ width: 22,
802
+ height: 22,
803
+ borderRadius: 11,
804
+ backgroundColor: "rgba(255,255,255,0.15)",
805
+ alignItems: "center",
806
+ justifyContent: "center"
807
+ },
808
+ tagInitialText: { color: "white", fontSize: 11, fontWeight: "700" },
791
809
  tagText: { color: "rgba(255,255,255,0.6)", fontSize: 13 },
792
810
  tagTextActive: { color: "white", fontWeight: "600" },
793
811
  tagDescription: { color: "rgba(255,255,255,0.4)", fontSize: 11, marginTop: 2, lineHeight: 14 },
package/dist/index.mjs CHANGED
@@ -14,6 +14,7 @@ var noopHandle = {
14
14
  openLine: noop,
15
15
  exitLine: noop,
16
16
  scrollToTag: noop,
17
+ scrollToProgress: noop,
17
18
  toggleAutoplay: noop,
18
19
  setAutoplay: noop
19
20
  };
@@ -132,6 +133,9 @@ function useViewer(target = "default") {
132
133
  scrollToTag: (tagId) => {
133
134
  resolve()?.scrollToTag(tagId);
134
135
  },
136
+ scrollToProgress: (t) => {
137
+ resolve()?.scrollToProgress(t);
138
+ },
135
139
  toggleAutoplay: () => {
136
140
  resolve()?.toggleAutoplay();
137
141
  },
@@ -192,6 +196,7 @@ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl =
192
196
  openLine: (lineId) => send("open-line", { lineId }),
193
197
  exitLine: () => send("exit-line"),
194
198
  scrollToTag: (tagId) => send("scroll-to-tag", { tagId }),
199
+ scrollToProgress: (t) => send("scroll-to-progress", { t }),
195
200
  // Bridge owns autoplay state — it'll emit `autoplay-state` back, which
196
201
  // we use to update isPlaying. No optimistic local update.
197
202
  toggleAutoplay: () => send("toggle-autoplay"),
@@ -528,7 +533,7 @@ var styles2 = StyleSheet4.create({
528
533
 
529
534
  // src/LineDetailSheet.tsx
530
535
  import React6, { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
531
- import { Pressable as Pressable2, StyleSheet as StyleSheet5, Text as Text2, View as View5 } from "react-native";
536
+ import { Image, Pressable as Pressable2, StyleSheet as StyleSheet5, Text as Text2, View as View5 } from "react-native";
532
537
  import {
533
538
  BottomSheetBackdrop as BottomSheetBackdrop2,
534
539
  BottomSheetFooter,
@@ -540,12 +545,9 @@ import { ArrowDown as ArrowDown2, ArrowUp as ArrowUp2, Pause, Play, Plus } from
540
545
 
541
546
  // src/lineProgress.ts
542
547
  function mergeLineTagsByProgress(controls, notes) {
543
- const sortedControls = [...controls].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
544
- const lastIdx = Math.max(1, sortedControls.length - 1);
545
548
  const merged = [];
546
- for (const c of sortedControls) {
547
- const idx = c.index ?? 0;
548
- merged.push({ ...c, _isNote: false, progress: idx / lastIdx });
549
+ for (const c of controls) {
550
+ merged.push({ ...c, _isNote: false, progress: c.progress ?? 0 });
549
551
  }
550
552
  for (const n of notes) {
551
553
  merged.push({ ...n, _isNote: true, progress: n.progress ?? 0 });
@@ -694,12 +696,18 @@ function DefaultLineTagList({ listHeader }) {
694
696
  }
695
697
  function DefaultTagItem({ tag, isActive }) {
696
698
  const { controls, openAddNote } = useRetorBridge();
699
+ const initial = tag.authorName?.trim().charAt(0).toUpperCase();
700
+ const handlePress = () => {
701
+ if (typeof tag.progress === "number") controls.scrollToProgress(tag.progress);
702
+ else controls.scrollToTag(tag._id);
703
+ };
697
704
  return /* @__PURE__ */ React6.createElement(
698
705
  Pressable2,
699
706
  {
700
- onPress: () => controls.scrollToTag(tag._id),
707
+ onPress: handlePress,
701
708
  style: [styles3.tagItem, isActive && styles3.tagItemActive]
702
709
  },
710
+ tag.avatarUrl ? /* @__PURE__ */ React6.createElement(Image, { source: { uri: tag.avatarUrl }, style: styles3.tagAvatar }) : initial ? /* @__PURE__ */ React6.createElement(View5, { style: styles3.tagInitial }, /* @__PURE__ */ React6.createElement(Text2, { style: styles3.tagInitialText }, initial)) : null,
703
711
  /* @__PURE__ */ React6.createElement(View5, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React6.createElement(Text2, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: 1 }, tag.name), isActive && tag.description && /* @__PURE__ */ React6.createElement(Text2, { style: styles3.tagDescription, numberOfLines: 2 }, tag.description)),
704
712
  tag.subtitle && /* @__PURE__ */ React6.createElement(Text2, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle),
705
713
  isActive && /* @__PURE__ */ React6.createElement(
@@ -749,6 +757,16 @@ var styles3 = StyleSheet5.create({
749
757
  gap: 8
750
758
  },
751
759
  tagItemActive: { backgroundColor: "rgba(255,255,255,0.1)" },
760
+ tagAvatar: { width: 22, height: 22, borderRadius: 11 },
761
+ tagInitial: {
762
+ width: 22,
763
+ height: 22,
764
+ borderRadius: 11,
765
+ backgroundColor: "rgba(255,255,255,0.15)",
766
+ alignItems: "center",
767
+ justifyContent: "center"
768
+ },
769
+ tagInitialText: { color: "white", fontSize: 11, fontWeight: "700" },
752
770
  tagText: { color: "rgba(255,255,255,0.6)", fontSize: 13 },
753
771
  tagTextActive: { color: "white", fontWeight: "600" },
754
772
  tagDescription: { color: "rgba(255,255,255,0.4)", fontSize: 11, marginTop: 2, lineHeight: 14 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retor/react-native",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "React Native SDK for embedding Retor 3D experiences",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",