-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2f3e181
commit bfda483
Showing
9 changed files
with
2,853 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
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,63 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/gopherjs/gopherjs/js" | ||
) | ||
|
||
// Fragment is used to group a list of children | ||
// without adding extra nodes to the DOM. | ||
// See: https://reactjs.org/docs/fragments.html | ||
func Fragment(key *string, children ...interface{}) *js.Object { | ||
props := map[string]interface{}{} | ||
if key != nil { | ||
props["key"] = *key | ||
} | ||
return JSX(React.Get("Fragment"), props, children...) | ||
} | ||
|
||
// JSX is used to create an Element. | ||
func JSX(component interface{}, props interface{}, children ...interface{}) *js.Object { | ||
|
||
args := []interface{}{ | ||
component, | ||
SToMap(props), | ||
} | ||
if len(children) > 0 { | ||
args = append(args, children...) | ||
} | ||
|
||
return React.Call("createElement", args...) | ||
} | ||
|
||
// JSFn is a convenience function used to call javascript functions. | ||
func JSFn(name string, args ...interface{}) *js.Object { | ||
return js.Global.Call(name, args...) | ||
} | ||
|
||
// CreateRef will create a Ref. | ||
// See: https://reactjs.org/docs/refs-and-the-dom.html | ||
func CreateRef() *js.Object { | ||
return React.Call("createRef") | ||
} | ||
|
||
// ForwardRef will forward a Ref to child components. | ||
// See: https://reactjs.org/docs/forwarding-refs.html | ||
func ForwardRef(component interface{}) *js.Object { | ||
return React.Call("forwardRef", func(props *js.Object, ref *js.Object) *js.Object { | ||
props.Set("ref", ref) | ||
|
||
n := React.Get("Children").Call("count", props.Get("children")).Int() | ||
switch n { | ||
case 0: | ||
return JSX(component, props) | ||
case 1: | ||
return JSX(component, props, props.Get("children")) | ||
default: | ||
children := []interface{}{} | ||
for i := 0; i < n; i++ { | ||
children = append(children, props.Get("children").Index(i)) | ||
} | ||
return JSX(component, props, children...) | ||
} | ||
}) | ||
} |
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,36 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/gopherjs/gopherjs/js" | ||
"honnef.co/go/js/dom" | ||
) | ||
|
||
var ( | ||
// React points to the React library. Change it | ||
// if it is not in your global namespace. | ||
React = js.Global.Get("React") | ||
// ReactDOM points to the ReactDOM library. Change it | ||
// if it is not in your global namespace. | ||
ReactDOM = js.Global.Get("ReactDOM") | ||
// CreateReactClass points to create-react-class module. | ||
CreateReactClass = js.Global | ||
) | ||
|
||
// ForceUpdate will force a rerender of the component. | ||
// See: https://reactjs.org/docs/react-component.html#forceupdate | ||
func ForceUpdate(this *js.Object, callback ...func()) { | ||
|
||
if len(callback) > 0 && callback[0] != nil { | ||
this.Call("forceUpdate", callback[0]) | ||
} else { | ||
this.Call("forceUpdate") | ||
} | ||
} | ||
|
||
// Render will render component to the specified target dom element. | ||
func Render(element *js.Object, domTarget dom.Element, callback ...func()) *js.Object { | ||
if len(callback) > 0 && callback[0] != nil { | ||
return ReactDOM.Call("render", element, domTarget, callback[0]) | ||
} | ||
return ReactDOM.Call("render", element, domTarget) | ||
} |
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,116 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/gopherjs/gopherjs/js" | ||
) | ||
|
||
// Map is a convenience method that can be used to access fields in a | ||
// js object. | ||
type Map func(key string) *js.Object | ||
|
||
// UpdaterFunc is the first argument for SetState method. | ||
// See: https://reactjs.org/docs/react-component.html#setstate | ||
type UpdaterFunc func(props, state Map) interface{} | ||
|
||
// SetState is used to asynchronously update the state. | ||
// See: https://reactjs.org/docs/react-component.html#setstate | ||
type SetState func(updater interface{}, callback ...func()) | ||
|
||
type ClassDef map[string]interface{} | ||
|
||
// NewClassDef will create an empty class definition which can immediately be used | ||
// to create a React component. | ||
func NewClassDef(displayName string) ClassDef { | ||
def := ClassDef{ | ||
render: js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { | ||
return nil | ||
}), | ||
} | ||
def["displayName"] = displayName | ||
return def | ||
} | ||
|
||
func (def ClassDef) setMethod(static bool, name string, f func(this *js.Object, props, state Map, setState SetState, arguments []*js.Object) interface{}) { | ||
|
||
const statics = "statics" | ||
|
||
if f == nil { | ||
// Clear method | ||
if static { | ||
if _, exists := def[statics]; exists { | ||
switch s := def[statics].(type) { | ||
case (map[string]interface{}): | ||
delete(s, name) | ||
default: | ||
|
||
} | ||
} | ||
} else { | ||
delete(def, name) | ||
} | ||
return | ||
} | ||
|
||
if !static && name == statics { | ||
panic("can't have function name called 'statics'") | ||
} | ||
|
||
x := func(this *js.Object, arguments []*js.Object) interface{} { | ||
|
||
props := func(key string) *js.Object { | ||
return this.Get("props").Get(key) | ||
} | ||
|
||
state := func(key string) *js.Object { | ||
return this.Get("state").Get(key) | ||
} | ||
|
||
setState := func(updater interface{}, callback ...func()) { | ||
|
||
if updater == nil { | ||
return | ||
} | ||
|
||
if len(callback) > 0 && callback[0] != nil { | ||
switch updater := updater.(type) { | ||
case func(props, state Map) interface{}: | ||
this.Call("setState", SToMap(updater(props, state)), callback[0]) | ||
case UpdaterFunc: | ||
this.Call("setState", SToMap(updater(props, state)), callback[0]) | ||
default: | ||
this.Call("setState", SToMap(updater), callback[0]) | ||
} | ||
} else { | ||
switch updater := updater.(type) { | ||
case func(props, state Map) interface{}: | ||
this.Call("setState", SToMap(updater(props, state))) | ||
case UpdaterFunc: | ||
this.Call("setState", SToMap(updater(props, state))) | ||
default: | ||
this.Call("setState", SToMap(updater)) | ||
} | ||
} | ||
} | ||
|
||
return f(this, props, state, setState, arguments) | ||
} | ||
|
||
if static { | ||
def[statics] = map[string]interface{}{ | ||
name: js.MakeFunc(x), | ||
} | ||
} else { | ||
def[name] = js.MakeFunc(x) | ||
} | ||
} | ||
|
||
// SetMethod allows a custom method to be attached. | ||
// By passing nil for f, the method can also be detached (cleared). | ||
func (def ClassDef) SetMethod(name string, f func(this *js.Object, props, state Map, setState SetState, arguments []*js.Object) interface{}) { | ||
def.setMethod(false, name, f) | ||
} | ||
|
||
// ReactCreateClass is used to create a react component. | ||
func ReactCreateClass(def ClassDef) *js.Object { | ||
return CreateReactClass.Call("createReactClass", def) | ||
} |
Oops, something went wrong.