@retor/react-native 0.4.3 → 0.4.5

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
@@ -23,6 +23,8 @@ interface RetorTag {
23
23
  avatarUrl?: string;
24
24
  /** Display name of the note's author. Used for the initial-letter fallback when `avatarUrl` is absent. */
25
25
  authorName?: string;
26
+ /** ID of the user who created this note. Compared against `Viewer.userId` to show the delete button. */
27
+ userId?: string;
26
28
  }
27
29
  interface RetorLine {
28
30
  _id: string;
@@ -63,6 +65,8 @@ interface ViewerHandle {
63
65
  openLine: (lineId: string) => void;
64
66
  exitLine: () => void;
65
67
  scrollToTag: (tagId: string) => void;
68
+ /** Scroll the active line's camera to a 0..1 position. Use for notes (which aren't indexed by tagId on the server). */
69
+ scrollToProgress: (t: number) => void;
66
70
  toggleAutoplay: () => void;
67
71
  setAutoplay: (playing: boolean) => void;
68
72
  }
@@ -101,12 +105,16 @@ interface RetorBridgeContextValue {
101
105
  lineNotes: RetorTag[];
102
106
  /** Notes injected by the consumer via the <Notes> sentinel. */
103
107
  externalNotes: RetorTag[];
108
+ /** The current user's ID — notes with a matching `userId` show a delete button. */
109
+ userId: string | null;
104
110
  isAddNoteOpen: boolean;
105
111
  addNoteTagId: string | null;
106
112
  controls: ViewerHandle;
107
113
  openAddNote: (tagId?: string) => void;
108
114
  closeAddNote: () => void;
109
115
  submitNote: (text: string, isPrivate?: boolean) => void;
116
+ /** Optimistically remove a note and fire the consumer's onNoteDelete callback. */
117
+ deleteNote: (noteId: string) => void;
110
118
  }
111
119
  declare function useRetorBridge(): RetorBridgeContextValue;
112
120
  /** Returns the array of all lines in the current project. */
@@ -185,8 +193,12 @@ interface ViewerProps {
185
193
  id?: string;
186
194
  /** Base URL where Retor is hosted. Defaults to https://retor.app */
187
195
  baseUrl?: string;
196
+ /** The current user's ID. When set, notes with a matching `userId` field show a delete button. */
197
+ userId?: string;
188
198
  /** Called when a note is submitted via `<AddNoteSheet>`. Receives the text + position. */
189
199
  onNoteSubmit?: (note: NoteSubmitPayload) => void;
200
+ /** Called when the user deletes a note. The note is optimistically removed from the list. */
201
+ onNoteDelete?: (noteId: string) => void;
190
202
  onInit?: (data: InitPayload) => void;
191
203
  onLineOpen?: (data: {
192
204
  lineId: string;
package/dist/index.d.ts CHANGED
@@ -23,6 +23,8 @@ interface RetorTag {
23
23
  avatarUrl?: string;
24
24
  /** Display name of the note's author. Used for the initial-letter fallback when `avatarUrl` is absent. */
25
25
  authorName?: string;
26
+ /** ID of the user who created this note. Compared against `Viewer.userId` to show the delete button. */
27
+ userId?: string;
26
28
  }
27
29
  interface RetorLine {
28
30
  _id: string;
@@ -63,6 +65,8 @@ interface ViewerHandle {
63
65
  openLine: (lineId: string) => void;
64
66
  exitLine: () => void;
65
67
  scrollToTag: (tagId: string) => void;
68
+ /** Scroll the active line's camera to a 0..1 position. Use for notes (which aren't indexed by tagId on the server). */
69
+ scrollToProgress: (t: number) => void;
66
70
  toggleAutoplay: () => void;
67
71
  setAutoplay: (playing: boolean) => void;
68
72
  }
@@ -101,12 +105,16 @@ interface RetorBridgeContextValue {
101
105
  lineNotes: RetorTag[];
102
106
  /** Notes injected by the consumer via the <Notes> sentinel. */
103
107
  externalNotes: RetorTag[];
108
+ /** The current user's ID — notes with a matching `userId` show a delete button. */
109
+ userId: string | null;
104
110
  isAddNoteOpen: boolean;
105
111
  addNoteTagId: string | null;
106
112
  controls: ViewerHandle;
107
113
  openAddNote: (tagId?: string) => void;
108
114
  closeAddNote: () => void;
109
115
  submitNote: (text: string, isPrivate?: boolean) => void;
116
+ /** Optimistically remove a note and fire the consumer's onNoteDelete callback. */
117
+ deleteNote: (noteId: string) => void;
110
118
  }
111
119
  declare function useRetorBridge(): RetorBridgeContextValue;
112
120
  /** Returns the array of all lines in the current project. */
@@ -185,8 +193,12 @@ interface ViewerProps {
185
193
  id?: string;
186
194
  /** Base URL where Retor is hosted. Defaults to https://retor.app */
187
195
  baseUrl?: string;
196
+ /** The current user's ID. When set, notes with a matching `userId` field show a delete button. */
197
+ userId?: string;
188
198
  /** Called when a note is submitted via `<AddNoteSheet>`. Receives the text + position. */
189
199
  onNoteSubmit?: (note: NoteSubmitPayload) => void;
200
+ /** Called when the user deletes a note. The note is optimistically removed from the list. */
201
+ onNoteDelete?: (noteId: string) => void;
190
202
  onInit?: (data: InitPayload) => void;
191
203
  onLineOpen?: (data: {
192
204
  lineId: string;
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
  };
@@ -77,12 +78,14 @@ var fallback = {
77
78
  activeLine: null,
78
79
  lineNotes: [],
79
80
  externalNotes: [],
81
+ userId: null,
80
82
  isAddNoteOpen: false,
81
83
  addNoteTagId: null,
82
84
  controls: noopHandle,
83
85
  openAddNote: noop,
84
86
  closeAddNote: noop,
85
- submitNote: noop
87
+ submitNote: noop,
88
+ deleteNote: noop
86
89
  };
87
90
  function useRetorBridge() {
88
91
  return (0, import_react.useContext)(RetorBridgeContext) ?? fallback;
@@ -176,6 +179,9 @@ function useViewer(target = "default") {
176
179
  scrollToTag: (tagId) => {
177
180
  resolve()?.scrollToTag(tagId);
178
181
  },
182
+ scrollToProgress: (t) => {
183
+ resolve()?.scrollToProgress(t);
184
+ },
179
185
  toggleAutoplay: () => {
180
186
  resolve()?.toggleAutoplay();
181
187
  },
@@ -201,7 +207,7 @@ function extractNotes(children) {
201
207
  });
202
208
  return notes;
203
209
  }
204
- var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "default", baseUrl = "https://retor.app", onNoteSubmit, onInit, onLineOpen, onLineClose, onLineProgress, onMessage, style, children }, ref) {
210
+ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "default", baseUrl = "https://retor.app", userId = null, onNoteSubmit, onNoteDelete, onInit, onLineOpen, onLineClose, onLineProgress, onMessage, style, children }, ref) {
205
211
  const webviewRef = (0, import_react2.useRef)(null);
206
212
  const notes = extractNotes(children);
207
213
  const readyRef = (0, import_react2.useRef)(false);
@@ -236,6 +242,7 @@ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "d
236
242
  openLine: (lineId) => send("open-line", { lineId }),
237
243
  exitLine: () => send("exit-line"),
238
244
  scrollToTag: (tagId) => send("scroll-to-tag", { tagId }),
245
+ scrollToProgress: (t) => send("scroll-to-progress", { t }),
239
246
  // Bridge owns autoplay state — it'll emit `autoplay-state` back, which
240
247
  // we use to update isPlaying. No optimistic local update.
241
248
  toggleAutoplay: () => send("toggle-autoplay"),
@@ -255,6 +262,7 @@ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "d
255
262
  const addNoteTagIdRef = (0, import_react2.useRef)(addNoteTagId);
256
263
  const activeLineIdRef = (0, import_react2.useRef)(activeLineId);
257
264
  const onNoteSubmitRef = (0, import_react2.useRef)(onNoteSubmit);
265
+ const onNoteDeleteRef = (0, import_react2.useRef)(onNoteDelete);
258
266
  const noteSnapshotRef = (0, import_react2.useRef)({ progress: 0, targetPosition: null, distanceFromStart: null });
259
267
  const progressRef = (0, import_react2.useRef)(progress);
260
268
  const targetPositionRef = (0, import_react2.useRef)(targetPosition);
@@ -271,6 +279,9 @@ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "d
271
279
  (0, import_react2.useEffect)(() => {
272
280
  onNoteSubmitRef.current = onNoteSubmit;
273
281
  }, [onNoteSubmit]);
282
+ (0, import_react2.useEffect)(() => {
283
+ onNoteDeleteRef.current = onNoteDelete;
284
+ }, [onNoteDelete]);
274
285
  (0, import_react2.useEffect)(() => {
275
286
  progressRef.current = progress;
276
287
  }, [progress]);
@@ -312,6 +323,10 @@ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "d
312
323
  }
313
324
  setIsAddNoteOpen(false);
314
325
  }, [send]);
326
+ const deleteNote = (0, import_react2.useCallback)((noteId) => {
327
+ setLineNotes((prev) => prev.filter((n) => n._id !== noteId));
328
+ onNoteDeleteRef.current?.(noteId);
329
+ }, []);
315
330
  const handleMessage = (0, import_react2.useCallback)(
316
331
  (event) => {
317
332
  let data = null;
@@ -386,14 +401,16 @@ var Viewer = (0, import_react2.forwardRef)(function Viewer2({ projectId, id = "d
386
401
  activeLine,
387
402
  lineNotes,
388
403
  externalNotes,
404
+ userId,
389
405
  isAddNoteOpen,
390
406
  addNoteTagId,
391
407
  controls,
392
408
  openAddNote,
393
409
  closeAddNote,
394
- submitNote
410
+ submitNote,
411
+ deleteNote
395
412
  }),
396
- [project, lines, activeLineId, activeLine, lineNotes, externalNotes, isAddNoteOpen, addNoteTagId, controls, openAddNote, closeAddNote, submitNote]
413
+ [project, lines, activeLineId, activeLine, lineNotes, externalNotes, userId, isAddNoteOpen, addNoteTagId, controls, openAddNote, closeAddNote, submitNote, deleteNote]
397
414
  );
398
415
  const progressCtx = (0, import_react2.useMemo)(
399
416
  () => ({ progress, closestTagId, targetPosition, distanceFromStart, isPlaying }),
@@ -722,25 +739,45 @@ function LineTagList({ children, listHeader }) {
722
739
  contentContainerStyle: styles3.list
723
740
  },
724
741
  listHeader,
725
- tags.map((tag) => /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { key: tag._id, onLayout: (e) => handleItemLayout(tag._id, e) }, children(tag, tag._id === closestTagId)))
742
+ tags.map((tag, i) => {
743
+ const isNote = !!tag._isNote;
744
+ const prevIsNote = i > 0 && !!tags[i - 1]._isNote;
745
+ const showSep = isNote && !prevIsNote && i > 0 || !isNote && i > 0 && prevIsNote;
746
+ return /* @__PURE__ */ import_react6.default.createElement(import_react6.Fragment, { key: tag._id }, showSep && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: styles3.separator }), /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { onLayout: (e) => handleItemLayout(tag._id, e) }, children(tag, tag._id === closestTagId)));
747
+ })
726
748
  );
