@boostdev/design-system-react-native 0.2.5 → 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.
Files changed (26) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/dist/index.cjs +176 -165
  3. package/dist/index.d.cts +12 -2
  4. package/dist/index.d.ts +12 -2
  5. package/dist/index.js +176 -165
  6. package/package.json +1 -1
  7. package/src/components/interaction/Dialog/Dialog.mdx +3 -2
  8. package/src/components/interaction/Dialog/Dialog.spec.tsx +42 -11
  9. package/src/components/interaction/Dialog/Dialog.tsx +19 -12
  10. package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +3 -1
  11. package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +73 -0
  12. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +79 -73
  13. package/src/components/interaction/Popover/Popover.mdx +3 -1
  14. package/src/components/interaction/Popover/Popover.spec.tsx +43 -3
  15. package/src/components/interaction/Popover/Popover.tsx +23 -13
  16. package/src/components/interaction/SideSheet/SideSheet.mdx +4 -3
  17. package/src/components/interaction/SideSheet/SideSheet.spec.tsx +8 -9
  18. package/src/components/interaction/SideSheet/SideSheet.tsx +9 -3
  19. package/src/components/ui/Alert/Alert.spec.tsx +32 -1
  20. package/src/components/ui/Alert/Alert.stories.tsx +45 -0
  21. package/src/components/ui/Alert/Alert.tsx +11 -2
  22. package/src/components/ui/Collapsible/Collapsible.spec.tsx +11 -0
  23. package/src/components/ui/Collapsible/Collapsible.tsx +13 -8
  24. package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +32 -1
  25. package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +30 -0
  26. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +16 -3
package/CHANGELOG.md CHANGED
@@ -1,6 +1,93 @@
1
1
  # Changelog
2
2
 
3
3
  All notable changes to `@boostdev/design-system-react-native` are documented here.
