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  }