@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.
- package/CHANGELOG.md +87 -0
- package/dist/index.cjs +176 -165
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +176 -165
- package/package.json +1 -1
- package/src/components/interaction/Dialog/Dialog.mdx +3 -2
- package/src/components/interaction/Dialog/Dialog.spec.tsx +42 -11
- package/src/components/interaction/Dialog/Dialog.tsx +19 -12
- package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +3 -1
- package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +73 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +79 -73
- package/src/components/interaction/Popover/Popover.mdx +3 -1
- package/src/components/interaction/Popover/Popover.spec.tsx +43 -3
- package/src/components/interaction/Popover/Popover.tsx +23 -13
- package/src/components/interaction/SideSheet/SideSheet.mdx +4 -3
- package/src/components/interaction/SideSheet/SideSheet.spec.tsx +8 -9
- package/src/components/interaction/SideSheet/SideSheet.tsx +9 -3
- package/src/components/ui/Alert/Alert.spec.tsx +32 -1
- package/src/components/ui/Alert/Alert.stories.tsx +45 -0
- package/src/components/ui/Alert/Alert.tsx +11 -2
- package/src/components/ui/Collapsible/Collapsible.spec.tsx +11 -0
- package/src/components/ui/Collapsible/Collapsible.tsx +13 -8
- package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +32 -1
- package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +30 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.tsx +16 -3
package/dist/index.js
CHANGED
|
@@ -435,6 +435,7 @@ function Alert({
|
|
|
435
435
|
error: { bg: colors2.colorRedSubtle, text: colors2.colorOnBg, border: colors2.colorError }
|
|
436
436
|
};
|
|
437
437
|
const { bg, text, border: borderColor } = variantColors[variant];
|
|
438
|
+
const resolvedChildren = typeof children === "function" ? children({ color: text }) : children;
|
|
438
439
|
return /* @__PURE__ */ jsxs2(
|
|
439
440
|
View5,
|
|
440
441
|
{
|
|
@@ -445,7 +446,7 @@ function Alert({
|
|
|
445
446
|
icon && /* @__PURE__ */ jsx9(View5, { style: styles7.icon, children: icon }),
|
|
446
447
|
/* @__PURE__ */ jsxs2(View5, { style: styles7.content, children: [
|
|
447
448
|
title && /* @__PURE__ */ jsx9(Text5, { style: [styles7.title, { color: text }], children: title }),
|
|
448
|
-
/* @__PURE__ */ jsx9(Text5, { style: [styles7.body, { color: text }], children })
|
|
449
|
+
typeof resolvedChildren === "string" || typeof resolvedChildren === "number" ? /* @__PURE__ */ jsx9(Text5, { style: [styles7.body, { color: text }], children: resolvedChildren }) : resolvedChildren
|
|
449
450
|
] }),
|
|
450
451
|
onDismiss && /* @__PURE__ */ jsx9(
|
|
451
452
|
Pressable,
|
|
@@ -474,8 +475,10 @@ var styles8 = StyleSheet8.create({
|
|
|
474
475
|
paddingHorizontal: spacing.m,
|
|
475
476
|
gap: spacing.xs
|
|
476
477
|
},
|
|
478
|
+
body: {
|
|
479
|
+
flex: 1
|
|
480
|
+
},
|
|
477
481
|
content: {
|
|
478
|
-
flex: 1,
|
|
479
482
|
fontSize: font.size.bodyS,
|
|
480
483
|
fontFamily: font.family.body,
|
|
481
484
|
lineHeight: lineHeight.bodyS
|
|
@@ -501,6 +504,7 @@ function NotificationBanner({
|
|
|
501
504
|
error: { bg: colors2.colorRedSubtle, text: colors2.colorOnBg, border: colors2.colorError }
|
|
502
505
|
};
|
|
503
506
|
const { bg, text, border: borderColor } = variantColors[variant];
|
|
507
|
+
const resolvedChildren = typeof children === "function" ? children({ color: text }) : children;
|
|
504
508
|
return /* @__PURE__ */ jsxs3(
|
|
505
509
|
View6,
|
|
506
510
|
{
|
|
@@ -508,7 +512,7 @@ function NotificationBanner({
|
|
|
508
512
|
accessibilityLiveRegion: isUrgent ? "assertive" : "polite",
|
|
509
513
|
style: [styles8.banner, { backgroundColor: bg, borderBottomWidth: 3, borderBottomColor: borderColor }, style],
|
|
510
514
|
children: [
|
|
511
|
-
/* @__PURE__ */ jsx10(Text6, { style: [styles8.content, { color: text }], children }),
|
|
515
|
+
/* @__PURE__ */ jsx10(View6, { style: styles8.body, children: typeof resolvedChildren === "string" || typeof resolvedChildren === "number" ? /* @__PURE__ */ jsx10(Text6, { style: [styles8.content, { color: text }], children: resolvedChildren }) : resolvedChildren }),
|
|
512
516
|
action,
|
|
513
517
|
onDismiss && /* @__PURE__ */ jsx10(
|
|
514
518
|
Pressable2,
|
|
@@ -1059,7 +1063,12 @@ var styles15 = StyleSheet15.create({
|
|
|
1059
1063
|
lineHeight: lineHeight.body
|
|
1060
1064
|
},
|
|
1061
1065
|
chevron: {
|
|
1062
|
-
|
|
1066
|
+
// Border-box chevron (no glyph font dependency): a small square with two
|
|
1067
|
+
// adjacent borders, rotated to form a crisp "›" / "⌄" disclosure indicator.
|
|
1068
|
+
width: 8,
|
|
1069
|
+
height: 8,
|
|
1070
|
+
borderRightWidth: 2,
|
|
1071
|
+
borderBottomWidth: 2,
|
|
1063
1072
|
marginStart: spacing.xs
|
|
1064
1073
|
},
|
|
1065
1074
|
content: {
|
|
@@ -1098,9 +1107,9 @@ function Collapsible({
|
|
|
1098
1107
|
}
|
|
1099
1108
|
onToggle?.(next);
|
|
1100
1109
|
}, [isOpen, isControlled, onToggle, rotation]);
|
|
1101
|
-
const
|
|
1110
|
+
const rotate = rotation.interpolate({
|
|
1102
1111
|
inputRange: [0, 1],
|
|
1103
|
-
outputRange: ["
|
|
1112
|
+
outputRange: ["-45deg", "45deg"]
|
|
1104
1113
|
});
|
|
1105
1114
|
return /* @__PURE__ */ jsxs9(
|
|
1106
1115
|
View12,
|
|
@@ -1119,12 +1128,12 @@ function Collapsible({
|
|
|
1119
1128
|
children: [
|
|
1120
1129
|
/* @__PURE__ */ jsx17(Text13, { style: [styles15.summaryText, { color: colors2.colorOnBg }], children: summary }),
|
|
1121
1130
|
/* @__PURE__ */ jsx17(
|
|
1122
|
-
Animated2.
|
|
1131
|
+
Animated2.View,
|
|
1123
1132
|
{
|
|
1124
|
-
|
|
1133
|
+
testID: "bds-collapsible-chevron",
|
|
1134
|
+
style: [styles15.chevron, { borderColor: colors2.colorOnBgSubtle, transform: [{ rotate }] }],
|
|
1125
1135
|
importantForAccessibility: "no",
|
|
1126
|
-
accessibilityElementsHidden: true
|
|
1127
|
-
children: "\u25B8"
|
|
1136
|
+
accessibilityElementsHidden: true
|
|
1128
1137
|
}
|
|
1129
1138
|
)
|
|
1130
1139
|
]
|
|
@@ -3777,46 +3786,48 @@ function Dialog({
|
|
|
3777
3786
|
transparent: true,
|
|
3778
3787
|
animationType: "fade",
|
|
3779
3788
|
onRequestClose: onClose,
|
|
3780
|
-
children: /* @__PURE__ */
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
}
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3789
|
+
children: /* @__PURE__ */ jsxs29(View37, { style: styles40.overlay, children: [
|
|
3790
|
+
/* @__PURE__ */ jsx44(
|
|
3791
|
+
Pressable22,
|
|
3792
|
+
{
|
|
3793
|
+
testID: "bds-dialog-backdrop",
|
|
3794
|
+
style: StyleSheet40.absoluteFill,
|
|
3795
|
+
onPress: onClose,
|
|
3796
|
+
accessible: false,
|
|
3797
|
+
importantForAccessibility: "no"
|
|
3798
|
+
}
|
|
3799
|
+
),
|
|
3800
|
+
/* @__PURE__ */ jsxs29(
|
|
3801
|
+
View37,
|
|
3802
|
+
{
|
|
3803
|
+
style: [styles40.panel, { backgroundColor: colors2.colorGreySubtle }, style],
|
|
3804
|
+
accessibilityViewIsModal: true,
|
|
3805
|
+
onAccessibilityEscape: onClose,
|
|
3806
|
+
children: [
|
|
3807
|
+
/* @__PURE__ */ jsx44(
|
|
3808
|
+
Pressable22,
|
|
3809
|
+
{
|
|
3810
|
+
style: styles40.closeButton,
|
|
3811
|
+
onPress: onClose,
|
|
3812
|
+
accessibilityRole: "button",
|
|
3813
|
+
accessibilityLabel: "Close dialog",
|
|
3814
|
+
hitSlop: 8,
|
|
3815
|
+
children: /* @__PURE__ */ jsx44(
|
|
3816
|
+
Text32,
|
|
3817
|
+
{
|
|
3818
|
+
style: [styles40.closeText, { color: colors2.colorOnBgSubtle }],
|
|
3819
|
+
"aria-hidden": true,
|
|
3820
|
+
children: "\u2715"
|
|
3821
|
+
}
|
|
3822
|
+
)
|
|
3823
|
+
}
|
|
3824
|
+
),
|
|
3825
|
+
!!title && /* @__PURE__ */ jsx44(View37, { style: styles40.header, children: /* @__PURE__ */ jsx44(Text32, { style: [styles40.title, { color: colors2.colorOnGreySubtle }], children: title }) }),
|
|
3826
|
+
children
|
|
3827
|
+
]
|
|
3828
|
+
}
|
|
3829
|
+
)
|
|
3830
|
+
] })
|
|
3820
3831
|
}
|
|
3821
3832
|
);
|
|
3822
3833
|
}
|
|
@@ -3942,8 +3953,9 @@ function SideSheet({
|
|
|
3942
3953
|
{
|
|
3943
3954
|
style: StyleSheet41.absoluteFill,
|
|
3944
3955
|
onPress: onClose,
|
|
3945
|
-
|
|
3946
|
-
|
|
3956
|
+
testID: "bds-sidesheet-backdrop",
|
|
3957
|
+
accessible: false,
|
|
3958
|
+
importantForAccessibility: "no"
|
|
3947
3959
|
}
|
|
3948
3960
|
)
|
|
3949
3961
|
}
|
|
@@ -3959,7 +3971,8 @@ function SideSheet({
|
|
|
3959
3971
|
},
|
|
3960
3972
|
style
|
|
3961
3973
|
],
|
|
3962
|
-
|
|
3974
|
+
accessibilityViewIsModal: true,
|
|
3975
|
+
onAccessibilityEscape: onClose,
|
|
3963
3976
|
children: [
|
|
3964
3977
|
/* @__PURE__ */ jsxs30(
|
|
3965
3978
|
View38,
|
|
@@ -4295,8 +4308,9 @@ function DropdownMenu({
|
|
|
4295
4308
|
{
|
|
4296
4309
|
style: StyleSheet43.absoluteFill,
|
|
4297
4310
|
onPress: () => setOpen(false),
|
|
4298
|
-
|
|
4299
|
-
|
|
4311
|
+
testID: "bds-dropdownmenu-backdrop",
|
|
4312
|
+
accessible: false,
|
|
4313
|
+
importantForAccessibility: "no"
|
|
4300
4314
|
}
|
|
4301
4315
|
)
|
|
4302
4316
|
}
|
|
@@ -4311,100 +4325,95 @@ function DropdownMenu({
|
|
|
4311
4325
|
transform: [{ translateY: slideAnim }]
|
|
4312
4326
|
}
|
|
4313
4327
|
],
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
{
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
hitSlop: 8,
|
|
4336
|
-
children: /* @__PURE__ */ jsx47(
|
|
4337
|
-
Text35,
|
|
4338
|
-
{
|
|
4339
|
-
style: [
|
|
4340
|
-
styles43.closeText,
|
|
4341
|
-
{ color: colors2.colorInteractive }
|
|
4342
|
-
],
|
|
4343
|
-
children: "Done"
|
|
4344
|
-
}
|
|
4345
|
-
)
|
|
4346
|
-
}
|
|
4347
|
-
)
|
|
4348
|
-
]
|
|
4349
|
-
}
|
|
4350
|
-
),
|
|
4351
|
-
/* @__PURE__ */ jsx47(
|
|
4352
|
-
FlatList2,
|
|
4353
|
-
{
|
|
4354
|
-
data: items,
|
|
4355
|
-
keyExtractor: (item) => item.id,
|
|
4356
|
-
renderItem: ({ item }) => /* @__PURE__ */ jsxs32(Fragment2, { children: [
|
|
4357
|
-
item.separator && /* @__PURE__ */ jsx47(
|
|
4358
|
-
View40,
|
|
4328
|
+
accessibilityViewIsModal: true,
|
|
4329
|
+
onAccessibilityEscape: () => setOpen(false),
|
|
4330
|
+
children: /* @__PURE__ */ jsxs32(SafeAreaView2, { children: [
|
|
4331
|
+
/* @__PURE__ */ jsxs32(
|
|
4332
|
+
View40,
|
|
4333
|
+
{
|
|
4334
|
+
style: [
|
|
4335
|
+
styles43.sheetHeader,
|
|
4336
|
+
{ borderBottomColor: colors2.colorBgSubtle }
|
|
4337
|
+
],
|
|
4338
|
+
children: [
|
|
4339
|
+
/* @__PURE__ */ jsx47(Text35, { style: [styles43.sheetTitle, { color: colors2.colorOnBg }], children: title }),
|
|
4340
|
+
/* @__PURE__ */ jsx47(
|
|
4341
|
+
Pressable25,
|
|
4342
|
+
{
|
|
4343
|
+
accessibilityRole: "button",
|
|
4344
|
+
accessibilityLabel: "Close",
|
|
4345
|
+
onPress: () => setOpen(false),
|
|
4346
|
+
hitSlop: 8,
|
|
4347
|
+
children: /* @__PURE__ */ jsx47(
|
|
4348
|
+
Text35,
|
|
4359
4349
|
{
|
|
4360
4350
|
style: [
|
|
4361
|
-
styles43.
|
|
4362
|
-
{
|
|
4363
|
-
],
|
|
4364
|
-
accessibilityRole: "none"
|
|
4365
|
-
}
|
|
4366
|
-
),
|
|
4367
|
-
/* @__PURE__ */ jsxs32(
|
|
4368
|
-
Pressable25,
|
|
4369
|
-
{
|
|
4370
|
-
accessibilityRole: "menuitem",
|
|
4371
|
-
accessibilityLabel: item.label,
|
|
4372
|
-
accessibilityState: { disabled: item.disabled },
|
|
4373
|
-
disabled: item.disabled,
|
|
4374
|
-
onPress: () => handleItemPress(item),
|
|
4375
|
-
style: ({ pressed }) => [
|
|
4376
|
-
styles43.item,
|
|
4377
|
-
pressed && { backgroundColor: colors2.colorBgSubtle },
|
|
4378
|
-
item.disabled && { opacity: 0.4 }
|
|
4351
|
+
styles43.closeText,
|
|
4352
|
+
{ color: colors2.colorInteractive }
|
|
4379
4353
|
],
|
|
4380
|
-
children:
|
|
4381
|
-
!!item.icon && /* @__PURE__ */ jsx47(
|
|
4382
|
-
View40,
|
|
4383
|
-
{
|
|
4384
|
-
importantForAccessibility: "no-hide-descendants",
|
|
4385
|
-
accessibilityElementsHidden: true,
|
|
4386
|
-
children: item.icon
|
|
4387
|
-
}
|
|
4388
|
-
),
|
|
4389
|
-
/* @__PURE__ */ jsx47(
|
|
4390
|
-
Text35,
|
|
4391
|
-
{
|
|
4392
|
-
style: [
|
|
4393
|
-
styles43.itemText,
|
|
4394
|
-
{ color: colors2.colorOnBg }
|
|
4395
|
-
],
|
|
4396
|
-
children: item.label
|
|
4397
|
-
}
|
|
4398
|
-
)
|
|
4399
|
-
]
|
|
4354
|
+
children: "Done"
|
|
4400
4355
|
}
|
|
4401
4356
|
)
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4357
|
+
}
|
|
4358
|
+
)
|
|
4359
|
+
]
|
|
4360
|
+
}
|
|
4361
|
+
),
|
|
4362
|
+
/* @__PURE__ */ jsx47(
|
|
4363
|
+
FlatList2,
|
|
4364
|
+
{
|
|
4365
|
+
data: items,
|
|
4366
|
+
keyExtractor: (item) => item.id,
|
|
4367
|
+
renderItem: ({ item }) => /* @__PURE__ */ jsxs32(Fragment2, { children: [
|
|
4368
|
+
item.separator && /* @__PURE__ */ jsx47(
|
|
4369
|
+
View40,
|
|
4370
|
+
{
|
|
4371
|
+
style: [
|
|
4372
|
+
styles43.separator,
|
|
4373
|
+
{ backgroundColor: colors2.colorBgSubtle }
|
|
4374
|
+
],
|
|
4375
|
+
accessibilityRole: "none"
|
|
4376
|
+
}
|
|
4377
|
+
),
|
|
4378
|
+
/* @__PURE__ */ jsxs32(
|
|
4379
|
+
Pressable25,
|
|
4380
|
+
{
|
|
4381
|
+
accessibilityRole: "menuitem",
|
|
4382
|
+
accessibilityLabel: item.label,
|
|
4383
|
+
accessibilityState: { disabled: item.disabled },
|
|
4384
|
+
disabled: item.disabled,
|
|
4385
|
+
onPress: () => handleItemPress(item),
|
|
4386
|
+
style: ({ pressed }) => [
|
|
4387
|
+
styles43.item,
|
|
4388
|
+
pressed && { backgroundColor: colors2.colorBgSubtle },
|
|
4389
|
+
item.disabled && { opacity: 0.4 }
|
|
4390
|
+
],
|
|
4391
|
+
children: [
|
|
4392
|
+
!!item.icon && /* @__PURE__ */ jsx47(
|
|
4393
|
+
View40,
|
|
4394
|
+
{
|
|
4395
|
+
importantForAccessibility: "no-hide-descendants",
|
|
4396
|
+
accessibilityElementsHidden: true,
|
|
4397
|
+
children: item.icon
|
|
4398
|
+
}
|
|
4399
|
+
),
|
|
4400
|
+
/* @__PURE__ */ jsx47(
|
|
4401
|
+
Text35,
|
|
4402
|
+
{
|
|
4403
|
+
style: [
|
|
4404
|
+
styles43.itemText,
|
|
4405
|
+
{ color: colors2.colorOnBg }
|
|
4406
|
+
],
|
|
4407
|
+
children: item.label
|
|
4408
|
+
}
|
|
4409
|
+
)
|
|
4410
|
+
]
|
|
4411
|
+
}
|
|
4412
|
+
)
|
|
4413
|
+
] })
|
|
4414
|
+
}
|
|
4415
|
+
)
|
|
4416
|
+
] })
|
|
4408
4417
|
}
|
|
4409
4418
|
)
|
|
4410
4419
|
] })
|
|
@@ -4453,6 +4462,7 @@ function Popover({
|
|
|
4453
4462
|
}) {
|
|
4454
4463
|
const { colors: colors2 } = useTheme();
|
|
4455
4464
|
const [isOpen, setIsOpen] = useState15(false);
|
|
4465
|
+
const close = () => setIsOpen(false);
|
|
4456
4466
|
return /* @__PURE__ */ jsxs33(View41, { style: [styles44.wrapper, style], children: [
|
|
4457
4467
|
React2.cloneElement(children, {
|
|
4458
4468
|
onPress: () => setIsOpen(true),
|
|
@@ -4465,27 +4475,28 @@ function Popover({
|
|
|
4465
4475
|
visible: isOpen,
|
|
4466
4476
|
transparent: true,
|
|
4467
4477
|
animationType: "fade",
|
|
4468
|
-
onRequestClose:
|
|
4469
|
-
children: /* @__PURE__ */
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4478
|
+
onRequestClose: close,
|
|
4479
|
+
children: /* @__PURE__ */ jsxs33(View41, { style: styles44.overlay, onAccessibilityEscape: close, children: [
|
|
4480
|
+
/* @__PURE__ */ jsx48(
|
|
4481
|
+
Pressable26,
|
|
4482
|
+
{
|
|
4483
|
+
testID: "bds-popover-backdrop",
|
|
4484
|
+
style: StyleSheet44.absoluteFill,
|
|
4485
|
+
onPress: close,
|
|
4486
|
+
onAccessibilityTap: close,
|
|
4487
|
+
accessibilityRole: "button",
|
|
4488
|
+
accessibilityLabel: "Close popover"
|
|
4489
|
+
}
|
|
4490
|
+
),
|
|
4491
|
+
/* @__PURE__ */ jsx48(
|
|
4492
|
+
View41,
|
|
4493
|
+
{
|
|
4494
|
+
style: [styles44.panel, { backgroundColor: colors2.colorBg }],
|
|
4495
|
+
accessibilityLabel,
|
|
4496
|
+
children: content
|
|
4497
|
+
}
|
|
4498
|
+
)
|
|
4499
|
+
] })
|
|
4489
4500
|
}
|
|
4490
4501
|
)
|
|
4491
4502
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boostdev/design-system-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "BoostDev React Native component library: accessible, token-driven components built on @boostdev/design-system-foundation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -56,6 +56,7 @@ export default function App() {
|
|
|
56
56
|
|
|
57
57
|
## Accessibility
|
|
58
58
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
59
|
+
- The backdrop still closes on press, but is hidden from assistive tech (a leaf `Pressable` would otherwise group the whole dialog into one element on iOS); the close button, labelled `accessibilityLabel="Close dialog"`, is the accessible way to close
|
|
60
|
+
- The title, the content and any controls inside are separately reachable by VoiceOver and XCUITest, not grouped into one element
|
|
61
|
+
- VoiceOver's escape gesture also calls `onClose`
|
|
61
62
|
- Android back button triggers `onRequestClose` which calls `onClose`
|
|
@@ -40,34 +40,65 @@ describe('Dialog (native)', () => {
|
|
|
40
40
|
<span>Body</span>
|
|
41
41
|
</Dialog>,
|
|
42
42
|
);
|
|
43
|
-
|
|
44
|
-
expect(closeButtons.length).toBeGreaterThanOrEqual(1);
|
|
43
|
+
expect(screen.getByRole('button', { name: 'Close dialog' })).toBeInTheDocument();
|
|
45
44
|
});
|
|
46
45
|
|
|
47
|
-
it('calls onClose when close button is pressed', () => {
|
|
46
|
+
it('calls onClose when the close button is pressed', () => {
|
|
48
47
|
const onClose = vi.fn();
|
|
49
48
|
renderWithTheme(
|
|
50
49
|
<Dialog isOpen onClose={onClose}>
|
|
51
50
|
<span>Body</span>
|
|
52
51
|
</Dialog>,
|
|
53
52
|
);
|
|
54
|
-
|
|
55
|
-
// The inner close button (not the backdrop)
|
|
56
|
-
const innerClose = closeButtons[closeButtons.length - 1];
|
|
57
|
-
fireEvent.click(innerClose);
|
|
53
|
+
fireEvent.click(screen.getByRole('button', { name: 'Close dialog' }));
|
|
58
54
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
59
55
|
});
|
|
60
56
|
|
|
61
|
-
it('calls onClose when backdrop is pressed', () => {
|
|
57
|
+
it('calls onClose when the backdrop is pressed', () => {
|
|
62
58
|
const onClose = vi.fn();
|
|
63
59
|
renderWithTheme(
|
|
64
60
|
<Dialog isOpen onClose={onClose}>
|
|
65
61
|
<span>Body</span>
|
|
66
62
|
</Dialog>,
|
|
67
63
|
);
|
|
68
|
-
|
|
69
|
-
// The first one is the backdrop
|
|
70
|
-
fireEvent.click(closeButtons[0]);
|
|
64
|
+
fireEvent.click(screen.getByTestId('bds-dialog-backdrop'));
|
|
71
65
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
72
66
|
});
|
|
67
|
+
|
|
68
|
+
it('does not include the content inside the backdrop', () => {
|
|
69
|
+
renderWithTheme(
|
|
70
|
+
<Dialog isOpen onClose={() => {}}>
|
|
71
|
+
<span>Dialog body</span>
|
|
72
|
+
</Dialog>,
|
|
73
|
+
);
|
|
74
|
+
const backdrop = screen.getByTestId('bds-dialog-backdrop');
|
|
75
|
+
expect(backdrop).not.toContainElement(screen.getByText('Dialog body'));
|
|
76
|
+
expect(backdrop).not.toHaveAttribute('role');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('does not call onClose when the content is pressed', () => {
|
|
80
|
+
const onClose = vi.fn();
|
|
81
|
+
renderWithTheme(
|
|
82
|
+
<Dialog isOpen onClose={onClose}>
|
|
83
|
+
<span>Dialog body</span>
|
|
84
|
+
</Dialog>,
|
|
85
|
+
);
|
|
86
|
+
fireEvent.click(screen.getByText('Dialog body'));
|
|
87
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('keeps a child button reachable and separate from onClose', () => {
|
|
91
|
+
const onClose = vi.fn();
|
|
92
|
+
const onAction = vi.fn();
|
|
93
|
+
renderWithTheme(
|
|
94
|
+
<Dialog isOpen onClose={onClose}>
|
|
95
|
+
<button type="button" onClick={onAction}>
|
|
96
|
+
Confirm
|
|
97
|
+
</button>
|
|
98
|
+
</Dialog>,
|
|
99
|
+
);
|
|
100
|
+
fireEvent.click(screen.getByRole('button', { name: 'Confirm' }));
|
|
101
|
+
expect(onAction).toHaveBeenCalledTimes(1);
|
|
102
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
73
104
|
});
|
|
@@ -84,18 +84,25 @@ export function Dialog({
|
|
|
84
84
|
animationType="fade"
|
|
85
85
|
onRequestClose={onClose}
|
|
86
86
|
>
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
<View style={styles.overlay}>
|
|
88
|
+
{/*
|
|
89
|
+
* A Pressable is accessible by default on iOS, which makes it a leaf:
|
|
90
|
+
* VoiceOver cannot reach anything nested inside it. As a sibling behind
|
|
91
|
+
* the panel (not its parent), the backdrop still closes on press for
|
|
92
|
+
* sighted/touch users but never swallows the panel's contents, so the
|
|
93
|
+
* close button below stays reachable as the accessible way to close.
|
|
94
|
+
*/}
|
|
93
95
|
<Pressable
|
|
96
|
+
testID="bds-dialog-backdrop"
|
|
97
|
+
style={StyleSheet.absoluteFill}
|
|
98
|
+
onPress={onClose}
|
|
99
|
+
accessible={false}
|
|
100
|
+
importantForAccessibility="no"
|
|
101
|
+
/>
|
|
102
|
+
<View
|
|
94
103
|
style={[styles.panel, { backgroundColor: colors.colorGreySubtle }, style]}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}}
|
|
98
|
-
accessibilityRole="none"
|
|
104
|
+
accessibilityViewIsModal
|
|
105
|
+
onAccessibilityEscape={onClose}
|
|
99
106
|
>
|
|
100
107
|
<Pressable
|
|
101
108
|
style={styles.closeButton}
|
|
@@ -121,8 +128,8 @@ export function Dialog({
|
|
|
121
128
|
)}
|
|
122
129
|
|
|
123
130
|
{children}
|
|
124
|
-
</
|
|
125
|
-
</
|
|
131
|
+
</View>
|
|
132
|
+
</View>
|
|
126
133
|
</Modal>
|
|
127
134
|
);
|
|
128
135
|
}
|
|
@@ -69,6 +69,8 @@ export default function App() {
|
|
|
69
69
|
## Accessibility
|
|
70
70
|
|
|
71
71
|
- Trigger has `accessibilityRole="button"` with `expanded` state
|
|
72
|
-
- Menu items have `accessibilityRole="menuitem"`
|
|
72
|
+
- Menu items have `accessibilityRole="menuitem"` and are each reachable on their own — on iOS the sheet is no longer wrapped in a `Pressable`, which used to group the whole sheet (title, Done, every item) into a single VoiceOver element
|
|
73
73
|
- Disabled items communicate their state to assistive technologies
|
|
74
|
+
- The backdrop still closes the menu on press, but is hidden from assistive tech (`accessible={false}`, `importantForAccessibility="no"`) so it doesn't duplicate the sheet's own close control
|
|
75
|
+
- "Done" is the accessible close control; VoiceOver's escape gesture (`onAccessibilityEscape`) also closes the menu
|
|
74
76
|
- Android back button closes the menu
|