4
+ ## [0.3.0] - 2026-09-23
5
+ ### Added
6
+ - Feat(alert): support arbitrary and theme-aware children
7
+
8
+ Render string/number children in the themed body Text as before, but render any other node as-is so children can hold custom layout (View, Pressable, etc.). Also accept a function child that receives the variant's resolved text color, so custom content can match the theme. ([`4a43a8e`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/4a43a8ead2a70675a2e7eb39e86a0bed18515c93))
9
+ - Feat(notification-banner): support arbitrary and theme-aware children
10
+
11
+ Mirror the Alert change: only string/number children go in the themed body Text; any other node renders as-is. Move flex:1 onto a wrapper View so layout is preserved for non-text children. Accept a function child that receives the resolved text color. ([`d804efc`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/d804efc5721924b700730c23402838ca5da1bcb6))
12
+
13
+ ### Fixed
14
+ - Fix(dropdown-menu): make each item reachable for VoiceOver on iOS
15
+
16
+ The sheet's content was wrapped in a no-op Pressable to swallow presses.
17
+ On iOS a Pressable is accessible by default, and an accessible view is a
18
+ single element to VoiceOver and XCUITest: the whole sheet (title, Done,
19
+ every item) read as one element whose label listed all items, and no item
20
+ could be picked on its own. The wrapper was also unneeded: the backdrop is
21
+ a sibling behind the sheet, so sheet touches never reach it.
22
+
23
+ The wrapper is gone, so title, Done and each menuitem are separate
24
+ elements. The backdrop still closes on press but is hidden from assistive
25
+ tech (testID "bds-dropdownmenu-backdrop"); Done is the accessible close.
26
+ The sheet is accessibilityViewIsModal and closes on VoiceOver's escape
27
+ gesture. Specs pin the roleless backdrop, the missing "Close menu" button,
28
+ independent menuitems and no press-swallowing wrapper around them.
29
+
30
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`a42e0da`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/a42e0daa2ece8db443326b07840c8a15edcb2884))
31
+ - Fix(side-sheet): hide the backdrop from assistive tech, close on escape
32
+
33
+ The full-screen backdrop was an accessible "Close side sheet" button next
34
+ to the real close button. VoiceOver listed the close control twice, and a
35
+ double-tap on the full-screen element activates its centre, which can land
36
+ on the panel instead of closing.
37
+
38
+ The backdrop still closes on press but is hidden from assistive tech
39
+ (testID "bds-sidesheet-backdrop"); the close button is the one accessible
40
+ close. The panel is accessibilityViewIsModal and closes on VoiceOver's
41
+ escape gesture. Specs pin exactly one "Close side sheet" button and a
42
+ roleless backdrop that still calls onClose.
43
+
44
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`4b93294`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/4b932947c3989cbf9a23cedb9c545b2d37243781))
45
+ - Fix(dialog): make the dialog's content reachable for VoiceOver on iOS
46
+
47
+ The backdrop Pressable wrapped the panel. On iOS a Pressable is
48
+ accessible by default, and an accessible view is a single element to
49
+ VoiceOver and XCUITest: an open dialog was one full-screen "Close dialog"
50
+ button. The title, the content and the dialog's own buttons could not be
51
+ reached, and a VoiceOver double-tap activated the centre of the screen
52
+ (the panel), so it did nothing.
53
+
54
+ The backdrop is now a sibling behind the panel: it still closes on press
55
+ but is hidden from assistive tech (testID "bds-dialog-backdrop"), and the
56
+ close button is the accessible close. The panel is a plain View,
57
+ accessibilityViewIsModal, and closes on VoiceOver's escape gesture.
58
+ Verified on an iPhone 17 simulator (iOS 26.1): title, close button,
59
+ content and a "Klaar" button inside are separate elements, a backdrop tap
60
+ closes, a panel tap does not, and the dialog looks the same. Specs pin one
61
+ "Close dialog" button, a roleless backdrop that does not contain the
62
+ content, and content presses that do not close.
63
+
64
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`fe6703e`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/fe6703e4aeb9b716212dacf94886cdc7629b2f55))
65
+ - Fix(popover): keep the popover's content reachable for VoiceOver on iOS
66
+
67
+ The "Close popover" backdrop Pressable wrapped the panel, so on iOS the
68
+ open popover was a single accessibility element and its content could not
69
+ be reached by VoiceOver or XCUITest.
70
+
71
+ The backdrop is now a sibling behind the panel. Popover has no close
72
+ button, so the backdrop stays the accessible "Close popover" button, with
73
+ onAccessibilityTap so a VoiceOver double-tap closes it (without it the
74
+ activation lands on the centred panel). The panel is a plain View and
75
+ VoiceOver's escape gesture closes the popover. Specs pin the separate
76
+ backdrop button, content outside it, and content presses that do not
77
+ close.
78
+
79
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`5ddb57c`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/5ddb57c5158b8181d9d87eb706099662519fbdad))
80
+
81
+ ## [0.2.6] - 2026-06-15
82
+ ### Fixed
83
+ - Fix(collapsible): render the disclosure indicator as a border-box chevron instead of the ▸ (U+25B8) glyph char
84
+
85
+ The Collapsible's caret was a text glyph, which reads as a stray unicode
86
+ character rather than a crisp icon. It is now a small View with two adjacent
87
+ borders, rotated -45deg when collapsed (points right) to 45deg when expanded
88
+ (points down) — font-independent and icon-like, with the toggle animation
89
+ preserved. The spec pins it as a border chevron, not a glyph. ([`ee649db`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/ee649db))
90
+
4
91
  ## [0.2.5] - 2026-06-12
5
92
  ### Fixed
6
93
  - Fix(side-sheet): body sizes to content instead of collapsing to zero height
package/dist/index.cjs CHANGED
@@ -530,6 +530,7 @@ function Alert({
530
530
  error: { bg: colors2.colorRedSubtle, text: colors2.colorOnBg, border: colors2.colorError }
531
531
  };
532
532
  const { bg, text, border: borderColor } = variantColors[variant];
533
+ const resolvedChildren = typeof children === "function" ? children({ color: text }) : children;
533
534
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
534
535
  import_react_native9.View,
535
536
  {
@@ -540,7 +541,7 @@ function Alert({
540
541
  icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.View, { style: styles7.icon, children: icon }),
541
542
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.View, { style: styles7.content, children: [
542
543
  title && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles7.title, { color: text }], children: title }),
543
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles7.body, { color: text }], children })
544
+ typeof resolvedChildren === "string" || typeof resolvedChildren === "number" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles7.body, { color: text }], children: resolvedChildren }) : resolvedChildren
544
545
  ] }),
