github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/components/imm/select.go (about) 1 package imm 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "honnef.co/go/js/dom" 8 9 r "myitcv.io/react" 10 ) 11 12 const ( 13 noEntry = "-1" 14 ) 15 16 //go:generate reactGen 17 //go:generate immutableGen 18 19 type Label interface { 20 Label() string 21 } 22 23 type _Imm_LabelEntries []Label 24 25 type _Imm_strEntrySelect map[string]Label 26 27 type ImmSelectEntry interface { 28 Range() []Label 29 } 30 31 // SelectDef is a wrapper around the myitcv.io/react.SelectDef component. It allows 32 // any value implementing the Label interface to be selected 33 // 34 type SelectDef struct { 35 r.ComponentDef 36 } 37 38 type OnSelect interface { 39 OnSelect(i Label) 40 } 41 42 type SelectProps struct { 43 Entry Label 44 Entries ImmSelectEntry 45 OnSelect 46 } 47 48 type SelectState struct { 49 currEntry string 50 entries *entriesKeysSelect 51 entriesMap *strEntrySelect 52 } 53 54 type entryKey struct { 55 key string 56 p Label 57 } 58 59 type _Imm_entriesKeysSelect []entryKey 60 61 // Select creates a new instance of the SelectDef component with the provided props 62 // 63 func Select(props SelectProps) *SelectElem { 64 return buildSelectElem(props) 65 } 66 67 func (p SelectDef) ComponentWillMount() { 68 p.updateMap(p.Props().Entries) 69 } 70 71 func (p SelectDef) ComponentWillReceiveProps(props SelectProps) { 72 p.updateMap(props.Entries) 73 } 74 75 func (p SelectDef) updateMap(es ImmSelectEntry) { 76 eks := newEntriesKeysSelect().AsMutable() 77 defer eks.AsImmutable(nil) 78 79 kem := newStrEntrySelect().AsMutable() 80 defer kem.AsImmutable(nil) 81 82 for i, p := range es.Range() { 83 k := strconv.Itoa(i) 84 kem.Set(k, p) 85 eks.Append(entryKey{ 86 key: k, 87 p: p, 88 }) 89 } 90 91 kem.Set(noEntry, nil) 92 93 st := p.State() 94 st.entries = eks 95 st.entriesMap = kem 96 p.SetState(st) 97 } 98 99 func (p SelectDef) Render() r.Element { 100 101 var ps []*r.OptionElem 102 103 for _, v := range p.State().entries.Range() { 104 p := r.Option( 105 &r.OptionProps{Value: v.key}, 106 r.S(v.p.Label()), 107 ) 108 109 ps = append(ps, p) 110 } 111 112 return r.Select( 113 &r.SelectProps{ 114 Value: p.State().currEntry, 115 OnChange: changeEntry{p}, 116 }, 117 ps..., 118 ) 119 } 120 121 type changeEntry struct{ SelectDef } 122 123 func (c changeEntry) OnChange(e *r.SyntheticEvent) { 124 v := e.Target().(*dom.HTMLSelectElement).Value 125 126 p := c.SelectDef 127 128 s := c.SelectDef.State() 129 130 l, ok := p.State().entriesMap.Get(v) 131 if !ok { 132 panic(fmt.Errorf("Select component selected value %q that we don't know about", v)) 133 } 134 135 s.currEntry = v 136 p.SetState(s) 137 138 p.Props().OnSelect.OnSelect(l) 139 }