@bbearai/react-native 0.8.4 → 0.9.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.
Files changed (3) hide show
  1. package/dist/index.js +106 -29
  2. package/dist/index.mjs +109 -32
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12935,7 +12935,7 @@ var BugBearClient = class {
12935
12935
  async updateAssignmentStatus(assignmentId, status, options) {
12936
12936
  try {
12937
12937
  await this.ensureReady();
12938
- const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at").eq("id", assignmentId).single();
12938
+ const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at, tester_id, project_id").eq("id", assignmentId).single();
12939
12939
  if (fetchError || !currentAssignment) {
12940
12940
  console.error("BugBear: Assignment not found", {
12941
12941
  message: fetchError?.message,
@@ -12956,6 +12956,19 @@ var BugBearClient = class {
12956
12956
  const completedAt = /* @__PURE__ */ new Date();
12957
12957
  durationSeconds = Math.round((completedAt.getTime() - startedAt.getTime()) / 1e3);
12958
12958
  updateData.duration_seconds = durationSeconds;
12959
+ if (currentAssignment.tester_id && currentAssignment.project_id) {
12960
+ try {
12961
+ const { data: activeTime } = await this.supabase.rpc("compute_assignment_active_time", {
12962
+ p_tester_id: currentAssignment.tester_id,
12963
+ p_project_id: currentAssignment.project_id,
12964
+ p_started_at: currentAssignment.started_at,
12965
+ p_completed_at: updateData.completed_at
12966
+ });
12967
+ updateData.active_seconds = typeof activeTime === "number" ? activeTime : Math.min(durationSeconds, 1800);
12968
+ } catch {
12969
+ updateData.active_seconds = Math.min(durationSeconds, 1800);
12970
+ }
12971
+ }
12959
12972
  }
12960
12973
  }
12961
12974
  if (options?.notes) {
@@ -13034,6 +13047,7 @@ var BugBearClient = class {
13034
13047
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
13035
13048
  completed_at: null,
13036
13049
  duration_seconds: null,
13050
+ active_seconds: null,
13037
13051
  skip_reason: null
13038
13052
  }).eq("id", assignmentId).eq("status", current.status);
13039
13053
  if (error) {
@@ -19115,14 +19129,31 @@ function BugBearButton({
19115
19129
  }) {
19116
19130
  const { shouldShowWidget, testerInfo, isLoading, unreadCount, assignments, widgetMode, widgetColorScheme } = useBugBear();
19117
19131
  const { currentScreen, canGoBack, push, pop, replace, reset } = useNavigation();
19118
- const [modalVisible, setModalVisible] = (0, import_react23.useState)(false);
19132
+ const [panelVisible, setPanelVisible] = (0, import_react23.useState)(false);
19133
+ const panelAnim = (0, import_react23.useRef)(new import_react_native22.Animated.Value(0)).current;
19119
19134
  const styles5 = (0, import_react23.useMemo)(() => createStyles16(), [widgetColorScheme]);
19120
19135
  const screenCaptureRef = (0, import_react23.useRef)(null);
19121
- const openModal = () => {
19136
+ const openPanel = () => {
19122
19137
  captureAppScreen().then((uri) => {
19123
19138
  screenCaptureRef.current = uri;
19124
19139
  });
19125
- setModalVisible(true);
19140
+ setPanelVisible(true);
19141
+ import_react_native22.Animated.spring(panelAnim, {
19142
+ toValue: 1,
19143
+ useNativeDriver: true,
19144
+ friction: 8,
19145
+ tension: 65
19146
+ }).start();
19147
+ };
19148
+ const closePanel = () => {
19149
+ import_react_native22.Keyboard.dismiss();
19150
+ import_react_native22.Animated.timing(panelAnim, {
19151
+ toValue: 0,
19152
+ duration: 250,
19153
+ useNativeDriver: true
19154
+ }).start(() => {
19155
+ setPanelVisible(false);
19156
+ });
19126
19157
  };
19127
19158
  const getInitialPosition = () => {
19128
19159
  const buttonSize = 56;
@@ -19173,7 +19204,7 @@ function BugBearButton({
19173
19204
  tension: 40
19174
19205
  }).start();
19175
19206
  if (!isDragging.current && Math.abs(gs.dx) < 5 && Math.abs(gs.dy) < 5) {
19176
- openModal();
19207
+ openPanel();
19177
19208
  }
19178
19209
  isDragging.current = false;
19179
19210
  }
@@ -19181,6 +19212,19 @@ function BugBearButton({
19181
19212
  ).current;
19182
19213
  const pendingTests = widgetMode === "qa" ? assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length : 0;
19183
19214
  const badgeCount = pendingTests + unreadCount;
19215
+ (0, import_react23.useEffect)(() => {
19216
+ if (!panelVisible || import_react_native22.Platform.OS !== "android") return;
19217
+ const handler = import_react_native22.BackHandler.addEventListener("hardwareBackPress", () => {
19218
+ if (canGoBack) {
19219
+ import_react_native22.Keyboard.dismiss();
19220
+ pop();
19221
+ } else {
19222
+ closePanel();
19223
+ }
19224
+ return true;
19225
+ });
19226
+ return () => handler.remove();
19227
+ }, [panelVisible, canGoBack]);
19184
19228
  if (!shouldShowWidget) return null;
19185
19229
  const getHeaderTitle = () => {
19186
19230
  switch (currentScreen.name) {
@@ -19219,8 +19263,7 @@ function BugBearButton({
19219
19263
  }
19220
19264
  };
19221
19265
  const handleClose = () => {
19222
- import_react_native22.Keyboard.dismiss();
19223
- setModalVisible(false);
19266
+ closePanel();
19224
19267
  };
19225
19268
  const nav = {
19226
19269
  push: (screen) => {
@@ -19292,7 +19335,7 @@ function BugBearButton({
19292
19335
  return /* @__PURE__ */ import_react23.default.createElement(HomeScreen, { nav });
19293
19336
  }
19294
19337
  };
19295
- return /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, /* @__PURE__ */ import_react23.default.createElement(
19338
+ return /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, !panelVisible && /* @__PURE__ */ import_react23.default.createElement(
19296
19339
  import_react_native22.Animated.View,
19297
19340
  {
19298
19341
  style: [styles5.fabContainer, { transform: pan.getTranslateTransform() }, buttonStyle],
@@ -19302,27 +19345,37 @@ function BugBearButton({
19302
19345
  import_react_native22.TouchableOpacity,
19303
19346
  {
19304
19347
  style: styles5.fab,
19305
- onPress: openModal,
19348
+ onPress: openPanel,
19306
19349
  activeOpacity: draggable ? 1 : 0.7
19307
19350
  },
19308
19351
  /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Image, { source: { uri: BUGBEAR_LOGO_BASE64 }, style: styles5.fabIcon }),
19309
19352
  badgeCount > 0 && /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.badge }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.badgeText }, badgeCount > 9 ? "9+" : badgeCount))
19310
19353
  )
19311
- ), /* @__PURE__ */ import_react23.default.createElement(
19312
- import_react_native22.Modal,
19354
+ ), panelVisible && /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.panelWrapper, pointerEvents: "box-none" }, /* @__PURE__ */ import_react23.default.createElement(
19355
+ import_react_native22.KeyboardAvoidingView,
19313
19356
  {
19314
- visible: modalVisible,
19315
- animationType: "slide",
19316
- transparent: true,
19317
- onRequestClose: handleClose
19357
+ behavior: import_react_native22.Platform.OS === "ios" ? "padding" : "height",
19358
+ style: styles5.panelKeyboardAvoid,
19359
+ pointerEvents: "box-none"
19318
19360
  },
19319
19361
  /* @__PURE__ */ import_react23.default.createElement(
19320
- import_react_native22.KeyboardAvoidingView,
19362
+ import_react_native22.Animated.View,
19321
19363
  {
19322
- behavior: import_react_native22.Platform.OS === "ios" ? "padding" : "height",
19323
- style: styles5.modalOverlay
19364
+ style: [
19365
+ styles5.panelContainer,
19366
+ {
19367
+ transform: [{
19368
+ translateY: panelAnim.interpolate({
19369
+ inputRange: [0, 1],
19370
+ outputRange: [screenHeight, 0]
19371
+ })
19372
+ }]
19373
+ }
19374
+ ]
19324
19375
  },
19325
- /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.modalContainer }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.header }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.headerLeft }, canGoBack ? /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: () => nav.pop(), style: styles5.backButton }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.backText }, "\u2190 Back")) : /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.headerTitleRow }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.headerActions }, currentScreen.name !== "HOME" && /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: () => nav.reset(), style: styles5.homeButton }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.homeIcon }, "\u2302")), /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: handleClose, style: styles5.closeButton }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.closeText }, "\u2715")))), /* @__PURE__ */ import_react23.default.createElement(
19376
+ /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.panelHandle }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.panelHandleBar })),
19377
+ /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.header }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.headerLeft }, canGoBack ? /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: () => nav.pop(), style: styles5.backButton }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.backText }, "\u2190 Back")) : /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.headerTitleRow }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.headerActions }, currentScreen.name !== "HOME" && /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: () => nav.reset(), style: styles5.homeButton }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.homeIcon }, "\u2302")), /* @__PURE__ */ import_react23.default.createElement(import_react_native22.TouchableOpacity, { onPress: handleClose, style: styles5.closeButton }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.closeText }, "\u2715")))),
19378
+ /* @__PURE__ */ import_react23.default.createElement(
19326
19379
  import_react_native22.ScrollView,
19327
19380
  {
19328
19381
  style: styles5.content,
@@ -19331,9 +19384,9 @@ function BugBearButton({
19331
19384
  showsVerticalScrollIndicator: false
19332
19385
  },
19333
19386
  isLoading ? /* @__PURE__ */ import_react23.default.createElement(import_react_native22.View, { style: styles5.loadingContainer }, /* @__PURE__ */ import_react23.default.createElement(import_react_native22.ActivityIndicator, { size: "large", color: colors.blue }), /* @__PURE__ */ import_react23.default.createElement(import_react_native22.Text, { style: styles5.loadingText }, "Loading...")) : renderScreen()
19334
- ))
19387
+ )
19335
19388
  )
19336
- ));
19389
+ )));
19337
19390
  }
19338
19391
  function createStyles16() {
19339
19392
  return import_react_native22.StyleSheet.create({
@@ -19377,18 +19430,42 @@ function createStyles16() {
19377
19430
  fontSize: 11,
19378
19431
  fontWeight: "700"
19379
19432
  },
19380
- // Modal
19381
- modalOverlay: {
19433
+ // Panel (replaces Modal — no backdrop, app stays interactive)
19434
+ panelWrapper: {
19435
+ position: "absolute",
19436
+ top: 0,
19437
+ left: 0,
19438
+ right: 0,
19439
+ bottom: 0,
19440
+ zIndex: 9998,
19441
+ justifyContent: "flex-end"
19442
+ },
19443
+ panelKeyboardAvoid: {
19382
19444
  flex: 1,
19383
- justifyContent: "flex-end",
19384
- backgroundColor: "rgba(0,0,0,0.5)"
19445
+ justifyContent: "flex-end"
19385
19446
  },
19386
- modalContainer: {
19447
+ panelContainer: {
19387
19448
  backgroundColor: colors.bg,
19388
19449
  borderTopLeftRadius: 20,
19389
19450
  borderTopRightRadius: 20,
19390
- maxHeight: "85%",
19391
- minHeight: "50%"
19451
+ maxHeight: "70%",
19452
+ minHeight: "40%",
19453
+ shadowColor: colors.onBright,
19454
+ shadowOffset: { width: 0, height: -4 },
19455
+ shadowOpacity: 0.25,
19456
+ shadowRadius: 12,
19457
+ elevation: 16
19458
+ },
19459
+ panelHandle: {
19460
+ alignItems: "center",
19461
+ paddingTop: 8,
19462
+ paddingBottom: 4
19463
+ },
19464
+ panelHandleBar: {
19465
+ width: 36,
19466
+ height: 4,
19467
+ borderRadius: 2,
19468
+ backgroundColor: colors.border
19392
19469
  },
19393
19470
  // Header
19394
19471
  header: {
@@ -19471,7 +19548,7 @@ function createStyles16() {
19471
19548
  },
19472
19549
  contentContainer: {
19473
19550
  padding: 16,
19474
- paddingBottom: 32
19551
+ paddingBottom: import_react_native22.Platform.OS === "ios" ? 50 : 28
19475
19552
  },
19476
19553
  // Loading
19477
19554
  loadingContainer: {
package/dist/index.mjs CHANGED
@@ -12902,7 +12902,7 @@ var BugBearClient = class {
12902
12902
  async updateAssignmentStatus(assignmentId, status, options) {
12903
12903
  try {
12904
12904
  await this.ensureReady();
12905
- const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at").eq("id", assignmentId).single();
12905
+ const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at, tester_id, project_id").eq("id", assignmentId).single();
12906
12906
  if (fetchError || !currentAssignment) {
12907
12907
  console.error("BugBear: Assignment not found", {
12908
12908
  message: fetchError?.message,
@@ -12923,6 +12923,19 @@ var BugBearClient = class {
12923
12923
  const completedAt = /* @__PURE__ */ new Date();
12924
12924
  durationSeconds = Math.round((completedAt.getTime() - startedAt.getTime()) / 1e3);
12925
12925
  updateData.duration_seconds = durationSeconds;
12926
+ if (currentAssignment.tester_id && currentAssignment.project_id) {
12927
+ try {
12928
+ const { data: activeTime } = await this.supabase.rpc("compute_assignment_active_time", {
12929
+ p_tester_id: currentAssignment.tester_id,
12930
+ p_project_id: currentAssignment.project_id,
12931
+ p_started_at: currentAssignment.started_at,
12932
+ p_completed_at: updateData.completed_at
12933
+ });
12934
+ updateData.active_seconds = typeof activeTime === "number" ? activeTime : Math.min(durationSeconds, 1800);
12935
+ } catch {
12936
+ updateData.active_seconds = Math.min(durationSeconds, 1800);
12937
+ }
12938
+ }
12926
12939
  }
12927
12940
  }
12928
12941
  if (options?.notes) {
@@ -13001,6 +13014,7 @@ var BugBearClient = class {
13001
13014
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
13002
13015
  completed_at: null,
13003
13016
  duration_seconds: null,
13017
+ active_seconds: null,
13004
13018
  skip_reason: null
13005
13019
  }).eq("id", assignmentId).eq("status", current.status);
13006
13020
  if (error) {
@@ -15133,13 +15147,12 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
15133
15147
  }
15134
15148
 
15135
15149
  // src/BugBearButton.tsx
15136
- import React21, { useState as useState18, useRef as useRef6, useMemo as useMemo16 } from "react";
15150
+ import React21, { useState as useState18, useRef as useRef6, useEffect as useEffect12, useMemo as useMemo16 } from "react";
15137
15151
  import {
15138
15152
  View as View21,
15139
15153
  Text as Text19,
15140
15154
  Image as Image4,
15141
15155
  TouchableOpacity as TouchableOpacity18,
15142
- Modal as Modal3,
15143
15156
  ScrollView as ScrollView4,
15144
15157
  StyleSheet as StyleSheet21,
15145
15158
  Dimensions as Dimensions2,
@@ -15148,7 +15161,8 @@ import {
15148
15161
  PanResponder,
15149
15162
  Animated as Animated2,
15150
15163
  ActivityIndicator as ActivityIndicator3,
15151
- Keyboard as Keyboard4
15164
+ Keyboard as Keyboard4,
15165
+ BackHandler
15152
15166
  } from "react-native";
15153
15167
 
15154
15168
  // src/widget/logo.ts
@@ -19097,14 +19111,31 @@ function BugBearButton({
19097
19111
  }) {
19098
19112
  const { shouldShowWidget, testerInfo, isLoading, unreadCount, assignments, widgetMode, widgetColorScheme } = useBugBear();
19099
19113
  const { currentScreen, canGoBack, push, pop, replace, reset } = useNavigation();
19100
- const [modalVisible, setModalVisible] = useState18(false);
19114
+ const [panelVisible, setPanelVisible] = useState18(false);
19115
+ const panelAnim = useRef6(new Animated2.Value(0)).current;
19101
19116
  const styles5 = useMemo16(() => createStyles16(), [widgetColorScheme]);
19102
19117
  const screenCaptureRef = useRef6(null);
19103
- const openModal = () => {
19118
+ const openPanel = () => {
19104
19119
  captureAppScreen().then((uri) => {
19105
19120
  screenCaptureRef.current = uri;
19106
19121
  });
19107
- setModalVisible(true);
19122
+ setPanelVisible(true);
19123
+ Animated2.spring(panelAnim, {
19124
+ toValue: 1,
19125
+ useNativeDriver: true,
19126
+ friction: 8,
19127
+ tension: 65
19128
+ }).start();
19129
+ };
19130
+ const closePanel = () => {
19131
+ Keyboard4.dismiss();
19132
+ Animated2.timing(panelAnim, {
19133
+ toValue: 0,
19134
+ duration: 250,
19135
+ useNativeDriver: true
19136
+ }).start(() => {
19137
+ setPanelVisible(false);
19138
+ });
19108
19139
  };
19109
19140
  const getInitialPosition = () => {
19110
19141
  const buttonSize = 56;
@@ -19155,7 +19186,7 @@ function BugBearButton({
19155
19186
  tension: 40
19156
19187
  }).start();
19157
19188
  if (!isDragging.current && Math.abs(gs.dx) < 5 && Math.abs(gs.dy) < 5) {
19158
- openModal();
19189
+ openPanel();
19159
19190
  }
19160
19191
  isDragging.current = false;
19161
19192
  }
@@ -19163,6 +19194,19 @@ function BugBearButton({
19163
19194
  ).current;
19164
19195
  const pendingTests = widgetMode === "qa" ? assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length : 0;
19165
19196
  const badgeCount = pendingTests + unreadCount;
19197
+ useEffect12(() => {
19198
+ if (!panelVisible || Platform5.OS !== "android") return;
19199
+ const handler = BackHandler.addEventListener("hardwareBackPress", () => {
19200
+ if (canGoBack) {
19201
+ Keyboard4.dismiss();
19202
+ pop();
19203
+ } else {
19204
+ closePanel();
19205
+ }
19206
+ return true;
19207
+ });
19208
+ return () => handler.remove();
19209
+ }, [panelVisible, canGoBack]);
19166
19210
  if (!shouldShowWidget) return null;
19167
19211
  const getHeaderTitle = () => {
19168
19212
  switch (currentScreen.name) {
@@ -19201,8 +19245,7 @@ function BugBearButton({
19201
19245
  }
19202
19246
  };
19203
19247
  const handleClose = () => {
19204
- Keyboard4.dismiss();
19205
- setModalVisible(false);
19248
+ closePanel();
19206
19249
  };
19207
19250
  const nav = {
19208
19251
  push: (screen) => {
@@ -19274,7 +19317,7 @@ function BugBearButton({
19274
19317
  return /* @__PURE__ */ React21.createElement(HomeScreen, { nav });
19275
19318
  }
19276
19319
  };
19277
- return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(
19320
+ return /* @__PURE__ */ React21.createElement(React21.Fragment, null, !panelVisible && /* @__PURE__ */ React21.createElement(
19278
19321
  Animated2.View,
19279
19322
  {
19280
19323
  style: [styles5.fabContainer, { transform: pan.getTranslateTransform() }, buttonStyle],
@@ -19284,27 +19327,37 @@ function BugBearButton({
19284
19327
  TouchableOpacity18,
19285
19328
  {
19286
19329
  style: styles5.fab,
19287
- onPress: openModal,
19330
+ onPress: openPanel,
19288
19331
  activeOpacity: draggable ? 1 : 0.7
19289
19332
  },
19290
19333
  /* @__PURE__ */ React21.createElement(Image4, { source: { uri: BUGBEAR_LOGO_BASE64 }, style: styles5.fabIcon }),
19291
19334
  badgeCount > 0 && /* @__PURE__ */ React21.createElement(View21, { style: styles5.badge }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.badgeText }, badgeCount > 9 ? "9+" : badgeCount))
19292
19335
  )
19293
- ), /* @__PURE__ */ React21.createElement(
19294
- Modal3,
19336
+ ), panelVisible && /* @__PURE__ */ React21.createElement(View21, { style: styles5.panelWrapper, pointerEvents: "box-none" }, /* @__PURE__ */ React21.createElement(
19337
+ KeyboardAvoidingView,
19295
19338
  {
19296
- visible: modalVisible,
19297
- animationType: "slide",
19298
- transparent: true,
19299
- onRequestClose: handleClose
19339
+ behavior: Platform5.OS === "ios" ? "padding" : "height",
19340
+ style: styles5.panelKeyboardAvoid,
19341
+ pointerEvents: "box-none"
19300
19342
  },
19301
19343
  /* @__PURE__ */ React21.createElement(
19302
- KeyboardAvoidingView,
19344
+ Animated2.View,
19303
19345
  {
19304
- behavior: Platform5.OS === "ios" ? "padding" : "height",
19305
- style: styles5.modalOverlay
19346
+ style: [
19347
+ styles5.panelContainer,
19348
+ {
19349
+ transform: [{
19350
+ translateY: panelAnim.interpolate({
19351
+ inputRange: [0, 1],
19352
+ outputRange: [screenHeight, 0]
19353
+ })
19354
+ }]
19355
+ }
19356
+ ]
19306
19357
  },
19307
- /* @__PURE__ */ React21.createElement(View21, { style: styles5.modalContainer }, /* @__PURE__ */ React21.createElement(View21, { style: styles5.header }, /* @__PURE__ */ React21.createElement(View21, { style: styles5.headerLeft }, canGoBack ? /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: () => nav.pop(), style: styles5.backButton }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.backText }, "\u2190 Back")) : /* @__PURE__ */ React21.createElement(View21, { style: styles5.headerTitleRow }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ React21.createElement(Text19, { style: styles5.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ React21.createElement(View21, { style: styles5.headerActions }, currentScreen.name !== "HOME" && /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: () => nav.reset(), style: styles5.homeButton }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.homeIcon }, "\u2302")), /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: handleClose, style: styles5.closeButton }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.closeText }, "\u2715")))), /* @__PURE__ */ React21.createElement(
19358
+ /* @__PURE__ */ React21.createElement(View21, { style: styles5.panelHandle }, /* @__PURE__ */ React21.createElement(View21, { style: styles5.panelHandleBar })),
19359
+ /* @__PURE__ */ React21.createElement(View21, { style: styles5.header }, /* @__PURE__ */ React21.createElement(View21, { style: styles5.headerLeft }, canGoBack ? /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: () => nav.pop(), style: styles5.backButton }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.backText }, "\u2190 Back")) : /* @__PURE__ */ React21.createElement(View21, { style: styles5.headerTitleRow }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ React21.createElement(Text19, { style: styles5.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ React21.createElement(View21, { style: styles5.headerActions }, currentScreen.name !== "HOME" && /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: () => nav.reset(), style: styles5.homeButton }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.homeIcon }, "\u2302")), /* @__PURE__ */ React21.createElement(TouchableOpacity18, { onPress: handleClose, style: styles5.closeButton }, /* @__PURE__ */ React21.createElement(Text19, { style: styles5.closeText }, "\u2715")))),
19360
+ /* @__PURE__ */ React21.createElement(
19308
19361
  ScrollView4,
19309
19362
  {
19310
19363
  style: styles5.content,
@@ -19313,9 +19366,9 @@ function BugBearButton({
19313
19366
  showsVerticalScrollIndicator: false
19314
19367
  },
19315
19368
  isLoading ? /* @__PURE__ */ React21.createElement(View21, { style: styles5.loadingContainer }, /* @__PURE__ */ React21.createElement(ActivityIndicator3, { size: "large", color: colors.blue }), /* @__PURE__ */ React21.createElement(Text19, { style: styles5.loadingText }, "Loading...")) : renderScreen()
19316
- ))
19369
+ )
19317
19370
  )
19318
- ));
19371
+ )));
19319
19372
  }
19320
19373
  function createStyles16() {
19321
19374
  return StyleSheet21.create({
@@ -19359,18 +19412,42 @@ function createStyles16() {
19359
19412
  fontSize: 11,
19360
19413
  fontWeight: "700"
19361
19414
  },
19362
- // Modal
19363
- modalOverlay: {
19415
+ // Panel (replaces Modal — no backdrop, app stays interactive)
19416
+ panelWrapper: {
19417
+ position: "absolute",
19418
+ top: 0,
19419
+ left: 0,
19420
+ right: 0,
19421
+ bottom: 0,
19422
+ zIndex: 9998,
19423
+ justifyContent: "flex-end"
19424
+ },
19425
+ panelKeyboardAvoid: {
19364
19426
  flex: 1,
19365
- justifyContent: "flex-end",
19366
- backgroundColor: "rgba(0,0,0,0.5)"
19427
+ justifyContent: "flex-end"
19367
19428
  },
19368
- modalContainer: {
19429
+ panelContainer: {
19369
19430
  backgroundColor: colors.bg,
19370
19431
  borderTopLeftRadius: 20,
19371
19432
  borderTopRightRadius: 20,
19372
- maxHeight: "85%",
19373
- minHeight: "50%"
19433
+ maxHeight: "70%",
19434
+ minHeight: "40%",
19435
+ shadowColor: colors.onBright,
19436
+ shadowOffset: { width: 0, height: -4 },
19437
+ shadowOpacity: 0.25,
19438
+ shadowRadius: 12,
19439
+ elevation: 16
19440
+ },
19441
+ panelHandle: {
19442
+ alignItems: "center",
19443
+ paddingTop: 8,
19444
+ paddingBottom: 4
19445
+ },
19446
+ panelHandleBar: {
19447
+ width: 36,
19448
+ height: 4,
19449
+ borderRadius: 2,
19450
+ backgroundColor: colors.border
19374
19451
  },
19375
19452
  // Header
19376
19453
  header: {
@@ -19453,7 +19530,7 @@ function createStyles16() {
19453
19530
  },
19454
19531
  contentContainer: {
19455
19532
  padding: 16,
19456
- paddingBottom: 32
19533
+ paddingBottom: Platform5.OS === "ios" ? 50 : 28
19457
19534
  },
19458
19535
  // Loading
19459
19536
  loadingContainer: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/react-native",
3
- "version": "0.8.4",
3
+ "version": "0.9.0",
4
4
  "description": "BugBear React Native components for mobile apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",