-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathselect.tsx
More file actions
145 lines (116 loc) · 3.05 KB
/
Copy pathselect.tsx
File metadata and controls
145 lines (116 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//////////////////////////////////////////////////////////////
import {
Attrs,
bind,
Component,
o,
O,
on,
RO,
Observable,
Renderable,
Repeat,
Display,
Mixin
} from 'elt'
export type LabelFn<T> = (opt: T) => Renderable
// export type ChangeFn<T> = (value: T, event: Event, atom: Atom) => any
export type ChangeFn<T> = (value: T, ev?: Event) => any
export interface SelectAttributes<T> extends Attrs {
model: O<T>
options: RO<T[]>
labelfn?: LabelFn<T>
onchange?: ChangeFn<T>
placeholder?: RO<string>
}
export class Select<T> extends Component<SelectAttributes<T>> {
protected selected: Observable<string> = o('-1')
/**
* Setup the observation logic.
*/
render(children: DocumentFragment): Element {
let mod = false;
let attrs = this.attrs
let options = o(attrs.options)
let {model, labelfn, onchange} = attrs
const o_model = o(model)
// Used for typing, to avoid the undefined part.
var real_labelfn = (obj: any) => {
return obj.label || obj.text || obj
}
if (labelfn) real_labelfn = labelfn
// We use a touched() function to avoid infinite loops since there
// is a circular logic here.
let touched = () => {
if (mod)
return true
mod = true
requestAnimationFrame(() => { mod = false; });
return false
}
this.observe(options, (opts) => {
if (touched()) return;
this.selected.set('' + opts.indexOf(o_model.get()));
});
this.observe(model, (v) => {
if (touched()) return;
this.selected.set(''+ options.get().indexOf(v));
});
this.observe(this.selected, (v) => {
if (touched()) return;
o_model.set(options.get()[parseInt(v)]);
});
////////////////////////////////
let decorators: Mixin[] = [bind(this.selected)];
if (onchange) {
var fn = onchange // used this for typing matters.
decorators.push(on('change', ev => fn(o_model.get(), ev)))
}
return <label class={Select.label}>
<select class={Select.select} $$={decorators}>
{Repeat(options, (opt, i) => <option
value={i}
selected={o_model.equals(opt)}>
{opt.tf(val => Display(real_labelfn(val)))}
</option>
)}
</select>
</label>
}
}
import { Styling } from './styling'
import { cls, s } from 'osun'
export namespace Select {
export const select = cls('select',
Styling.no_spurious_borders,
Styling.no_native_appearance,
{
padding: '0 16px 0 8px',
height: '32px',
margin: 0,
border: `1px solid ${Styling.colors.FG5}`,
borderColor: Styling.colors.FG5,
borderRadius: '2px',
background: Styling.colors.BG,
color: Styling.colors.FG3,
display: 'inline-block',
cursor: 'pointer'
},
)
s(select).append(`:-moz-focusring`).define({
color: Styling.colors.TRANSPARENT,
textShadow: `0 0 0 ${Styling.colors.FG3}`
})
export const label = cls('label', {position: 'relative'})
s(label).append('::after').define({
content: "'\\f2f2'",
fontFamily: '"Material-Design-Iconic-Font", monospace',
color: Styling.colors.FG3,
right: '8px',
top: '9px',
padding: '0 0 2px',
position: 'absolute',
pointerEvents: 'none',
verticalAlign: 'middle'
})
}