Skip to content

Commit 5ffbba0

Browse files
committed
feat: add support for adding dom element properties similar to @cycle/dom
1 parent 2205231 commit 5ffbba0

File tree

6 files changed

+107
-6
lines changed

6 files changed

+107
-6
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
/lib
55
/dist
66
/.cache
7+
fixtures
8+
support
9+
plugins
710
node_modules
811
package-lock.json
912
pnpm-lock.yaml

cypress.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
22
"baseUrl": "http://localhost:1234",
3-
"video": false
3+
"chromeWebSecurity": false,
4+
"defaultCommandTimeout": 10000,
5+
"modifyObstructiveCode": false,
6+
"video": false,
7+
"fixturesFolder": false
48
}

cypress/integration/test.spec.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
/// <reference types="cypress" />
22

3+
const { watchFile } = require("fs")
4+
35
context('Page load', () => {
46
beforeEach(() => {
57
cy.visit('/')
8+
cy.wait(500)
69
})
710
describe('React integration', () => {
11+
812
it('Should mount', () => {
913
cy.get('#app')
1014
.should('exist', 'success')
1115
})
16+
it('Should have foo property on button', () => {
17+
cy.get('.clicker')
18+
// .its('foo')
19+
// .should('eq', 3)
20+
.then(($el) => {
21+
cy.wrap($el[0].foo).should('eq', 3)
22+
})
23+
})
1224
})
1325
})

example/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ function main(sources) {
1313
const reset$ = sources.react
1414
.select(btnSel)
1515
.events('click')
16+
.debug((ev) => {
17+
return ev.target.printer()
18+
})
1619
.mapTo(() => 0);
1720

1821
const count$ = xs
@@ -22,7 +25,7 @@ function main(sources) {
2225
const vdom$ = count$.map(i =>
2326
h('div', [
2427
h('h1', `Hello ${i} times`),
25-
h('button', {sel: btnSel}, 'Reset'),
28+
h('button', {sel: btnSel, className: 'clicker', domProps: {foo: 3, printer: () => console.log('domProps being used')}}, 'Reset'),
2629
]),
2730
);
2831

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,11 @@
4949
"compile": "npm run compile-cjs && npm run compile-es6",
5050
"compile-cjs": "tsc --module commonjs --outDir ./lib/cjs",
5151
"compile-es6": "echo 'TODO' : tsc --module es6 --outDir ./lib/es6",
52-
"test": "$(npm bin)/mocha test/*.ts --require ts-node/register --recursive; cypress run",
52+
"test": "$(npm bin)/mocha test/*.ts --require ts-node/register --recursive",
53+
"full-test": "npm test; npm run cypress:run",
5354
"start": "parcel example/index.html",
54-
"serve-test": "start-server-and-test start http://localhost:1234 test"
55+
"serve-test": "start-server-and-test start http://localhost:1234 full-test",
56+
"cypress:open": "cypress open",
57+
"cypress:run": "cypress run"
5558
}
5659
}

src/h.ts

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import {
55
ElementType,
66
ReactHTML,
77
Attributes,
8+
Component,
9+
ComponentType,
10+
createRef,
11+
forwardRef
812
} from 'react';
913
import {incorporate} from './incorporate';
1014

@@ -17,6 +21,78 @@ type PropsLike<P> = P & PropsExtensions & Attributes;
1721

1822
type Children = string | Array<ReactNode>;
1923

24+
export function domPropify(Comp: any): ComponentType<any> {
25+
class DomProps extends Component<any, any> {
26+
private ref: any;
27+
private domProps: any;
28+
constructor(props) {
29+
super(props);
30+
this.domProps = this.props.domProps;
31+
this.ref = props.forwardedRef || createRef();
32+
}
33+
34+
public componentDidMount() {
35+
if (this.domProps && this.ref) {
36+
Object.entries(this.domProps).forEach(([key, val]) => {
37+
this.ref.current[key] = val;
38+
});
39+
}
40+
}
41+
42+
render() {
43+
const p: any = {ref: this.ref, ...this.props};
44+
delete p.forwardedRef
45+
delete p.domProps;
46+
return createElement(Comp, p);
47+
}
48+
}
49+
50+
return forwardRef((props, ref) => {
51+
return createElement(DomProps, {...props, forwardedRef: ref});
52+
});
53+
}
54+
55+
export function domHookify(Comp: any): ComponentType<any> {
56+
class DomHooks extends Component<any, any> {
57+
private ref: any;
58+
private hooks: any;
59+
constructor(props) {
60+
super(props);
61+
this.hooks = this.props.domHooks;
62+
this.ref = props.forwardedRef || createRef();
63+
}
64+
65+
public componentDidMount() {
66+
if (this.hooks && this.hooks.insert && this.ref) {
67+
this.hooks.insert({elm: this.ref.current})
68+
}
69+
}
70+
71+
public componentDidUpdate() {
72+
if (this.hooks && this.hooks.update && this.ref) {
73+
this.hooks.update({elm: this.ref.current})
74+
}
75+
}
76+
77+
public componentWillUnmount() {
78+
if (this.hooks && this.hooks.destroy && this.ref) {
79+
this.hooks.destroy({elm: this.ref.current})
80+
}
81+
}
82+
83+
render() {
84+
const p: any = {ref: this.ref, ...this.props};
85+
delete p.forwardedRef
86+
delete p.domHooks;
87+
return createElement(Comp, p);
88+
}
89+
}
90+
91+
return forwardRef((props, ref) => {
92+
return createElement(DomHooks, {...props, forwardedRef: ref});
93+
});
94+
}
95+
2096
function createElementSpreading<P = any>(
2197
type: ElementType<P> | keyof ReactHTML,
2298
props: PropsLike<P> | null,
@@ -36,7 +112,7 @@ function hyperscriptProps<P = any>(
36112
if (!props.sel) {
37113
return createElement(type, props);
38114
} else {
39-
return createElement(incorporate(type), props);
115+
return createElement(domHookify(domPropify(incorporate(type))), props);
40116
}
41117
}
42118

@@ -55,7 +131,7 @@ function hyperscriptPropsChildren<P = any>(
55131
if (!props.sel) {
56132
return createElementSpreading(type, props, children);
57133
} else {
58-
return createElementSpreading(incorporate(type), props, children);
134+
return createElementSpreading(domHookify(domPropify(incorporate(type))), props, children);
59135
}
60136
}
61137

0 commit comments

Comments
 (0)