Skip to content

Commit

Permalink
Add otherProps util and DangerouslySetHTML component (#242)
Browse files Browse the repository at this point in the history
* Export component specifically for rendering html

* Export utility for passing props for higher order components
  • Loading branch information
bryceosterhaus authored and eduardolundgren committed May 31, 2017
1 parent d49b2cc commit d1f9b25
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 1 deletion.
32 changes: 32 additions & 0 deletions packages/metal-jsx/src/DangerouslySetHTML.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

import Component from './JSXComponent';
import { Config } from 'metal-state';

/**
* JSXComponent that renders html passed in.
* @class
*/
class DangerouslySetHTML extends Component {
/**
* @return {Component}
*/
render() {
const {content, tag} = this.props;

IncrementalDOM.elementOpen(tag, null, null);

const node = IncrementalDOM.elementClose(tag);

node.innerHTML = content;

return node;
}
}

DangerouslySetHTML.PROPS = {
content: Config.string(),
tag: Config.string().value('span'),
};

export default DangerouslySetHTML;
24 changes: 23 additions & 1 deletion packages/metal-jsx/src/JSXComponent.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';

import './iDOMHelpers';
import { object } from 'metal';
import { validators, Config } from 'metal-state';
import Component from 'metal-component';
import DangerouslySetHTML from './DangerouslySetHTML';
import IncrementalDomRenderer from 'metal-incremental-dom';
import JSXDataManager from './JSXDataManager';
import JSXRenderer from './JSXRenderer';
Expand Down Expand Up @@ -32,10 +34,30 @@ class JSXComponent extends Component {
static render(...args) {
return IncrementalDomRenderer.render(...args);
}

/**
* Returns props that are not used or declared in the component.
* @return {Object} Object containing props
*/
otherProps() {
const removeKeys = [...this.getDataManager().getPropsInstance(this).getStateKeys(), 'key', 'ref'];

const retObj = object.mixin({}, this.props);

for (let i = 0; i < removeKeys.length; i++) {
const key = removeKeys[i];

if (retObj.hasOwnProperty(key)) {
delete retObj[key];
}
}

return retObj;
}
}

JSXComponent.DATA_MANAGER = JSXDataManager;
JSXComponent.RENDERER = JSXRenderer;

export default JSXComponent;
export { validators, Config, JSXComponent };
export { DangerouslySetHTML, validators, Config, JSXComponent };
48 changes: 48 additions & 0 deletions packages/metal-jsx/test/DangerouslySetHTML.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';

import DangerouslySetHTML from '../src/DangerouslySetHTML';
import JSXComponent from '../src/JSXComponent';

describe('JSXComponent', function() {
var component;

afterEach(function() {
if (component) {
component.dispose();
}
});

it('should render', function() {
component = new DangerouslySetHTML();
assert.strictEqual('SPAN', component.element.tagName);
});

it('should render with custom tag', function() {
component = new DangerouslySetHTML({tag: 'div'});
assert.strictEqual('DIV', component.element.tagName);
});

it('should render with html content', function() {
var content = '<h2>hello</h2><div><span>world</span></div>';

component = new DangerouslySetHTML({content: content});
assert.strictEqual(content, component.element.innerHTML);
});

it('should render inside of another component', function() {
var content = '<h2>hello</h2><div><span>world</span></div>';

class TestComponent extends JSXComponent {
render() {
return (
<div>
<DangerouslySetHTML content={content} ref="inner" />
</div>
);
}
}

component = new TestComponent();
assert.strictEqual(content, component.refs.inner.element.innerHTML);
});
});
56 changes: 56 additions & 0 deletions packages/metal-jsx/test/JSXComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,4 +431,60 @@ describe('JSXComponent', function() {
});
});
});

describe('otherProps', function() {
var component;

afterEach(function() {
if (component) {
component.dispose();
}
});

it('should return object', function() {
class TestComponent extends JSXComponent {
render() {
return <div />;
}
}

component = new TestComponent();

assert.deepEqual(component.otherProps(), {});
});

it('should pass through unspecified props', function() {
class TestComponent extends JSXComponent {
render() {
return <div />;
}
}

TestComponent.PROPS = {
foo: {},
};

component = new TestComponent({baz: 'qux', foo: 'bar'});

assert.deepEqual(
component.otherProps(),
{baz: 'qux'}
);
});

it('should ignore key and ref', function() {
class TestComponent extends JSXComponent {
render() {
return <div />;
}
}

component = new TestComponent({key: 'bar', ref: 'qux'});

assert.deepEqual(
component.otherProps(),
{}
);
});
});
});

0 comments on commit d1f9b25

Please sign in to comment.