@boostdev/design-system-react-native 0.2.6 → 0.4.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 (28) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/index.cjs +166 -159
  3. package/dist/index.d.cts +13 -3
  4. package/dist/index.d.ts +13 -3
  5. package/dist/index.js +166 -159
  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/interaction/form/SegmentedControl/SegmentedControl.mdx +17 -3
  20. package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +15 -0
  21. package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +9 -0
  22. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +2 -1
  23. package/src/components/ui/Alert/Alert.spec.tsx +32 -1
  24. package/src/components/ui/Alert/Alert.stories.tsx +45 -0
  25. package/src/components/ui/Alert/Alert.tsx +11 -2
  26. package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +32 -1
  27. package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +30 -0
  28. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +16 -3
package/CHANGELOG.md CHANGED
@@ -1,6 +1,100 @@
1
1
  # Changelog
2
2
 
3
3
  All notable changes to `@boostdev/design-system-react-native` are documented here.
4
+ ## [0.4.0] - 2026-09-24
5
+ ### Added
6
+ - Feat(segmented-control): xlarge size with a 56 pt tap target
7
+
8
+ CoachHelpr requires 56 pt tap targets app-wide (the DS Button's own
9
+ `large` is already 56 high). SegmentedControl's largest size was 48,
10
+ short of that minimum.
11
+
12
+ Add an additive `xlarge` size (minHeight 56, font.size.body,
13
+ px spacing.m, py spacing.s) alongside the existing small/medium/large —
14
+ no change to their values. Cover it with a spec asserting a rendered
15
+ xlarge segment has a 56px minHeight, add an XLarge story, and document
16
+ the new size in the component's size table and props reference in
17
+ SegmentedControl.mdx.
18
+
19
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`4e3121d`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/4e3121db4c8f7f1931bcdb8c78a28337ee78d259))
20
+
21
+ ## [0.3.0] - 2026-09-23
22
+ ### Added
23
+ - Feat(alert): support arbitrary and theme-aware children
24
+
25
+ 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))
26
+ - Feat(notification-banner): support arbitrary and theme-aware children
27
+
28
+ 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))
29
+
30
+ ### Fixed
31
+ - Fix(dropdown-menu): make each item reachable for VoiceOver on iOS
32
+
33
+ The sheet's content was wrapped in a no-op Pressable to swallow presses.
34
+ On iOS a Pressable is accessible by default, and an accessible view is a
35
+ single element to VoiceOver and XCUITest: the whole sheet (title, Done,
36
+ every item) read as one element whose label listed all items, and no item
37
+ could be picked on its own. The wrapper was also unneeded: the backdrop is
38
+ a sibling behind the sheet, so sheet touches never reach it.
39
+
40
+ The wrapper is gone, so title, Done and each menuitem are separate
41
+ elements. The backdrop still closes on press but is hidden from assistive
42
+ tech (testID "bds-dropdownmenu-backdrop"); Done is the accessible close.
43
+ The sheet is accessibilityViewIsModal and closes on VoiceOver's escape
44
+ gesture. Specs pin the roleless backdrop, the missing "Close menu" button,
45
+ independent menuitems and no press-swallowing wrapper around them.
46
+
47
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`a42e0da`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/a42e0daa2ece8db443326b07840c8a15edcb2884))
48
+ - Fix(side-sheet): hide the backdrop from assistive tech, close on escape
49
+
50
+ The full-screen backdrop was an accessible "Close side sheet" button next
51
+ to the real close button. VoiceOver listed the close control twice, and a
52
+ double-tap on the full-screen element activates its centre, which can land
53
+ on the panel instead of closing.
54
+
55
+ The backdrop still closes on press but is hidden from assistive tech
56
+ (testID "bds-sidesheet-backdrop"); the close button is the one accessible
57
+ close. The panel is accessibilityViewIsModal and closes on VoiceOver's
58
+ escape gesture. Specs pin exactly one "Close side sheet" button and a
59
+ roleless backdrop that still calls onClose.
60
+
61
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`4b93294`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/4b932947c3989cbf9a23cedb9c545b2d37243781))
62
+ - Fix(dialog): make the dialog's content reachable for VoiceOver on iOS
63
+
64
+ The backdrop Pressable wrapped the panel. On iOS a Pressable is
65
+ accessible by default, and an accessible view is a single element to
66
+ VoiceOver and XCUITest: an open dialog was one full-screen "Close dialog"
67
+ button. The title, the content and the dialog's own buttons could not be
68
+ reached, and a VoiceOver double-tap activated the centre of the screen
69
+ (the panel), so it did nothing.
70
+
71
+ The backdrop is now a sibling behind the panel: it still closes on press
72
+ but is hidden from assistive tech (testID "bds-dialog-backdrop"), and the
73
+ close button is the accessible close. The panel is a plain View,
74
+ accessibilityViewIsModal, and closes on VoiceOver's escape gesture.
75
+ Verified on an iPhone 17 simulator (iOS 26.1): title, close button,
76
+ content and a "Klaar" button inside are separate elements, a backdrop tap
77
+ closes, a panel tap does not, and the dialog looks the same. Specs pin one
78
+ "Close dialog" button, a roleless backdrop that does not contain the
79
+ content, and content presses that do not close.
80
+
81
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`fe6703e`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/fe6703e4aeb9b716212dacf94886cdc7629b2f55))
82
+ - Fix(popover): keep the popover's content reachable for VoiceOver on iOS
83
+
84
+ The "Close popover" backdrop Pressable wrapped the panel, so on iOS the
85
+ open popover was a single accessibility element and its content could not
86
+ be reached by VoiceOver or XCUITest.
87
+
88
+ The backdrop is now a sibling behind the panel. Popover has no close
89
+ button, so the backdrop stays the accessible "Close popover" button, with
90
+ onAccessibilityTap so a VoiceOver double-tap closes it (without it the
91
+ activation lands on the centred panel). The panel is a plain View and
92
+ VoiceOver's escape gesture closes the popover. Specs pin the separate
93
+ backdrop button, content outside it, and content presses that do not
94
+ close.
95
+
96
+ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ([`5ddb57c`](https://gitlab.com/b00stdev/boostdev-design-system-react-native/-/commit/5ddb57c5158b8181d9d87eb706099662519fbdad))
97
+
4
98
  ## [0.2.6] - 2026-06-15
5
99
  ### Fixed
6
100
  - Fix(collapsible): render the disclosure indicator as a border-box chevron instead of the ▸ (U+25B8) glyph char
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,
@@ -2887,7 +2891,8 @@ var TRACK_PADDING = import_native.spacing.xxxs;
2887
2891
  var sizeTokens2 = {
2888
2892
  small: { minHeight: 32, fontSize: import_native.font.size.bodyS, px: import_native.spacing.s, py: import_native.spacing.xxs },
2889
2893
  medium: { minHeight: 44, fontSize: import_native.font.size.body, px: import_native.spacing.m, py: import_native.spacing.xs },
2890
- large: { minHeight: 48, fontSize: import_native.font.size.body, px: import_native.spacing.m, py: import_native.spacing.s }
2894
+ large: { minHeight: 48, fontSize: import_native.font.size.body, px: import_native.spacing.m, py: import_native.spacing.s },
2895
+ xlarge: { minHeight: 56, fontSize: import_native.font.size.body, px: import_native.spacing.m, py: import_native.spacing.s }
2891
2896
  };
2892
2897
  var thumbShadow = {
2893
2898
  shadowColor: "#000",
@@ -3797,46 +3802,48 @@ function Dialog({
3797
3802
  transparent: true,
3798
3803
  animationType: "fade",
3799
3804
  onRequestClose: onClose,
3800
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3801
- import_react_native44.Pressable,
3802
- {
3803
- style: styles40.overlay,
3804
- onPress: onClose,
3805
- accessibilityRole: "button",
3806
- accessibilityLabel: "Close dialog",
3807
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3808
- import_react_native44.Pressable,
3809
- {
3810
- style: [styles40.panel, { backgroundColor: colors2.colorGreySubtle }, style],
3811
- onPress: () => {
3812
- },
3813
- accessibilityRole: "none",
3814
- children: [
3815
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3816
- import_react_native44.Pressable,
3817
- {
3818
- style: styles40.closeButton,
3819
- onPress: onClose,
3820
- accessibilityRole: "button",
3821
- accessibilityLabel: "Close dialog",
3822
- hitSlop: 8,
3823
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3824
- import_react_native44.Text,
3825
- {
3826
- style: [styles40.closeText, { color: colors2.colorOnBgSubtle }],
3827
- "aria-hidden": true,
3828
- children: "\u2715"
3829
- }
3830
- )
3831
- }
3832
- ),
3833
- !!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 }) }),
3834
- children
3835
- ]
3836
- }
3837
- )
3838
- }
3839
- )
3805
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_react_native44.View, { style: styles40.overlay, children: [
3806
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3807
+ import_react_native44.Pressable,
3808
+ {
3809
+ testID: "bds-dialog-backdrop",
3810
+ style: import_react_native44.StyleSheet.absoluteFill,
3811
+ onPress: onClose,
3812
+ accessible: false,
3813
+ importantForAccessibility: "no"
3814
+ }
3815
+ ),
3816
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3817
+ import_react_native44.View,
3818
+ {
3819
+ style: [styles40.panel, { backgroundColor: colors2.colorGreySubtle }, style],
3820
+ accessibilityViewIsModal: true,
3821
+ onAccessibilityEscape: onClose,
3822
+ children: [
3823
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3824
+ import_react_native44.Pressable,
3825
+ {
3826
+ style: styles40.closeButton,
3827
+ onPress: onClose,
3828
+ accessibilityRole: "button",
3829
+ accessibilityLabel: "Close dialog",
3830
+ hitSlop: 8,
3831
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3832
+ import_react_native44.Text,
3833
+ {
3834
+ style: [styles40.closeText, { color: colors2.colorOnBgSubtle }],
3835
+ "aria-hidden": true,
3836
+ children: "\u2715"
3837
+ }
3838
+ )
3839
+ }
3840
+ ),
3841
+ !!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 }) }),
3842
+ children
3843
+ ]
3844
+ }
3845
+ )
3846
+ ] })
3840
3847
  }
3841
3848
  );
3842
3849
  }
@@ -3954,8 +3961,9 @@ function SideSheet({
3954
3961
  {
3955
3962
  style: import_react_native45.StyleSheet.absoluteFill,
3956
3963
  onPress: onClose,
3957
- accessibilityRole: "button",
3958
- accessibilityLabel: "Close side sheet"
3964
+ testID: "bds-sidesheet-backdrop",
3965
+ accessible: false,
3966
+ importantForAccessibility: "no"
3959
3967
  }
3960
3968
  )
3961
3969
  }
@@ -3971,7 +3979,8 @@ function SideSheet({
3971
3979
  },
3972
3980
  style
3973
3981
  ],
3974
- accessibilityRole: "none",
3982
+ accessibilityViewIsModal: true,
3983
+ onAccessibilityEscape: onClose,
3975
3984
  children: [
3976
3985
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3977
3986
  import_react_native45.View,
@@ -4283,8 +4292,9 @@ function DropdownMenu({
4283
4292
  {
4284
4293
  style: import_react_native47.StyleSheet.absoluteFill,
4285
4294
  onPress: () => setOpen(false),
4286
- accessibilityRole: "button",
4287
- accessibilityLabel: "Close menu"
4295
+ testID: "bds-dropdownmenu-backdrop",
4296
+ accessible: false,
4297
+ importantForAccessibility: "no"
4288
4298
  }
4289
4299
  )
4290
4300
  }
@@ -4299,100 +4309,95 @@ function DropdownMenu({
4299
4309
  transform: [{ translateY: slideAnim }]
4300
4310
  }
4301
4311
  ],
4302
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4303
- import_react_native47.Pressable,
4304
- {
4305
- onPress: () => {
4306
- },
4307
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native47.SafeAreaView, { children: [
4308
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4309
- import_react_native47.View,
4310
- {
4311
- style: [
4312
- styles43.sheetHeader,
4313
- { borderBottomColor: colors2.colorBgSubtle }
4314
- ],
4315
- children: [
4316
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native47.Text, { style: [styles43.sheetTitle, { color: colors2.colorOnBg }], children: title }),
4317
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4318
- import_react_native47.Pressable,
4319
- {
4320
- accessibilityRole: "button",
4321
- accessibilityLabel: "Close",
4322
- onPress: () => setOpen(false),
4323
- hitSlop: 8,
4324
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4325
- import_react_native47.Text,
4326
- {
4327
- style: [
4328
- styles43.closeText,
4329
- { color: colors2.colorInteractive }
4330
- ],
4331
- children: "Done"
4332
- }
4333
- )
4334
- }
4335
- )
4336
- ]
4337
- }
4338
- ),
4339
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4340
- import_react_native47.FlatList,
4341
- {
4342
- data: items,
4343
- keyExtractor: (item) => item.id,
4344
- renderItem: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
4345
- item.separator && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4346
- import_react_native47.View,
4312
+ accessibilityViewIsModal: true,
4313
+ onAccessibilityEscape: () => setOpen(false),
4314
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_native47.SafeAreaView, { children: [
4315
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4316
+ import_react_native47.View,
4317
+ {
4318
+ style: [
4319
+ styles43.sheetHeader,
4320
+ { borderBottomColor: colors2.colorBgSubtle }
4321
+ ],
4322
+ children: [
4323
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_react_native47.Text, { style: [styles43.sheetTitle, { color: colors2.colorOnBg }], children: title }),
4324
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4325
+ import_react_native47.Pressable,
4326
+ {
4327
+ accessibilityRole: "button",
4328
+ accessibilityLabel: "Close",
4329
+ onPress: () => setOpen(false),
4330
+ hitSlop: 8,
4331
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4332
+ import_react_native47.Text,
4347
4333
  {
4348
4334
  style: [
4349
- styles43.separator,
4350
- { backgroundColor: colors2.colorBgSubtle }
4335
+ styles43.closeText,
4336
+ { color: colors2.colorInteractive }
4351
4337
  ],
4352
- accessibilityRole: "none"
4353
- }
4354
- ),
4355
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4356
- import_react_native47.Pressable,
4357
- {
4358
- accessibilityRole: "menuitem",
4359
- accessibilityLabel: item.label,
4360
- accessibilityState: { disabled: item.disabled },
4361
- disabled: item.disabled,
4362
- onPress: () => handleItemPress(item),
4363
- style: ({ pressed }) => [
4364
- styles43.item,
4365
- pressed && { backgroundColor: colors2.colorBgSubtle },
4366
- item.disabled && { opacity: 0.4 }
4367
- ],
4368
- children: [
4369
- !!item.icon && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4370
- import_react_native47.View,
4371
- {
4372
- importantForAccessibility: "no-hide-descendants",
4373
- accessibilityElementsHidden: true,
4374
- children: item.icon
4375
- }
4376
- ),
4377
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4378
- import_react_native47.Text,
4379
- {
4380
- style: [
4381
- styles43.itemText,
4382
- { color: colors2.colorOnBg }
4383
- ],
4384
- children: item.label
4385
- }
4386
- )
4387
- ]
4338
+ children: "Done"
4388
4339
  }
4389
4340
  )
4390
- ] })
4391
- }
4392
- )
4393
- ] })
4394
- }
4395
- )
4341
+ }
4342
+ )
4343
+ ]
4344
+ }
4345
+ ),
4346
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4347
+ import_react_native47.FlatList,
4348
+ {
4349
+ data: items,
4350
+ keyExtractor: (item) => item.id,
4351
+ renderItem: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
4352
+ item.separator && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4353
+ import_react_native47.View,
4354
+ {
4355
+ style: [
4356
+ styles43.separator,
4357
+ { backgroundColor: colors2.colorBgSubtle }
4358
+ ],
4359
+ accessibilityRole: "none"
4360
+ }
4361
+ ),
4362
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
4363
+ import_react_native47.Pressable,
4364
+ {
4365
+ accessibilityRole: "menuitem",
4366
+ accessibilityLabel: item.label,
4367
+ accessibilityState: { disabled: item.disabled },
4368
+ disabled: item.disabled,
4369
+ onPress: () => handleItemPress(item),
4370
+ style: ({ pressed }) => [
4371
+ styles43.item,
4372
+ pressed && { backgroundColor: colors2.colorBgSubtle },
4373
+ item.disabled && { opacity: 0.4 }
4374
+ ],
4375
+ children: [
4376
+ !!item.icon && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4377
+ import_react_native47.View,
4378
+ {
4379
+ importantForAccessibility: "no-hide-descendants",
4380
+ accessibilityElementsHidden: true,
4381
+ children: item.icon
4382
+ }
4383
+ ),
4384
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4385
+ import_react_native47.Text,
4386
+ {
4387
+ style: [
4388
+ styles43.itemText,
4389
+ { color: colors2.colorOnBg }
4390
+ ],
4391
+ children: item.label
4392
+ }
4393
+ )
4394
+ ]
4395
+ }
4396
+ )
4397
+ ] })
4398
+ }
4399
+ )
4400
+ ] })
4396
4401
  }
