Skip to content

Commit 3109960

Browse files
committed
feat: add accessibility
1 parent 33c7541 commit 3109960

21 files changed

+404
-68
lines changed

packages/pluggableWidgets/accordion-native/src/Accordion.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<description />
6868
<returnType type="Boolean" />
6969
</property>
70-
<property key="accessible" type="enumeration" defaultValue="yes">
70+
<property key="accessible" type="enumeration" defaultValue="no">
7171
<caption>Accessible</caption>
7272
<description />
7373
<enumerationValues>

packages/pluggableWidgets/bottom-sheet-native/src/BottomSheet.editorConfig.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ export function getPreview(values: BottomSheetPreviewProps, isDarkMode: boolean)
8787
};
8888
}
8989

90-
export function getProperties(values: any, defaultProperties: Properties): Properties {
90+
export function getProperties(values: BottomSheetPreviewProps, defaultProperties: Properties): Properties {
9191
if (values.type === "modal") {
9292
if (values.modalRendering === "basic") {
93+
hidePropertyIn(defaultProperties, values, "accessible");
9394
hidePropertiesIn(defaultProperties, values, ["smallContent", "largeContent", "fullscreenContent"]);
9495
} else {
9596
hidePropertiesIn(defaultProperties, values, [
@@ -112,10 +113,23 @@ export function getProperties(values: any, defaultProperties: Properties): Prope
112113
hidePropertyIn(defaultProperties, values, "fullscreenContent");
113114
}
114115
}
116+
117+
if (values.accessible === "no" || (values.type === "modal" && values.modalRendering === "basic")) {
118+
hidePropertyIn(defaultProperties, values, "screenReaderCaption");
119+
hidePropertyIn(defaultProperties, values, "screenReaderHint");
120+
}
121+
122+
values.itemsBasic.forEach((item, index) => {
123+
if (item.modalAccessible === "no") {
124+
hidePropertyIn(defaultProperties, values, "itemsBasic", index, "modalScreenReaderCaption");
125+
hidePropertyIn(defaultProperties, values, "itemsBasic", index, "modalScreenReaderHint");
126+
}
127+
});
128+
115129
return defaultProperties;
116130
}
117131

118-
export function check(values: any): Problem[] {
132+
export function check(values: BottomSheetPreviewProps): Problem[] {
119133
const errors: Problem[] = [];
120134
if (values.type === "modal") {
121135
if (!values.triggerAttribute) {

packages/pluggableWidgets/bottom-sheet-native/src/BottomSheet.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export function BottomSheet(props: BottomSheetProps<BottomSheetStyle>): ReactEle
2929
if (props.type === "expanding") {
3030
return (
3131
<ExpandingDrawer
32+
accessible={props.accessible === "yes"}
33+
screenReaderCaption={props.screenReaderCaption}
34+
screenReaderHint={props.screenReaderHint}
3235
smallContent={props.smallContent}
3336
largeContent={props.largeContent}
3437
fullscreenContent={props.showFullscreenContent ? props.fullscreenContent : null}

packages/pluggableWidgets/bottom-sheet-native/src/BottomSheet.xml

+39-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<caption>Trigger attribute</caption>
2020
<description>Defines if the modal bottom sheet is visible or not. Initially this value should be false. When set to true, the bottom sheet will be shown. When the bottom sheet is hidden, the trigger attribute value is set to false.</description>
2121
<attributeTypes>
22-
<attributeType name="Boolean"/>
22+
<attributeType name="Boolean" />
2323
</attributeTypes>
2424
</property>
2525
<property key="modalRendering" type="enumeration" defaultValue="basic">
@@ -55,6 +55,25 @@
5555
<enumerationValue key="customStyle">Custom</enumerationValue>
5656
</enumerationValues>
5757
</property>
58+
<property key="modalAccessible" type="enumeration" defaultValue="yes">
59+
<caption>Accessible</caption>
60+
<category>General</category>
61+
<description />
62+
<enumerationValues>
63+
<enumerationValue key="yes">Yes</enumerationValue>
64+
<enumerationValue key="no">No</enumerationValue>
65+
</enumerationValues>
66+
</property>
67+
<property key="modalScreenReaderCaption" type="textTemplate" required="false">
68+
<caption>Screen reader caption</caption>
69+
<category>General</category>
70+
<description />
71+
</property>
72+
<property key="modalScreenReaderHint" type="textTemplate" required="false">
73+
<caption>Screen reader hint</caption>
74+
<category>General</category>
75+
<description />
76+
</property>
5877
</properties>
5978
</property>
6079
<property key="nativeImplementation" type="boolean" defaultValue="true">
@@ -87,9 +106,27 @@
87106
</property>
88107
</propertyGroup>
89108
<propertyGroup caption="Common">
90-
<systemProperty key="Name"/>
109+
<systemProperty key="Name" />
91110
<systemProperty key="Visibility" />
92111
</propertyGroup>
112+
<propertyGroup caption="Accessibilty">
113+
<property key="accessible" type="enumeration" defaultValue="no">
114+
<caption>Accessible</caption>
115+
<description />
116+
<enumerationValues>
117+
<enumerationValue key="yes">Yes</enumerationValue>
118+
<enumerationValue key="no">No</enumerationValue>
119+
</enumerationValues>
120+
</property>
121+
<property key="screenReaderCaption" type="textTemplate" required="false">
122+
<caption>Screen reader caption</caption>
123+
<description />
124+
</property>
125+
<property key="screenReaderHint" type="textTemplate" required="false">
126+
<caption>Screen reader hint</caption>
127+
<description />
128+
</property>
129+
</propertyGroup>
93130
</propertyGroup>
94131
</properties>
95132
</widget>

packages/pluggableWidgets/bottom-sheet-native/src/components/CustomModalSheet.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { createElement, ReactElement, ReactNode, useCallback, useEffect, useState } from "react";
22
import { InteractionManager, LayoutChangeEvent, SafeAreaView, StyleSheet, View } from "react-native";
33
import Modal, { OnSwipeCompleteParams } from "react-native-modal";
4-
import { EditableValue, ValueStatus } from "mendix";
4+
import { DynamicValue, EditableValue, ValueStatus } from "mendix";
55
import { BottomSheetStyle, defaultPaddings } from "../ui/Styles";
66

77
interface CustomModalSheetProps {
88
triggerAttribute?: EditableValue<boolean>;
99
content?: ReactNode;
1010
styles: BottomSheetStyle;
11+
accessible?: boolean;
12+
screenReaderCaption?: DynamicValue<string>;
13+
screenReaderHint?: DynamicValue<string>;
1114
}
1215

1316
export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement => {
@@ -62,6 +65,10 @@ export const CustomModalSheet = (props: CustomModalSheetProps): ReactElement =>
6265

6366
return (
6467
<Modal
68+
accessible={props.accessible}
69+
accessibilityLabel={props.screenReaderCaption?.value}
70+
accessibilityHint={props.screenReaderHint?.value}
71+
accessibilityState={{ expanded: height > 0 }}
6572
isVisible={currentStatus}
6673
coverScreen
6774
backdropOpacity={0.5}

packages/pluggableWidgets/bottom-sheet-native/src/components/ExpandingDrawer.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { BottomSheetStyle } from "../ui/Styles";
21
import { createElement, ReactNode, useCallback, useState, ReactElement, Children } from "react";
3-
import BottomSheet from "reanimated-bottom-sheet";
42
import { Dimensions, LayoutChangeEvent, SafeAreaView, StyleSheet, View } from "react-native";
3+
import BottomSheet from "reanimated-bottom-sheet";
4+
import { DynamicValue } from "mendix";
5+
import { BottomSheetStyle } from "../ui/Styles";
56

67
interface ExpandingDrawerProps {
78
smallContent?: ReactNode;
@@ -10,6 +11,9 @@ interface ExpandingDrawerProps {
1011
onOpen?: () => void;
1112
onClose?: () => void;
1213
styles: BottomSheetStyle;
14+
accessible?: boolean;
15+
screenReaderCaption?: DynamicValue<string>;
16+
screenReaderHint?: DynamicValue<string>;
1317
}
1418

1519
export const ExpandingDrawer = (props: ExpandingDrawerProps): ReactElement => {
@@ -56,6 +60,10 @@ export const ExpandingDrawer = (props: ExpandingDrawerProps): ReactElement => {
5660
pointerEvents="box-none"
5761
>
5862
<View
63+
accessible={props.accessible}
64+
accessibilityLabel={props.screenReaderCaption?.value}
65+
accessibilityHint={props.screenReaderHint?.value}
66+
accessibilityState={{ expanded: isOpen }}
5967
onLayout={onLayoutHandlerHeader}
6068
style={!isSmallContentValid ? { height: 20 } : {}}
6169
pointerEvents="box-none"

packages/pluggableWidgets/bottom-sheet-native/src/components/NativeBottomSheet.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { createElement, ReactElement, useCallback, useEffect, useRef, useState }
22
import ActionSheet, { ActionSheetCustom } from "react-native-actionsheet";
33
import { Platform, Text } from "react-native";
44
import { EditableValue, ValueStatus } from "mendix";
5+
import { executeAction } from "@mendix/piw-utils-internal";
56
import { ItemsBasicType } from "../../typings/BottomSheetProps";
67
import { ModalItemContainerStyle, BottomSheetStyle, defaultMargins } from "../ui/Styles";
7-
import { executeAction } from "@mendix/piw-utils-internal";
88

99
interface NativeBottomSheetProps {
1010
name: string;
@@ -47,7 +47,14 @@ export const NativeBottomSheet = (props: NativeBottomSheetProps): ReactElement =
4747

4848
if (Platform.OS === "android" || !props.useNative) {
4949
const options = props.itemsBasic.map((item, index) => (
50-
<Text key={`${props.name}_item_${index}`} style={props.styles.modalItems[item.styleClass]}>
50+
<Text
51+
accessible={item.modalAccessible === "yes"}
52+
accessibilityLabel={item.modalScreenReaderCaption?.value || item.caption}
53+
accessibilityHint={item.modalScreenReaderHint?.value}
54+
accessibilityRole="button"
55+
key={`${props.name}_item_${index}`}
56+
style={props.styles.modalItems[item.styleClass]}
57+
>
5158
{item.caption}
5259
</Text>
5360
));

packages/pluggableWidgets/bottom-sheet-native/typings/BottomSheetProps.d.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,34 @@
44
* @author Mendix UI Content Team
55
*/
66
import { ComponentType, CSSProperties, ReactNode } from "react";
7-
import { ActionValue, EditableValue } from "mendix";
7+
import { ActionValue, DynamicValue, EditableValue } from "mendix";
88

99
export type TypeEnum = "modal" | "expanding";
1010

1111
export type ModalRenderingEnum = "basic" | "custom";
1212

1313
export type StyleClassEnum = "defaultStyle" | "primaryStyle" | "dangerStyle" | "customStyle";
1414

15+
export type ModalAccessibleEnum = "yes" | "no";
16+
1517
export interface ItemsBasicType {
1618
caption: string;
1719
action?: ActionValue;
1820
styleClass: StyleClassEnum;
21+
modalAccessible: ModalAccessibleEnum;
22+
modalScreenReaderCaption?: DynamicValue<string>;
23+
modalScreenReaderHint?: DynamicValue<string>;
1924
}
2025

26+
export type AccessibleEnum = "yes" | "no";
27+
2128
export interface ItemsBasicPreviewType {
2229
caption: string;
2330
action: {} | null;
2431
styleClass: StyleClassEnum;
32+
modalAccessible: ModalAccessibleEnum;
33+
modalScreenReaderCaption: string;
34+
modalScreenReaderHint: string;
2535
}
2636

2737
export interface BottomSheetProps<Style> {
@@ -38,6 +48,9 @@ export interface BottomSheetProps<Style> {
3848
fullscreenContent?: ReactNode;
3949
onOpen?: ActionValue;
4050
onClose?: ActionValue;
51+
accessible: AccessibleEnum;
52+
screenReaderCaption?: DynamicValue<string>;
53+
screenReaderHint?: DynamicValue<string>;
4154
}
4255

4356
export interface BottomSheetPreviewProps {
@@ -56,4 +69,7 @@ export interface BottomSheetPreviewProps {
5669
fullscreenContent: { widgetCount: number; renderer: ComponentType<{ caption?: string }> };
5770
onOpen: {} | null;
5871
onClose: {} | null;
72+
accessible: AccessibleEnum;
73+
screenReaderCaption: string;
74+
screenReaderHint: string;
5975
}

packages/pluggableWidgets/carousel-native/src/Carousel.editorConfig.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { RowLayoutProps, StructurePreviewProps } from "@mendix/piw-utils-internal";
2+
import { hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools";
23

34
import paginationSVG from "./assets/pagination.svg";
45

@@ -56,3 +57,12 @@ export function getPreview(values: CarouselPreviewProps, isDarkMode: boolean): S
5657
]
5758
};
5859
}
60+
61+
export function getProperties(values: CarouselPreviewProps, defaultProperties: Properties): Properties {
62+
if (values.accessible === "no") {
63+
hidePropertyIn(defaultProperties, values, "screenReaderCaption");
64+
hidePropertyIn(defaultProperties, values, "screenReaderHint");
65+
}
66+
67+
return defaultProperties;
68+
}

packages/pluggableWidgets/carousel-native/src/Carousel.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ export const Carousel = (props: CarouselProps<CarouselStyle>): ReactElement => {
147147
<Fragment>
148148
<NativeCarousel
149149
testID={`${props.name}$carousel`}
150+
accessible={props.accessible === "yes"}
151+
accessibilityLabel={props.screenReaderCaption?.value}
152+
accessibilityHint={props.screenReaderHint?.value}
150153
activeSlideAlignment={props.activeSlideAlignment}
151154
layout="default"
152155
firstItem={0}

packages/pluggableWidgets/carousel-native/src/Carousel.xml

+35-19
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
<?xml version="1.0" encoding="utf-8" ?>
2-
<widget id="com.mendix.widget.native.carousel.Carousel" pluginWidget="true" needsEntityContext="true" offlineCapable="true"
3-
supportedPlatform="Native"
4-
xmlns="http://www.mendix.com/widget/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5-
xsi:schemaLocation="http://www.mendix.com/widget/1.0/ ../node_modules/mendix/custom_widget.xsd">
2+
<widget id="com.mendix.widget.native.carousel.Carousel" pluginWidget="true" needsEntityContext="true" offlineCapable="true" supportedPlatform="Native" xmlns="http://www.mendix.com/widget/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mendix.com/widget/1.0/ ../node_modules/mendix/custom_widget.xsd">
63
<name>Carousel</name>
7-
<description/>
4+
<description />
85
<studioProCategory>Display</studioProCategory>
96
<studioCategory>Display</studioCategory>
107
<properties>
118
<propertyGroup caption="General">
129
<propertyGroup caption="Data source">
1310
<property key="contentSource" type="datasource" isList="true">
1411
<caption>Source</caption>
15-
<description/>
12+
<description />
1613
</property>
1714
<property key="content" type="widgets" dataSource="contentSource">
1815
<caption>Content</caption>
19-
<description/>
16+
<description />
2017
</property>
2118
</propertyGroup>
2219
<propertyGroup caption="Display">
@@ -41,19 +38,38 @@
4138
</enumerationValues>
4239
</property>
4340
</propertyGroup>
44-
<!-- Library has a bug with loops-->
45-
<!-- https://github.com/archriss/react-native-snap-carousel/issues/653 - -->
46-
<!-- https://github.com/archriss/react-native-snap-carousel/issues/608-->
47-
<!-- Also not working properly with Mobx-->
48-
<!-- <propertyGroup caption="Behavior">-->
49-
<!-- <property key="loop" type="boolean" defaultValue="false">-->
50-
<!-- <caption>Loop</caption>-->
51-
<!-- <description>After the last item the carousel continues to the first item.</description>-->
52-
<!-- </property>-->
53-
<!-- </propertyGroup>-->
41+
<!-- Library has a bug with loops-->
42+
<!-- https://github.com/archriss/react-native-snap-carousel/issues/653 - -->
43+
<!-- https://github.com/archriss/react-native-snap-carousel/issues/608-->
44+
<!-- Also not working properly with Mobx-->
45+
<!-- <propertyGroup caption="Behavior">-->
46+
<!-- <property key="loop" type="boolean" defaultValue="false">-->
47+
<!-- <caption>Loop</caption>-->
48+
<!-- <description>After the last item the carousel continues to the first item.</description>-->
49+
<!-- </property>-->
50+
<!-- </propertyGroup>-->
5451
<propertyGroup caption="Common">
55-
<systemProperty key="Name"/>
56-
<systemProperty key="Visibility"/>
52+
<systemProperty key="Name" />
53+
<systemProperty key="Visibility" />
54+
</propertyGroup>
55+
56+
<propertyGroup caption="Accessibilty">
57+
<property key="accessible" type="enumeration" defaultValue="no">
58+
<caption>Accessible</caption>
59+
<description />
60+
<enumerationValues>
61+
<enumerationValue key="yes">Yes</enumerationValue>
62+
<enumerationValue key="no">No</enumerationValue>
63+
</enumerationValues>
64+
</property>
65+
<property key="screenReaderCaption" type="textTemplate" required="false">
66+
<caption>Screen reader caption</caption>
67+
<description />
68+
</property>
69+
<property key="screenReaderHint" type="textTemplate" required="false">
70+
<caption>Screen reader hint</caption>
71+
<description />
72+
</property>
5773
</propertyGroup>
5874
</propertyGroup>
5975
</properties>

0 commit comments

Comments
 (0)