Skip to content

Commit

Permalink
feat(image-native): add accessibility
Browse files Browse the repository at this point in the history
  • Loading branch information
UrazAkgultan committed Oct 5, 2023
1 parent fce59a1 commit ffa7ccd
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 22 deletions.
2 changes: 1 addition & 1 deletion packages/jsActions/mobile-resources-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@
"rimraf": "^2.7.1",
"rollup": "^2.68.0"
}
}
}
2 changes: 1 addition & 1 deletion packages/pluggableWidgets/column-chart-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@
"detox": "^19.7.1",
"eslint": "^7.20.0"
}
}
}
4 changes: 4 additions & 0 deletions packages/pluggableWidgets/image-native/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- Added accessibility.

## [1.0.2] - 2022-9-20

### Changed
Expand Down
2 changes: 1 addition & 1 deletion packages/pluggableWidgets/image-native/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "image-native",
"widgetName": "Image",
"version": "1.0.2",
"version": "1.1.0",
"description": "Display an image and enlarge it on click",
"copyright": "© Mendix Technology BV 2022. All rights reserved.",
"license": "Apache-2.0",
Expand Down
12 changes: 12 additions & 0 deletions packages/pluggableWidgets/image-native/src/Image.editorConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ export function getProperties(values: ImagePreviewProps, defaultProperties: Prop
hidePropertyIn(defaultProperties, values, "customHeight");
}

if (values.accessible === "no") {
hidePropertyIn(defaultProperties, values, "screenReaderCaption");
hidePropertyIn(defaultProperties, values, "screenReaderHint");
}

return defaultProperties;
}