4397
4402
  )
4398
4403
  ] })
@@ -4436,6 +4441,7 @@ function Popover({
4436
4441
  }) {
4437
4442
  const { colors: colors2 } = useTheme();
4438
4443
  const [isOpen, setIsOpen] = (0, import_react19.useState)(false);
4444
+ const close = () => setIsOpen(false);
4439
4445
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_react_native48.View, { style: [styles44.wrapper, style], children: [
4440
4446
  import_react19.default.cloneElement(children, {
4441
4447
  onPress: () => setIsOpen(true),
@@ -4448,27 +4454,28 @@ function Popover({
4448
4454
  visible: isOpen,
4449
4455
  transparent: true,
4450
4456
  animationType: "fade",
4451
- onRequestClose: () => setIsOpen(false),
4452
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4453
- import_react_native48.Pressable,
4454
- {
4455
- style: styles44.overlay,
4456
- onPress: () => setIsOpen(false),
4457
- accessibilityRole: "button",
4458
- accessibilityLabel: "Close popover",
4459
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4460
- import_react_native48.Pressable,
4461
- {
4462
- style: [styles44.panel, { backgroundColor: colors2.colorBg }],
4463
- onPress: () => {
4464
- },
4465
- accessibilityRole: "none",
4466
- accessibilityLabel,
4467
- children: content
4468
- }
4469
- )
4470
- }
4471
- )
4457
+ onRequestClose: close,
4458
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_react_native48.View, { style: styles44.overlay, onAccessibilityEscape: close, children: [
4459
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4460
+ import_react_native48.Pressable,
4461
+ {
4462
+ testID: "bds-popover-backdrop",
4463
+ style: import_react_native48.StyleSheet.absoluteFill,
4464
+ onPress: close,
4465
+ onAccessibilityTap: close,
4466
+ accessibilityRole: "button",
4467
+ accessibilityLabel: "Close popover"
4468
+ }
4469
+ ),
4470
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4471
+ import_react_native48.View,
4472
+ {
4473
+ style: [styles44.panel, { backgroundColor: colors2.colorBg }],
4474
+ accessibilityLabel,
4475
+ children: content
4476
+ }
4477
+ )
4478
+ ] })
4472
4479
  }
4473
4480
  )
