@retor/react-native 0.4.5 → 0.4.6
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 +44 -19
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -1
- package/dist/index.mjs +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,24 +111,43 @@ function MyLineCard({ line }: { line: RetorLine }) {
|
|
|
111
111
|
|
|
112
112
|
## Notes
|
|
113
113
|
|
|
114
|
-
`<AddNoteSheet>` triggers when you call `useAddNote().open(tagId?)
|
|
114
|
+
`<AddNoteSheet>` triggers when you call `useAddNote().open(tagId?)`. It collects text + private/public, then either:
|
|
115
|
+
- calls `onNoteSubmit` on the parent `<Viewer>` (if set) — **persistence is your responsibility**
|
|
116
|
+
- or falls back to persisting via Retor's own backend (Convex) when no `onNoteSubmit` is provided
|
|
117
|
+
|
|
118
|
+
Re-pass saved notes back to the 3D scene via `<Notes>`.
|
|
119
|
+
|
|
120
|
+
### Note fields for proper rendering
|
|
121
|
+
|
|
122
|
+
When passing notes via `<Notes>`, each note should include:
|
|
123
|
+
|
|
124
|
+
| Field | Required | Purpose |
|
|
125
|
+
|-------|----------|---------|
|
|
126
|
+
| `_id` | yes | Unique identifier |
|
|
127
|
+
| `name` | yes | The note text (displayed in the tag list and 3D scene) |
|
|
128
|
+
| `position` | yes | `{ x, y, z }` — where the note sits on the line |
|
|
129
|
+
| `objectId` | yes | Set to the `lineId` so the note associates with the correct line |
|
|
130
|
+
| `progress` | yes | `0..1` position along the line (from the submit payload) — used for sort order and scroll-to |
|
|
131
|
+
| `avatarUrl` | recommended | Profile image URL — renders as a circular avatar in the tag pill and list item |
|
|
132
|
+
| `authorName` | recommended | Display name — used as initial-letter fallback when no `avatarUrl` |
|
|
133
|
+
| `tagType` | recommended | Set to `"icon"` for the standard note pill appearance |
|
|
134
|
+
| `userId` | for deletion | The note author's user ID — compared against `Viewer.userId` to show the delete button |
|
|
135
|
+
|
|
136
|
+
### Creating + deleting notes
|
|
115
137
|
|
|
116
138
|
```tsx
|
|
117
139
|
import { useState } from "react";
|
|
118
|
-
import { Viewer, Hud, ProjectSheet, LineDetailSheet, AddNoteSheet, Notes,
|
|
119
|
-
|
|
120
|
-
function AddButton() {
|
|
121
|
-
const { open } = useAddNote();
|
|
122
|
-
return <Pressable onPress={() => open()}><Text>+</Text></Pressable>;
|
|
123
|
-
}
|
|
140
|
+
import { Viewer, Hud, ProjectSheet, LineDetailSheet, AddNoteSheet, Notes, type RetorTag } from "@retor/react-native";
|
|
124
141
|
|
|
125
142
|
export default function Scene() {
|
|
126
143
|
const [notes, setNotes] = useState<RetorTag[]>([]);
|
|
144
|
+
const currentUserId = "user_abc"; // your auth system's user ID
|
|
127
145
|
|
|
128
146
|
return (
|
|
129
147
|
<Viewer
|
|
130
148
|
projectId="abc123"
|
|
131
|
-
|
|
149
|
+
userId={currentUserId}
|
|
150
|
+
onNoteSubmit={({ text, isPrivate, lineId, position, progress }) => {
|
|
132
151
|
if (!position) return;
|
|
133
152
|
setNotes((prev) => [
|
|
134
153
|
...prev,
|
|
@@ -136,24 +155,24 @@ export default function Scene() {
|
|
|
136
155
|
_id: `note-${Date.now()}`,
|
|
137
156
|
name: text,
|
|
138
157
|
position,
|
|
158
|
+
progress,
|
|
139
159
|
objectId: lineId ?? undefined,
|
|
160
|
+
tagType: "icon",
|
|
161
|
+
avatarUrl: "https://example.com/avatar.jpg",
|
|
162
|
+
authorName: "Jane",
|
|
163
|
+
userId: currentUserId,
|
|
140
164
|
},
|
|
141
165
|
]);
|
|
142
166
|
}}
|
|
167
|
+
onNoteDelete={(noteId) => {
|
|
168
|
+
setNotes((prev) => prev.filter((n) => n._id !== noteId));
|
|
169
|
+
// also delete from your backend
|
|
170
|
+
}}
|
|
143
171
|
>
|
|
144
172
|
<Notes notes={notes} />
|
|
145
173
|
<Hud>
|
|
146
174
|
<ProjectSheet />
|
|
147
|
-
<LineDetailSheet
|
|
148
|
-
<LineTagList>
|
|
149
|
-
{(tag, isActive) => (
|
|
150
|
-
<View style={{ flexDirection: "row", padding: 12 }}>
|
|
151
|
-
<Text style={{ flex: 1, color: isActive ? "white" : "gray" }}>{tag.name}</Text>
|
|
152
|
-
{isActive && <AddButton />}
|
|
153
|
-
</View>
|
|
154
|
-
)}
|
|
155
|
-
</LineTagList>
|
|
156
|
-
</LineDetailSheet>
|
|
175
|
+
<LineDetailSheet />
|
|
157
176
|
<AddNoteSheet />
|
|
158
177
|
</Hud>
|
|
159
178
|
</Viewer>
|
|
@@ -161,6 +180,12 @@ export default function Scene() {
|
|
|
161
180
|
}
|
|
162
181
|
```
|
|
163
182
|
|
|
183
|
+
When `onNoteSubmit` is **not** provided, the SDK sends the note to Retor's backend automatically (using the signed-in Clerk session inside the WebView). No `<Notes>` re-injection needed in that case.
|
|
184
|
+
|
|
185
|
+
When a user deletes a note, the SDK:
|
|
186
|
+
1. Optimistically removes it from the local tag list
|
|
187
|
+
2. Fires `onNoteDelete(noteId)` so you can delete from your backend
|
|
188
|
+
|
|
164
189
|
## Hooks
|
|
165
190
|
|
|
166
191
|
All hooks read from the bridge context provided by the parent `<Viewer>`.
|
|
@@ -173,7 +198,7 @@ All hooks read from the bridge context provided by the parent `<Viewer>`.
|
|
|
173
198
|
| `useLineProgress()` | `{ progress, closestTagId }` |
|
|
174
199
|
| `useAutoplay()` | `{ isPlaying, toggle, play, pause }` |
|
|
175
200
|
| `useAddNote()` | `{ isOpen, tagId, open, close, submit }` |
|
|
176
|
-
| `useViewer()` | Imperative controls (`openLine`, `exitLine`, `scrollToTag`, ...) |
|
|
201
|
+
| `useViewer()` | Imperative controls (`openLine`, `exitLine`, `scrollToTag`, `scrollToProgress`, ...) |
|
|
177
202
|
|
|
178
203
|
## Imperative API
|
|
179
204
|
|
package/dist/index.d.mts
CHANGED
|
@@ -36,6 +36,8 @@ interface RetorLine {
|
|
|
36
36
|
scrollType?: "track" | "observe";
|
|
37
37
|
closed?: boolean;
|
|
38
38
|
notesSupported?: boolean;
|
|
39
|
+
/** User-defined key/value fields set in the line editor. */
|
|
40
|
+
metadata?: Record<string, string | number | boolean>;
|
|
39
41
|
tags: RetorTag[];
|
|
40
42
|
}
|
|
41
43
|
interface RetorProject {
|
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ interface RetorLine {
|
|
|
36
36
|
scrollType?: "track" | "observe";
|
|
37
37
|
closed?: boolean;
|
|
38
38
|
notesSupported?: boolean;
|
|
39
|
+
/** User-defined key/value fields set in the line editor. */
|
|
40
|
+
metadata?: Record<string, string | number | boolean>;
|
|
39
41
|
tags: RetorTag[];
|
|
40
42
|
}
|
|
41
43
|
interface RetorProject {
|
package/dist/index.js
CHANGED
|
@@ -667,7 +667,7 @@ function LineDetailSheet({ snapPoints = ["35%", "75%"], topInset, renderHeader,
|
|
|
667
667
|
backgroundComponent: BlurBackground,
|
|
668
668
|
topInset: effectiveTopInset
|
|
669
669
|
},
|
|
670
|
-
activeLine && (children
|
|
670
|
+
activeLine && (children ? /* @__PURE__ */ import_react6.default.createElement(import_bottom_sheet3.BottomSheetScrollView, { contentContainerStyle: styles3.customContent }, children) : /* @__PURE__ */ import_react6.default.createElement(DefaultLineTagList, { listHeader: header }))
|
|
671
671
|
);
|
|
672
672
|
}
|
|
673
673
|
function DefaultHeader({
|
|
@@ -792,6 +792,7 @@ function DefaultTagItem({ tag, isActive }) {
|
|
|
792
792
|
}
|
|
793
793
|
var styles3 = import_react_native5.StyleSheet.create({
|
|
794
794
|
handle: { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
795
|
+
customContent: { paddingBottom: 120 },
|
|
795
796
|
header: {
|
|
796
797
|
flexDirection: "row",
|
|
797
798
|
alignItems: "flex-start",
|
package/dist/index.mjs
CHANGED
|
@@ -628,7 +628,7 @@ function LineDetailSheet({ snapPoints = ["35%", "75%"], topInset, renderHeader,
|
|
|
628
628
|
backgroundComponent: BlurBackground,
|
|
629
629
|
topInset: effectiveTopInset
|
|
630
630
|
},
|
|
631
|
-
activeLine && (children
|
|
631
|
+
activeLine && (children ? /* @__PURE__ */ React6.createElement(BottomSheetScrollView, { contentContainerStyle: styles3.customContent }, children) : /* @__PURE__ */ React6.createElement(DefaultLineTagList, { listHeader: header }))
|
|
632
632
|
);
|
|
633
633
|
}
|
|
634
634
|
function DefaultHeader({
|
|
@@ -753,6 +753,7 @@ function DefaultTagItem({ tag, isActive }) {
|
|
|
753
753
|
}
|
|
754
754
|
var styles3 = StyleSheet5.create({
|
|
755
755
|
handle: { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
756
|
+
customContent: { paddingBottom: 120 },
|
|
756
757
|
header: {
|
|
757
758
|
flexDirection: "row",
|
|
758
759
|
alignItems: "flex-start",
|