545
546
  onDismiss && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
546
547
  import_react_native9.Pressable,
@@ -569,8 +570,10 @@ var styles8 = import_react_native10.StyleSheet.create({
569
570
  paddingHorizontal: import_native.spacing.m,
570
571
  gap: import_native.spacing.xs
571
572
  },
573
+ body: {
574
+ flex: 1
575
+ },
572
576
  content: {
573
- flex: 1,
574
577
  fontSize: import_native.font.size.bodyS,
575
578
  fontFamily: import_native.font.family.body,
576
579
  lineHeight: lineHeight.bodyS
@@ -596,6 +599,7 @@ function NotificationBanner({
596
599
  error: { bg: colors2.colorRedSubtle, text: colors2.colorOnBg, border: colors2.colorError }
597
600
  };
598
601
  const { bg, text, border: borderColor } = variantColors[variant];
602
+ const resolvedChildren = typeof children === "function" ? children({ color: text }) : children;
599
603
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
600
604
  import_react_native10.View,
601
605
  {
@@ -603,7 +607,7 @@ function NotificationBanner({
603
607
  accessibilityLiveRegion: isUrgent ? "assertive" : "polite",
604
608
  style: [styles8.banner, { backgroundColor: bg, borderBottomWidth: 3, borderBottomColor: borderColor }, style],
605
609
  children: [
606
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native10.Text, { style: [styles8.content, { color: text }], children }),
610
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native10.View, { style: styles8.body, children: typeof resolvedChildren === "string" || typeof resolvedChildren === "number" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native10.Text, { style: [styles8.content, { color: text }], children: resolvedChildren }) : resolvedChildren }),
607
611
  action,
608
612
  onDismiss && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
609
613
  import_react_native10.Pressable,
@@ -1145,7 +1149,12 @@ var styles15 = import_react_native17.StyleSheet.create({
1145
1149
  lineHeight: lineHeight.body
1146
1150
  },
1147
1151
  chevron: {
1148
- fontSize: import_native.font.size.body,
1152
+ // Border-box chevron (no glyph font dependency): a small square with two
1153
+ // adjacent borders, rotated to form a crisp "›" / "⌄" disclosure indicator.
1154
+ width: 8,
1155
+ height: 8,
1156
+ borderRightWidth: 2,
1157
+ borderBottomWidth: 2,
1149
1158
  marginStart: import_native.spacing.xs
1150
1159
  },
1151
1160
  content: {
@@ -1184,9 +1193,9 @@ function Collapsible({
1184
1193
  }
1185
1194
  onToggle?.(next);
1186
1195
  }, [isOpen, isControlled, onToggle, rotation]);
1187
- const rotateZ = rotation.interpolate({
1196
+ const rotate = rotation.interpolate({
1188
1197
  inputRange: [0, 1],
1189
- outputRange: ["0deg", "90deg"]
1198
+ outputRange: ["-45deg", "45deg"]
1190
1199
  });
1191
1200
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1192
1201
  import_react_native17.View,
@@ -1205,12 +1214,12 @@ function Collapsible({
1205
1214
  children: [
1206
1215
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native17.Text, { style: [styles15.summaryText, { color: colors2.colorOnBg }], children: summary }),
1207
1216
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1208
- import_react_native17.Animated.Text,
1217
+ import_react_native17.Animated.View,
1209
1218
  {
1210
- style: [styles15.chevron, { color: colors2.colorOnBgSubtle, transform: [{ rotateZ }] }],
1219
+ testID: "bds-collapsible-chevron",
1220
+ style: [styles15.chevron, { borderColor: colors2.colorOnBgSubtle, transform: [{ rotate }] }],
1211
1221
  importantForAccessibility: "no",
1212
- accessibilityElementsHidden: true,
1213
- children: "\u25B8"
1222
+ accessibilityElementsHidden: true
1214
1223
  }
1215
1224
  )
1216
1225
  ]
@@ -3792,46 +3801,48 @@ function Dialog({
3792
3801
  transparent: true,
3793
3802
  animationType: "fade",
3794
3803
  onRequestClose: onClose,
3795
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3796
- import_react_native44.Pressable,
3797
- {
3798
- style: styles40.overlay,
3799
- onPress: onClose,
3800
- accessibilityRole: "button",
3801
- accessibilityLabel: "Close dialog",
3802
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3803
- import_react_native44.Pressable,
3804
- {
3805
- style: [styles40.panel, { backgroundColor: colors2.colorGreySubtle }, style],
3806
- onPress: () => {
3807
- },
3808
- accessibilityRole: "none",
3809
- children: [
3810
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3811
- import_react_native44.Pressable,
3812
- {
3813
- style: styles40.closeButton,
3814
- onPress: onClose,
3815
- accessibilityRole: "button",
3816
- accessibilityLabel: "Close dialog",
3817
- hitSlop: 8,
3818
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3819
- import_react_native44.Text,
3820
- {
3821
- style: [styles40.closeText, { color: colors2.colorOnBgSubtle }],
3822
- "aria-hidden": true,
3823
- children: "\u2715"
3824
- }
3825
- )
3826
- }
3827
- ),
3828
- !!title && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native44.View, { style: styles40.header, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native44.Text, { style: [styles40.title, { color: colors2.colorOnGreySubtle }], children: title }) }),
3829
- children
3830
- ]
3831
- }
3832
- )
3833
- }
3834
- )
3804
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_react_native44.View, { style: styles40.overlay, children: [
3805
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3806
+ import_react_native44.Pressable,
3807
+ {
3808
+ testID: "bds-dialog-backdrop",
3809
+ style: import_react_native44.StyleSheet.absoluteFill,
3810
+ onPress: onClose,
3811
+ accessible: false,
3812
+ importantForAccessibility: "no"
3813
+ }
3814
+ ),
3815
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3816
+ import_react_native44.View,
3817
+ {
3818
+ style: [styles40.panel, { backgroundColor: colors2.colorGreySubtle }, style],
3819
+ accessibilityViewIsModal: true,
3820
+ onAccessibilityEscape: onClose,
3821
+ children: [
3822
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3823
+ import_react_native44.Pressable,
3824
+ {
3825
+ style: styles40.closeButton,
3826
+ onPress: onClose,
3827
+ accessibilityRole: "button",
3828
+ accessibilityLabel: "Close dialog",
3829
+ hitSlop: 8,
3830
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3831
+ import_react_native44.Text,
3832
+ {
3833
+ style: [styles40.closeText, { color: colors2.colorOnBgSubtle }],
3834
+ "aria-hidden": true,
3835
+ children: "\u2715"
3836
+ }
3837
+ )
3838
+ }
3839
+ ),
3840
+ !!title && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native44.View, { style: styles40.header, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native44.Text, { style: [styles40.title, { color: colors2.colorOnGreySubtle }], children: title }) }),
3841
+ children
3842
+ ]
3843
+ }
3844
+ )
3845
+ ] })
3835
3846
  }