4474
4481
  ] });
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>;
@@ -458,7 +468,7 @@ interface ComboboxProps {
458
468
  }
459
469
  declare function Combobox({ label, name, options, placeholder, value, onChange, disabled, error, hint, style, }: Readonly<ComboboxProps>): react_jsx_runtime.JSX.Element;
460
470
 
461
- type SegmentedControlSize = 'small' | 'medium' | 'large';
471
+ type SegmentedControlSize = 'small' | 'medium' | 'large' | 'xlarge';
462
472
  type SegmentedControlVariant = 'outline' | 'filled';
463
473
  interface SegmentedControlProps {
464
474
  selectedIndex?: number;
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>;
@@ -458,7 +468,7 @@ interface ComboboxProps {
458
468
  }
459
469
  declare function Combobox({ label, name, options, placeholder, value, onChange, disabled, error, hint, style, }: Readonly<ComboboxProps>): react_jsx_runtime.JSX.Element;
460
470
 
461
- type SegmentedControlSize = 'small' | 'medium' | 'large';
471
+ type SegmentedControlSize = 'small' | 'medium' | 'large' | 'xlarge';
462
472
  type SegmentedControlVariant = 'outline' | 'filled';
463
473
  interface SegmentedControlProps {
464
474
  selectedIndex?: number;