727
749
  }
728
750
  function DefaultLineTagList({ listHeader }) {
729
751
  return /* @__PURE__ */ import_react6.default.createElement(LineTagList, { listHeader }, (tag, isActive) => /* @__PURE__ */ import_react6.default.createElement(DefaultTagItem, { tag, isActive }));
730
752
  }
731
753
  function DefaultTagItem({ tag, isActive }) {
732
- const { controls, openAddNote } = useRetorBridge();
754
+ const { controls, openAddNote, userId, deleteNote } = useRetorBridge();
755
+ const isNote = !!tag._isNote;
756
+ const tagUserId = tag.userId;
757
+ const isOwn = !!userId && !!tagUserId && tagUserId === userId;
733
758
  const initial = tag.authorName?.trim().charAt(0).toUpperCase();
759
+ const handlePress = () => {
760
+ if (typeof tag.progress === "number") controls.scrollToProgress(tag.progress);
761
+ else controls.scrollToTag(tag._id);
762
+ };
734
763
  return /* @__PURE__ */ import_react6.default.createElement(
735
764
  import_react_native5.Pressable,
736
765
  {
737
- onPress: () => controls.scrollToTag(tag._id),
766
+ onPress: handlePress,
738
767
  style: [styles3.tagItem, isActive && styles3.tagItemActive]
739
768
  },
740
769
  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,
741
- /* @__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)),
770
+ /* @__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: isNote ? 3 : 1 }, tag.name), isActive && tag.description && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles3.tagDescription, numberOfLines: 2 }, tag.description)),
742
771
  tag.subtitle && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle),
743
- isActive && /* @__PURE__ */ import_react6.default.createElement(
772
+ isNote && isOwn && /* @__PURE__ */ import_react6.default.createElement(
773
+ import_react_native5.Pressable,
774
+ {
775
+ onPress: () => deleteNote(tag._id),
776
+ style: styles3.deleteBtn
777
+ },
778
+ /* @__PURE__ */ import_react6.default.createElement(import_lucide_react_native2.Trash2, { size: 12, color: "rgba(255,255,255,0.4)" })
779
+ ),
780
+ isActive && !isNote && /* @__PURE__ */ import_react6.default.createElement(
744
781
  import_react_native5.Pressable,
745
782
  {
746
783
  onPress: (e) => {
@@ -797,10 +834,18 @@ var styles3 = import_react_native5.StyleSheet.create({
797
834
  justifyContent: "center"
798
835
  },
799
836
  tagInitialText: { color: "white", fontSize: 11, fontWeight: "700" },
837
+ separator: { height: 1, backgroundColor: "rgba(255,255,255,0.1)", marginHorizontal: 20, marginVertical: 4 },
800
838
  tagText: { color: "rgba(255,255,255,0.6)", fontSize: 13 },
801
839
  tagTextActive: { color: "white", fontWeight: "600" },
802
840
  tagDescription: { color: "rgba(255,255,255,0.4)", fontSize: 11, marginTop: 2, lineHeight: 14 },
803
841
  tagSubtitle: { color: "rgba(255,255,255,0.4)", fontSize: 10 },
842
+ deleteBtn: {
843
+ width: 24,
844
+ height: 24,
845
+ borderRadius: 12,
846
+ alignItems: "center",
847
+ justifyContent: "center"
848
+ },
804
849
  plusBtn: {
805
850
  width: 24,
806
851
  height: 24,
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
  };
@@ -24,12 +25,14 @@ var fallback = {
24
25
  activeLine: null,
25
26
  lineNotes: [],
26
27
  externalNotes: [],
28
+ userId: null,
27
29
  isAddNoteOpen: false,
28
30
  addNoteTagId: null,
29
31
  controls: noopHandle,
30
32
  openAddNote: noop,
31
33
  closeAddNote: noop,
32
- submitNote: noop
34
+ submitNote: noop,
35
+ deleteNote: noop
33
36
  };
34
37
  function useRetorBridge() {
35
38
  return useContext(RetorBridgeContext) ?? fallback;
@@ -132,6 +135,9 @@ function useViewer(target = "default") {
132
135
  scrollToTag: (tagId) => {
133
136
  resolve()?.scrollToTag(tagId);
134
137
  },
138
+ scrollToProgress: (t) => {
139
+ resolve()?.scrollToProgress(t);
140
+ },
135
141
  toggleAutoplay: () => {
136
142
  resolve()?.toggleAutoplay();
137
143
  },
@@ -157,7 +163,7 @@ function extractNotes(children) {
157
163
  });
158
164
  return notes;
159
165
  }
160
- var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl = "https://retor.app", onNoteSubmit, onInit, onLineOpen, onLineClose, onLineProgress, onMessage, style, children }, ref) {
166
+ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl = "https://retor.app", userId = null, onNoteSubmit, onNoteDelete, onInit, onLineOpen, onLineClose, onLineProgress, onMessage, style, children }, ref) {
161
167
  const webviewRef = useRef(null);
162
168
  const notes = extractNotes(children);
163
169
  const readyRef = useRef(false);
@@ -192,6 +198,7 @@ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl =
192
198
  openLine: (lineId) => send("open-line", { lineId }),
193
199
  exitLine: () => send("exit-line"),
194
200
  scrollToTag: (tagId) => send("scroll-to-tag", { tagId }),
201
+ scrollToProgress: (t) => send("scroll-to-progress", { t }),
195
202
  // Bridge owns autoplay state — it'll emit `autoplay-state` back, which
196
203
  // we use to update isPlaying. No optimistic local update.
197
204
  toggleAutoplay: () => send("toggle-autoplay"),
@@ -211,6 +218,7 @@ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl =
211
218
  const addNoteTagIdRef = useRef(addNoteTagId);
212
219
  const activeLineIdRef = useRef(activeLineId);
213
220
  const onNoteSubmitRef = useRef(onNoteSubmit);
221
+ const onNoteDeleteRef = useRef(onNoteDelete);
214
222
  const noteSnapshotRef = useRef({ progress: 0, targetPosition: null, distanceFromStart: null });
215
223
  const progressRef = useRef(progress);
216
224
  const targetPositionRef = useRef(targetPosition);
@@ -227,6 +235,9 @@ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl =
227
235
  useEffect(() => {
228
236
  onNoteSubmitRef.current = onNoteSubmit;
229
237
  }, [onNoteSubmit]);
238
+ useEffect(() => {
239
+ onNoteDeleteRef.current = onNoteDelete;
240
+ }, [onNoteDelete]);
230
241
  useEffect(() => {
231
242
  progressRef.current = progress;
232
243
  }, [progress]);
@@ -268,6 +279,10 @@ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl =
268
279
  }
269
280
  setIsAddNoteOpen(false);
270
281
  }, [send]);
282
+ const deleteNote = useCallback((noteId) => {
283
+ setLineNotes((prev) => prev.filter((n) => n._id !== noteId));
284
+ onNoteDeleteRef.current?.(noteId);
285
+ }, []);
271
286
  const handleMessage = useCallback(
272
287
  (event) => {
273
288
  let data = null;
@@ -342,14 +357,16 @@ var Viewer = forwardRef(function Viewer2({ projectId, id = "default", baseUrl =
342
357
  activeLine,
343
358
  lineNotes,
344
359
  externalNotes,
360
+ userId,
345
361
  isAddNoteOpen,
346
362
  addNoteTagId,
347
363
  controls,
348
364
  openAddNote,
349
365
  closeAddNote,
350
- submitNote
366
+ submitNote,
367
+ deleteNote
351
368
  }),
352
- [project, lines, activeLineId, activeLine, lineNotes, externalNotes, isAddNoteOpen, addNoteTagId, controls, openAddNote, closeAddNote, submitNote]
369
+ [project, lines, activeLineId, activeLine, lineNotes, externalNotes, userId, isAddNoteOpen, addNoteTagId, controls, openAddNote, closeAddNote, submitNote, deleteNote]
353
370
  );
354
371
  const progressCtx = useMemo2(
355
372
  () => ({ progress, closestTagId, targetPosition, distanceFromStart, isPlaying }),
@@ -527,7 +544,7 @@ var styles2 = StyleSheet4.create({
527
544
  });
528
545
 
529
546
  // src/LineDetailSheet.tsx
530
- import React6, { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
547
+ import React6, { Fragment, useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
531
548
  import { Image, Pressable as Pressable2, StyleSheet as StyleSheet5, Text as Text2, View as View5 } from "react-native";
532
549
  import {
533
550
  BottomSheetBackdrop as BottomSheetBackdrop2,
@@ -536,7 +553,7 @@ import {
536
553
  BottomSheetScrollView
537
554
  } from "@gorhom/bottom-sheet";
538
555
  import Svg, { Circle } from "react-native-svg";
539
- import { ArrowDown as ArrowDown2, ArrowUp as ArrowUp2, Pause, Play, Plus } from "lucide-react-native";
556
+ import { ArrowDown as ArrowDown2, ArrowUp as ArrowUp2, Pause, Play, Plus, Trash2 } from "lucide-react-native";
540
557
 
541
558
  // src/lineProgress.ts
542
559
  function mergeLineTagsByProgress(controls, notes) {
@@ -683,25 +700,45 @@ function LineTagList({ children, listHeader }) {
683
700
  contentContainerStyle: styles3.list
684
701
  },
685
702
  listHeader,
686
- tags.map((tag) => /* @__PURE__ */ React6.createElement(View5, { key: tag._id, onLayout: (e) => handleItemLayout(tag._id, e) }, children(tag, tag._id === closestTagId)))
703
+ tags.map((tag, i) => {
704
+ const isNote = !!tag._isNote;
705
+ const prevIsNote = i > 0 && !!tags[i - 1]._isNote;
706
+ const showSep = isNote && !prevIsNote && i > 0 || !isNote && i > 0 && prevIsNote;
707
+ return /* @__PURE__ */ React6.createElement(Fragment, { key: tag._id }, showSep && /* @__PURE__ */ React6.createElement(View5, { style: styles3.separator }), /* @__PURE__ */ React6.createElement(View5, { onLayout: (e) => handleItemLayout(tag._id, e) }, children(tag, tag._id === closestTagId)));
708
+ })
687
709
  );
688
710
  }
689
711
  function DefaultLineTagList({ listHeader }) {
690
712
  return /* @__PURE__ */ React6.createElement(LineTagList, { listHeader }, (tag, isActive) => /* @__PURE__ */ React6.createElement(DefaultTagItem, { tag, isActive }));
691
713
  }
692
714
  function DefaultTagItem({ tag, isActive }) {
693
- const { controls, openAddNote } = useRetorBridge();
715
+ const { controls, openAddNote, userId, deleteNote } = useRetorBridge();
716
+ const isNote = !!tag._isNote;
717
+ const tagUserId = tag.userId;
718
+ const isOwn = !!userId && !!tagUserId && tagUserId === userId;
694
719
  const initial = tag.authorName?.trim().charAt(0).toUpperCase();
720
+ const handlePress = () => {
721
+ if (typeof tag.progress === "number") controls.scrollToProgress(tag.progress);
722
+ else controls.scrollToTag(tag._id);
723
+ };
695
724
  return /* @__PURE__ */ React6.createElement(
696
725
  Pressable2,
697
726
  {
698
- onPress: () => controls.scrollToTag(tag._id),
727
+ onPress: handlePress,
699
728
  style: [styles3.tagItem, isActive && styles3.tagItemActive]
700
729
  },
701
730
  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,
702
- /* @__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)),
731
+ /* @__PURE__ */ React6.createElement(View5, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React6.createElement(Text2, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: isNote ? 3 : 1 }, tag.name), isActive && tag.description && /* @__PURE__ */ React6.createElement(Text2, { style: styles3.tagDescription, numberOfLines: 2 }, tag.description)),
703
732
  tag.subtitle && /* @__PURE__ */ React6.createElement(Text2, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle),
704
- isActive && /* @__PURE__ */ React6.createElement(
733
+ isNote && isOwn && /* @__PURE__ */ React6.createElement(
734
+ Pressable2,
735
+ {
736
+ onPress: () => deleteNote(tag._id),
737
+ style: styles3.deleteBtn
738
+ },
739
+ /* @__PURE__ */ React6.createElement(Trash2, { size: 12, color: "rgba(255,255,255,0.4)" })
740
+ ),
741
+ isActive && !isNote && /* @__PURE__ */ React6.createElement(
705
742
  Pressable2,
706
743
  {
707
744
  onPress: (e) => {
@@ -758,10 +795,18 @@ var styles3 = StyleSheet5.create({
758
795
  justifyContent: "center"
759
796
  },
760
797
  tagInitialText: { color: "white", fontSize: 11, fontWeight: "700" },
798
+ separator: { height: 1, backgroundColor: "rgba(255,255,255,0.1)", marginHorizontal: 20, marginVertical: 4 },
761
799
  tagText: { color: "rgba(255,255,255,0.6)", fontSize: 13 },
762
800
  tagTextActive: { color: "white", fontWeight: "600" },
763
801
  tagDescription: { color: "rgba(255,255,255,0.4)", fontSize: 11, marginTop: 2, lineHeight: 14 },
764
802
  tagSubtitle: { color: "rgba(255,255,255,0.4)", fontSize: 10 },
803
+ deleteBtn: {
804
+ width: 24,
805
+ height: 24,
806
+ borderRadius: 12,
807
+ alignItems: "center",
808
+ justifyContent: "center"
809
+ },
765
810
  plusBtn: {
766
811
  width: 24,
767
812
  height: 24,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retor/react-native",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "React Native SDK for embedding Retor 3D experiences",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",