-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add h2 hyperscript function for assisting snabbdom/react migration
- Loading branch information
Showing
10 changed files
with
637 additions
and
437 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,9 @@ | |
/lib | ||
/dist | ||
/.cache | ||
fixtures | ||
support | ||
plugins | ||
node_modules | ||
package-lock.json | ||
pnpm-lock.yaml | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
{ | ||
"baseUrl": "http://localhost:1234", | ||
"video": false | ||
"chromeWebSecurity": false, | ||
"defaultCommandTimeout": 10000, | ||
"modifyObstructiveCode": false, | ||
"video": false, | ||
"fixturesFolder": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,25 @@ | ||
/// <reference types="cypress" /> | ||
|
||
const { watchFile } = require("fs") | ||
|
||
context('Page load', () => { | ||
beforeEach(() => { | ||
cy.visit('/') | ||
cy.wait(500) | ||
}) | ||
describe('React integration', () => { | ||
|
||
it('Should mount', () => { | ||
cy.get('#app') | ||
.should('exist', 'success') | ||
}) | ||
it('Should have foo property on button', () => { | ||
cy.get('.clicker') | ||
// .its('foo') | ||
// .should('eq', 3) | ||
.then(($el) => { | ||
cy.wrap($el[0].foo).should('eq', 3) | ||
}) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import { | ||
createElement, | ||
ReactElement, | ||
ReactNode, | ||
ElementType, | ||
ReactHTML, | ||
Attributes, | ||
Component, | ||
ComponentType, | ||
createRef, | ||
forwardRef | ||
} from 'react'; | ||
import {incorporate} from './incorporate'; | ||
|
||
export type PropsExtensions = { | ||
sel?: string | symbol; | ||
domProps?: any | ||
}; | ||
|
||
type PropsLike<P> = P & PropsExtensions & Attributes; | ||
|
||
type Children = string | Array<ReactNode>; | ||
|
||
export function domPropify(Comp: any): ComponentType<any> { | ||
class DomProps extends Component<any, any> { | ||
private ref: any; | ||
private domProps: any; | ||
constructor(props) { | ||
super(props); | ||
this.domProps = this.props.domProps; | ||
this.ref = props.forwardedRef || createRef(); | ||
} | ||
|
||
public componentDidMount() { | ||
if (this.domProps && this.ref) { | ||
Object.entries(this.domProps).forEach(([key, val]) => { | ||
this.ref.current[key] = val; | ||
}); | ||
} | ||
} | ||
|
||
render() { | ||
const p: any = {ref: this.ref, ...this.props}; | ||
delete p.forwardedRef | ||
delete p.domProps; | ||
return createElement(Comp, p); | ||
} | ||
} | ||
|
||
return forwardRef((props, ref) => { | ||
return createElement(DomProps, {...props, forwardedRef: ref}); | ||
}); | ||
} | ||
|
||
export function domHookify(Comp: any): ComponentType<any> { | ||
class DomHooks extends Component<any, any> { | ||
private ref: any; | ||
private hooks: any; | ||
constructor(props) { | ||
super(props); | ||
this.hooks = this.props.domHooks; | ||
this.ref = props.forwardedRef || createRef(); | ||
} | ||
|
||
public componentDidMount() { | ||
if (this.hooks && this.hooks.insert && this.ref) { | ||
this.hooks.insert({elm: this.ref.current}) | ||
} | ||
} | ||
|
||
public componentDidUpdate() { | ||
if (this.hooks && this.hooks.update && this.ref) { | ||
this.hooks.update({elm: this.ref.current}) | ||
} | ||
} | ||
|
||
public componentWillUnmount() { | ||
if (this.hooks && this.hooks.destroy && this.ref) { | ||
this.hooks.destroy({elm: this.ref.current}) | ||
} | ||
} | ||
|
||
render() { | ||
const p: any = {ref: this.ref, ...this.props}; | ||
delete p.forwardedRef | ||
delete p.domHooks; | ||
return createElement(Comp, p); | ||
} | ||
} | ||
|
||
return forwardRef((props, ref) => { | ||
return createElement(DomHooks, {...props, forwardedRef: ref}); | ||
}); | ||
} | ||
|
||
function createElementSpreading<P = any>( | ||
type: ElementType<P> | keyof ReactHTML, | ||
props: PropsLike<P> | null, | ||
children: Children, | ||
): ReactElement<P> { | ||
if (typeof children === 'string') { | ||
return createElement(type, props, children); | ||
} else { | ||
return createElement(type, props, ...children); | ||
} | ||
} | ||
|
||
function hyperscriptProps<P = any>( | ||
type: ElementType<P> | keyof ReactHTML, | ||
props: PropsLike<P>, | ||
): ReactElement<P> { | ||
if (!props.sel) { | ||
return createElement(type, props); | ||
} else { | ||
return createElement(domHookify(domPropify(incorporate(type))), props); | ||
} | ||
} | ||
|
||
function hyperscriptChildren<P = any>( | ||
type: ElementType<P> | keyof ReactHTML, | ||
children: Children, | ||
): ReactElement<P> { | ||
return createElementSpreading(type, null, children); | ||
} | ||
|
||
function hyperscriptPropsChildren<P = any>( | ||
type: ElementType<P> | keyof ReactHTML, | ||
props: PropsLike<P>, | ||
children: Children, | ||
): ReactElement<P> { | ||
if (!props.sel) { | ||
return createElementSpreading(type, props, children); | ||
} else { | ||
return createElementSpreading(domHookify(domPropify(incorporate(type))), props, children); | ||
} | ||
} | ||
|
||
export function h2<P = any>( | ||
type: ElementType<P> | keyof ReactHTML, | ||
a?: PropsLike<P> | Children, | ||
b?: Children, | ||
): ReactElement<P> { | ||
if (a === undefined && b === undefined) { | ||
return createElement(type, null); | ||
} | ||
if (b === undefined && (typeof a === 'string' || Array.isArray(a))) { | ||
return hyperscriptChildren(type, a as Array<ReactNode>); | ||
} | ||
if (b === undefined && typeof a === 'object' && !Array.isArray(a)) { | ||
return hyperscriptProps(type, a); | ||
} | ||
if ( | ||
a !== undefined && | ||
typeof a !== 'string' && | ||
!Array.isArray(a) && | ||
b !== undefined | ||
) { | ||
return hyperscriptPropsChildren(type, a, b); | ||
} else { | ||
throw new Error('Unexpected usage of h() function'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.