3836
3847
  );
3837
3848
  }
@@ -3949,8 +3960,9 @@ function SideSheet({
3949
3960
  {
3950
3961
  style: import_react_native45.StyleSheet.absoluteFill,
3951
3962
  onPress: onClose,
3952
- accessibilityRole: "button",
3953
- accessibilityLabel: "Close side sheet"
3963
+ testID: "bds-sidesheet-backdrop",
3964
+ accessible: false,
3965
+ importantForAccessibility: "no"
3954
3966
  }
3955
3967
  )
3956
3968
  }
@@ -3966,7 +3978,8 @@ function SideSheet({
3966
3978
  },
3967
3979
  style
3968
3980
  ],
3969
- accessibilityRole: "none",
3981
+ accessibilityViewIsModal: true,
3982
+ onAccessibilityEscape: onClose,
3970
3983
  children: [
3971
3984
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3972
3985
  import_react_native45.View,
@@ -4278,8 +4291,9 @@ function DropdownMenu({
4278
4291
  {
4279
4292
  style: import_react_native47.StyleSheet.absoluteFill,
4280
4293
  onPress: () => setOpen(false),
4281
- accessibilityRole: "button",
4282
- accessibilityLabel: "Close menu"
4294
+ testID: "bds-dropdownmenu-backdrop",
4295
+ accessible: false,
4296
+ importantForAccessibility: "no"
4283
4297
  }
4284
4298
  )
4285
4299
  }
@@ -4294,100 +4308,95 @@ function DropdownMenu({
4294
4308
  transform: [{ translateY: slideAnim }]
4295
4309
  }
4296
4310
  ],
4297
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4298
- import_react_native47.Pressable,
4299
- {
4300
- onPress: () => {
4301
- },
4302
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native47.SafeAreaView, { children: [
4303
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4304
- import_react_native47.View,
4305
- {
4306
- style: [
4307
- styles43.sheetHeader,
4308
- { borderBottomColor: colors2.colorBgSubtle }
4309
- ],
4310
- children: [
4311
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native47.Text, { style: [styles43.sheetTitle, { color: colors2.colorOnBg }], children: title }),
4312
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4313
- import_react_native47.Pressable,
4314
- {
4315
- accessibilityRole: "button",
4316
- accessibilityLabel: "Close",
4317
- onPress: () => setOpen(false),
4318
- hitSlop: 8,
4319
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4320
- import_react_native47.Text,
4321
- {
4322
- style: [
4323
- styles43.closeText,
4324
- { color: colors2.colorInteractive }
4325
- ],
4326
- children: "Done"
4327
- }
4328
- )
4329
- }
4330
- )
4331
- ]
4332
- }
4333
- ),
4334
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4335
- import_react_native47.FlatList,
4336
- {
4337
- data: items,
4338
- keyExtractor: (item) => item.id,
4339
- renderItem: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
4340
- item.separator && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4341
- import_react_native47.View,
4311
+ accessibilityViewIsModal: true,
4312
+ onAccessibilityEscape: () => setOpen(false),
4313
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native47.SafeAreaView, { children: [
4314
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4315
+ import_react_native47.View,
4316
+ {
4317
+ style: [
4318
+ styles43.sheetHeader,
4319
+ { borderBottomColor: colors2.colorBgSubtle }
4320
+ ],
4321
+ children: [
4322
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native47.Text, { style: [styles43.sheetTitle, { color: colors2.colorOnBg }], children: title }),
4323
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4324
+ import_react_native47.Pressable,
4325
+ {
4326
+ accessibilityRole: "button",
4327
+ accessibilityLabel: "Close",
4328
+ onPress: () => setOpen(false),
4329
+ hitSlop: 8,
4330
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4331
+ import_react_native47.Text,
4342
4332
  {
4343
4333
  style: [
4344
- styles43.separator,
4345
- { backgroundColor: colors2.colorBgSubtle }
4346
- ],
4347
- accessibilityRole: "none"
4348
- }
4349
- ),
4350
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4351
- import_react_native47.Pressable,
4352
- {
4353
- accessibilityRole: "menuitem",
4354
- accessibilityLabel: item.label,
4355
- accessibilityState: { disabled: item.disabled },
4356
- disabled: item.disabled,
4357
- onPress: () => handleItemPress(item),
4358
- style: ({ pressed }) => [
4359
- styles43.item,
4360
- pressed && { backgroundColor: colors2.colorBgSubtle },
4361
- item.disabled && { opacity: 0.4 }
4334
+ styles43.closeText,
4335
+ { color: colors2.colorInteractive }
4362
4336
  ],
4363
- children: [
4364
- !!item.icon && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4365
- import_react_native47.View,
4366
- {
4367
- importantForAccessibility: "no-hide-descendants",
4368
- accessibilityElementsHidden: true,
4369
- children: item.icon
4370
- }
4371
- ),
4372
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4373
- import_react_native47.Text,
4374
- {
4375
- style: [
4376
- styles43.itemText,
4377
- { color: colors2.colorOnBg }
4378
- ],
4379
- children: item.label
4380
- }
4381
- )
4382
- ]
4337
+ children: "Done"
4383
4338
  }
4384
4339
  )
4385
- ] })
4386
- }
4387
- )
4388
- ] })
4389
- }
4390
- )
4340
+ }
4341
+ )
4342
+ ]
4343
+ }
4344
+ ),
4345
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4346
+ import_react_native47.FlatList,
4347
+ {
4348
+ data: items,
4349
+ keyExtractor: (item) => item.id,
4350
+ renderItem: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
4351
+ item.separator && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4352
+ import_react_native47.View,
4353
+ {
4354
+ style: [
4355
+ styles43.separator,
4356
+ { backgroundColor: colors2.colorBgSubtle }
4357
+ ],
4358
+ accessibilityRole: "none"
4359
+ }
4360
+ ),
4361
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4362
+ import_react_native47.Pressable,
4363
+ {
4364
+ accessibilityRole: "menuitem",
4365
+ accessibilityLabel: item.label,
4366
+ accessibilityState: { disabled: item.disabled },
4367
+ disabled: item.disabled,
4368
+ onPress: () => handleItemPress(item),
4369
+ style: ({ pressed }) => [
4370
+ styles43.item,
4371
+ pressed && { backgroundColor: colors2.colorBgSubtle },
4372
+ item.disabled && { opacity: 0.4 }
4373
+ ],
4374
+ children: [
4375
+ !!item.icon && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4376
+ import_react_native47.View,
4377
+ {
4378
+ importantForAccessibility: "no-hide-descendants",
4379
+ accessibilityElementsHidden: true,
4380
+ children: item.icon
4381
+ }
4382
+ ),
4383
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4384
+ import_react_native47.Text,
4385
+ {
4386
+ style: [
4387
+ styles43.itemText,
4388
+ { color: colors2.colorOnBg }
4389
+ ],
4390
+ children: item.label
4391
+ }
4392
+ )
4393
+ ]
4394
+ }
4395
+ )
4396
+ ] })
4397
+ }
4398
+ )
4399
+ ] })
4391
4400
  }
