[change] Remove createElement host type inference for 'href'

Elements other than 'a' support the 'href' attribute, so the element type
should not be inferred from 'href'. Longer term no host element type inference
should be performed by 'createElement'.

Fix #1958
This commit is contained in:
Nicolas Gallagher
2021-06-08 16:45:20 -07:00
parent 7775b3ab19
commit 6d7a1eaf0e
11 changed files with 67 additions and 41 deletions
@@ -106,9 +106,10 @@ exports[`components/Pressable prop "accessibilityLiveRegion" value is set 1`] =
`;
exports[`components/Pressable prop "accessibilityRole" value alters HTML element 1`] = `
<a
class="css-reset-4rbku5 css-cursor-18t94o4 css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
role="link"
<article
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
role="article"
tabindex="0"
/>
`;
@@ -136,6 +137,13 @@ exports[`components/Pressable prop "disabled" 1`] = `
/>
`;
exports[`components/Pressable prop "href" 1`] = `
<a
class="css-reset-4rbku5 css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
href="#href"
/>
`;
exports[`components/Pressable prop "nativeID" value is set 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
@@ -38,7 +38,7 @@ describe('components/Pressable', () => {
});
test('value alters HTML element', () => {
const { container } = render(<Pressable accessibilityRole="link" />);
const { container } = render(<Pressable accessibilityRole="article" />);
expect(container.firstChild).toMatchSnapshot();
});
});
@@ -48,6 +48,11 @@ describe('components/Pressable', () => {
expect(container.firstChild).toMatchSnapshot();
});
test('prop "href"', () => {
const { container } = render(<Pressable href="#href" />);
expect(container.firstChild).toMatchSnapshot();
});
describe('prop "nativeID"', () => {
test('value is set', () => {
const { container } = render(<Pressable nativeID="nativeID" />);
@@ -51,10 +51,10 @@ exports[`components/Text prop "accessibilityLiveRegion" value is set 1`] = `
`;
exports[`components/Text prop "accessibilityRole" value alters HTML element 1`] = `
<a
class="css-reset-4rbku5 css-cursor-18t94o4 css-text-901oao"
<article
class="css-text-901oao"
dir="auto"
role="link"
role="article"
/>
`;
@@ -51,7 +51,7 @@ describe('components/Text', () => {
});
test('value alters HTML element', () => {
const { container } = render(<Text accessibilityRole="link" />);
const { container } = render(<Text accessibilityRole="article" />);
expect(container.firstChild).toMatchSnapshot();
});
});
+14 -11
View File
@@ -114,7 +114,7 @@ const Text: React.AbstractComponent<TextProps, HTMLElement & PlatformMethods> =
}
}
const component = hasTextAncestor ? 'span' : 'div';
let component = hasTextAncestor ? 'span' : 'div';
const supportedProps = pickProps(props);
supportedProps.classList = classList;
supportedProps.dir = dir;
@@ -124,16 +124,19 @@ const Text: React.AbstractComponent<TextProps, HTMLElement & PlatformMethods> =
}
supportedProps.onClick = handleClick;
supportedProps.style = style;
if (props.href != null && hrefAttrs != null) {
const { download, rel, target } = hrefAttrs;
if (download != null) {
supportedProps.download = download;
}
if (rel != null) {
supportedProps.rel = rel;
}
if (typeof target === 'string') {
supportedProps.target = target.charAt(0) !== '_' ? '_' + target : target;
if (props.href != null) {
component = 'a';
if (hrefAttrs != null) {
const { download, rel, target } = hrefAttrs;
if (download != null) {
supportedProps.download = download;
}
if (rel != null) {
supportedProps.rel = rel;
}
if (typeof target === 'string') {
supportedProps.target = target.charAt(0) !== '_' ? '_' + target : target;
}
}
}
@@ -46,9 +46,9 @@ exports[`components/View prop "accessibilityLiveRegion" value is set 1`] = `
`;
exports[`components/View prop "accessibilityRole" value alters HTML element 1`] = `
<a
class="css-reset-4rbku5 css-cursor-18t94o4 css-view-1dbjc4n"
role="link"
<article
class="css-view-1dbjc4n"
role="article"
/>
`;
@@ -79,7 +79,7 @@ describe('components/View', () => {
});
test('value alters HTML element', () => {
const { container } = render(<View accessibilityRole="link" />);
const { container } = render(<View accessibilityRole="article" />);
expect(container.firstChild).toMatchSnapshot();
});
});
+15 -11
View File
@@ -97,21 +97,25 @@ const View: React.AbstractComponent<ViewProps, HTMLElement & PlatformMethods> =
onStartShouldSetResponderCapture
});
let component = 'div';
const style = StyleSheet.compose(hasTextAncestor && styles.inline, props.style);
const supportedProps = pickProps(props);
supportedProps.classList = classList;
supportedProps.style = style;
if (props.href != null && hrefAttrs != null) {
const { download, rel, target } = hrefAttrs;
if (download != null) {
supportedProps.download = download;
}
if (rel != null) {
supportedProps.rel = rel;
}
if (typeof target === 'string') {
supportedProps.target = target.charAt(0) !== '_' ? '_' + target : target;
if (props.href != null) {
component = 'a';
if (hrefAttrs != null) {
const { download, rel, target } = hrefAttrs;
if (download != null) {
supportedProps.download = download;
}
if (rel != null) {
supportedProps.rel = rel;
}
if (typeof target === 'string') {
supportedProps.target = target.charAt(0) !== '_' ? '_' + target : target;
}
}
}
@@ -120,7 +124,7 @@ const View: React.AbstractComponent<ViewProps, HTMLElement & PlatformMethods> =
supportedProps.ref = setRef;
return createElement('div', supportedProps);
return createElement(component, supportedProps);
}
);
@@ -3,3 +3,11 @@
exports[`exports/createElement renders different DOM elements 1`] = `<span />`;
exports[`exports/createElement renders different DOM elements 2`] = `<main />`;
exports[`exports/createElement renders different DOM elements 3`] = `
<svg>
<image
href="#href"
/>
</svg>
`;
@@ -18,12 +18,16 @@ describe('exports/createElement', () => {
expect(container.firstChild).toMatchSnapshot();
({ container } = render(createElement('main')));
expect(container.firstChild).toMatchSnapshot();
({ container } = render(
createElement('svg', { children: createElement('image', { href: '#href' }) })
));
expect(container.firstChild).toMatchSnapshot();
});
describe('prop "accessibilityRole"', () => {
test('string component type', () => {
const { container } = render(createElement('span', { accessibilityRole: 'link' }));
expect(container.firstChild.nodeName).toBe('A');
expect(container.firstChild.nodeName).toBe('SPAN');
});
test('function component type', () => {
@@ -21,7 +21,6 @@ const roleComponents = {
figure: 'figure',
insertion: 'ins',
form: 'form',
link: 'a',
list: 'ul',
listitem: 'li',
main: 'main',
@@ -38,11 +37,6 @@ const propsToAccessibilityComponent = (props: Object = emptyObject): void | stri
return 'label';
}
// special-case for "href" which becomes a link
if (props.href != null) {
return 'a';
}
const role = propsToAriaRole(props);
if (role) {
if (role === 'heading') {