Expand Down Expand Up @@ -98,6 +103,13 @@ export function getPreview(values: ImagePreviewProps, isDarkMode: boolean): Stru
export function check(values: ImagePreviewProps): Problem[] {
const errors: Problem[] = [];

if (!values.isBackgroundImage && values.accessible === "yes" && !values.screenReaderCaption) {
errors.push({
property: "screenReaderCaption",
message: "Screen reader caption cannot be empty."
});
}

if (values.datasource === "image" && !values.imageObject) {
errors.push({
property: "imageObject",
Expand Down
6 changes: 6 additions & 0 deletions packages/pluggableWidgets/image-native/src/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export const Image: FunctionComponent<ImageProps<Style>> = props => {
return !props.isBackgroundImage ? (
<ImageViewer
name={props.name}
accessible={props.accessible === "yes"}
screenReaderCaption={props.screenReaderCaption}
screenReaderHint={props.screenReaderHint}
source={source}
onClick={onClick}
onClickType={props.onClickType}
Expand All @@ -65,6 +68,9 @@ export const Image: FunctionComponent<ImageProps<Style>> = props => {
) : (
<BackgroundImage
name={props.name}
accessible={props.accessible === "yes"}
screenReaderCaption={props.screenReaderCaption}
screenReaderHint={props.screenReaderHint}
source={source}
initialDimensions={initialDimensions}
resizeMode={props.resizeMode}
Expand Down
40 changes: 29 additions & 11 deletions packages/pluggableWidgets/image-native/src/Image.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<propertyGroup caption="Data source">
<property key="datasource" type="enumeration" defaultValue="image">
<caption>Data source</caption>
<description/>
<description />
<enumerationValues>
<enumerationValue key="image">Image</enumerationValue>
<enumerationValue key="imageUrl">Image URL</enumerationValue>
Expand All @@ -18,11 +18,11 @@
</property>
<property key="imageObject" type="image" required="false">
<caption>Image</caption>
<description/>
<description />
</property>
<property key="defaultImageDynamic" type="image" required="false">
<caption>Default image</caption>
<description/>
<description />
</property>
<property key="imageUrl" type="textTemplate" required="false">
<caption>Image URL</caption>
Expand Down Expand Up @@ -52,13 +52,13 @@
</property>
<property key="opacity" type="integer" defaultValue="100">
<caption>Opacity</caption>
<description/>
<description />
</property>
</propertyGroup>
<propertyGroup caption="Dimensions">
<property key="widthUnit" type="enumeration" defaultValue="auto">
<caption>Width unit</caption>
<description/>
<description />
<enumerationValues>
<enumerationValue key="auto">Auto</enumerationValue>
<enumerationValue key="points">Points</enumerationValue>
Expand All @@ -70,7 +70,7 @@
</property>
<property key="heightUnit" type="enumeration" defaultValue="auto">
<caption>Height unit</caption>
<description/>
<description />
<enumerationValues>
<enumerationValue key="auto">Auto</enumerationValue>
<enumerationValue key="points">Points</enumerationValue>
Expand All @@ -82,27 +82,45 @@
</property>
<property key="iconSize" type="integer" defaultValue="16">
<caption>Size</caption>
<description/>
<description />
</property>
</propertyGroup>
<propertyGroup caption="Accessibilty">
<property key="accessible" type="enumeration" defaultValue="no">
<caption>Accessible</caption>
<description />
<enumerationValues>
<enumerationValue key="yes">Yes</enumerationValue>
<enumerationValue key="no">No</enumerationValue>
</enumerationValues>
</property>
<property key="screenReaderCaption" type="textTemplate" required="false">
<caption>Screen reader caption</caption>
<description />
</property>
<property key="screenReaderHint" type="textTemplate" required="false">
<caption>Screen reader hint</caption>
<description />
</property>
</propertyGroup>
</propertyGroup>
<propertyGroup caption="Events">
<property key="onClickType" type="enumeration" defaultValue="action">
<caption>On click type</caption>
<description/>
<description />
<enumerationValues>
<enumerationValue key="action">Action</enumerationValue>
<enumerationValue key="enlarge">Enlarge</enumerationValue>
</enumerationValues>
</property>
<property key="onClick" type="action" required="false">
<caption>On click</caption>
<description/>
<description />
</property>
</propertyGroup>
<propertyGroup caption="Common">
<systemProperty key="Name"/>
<systemProperty key="Visibility"/>
<systemProperty key="Name" />
<systemProperty key="Visibility" />
</propertyGroup>
</properties>
</widget>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ResizeModeEnum } from "../../typings/ImageProps";
import { CustomImageObjectProps, onLayoutSetDimensions } from "../utils/imageUtils";
import { DimensionsType, ImageIconSVG } from "./ImageIconSVG";
import { DefaultImageStyle } from "../ui/Styles.js";
import { DynamicValue } from "mendix";

export interface BackgroundImageProps {
name?: string;
Expand All @@ -14,6 +15,9 @@ export interface BackgroundImageProps {
resizeMode: ResizeModeEnum;
opacity: number;
styles: DefaultImageStyle;
accessible: boolean;
screenReaderCaption?: DynamicValue<string>;
screenReaderHint?: DynamicValue<string>;
}

export const BackgroundImage: FunctionComponent<BackgroundImageProps> = props => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ import { OnClickTypeEnum } from "../../typings/ImageProps";
import { CustomImageObjectProps, onLayoutSetDimensions } from "../utils/imageUtils";
import { DimensionsType, ImageIconSVG } from "./ImageIconSVG";
import { DefaultImageStyle } from "../ui/Styles.js";
import { DynamicValue } from "mendix";

interface ImageViewerBaseProps {
interface AccessibilityProps {
accessible: boolean;
screenReaderCaption?: DynamicValue<string>;
screenReaderHint?: DynamicValue<string>;
}

interface ImageViewerBaseProps extends AccessibilityProps {
name?: string;
source: CustomImageObjectProps;
customWidth?: number;
Expand Down Expand Up @@ -38,6 +45,9 @@ interface GetImageDimensionsComponentProps extends ImageViewerBaseProps {
export const ImageViewer: FunctionComponent<ImageViewerProps> = props => {
const [enlarged, setEnlarged] = useState(false);
const {
accessible,
screenReaderCaption,
screenReaderHint,
source,
initialDimensions,
setInitialDimensions,
Expand All @@ -54,6 +64,9 @@ export const ImageViewer: FunctionComponent<ImageViewerProps> = props => {
<Fragment>
<ImageSmall
name={name}
accessible={accessible}
screenReaderCaption={screenReaderCaption}
screenReaderHint={screenReaderHint}
source={source}
customWidth={customWidth}
customHeight={customHeight}
Expand All @@ -64,12 +77,18 @@ export const ImageViewer: FunctionComponent<ImageViewerProps> = props => {
/>
<GetImageDimensionsComponent
name={name}
accessible={accessible}
screenReaderCaption={screenReaderCaption}
screenReaderHint={screenReaderHint}
source={source}
initialDimensions={initialDimensions}
setInitialDimensions={setInitialDimensions}
/>
<ImageEnlarged
name={name}
accessible={accessible}
screenReaderCaption={screenReaderCaption}
screenReaderHint={screenReaderHint}
visible={enlarged}
setEnlarged={setEnlarged}
source={source}
Expand All @@ -81,7 +100,8 @@ export const ImageViewer: FunctionComponent<ImageViewerProps> = props => {
};

export const GetImageDimensionsComponent: FunctionComponent<GetImageDimensionsComponentProps> = props => {
const { source, initialDimensions, setInitialDimensions, name } = props;
const { source, initialDimensions, setInitialDimensions, name, accessible, screenReaderCaption, screenReaderHint } =
props;

const onLayoutSetInitialDimensions = useCallback(
({ nativeEvent: { layout } }: LayoutChangeEvent) => {
Expand Down Expand Up @@ -113,6 +133,10 @@ export const GetImageDimensionsComponent: FunctionComponent<GetImageDimensionsCo
pointerEvents={source.image === "this/is/a/fake/path.svg" ? "auto" : "none"}
>
<SvgUri
accessible={accessible}
accessibilityLabel={screenReaderCaption?.value}
accessibilityHint={screenReaderHint?.value}
accessibilityRole="image"
testID={`${name}$SvgUriTemporary`}
uri={source.image as string}
onLayout={onLayoutSetInitialDimensions}
Expand All @@ -125,7 +149,19 @@ export const GetImageDimensionsComponent: FunctionComponent<GetImageDimensionsCo
};

export const ImageSmall: FunctionComponent<ImageSmallProps> = props => {
const { source, initialDimensions, customWidth, customHeight, iconSize, onClick, styles, name } = props;
const {
source,
initialDimensions,
customWidth,
customHeight,
iconSize,
onClick,
styles,
name,
accessible,
screenReaderCaption,
screenReaderHint
} = props;
const [dimensions, setDimensions] = useState<DimensionsType>();
const [svgProps] = extractStyles(styles.image as ImageStyle, ["width", "height"]);
const dimensionsNotSet =
Expand All @@ -145,6 +181,10 @@ export const ImageSmall: FunctionComponent<ImageSmallProps> = props => {

return source.type === "icon" || (initialDimensions?.width && initialDimensions?.height) ? (
<Pressable
accessible={accessible}
accessibilityLabel={screenReaderCaption?.value}
accessibilityHint={screenReaderHint?.value}
accessibilityRole="image"
testID={`${name}$ImageSmallPressable`}
onPress={onClick}
onLayout={dimensionsNotSet ? onLayoutSetDimensionsCallback : undefined}
Expand All @@ -170,7 +210,17 @@ export const ImageSmall: FunctionComponent<ImageSmallProps> = props => {

export const ImageEnlarged: FunctionComponent<ImageEnlargedProps> = props => {
const [dimensions, setDimensions] = useState<DimensionsType>();
const { visible, setEnlarged, source, initialDimensions, styles, name } = props;
const {
visible,
setEnlarged,
source,
initialDimensions,
styles,
name,
accessible,
screenReaderCaption,
screenReaderHint
} = props;
const [svgProps] = extractStyles(styles.image as ImageStyle, ["width", "height"]);
const onLayoutSetDimensionsCallback = useCallback(
({ nativeEvent: { layout } }: LayoutChangeEvent) => {
Expand All @@ -181,6 +231,10 @@ export const ImageEnlarged: FunctionComponent<ImageEnlargedProps> = props => {

return visible && initialDimensions?.width && initialDimensions?.height ? (
<Modal
accessible={accessible}
accessibilityLabel={screenReaderCaption?.value}
accessibilityHint={screenReaderHint?.value}
accessibilityRole="image"
visible={visible}
onRequestClose={() => setEnlarged(false)}
onDismiss={() => setEnlarged(false)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe("Widget", () => {
beforeEach(() => {
imageProps = {
name: "Image1",
accessible: "yes",
style: [],
datasource: "image",
imageObject: dynamicValue<number>(1),
Expand Down
Loading

0 comments on commit ffa7ccd

Please sign in to comment.