Skip to content

Commit 3d406f4

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

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+696
-119
lines changed

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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 16 additions & 2 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 39 additions & 2 deletions
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

Lines changed: 8 additions & 1 deletion
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

Lines changed: 10 additions & 2 deletions
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

Lines changed: 9 additions & 2 deletions
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

Lines changed: 17 additions & 1 deletion
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

Lines changed: 10 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 35 additions & 19 deletions
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)