mirror of
https://github.com/wagtail/wagtail.git
synced 2024-11-25 05:02:57 +01:00
Ensure the Icon react component can support custom icon paths #11122
- When provided with children (e.g. custom paths), render these instead of the `use` symbol reference - Allow any valid SVG attribute to be passed to the component to render on the `svg` element - Clean up rendering of className to avoid extra whitespace - Clean up ordering of the props to be alphabetically sorted - Update unit tests to be focused more on testing and less on snapshots
This commit is contained in:
parent
d2f476c050
commit
c611dd4056
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow, mount } from 'enzyme';
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
|
|
||||||
describe('Icon', () => {
|
describe('Icon', () => {
|
||||||
@ -7,15 +7,53 @@ describe('Icon', () => {
|
|||||||
expect(Icon).toBeDefined();
|
expect(Icon).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('#name', () => {
|
it('should support icons with a name', () => {
|
||||||
expect(shallow(<Icon name="test" />)).toMatchSnapshot();
|
const wrapper = mount(<Icon name="test" />);
|
||||||
|
|
||||||
|
expect(wrapper.find('.icon.icon-test')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('use[href="#icon-test"]')).toHaveLength(1);
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('#className', () => {
|
it('should support children in place of the icon use#name', () => {
|
||||||
expect(shallow(<Icon name="test" className="u-test" />)).toMatchSnapshot();
|
const wrapper = shallow(
|
||||||
|
<icon name="example">
|
||||||
|
<rect
|
||||||
|
x="10"
|
||||||
|
y="10"
|
||||||
|
width="30"
|
||||||
|
height="30"
|
||||||
|
stroke="black"
|
||||||
|
fill="transparent"
|
||||||
|
strokeWidth="5"
|
||||||
|
/>
|
||||||
|
</icon>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper.find('use')).toHaveLength(0);
|
||||||
|
expect(wrapper.find('rect')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('#title', () => {
|
it('should support a className prop', () => {
|
||||||
expect(shallow(<Icon name="test" title="Test title" />)).toMatchSnapshot();
|
const wrapper = mount(<Icon name="test" className="u-test" />);
|
||||||
|
|
||||||
|
expect(wrapper.find('.icon.u-test')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support other svg attributes', () => {
|
||||||
|
const wrapper = mount(<Icon name="test" viewBox="0 0 1024 1024" />);
|
||||||
|
|
||||||
|
expect(wrapper.find('svg').prop('viewBox')).toBe('0 0 1024 1024');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support a title that is output as a sibling of the title', () => {
|
||||||
|
const wrapper = mount(<Icon name="test" title="Test title" />);
|
||||||
|
|
||||||
|
const title = wrapper.find('svg.icon ~ span');
|
||||||
|
expect(title).toHaveLength(1);
|
||||||
|
|
||||||
|
expect(title.text()).toBe('Test title');
|
||||||
|
expect(title.hasClass('w-sr-only')).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
export interface IconProps {
|
export interface IconProps extends React.SVGProps<SVGSVGElement> {
|
||||||
name: string;
|
/** Optional svg `path` instead of the `use` based on the icon name. */
|
||||||
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
name: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,13 +12,21 @@ export interface IconProps {
|
|||||||
* Provide a `title` as an accessible label intended for screen readers.
|
* Provide a `title` as an accessible label intended for screen readers.
|
||||||
*/
|
*/
|
||||||
const Icon: React.FunctionComponent<IconProps> = ({
|
const Icon: React.FunctionComponent<IconProps> = ({
|
||||||
name,
|
children,
|
||||||
className,
|
className,
|
||||||
|
name,
|
||||||
title,
|
title,
|
||||||
|
...props
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
<svg className={`icon icon-${name} ${className || ''}`} aria-hidden="true">
|
<svg
|
||||||
<use href={`#icon-${name}`} />
|
{...props}
|
||||||
|
className={['icon', `icon-${name}`, className || '']
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' ')}
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
{children || <use href={`#icon-${name}`} />}
|
||||||
</svg>
|
</svg>
|
||||||
{title && <span className="w-sr-only">{title}</span>}
|
{title && <span className="w-sr-only">{title}</span>}
|
||||||
</>
|
</>
|
||||||
|
@ -1,45 +1,16 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Icon #className 1`] = `
|
exports[`Icon should support icons with a name 1`] = `
|
||||||
<Fragment>
|
<Icon
|
||||||
|
name="test"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="icon icon-test u-test"
|
className="icon icon-test"
|
||||||
>
|
>
|
||||||
<use
|
<use
|
||||||
href="#icon-test"
|
href="#icon-test"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</Fragment>
|
</Icon>
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Icon #name 1`] = `
|
|
||||||
<Fragment>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
className="icon icon-test "
|
|
||||||
>
|
|
||||||
<use
|
|
||||||
href="#icon-test"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</Fragment>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Icon #title 1`] = `
|
|
||||||
<Fragment>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
className="icon icon-test "
|
|
||||||
>
|
|
||||||
<use
|
|
||||||
href="#icon-test"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span
|
|
||||||
className="w-sr-only"
|
|
||||||
>
|
|
||||||
Test title
|
|
||||||
</span>
|
|
||||||
</Fragment>
|
|
||||||
`;
|
`;
|
||||||
|
@ -51,7 +51,7 @@ exports[`telepath: wagtail.blocks.FieldBlock with comments enabled it renders co
|
|||||||
<div class="w-field__help" id="the-prefix-helptext" data-field-help=""><p class="help">drink <em>more</em> water</p></div>
|
<div class="w-field__help" id="the-prefix-helptext" data-field-help=""><p class="help">drink <em>more</em> water</p></div>
|
||||||
<div class="w-field__input" data-field-input="">
|
<div class="w-field__input" data-field-input="">
|
||||||
<p name="the-prefix" id="the-prefix">The widget</p>
|
<p name="the-prefix" id="the-prefix">The widget</p>
|
||||||
<button type="button" aria-label="Add Comment" data-comment-add="" class="w-field__comment-button w-field__comment-button--add"><svg class="icon icon-comment-add " aria-hidden="true"><use href="#icon-comment-add"></use></svg><svg class="icon icon-comment-add-reversed " aria-hidden="true"><use href="#icon-comment-add-reversed"></use></svg></button></div>
|
<button type="button" aria-label="Add Comment" data-comment-add="" class="w-field__comment-button w-field__comment-button--add"><svg class="icon icon-comment-add" aria-hidden="true"><use href="#icon-comment-add"></use></svg><svg class="icon icon-comment-add-reversed" aria-hidden="true"><use href="#icon-comment-add-reversed"></use></svg></button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>"
|
</div>"
|
||||||
`;
|
`;
|
||||||
|
@ -711,7 +711,7 @@ exports[`telepath: wagtail.blocks.StreamBlock it renders menus on opening 1`] =
|
|||||||
<button type="button" title="Insert a block" class="c-sf-add-button" aria-expanded="true">
|
<button type="button" title="Insert a block" class="c-sf-add-button" aria-expanded="true">
|
||||||
<svg class="icon icon-plus" aria-hidden="true"><use href="#icon-plus"></use></svg>
|
<svg class="icon icon-plus" aria-hidden="true"><use href="#icon-plus"></use></svg>
|
||||||
</button>
|
</button>
|
||||||
<div data-tippy-root="" id="tippy-5" style="z-index: 9999; visibility: visible; transition: none; position: absolute; left: 0px; top: 0px; margin: 0px;"><div class="tippy-box" data-state="hidden" tabindex="-1" data-theme="dropdown" data-animation="fade" style="max-width: 350px; transition-duration: 0ms;" role="tooltip"><div class="tippy-content" data-state="hidden" style="transition-duration: 0ms;"><div><div class="w-combobox"><label id="downshift-0-label" for="downshift-0-input" class="w-sr-only">Search options…</label><div class="w-combobox__field"><input aria-activedescendant="" aria-autocomplete="list" aria-controls="downshift-0-menu" aria-expanded="false" aria-labelledby="downshift-0-label" autocomplete="off" id="downshift-0-input" role="combobox" type="text" placeholder="Search options…" value=""></div><div id="downshift-0-menu" role="listbox" aria-labelledby="downshift-0-label" class="w-combobox__menu"><div class="w-combobox__optgroup"><div role="option" aria-selected="false" id="downshift-0-item-0" class="w-combobox__option w-combobox__option--col1"><div class="w-combobox__option-icon"><svg class="icon icon-placeholder " aria-hidden="true"><use href="#icon-placeholder"></use></svg></div><div class="w-combobox__option-text">Test Block A</div></div><div role="option" aria-selected="false" id="downshift-0-item-1" class="w-combobox__option w-combobox__option--col2"><div class="w-combobox__option-icon"><svg class="icon icon-pilcrow " aria-hidden="true"><use href="#icon-pilcrow"></use></svg></div><div class="w-combobox__option-text">Test Block B</div></div></div></div></div></div></div></div></div></div><div data-contentpath="2">
|
<div data-tippy-root="" id="tippy-5" style="z-index: 9999; visibility: visible; transition: none; position: absolute; left: 0px; top: 0px; margin: 0px;"><div class="tippy-box" data-state="hidden" tabindex="-1" data-theme="dropdown" data-animation="fade" style="max-width: 350px; transition-duration: 0ms;" role="tooltip"><div class="tippy-content" data-state="hidden" style="transition-duration: 0ms;"><div><div class="w-combobox"><label id="downshift-0-label" for="downshift-0-input" class="w-sr-only">Search options…</label><div class="w-combobox__field"><input aria-activedescendant="" aria-autocomplete="list" aria-controls="downshift-0-menu" aria-expanded="false" aria-labelledby="downshift-0-label" autocomplete="off" id="downshift-0-input" role="combobox" type="text" placeholder="Search options…" value=""></div><div id="downshift-0-menu" role="listbox" aria-labelledby="downshift-0-label" class="w-combobox__menu"><div class="w-combobox__optgroup"><div role="option" aria-selected="false" id="downshift-0-item-0" class="w-combobox__option w-combobox__option--col1"><div class="w-combobox__option-icon"><svg class="icon icon-placeholder" aria-hidden="true"><use href="#icon-placeholder"></use></svg></div><div class="w-combobox__option-text">Test Block A</div></div><div role="option" aria-selected="false" id="downshift-0-item-1" class="w-combobox__option w-combobox__option--col2"><div class="w-combobox__option-icon"><svg class="icon icon-pilcrow" aria-hidden="true"><use href="#icon-pilcrow"></use></svg></div><div class="w-combobox__option-text">Test Block B</div></div></div></div></div></div></div></div></div></div><div data-contentpath="2">
|
||||||
<input type="hidden" name="the-prefix-1-deleted" value="">
|
<input type="hidden" name="the-prefix-1-deleted" value="">
|
||||||
<input type="hidden" name="the-prefix-1-order" value="1">
|
<input type="hidden" name="the-prefix-1-order" value="1">
|
||||||
<input type="hidden" name="the-prefix-1-type" value="test_block_b">
|
<input type="hidden" name="the-prefix-1-type" value="test_block_b">
|
||||||
@ -922,7 +922,7 @@ exports[`telepath: wagtail.blocks.StreamBlock setError renders error messages 1`
|
|||||||
</div>"
|
</div>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`telepath: wagtail.blocks.StreamBlock with labels that need escaping it renders correctly 1`] = `"<div class="w-combobox__optgroup"><div role="option" aria-selected="false" id="downshift-2-item-0" class="w-combobox__option w-combobox__option--col1"><div class="w-combobox__option-icon"><svg class="icon icon-placeholder " aria-hidden="true"><use href="#icon-placeholder"></use></svg></div><div class="w-combobox__option-text">Test Block <A></div></div><div role="option" aria-selected="false" id="downshift-2-item-1" class="w-combobox__option w-combobox__option--col2"><div class="w-combobox__option-icon"><svg class="icon icon-pilcrow " aria-hidden="true"><use href="#icon-pilcrow"></use></svg></div><div class="w-combobox__option-text">Test Block <B></div></div></div>"`;
|
exports[`telepath: wagtail.blocks.StreamBlock with labels that need escaping it renders correctly 1`] = `"<div class="w-combobox__optgroup"><div role="option" aria-selected="false" id="downshift-2-item-0" class="w-combobox__option w-combobox__option--col1"><div class="w-combobox__option-icon"><svg class="icon icon-placeholder" aria-hidden="true"><use href="#icon-placeholder"></use></svg></div><div class="w-combobox__option-text">Test Block <A></div></div><div role="option" aria-selected="false" id="downshift-2-item-1" class="w-combobox__option w-combobox__option--col2"><div class="w-combobox__option-icon"><svg class="icon icon-pilcrow" aria-hidden="true"><use href="#icon-pilcrow"></use></svg></div><div class="w-combobox__option-text">Test Block <B></div></div></div>"`;
|
||||||
|
|
||||||
exports[`telepath: wagtail.blocks.StreamBlock with unique block type it can add block 1`] = `
|
exports[`telepath: wagtail.blocks.StreamBlock with unique block type it can add block 1`] = `
|
||||||
"<div class="c-sf-help">
|
"<div class="c-sf-help">
|
||||||
|
Loading…
Reference in New Issue
Block a user