Unverified Commit 87c31b3c authored by Robert Knight's avatar Robert Knight Committed by GitHub

Merge pull request #1038 from hypothesis/react-svg-icon

Convert `<svg-icon>` component to React
parents 5eaea90d e5728d69
'use strict';
/**
* The <svg-icon> component renders SVG icons using inline <svg> tags,
* enabling their appearance to be customized via CSS.
*
* This matches the way we do icons on the website, see
* https://github.com/hypothesis/h/pull/3675
*/
const { createElement } = require('preact');
const propTypes = require('prop-types');
// The list of supported icons
const icons = {
......@@ -14,21 +9,24 @@ const icons = {
cursor: require('../../images/icons/cursor.svg'),
};
// @ngInject
function SvgIconController($element) {
this.$onInit = () => {
if (!icons[this.name]) {
throw new Error('Unknown icon: ' + this.name);
}
$element[0].innerHTML = icons[this.name];
};
/**
* Component that renders icons using inline `<svg>` elements.
* This enables their appearance to be customized via CSS.
*
* This matches the way we do icons on the website, see
* https://github.com/hypothesis/h/pull/3675
*/
function SvgIcon({ name }) {
if (!icons[name]) {
throw new Error(`Unknown icon ${name}`);
}
const markup = { __html: icons[name] };
return <span dangerouslySetInnerHTML={markup} />;
}
module.exports = {
controllerAs: 'vm',
controller: SvgIconController,
bindings: {
/** The name of the icon to load. */
name: '<',
},
SvgIcon.propTypes = {
/** The name of the icon to load. */
name: propTypes.string,
};
module.exports = SvgIcon;
'use strict';
const angular = require('angular');
const { createElement, render } = require('preact');
const util = require('../../directive/test/util');
const SvgIcon = require('../svg-icon');
describe('svgIcon', function() {
before(function() {
angular.module('app', []).component('svgIcon', require('../svg-icon'));
});
beforeEach(function() {
angular.mock.module('app');
});
describe('SvgIcon', () => {
// Tests here use DOM APIs rather than Enzyme because SvgIcon uses
// `dangerouslySetInnerHTML` for its content, and that is not visible in the
// Enzyme tree.
it("sets the element's content to the content of the SVG", function() {
const el = util.createDirective(document, 'svgIcon', { name: 'refresh' });
assert.ok(el[0].querySelector('svg'));
it("sets the element's content to the content of the SVG", () => {
const container = document.createElement('div');
render(<SvgIcon name="refresh" />, container);
assert.ok(container.querySelector('svg'));
});
it('throws an error if the icon is unknown', function() {
assert.throws(function() {
util.createDirective(document, 'svgIcon', { name: 'unknown' });
it('throws an error if the icon is unknown', () => {
assert.throws(() => {
const container = document.createElement('div');
render(<SvgIcon name="unknown" />, container);
});
});
});
......@@ -185,7 +185,7 @@ function startAngularApp(config) {
.component('sortDropdown', require('./components/sort-dropdown'))
.component('spinner', require('./components/spinner'))
.component('streamContent', require('./components/stream-content'))
.component('svgIcon', require('./components/svg-icon'))
.component('svgIcon', wrapReactComponent(require('./components/svg-icon')))
.component('tagEditor', require('./components/tag-editor'))
.component('threadList', require('./components/thread-list'))
.component('timestamp', require('./components/timestamp'))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment