@oxy.so/bloom 4.21.1 → 4.22.1

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 (54) hide show
  1. package/docs/ai-chat.mdx +11 -2
  2. package/docs/bottom-sheet.mdx +4 -0
  3. package/docs/chip.mdx +1 -0
  4. package/lib/commonjs/ai-chat/AiChatCodePanel.js +12 -8
  5. package/lib/commonjs/ai-chat/AiChatCodePanel.js.map +1 -1
  6. package/lib/commonjs/ai-chat/AiChatGalleryPanelBase.js +15 -10
  7. package/lib/commonjs/ai-chat/AiChatGalleryPanelBase.js.map +1 -1
  8. package/lib/commonjs/bottom-sheet/BottomSheet.js +35 -43
  9. package/lib/commonjs/bottom-sheet/BottomSheet.js.map +1 -1
  10. package/lib/commonjs/bottom-sheet/BottomSheetBase.js +1 -1
  11. package/lib/commonjs/chip/ChipRow.js +2 -0
  12. package/lib/commonjs/chip/ChipRow.js.map +1 -1
  13. package/lib/module/ai-chat/AiChatCodePanel.js +12 -8
  14. package/lib/module/ai-chat/AiChatCodePanel.js.map +1 -1
  15. package/lib/module/ai-chat/AiChatGalleryPanelBase.js +15 -10
  16. package/lib/module/ai-chat/AiChatGalleryPanelBase.js.map +1 -1
  17. package/lib/module/bottom-sheet/BottomSheet.js +36 -44
  18. package/lib/module/bottom-sheet/BottomSheet.js.map +1 -1
  19. package/lib/module/bottom-sheet/BottomSheetBase.js +1 -1
  20. package/lib/module/chip/ChipRow.js +2 -0
  21. package/lib/module/chip/ChipRow.js.map +1 -1
  22. package/lib/typescript/commonjs/ai-chat/AiChatCodePanel.d.ts +3 -2
  23. package/lib/typescript/commonjs/ai-chat/AiChatCodePanel.d.ts.map +1 -1
  24. package/lib/typescript/commonjs/ai-chat/AiChatGalleryPanelBase.d.ts.map +1 -1
  25. package/lib/typescript/commonjs/ai-chat/types.d.ts +11 -2
  26. package/lib/typescript/commonjs/ai-chat/types.d.ts.map +1 -1
  27. package/lib/typescript/commonjs/bottom-sheet/BottomSheet.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/bottom-sheet/types.d.ts +2 -1
  29. package/lib/typescript/commonjs/bottom-sheet/types.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/chip/ChipRow.d.ts +1 -1
  31. package/lib/typescript/commonjs/chip/ChipRow.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/chip/types.d.ts +9 -0
  33. package/lib/typescript/commonjs/chip/types.d.ts.map +1 -1
  34. package/lib/typescript/module/ai-chat/AiChatCodePanel.d.ts +3 -2
  35. package/lib/typescript/module/ai-chat/AiChatCodePanel.d.ts.map +1 -1
  36. package/lib/typescript/module/ai-chat/AiChatGalleryPanelBase.d.ts.map +1 -1
  37. package/lib/typescript/module/ai-chat/types.d.ts +11 -2
  38. package/lib/typescript/module/ai-chat/types.d.ts.map +1 -1
  39. package/lib/typescript/module/bottom-sheet/BottomSheet.d.ts.map +1 -1
  40. package/lib/typescript/module/bottom-sheet/types.d.ts +2 -1
  41. package/lib/typescript/module/bottom-sheet/types.d.ts.map +1 -1
  42. package/lib/typescript/module/chip/ChipRow.d.ts +1 -1
  43. package/lib/typescript/module/chip/ChipRow.d.ts.map +1 -1
  44. package/lib/typescript/module/chip/types.d.ts +9 -0
  45. package/lib/typescript/module/chip/types.d.ts.map +1 -1
  46. package/package.json +1 -1
  47. package/src/ai-chat/AiChatCodePanel.tsx +12 -6
  48. package/src/ai-chat/AiChatGalleryPanelBase.tsx +24 -16
  49. package/src/ai-chat/types.ts +11 -2
  50. package/src/bottom-sheet/BottomSheet.tsx +32 -36
  51. package/src/bottom-sheet/BottomSheetBase.tsx +1 -1
  52. package/src/bottom-sheet/types.ts +2 -1
  53. package/src/chip/ChipRow.tsx +2 -0
  54. package/src/chip/types.ts +9 -0
@@ -22,41 +22,39 @@ import type { BottomSheetProps, BottomSheetRef, BottomSheetShellProps } from './
22
22
  const noopKeyboardHandler = (_handlers: Record<string, (e: { height: number }) => void>, _deps: unknown[]) => {};
23
23
  let useKeyboardHandler: (handlers: Record<string, (e: { height: number }) => void>, deps: unknown[]) => void = noopKeyboardHandler;
24
24
 
25
- // react-native-keyboard-controller's <KeyboardProvider>. We re-establish it
26
- // INSIDE the sheet's RN <Modal> (see the render below): a <Modal> mounts into
27
- // its OWN native root, and neither the app-root GestureHandlerRootView nor the
28
- // app-root KeyboardProvider's native KeyboardControllerView extend across that
29
- // boundary. Without a provider inside the Modal, keyboard-controller consumers
30
- // (this sheet's keyboard tracker, plus any TextInputs in `children`) read the
31
- // default empty KeyboardContext — logging "Couldn't find real values for
32
- // KeyboardContext ..." — and receive no keyboard insets. When the optional
33
- // module is absent, or on web (no RN Modal native-window boundary, keyboard is
34
- // the browser's concern), this resolves to a passthrough that just renders its
35
- // children, so no provider is introduced where one isn't needed.
36
- const PassthroughKeyboardProvider = ({ children }: { children: React.ReactNode }) => <>{children}</>;
37
- let KeyboardProvider: React.ComponentType<{ children: React.ReactNode }> = PassthroughKeyboardProvider;
38
-
39
25
  if (Platform.OS !== 'web' && typeof require !== 'undefined') {
40
26
  try {
41
27
  const keyboardController = require('react-native-keyboard-controller');
42
28
  useKeyboardHandler = keyboardController.useKeyboardHandler ?? noopKeyboardHandler;
43
- KeyboardProvider = keyboardController.KeyboardProvider ?? PassthroughKeyboardProvider;
44
29
  } catch {
45
- // react-native-keyboard-controller not available — keep the no-op
46
- // handler and passthrough provider.
30
+ // react-native-keyboard-controller not available — keep the no-op handler.
47
31
  }
48
32
  }
49
33
 
50
34
  /**
51
- * Registers the sheet's keyboard-height tracker. It lives in its own tiny
52
- * component — rendered INSIDE the Modal, under the re-established
53
- * <KeyboardProvider> — so `useKeyboardHandler` reads the in-Modal
54
- * KeyboardContext whose native KeyboardControllerView actually receives the
55
- * Modal window's keyboard insets (the app-root provider does not cross the
56
- * Modal's native-window boundary). It writes the live keyboard height into the
57
- * shared value that drives the sheet's translate/height styles. Renders
58
- * nothing. No-ops when react-native-keyboard-controller isn't installed / on
59
- * web (`useKeyboardHandler` is the module-level no-op there).
35
+ * Registers the sheet's keyboard-height tracker, writing the live keyboard
36
+ * height into the shared value that drives the sheet's translate/height styles.
37
+ * Renders nothing.
38
+ *
39
+ * It reads the APP's one `<KeyboardProvider>`, and the sheet deliberately does
40
+ * not mount a second one inside its `<Modal>`:
41
+ *
42
+ * - React context crosses a `<Modal>` like any other element, so this hook
43
+ * finds the app-root provider from inside the sheet.
44
+ * - The native events cross too: when a `<Modal>` shows, the root provider's
45
+ * `ModalAttachedWatcher` (keyboard-controller ≥ 1.13, Android) attaches a
46
+ * keyboard callback to the dialog's window and propagates it to the ROOT
47
+ * provider's view, which is where this handler is registered.
48
+ * - A second provider breaks the app until it restarts. Every provider's
49
+ * watcher answers the same `topShow`: each SUSPENDS its own main-window
50
+ * callback and then calls `dialog.setOnDismissListener` to un-suspend it —
51
+ * and a dialog keeps only the LAST listener. So on dismiss one provider
52
+ * resumes and the others stay suspended for good: after the first sheet, the
53
+ * app's `KeyboardAvoidingView`s never saw the keyboard again (Alia #608,
54
+ * Android 16, keyboard-controller 1.21.9 and unchanged in 1.22.5).
55
+ *
56
+ * No app-root provider means keyboard-controller works nowhere in that app; the
57
+ * hook then no-ops (and warns in development) like every other consumer.
60
58
  */
