@retor/react-native 0.2.0 → 0.3.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/README.md +3 -3
- package/dist/index.d.mts +9 -37
- package/dist/index.d.ts +9 -37
- package/dist/index.js +174 -31
- package/dist/index.mjs +181 -38
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ Embed Retor 3D experiences in a React Native / Expo app — with composable bott
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# Expo
|
|
9
|
-
npx expo install react-native-webview react-native-gesture-handler react-native-reanimated
|
|
10
|
-
npm install @gorhom/bottom-sheet @retor/react-native
|
|
9
|
+
npx expo install react-native-webview react-native-gesture-handler react-native-reanimated react-native-svg
|
|
10
|
+
npm install @gorhom/bottom-sheet lucide-react-native @retor/react-native
|
|
11
11
|
|
|
12
12
|
# bare React Native
|
|
13
|
-
npm install react-native-webview react-native-gesture-handler react-native-reanimated @gorhom/bottom-sheet @retor/react-native
|
|
13
|
+
npm install react-native-webview react-native-gesture-handler react-native-reanimated react-native-svg @gorhom/bottom-sheet lucide-react-native @retor/react-native
|
|
14
14
|
cd ios && pod install
|
|
15
15
|
```
|
|
16
16
|
|
package/dist/index.d.mts
CHANGED
|
@@ -185,71 +185,43 @@ interface HudProps {
|
|
|
185
185
|
declare function Hud({ children }: HudProps): React.JSX.Element;
|
|
186
186
|
|
|
187
187
|
interface ProjectSheetProps {
|
|
188
|
-
/**
|
|
189
|
-
* Snap points for the sheet. Defaults to ["20%", "60%"].
|
|
190
|
-
*/
|
|
188
|
+
/** Snap points. Defaults to ["35%", "85%"]. */
|
|
191
189
|
snapPoints?: (string | number)[];
|
|
192
|
-
/**
|
|
193
|
-
* Override the default header (project name + description).
|
|
194
|
-
* Receives the project metadata.
|
|
195
|
-
*/
|
|
190
|
+
/** Override the default header (project name + description + arrow button). */
|
|
196
191
|
renderHeader?: (project: {
|
|
197
192
|
name?: string;
|
|
198
193
|
description?: string;
|
|
199
194
|
}) => React.ReactNode;
|
|
200
|
-
/**
|
|
201
|
-
* Children to render below the header. Typically a `<LinesCarousel>`.
|
|
202
|
-
* If omitted, a default LinesCarousel is rendered.
|
|
203
|
-
*/
|
|
195
|
+
/** Children to render inside. Defaults to a built-in `<LinesCarousel>`. */
|
|
204
196
|
children?: React.ReactNode;
|
|
205
197
|
}
|
|
206
198
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
* ```tsx
|
|
210
|
-
* <ProjectSheet>
|
|
211
|
-
* <LinesCarousel>
|
|
212
|
-
* {(line) => <MyLineCard line={line} />}
|
|
213
|
-
* </LinesCarousel>
|
|
214
|
-
* </ProjectSheet>
|
|
215
|
-
* ```
|
|
199
|
+
* Browse-mode bottom sheet — auto-presents whenever no line is open.
|
|
216
200
|
*/
|
|
217
201
|
declare function ProjectSheet({ snapPoints, renderHeader, children }: ProjectSheetProps): React.JSX.Element;
|
|
218
202
|
interface LinesCarouselProps {
|
|
219
203
|
children: (line: RetorLine, index: number) => React.ReactNode;
|
|
220
|
-
/** Optional gap between items. Defaults to 12. */
|
|
221
204
|
gap?: number;
|
|
222
|
-
/** Optional horizontal padding. Defaults to 16. */
|
|
223
205
|
paddingHorizontal?: number;
|
|
224
206
|
}
|
|
225
|
-
/**
|
|
226
|
-
* Renders a horizontally scrolling list of lines using a render prop.
|
|
227
|
-
* Place inside `<ProjectSheet>`.
|
|
228
|
-
*
|
|
229
|
-
* Pressing an item is up to your render — use `useViewer().openLine(line._id)`.
|
|
230
|
-
*/
|
|
231
207
|
declare function LinesCarousel({ children, gap, paddingHorizontal }: LinesCarouselProps): React.JSX.Element | null;
|
|
232
208
|
|
|
233
209
|
interface LineDetailSheetProps {
|
|
234
|
-
/** Snap points. Defaults to ["
|
|
210
|
+
/** Snap points. Defaults to ["35%", "85%"]. */
|
|
235
211
|
snapPoints?: (string | number)[];
|
|
236
|
-
/** Override the header.
|
|
212
|
+
/** Override the header. */
|
|
237
213
|
renderHeader?: (line: RetorLine) => React.ReactNode;
|
|
238
|
-
/** Custom content (typically a `<LineTagList>`).
|
|
214
|
+
/** Custom content (typically a `<LineTagList>`). */
|
|
239
215
|
children?: React.ReactNode;
|
|
240
216
|
}
|
|
241
217
|
/**
|
|
242
|
-
* Sheet
|
|
243
|
-
*
|
|
218
|
+
* Sheet shown when a line is open. Includes a default header with the
|
|
219
|
+
* autoplay button + minimize arrow, the tag list, and a Done footer.
|
|
244
220
|
*/
|
|
245
221
|
declare function LineDetailSheet({ snapPoints, renderHeader, children }: LineDetailSheetProps): React.JSX.Element;
|
|
246
222
|
interface LineTagListProps {
|
|
247
223
|
children: (tag: RetorTag, isActive: boolean) => React.ReactNode;
|
|
248
224
|
}
|
|
249
|
-
/**
|
|
250
|
-
* Renders the tags of the active line as a vertical list. Re-renders the
|
|
251
|
-
* active item when the camera scrolls to it. Empty when no line is open.
|
|
252
|
-
*/
|
|
253
225
|
declare function LineTagList({ children }: LineTagListProps): React.JSX.Element | null;
|
|
254
226
|
|
|
255
227
|
interface AddNoteSheetProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -185,71 +185,43 @@ interface HudProps {
|
|
|
185
185
|
declare function Hud({ children }: HudProps): React.JSX.Element;
|
|
186
186
|
|
|
187
187
|
interface ProjectSheetProps {
|
|
188
|
-
/**
|
|
189
|
-
* Snap points for the sheet. Defaults to ["20%", "60%"].
|
|
190
|
-
*/
|
|
188
|
+
/** Snap points. Defaults to ["35%", "85%"]. */
|
|
191
189
|
snapPoints?: (string | number)[];
|
|
192
|
-
/**
|
|
193
|
-
* Override the default header (project name + description).
|
|
194
|
-
* Receives the project metadata.
|
|
195
|
-
*/
|
|
190
|
+
/** Override the default header (project name + description + arrow button). */
|
|
196
191
|
renderHeader?: (project: {
|
|
197
192
|
name?: string;
|
|
198
193
|
description?: string;
|
|
199
194
|
}) => React.ReactNode;
|
|
200
|
-
/**
|
|
201
|
-
* Children to render below the header. Typically a `<LinesCarousel>`.
|
|
202
|
-
* If omitted, a default LinesCarousel is rendered.
|
|
203
|
-
*/
|
|
195
|
+
/** Children to render inside. Defaults to a built-in `<LinesCarousel>`. */
|
|
204
196
|
children?: React.ReactNode;
|
|
205
197
|
}
|
|
206
198
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
* ```tsx
|
|
210
|
-
* <ProjectSheet>
|
|
211
|
-
* <LinesCarousel>
|
|
212
|
-
* {(line) => <MyLineCard line={line} />}
|
|
213
|
-
* </LinesCarousel>
|
|
214
|
-
* </ProjectSheet>
|
|
215
|
-
* ```
|
|
199
|
+
* Browse-mode bottom sheet — auto-presents whenever no line is open.
|
|
216
200
|
*/
|
|
217
201
|
declare function ProjectSheet({ snapPoints, renderHeader, children }: ProjectSheetProps): React.JSX.Element;
|
|
218
202
|
interface LinesCarouselProps {
|
|
219
203
|
children: (line: RetorLine, index: number) => React.ReactNode;
|
|
220
|
-
/** Optional gap between items. Defaults to 12. */
|
|
221
204
|
gap?: number;
|
|
222
|
-
/** Optional horizontal padding. Defaults to 16. */
|
|
223
205
|
paddingHorizontal?: number;
|
|
224
206
|
}
|
|
225
|
-
/**
|
|
226
|
-
* Renders a horizontally scrolling list of lines using a render prop.
|
|
227
|
-
* Place inside `<ProjectSheet>`.
|
|
228
|
-
*
|
|
229
|
-
* Pressing an item is up to your render — use `useViewer().openLine(line._id)`.
|
|
230
|
-
*/
|
|
231
207
|
declare function LinesCarousel({ children, gap, paddingHorizontal }: LinesCarouselProps): React.JSX.Element | null;
|
|
232
208
|
|
|
233
209
|
interface LineDetailSheetProps {
|
|
234
|
-
/** Snap points. Defaults to ["
|
|
210
|
+
/** Snap points. Defaults to ["35%", "85%"]. */
|
|
235
211
|
snapPoints?: (string | number)[];
|
|
236
|
-
/** Override the header.
|
|
212
|
+
/** Override the header. */
|
|
237
213
|
renderHeader?: (line: RetorLine) => React.ReactNode;
|
|
238
|
-
/** Custom content (typically a `<LineTagList>`).
|
|
214
|
+
/** Custom content (typically a `<LineTagList>`). */
|
|
239
215
|
children?: React.ReactNode;
|
|
240
216
|
}
|
|
241
217
|
/**
|
|
242
|
-
* Sheet
|
|
243
|
-
*
|
|
218
|
+
* Sheet shown when a line is open. Includes a default header with the
|
|
219
|
+
* autoplay button + minimize arrow, the tag list, and a Done footer.
|
|
244
220
|
*/
|
|
245
221
|
declare function LineDetailSheet({ snapPoints, renderHeader, children }: LineDetailSheetProps): React.JSX.Element;
|
|
246
222
|
interface LineTagListProps {
|
|
247
223
|
children: (tag: RetorTag, isActive: boolean) => React.ReactNode;
|
|
248
224
|
}
|
|
249
|
-
/**
|
|
250
|
-
* Renders the tags of the active line as a vertical list. Re-renders the
|
|
251
|
-
* active item when the camera scrolls to it. Empty when no line is open.
|
|
252
|
-
*/
|
|
253
225
|
declare function LineTagList({ children }: LineTagListProps): React.JSX.Element | null;
|
|
254
226
|
|
|
255
227
|
interface AddNoteSheetProps {
|
package/dist/index.js
CHANGED
|
@@ -359,17 +359,30 @@ function Hud({ children }) {
|
|
|
359
359
|
var import_react4 = __toESM(require("react"));
|
|
360
360
|
var import_react_native3 = require("react-native");
|
|
361
361
|
var import_bottom_sheet2 = require("@gorhom/bottom-sheet");
|
|
362
|
-
|
|
362
|
+
var import_lucide_react_native = require("lucide-react-native");
|
|
363
|
+
function ProjectSheet({ snapPoints = ["35%", "85%"], renderHeader, children }) {
|
|
363
364
|
const { project, activeLineId, isAddNoteOpen } = useRetorBridge();
|
|
364
365
|
const sheetRef = (0, import_react4.useRef)(null);
|
|
365
366
|
const snapPointsArr = (0, import_react4.useMemo)(() => snapPoints, [snapPoints]);
|
|
367
|
+
const [minimized, setMinimized] = (0, import_react4.useState)(false);
|
|
366
368
|
(0, import_react4.useEffect)(() => {
|
|
367
369
|
if (activeLineId || isAddNoteOpen) {
|
|
368
370
|
sheetRef.current?.dismiss();
|
|
369
371
|
} else {
|
|
370
372
|
sheetRef.current?.present();
|
|
373
|
+
setMinimized(false);
|
|
371
374
|
}
|
|
372
375
|
}, [activeLineId, isAddNoteOpen]);
|
|
376
|
+
const handleSheetChange = (index) => {
|
|
377
|
+
setMinimized(index === 0);
|
|
378
|
+
};
|
|
379
|
+
const toggleMinimize = () => {
|
|
380
|
+
if (minimized) {
|
|
381
|
+
sheetRef.current?.snapToIndex(snapPointsArr.length - 1);
|
|
382
|
+
} else {
|
|
383
|
+
sheetRef.current?.snapToIndex(0);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
373
386
|
return /* @__PURE__ */ import_react4.default.createElement(
|
|
374
387
|
import_bottom_sheet2.BottomSheetModal,
|
|
375
388
|
{
|
|
@@ -377,6 +390,7 @@ function ProjectSheet({ snapPoints = ["20%", "60%"], renderHeader, children }) {
|
|
|
377
390
|
snapPoints: snapPointsArr,
|
|
378
391
|
enablePanDownToClose: false,
|
|
379
392
|
enableDismissOnClose: false,
|
|
393
|
+
onChange: handleSheetChange,
|
|
380
394
|
backdropComponent: (props) => /* @__PURE__ */ import_react4.default.createElement(
|
|
381
395
|
import_bottom_sheet2.BottomSheetBackdrop,
|
|
382
396
|
{
|
|
@@ -390,7 +404,7 @@ function ProjectSheet({ snapPoints = ["20%", "60%"], renderHeader, children }) {
|
|
|
390
404
|
handleIndicatorStyle: styles2.handle,
|
|
391
405
|
backgroundStyle: styles2.background
|
|
392
406
|
},
|
|
393
|
-
/* @__PURE__ */ import_react4.default.createElement(import_bottom_sheet2.BottomSheetView, { style: styles2.content }, renderHeader ? renderHeader({ name: project?.name, description: project?.description }) : /* @__PURE__ */ import_react4.default.createElement(import_react_native3.View, { style: styles2.header }, project?.name && /* @__PURE__ */ import_react4.default.createElement(import_react_native3.Text, { style: styles2.title }, project.name), project?.description && /* @__PURE__ */ import_react4.default.createElement(import_react_native3.Text, { style: styles2.subtitle, numberOfLines: 4 }, project.description)), children ?? /* @__PURE__ */ import_react4.default.createElement(DefaultLinesCarousel, null))
|
|
407
|
+
/* @__PURE__ */ import_react4.default.createElement(import_bottom_sheet2.BottomSheetView, { style: styles2.content }, renderHeader ? renderHeader({ name: project?.name, description: project?.description }) : /* @__PURE__ */ import_react4.default.createElement(import_react_native3.View, { style: styles2.header }, /* @__PURE__ */ import_react4.default.createElement(import_react_native3.View, { style: { flex: 1, minWidth: 0 } }, project?.name && /* @__PURE__ */ import_react4.default.createElement(import_react_native3.Text, { style: styles2.title, numberOfLines: 1 }, project.name), project?.description && /* @__PURE__ */ import_react4.default.createElement(import_react_native3.Text, { style: styles2.subtitle, numberOfLines: 4 }, project.description)), /* @__PURE__ */ import_react4.default.createElement(import_react_native3.Pressable, { style: styles2.iconBtn, onPress: toggleMinimize }, minimized ? /* @__PURE__ */ import_react4.default.createElement(import_lucide_react_native.ArrowUp, { size: 14, color: "rgba(255,255,255,0.6)" }) : /* @__PURE__ */ import_react4.default.createElement(import_lucide_react_native.ArrowDown, { size: 14, color: "rgba(255,255,255,0.6)" }))), children ?? /* @__PURE__ */ import_react4.default.createElement(DefaultLinesCarousel, null))
|
|
394
408
|
);
|
|
395
409
|
}
|
|
396
410
|
function DefaultLinesCarousel() {
|
|
@@ -399,16 +413,15 @@ function DefaultLinesCarousel() {
|
|
|
399
413
|
function LinesCarousel({ children, gap = 12, paddingHorizontal = 16 }) {
|
|
400
414
|
const { lines } = useRetorBridge();
|
|
401
415
|
if (lines.length === 0) return null;
|
|
402
|
-
return /* @__PURE__ */ import_react4.default.createElement(
|
|
416
|
+
return /* @__PURE__ */ import_react4.default.createElement(import_react_native3.View, { style: styles2.carouselWrap }, /* @__PURE__ */ import_react4.default.createElement(import_react_native3.Text, { style: styles2.carouselLabel }, "Routes"), /* @__PURE__ */ import_react4.default.createElement(
|
|
403
417
|
import_react_native3.ScrollView,
|
|
404
418
|
{
|
|
405
419
|
horizontal: true,
|
|
406
420
|
showsHorizontalScrollIndicator: false,
|
|
407
|
-
contentContainerStyle: { paddingHorizontal, gap }
|
|
408
|
-
style: styles2.carousel
|
|
421
|
+
contentContainerStyle: { paddingHorizontal, gap }
|
|
409
422
|
},
|
|
410
423
|
lines.map((line, idx) => /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, { key: line._id }, children(line, idx)))
|
|
411
|
-
);
|
|
424
|
+
));
|
|
412
425
|
}
|
|
413
426
|
function DefaultLineCard({ line }) {
|
|
414
427
|
const { controls } = useRetorBridge();
|
|
@@ -426,10 +439,33 @@ var styles2 = import_react_native3.StyleSheet.create({
|
|
|
426
439
|
background: { backgroundColor: "rgba(20,20,20,0.95)" },
|
|
427
440
|
handle: { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
428
441
|
content: { flex: 1, paddingTop: 12, paddingBottom: 24 },
|
|
429
|
-
header: {
|
|
442
|
+
header: {
|
|
443
|
+
flexDirection: "row",
|
|
444
|
+
alignItems: "flex-start",
|
|
445
|
+
paddingHorizontal: 24,
|
|
446
|
+
paddingBottom: 16,
|
|
447
|
+
gap: 8
|
|
448
|
+
},
|
|
430
449
|
title: { color: "white", fontSize: 18, fontWeight: "600", lineHeight: 22 },
|
|
431
450
|
subtitle: { color: "rgba(255,255,255,0.6)", fontSize: 13, marginTop: 4, lineHeight: 18 },
|
|
432
|
-
|
|
451
|
+
iconBtn: {
|
|
452
|
+
width: 28,
|
|
453
|
+
height: 28,
|
|
454
|
+
borderRadius: 14,
|
|
455
|
+
backgroundColor: "rgba(255,255,255,0.1)",
|
|
456
|
+
alignItems: "center",
|
|
457
|
+
justifyContent: "center"
|
|
458
|
+
},
|
|
459
|
+
carouselWrap: { marginTop: 8 },
|
|
460
|
+
carouselLabel: {
|
|
461
|
+
color: "rgba(255,255,255,0.4)",
|
|
462
|
+
fontSize: 10,
|
|
463
|
+
textTransform: "uppercase",
|
|
464
|
+
letterSpacing: 1,
|
|
465
|
+
fontWeight: "500",
|
|
466
|
+
paddingHorizontal: 24,
|
|
467
|
+
marginBottom: 8
|
|
468
|
+
},
|
|
433
469
|
lineCard: {
|
|
434
470
|
width: 220,
|
|
435
471
|
backgroundColor: "rgba(255,255,255,0.06)",
|
|
@@ -444,17 +480,31 @@ var styles2 = import_react_native3.StyleSheet.create({
|
|
|
444
480
|
var import_react5 = __toESM(require("react"));
|
|
445
481
|
var import_react_native4 = require("react-native");
|
|
446
482
|
var import_bottom_sheet3 = require("@gorhom/bottom-sheet");
|
|
447
|
-
|
|
483
|
+
var import_react_native_svg = __toESM(require("react-native-svg"));
|
|
484
|
+
var import_lucide_react_native2 = require("lucide-react-native");
|
|
485
|
+
function LineDetailSheet({ snapPoints = ["35%", "85%"], renderHeader, children }) {
|
|
448
486
|
const { activeLine, isAddNoteOpen, controls } = useRetorBridge();
|
|
449
487
|
const sheetRef = (0, import_react5.useRef)(null);
|
|
450
488
|
const snapPointsArr = (0, import_react5.useMemo)(() => snapPoints, [snapPoints]);
|
|
489
|
+
const [minimized, setMinimized] = (0, import_react5.useState)(false);
|
|
451
490
|
(0, import_react5.useEffect)(() => {
|
|
452
491
|
if (activeLine && !isAddNoteOpen) {
|
|
453
492
|
sheetRef.current?.present();
|
|
493
|
+
setMinimized(false);
|
|
454
494
|
} else {
|
|
455
495
|
sheetRef.current?.dismiss();
|
|
456
496
|
}
|
|
457
497
|
}, [activeLine, isAddNoteOpen]);
|
|
498
|
+
const handleSheetChange = (index) => {
|
|
499
|
+
setMinimized(index === 0);
|
|
500
|
+
};
|
|
501
|
+
const toggleMinimize = () => {
|
|
502
|
+
if (minimized) {
|
|
503
|
+
sheetRef.current?.snapToIndex(snapPointsArr.length - 1);
|
|
504
|
+
} else {
|
|
505
|
+
sheetRef.current?.snapToIndex(0);
|
|
506
|
+
}
|
|
507
|
+
};
|
|
458
508
|
return /* @__PURE__ */ import_react5.default.createElement(
|
|
459
509
|
import_bottom_sheet3.BottomSheetModal,
|
|
460
510
|
{
|
|
@@ -462,6 +512,7 @@ function LineDetailSheet({ snapPoints = ["25%", "75%"], renderHeader, children }
|
|
|
462
512
|
snapPoints: snapPointsArr,
|
|
463
513
|
enablePanDownToClose: false,
|
|
464
514
|
enableDismissOnClose: false,
|
|
515
|
+
onChange: handleSheetChange,
|
|
465
516
|
backdropComponent: (props) => /* @__PURE__ */ import_react5.default.createElement(
|
|
466
517
|
import_bottom_sheet3.BottomSheetBackdrop,
|
|
467
518
|
{
|
|
@@ -475,60 +526,153 @@ function LineDetailSheet({ snapPoints = ["25%", "75%"], renderHeader, children }
|
|
|
475
526
|
handleIndicatorStyle: styles3.handle,
|
|
476
527
|
backgroundStyle: styles3.background
|
|
477
528
|
},
|
|
478
|
-
|
|
529
|
+
activeLine && /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: styles3.root }, renderHeader ? renderHeader(activeLine) : /* @__PURE__ */ import_react5.default.createElement(
|
|
530
|
+
DefaultHeader,
|
|
531
|
+
{
|
|
532
|
+
line: activeLine,
|
|
533
|
+
minimized,
|
|
534
|
+
onToggleMinimize: toggleMinimize
|
|
535
|
+
}
|
|
536
|
+
), /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: styles3.listContainer }, children ?? /* @__PURE__ */ import_react5.default.createElement(DefaultLineTagList, null)), /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: styles3.footer }, /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Pressable, { style: styles3.doneButton, onPress: () => controls.exitLine() }, /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.doneText }, "Done"))))
|
|
479
537
|
);
|
|
480
538
|
}
|
|
481
|
-
function
|
|
482
|
-
|
|
539
|
+
function DefaultHeader({
|
|
540
|
+
line,
|
|
541
|
+
minimized,
|
|
542
|
+
onToggleMinimize
|
|
543
|
+
}) {
|
|
544
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: styles3.header }, /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.title, numberOfLines: 1 }, line.name), line.subtitle && /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.subtitle, numberOfLines: 1 }, line.subtitle), line.description && /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.description, numberOfLines: minimized ? 2 : 4 }, line.description)), /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: styles3.headerActions }, /* @__PURE__ */ import_react5.default.createElement(AutoplayButton, null), /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Pressable, { style: styles3.iconBtn, onPress: onToggleMinimize }, minimized ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react_native2.ArrowUp, { size: 14, color: "rgba(255,255,255,0.6)" }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react_native2.ArrowDown, { size: 14, color: "rgba(255,255,255,0.6)" }))));
|
|
545
|
+
}
|
|
546
|
+
function AutoplayButton() {
|
|
547
|
+
const { isPlaying, progress, controls } = useRetorBridge();
|
|
548
|
+
const r = 12.5;
|
|
549
|
+
const c = 2 * Math.PI * r;
|
|
550
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Pressable, { style: styles3.iconBtn, onPress: () => controls.toggleAutoplay() }, /* @__PURE__ */ import_react5.default.createElement(import_react_native_svg.default, { width: 28, height: 28, style: import_react_native4.StyleSheet.absoluteFill }, /* @__PURE__ */ import_react5.default.createElement(
|
|
551
|
+
import_react_native_svg.Circle,
|
|
552
|
+
{
|
|
553
|
+
cx: 14,
|
|
554
|
+
cy: 14,
|
|
555
|
+
r,
|
|
556
|
+
fill: "none",
|
|
557
|
+
stroke: "white",
|
|
558
|
+
strokeWidth: 2,
|
|
559
|
+
strokeDasharray: `${c}`,
|
|
560
|
+
strokeDashoffset: c * (1 - progress),
|
|
561
|
+
strokeLinecap: "round",
|
|
562
|
+
transform: "rotate(-90, 14, 14)"
|
|
563
|
+
}
|
|
564
|
+
)), isPlaying ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react_native2.Pause, { size: 11, color: "white", fill: "white" }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react_native2.Play, { size: 11, color: "white", fill: "white", style: { marginLeft: 1 } }));
|
|
483
565
|
}
|
|
484
566
|
function LineTagList({ children }) {
|
|
485
567
|
const { activeLine, closestTagId } = useRetorBridge();
|
|
568
|
+
const listRef = (0, import_react5.useRef)(null);
|
|
486
569
|
const tags = (0, import_react5.useMemo)(
|
|
487
570
|
() => (activeLine?.tags ?? []).filter((t) => t.name && t.name.trim().length > 0),
|
|
488
571
|
[activeLine]
|
|
489
572
|
);
|
|
573
|
+
(0, import_react5.useEffect)(() => {
|
|
574
|
+
if (!closestTagId) return;
|
|
575
|
+
const index = tags.findIndex((t) => t._id === closestTagId);
|
|
576
|
+
if (index < 0) return;
|
|
577
|
+
requestAnimationFrame(() => {
|
|
578
|
+
try {
|
|
579
|
+
listRef.current?.scrollToIndex({ index, animated: true, viewPosition: 0 });
|
|
580
|
+
} catch {
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
}, [closestTagId, tags]);
|
|
490
584
|
if (!activeLine) return null;
|
|
491
585
|
return /* @__PURE__ */ import_react5.default.createElement(
|
|
492
586
|
import_bottom_sheet3.BottomSheetFlatList,
|
|
493
587
|
{
|
|
588
|
+
ref: listRef,
|
|
494
589
|
data: tags,
|
|
495
590
|
keyExtractor: (t) => t._id,
|
|
496
591
|
renderItem: ({ item }) => /* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, null, children(item, item._id === closestTagId)),
|
|
497
|
-
contentContainerStyle: styles3.list
|
|
592
|
+
contentContainerStyle: styles3.list,
|
|
593
|
+
onScrollToIndexFailed: (info) => {
|
|
594
|
+
setTimeout(() => {
|
|
595
|
+
listRef.current?.scrollToOffset({ offset: info.averageItemLength * info.index, animated: true });
|
|
596
|
+
}, 100);
|
|
597
|
+
}
|
|
498
598
|
}
|
|
499
599
|
);
|
|
500
600
|
}
|
|
601
|
+
function DefaultLineTagList() {
|
|
602
|
+
return /* @__PURE__ */ import_react5.default.createElement(LineTagList, null, (tag, isActive) => /* @__PURE__ */ import_react5.default.createElement(DefaultTagItem, { tag, isActive }));
|
|
603
|
+
}
|
|
501
604
|
function DefaultTagItem({ tag, isActive }) {
|
|
502
|
-
const { controls } = useRetorBridge();
|
|
605
|
+
const { controls, openAddNote, activeLine } = useRetorBridge();
|
|
606
|
+
const showPlus = isActive && (activeLine?.notesSupported ?? false);
|
|
503
607
|
return /* @__PURE__ */ import_react5.default.createElement(
|
|
504
608
|
import_react_native4.Pressable,
|
|
505
609
|
{
|
|
506
610
|
onPress: () => controls.scrollToTag(tag._id),
|
|
507
611
|
style: [styles3.tagItem, isActive && styles3.tagItemActive]
|
|
508
612
|
},
|
|
509
|
-
/* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: 1 }, tag.name),
|
|
510
|
-
tag.subtitle && /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle)
|
|
613
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native4.View, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: 1 }, tag.name), isActive && tag.description && /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.tagDescription, numberOfLines: 2 }, tag.description)),
|
|
614
|
+
tag.subtitle && /* @__PURE__ */ import_react5.default.createElement(import_react_native4.Text, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle),
|
|
615
|
+
showPlus && /* @__PURE__ */ import_react5.default.createElement(
|
|
616
|
+
import_react_native4.Pressable,
|
|
617
|
+
{
|
|
618
|
+
onPress: (e) => {
|
|
619
|
+
e.stopPropagation();
|
|
620
|
+
openAddNote(tag._id);
|
|
621
|
+
},
|
|
622
|
+
style: styles3.plusBtn
|
|
623
|
+
},
|
|
624
|
+
/* @__PURE__ */ import_react5.default.createElement(import_lucide_react_native2.Plus, { size: 14, color: "white" })
|
|
625
|
+
)
|
|
511
626
|
);
|
|
512
627
|
}
|
|
513
628
|
var styles3 = import_react_native4.StyleSheet.create({
|
|
514
629
|
background: { backgroundColor: "rgba(20,20,20,0.95)" },
|
|
515
630
|
handle: { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
516
|
-
|
|
517
|
-
header: {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
631
|
+
root: { flex: 1 },
|
|
632
|
+
header: {
|
|
633
|
+
flexDirection: "row",
|
|
634
|
+
alignItems: "flex-start",
|
|
635
|
+
paddingHorizontal: 24,
|
|
636
|
+
paddingTop: 8,
|
|
637
|
+
paddingBottom: 12,
|
|
638
|
+
gap: 8
|
|
639
|
+
},
|
|
640
|
+
headerActions: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
641
|
+
title: { color: "white", fontSize: 18, fontWeight: "700" },
|
|
642
|
+
subtitle: { color: "rgba(255,255,255,0.5)", fontSize: 12, marginTop: 2 },
|
|
643
|
+
description: { color: "rgba(255,255,255,0.6)", fontSize: 12, marginTop: 6, lineHeight: 18 },
|
|
644
|
+
iconBtn: {
|
|
645
|
+
width: 28,
|
|
646
|
+
height: 28,
|
|
647
|
+
borderRadius: 14,
|
|
648
|
+
backgroundColor: "rgba(255,255,255,0.1)",
|
|
649
|
+
alignItems: "center",
|
|
650
|
+
justifyContent: "center",
|
|
651
|
+
position: "relative"
|
|
652
|
+
},
|
|
653
|
+
listContainer: { flex: 1 },
|
|
654
|
+
list: { paddingHorizontal: 16, paddingBottom: 8, gap: 4 },
|
|
522
655
|
tagItem: {
|
|
656
|
+
flexDirection: "row",
|
|
657
|
+
alignItems: "center",
|
|
523
658
|
paddingHorizontal: 12,
|
|
524
|
-
paddingVertical:
|
|
659
|
+
paddingVertical: 12,
|
|
525
660
|
borderRadius: 12,
|
|
526
|
-
|
|
661
|
+
gap: 8
|
|
527
662
|
},
|
|
528
663
|
tagItemActive: { backgroundColor: "rgba(255,255,255,0.1)" },
|
|
529
|
-
tagText: { color: "rgba(255,255,255,0.6)", fontSize:
|
|
664
|
+
tagText: { color: "rgba(255,255,255,0.6)", fontSize: 13 },
|
|
530
665
|
tagTextActive: { color: "white", fontWeight: "600" },
|
|
531
|
-
|
|
666
|
+
tagDescription: { color: "rgba(255,255,255,0.4)", fontSize: 11, marginTop: 2, lineHeight: 14 },
|
|
667
|
+
tagSubtitle: { color: "rgba(255,255,255,0.4)", fontSize: 10 },
|
|
668
|
+
plusBtn: {
|
|
669
|
+
width: 22,
|
|
670
|
+
height: 22,
|
|
671
|
+
borderRadius: 11,
|
|
672
|
+
backgroundColor: "rgba(255,255,255,0.15)",
|
|
673
|
+
alignItems: "center",
|
|
674
|
+
justifyContent: "center"
|
|
675
|
+
},
|
|
532
676
|
footer: { paddingHorizontal: 16, paddingBottom: 16, paddingTop: 8 },
|
|
533
677
|
doneButton: {
|
|
534
678
|
backgroundColor: "white",
|
|
@@ -543,6 +687,7 @@ var styles3 = import_react_native4.StyleSheet.create({
|
|
|
543
687
|
var import_react6 = __toESM(require("react"));
|
|
544
688
|
var import_react_native5 = require("react-native");
|
|
545
689
|
var import_bottom_sheet4 = require("@gorhom/bottom-sheet");
|
|
690
|
+
var import_lucide_react_native3 = require("lucide-react-native");
|
|
546
691
|
function AddNoteSheet({
|
|
547
692
|
snapPoints = ["50%"],
|
|
548
693
|
maxLength = 280,
|
|
@@ -602,7 +747,7 @@ function AddNoteSheet({
|
|
|
602
747
|
handleIndicatorStyle: styles4.handle,
|
|
603
748
|
backgroundStyle: styles4.background
|
|
604
749
|
},
|
|
605
|
-
/* @__PURE__ */ import_react6.default.createElement(import_bottom_sheet4.BottomSheetView, { style: styles4.content }, renderForm ? renderForm(formApi) : /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: styles4.form }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: styles4.headerRow }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: { flex: 1 } }, activeLine && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles4.title, numberOfLines: 1 }, activeLine.name), tag && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles4.subtitle, numberOfLines: 1 }, tag.name)), /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Pressable, { onPress: closeAddNote, style: styles4.closeBtn }, /* @__PURE__ */ import_react6.default.createElement(
|
|
750
|
+
/* @__PURE__ */ import_react6.default.createElement(import_bottom_sheet4.BottomSheetView, { style: styles4.content }, renderForm ? renderForm(formApi) : /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: styles4.form }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: styles4.headerRow }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: { flex: 1 } }, activeLine && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles4.title, numberOfLines: 1 }, activeLine.name), tag && /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Text, { style: styles4.subtitle, numberOfLines: 1 }, tag.name)), /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Pressable, { onPress: closeAddNote, style: styles4.closeBtn }, /* @__PURE__ */ import_react6.default.createElement(import_lucide_react_native3.X, { size: 14, color: "rgba(255,255,255,0.6)" }))), /* @__PURE__ */ import_react6.default.createElement(
|
|
606
751
|
import_bottom_sheet4.BottomSheetTextInput,
|
|
607
752
|
{
|
|
608
753
|
value: text,
|
|
@@ -629,7 +774,7 @@ function AddNoteSheet({
|
|
|
629
774
|
disabled: !text.trim(),
|
|
630
775
|
style: [styles4.submit, !text.trim() && styles4.submitDisabled]
|
|
631
776
|
},
|
|
632
|
-
/* @__PURE__ */ import_react6.default.createElement(
|
|
777
|
+
/* @__PURE__ */ import_react6.default.createElement(import_lucide_react_native3.ArrowUp, { size: 16, color: "black", strokeWidth: 2.5 })
|
|
633
778
|
))))
|
|
634
779
|
);
|
|
635
780
|
}
|
|
@@ -649,7 +794,6 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
649
794
|
alignItems: "center",
|
|
650
795
|
justifyContent: "center"
|
|
651
796
|
},
|
|
652
|
-
closeBtnText: { color: "rgba(255,255,255,0.6)", fontSize: 14 },
|
|
653
797
|
input: {
|
|
654
798
|
flex: 1,
|
|
655
799
|
color: "white",
|
|
@@ -683,8 +827,7 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
683
827
|
alignItems: "center",
|
|
684
828
|
justifyContent: "center"
|
|
685
829
|
},
|
|
686
|
-
submitDisabled: { opacity: 0.3 }
|
|
687
|
-
submitArrow: { color: "black", fontSize: 16, fontWeight: "700" }
|
|
830
|
+
submitDisabled: { opacity: 0.3 }
|
|
688
831
|
});
|
|
689
832
|
|
|
690
833
|
// src/CoverPhoto.tsx
|
package/dist/index.mjs
CHANGED
|
@@ -313,20 +313,33 @@ function Hud({ children }) {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// src/ProjectSheet.tsx
|
|
316
|
-
import React4, { useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2 } from "react";
|
|
316
|
+
import React4, { useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState as useState2 } from "react";
|
|
317
317
|
import { Pressable, ScrollView, StyleSheet as StyleSheet3, Text, View as View3 } from "react-native";
|
|
318
318
|
import { BottomSheetBackdrop, BottomSheetModal, BottomSheetView } from "@gorhom/bottom-sheet";
|
|
319
|
-
|
|
319
|
+
import { ArrowDown, ArrowUp } from "lucide-react-native";
|
|
320
|
+
function ProjectSheet({ snapPoints = ["35%", "85%"], renderHeader, children }) {
|
|
320
321
|
const { project, activeLineId, isAddNoteOpen } = useRetorBridge();
|
|
321
322
|
const sheetRef = useRef2(null);
|
|
322
323
|
const snapPointsArr = useMemo3(() => snapPoints, [snapPoints]);
|
|
324
|
+
const [minimized, setMinimized] = useState2(false);
|
|
323
325
|
useEffect2(() => {
|
|
324
326
|
if (activeLineId || isAddNoteOpen) {
|
|
325
327
|
sheetRef.current?.dismiss();
|
|
326
328
|
} else {
|
|
327
329
|
sheetRef.current?.present();
|
|
330
|
+
setMinimized(false);
|
|
328
331
|
}
|
|
329
332
|
}, [activeLineId, isAddNoteOpen]);
|
|
333
|
+
const handleSheetChange = (index) => {
|
|
334
|
+
setMinimized(index === 0);
|
|
335
|
+
};
|
|
336
|
+
const toggleMinimize = () => {
|
|
337
|
+
if (minimized) {
|
|
338
|
+
sheetRef.current?.snapToIndex(snapPointsArr.length - 1);
|
|
339
|
+
} else {
|
|
340
|
+
sheetRef.current?.snapToIndex(0);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
330
343
|
return /* @__PURE__ */ React4.createElement(
|
|
331
344
|
BottomSheetModal,
|
|
332
345
|
{
|
|
@@ -334,6 +347,7 @@ function ProjectSheet({ snapPoints = ["20%", "60%"], renderHeader, children }) {
|
|
|
334
347
|
snapPoints: snapPointsArr,
|
|
335
348
|
enablePanDownToClose: false,
|
|
336
349
|
enableDismissOnClose: false,
|
|
350
|
+
onChange: handleSheetChange,
|
|
337
351
|
backdropComponent: (props) => /* @__PURE__ */ React4.createElement(
|
|
338
352
|
BottomSheetBackdrop,
|
|
339
353
|
{
|
|
@@ -347,7 +361,7 @@ function ProjectSheet({ snapPoints = ["20%", "60%"], renderHeader, children }) {
|
|
|
347
361
|
handleIndicatorStyle: styles2.handle,
|
|
348
362
|
backgroundStyle: styles2.background
|
|
349
363
|
},
|
|
350
|
-
/* @__PURE__ */ React4.createElement(BottomSheetView, { style: styles2.content }, renderHeader ? renderHeader({ name: project?.name, description: project?.description }) : /* @__PURE__ */ React4.createElement(View3, { style: styles2.header }, project?.name && /* @__PURE__ */ React4.createElement(Text, { style: styles2.title }, project.name), project?.description && /* @__PURE__ */ React4.createElement(Text, { style: styles2.subtitle, numberOfLines: 4 }, project.description)), children ?? /* @__PURE__ */ React4.createElement(DefaultLinesCarousel, null))
|
|
364
|
+
/* @__PURE__ */ React4.createElement(BottomSheetView, { style: styles2.content }, renderHeader ? renderHeader({ name: project?.name, description: project?.description }) : /* @__PURE__ */ React4.createElement(View3, { style: styles2.header }, /* @__PURE__ */ React4.createElement(View3, { style: { flex: 1, minWidth: 0 } }, project?.name && /* @__PURE__ */ React4.createElement(Text, { style: styles2.title, numberOfLines: 1 }, project.name), project?.description && /* @__PURE__ */ React4.createElement(Text, { style: styles2.subtitle, numberOfLines: 4 }, project.description)), /* @__PURE__ */ React4.createElement(Pressable, { style: styles2.iconBtn, onPress: toggleMinimize }, minimized ? /* @__PURE__ */ React4.createElement(ArrowUp, { size: 14, color: "rgba(255,255,255,0.6)" }) : /* @__PURE__ */ React4.createElement(ArrowDown, { size: 14, color: "rgba(255,255,255,0.6)" }))), children ?? /* @__PURE__ */ React4.createElement(DefaultLinesCarousel, null))
|
|
351
365
|
);
|
|
352
366
|
}
|
|
353
367
|
function DefaultLinesCarousel() {
|
|
@@ -356,16 +370,15 @@ function DefaultLinesCarousel() {
|
|
|
356
370
|
function LinesCarousel({ children, gap = 12, paddingHorizontal = 16 }) {
|
|
357
371
|
const { lines } = useRetorBridge();
|
|
358
372
|
if (lines.length === 0) return null;
|
|
359
|
-
return /* @__PURE__ */ React4.createElement(
|
|
373
|
+
return /* @__PURE__ */ React4.createElement(View3, { style: styles2.carouselWrap }, /* @__PURE__ */ React4.createElement(Text, { style: styles2.carouselLabel }, "Routes"), /* @__PURE__ */ React4.createElement(
|
|
360
374
|
ScrollView,
|
|
361
375
|
{
|
|
362
376
|
horizontal: true,
|
|
363
377
|
showsHorizontalScrollIndicator: false,
|
|
364
|
-
contentContainerStyle: { paddingHorizontal, gap }
|
|
365
|
-
style: styles2.carousel
|
|
378
|
+
contentContainerStyle: { paddingHorizontal, gap }
|
|
366
379
|
},
|
|
367
380
|
lines.map((line, idx) => /* @__PURE__ */ React4.createElement(React4.Fragment, { key: line._id }, children(line, idx)))
|
|
368
|
-
);
|
|
381
|
+
));
|
|
369
382
|
}
|
|
370
383
|
function DefaultLineCard({ line }) {
|
|
371
384
|
const { controls } = useRetorBridge();
|
|
@@ -383,10 +396,33 @@ var styles2 = StyleSheet3.create({
|
|
|
383
396
|
background: { backgroundColor: "rgba(20,20,20,0.95)" },
|
|
384
397
|
handle: { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
385
398
|
content: { flex: 1, paddingTop: 12, paddingBottom: 24 },
|
|
386
|
-
header: {
|
|
399
|
+
header: {
|
|
400
|
+
flexDirection: "row",
|
|
401
|
+
alignItems: "flex-start",
|
|
402
|
+
paddingHorizontal: 24,
|
|
403
|
+
paddingBottom: 16,
|
|
404
|
+
gap: 8
|
|
405
|
+
},
|
|
387
406
|
title: { color: "white", fontSize: 18, fontWeight: "600", lineHeight: 22 },
|
|
388
407
|
subtitle: { color: "rgba(255,255,255,0.6)", fontSize: 13, marginTop: 4, lineHeight: 18 },
|
|
389
|
-
|
|
408
|
+
iconBtn: {
|
|
409
|
+
width: 28,
|
|
410
|
+
height: 28,
|
|
411
|
+
borderRadius: 14,
|
|
412
|
+
backgroundColor: "rgba(255,255,255,0.1)",
|
|
413
|
+
alignItems: "center",
|
|
414
|
+
justifyContent: "center"
|
|
415
|
+
},
|
|
416
|
+
carouselWrap: { marginTop: 8 },
|
|
417
|
+
carouselLabel: {
|
|
418
|
+
color: "rgba(255,255,255,0.4)",
|
|
419
|
+
fontSize: 10,
|
|
420
|
+
textTransform: "uppercase",
|
|
421
|
+
letterSpacing: 1,
|
|
422
|
+
fontWeight: "500",
|
|
423
|
+
paddingHorizontal: 24,
|
|
424
|
+
marginBottom: 8
|
|
425
|
+
},
|
|
390
426
|
lineCard: {
|
|
391
427
|
width: 220,
|
|
392
428
|
backgroundColor: "rgba(255,255,255,0.06)",
|
|
@@ -398,20 +434,34 @@ var styles2 = StyleSheet3.create({
|
|
|
398
434
|
});
|
|
399
435
|
|
|
400
436
|
// src/LineDetailSheet.tsx
|
|
401
|
-
import React5, { useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3 } from "react";
|
|
437
|
+
import React5, { useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
|
|
402
438
|
import { Pressable as Pressable2, StyleSheet as StyleSheet4, Text as Text2, View as View4 } from "react-native";
|
|
403
|
-
import { BottomSheetBackdrop as BottomSheetBackdrop2, BottomSheetFlatList, BottomSheetModal as BottomSheetModal2
|
|
404
|
-
|
|
439
|
+
import { BottomSheetBackdrop as BottomSheetBackdrop2, BottomSheetFlatList, BottomSheetModal as BottomSheetModal2 } from "@gorhom/bottom-sheet";
|
|
440
|
+
import Svg, { Circle } from "react-native-svg";
|
|
441
|
+
import { ArrowDown as ArrowDown2, ArrowUp as ArrowUp2, Pause, Play, Plus } from "lucide-react-native";
|
|
442
|
+
function LineDetailSheet({ snapPoints = ["35%", "85%"], renderHeader, children }) {
|
|
405
443
|
const { activeLine, isAddNoteOpen, controls } = useRetorBridge();
|
|
406
444
|
const sheetRef = useRef3(null);
|
|
407
445
|
const snapPointsArr = useMemo4(() => snapPoints, [snapPoints]);
|
|
446
|
+
const [minimized, setMinimized] = useState3(false);
|
|
408
447
|
useEffect3(() => {
|
|
409
448
|
if (activeLine && !isAddNoteOpen) {
|
|
410
449
|
sheetRef.current?.present();
|
|
450
|
+
setMinimized(false);
|
|
411
451
|
} else {
|
|
412
452
|
sheetRef.current?.dismiss();
|
|
413
453
|
}
|
|
414
454
|
}, [activeLine, isAddNoteOpen]);
|
|
455
|
+
const handleSheetChange = (index) => {
|
|
456
|
+
setMinimized(index === 0);
|
|
457
|
+
};
|
|
458
|
+
const toggleMinimize = () => {
|
|
459
|
+
if (minimized) {
|
|
460
|
+
sheetRef.current?.snapToIndex(snapPointsArr.length - 1);
|
|
461
|
+
} else {
|
|
462
|
+
sheetRef.current?.snapToIndex(0);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
415
465
|
return /* @__PURE__ */ React5.createElement(
|
|
416
466
|
BottomSheetModal2,
|
|
417
467
|
{
|
|
@@ -419,6 +469,7 @@ function LineDetailSheet({ snapPoints = ["25%", "75%"], renderHeader, children }
|
|
|
419
469
|
snapPoints: snapPointsArr,
|
|
420
470
|
enablePanDownToClose: false,
|
|
421
471
|
enableDismissOnClose: false,
|
|
472
|
+
onChange: handleSheetChange,
|
|
422
473
|
backdropComponent: (props) => /* @__PURE__ */ React5.createElement(
|
|
423
474
|
BottomSheetBackdrop2,
|
|
424
475
|
{
|
|
@@ -432,60 +483,153 @@ function LineDetailSheet({ snapPoints = ["25%", "75%"], renderHeader, children }
|
|
|
432
483
|
handleIndicatorStyle: styles3.handle,
|
|
433
484
|
backgroundStyle: styles3.background
|
|
434
485
|
},
|
|
435
|
-
|
|
486
|
+
activeLine && /* @__PURE__ */ React5.createElement(View4, { style: styles3.root }, renderHeader ? renderHeader(activeLine) : /* @__PURE__ */ React5.createElement(
|
|
487
|
+
DefaultHeader,
|
|
488
|
+
{
|
|
489
|
+
line: activeLine,
|
|
490
|
+
minimized,
|
|
491
|
+
onToggleMinimize: toggleMinimize
|
|
492
|
+
}
|
|
493
|
+
), /* @__PURE__ */ React5.createElement(View4, { style: styles3.listContainer }, children ?? /* @__PURE__ */ React5.createElement(DefaultLineTagList, null)), /* @__PURE__ */ React5.createElement(View4, { style: styles3.footer }, /* @__PURE__ */ React5.createElement(Pressable2, { style: styles3.doneButton, onPress: () => controls.exitLine() }, /* @__PURE__ */ React5.createElement(Text2, { style: styles3.doneText }, "Done"))))
|
|
436
494
|
);
|
|
437
495
|
}
|
|
438
|
-
function
|
|
439
|
-
|
|
496
|
+
function DefaultHeader({
|
|
497
|
+
line,
|
|
498
|
+
minimized,
|
|
499
|
+
onToggleMinimize
|
|
500
|
+
}) {
|
|
501
|
+
return /* @__PURE__ */ React5.createElement(View4, { style: styles3.header }, /* @__PURE__ */ React5.createElement(View4, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React5.createElement(Text2, { style: styles3.title, numberOfLines: 1 }, line.name), line.subtitle && /* @__PURE__ */ React5.createElement(Text2, { style: styles3.subtitle, numberOfLines: 1 }, line.subtitle), line.description && /* @__PURE__ */ React5.createElement(Text2, { style: styles3.description, numberOfLines: minimized ? 2 : 4 }, line.description)), /* @__PURE__ */ React5.createElement(View4, { style: styles3.headerActions }, /* @__PURE__ */ React5.createElement(AutoplayButton, null), /* @__PURE__ */ React5.createElement(Pressable2, { style: styles3.iconBtn, onPress: onToggleMinimize }, minimized ? /* @__PURE__ */ React5.createElement(ArrowUp2, { size: 14, color: "rgba(255,255,255,0.6)" }) : /* @__PURE__ */ React5.createElement(ArrowDown2, { size: 14, color: "rgba(255,255,255,0.6)" }))));
|
|
502
|
+
}
|
|
503
|
+
function AutoplayButton() {
|
|
504
|
+
const { isPlaying, progress, controls } = useRetorBridge();
|
|
505
|
+
const r = 12.5;
|
|
506
|
+
const c = 2 * Math.PI * r;
|
|
507
|
+
return /* @__PURE__ */ React5.createElement(Pressable2, { style: styles3.iconBtn, onPress: () => controls.toggleAutoplay() }, /* @__PURE__ */ React5.createElement(Svg, { width: 28, height: 28, style: StyleSheet4.absoluteFill }, /* @__PURE__ */ React5.createElement(
|
|
508
|
+
Circle,
|
|
509
|
+
{
|
|
510
|
+
cx: 14,
|
|
511
|
+
cy: 14,
|
|
512
|
+
r,
|
|
513
|
+
fill: "none",
|
|
514
|
+
stroke: "white",
|
|
515
|
+
strokeWidth: 2,
|
|
516
|
+
strokeDasharray: `${c}`,
|
|
517
|
+
strokeDashoffset: c * (1 - progress),
|
|
518
|
+
strokeLinecap: "round",
|
|
519
|
+
transform: "rotate(-90, 14, 14)"
|
|
520
|
+
}
|
|
521
|
+
)), isPlaying ? /* @__PURE__ */ React5.createElement(Pause, { size: 11, color: "white", fill: "white" }) : /* @__PURE__ */ React5.createElement(Play, { size: 11, color: "white", fill: "white", style: { marginLeft: 1 } }));
|
|
440
522
|
}
|
|
441
523
|
function LineTagList({ children }) {
|
|
442
524
|
const { activeLine, closestTagId } = useRetorBridge();
|
|
525
|
+
const listRef = useRef3(null);
|
|
443
526
|
const tags = useMemo4(
|
|
444
527
|
() => (activeLine?.tags ?? []).filter((t) => t.name && t.name.trim().length > 0),
|
|
445
528
|
[activeLine]
|
|
446
529
|
);
|
|
530
|
+
useEffect3(() => {
|
|
531
|
+
if (!closestTagId) return;
|
|
532
|
+
const index = tags.findIndex((t) => t._id === closestTagId);
|
|
533
|
+
if (index < 0) return;
|
|
534
|
+
requestAnimationFrame(() => {
|
|
535
|
+
try {
|
|
536
|
+
listRef.current?.scrollToIndex({ index, animated: true, viewPosition: 0 });
|
|
537
|
+
} catch {
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
}, [closestTagId, tags]);
|
|
447
541
|
if (!activeLine) return null;
|
|
448
542
|
return /* @__PURE__ */ React5.createElement(
|
|
449
543
|
BottomSheetFlatList,
|
|
450
544
|
{
|
|
545
|
+
ref: listRef,
|
|
451
546
|
data: tags,
|
|
452
547
|
keyExtractor: (t) => t._id,
|
|
453
548
|
renderItem: ({ item }) => /* @__PURE__ */ React5.createElement(View4, null, children(item, item._id === closestTagId)),
|
|
454
|
-
contentContainerStyle: styles3.list
|
|
549
|
+
contentContainerStyle: styles3.list,
|
|
550
|
+
onScrollToIndexFailed: (info) => {
|
|
551
|
+
setTimeout(() => {
|
|
552
|
+
listRef.current?.scrollToOffset({ offset: info.averageItemLength * info.index, animated: true });
|
|
553
|
+
}, 100);
|
|
554
|
+
}
|
|
455
555
|
}
|
|
456
556
|
);
|
|
457
557
|
}
|
|
558
|
+
function DefaultLineTagList() {
|
|
559
|
+
return /* @__PURE__ */ React5.createElement(LineTagList, null, (tag, isActive) => /* @__PURE__ */ React5.createElement(DefaultTagItem, { tag, isActive }));
|
|
560
|
+
}
|
|
458
561
|
function DefaultTagItem({ tag, isActive }) {
|
|
459
|
-
const { controls } = useRetorBridge();
|
|
562
|
+
const { controls, openAddNote, activeLine } = useRetorBridge();
|
|
563
|
+
const showPlus = isActive && (activeLine?.notesSupported ?? false);
|
|
460
564
|
return /* @__PURE__ */ React5.createElement(
|
|
461
565
|
Pressable2,
|
|
462
566
|
{
|
|
463
567
|
onPress: () => controls.scrollToTag(tag._id),
|
|
464
568
|
style: [styles3.tagItem, isActive && styles3.tagItemActive]
|
|
465
569
|
},
|
|
466
|
-
/* @__PURE__ */ React5.createElement(Text2, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: 1 }, tag.name),
|
|
467
|
-
tag.subtitle && /* @__PURE__ */ React5.createElement(Text2, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle)
|
|
570
|
+
/* @__PURE__ */ React5.createElement(View4, { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React5.createElement(Text2, { style: [styles3.tagText, isActive && styles3.tagTextActive], numberOfLines: 1 }, tag.name), isActive && tag.description && /* @__PURE__ */ React5.createElement(Text2, { style: styles3.tagDescription, numberOfLines: 2 }, tag.description)),
|
|
571
|
+
tag.subtitle && /* @__PURE__ */ React5.createElement(Text2, { style: styles3.tagSubtitle, numberOfLines: 1 }, tag.subtitle),
|
|
572
|
+
showPlus && /* @__PURE__ */ React5.createElement(
|
|
573
|
+
Pressable2,
|
|
574
|
+
{
|
|
575
|
+
onPress: (e) => {
|
|
576
|
+
e.stopPropagation();
|
|
577
|
+
openAddNote(tag._id);
|
|
578
|
+
},
|
|
579
|
+
style: styles3.plusBtn
|
|
580
|
+
},
|
|
581
|
+
/* @__PURE__ */ React5.createElement(Plus, { size: 14, color: "white" })
|
|
582
|
+
)
|
|
468
583
|
);
|
|
469
584
|
}
|
|
470
585
|
var styles3 = StyleSheet4.create({
|
|
471
586
|
background: { backgroundColor: "rgba(20,20,20,0.95)" },
|
|
472
587
|
handle: { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
473
|
-
|
|
474
|
-
header: {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
588
|
+
root: { flex: 1 },
|
|
589
|
+
header: {
|
|
590
|
+
flexDirection: "row",
|
|
591
|
+
alignItems: "flex-start",
|
|
592
|
+
paddingHorizontal: 24,
|
|
593
|
+
paddingTop: 8,
|
|
594
|
+
paddingBottom: 12,
|
|
595
|
+
gap: 8
|
|
596
|
+
},
|
|
597
|
+
headerActions: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
598
|
+
title: { color: "white", fontSize: 18, fontWeight: "700" },
|
|
599
|
+
subtitle: { color: "rgba(255,255,255,0.5)", fontSize: 12, marginTop: 2 },
|
|
600
|
+
description: { color: "rgba(255,255,255,0.6)", fontSize: 12, marginTop: 6, lineHeight: 18 },
|
|
601
|
+
iconBtn: {
|
|
602
|
+
width: 28,
|
|
603
|
+
height: 28,
|
|
604
|
+
borderRadius: 14,
|
|
605
|
+
backgroundColor: "rgba(255,255,255,0.1)",
|
|
606
|
+
alignItems: "center",
|
|
607
|
+
justifyContent: "center",
|
|
608
|
+
position: "relative"
|
|
609
|
+
},
|
|
610
|
+
listContainer: { flex: 1 },
|
|
611
|
+
list: { paddingHorizontal: 16, paddingBottom: 8, gap: 4 },
|
|
479
612
|
tagItem: {
|
|
613
|
+
flexDirection: "row",
|
|
614
|
+
alignItems: "center",
|
|
480
615
|
paddingHorizontal: 12,
|
|
481
|
-
paddingVertical:
|
|
616
|
+
paddingVertical: 12,
|
|
482
617
|
borderRadius: 12,
|
|
483
|
-
|
|
618
|
+
gap: 8
|
|
484
619
|
},
|
|
485
620
|
tagItemActive: { backgroundColor: "rgba(255,255,255,0.1)" },
|
|
486
|
-
tagText: { color: "rgba(255,255,255,0.6)", fontSize:
|
|
621
|
+
tagText: { color: "rgba(255,255,255,0.6)", fontSize: 13 },
|
|
487
622
|
tagTextActive: { color: "white", fontWeight: "600" },
|
|
488
|
-
|
|
623
|
+
tagDescription: { color: "rgba(255,255,255,0.4)", fontSize: 11, marginTop: 2, lineHeight: 14 },
|
|
624
|
+
tagSubtitle: { color: "rgba(255,255,255,0.4)", fontSize: 10 },
|
|
625
|
+
plusBtn: {
|
|
626
|
+
width: 22,
|
|
627
|
+
height: 22,
|
|
628
|
+
borderRadius: 11,
|
|
629
|
+
backgroundColor: "rgba(255,255,255,0.15)",
|
|
630
|
+
alignItems: "center",
|
|
631
|
+
justifyContent: "center"
|
|
632
|
+
},
|
|
489
633
|
footer: { paddingHorizontal: 16, paddingBottom: 16, paddingTop: 8 },
|
|
490
634
|
doneButton: {
|
|
491
635
|
backgroundColor: "white",
|
|
@@ -497,14 +641,15 @@ var styles3 = StyleSheet4.create({
|
|
|
497
641
|
});
|
|
498
642
|
|
|
499
643
|
// src/AddNoteSheet.tsx
|
|
500
|
-
import React6, { useEffect as useEffect4, useMemo as useMemo5, useRef as useRef4, useState as
|
|
644
|
+
import React6, { useEffect as useEffect4, useMemo as useMemo5, useRef as useRef4, useState as useState4 } from "react";
|
|
501
645
|
import { Pressable as Pressable3, StyleSheet as StyleSheet5, Text as Text3, View as View5 } from "react-native";
|
|
502
646
|
import {
|
|
503
647
|
BottomSheetBackdrop as BottomSheetBackdrop3,
|
|
504
648
|
BottomSheetModal as BottomSheetModal3,
|
|
505
649
|
BottomSheetTextInput,
|
|
506
|
-
BottomSheetView as
|
|
650
|
+
BottomSheetView as BottomSheetView2
|
|
507
651
|
} from "@gorhom/bottom-sheet";
|
|
652
|
+
import { ArrowUp as ArrowUp3, X } from "lucide-react-native";
|
|
508
653
|
function AddNoteSheet({
|
|
509
654
|
snapPoints = ["50%"],
|
|
510
655
|
maxLength = 280,
|
|
@@ -514,8 +659,8 @@ function AddNoteSheet({
|
|
|
514
659
|
const { isAddNoteOpen, addNoteTagId, activeLine, closeAddNote, submitNote } = useRetorBridge();
|
|
515
660
|
const sheetRef = useRef4(null);
|
|
516
661
|
const snapPointsArr = useMemo5(() => snapPoints, [snapPoints]);
|
|
517
|
-
const [text, setText] =
|
|
518
|
-
const [isPrivate, setPrivate] =
|
|
662
|
+
const [text, setText] = useState4("");
|
|
663
|
+
const [isPrivate, setPrivate] = useState4(true);
|
|
519
664
|
useEffect4(() => {
|
|
520
665
|
if (isAddNoteOpen) {
|
|
521
666
|
sheetRef.current?.present();
|
|
@@ -564,7 +709,7 @@ function AddNoteSheet({
|
|
|
564
709
|
handleIndicatorStyle: styles4.handle,
|
|
565
710
|
backgroundStyle: styles4.background
|
|
566
711
|
},
|
|
567
|
-
/* @__PURE__ */ React6.createElement(
|
|
712
|
+
/* @__PURE__ */ React6.createElement(BottomSheetView2, { style: styles4.content }, renderForm ? renderForm(formApi) : /* @__PURE__ */ React6.createElement(View5, { style: styles4.form }, /* @__PURE__ */ React6.createElement(View5, { style: styles4.headerRow }, /* @__PURE__ */ React6.createElement(View5, { style: { flex: 1 } }, activeLine && /* @__PURE__ */ React6.createElement(Text3, { style: styles4.title, numberOfLines: 1 }, activeLine.name), tag && /* @__PURE__ */ React6.createElement(Text3, { style: styles4.subtitle, numberOfLines: 1 }, tag.name)), /* @__PURE__ */ React6.createElement(Pressable3, { onPress: closeAddNote, style: styles4.closeBtn }, /* @__PURE__ */ React6.createElement(X, { size: 14, color: "rgba(255,255,255,0.6)" }))), /* @__PURE__ */ React6.createElement(
|
|
568
713
|
BottomSheetTextInput,
|
|
569
714
|
{
|
|
570
715
|
value: text,
|
|
@@ -591,7 +736,7 @@ function AddNoteSheet({
|
|
|
591
736
|
disabled: !text.trim(),
|
|
592
737
|
style: [styles4.submit, !text.trim() && styles4.submitDisabled]
|
|
593
738
|
},
|
|
594
|
-
/* @__PURE__ */ React6.createElement(
|
|
739
|
+
/* @__PURE__ */ React6.createElement(ArrowUp3, { size: 16, color: "black", strokeWidth: 2.5 })
|
|
595
740
|
))))
|
|
596
741
|
);
|
|
597
742
|
}
|
|
@@ -611,7 +756,6 @@ var styles4 = StyleSheet5.create({
|
|
|
611
756
|
alignItems: "center",
|
|
612
757
|
justifyContent: "center"
|
|
613
758
|
},
|
|
614
|
-
closeBtnText: { color: "rgba(255,255,255,0.6)", fontSize: 14 },
|
|
615
759
|
input: {
|
|
616
760
|
flex: 1,
|
|
617
761
|
color: "white",
|
|
@@ -645,8 +789,7 @@ var styles4 = StyleSheet5.create({
|
|
|
645
789
|
alignItems: "center",
|
|
646
790
|
justifyContent: "center"
|
|
647
791
|
},
|
|
648
|
-
submitDisabled: { opacity: 0.3 }
|
|
649
|
-
submitArrow: { color: "black", fontSize: 16, fontWeight: "700" }
|
|
792
|
+
submitDisabled: { opacity: 0.3 }
|
|
650
793
|
});
|
|
651
794
|
|
|
652
795
|
// src/CoverPhoto.tsx
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retor/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React Native SDK for embedding Retor 3D experiences",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -27,26 +27,30 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"@gorhom/bottom-sheet": ">=5",
|
|
30
|
+
"lucide-react-native": ">=1",
|
|
30
31
|
"react": ">=18",
|
|
31
32
|
"react-native": ">=0.72",
|
|
32
33
|
"react-native-gesture-handler": ">=2.12",
|
|
33
34
|
"react-native-reanimated": ">=3.5",
|
|
35
|
+
"react-native-svg": ">=14",
|
|
34
36
|
"react-native-webview": ">=13"
|
|
35
37
|
},
|
|
36
38
|
"devDependencies": {
|
|
37
39
|
"@gorhom/bottom-sheet": "^5.1.0",
|
|
38
40
|
"@types/react": "^19.0.0",
|
|
41
|
+
"lucide-react-native": "^1.8.0",
|
|
39
42
|
"react": "19.1.0",
|
|
40
43
|
"react-native": "0.81.4",
|
|
41
44
|
"react-native-gesture-handler": "^2.20.0",
|
|
42
45
|
"react-native-reanimated": "^3.16.0",
|
|
46
|
+
"react-native-svg": "^15.8.0",
|
|
43
47
|
"react-native-webview": "^13.13.0",
|
|
44
48
|
"tsup": "^8.0.0",
|
|
45
49
|
"typescript": "^5.4.0"
|
|
46
50
|
},
|
|
47
51
|
"scripts": {
|
|
48
|
-
"build": "tsup src/index.tsx --format cjs,esm --dts --clean --external react --external react-native --external react-native-webview --external @gorhom/bottom-sheet --external react-native-gesture-handler --external react-native-reanimated",
|
|
49
|
-
"dev": "tsup src/index.tsx --format cjs,esm --dts --watch --external react --external react-native --external react-native-webview --external @gorhom/bottom-sheet --external react-native-gesture-handler --external react-native-reanimated",
|
|
52
|
+
"build": "tsup src/index.tsx --format cjs,esm --dts --clean --external react --external react-native --external react-native-webview --external @gorhom/bottom-sheet --external react-native-gesture-handler --external react-native-reanimated --external react-native-svg --external lucide-react-native",
|
|
53
|
+
"dev": "tsup src/index.tsx --format cjs,esm --dts --watch --external react --external react-native --external react-native-webview --external @gorhom/bottom-sheet --external react-native-gesture-handler --external react-native-reanimated --external react-native-svg --external lucide-react-native",
|
|
50
54
|
"typecheck": "tsc --noEmit"
|
|
51
55
|
}
|
|
52
56
|
}
|