1+ import Checkbox from "components/checkbox" ;
12import tile from "components/tile" ;
23import actionStack from "lib/actionStack" ;
34import restoreTheme from "lib/restoreTheme" ;
@@ -11,84 +12,110 @@ import restoreTheme from "lib/restoreTheme";
1112 * @property {function():void } [onHide]
1213 */
1314
15+ /**
16+ * @typedef {object } SelectItem
17+ * @property {string } [value]
18+ * @property {string } [text]
19+ * @property {string } [icon]
20+ * @property {boolean } [disabled]
21+ * @property {string } [letters]
22+ * @property {boolean } [checkbox]
23+ */
24+
1425/**
1526 * Create a select dialog
1627 * @param {string } title Title of the select
17- * @param {string[] } options [value, text, icon, disable?] or string
18- * @param {SelectOptions | boolean } opts options or rejectOnCancel
28+ * @param {string | string[] | SelectItem } items Object or [value, text, icon, disable?, letters?, checkbox? ] or String
29+ * @param {SelectOptions | boolean } options options or rejectOnCancel
1930 * @returns {Promise<string> }
2031 */
21- function select ( title , options , opts = { } ) {
32+ function select ( title , items , options = { } ) {
2233 let rejectOnCancel = false ;
23- if ( typeof opts === "boolean" ) {
24- rejectOnCancel = opts ;
25- opts = { } ;
34+ if ( typeof options === "boolean" ) {
35+ rejectOnCancel = options ;
36+ options = { } ;
2637 }
27- return new Promise ( ( resolve , reject ) => {
28- const $titleSpan = title ? (
29- < strong className = "title" > { title } </ strong >
30- ) : null ;
31- const $list = (
32- < ul
33- className = { `scroll ${ opts . textTransform === false ? " no-text-transform" : "" } ` }
34- > </ ul >
35- ) ;
36- const selectDiv = (
38+
39+ return new Promise ( ( res , rej ) => {
40+ const { textTransform = false , hideOnSelect = true } = options ;
41+ let $defaultVal ;
42+
43+ // elements
44+ const $mask = < span className = "mask" onclick = { cancel } > </ span > ;
45+ const $list = tag ( "ul" , {
46+ className : "scroll" + ! textTransform ? " no-text-transform" : "" ,
47+ } ) ;
48+ const $select = (
3749 < div className = "prompt select" >
38- { $titleSpan ? [ $titleSpan , $list ] : $list }
50+ { title ? < strong className = "title" > { title } </ strong > : "" }
51+ { $list }
3952 </ div >
4053 ) ;
41- const mask = < span className = "mask" onclick = { cancel } > </ span > ;
42- let $defaultVal ;
4354
44- if ( opts . hideOnSelect === undefined ) opts . hideOnSelect = true ;
45-
46- options . map ( ( option ) => {
47- let value = null ;
48- let text = null ;
49- let lead = null ;
50- let disabled = false ;
51- if ( Array . isArray ( option ) ) {
52- value = option [ 0 ] ;
53- text = option [ 1 ] ;
54-
55- if ( option . length > 2 && typeof option [ 2 ] === "string" ) {
56- const icon = option [ 2 ] ;
57- if ( icon === "letters" ) {
58- const letters = option [ 4 ] ;
59- lead = < i className = "icon letters" data-letters = { letters } > </ i > ;
60- } else {
61- lead = < i className = { `icon ${ icon } ` } > </ i > ;
62- }
55+ items . map ( ( item ) => {
56+ let lead ,
57+ tail ,
58+ itemOptions = {
59+ value : null ,
60+ text : null ,
61+ icon : null ,
62+ disabled : false ,
63+ letters : "" ,
64+ checkbox : null ,
65+ } ;
66+
67+ // init item options
68+ if ( typeof item === "object" ) {
69+ if ( Array . isArray ( item ) ) {
70+ Object . keys ( itemOptions ) . forEach (
71+ ( key , i ) => ( itemOptions [ key ] = item [ i ] ) ,
72+ ) ;
73+ } else {
74+ itemOptions = Object . assign ( { } , itemOptions , item ) ;
75+ }
76+ } else {
77+ itemOptions . value = item ;
78+ itemOptions . text = item ;
79+ }
80+
81+ // handle icon
82+ if ( itemOptions . icon ) {
83+ if ( itemOptions . icon === "letters" && ! ! itemOptions . letters ) {
84+ lead = (
85+ < i className = "icon letters" data-letters = { itemOptions . letters } > </ i >
86+ ) ;
87+ } else {
88+ lead = < i className = { `icon ${ itemOptions . icon } ` } > </ i > ;
6389 }
90+ }
6491
65- option . map ( ( o , i ) => {
66- if ( typeof o === "boolean" && i > 1 ) disabled = ! o ;
92+ // handle checkbox
93+ if ( itemOptions . checkbox != null ) {
94+ tail = Checkbox ( {
95+ checked : itemOptions . checkbox ,
6796 } ) ;
68- } else {
69- value = text = option ;
7097 }
7198
7299 const $item = tile ( {
73100 lead,
74- text : < span className = "text" innerHTML = { text } > </ span > ,
101+ tail,
102+ text : < span className = "text" innerHTML = { itemOptions . text } > </ span > ,
75103 } ) ;
76104
77- if ( opts . default === value ) {
105+ $item . tabIndex = "0" ;
106+ if ( itemOptions . disabled ) $item . classList . add ( "disabled" ) ;
107+ if ( options . default === itemOptions . value ) {
78108 $item . classList . add ( "selected" ) ;
79109 $defaultVal = $item ;
80110 }
81111
82- $item . tabIndex = "0" ;
83-
112+ // handle events
84113 $item . onclick = function ( ) {
85- if ( value === undefined ) return ;
86- if ( opts . hideOnSelect ) hide ( ) ;
87- resolve ( value ) ;
114+ if ( ! itemOptions . value ) return ;
115+ if ( hideOnSelect ) hide ( ) ;
116+ res ( itemOptions . value ) ;
88117 } ;
89118
90- if ( disabled ) $item . classList . add ( "disabled" ) ;
91-
92119 $list . append ( $item ) ;
93120 } ) ;
94121
@@ -97,31 +124,30 @@ function select(title, options, opts = {}) {
97124 action : cancel ,
98125 } ) ;
99126
100- app . append ( selectDiv , mask ) ;
127+ app . append ( $select , $ mask) ;
101128 if ( $defaultVal ) $defaultVal . scrollIntoView ( ) ;
102129
103130 const $firstChild = $defaultVal || $list . firstChild ;
104131 if ( $firstChild && $firstChild . focus ) $firstChild . focus ( ) ;
105-
106132 restoreTheme ( true ) ;
107133
108134 function cancel ( ) {
109135 hide ( ) ;
110- if ( typeof opts . onCancel === "function" ) opts . onCancel ( ) ;
136+ if ( typeof options . onCancel === "function" ) options . onCancel ( ) ;
111137 if ( rejectOnCancel ) reject ( ) ;
112138 }
113139
114140 function hideSelect ( ) {
115- selectDiv . classList . add ( "hide" ) ;
141+ $select . classList . add ( "hide" ) ;
116142 restoreTheme ( ) ;
117143 setTimeout ( ( ) => {
118- selectDiv . remove ( ) ;
119- mask . remove ( ) ;
144+ $select . remove ( ) ;
145+ $ mask. remove ( ) ;
120146 } , 300 ) ;
121147 }
122148
123149 function hide ( ) {
124- if ( typeof opts . onHide === "function" ) opts . onHide ( ) ;
150+ if ( typeof options . onHide === "function" ) options . onHide ( ) ;
125151 actionStack . remove ( "select" ) ;
126152 hideSelect ( ) ;
127153 let listItems = [ ...$list . children ] ;
0 commit comments