diff --git a/package.json b/package.json index 77d9323..9fadf81 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,6 @@ "compile": "npm run compile-cjs && npm run compile-es6", "compile-cjs": "tsc --module commonjs --outDir ./lib/cjs", "compile-es6": "echo 'TODO' : tsc --module es6 --outDir ./lib/es6", - "test": "$(npm bin)/mocha test/*.ts --require ts-node/register --recursive" + "test": "$(npm bin)/mocha test/*.ts test/*.tsx --require ts-node/register --recursive" } } diff --git a/src/index.ts b/src/index.ts index 7c0473e..2e33bf7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,3 +5,4 @@ export {ReactSource} from './ReactSource'; export {h} from './h'; export {incorporate} from './incorporate'; export {StreamRenderer} from './StreamRenderer'; +export {default as jsxFactory} from './jsxFactory'; diff --git a/src/jsxFactory.ts b/src/jsxFactory.ts new file mode 100644 index 0000000..0cd12f1 --- /dev/null +++ b/src/jsxFactory.ts @@ -0,0 +1,36 @@ +import {createElement, ReactElement, ReactType} from 'react'; +import {incorporate} from './incorporate'; +export {Attributes} from 'react'; + +declare global { + namespace JSX { + interface IntrinsicAttributes { + sel?: string | symbol; + } + } + namespace React { + interface ClassAttributes extends Attributes { + sel?: string | symbol; + } + } +} + +type PropsExtensions = { + sel?: string | symbol; +} + +function createIncorporatedElement

( + type: ReactType

, + props: P & PropsExtensions | null, + ...children: Array> +): ReactElement

{ + if (!props || !props.sel) { + return createElement(type, props, ...children); + } else { + return createElement(incorporate(type), props, ...children); + } +} + +export default { + createElement: createIncorporatedElement +} diff --git a/test/jsxFactory.tsx b/test/jsxFactory.tsx new file mode 100644 index 0000000..e248515 --- /dev/null +++ b/test/jsxFactory.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import * as Adapter from 'enzyme-adapter-react-16'; +import * as Enzyme from 'enzyme'; +const assert = require('assert'); +import {jsxFactory, h, ReactSource, makeCycleReactComponent} from '../src'; + +Enzyme.configure({adapter: new Adapter()}); + +const {shallow} = Enzyme; + +describe('jsxFactory', function () { + it('w/ nothing', () => { + const wrapper = shallow(

); + + assert.strictEqual(wrapper.find('h1').length, 1); + }); + + it('w/ text child', () => { + const wrapper = shallow(

heading 1

); + + const h1 = wrapper.find('h1'); + assert.strictEqual(h1.text(), 'heading 1'); + }); + + it('w/ children array', () => { + const wrapper = shallow( +
+

heading 1

+

heading 2

+

heading 3

+
+ ); + + const section = wrapper.find('section'); + assert.strictEqual(section.children().length, 3); + }); + + it('w/ props', () => { + const wrapper = shallow(
); + + assert(wrapper.exists('[data-foo="bar"]')); + }); + + it('w/ props and children', () => { + const wrapper = shallow( +
+

heading 1

+

heading 2

+

heading 3

+
+ ); + + const section = wrapper.first(); + assert.strictEqual(section.length, 1); + assert(section.exists('[data-foo="bar"]')); + assert.deepStrictEqual(section.children().length, 3); + }); + + it('w/ className', () => { + const wrapper = shallow(
); + + assert(wrapper.hasClass('foo')); + }); + + it('renders functional component', () => { + const Test = () =>

Functional

; + const wrapper = shallow(); + + assert.strictEqual(wrapper.first().type(), 'h1'); + }); + + it('renders class component', () => { + class Test extends React.Component { + render() { + return

Class

; + } + } + + const wrapper = shallow(); + + assert.strictEqual(wrapper.first().type(), 'h1'); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index dab5af5..827111e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,9 @@ "rootDir": "src/", "outDir": "lib/cjs/", "skipLibCheck": true, - "lib": ["dom", "es5", "scripthost", "es2015"] + "lib": ["dom", "es5", "scripthost", "es2015"], + "jsx": "react", + "jsxFactory": "jsxFactory.createElement" }, "files": ["src/index.ts"] }