61
59
  function SheetKeyboardSync({ keyboardHeight }: { keyboardHeight: SharedValue<number> }) {
62
60
  useKeyboardHandler({
@@ -73,27 +71,25 @@ function SheetKeyboardSync({ keyboardHeight }: { keyboardHeight: SharedValue<num
73
71
  }
74
72
 
75
73
  /**
76
- * Native shell: RN's `<Modal>` (its own native root window) + the
77
- * re-established `<KeyboardProvider>` + the sheet's keyboard tracker + a
78
- * `<GestureHandlerRootView>` (the app-root GHRV does not cross the Modal's
79
- * native-window boundary, so pan gestures need their own root here).
74
+ * Native shell: RN's `<Modal>` (its own native root window) + the sheet's
75
+ * keyboard tracker + a `<GestureHandlerRootView>` (the app-root GHRV does not
76
+ * cross the Modal's native-window boundary, so pan gestures need their own root
77
+ * here). No `<KeyboardProvider>`: see `SheetKeyboardSync`.
80
78
  */
81
79
  function NativeShell({ visible, onRequestClose, keyboardHeight, children }: BottomSheetShellProps) {
82
80
  return (
83
81
  <Modal visible={visible} transparent animationType="none" statusBarTranslucent onRequestClose={onRequestClose}>
84
82
  {/*
85
83
  This <Modal> is its own native window — the same boundary the
86
- KeyboardProvider and GestureHandlerRootView above are re-established
87
- for. `GlassBlurWindow` declares it to the glass layer, which is the
84
+ GestureHandlerRootView below is re-established for.
85
+ `GlassBlurWindow` declares it to the glass layer, which is the
88
86
  ONLY thing that lets a backdrop in here take an Android blur target:
89
87
  a BlurView in the app's own window would be a descendant of what it
90
88
  blurs, and that segfaults. See `glass/blur-target.tsx`.
91
89
  */}
92
90
  <GlassBlurWindow>
93
- <KeyboardProvider>
94
- <SheetKeyboardSync keyboardHeight={keyboardHeight} />
95
- <GestureHandlerRootView style={styles.rootView}>{children}</GestureHandlerRootView>
96
- </KeyboardProvider>
91
+ <SheetKeyboardSync keyboardHeight={keyboardHeight} />
92
+ <GestureHandlerRootView style={styles.rootView}>{children}</GestureHandlerRootView>
97
93
  </GlassBlurWindow>
98
94
  </Modal>
99
95
  );
@@ -606,7 +606,7 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
606
606
  }, [colors.background, theme.isDark, detached]);
607
607
 
608
608
  // Publish the sheet's keyboard shared value to the shell so the native
609
- // shell can drive it from inside its own <KeyboardProvider>. Kept stable
609
+ // shell's keyboard tracker can drive it. Kept stable
610
610
  // (shared values are stable refs) so the shell never re-mounts for this.
611
611
  if (!rendered) return null;
612
612
 
@@ -127,7 +127,8 @@ export interface BottomSheetProps {
127
127
  /**
128
128
  * Props consumed by a platform Shell — the outermost wrapper that hosts the
129
129
  * sheet body in a full-screen overlay. Native wraps it in RN's `<Modal>` +
130
- * `<KeyboardProvider>` + `<GestureHandlerRootView>`; web wraps it in bloom's
130
+ * `<GestureHandlerRootView>` (keyboard tracking reads the app's own root
131
+ * `<KeyboardProvider>`, never a second one); web wraps it in bloom's
131
132
  * stable DOM `<Portal>` + a fixed `<GestureHandlerRootView>`. Splitting the
132
133
  * shell is what lets web avoid RN-Web's `<Modal>`/`ModalPortal`, whose host
133
134
  * node is orphaned under React 19 concurrent/StrictMode so the sheet mounts
@@ -65,6 +65,7 @@ function ChipRowComponent({
65
65
  role = 'group',
66
66
  accessibilityLabel,
67
67
  disabled,
68
+ keyboardShouldPersistTaps = 'handled',
68
69
  style,
69
70
  contentContainerStyle,
70
71
  testID,
@@ -127,6 +128,7 @@ function ChipRowComponent({
127
128
  {...(IS_WEB ? ({ dataSet: { bloomChipRowTrack: '' } } as Record<string, unknown>) : {})}
128
129
  horizontal
129
130
  showsHorizontalScrollIndicator={false}
131
+ keyboardShouldPersistTaps={keyboardShouldPersistTaps}
130
132
  scrollEventThrottle={16}
131
133
  onScroll={onScroll}
132
134
  onLayout={onLayout}
package/src/chip/types.ts CHANGED
@@ -132,6 +132,15 @@ export interface ChipRowProps {
132
132
  accessibilityLabel?: string;
133
133
  /** Marks the whole row disabled to assistive technology (web `aria-disabled`). */
134
134
  disabled?: boolean;
135
+ /**
136
+ * Whether a tap on a pill while the software keyboard is open reaches the
137
+ * pill. Default `handled`: the pill takes the press and the keyboard stays.
138
+ * React Native's own default (`never`) spends the first tap dismissing the
139
+ * keyboard, so a row of pills under a text field — a composer's audience and
140
+ * language pills, a search screen's filters — needed two taps, and the first
141
+ * one dropped the keyboard the reader was typing with. Native only.
142
+ */
143
+ keyboardShouldPersistTaps?: 'always' | 'never' | 'handled';
135
144
  style?: StyleProp<ViewStyle>;
136
145
  contentContainerStyle?: StyleProp<ViewStyle>;
137
146
  testID?: string;