4392
4401
  )
4393
4402
  ] })
@@ -4431,6 +4440,7 @@ function Popover({
4431
4440
  }) {
4432
4441
  const { colors: colors2 } = useTheme();
4433
4442
  const [isOpen, setIsOpen] = (0, import_react19.useState)(false);
4443
+ const close = () => setIsOpen(false);
4434
4444
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_react_native48.View, { style: [styles44.wrapper, style], children: [
4435
4445
  import_react19.default.cloneElement(children, {
4436
4446
  onPress: () => setIsOpen(true),
@@ -4443,27 +4453,28 @@ function Popover({
4443
4453
  visible: isOpen,
4444
4454
  transparent: true,
4445
4455
  animationType: "fade",
4446
- onRequestClose: () => setIsOpen(false),
4447
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4448
- import_react_native48.Pressable,
4449
- {
4450
- style: styles44.overlay,
4451
- onPress: () => setIsOpen(false),
4452
- accessibilityRole: "button",
4453
- accessibilityLabel: "Close popover",
4454
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4455
- import_react_native48.Pressable,
4456
- {
4457
- style: [styles44.panel, { backgroundColor: colors2.colorBg }],
4458
- onPress: () => {
4459
- },
4460
- accessibilityRole: "none",
4461
- accessibilityLabel,
4462
- children: content
4463
- }
4464
- )
4465
- }
4466
- )
4456
+ onRequestClose: close,
4457
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_react_native48.View, { style: styles44.overlay, onAccessibilityEscape: close, children: [
4458
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4459
+ import_react_native48.Pressable,
4460
+ {
4461
+ testID: "bds-popover-backdrop",
4462
+ style: import_react_native48.StyleSheet.absoluteFill,
4463
+ onPress: close,
4464
+ onAccessibilityTap: close,
4465
+ accessibilityRole: "button",
4466
+ accessibilityLabel: "Close popover"
4467
+ }
4468
+ ),
4469
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4470
+ import_react_native48.View,
4471
+ {
4472
+ style: [styles44.panel, { backgroundColor: colors2.colorBg }],
4473
+ accessibilityLabel,
4474
+ children: content
4475
+ }
4476
+ )
4477
+ ] })
4467
4478
  }
4468
4479
  )
4469
4480
  ] });
package/dist/index.d.cts CHANGED
@@ -137,20 +137,30 @@ interface SkeletonProps {
137
137
  declare function Skeleton({ style }: SkeletonProps): react_jsx_runtime.JSX.Element;
138
138
 
139
139
  type AlertVariant = 'info' | 'success' | 'warning' | 'error';
140
+ /** Function form of children: receives the variant's resolved text color so
141
+ * custom content can match the alert's theme. */
142
+ type AlertContentRenderProp = (props: {
143
+ color: string;
144
+ }) => ReactNode;
140
145
  interface AlertProps {
141
146
  variant?: AlertVariant;
142
147
  icon?: ReactNode;
143
148
  title?: string;
144
- children: ReactNode;
149
+ children: ReactNode | AlertContentRenderProp;
145
150
  onDismiss?: () => void;
146
151
  style?: StyleProp<ViewStyle>;
147
152
  }
148
153
  declare function Alert({ variant, icon, title, children, onDismiss, style, }: Readonly<AlertProps>): react_jsx_runtime.JSX.Element;
149
154
 
150
155
  type BannerVariant = 'info' | 'success' | 'warning' | 'error';
156
+ /** Function form of children: receives the variant's resolved text color so
157
+ * custom content can match the banner's theme. */
158
+ type BannerContentRenderProp = (props: {
159
+ color: string;
160
+ }) => ReactNode;
151
161
  interface NotificationBannerProps {
152
162
  variant?: BannerVariant;
153
- children: ReactNode;
163
+ children: ReactNode | BannerContentRenderProp;
154
164
  action?: ReactNode;
155
165
  onDismiss?: () => void;
156
166
  style?: StyleProp<ViewStyle>;
package/dist/index.d.ts CHANGED
@@ -137,20 +137,30 @@ interface SkeletonProps {
137
137
  declare function Skeleton({ style }: SkeletonProps): react_jsx_runtime.JSX.Element;
138
138
 
139
139
  type AlertVariant = 'info' | 'success' | 'warning' | 'error';
140
+ /** Function form of children: receives the variant's resolved text color so
141
+ * custom content can match the alert's theme. */
142
+ type AlertContentRenderProp = (props: {
143
+ color: string;
144
+ }) => ReactNode;
140
145
  interface AlertProps {
141
146
  variant?: AlertVariant;
142
147
  icon?: ReactNode;
143
148
  title?: string;
144
- children: ReactNode;
149
+ children: ReactNode | AlertContentRenderProp;
145
150
  onDismiss?: () => void;
146
151
  style?: StyleProp<ViewStyle>;
147
152
  }
148
153
  declare function Alert({ variant, icon, title, children, onDismiss, style, }: Readonly<AlertProps>): react_jsx_runtime.JSX.Element;
149
154
 
150
155
  type BannerVariant = 'info' | 'success' | 'warning' | 'error';
156
+ /** Function form of children: receives the variant's resolved text color so
157
+ * custom content can match the banner's theme. */
158
+ type BannerContentRenderProp = (props: {
159
+ color: string;
160
+ }) => ReactNode;
151
161
  interface NotificationBannerProps {
152
162
  variant?: BannerVariant;
153
- children: ReactNode;
163
+ children: ReactNode | BannerContentRenderProp;
154
164
  action?: ReactNode;
155
165
  onDismiss?: () => void;
156
166
  style?: StyleProp<ViewStyle>;