From 68313da4122ec7f76274b22926e762914c96723d Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Mon, 23 Dec 2019 18:22:54 +0000 Subject: [PATCH] Convert to typescript (#795) * Typescript config setup * Add type annotations to components * Further type additions * And more... * Add types to actions * Add types to templates * Further type checks * Further type additons * Install fuse latest * Housekeeping * Remove old type definitions * Fix remaning type issues * Fix some failing tests * Remove types workflow * Fix failing unit tests * Resolve back space event regression * Convert cypress files to .ts * Fix eslint issues * Remove cachebusting urls * Resolve delete button bug * Resolve regression bugs * Fix lint script * Fix lint workflow * Pass args instead of object to keyboard handlers * Flatten misc reducer * Resolve keyboad action test failures * Use Pick instead of Partial * Use interfaces in action tests * Update firefox image * Incorporate #791 * Incorporate #788 --- .eslintrc.json | 35 +- .../__snapshots__/firefox-darwin.png | Bin 45603 -> 45377 bytes .github/workflows/lint.yml | 8 +- .github/workflows/types.yml | 27 - .mocharc.yml | 9 +- .vscode/settings.json | 5 +- ...ltiple.spec.js => select-multiple.spec.ts} | 0 ...{select-one.spec.js => select-one.spec.ts} | 0 .../{text.spec.js => text.spec.ts} | 0 package-lock.json | 326 +- package.json | 23 +- public/assets/scripts/choices.js | 5896 ++++++++--------- public/assets/scripts/choices.min.js | 6 +- public/test/select-multiple/index.html | 12 +- public/test/select-one/index.html | 12 +- public/test/text/index.html | 12 +- src/scripts/actions/choices.js | 58 - .../{choices.test.js => choices.test.ts} | 20 +- src/scripts/actions/choices.ts | 73 + src/scripts/actions/groups.js | 18 - .../{groups.test.js => groups.test.ts} | 5 +- src/scripts/actions/groups.ts | 27 + src/scripts/actions/items.js | 53 - .../actions/{items.test.js => items.test.ts} | 19 +- src/scripts/actions/items.ts | 70 + src/scripts/actions/misc.js | 28 - .../actions/{misc.test.js => misc.test.ts} | 16 +- src/scripts/actions/misc.ts | 30 + .../{choices.test.js => choices.test.ts} | 322 +- src/scripts/{choices.js => choices.ts} | 669 +- .../{container.test.js => container.test.ts} | 6 +- .../components/{container.js => container.ts} | 95 +- .../{dropdown.test.js => dropdown.test.ts} | 0 .../components/{dropdown.js => dropdown.ts} | 43 +- src/scripts/components/{index.js => index.ts} | 0 .../{input.test.js => input.test.ts} | 3 +- src/scripts/components/{input.js => input.ts} | 101 +- .../components/{list.test.js => list.test.ts} | 0 src/scripts/components/{list.js => list.ts} | 58 +- ...lement.test.js => wrapped-element.test.ts} | 0 ...{wrapped-element.js => wrapped-element.ts} | 34 +- src/scripts/components/wrapped-input.js | 38 - ...ed-input.test.js => wrapped-input.test.ts} | 30 +- src/scripts/components/wrapped-input.ts | 29 + ...-select.test.js => wrapped-select.test.ts} | 8 +- .../{wrapped-select.js => wrapped-select.ts} | 53 +- .../{constants.test.js => constants.test.ts} | 3 + src/scripts/{constants.js => constants.ts} | 34 +- src/scripts/interfaces.ts | 754 +++ src/scripts/lib/utils.js | 214 - .../lib/{utils.test.js => utils.test.ts} | 21 +- src/scripts/lib/utils.ts | 180 + src/scripts/reducers/choices.js | 110 - .../{choices.test.js => choices.test.ts} | 77 +- src/scripts/reducers/choices.ts | 127 + src/scripts/reducers/general.js | 19 - src/scripts/reducers/groups.js | 25 - .../{groups.test.js => groups.test.ts} | 4 +- src/scripts/reducers/groups.ts | 36 + .../reducers/{index.test.js => index.test.ts} | 14 +- src/scripts/reducers/{index.js => index.ts} | 15 +- src/scripts/reducers/items.js | 58 - .../reducers/{items.test.js => items.test.ts} | 7 +- src/scripts/reducers/items.ts | 73 + .../{general.test.js => loading.test.ts} | 10 +- src/scripts/reducers/loading.ts | 23 + .../store/{store.test.js => store.test.ts} | 2 +- src/scripts/store/{store.js => store.ts} | 70 +- .../{templates.test.js => templates.test.ts} | 6 +- src/scripts/{templates.js => templates.ts} | 182 +- tsconfig.json | 18 + types/index.d.ts | 1041 --- webpack.config.base.js | 23 +- 73 files changed, 5703 insertions(+), 5720 deletions(-) mode change 100644 => 100755 .github/actions-scripts/__snapshots__/firefox-darwin.png delete mode 100644 .github/workflows/types.yml rename cypress/integration/{select-multiple.spec.js => select-multiple.spec.ts} (100%) rename cypress/integration/{select-one.spec.js => select-one.spec.ts} (100%) rename cypress/integration/{text.spec.js => text.spec.ts} (100%) delete mode 100644 src/scripts/actions/choices.js rename src/scripts/actions/{choices.test.js => choices.test.ts} (80%) create mode 100644 src/scripts/actions/choices.ts delete mode 100644 src/scripts/actions/groups.js rename src/scripts/actions/{groups.test.js => groups.test.ts} (86%) create mode 100644 src/scripts/actions/groups.ts delete mode 100644 src/scripts/actions/items.js rename src/scripts/actions/{items.test.js => items.test.ts} (80%) create mode 100644 src/scripts/actions/items.ts delete mode 100644 src/scripts/actions/misc.js rename src/scripts/actions/{misc.test.js => misc.test.ts} (73%) create mode 100644 src/scripts/actions/misc.ts rename src/scripts/{choices.test.js => choices.test.ts} (91%) rename src/scripts/{choices.js => choices.ts} (80%) rename src/scripts/components/{container.test.js => container.test.ts} (98%) rename src/scripts/components/{container.js => container.ts} (70%) rename src/scripts/components/{dropdown.test.js => dropdown.test.ts} (100%) rename src/scripts/components/{dropdown.js => dropdown.ts} (55%) rename src/scripts/components/{index.js => index.ts} (100%) rename src/scripts/components/{input.test.js => input.test.ts} (99%) rename src/scripts/components/{input.js => input.ts} (60%) rename src/scripts/components/{list.test.js => list.test.ts} (100%) rename src/scripts/components/{list.js => list.ts} (67%) rename src/scripts/components/{wrapped-element.test.js => wrapped-element.test.ts} (100%) rename src/scripts/components/{wrapped-element.js => wrapped-element.ts} (82%) delete mode 100644 src/scripts/components/wrapped-input.js rename src/scripts/components/{wrapped-input.test.js => wrapped-input.test.ts} (72%) create mode 100644 src/scripts/components/wrapped-input.ts rename src/scripts/components/{wrapped-select.test.js => wrapped-select.test.ts} (95%) rename src/scripts/components/{wrapped-select.js => wrapped-select.ts} (56%) rename src/scripts/{constants.test.js => constants.test.ts} (98%) rename src/scripts/{constants.js => constants.ts} (81%) create mode 100644 src/scripts/interfaces.ts delete mode 100644 src/scripts/lib/utils.js rename src/scripts/lib/{utils.test.js => utils.test.ts} (92%) create mode 100644 src/scripts/lib/utils.ts delete mode 100644 src/scripts/reducers/choices.js rename src/scripts/reducers/{choices.test.js => choices.test.ts} (81%) create mode 100644 src/scripts/reducers/choices.ts delete mode 100644 src/scripts/reducers/general.js delete mode 100644 src/scripts/reducers/groups.js rename src/scripts/reducers/{groups.test.js => groups.test.ts} (94%) create mode 100644 src/scripts/reducers/groups.ts rename src/scripts/reducers/{index.test.js => index.test.ts} (75%) rename src/scripts/reducers/{index.js => index.ts} (75%) delete mode 100644 src/scripts/reducers/items.js rename src/scripts/reducers/{items.test.js => items.test.ts} (95%) create mode 100644 src/scripts/reducers/items.ts rename src/scripts/reducers/{general.test.js => loading.test.ts} (62%) create mode 100644 src/scripts/reducers/loading.ts rename src/scripts/store/{store.test.js => store.test.ts} (99%) rename src/scripts/store/{store.js => store.ts} (58%) rename src/scripts/{templates.test.js => templates.test.ts} (99%) rename src/scripts/{templates.js => templates.ts} (65%) create mode 100644 tsconfig.json delete mode 100644 types/index.d.ts diff --git a/.eslintrc.json b/.eslintrc.json index ad9bb6a..916e411 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,16 +1,21 @@ { - "parserOptions": { - "ecmaVersion": 2020 - }, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier", "sort-class-members"], "extends": [ "airbnb-base", "plugin:prettier/recommended", - "plugin:compat/recommended" + "plugin:compat/recommended", + "plugin:@typescript-eslint/recommended" ], - "plugins": ["prettier", "sort-class-members"], "env": { "es6": true, - "browser": true + "browser": true, + "mocha": true, + "cypress/globals": true + }, + "parserOptions": { + "project": "./tsconfig.json", + "ecmaVersion": 2020 }, "rules": { "import/prefer-default-export": "off", @@ -54,18 +59,23 @@ ], "accessorPairPositioning": "getThenSet" } - ] + ], + "lines-between-class-members": "off", + "@typescript-eslint/no-namespace": "off" }, "overrides": [ { - "files": ["*.test.js"], + "files": ["*.test.ts"], "env": { "mocha": true }, "rules": { "no-restricted-syntax": "off", "compat/compat": "off", - "no-new": "off" + "no-new": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off" } }, { @@ -92,6 +102,11 @@ "Element.prototype.classList", "Element.prototype.closest", "Element.prototype.dataset" - ] + ], + "import/resolver": { + "node": { + "extensions": [".js", ".ts"] + } + } } } diff --git a/.github/actions-scripts/__snapshots__/firefox-darwin.png b/.github/actions-scripts/__snapshots__/firefox-darwin.png old mode 100644 new mode 100755 index ca328d13e52c3f81785d05c8016e57dbb4e4c74d..34c05c95456a4b596cbdcfab067a60289d4bd589 GIT binary patch literal 45377 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

7pEgpO^~zWhWk)mnh857bHGg; zPJ(trIX^tuZ;)S>e95{Z3+pv<@U^l57J6q{UwvxPSB~X=CX!3aKmk=?0v@|bRP@9j zcT*lO`bMPrnfKSF*At50J1K#$!19iP!kVzA_?F(|?JM%6A zFlJ`Aw+QqE(^ z5I{6>o825zBJ2Sz4=QF|erPjun9xh~Z=LS5Z^(8?MJ*!+3#$OSIle|a*ZDO%_r@CU zk=xS{==qCj$<}=*O^uCTwcA#H`t%f78d97R{S@!lDyG?1j)RfIKzMg<+LYh>I@HOh zXqj|pM05ptS5t3wfN`}r52_F57VEBUNsMb;54~Lsppi5bPn;eRAYLWOyRt8p?$o_} zq;`7EGiIRL*IJHL zgwx|oM$SFunaFQ4-lK1qY%nG!%%e%?ULOZkIVu?z(#tzB+aoznTNs#}A&O}?@KCF~7zBJjXQaVQLe@!0 zL_~9q*8xlb)Q0t;1I>Ej6w-Uzu33yk_2aZdJlj(~V*L{se@NSqVJNXMnp$D|wW-T7 zEB>xT+fau}4=CafsIQhZIrZms4%qRRC3DG26px27x3y|ajbA&eUYPZ&+E%Q>3JTa) zz58F*UkVmC51#oMkau-@Jmg@Vn5gKhk0-6a%Gik4959r1Z^o%Mw_X~zn1HxAfeWd| zvM>sFsp++TiKA5Hl#Gi!>@b=-PB&Z<$KZBr)>kpfjVT76jk;fvo#*_>UxveJa4dJr z=-MX&4P>zFXd4{f@}{Pt1|R1tk6VWFA_vzOE0=38&x@IksiyX|LSe-f)@ z#z5=rljbt*)f0TW=E9jlnkg2@XPH;qJw3?fnF|d-e#k(qG!){u0B921YpYJzkIgh`DaN6eE z`xWjONg`CpN<*Y`LEyl@%W@ok0oHc}XflKG2aoKxrS*J0Ra>o8gjtcB5IW2*rfXL> zHpapD<2@#m@5>&ak{$be%Moz1EplVw(M?yJ*t%!=67j%_{?=gL+M^D&T28z)0s6BwWH}EAC?e& zy$PWnFPwb7D1tLW4NRcASY5|%X?e0eaavbWQlevlSSCT|laxFSb-Y+-FUj)F6)n@X zhu^Uu3G5NyvEvZ9s8={Uul8IpHa-Y`k~!lQ50ppVp|(AR zyXla!DU0D2Bv$UL(aiE4PbuQjgiYw{Coxa6nr(&e+lt+{I=ETh4cLLOUXgyvHgWNq z?ADO-R&+s(uXz?poj9kZ6$4@+GPfXpHpwKxF6T>#wqdR_4wx>cM+yG5s;3SJn)44X5I_0$%%uVR!ERo{Swnm>%ZP z!P(x~={KHRsO^WU>@uhQ>C=HFLFHkun&)3U#0+t;9VyT=MAv{>%04lgshz;?*fg3_e@VhcFPFHoTs#b9NPu7d>a9{k@^%q2vbAUIG6w8_ zicA^2tuAels8+x^oa8^n4~EbO5hgfWR6UKlXN}{e&+jM{O~>jRvK!f)oa## z2dW|kGa?WVTW-RM>nN2Pfegy^UaL8|e*3kaIv^>)5)V!CEg_{Is65$|;UJGpSpHzs zIIf6BlO%Shcche*-l-->MC`};XFrwMNG`m&fQq58=-dm0yK;hXI^B#P(F*zMJ8L)j z>)*mZrEgI1w@sV$pI)6B8<3u9?45sF_`D77cvLENm>}`{?f(mY>dYiExfqn>h`-}g zUT(KqDH_e#uRgnXH{e8mc@XDjX8LR;OM!L&x6 zt9HVnlG6?aU_Kmpi;aP42(ac!F&+_tnae-?jb zgAP8}_}`-gbRU!&R$(xYm_Z>kP9M@&#IaEg@t{m!ubH{|Nptgr5_2@@YVcNEa(VYD zy?cX}6=RBz%$i)aa^;@BD`muNGtl8I=;5eWFQ)putHV^6lgE$ix9I8WCW2x`^4G1T zsjzz0swgNQtm~0rqg{Lq&jo%zpMVisw$viU!ELyV)El+=4noJ3g*@5@^w@AqCbkvA zLR+x)^Oh3#04yUop!toSO*mz1V-rY~kSatMRuqs^{Uz~&qN2I7V*oTCjKj5EN&^oB z*3MTy3S%O;))Cp^hq^AqC#$dpL&`$TEG%kJI*8)-1I9oS%GOybonK~|56<{O59&5~ z`PQ~+^kB5koqJN`&kq{UrAzVTrDhh9N&;!zm8CQ!^~MN-2EN7mDP5U)(+M+UMe_?gH`vAIv|%C!Tvl2OE{o9zD8|E`)?h(xMKOc*M%TF7lj% z6+Pl77C2+29i(j0_#cFEs(=$(ma8{2efV^&@iQQG1i%hI9;+?2bEYa7aEX&=*dM9i2{*M~3(! zDM<_C*t$=9J_hJ(c@lwm@J!uaZr`OkPsgCDJcXQ%nSKxXA~IkYF<$a$xk@!kt+#=& zg!lo1-}J}QrSR~32o1`G)Ysvwp(r(h+GQJ#5+LA}JCm~Yb01fmR)chx0B92x1y=M9 zNIlwK+4nVdTdh|)aA4e75zz7t0=czcmh9{5&m>0$O^vRRl_S6Xl%{4RP?eS%o}~F? z(kUGXMQ@<%Rt$xK$;F3GJ!2)MDXS75vLxs%xDlPLScLibNq8Swj{n-9!ae8CHI}&$ zjstNK)4#<}2>)d3LMw(itnu|W4%Vr)VxF|G)#K%D`B77 zitu_(aSljb{(K!J)FTvVaPZtNE^c>R4++J!Y-A7!wQzT@#_*6wVPSoCdN{q&jkLuK zOc4f-aUiA9SafKzY9Ow6{Df&~1CSAt?x2)1$Dmg*N*_d_oFNwuxcNa8j%@S#mj_to z#-5VApJ3)ChmK>&4ceaDy$YU@gOR{6V}d$aQKYzS&%no<;-+uFUp#PwWwLotCo4+>b zj^uA}E}${fg$mVQbfp>QKplmW2wK~8Ocnu%<44O(N>4wDCrZjNz&>5WQh2AYIOh*X zVobJu%a#jG?N126WZv>PIQRuV@8G&SDL9;7WMwsE=OMKLS}tYZ_e8A@LXz#>e5G>N3Vet=6sNa7wf3t`sf;E#$f0 z>_lxthIxny=1zm)BiuJ>g0PRq-w-3U+?TcsPgi38o$Em1!%RPV?AZOHNsK*wig7wu zWgPTv>hP(0=yO^-O<~G>BBI~BtqjE87(8O{y?l6mYxSIu_2-O+d4;uTsjK^7UFleW zRPqe0pCa#*_=dAL{!`Sq25f*;k8{h4-Uoac!ZO>SC9p){$A=-F2PBt#{P?gy-)iqU z$C)Vy*-1v~6-jPKMoQ68y;1mU@2vpta9UUxczbzSH)@_fabgReP*qhM)b$h!$1<`3 zLz4ZY2$JOyfsh@Gv*Cda+-=CB>B!C;$hUyR9}L;Qfai%xN^S#WfELyc>>G%Y1*qsS z#4X{ux(`#;av63s5WR;1>Vyn_2fZ{M(?$oCykIhiusay+7zsHM3FKhHJq4ExaljP0 zjN{K@eoKcOM5?Pd$-VDjY}wAwuY#`xy7Kb$E=2Z9e0S+5E{DM4_$g$Bw##3xS@*e>~T7B-QS_yRK%Xyq1}J%E4wt4+n|eems` z!1iCo#YNDqK&PQCCfE<4MmOZS<{{QULYPGSRt36!k4!uZDdkgL$HDOltddA{Kf2-C zQ4O-l$BSEIpFdZ|20#R@LZVUBTqPkY8ijKS<08CKeqL8~pWpeQ8R3@OR-O#I>;XmD z16=t@R2qQJFB%#KmvGBEo`6Hhi-ZIm9-(*~LzpOx9k9v?LpH$9eu1w+&4gxBC9Yw! zDmssqpxGkNeufhi)aq@#ykDL>O+qf0fWsJ75IYK9q1a!M4df?yc^B!FaoXWiI?MsH z;G;0#)BpyFDJb_pPSUcn(g3&NU((!kU^oC0!MTwUWQ03pWt+KO_wT<^(gR15xU{st z+Ujsvfz`&RN{a2nQuA>dMOOlB#p-+Q{6?j@S@v?Xh%l6kFq-HQCN&AFlH!JiN2Y6J z4EL;)WmCMBp}Zu5pB$_hF-*99LrD8S6c<~a&7jfFVif2JAaq;Ee&gFPAJ9^@6UY+6 z#T8AmuUrW#*SCRhcPgm%sOQ#8*}U%^0EPH92+;j2?ZDbQVQTt4&;V~n)6p>tQrsSW zJch=X0Kh6iV0jo45(iQf!l((jW*Spq zK?rGrOTq9d8wi)@?rbr+v$$lemJ@IwA%h17rEF30;_d92OU~iOc0h!T~N ziH8aURZfXTCe1Ch*`hWk{Mrk6hvQU?!&4*0!rml!bt=IR1(`VjAKd@oj=v;VEdyAx z96-SM$vV}|_aEQ8_Y^M+H?bXeheF-33zfhFxGp>g54@nTaEG|~DJ;ki-HiV5)o45a z2@Wy-tR}nZ&R{xr9;xTBd!S~)T8fQ|dKWjkA3)8U3ySl#zsAJG1U^l?qj*&dI8~pA z!?*PG^dN;xE}GeArNSEg7f$hOK*=Y~678&>^}r1&7DAUHFYT zsE2Lizx=1r^0~a9zg*g9u5>7&TYxZ(N`QYqUfX5{(3piv|EGQ$oJ`)?(^bR1_~Jyt zeUS+V)5Jd2kAFRMW9Dv`y%R+K|C-e|@33v#G|#AHmP^RpzAZUEhXHu#;1BxL1-b78 zDDDluGW6s*w{+6>?gPOO&UiALqv09HM*hGw-I~1IgwLpk`(~y>y|x zX|01>lagZpU{w~su%_9v56-!~3QF&a?~@oMz`*DJ^)Tv^x+?ASFJ9vD#2!5nx$mZ zrin~)0c)vRH5IaZVtnaI_GM|y@a_KWJJ?oCpC%val|0$5Wu&6<@Q3ZxqO9=nj(fW{ zJ=>s$b!6{S_sG`9?_A}#HLP!Eiu|>P~#@VCQ zFIE?%8`kC6C7fxs8+nmsdGu_eSV&2;Q-;Fp8lHL&kCVndRSP?lLPkR~hr1)Zs<8y( zOdSO(S(nGXsfp1GjS~$xt9v4Dr|h)py5yebV6KVAU87dY=i+N>%u1!2E38%W z1!y^qTl=15?w(0>oT`Ftmw!gw+H z`)aEcZA-1zdt0V|4xOByQo7U7t0+}zs#!O_!{vBu;(kxX*&dsq=ND!gBkEjbjy)@j zpl%hlGw#D*+eWJOj_^)A3!By53sG^+m35H+6LS z6)pPDl3g_qhc-3)2X_DGhlbsfbn~0#9xt(7-PLzHgafQRnyt0C#I~lMp8ZjJ5pOH& zfn&nXSgrnKMfp;JiiaQdr?;e@u6DWA;E+?jl@XSEJgF~&Iz4GAFt;|gXP&S;k{w|hs3jVk(P|+usArwn)qa<6 zI>ukiW=c6=rt*CCkyN#zD#ps`wmU1QGoKu99$eU;!sRknUG;<(@_}1gNh$9U;z8d; zGVM{S{_JSb9z4pmyTzx&McOC&Uq?&*)f5{>^_=O9jgweTn+?%QtYgkD&=aQ?eTf=N^ zj&oVNvR+Z&_)F#C<`FL&KcIKnzJ%&5;R&x#)_WLds9YKH3h!D)$2fBoGJqKvR@ zv7?eP7V#xdUlrRTcu$}D6*8W=I(*HW8Wud_ZOdV^%N6^`wJhg_Yv-3eTO+3%!!-h}$|D366?ulfRR?m;TgtCukZm8tDP?=GS?9*vS^aE^)jkHFvRBYb zQN#NWAMWmcaAldgi3!grqlr1ND4@G8$*L*C=FC9Hx!TeVL07hg*E*}ycmypqSp|YP zzv4}VsVfxK@s}*t#MU57O`2d3r~1XP1OJ6TkUL+RmYlpqBVk!-X(?N=BwMkM`ehBl z?Ck8|=})Q8qYf}M(&;yE-!8V6Dsq&SCa)M;wC%38BzJhRU!Ng)GC>1Ic23SgQ`403 zh(f%9q}3+8*N?tFzJ{U9xo;S6$r4~$PJSe=?dm$19+z{I$`#668ey>}*kVRhot8j9 z$iN@h*j^^zI)T0oFMYdaQE3GJW`!Tz*|wa#{Lgz>ZCs)FuU{_POO`B@mpu68s|Oh5 zZ+M^JwSw_@OJOQ`UTKa0)ep!yC`2uonGg-)G%oPVYwawLi^s{y&(^9~m9dSFkNafMHwg)i zDNeQJd7qga?fvh5Nu*TwX``UHI7d@cQ-+2A?6lnZ^XJpg3|ii$o8_KaW?^A*%G0wv zXc5;ySEQ;|@lg|#tG8|iU*Zya-O|DnCFfEm*X|>D>B!Ne+`4fp;pTq77t|%`l_wiL zO}DM){_^#!{B~usUcPt z`!~@o)7fUiO_F?d&R#%rK!vJepgZb5d76v1|N%Ym04kUJ+)tYZvqLqp32H z-@e(7|Nb4Ho_=66b*!(o_@z^e_0YiJV9|?{jql&Tryu~AtQOx}+}zwO=}^1zF8%D; zv+>#4N4d*Is5RQ}$N`J6)azR)>R~HQRzI|~#!*&KUVd$NcQ+n2%jdV0?b|y{&zi)z z6rVL+Zf-tmnnPvJ@$4`A^vX>js1P4B@VRsetH6Q7hc}s&m4)-zSY}$5E^a!NOqZ9Q zTeKb5+fK`^cp@FOg}Nf=pg48Gf(7q;M(j_XEPk*j?9`Vx%kEU4rcL%dE$I0EJ!DVV zs?PWEyRy8;#D~3<)68;$$?B=Ier#x{y!BzSGo(J*NO04pJ+hzv?fGkL-^D8Lx~1^! zE{;CWSIfq>Hjcbwk4ygUAc0lWYky7OzdNd=_`HNr7^l8CmYk^A3a(qa&s}B zC8P7hhYwP;Noi95c)Mpu*Cy)rp<6zu);|9WIQHQonrpqQ=^J<6mpwlSTq9;TYpsp4S3_`KR67 z68pWvT8l%LcJ}u#O*LHN;^N|n<3rAZM#4@fr>*}aC)4adY_8z0wN-dMUB$j zk22Qj%(HOr z(qqT&j+qP0h4)Z9=l{;!@SjRPTSTZ|zkZdxs~y_UI+v1~t)%WAm*Eci_Z;it;ZbBS z^B^nh4oQl4^e%p|-)&^n_%~O!vaXsd441`k{K=f0C==r94ss;Tk?Qez!~gxk|H6`l zZ=jvDw=WD^E%E;2$Kj^iI%G}Dg?l$6$k$T=0!oLw>ujoyWmqq&tgJMZn$6Buh*t6C zc4^CXt(emIDK&Yz^YsE&fq~)fLrG<-o_*^UFJ2t{$^i9SLs~0mQK@rKSnJoS+wq3U zH0M?Y(*i$Uy;!B4y1E?dyLK((NJGF0W(PiB&3T*u<=Zz7EynYs zTbFZjh5WbgHb2bF!()3{B!A@7{E13iI`Tt064j@CUmlclRHCfYUqfY-R8{%$XW=bd zu9nUIs*;HRU{BJLOaAYLsi~>sy_xL~lh1Jp>6TR96lJ3H_V$uwE_wEsHL|dPiV9zU zd%^8*1*baI*D0Oh+_GiMz^`BGXU^>4Q}MYtHRZE=_ii=RsjXYtZJ#wgVoYzXbCk70 zEn{7@sOaIo>sM~wS{PP3kD|{jaV+;D(v7_gcS%V}p|zBNpdfQmQPIWAmv>XCvXl?Nmh_64fjE5)8?pa0oplN; z!5m?vuRl*rc1ivgVT`rGn$+1P9f;(Tu}!@6Y2E?e8pSOC0hb(9>_o6@v| z1ZIU84zA7Gg-GRB?%rL5RTDGIUNJHD|dasFI#=?8-`pYrhGLp4?bvt`N2 z$pFvozGE@1Qe$S1JZ2iCnAGq+3`ABUwjL^^nPlp6JLmm0I&x$YC5zg7?|FWTrJTo4 z19uM(CJN9Fs!XK3+c(OUuoxssef{Omt=XHZ{l8Y;WL>=Yn#x$-${hD@{h$jM_VwI< z@nR*`qoSgMqfuTU=nC!993U;S^!!@6l2zc;%+%Q^i`Ldw)V{z{OIKkkg_DP8iGY{0 zuisF$T-Mp4M;n!VH&rS00?t@hMJt_^S|x7EdS8?AxvMMDLNj9BInH?iyOaQ&97I1N zsyWr9-6mGW_b9ijvNA7#hj9*dYY=Ca*T_ExBBwQ8e zKjV-Yf#j%h>QwshZ`5L0%iDMFZZYXYaK!6BIZiXSwlp#`3%_!Ob9{2rs;ev2`{ zz5Dpg)bEVn?MMz|{q3HA4!_Rd!>>pY78Wkda_!>e<_?XHUZ>-C1kIQr zsV#>d-A_;F^q(GCeLgU76K!&!lNo0jKrX!Tsd++f?mBbdk(Ef|3W|ycj~-nt;58AL z=Qqv0Dr`Y~d_2jPNPq|R^*1Q94I+jpapF|p+f5A(!G(otYuFa%dW|ebJY9^42u8L8 z^bHoHIy*bRsj1P}vuA;nw6s8wnwOUXAgSV(iC{ zA6I;hP&yJm2rD;rpI~gQLz8PS<5wHF(2%C+{(}?ebFi;fF(gwBEzLng!_D5^Zby#X z)xN)VRao^z|BoMP`}SRGE%0*t^SN8+&W!MK#m`E4r4c}AzfDP80^8nsn3l!?I9!OY zb3=SF64C7c9=sNQoYwR6=Xs<}SJ!Q%36zYxqBp(twB5f#va+hm0?<@8YAtD_e+S*s z-n=Hf%tF;ulwhG{B2*+xVR3OoAI;+grqZr`{%q;)>AAG$w+R8G;Rk5UYI807n$?f8 zvd+-owG#C6w{xFe`Tu2C{+~kL;R>`IuSxb;B{{9QD)Fh{%B?Je8RLQ?Iv%xS{O!5B zoNQKB9$VQ}J-8&a-*FC_eXd(wDK8ClI@UeeNjywrL#$7b(d|8Vaym(Ou6JOk_9w$Dub zW?d{@)8V^EkefT|gMs0>?8*~LZT{=Ne)kI;{KZ@9DLcnp^vyL_x(xBz(RHg`3d)l+ zH?Nq=UhX0_E7zAc$-lz6HG=E*;)643%j*?&?=#xsvZDN0%U<6O?YAe-KO{fb>nYHZ zlU>y6Ll!a=rxbtrEiN{Yb>m?lS!UAv_H=w6Ff z*BW&k9G#84rp?YB*?mr*UuK3Y>@|ztsmZ%*zt7sMe|vFs-7Ed>T3#W%6X4L9vA&oa z{xiQ>o;-Q7M$UQNv3wu-6vaMJ7wd!6%*d#xb0+v*nAci!5ur+JUy0ozR9r+R8!~IuNT0rIAo*CKMwR~@8VJpcIwoxFZ&$m zL*L(_VCm?v&rA*J0Yc~c&mQCU>uK0ZP^zu8OQ{r?ychKAIYnAAP13v)?$uHA3Qy_V)>GDr=9edGn=Exe24gL3--p#z(v&(FI=&X2QShDIXcb2!6 zmFG1QipaV#nx3)v`T5abI`O=?e5aB-#Fxv9-!+2O8b&RL%AGexhx_^3M zz*h?9nh+Tk@UyjlBB zfLRW;>0w63@`9;fOLFt_uHv+zE9*f2agAn`py`CJpJ}~h{@W!{9i1OP;T@|fy2aMX?T82EHEYhiVvVWYW_B)~6-o@FYJEAd; zp6By>xjHL~;RbYwXcp8?_7qg5rKFVHm9~4|))vvxaU7{&UvX$?=tf!&XfvRfd-v`= z>;yn6$NBrv)}}j`{JP&h zZCXjM)Ng!%3EdZvE%==xbWvAhVP* z{G{kJZ%kr3B9gz7WnE@o9xqni-oMnu4bPc>o=NGdySfK`SRa{u3@FUnTwm7+cDn-R0CeHY0%N$KK)hRQ8Tk@|2w3f zMlVLG{6B*7{!bOx|4VEAFHlbZKk;_1p=eDJVq47E&?tWR(`TRU zSLD2%)jf^o{ue?*$|Y|;_n*hiJXoiv>O1;1!b9czD4HHgcLlS8-Wfn|G%UZxYy=9M zUz`M|`+%u@3&erBE|?lJJJM**seV5t#c@aI_&ym~+0PRrJ@(GdhS|b_kDfnAccSDy z`ZjT>`rSLvtkfGy4Jy79AHRC=rT&X)>+I~z^6Zbjfv!Mc+qPxutfpC~in`Bk*+h+! zbyD~9o3S(RGyd-8^zPQJRp67>sralpeE2Z6Jf7}*tSp;;q-tig*Ca7a%075MBR4nq z6e60b{NOL+9P5hZ=%qz67*~Vm7=Q(qa){!negOMr>((hf=H0i2CRkkjy*U=`JiY>& z(00%PajQdH-|X2(JG4BswcyV~icrnW%s@1}M(=CWZl3405?mDIor_^%#pr<^T8!>q zFCnoMJUr;K*J!U?#|JC`k(nudZFx%|141@@^UXqXjkQo9kDT**l!8X6CGulzI)tyEEyn3}3{2M;?{L$24G+Uq!5<9=Yi!0Ce=s93) ze34E!Cd~SV4f8Tx+WAi9$Hc_Y3;b1IzkW>^q{GRE@z0+daKAkLRZGk~e;vL+txO09 zuezh77}7e0vT4&M3Sl`uZX+USw^O_;%yQis&7#^T>x>UMo#_!!KW~-Ko^i zI5DhCmxkQFy?T|zF)@>OOIC@g9XrNH?QOn*D!*aw{Q`}Zl*wr>MMLPA=d2>*6r$!fxwq4g|7*?s77mMo5%lGjzRd3z?DgEe=KWwq&+!?Sis$<=VB+1~KPidtds``ZX!xr%ZuG zl4Y8!*ez=C%6^n`)9~PPn@h2 zW7<4Gs?%DGnencrC8ecB#l_5oDh2sr)5ZR=%zv_1E~n=UXyFWnT$EE+S68A``OggT zW7!_GdqC#h2__N!DbamqakGiGh2GECu zOZf4_9>I1%wnlA)CPc0Is467HLXMZc4C$y*szUqvoS*bT?7@2g^`V?mtJ)@wd)~SZ z0w-P!4=)A4A_WRaQBX>1xm`{4)oRb0XnDf+I#v>54C>SC1`>+|)W`vffGumLeBK;$y&}{MaE(Ay=r>A!Q^pfBIMoM|>-XyEm4nl!QG1VO z<>c&VNzC7H<>pN&LJd#NBSB>oY8X(l7&;o$aP&ivVD8=5WOPtlgE-$*R9wy9uch@G zXks#TSHB-Ws4@~T1Sk%D({XIeU8{bPX_FYT0I9sEIw;OJ#xtz`{&5gUsi>}w3n}YnHtR-T1e`)HY;KK> zcv+yl?!~$D=jRc9Or6zdvNtoMw=D|NS#ed>5|HB4&VdApOpOoX6EvKi#UuDtIna=$ zr%M8IP}Gc#*T_0GZ>%1p)2u+Twq|?OdVa5o3CzsQY~^1rFE4-KiGdUo#Lj`?VX*5j z4|%+F&K&7!tokial2iu$9B`RMY3NFzpM1OEKp|!A-rBu(R*+CgGY}xW9{cJSkQ^& zvIFXgZS}nc5)x1S8W+76d=J4JW{lFCqDGSbGd^d$yzu(6ClkXf743fdLvjV{Y*V$$ z6w@x*rU*do4TD5)UbaC|7r z=g|yX8(AaqvkA<iYmCxsadA`8OTX>b#?24x1yq=oqc`c^*Ljs?zWR-rA@LO zj8tRImi4l-t5Dyi1iVLnt~3z2Y0%eSFw2Kre=AsM<3{pRue@Uu;PO4D+kQDXI|pkd zTulu@?k|G!9UdO8+jv&k(zBzG3F*11J{g5hJyCz(ugcQ03_>TpU-bcRebQ69Ja>EZX3yT{O+0ou z;H(@Rw^S6}L_yKZHw&ezo=#Ccmg?A=y%JnU?V#Oy+Oyg*Lq@*uWJhoB)|@Wjt!+`$ zC&a+D3a<@~;d&b-w-o6dJ9aAr)l2MH?ixNmzS@YHA0Gr+KMd{9fgz&uLxLvyW-F@% z?fHG}1xp2jv>gNZuIeY(*FJp_$g)&R(FKPSkOw-AM2t^+f&Ws0`68mC$gS<7gfFJ& z`zppNovrQfZJBwTl5!)hlF^d6RP7y;cEShxEgFZ`23e}+Zg2Z)yOw}wmU8c9!Mg?^<5n-4|HGkc|1B}5X66XX0GY)Z7D~$I;gG9c5ADNt#tqNufPkmK8VPUP!I<}c=#pxk22QcYb=BtW9ibRM0W*G zznL1L8{~VWz|Xg!r?S1>TsCdQ$f@5X(eT%=Uy{HKsN%)I1o(vQL07`e%y-hCJ6zvr zXUMn|lb3uSvd4|GXPL?@%`?8PFWG%6i@6${4j39P6bRB$<-M<&o8knE(-O4GC`h}G z99fIzT5Q!4+nVT0Fb9EbK)AA>37ejooyO8$dY+W#gVt<`Y~i|Lon~ zy{y!}PY%-k0Me`iunZmdY}$N%(aDCCa~cVd>du`zN6&QO7h4r}Xry~9wdS&m)Ai|* zsAp2xy^j&7gGg_VWe!Nloa)>z!j>$2`T(t9%kT4< zFPQ=N263L5p4jf(p3g2YAG;lbN*ILzxyw2QLWA@543{hHU%)Q`!$+W&1J9w}T*;5T zc(D+9p5`@j0yW33P=W59sqg722P*Uu{8Bp;J`8*3q=OTRjg2*aX3MUnrS-6C0(67^ z_tE%^W@r#lczV;43D1@bGs1jGgCHR}A0#Ebx{0;|GTGa=+TEijun7d63a5|wsg-D* zJ}pHGtC~2q#&I@(N6SJ}0cr!+p7!g^?*-@OW%`4|Kspb>;)xljQ`FvV9Yhp<2H2bK zTWSa~1e&8ONIW1^PGB6p}KdA+uI^FGAUb>dWb!Qa08-3Aj2%5%5JaTl|fnVD6( z&+|&1aUe2U8V&hW{n!LlbQsYNU6gbPk|{@?5hKDHRX?RzRez5A-w(^H54-cw8pT_h zn;ExK3z95Z+{Er}KY6RQ#jiYqHxOdAon2C^jmfsC>NCSXmR-Ac4UDmdM)2S5^q-#a zU=?uWQ$zXCfHq@L)45#n#nG)fW{ZcF?r$t9P*rElRfk=)9_0d1l~4qCCD%v%PWIHw zxpXa_E?=Z(c{@59#SJ19+)oQ2I8Dt=_Gh@J9m@*^j!MYMG1*KAsSH15!<5WnFV(wu zu3bA1=GC(KxkGK8F4{CgGlJIZ7@*Cxu|#2)TR!>i)6wZ2d%=5K+zdyHy60(XDm!*I zZX*>IHhllw>ePC;@jBjI6|DVUQnEWJIQRixGB`MhcKa%a7U_PCjqf;4sLoCuqSj8X zphYQrzjTbQsnG>$+9%Z7)>8L3$BLG4P>AaeI&afJS(yg-?`Lx;hu8zMdhP{MCH-G)-Z{JspWX|459LvR5x|?^BZp(0{g7rJ!_eHqFw}#Q`sHNQL}1o7}_ zd&JMW%*dF8K{N~2Ee(~#6PQU4+0O{NGFHs&H9=V{@Nni5(sKs?Bu?z)xspDR6d5y> zg$1f=8SK)O?L_jqcN-fu3qeIlzj#XL@@j9yyMu<^>Di4~bA9T_~NQ-2eVF{`T$L?zQ{(?+;8$N*b=3LYl8V$t`Z4e>p8J zO>ep4O|1){A08lOXe1n5e)c5GY<^4KhtbRsX{W-&mY#4r!0!O`g!b=qYmO)Aia-D? z<JlTUIK< z7z9@%8sjdMW^lXZq(XOgGX2dCYVTI=fpG=LuGzFm)q7M7TXq#|h(xzy=B#qSa7LVJa1`_!7UL{LS20xEF{OJ?h^Bnz(jwG9VB|-5yZlpa1At2Qy{3o)?Vk6 zay5v{xBRX>-PP4aC}+^Igl{IT6f}dSs#EL3xnRoz_~^i+O&@bw_YeI-P*4Zje|tyA z5-cFd1X1q}tG3*;tnBQi?f$dj$o%VIlxk~h%dl!7=n3Ko_%1db9i1Ii#u}7E_!G|k zWxOF+qlM;hQH-Sik*je+{kLomQbVf=mfI#%3Qm{7YPt5~D0a0q_pV*r&>H+xbY6p} z`H{(MXfL3beEcS2sHw>U)Ccp+O8mBK=$26x)uWwRsl&^l%o|qv_z6noOPyC^z>$s0a35- z$h$o8(sBl6CjHE7yx_Ikj9zDryCvO$eR{`fr4zE9^kr^9&P zyY)y33-5gyH|pDZS-PiiLW^HuzPkc1Ds6Z`K!BgQr~a{H5%4N&ImvI_I3KMq=jXbT zn!B>jrCwFF6UC3^kSnFZs{k2gX3D`q$6^`@&jmp@=<69f6N>o4fQZkdwSF>%43q_j zbwSkvue80Ru^Op{gtEzax#NH@Bd@&X;B-$<&sEF-AW{V8fBN((-Jx!ClVUqkr|65O z8D|@gJq&!*LnHAcJvpf9P3^B%u3Dv~>PTMd*dzr?NS*q&^4+`J%^rS!DsX}ff{%fv z*X-!+>zj41wX$<3|A7^9+ThqY#&4W3hX)@PQPrL>K^`6+;zRh@*r>SO&(~KOjTd9} z*~5o#7AIe*dEd|=+p*t{_n?{C)~Ni11gpZ3ozcimM%iZeQg;^~&M$KI?-r{O4^y>-#oM}Q#pqu_#pZxBi&swy#$fMZ|f5{jyv>(5z zihIvWeE+@?M6UnTU`W-s#<2n&@7blPd9%vA94a32S}(U4buy~Xo7MNN z{<*;U`rB+|s*>-7!AthZN!8D^2=a&tbYEEwtGg_LqNOzmd-(QmsYI@ziK4s9^B#K$ zXn>%s$afo_eWVo|6c!o^y|^XQg=KpySU@nx5|hr*yWfDVx9E;8uD7(4x=U=P-FsfF zP_$X&VA+`I`wq=38okG$F-=UOS{-hQ9XSsG(=A=vS0J$>NAI|dR;|6*(D88>&YXOp z)Q%{Z{Iwsa%0lT|E+m(xN&J1I)!?{r#+L5jC{1G_yC=7}r0;v2e;LXs;lba=D)Yc$ zb-P;kh>;PoC(K{CaD$A@3Ow!Y>3@#Gbc7xz{bZxKcJz*AsLI9=cA>}FRGpTI`^#jn z7B^J`GYEl|7({DpYj@sm;sg95&MJ`Eq)!14S2f|bBWEgq$3Lqng#IRSKX_3eUtgNv zwAb_J&-WH9DkxmJcP|ua0|;pMo;?-L?~auAjSqIgpLIW)X~h2aZAT zbwMDwD1|5*p#9(MKh=N{NAk+z*wn0FE360pHN7_X=AkZQ@-F+Dc z;pWHIVEm*Id?o&|)+qth!3HIzb?U6z0Puvue8gklA_0v+KtO<4GuRdex}P?AZoiDU z{LdP<+&MOP9Dn2fGACLoN)cbDtJ3CxAfQ=Okx1t%7C4zyCh^JV?>x)z* z)9LjeKY|&3(`<9_;4)D7fYc(sMh6dqsSj8!ag4kV=xA7~nIzB9o*9dgR_&2q90zg$ z8d&=CWSBlXz=Mzx1~UHv3Xf>`nI+y5<=L@FnvQi zP%l`(K4OL6G+aN-K(j##2N{>Sdi5$)-OG+gd_huJwH$~jZy22(AGCt;j-W8Cg5(-D z7#MDco50-*NdXNtKp=jskrOdx0YL0Arqjg_3P)u0E7-vh+>rY*llMoQ7# zldZ>0$p$dfgqS2Q%(#a&Z-qb#fC{*y;;WGH>>1&rNmPi4oH$_fQWM1P+`N)9fr!ta z%aE^w#_&d&tL<-J*GI?x4Dl#Z8Ke(&1&vC!3NR*5CJyr-#W*2gO?UXuD1H9?x#Qcn zU|`|>HcMb5G&VLau<-`JK+MDtEMQXqOiq8dI}FKzuz&!_Vp*A991TZ@4u-K1J`-Sa z;vNTm49DVCxQ5@n*^BUjFv&zAVhzqe=>~60n3sW3CS(ooZUh?E3s{UIAt51V^78GI zSpx_jd(NJH)oL+XqWhPx?I&YNkPYUIk8M=4cs(CF-)BrMk<+83q{PY3FQL=*SY?#3 z|Iov(L`8)WUkW^*gd&Hs0mkvdR+E?Ln2{*po@73i+Y56(nUKK~;`uw!)>FO+(f?mq zY6);*%;RG}_aM3akKA~`@UT0iIpP|Jop`e>?A74zI%Z+S1Pec$!+~caV4{2Ik6j0X z-ot*xEDKJ(vDhuWJ}bE5DLA}@u0ysWi47jw?!(FTz+;=?Lv|hfyyuS>vMYq&Fa3xv zXatNK!5_52qy|(t^i8w~;!#p;c2TEoxiv>ly12lwsR=tM7>`rE&D+5*1D5Ys{Ye-Q z!{m4vo-j}b(gp+?EF0?-soF;k`>EgG(wrWbTlJg<8F2+03}-Lah-|PW?M;~zT5b)E zg^zS&LJ5q+;URMe%|542ohoqRqrk)RKS(jk+M5p*eC4V5OQ;0EorM+0cd5)*g*7IK zvsU*kOwd6=L2vvL^Ue-wZ060+&nF$R*|~pGQi70}Irx-*4EvBH`t|Fkiuvz{P99(- z5Id>r({1b*X?_L&alX&1 z6b>kD=fJ=LwQr);op^E0(MJT}7^QKJJAmiYJ+bVd?}Q~f5=2viW~5d-JZ2V1<+aq8 zo}vvOUa~OSLwkMCzoGxOv0D&X5F`%k}kHQn9jlbSjHrTlMRxRoVL%_s_8}Dk+zF) zj3x~c+rpfxCiG_DPCqm?Z3*Xx=XNr_KC1J?p&H$;$9{-`b1(>iB}wdbY0tlTvwEU< z6l-;>+78VN#LlY`t$8gm3CNm}<-WI>eVSA0=bESRdRW2-etq5V5DiUD`<~1qoCRia zmxq7(Ze|2H3zj3SMC;I@>yAm$s{Se%mw=2dydTX^{$!sbMcLA>|NfmTR|3FG)OP;{ zO4-NaD{9#NBqhZ?`>pRQ|5=qF&WsqIA6JDy?@U{IJooY5ap-9q@<}IZC?Vt`g-CYLqNWJGC{Y(4ie>8Pjxy7X4t6Sua6^R z@|>3LSe1hYhomiAKVah!^dJHLdZ&FiZGqAO4v_NRt+WPCAt0D?h#-z>mvZtn7zOb2=tHNIA@@+9E1S z#*+Dz@ZLSftmjalTeg;;da=bW$6qKr zTl0YgcUOKD69~G6Cx%ei1R<8{@EWEby+FFitlX=By+q*RfW~?bEY{8H(5FwIK0g#3 z6f|t2(WBeoJ=Mne^y-j8r-C%U_fpnjm8&~UzU4r+yTI{|b8ec(s=2?FVNoKFEF7+RkQM9XsHbu`3#{tM4-Jb!zG`HuyOyz`V zJ`bj(`GydRtvV~o!Yx;Qiq0>qjkyb#8&O7yKGh?d|w2OAX z$*lpgDp#0ezJw&}$SZ~?OfV@=hXBMcL52q~>p+zc<~&WS>vos5N!PkF(m-ve%Dw;B z)|gHX?CzH>@SC3S>ygywGv*fiOIvniw)+KgzBGD(rqOy@5a5cS&N(W2^4;%=39U?1 z@9WXgV!U@^?nVlpb$$7Ey1u@x?$BRq`cM^UqLEN=(tz88m|=VJYy<`jB4kpOmpW<3 zDAe1wAzNYUTlZ$QS3sZlytxr56pqTDN^58*F|f%w4`1V%$vf~|`xsuH4`vObSLUGj z@nDDK`6xsO$EqtFjynf+`rpXgE6&|?E=A22zEfhpe2T_EOlDa?ctI_)J zIPo{l!O|E#vS`hI6HgQRmlwc;sKa18D8owgpJ5z38U{<~tvAc2SI}Bsxh1tykARgE zm`@z1lwDi|Dx(p(|LhqTdbh-sxFhDle>bBQ)D|WvY;Cos%g{Xt1er2G73lD*_tb0k zEPegoMoF+912oMtK0fD6ju$Up{I~f{L_`E2-_dVh+bcH~^(pVQzBuNxM%NV-6iD~9 zV#Nx|k7YSv{j18l8I0Wr4qSO2C@;;g`RlXe-O1#W{eHHT0V4egJWQGj-aw7`X`@_t z?A7T#vbv6rDek9LeJ5lfpKf$D1UT*+uGglZ%gE4Cz5j>oJ)(N2D3q6iJzJSW?Y+h> zF~_&A)81TX$E679y00V^+tz&1tlv+rA!D&Xbef(yo|w#+M_s>Ibo|QhM97%WNTg)C zc4+`nHY;rf4)l4_EAMvAB+u(b_12<~9}Ui&IYa;GxjxOjAOh|SqUa-KKoEu_h6c)* zEMk{mDBUdU6q7og8b1y@Ie~R%E7yh6A%yQr_&`RVfPa~(5Bbw%zcPTSj;wEel*86S1lC$qM|A3x}_AG=)Jzfy{Y{_^HZCr+HOCaOIPX0g_uIxDy` zv2}OF0Y)_O9l(@@{He3!!I>}{(zJmW{IZXpCI zD4y<1RY;3_>&T=RhHi+@8(dM$@*Fa00~s7Q0zhNih1_pxWtGUBs!WSg_0J#Xz7~I6 zj{(1M2-*nZuzmdGNfF9eXK$~QAQfWr4sfU-fJjva2V1G|N%0>&bBJ^3Yp()cCVU{I zHLf^Vf}XW@QM=azRXCs9@_lt z3LYYhmn?yo_aF#5^lWtZx1PjI0Yd>kFVXJ=G6~jOcIi8xP(px%<|RES8GOfHq0z*g z>cc*+!uKT{KhC}pgrN)_7ITAVR`ZQ#bvyns$HfLp%F2XKMnB#`c<^M;KRmejJ_ac1 zfq~9l#Cr&wF)%W6Q#toTPOH4zTfU!zXN2eEjJNl;FCm`>_;JXo&60Nf*O!VraxQ$w z3jD$$sF4mEB=_{_lXcyHq3L|ES$pADLZ2fL6aa=8q_9)lPWRav-|qfn_+pSJ15oAn z7yDvG0iMwpJ(+@^N49^bn+(6*m(nJwmgFAveh+63!u$>Y%+2X*JfU>?Lr*aj2y@vk z?pWmKk;vxUv(f?n?YnHv{6Qp>3nlJXQDId;v+JM&vz(fRMZ9A+fPhv{{F5gYTWHK) zv9Ct}#wr15g}1iE(trQ{ZBcn+%XFHYCY>wi^=tJf{gEiJP=kZfJkl?=f~^;eIUdAG zhHjxATMu!gJsKZ+r%DQN^`Sr1XYE#L)Hlqk9`#aQ(DCUdTCnmPTMi+yJ!Em7h#e>G zwh0x3uj0pYh1os7Z6w^#@uGQ6t{_t6YYWubg3%m+r*7I>=1}*jBKFP#m1&7m1Q?lX zfTFtdVyxdeaK{-esu%-n2>D0cEL-NdS;#XTd1=(eyV{%IM#~=(xs6T*9La_a8^GgM zSYK{)q41Pd?}FBk9h_RhT; z4sr*jR^;r&xFWGZjq&Q{J;9wEla%v-G44^A{*w1mJ>WmImaXR2D+!n+5v;Njt2`Dk z*C#`av$3(s_#xKWqOnZ0NL)4bK1~j<~D<65p+F))faAtoA8EO+Kj{HL{!ksHnvga=&3qPH@Y0&@d z2VZ7sp5M%MJ}u#&Nyt}&t?9k~p2R%kywnxL&7rqOOIK~p^r|;($$o$Se6X@`80)eG z4W@&x7F^4gJy}0*Lr{!}Nad=Ip_#&p8v=`V^YRwHbE|RFt!7*gQi|DxPrYy;M`sO{ zEyuIw$B)OuJlCG?f~_Cf^lbS$jM=RXX?A*@9@S;x`SarwqZy{b%uBjS*ZoeH@nN7B zzC=0eNJv>0nEk|+Dz}wcAh6d)S}`}Yw0!z>89YYSx9z`^PPg5FCvPX~wy$!v1>I6h z7B3!%o1M~}@WcrV;xwG>HoFG72}iQ@yW&}sMFQ5c@zf|u#u{q>W$+mUuPVgoP6&9I zXmjM8JI6$L4s@VFMaOZT&sSKhqiY5!N%SOMrd-#qg~$?{b)xRwTa1`%ni^v?2~JDq zEZ?!5>XNM;%qtM|mgA!{S1@mJUkn-T6qt{1o3zg5G(GX*!$K5@Z|-v{^E?ba%YL^J zW!xycn(lpQ4HbK;IJa2RI~W+v9VlL^YOI{^J?0E@jk0ET=L8N`7iQMsyE+#cxfFs) zqN`9yE9@HJOGTsF@na}u5|e{p;d}#tDnwO4h7%SMxkvSNb8{mX8xY?BriJCnd~;w2 zqI;b2>>WrPRC;paa)$1%p;}p45nv5DyLIr;p+l&*OqXZv$Ke!bq7Z!=+)d}_&-48K z{bA5!qL6;j!RPo?`7<e*R6}op~nZZz1 zlpbzv!p#hw-QA1udX!A~@0vsykG$9^T~7;uYNHiBbrlx#tXL6*!IPX8EmnbNi(a$@ zS;z$z_x<`>1s5NP%37;;ajGGx79iA^D1;Rp7*K;oNs1Nd23~d6EhU>n{(33}Omyc4 z`$0CcP%vq}9F{zAv~Q}ah*a14^QTDI-3pK`;Hl6<5sNv?Qof+DuqA$&^QamFdmB1F23YWg|?|J21!v$&^mx- zAainOhrV^fRYgte@9n+GOLO1In3$O8=;{iD?_iCPZge4frh(Gc=Eu=-K}wxZF*tk} zH!EyE*{~iU05Tpu+XFW(35$y_q>xWTGK69aGK35n7tBt(0C>K6?VR06k(`+T9NkVD zRNUYIHz~0|5=B1qCa1bB*NMzU#m);uT01({V`yJE=Z6Z`3>Jg(!a_=LNC*x0S|rz9 zK?hWOFvo~J2Mlx}yqw@FGF*w-8NP}p(|7s#DiHjwfEF^!rOB*yAsBPY4nGm<2ADuN z)wS2&$V+De&OlmjT?uP=rLn$;aaoIm>eJ4vq^d5x3~)I66jN zlWR28Ss{W~_U!=IpuZ#c1br*?_P&=#(|UTkyNi&b!Qw3xm`~IsF0LUhx&7KR*<6?; zH*@>(`SW?)7J{1x$~u3`FQ)?Ql_DoPjAVVlWpVRxl&-(7v6iYRYszvJgnf4bg-imt z4?Azb+0&=XPjH|5qEAt0y<7dbb@PeJbhm)3SC^6L4%{RLOLhq^ntB+<069+LkvOf< zanwFhhJmAd;Udk~HK*r4!JylP3l}&or?T@w+nYFu+5#(`kmjI}pxe85FJ-{XLQX*; z6xmZ?0biR@plk2W4N9;8y+=BFdl&;7yO;@)dod z9$)^$veIbVy1m~(WO!JvsiBeX)FSKPOZqM(B=XqmtWctkUeI-Mk-z|ogw9ZtU0nR* z$9qSMn%mnWA-;A6E>*!5IwT$eYLapvIbv6EVbS%pU3K;{<1o3{cdieE( z47X!@z8O`h*InE6+nYD6q$X!&XKM|aLMo`&i_^KViNSDKlv!D+)s*dx5euC6TAy`` z6pv4>Rt5&yTx~Z!F|yr^UL_w1Oh zi_236bK@%9BlOfK>GO{t!kFcMG?mdRXW{O?g0$_vzIpXq%H$F=Gd(L$euA0DMMh3e zbo9kKW@cuL;_meH96QtIwzBxP9jUoY-VC zia^CZ7!(SiA*Z@pQXLb;%i9}l(TDf%*H>G?j}F?}&#p%s_k`s}l4ZzQ%SSjVOlpm{ z&(4J4kj4Mevq?<^*8YH_jc!2wX(REOQOK250`ozz%fx|>L{96CNddax{FVQ&f(?64 zCk|{Oc-WNS!$wAPNejjeY!3WS6vC=Qm%16z2knxLu=SMn@I$b0th@5)>Ep+R&=JWj z9}1~~krAeU>W$2c0QwNXgnycVJ7r=NGvETxaIWTHYZ~sb0rzQRqaz>t)xZ&6VDuF< z+-Lx|3M#GuZZn!Q?UMTwC;@;7q6si3eJI0cszE{BXg4!7N( zboU=WOdP+3;m%j5Z7K&h2lF1EG+>mZPa*<4F=vQ!M^W?lR|UyKgQG*~?63LitPmEs zfD$Mam<5pUGt)0%45XJa# zo!(%TM8TWOmoLw!uq|EM1-6r(VYB4VKnyyD|M*3n9Ua+7Lj(kR5e~d2$tn-`n>TOb z?MMTPf?_=cH_mQ=EHL-Duj>*>Tna#=25KLi<(OY>`DBW1vTpbTZ~){8)Q5o1y-@fSUO`Ny{7QdjnghOsT;fPt3S8VJBm@gHkFKsRR1stb zWzdr}u&#hg`y0Q^we+%cix3>bOEEAsL9`x{t2urvvu`t*5 zRG8K;C3k85k@HyvIskqMIn_y>7MQdkqaWUqhGJbQ}kUv3EMmO&gy&jvhZueY}KA1~AZ{BMBpOkK*iss-H z>LhqaeXT8t!|aY2Cj~k+nPnKxVV)fftn`PvxOuIb~&KTs!976W97@!Gl}r z^flZ(Jcs=S58xGUr8o+g!^89H-?_}K*{)&^fGE8C;r9U5nKMnPe^`ba`dZ!I0!X*z z=?VDr_lqPY&%H24Pzo#rnm`W?ly*S;*DDQ4gaMtmP;;nK6Q!{{Mip6<-)>% zpDx090s|B;wwxntsc;wV2CoF?!ZLn-To)P!E&KuQ|Kd)A`88QE?}Gd$rT2 zGlu(NW_pmAxMyVK!43ThXKQ=~TQhpznZbDgw&l1o5RhS$G8H^5G~#&NwY6(kza3rK zcVY#ZmMIt-8gj)j-~#%Xs{+$nM@Kxi|PbMI`jKiqGL1WEnq!)Z7-v> z>_io4WOAtt3_74;ghfT8PV*DrG#C*8V$uRXJPRcn?y2MU_N-u+_Fx7W=2ntL-B8z-^pr;!*Zji@-w+0WV z29_U3_27X60q6m9&kVjkp-jjYF0Mcr!ht*p4uq{ABj&Q1$qygShtCXzK2h|@s^IO| zI5;YGOJ!wb$UGyN=7c9I5)KqR)$s7}-XW+>>dww-KmF;#iNn6sf3m!9KIY-JBwxsa zp7`j|XB6MM2qQcI`06)&K*MVw^GM3b`0W-|Rc$|U58Zx9u${Fvru6r6H-M?bY6GC+ z?yd(IbC-1jp$2L;wc**5CyPjpRK9iNMi4-!ad-=mAS`eWJi)=i?^{~Jr0r_%Cnc5t z({Tl z_O~fF4dDIP3kVd&cis{_iP{HhW#`G0$uez#*sjQhrrGZMq%aVTVFTI5-@xxg$AMdo zSW{9BPkJ0ZV{gA#;pZsOUDVKBaYo;#S7gY-;g~{9geTV_t!_3~%TIZ_AKBTrA*P>6 zGN6;VLKlcCCKIV}PsR(h$mwab<-ppJeCC9s<8FwByNW}C%esC5pyIl?U<{e+E`toc z0YgY=52b`cKEHp@3ABi*Cpe8=F?LNxdoTtfTbza?b2PQ#+m_b&`0nC9h?N)^ClVqSV89bl}L5Em1E)oB(JW_C&|Ukt?N}tQ2BuZ08``(Nx3H zm75{2kgEkTNu=aNM~DmHyMTy!Q(39*=JxETe+d$th!FCdT+eHgg)k9|+cYo04i6d# zs0WW9jG*Yg@x$E$7H8sz#1&_3?9*;vQXV{b9p8y7sX#s5>Z{4~oqXy3JROG}3sM`- zjX5&79M4RR)9OdjXduol@&3pmi0(ivZCYa#ndE}8liVSVxS0nhLpf$%BxS69OZw2y z5i<#Ir}sbyQ*B+{)qD5;nc!cK#8_F0%v_zF4*aC5<TK)wJZ4OY8Ih=8nZ*neOc<~XU@2lmMYI$JOn3+q zj9`wXSR$gONGT#g1@(X+$y8vVkR%|WQph2x1d-6ceXzcF-yP$2kM4e7cs;sCjeEV< z1Lq(1UVE*%=9~+lh!ge7#+0jlb6NdtIia{fr$N+0OyP5N_>dtdug*0$_i=amG!3n# zV01xuVrdX81bbrtv15@gPpha7$J0#~y~L3DVe0MAt4l>@Of15W`%4Bu88PYLp+gIs zT1_K@6TB4>yjQ!nZC_+&9vEnTA*$NAZM$}rh=YCe4i!DF$jx0Li*MJiU1{!LBVCMm zO~Vd7CA`fwNTyPxWUYCc{f#Ch*E{EHv@6HexLU36(+~c?{jf!68B{Z3+V71sE{c1R{nMEa`q*5L!J?nZq5n!hlt$9! z%a=Db+*+ncXWllaGxGmEswdGz_zy17{$su(r<1abWWnrS{f?TlOuq;PzW0~o{m2Iw zB%A|q=ZBdFeh(kg=H_{s*R z95SyTs(u6VW)vXZ%LK1Iet%~i&LD3$;NIvndautvlmY%pMMwpcRoM&-%$0N zC{awbk`RkkP#p=A`$CGNHh|e=!zbg)uwW1!3W}`8hH}qmM~}AWBFnN^9p!O-&(NN>o6Qfw6e;K;bQkCG{3IAIRTV3;hz60Idg!U}G%? zwxzfbS8?)Ww;sKE2|pLigC#p3KAa*f0T+j@Zo@BEfkXx8!PfmjL-n#|BDPKOs{lc@ zviFa!64g|0FGXH^#>;BKg6`C29`$#}nn|Ugw!a4lpN>nRJpSC-duiwGqIk|2HqF=74VA^LC$C}Ipw)~)0UCM z!iwwyN+>Rs$RV7qh4Vc1nl^Ivrn>YPf!mUFa$Lu*A8WGT(<~AGTI`c2?a`mXVXmmI zP7(-f|I=C?wK_st1+-3!J|91%eYA2&%>tLN6mQU8fmwWT&Ty|Q4pi09Xd~fi3mXq; z^le6JuHfdlixXZuc*^*RSU&T_RAH}*pqY@rOC)gJK|LjQ{s$Y-0%2g&ufb@{80>tD zf6snLf*}reAs&bHskQ?0xlU`i^_^B3%OT&lq#q!`PNf^qmA2UJlGy@?=&S%B)w{?9 zmsQUnx|L`?#yYD8FTK-&UeZaBJ(lgQd&+PMDH0t^ph%GDX-~f#9E!+DI7@RhiK3q- z3ymi12V0yqq;dA??ZZ}?hQbsF3S02)MtJeBMn0Q}s?|^Gj#>2a$X(wXt*B>*`99~$ z^WVM0aj_Fwt{cy%_Px)_H9&V+%f0jStM*c?57R0woaBoa#;H_-Dv_UhfM*Kap&{ITIHB?@a~8l)2mXhDDA6AY?wq#7b0 z7C84-c=#0;5_&^*sld`r9-H~$R@DQsr2tTNUW<3Q-@MG*eqZJoVkUv(RX!Q$f014Y zS&qQ<7iJh38TALc$F6|2jwc5%LbCJl;ZB1eV8S8v)JoRwzjTq@m&tf!d%0S4UYAL~ z(ERR(;mkvO0f4HL6k;31*?#jxHeb(&x73tb3GmlMNnrGnQ1@?A5Sd?md@e^uF6t$P z?F;g>_`W0dTtkGGmF3*Rr2cb*`+|Krj{mq`hIIyZ?C3r`Z&MAM2GgKdL*#H;_Z*v8 zH*;x`_%SNB)+05+WljKZshGqjCbl7r-sw9L4S`~_xO}axB^g(Wt+l#^#(*w|zuTww zta72qv0X02E!g6*$AF(CNyn6RX%jcYwK+Yr>0#6Bwbi822a)ge>vi`Rge?djA;2&_ z`qh8_VjYOQQDZ@F5BiRkaC>Bd+BinN3nxNEF+^5PM+(o&Hm_m+}nbDTgL4p+0J(BL$6bUNmpBT9s^YF#xn zg!|9(XxD{$jl^l9|8DxcC@uc@xIWb)9`?s(I`t@m^05REIXbaoZ7L;w4*-!F6jePg zMMR+|A?4VNM1s;9T4{!QIT4jIe>#r=D-azte;P(NUg7SP~_4tMf{ z{lc z^V1f}IrhDu)cD!8EKb+U#7+n-CZglJ7{fHKEP>RG;R=VqW`w|+$g14=Id)7x|2zPU zS^y@ZvcdmJC`z5mH354WM&*?4gABwygC}1>=omY*! zxpsvhLyQ<GqEaovluQ*=llYkMutl_Rz{ zSxES!qv{5`X(#$-kNf&1pucrs+J?3IJ{ZJnGpz@Y4q+!xYOpr7=-s;vWA|)KSZUNz z<(o#h!NY%2Vu^gCV=xp*-fc^MK<|;is+f*MrRfvw1isCf3Z%+j91m|>>E+Ay?i#ki06Ws2>iDn+7x%I~J{jUQSM3tT-=*~si zd1RZ?^>^Pt&LWfDj07sP>rD!Kf$OnxPt2J!=XPHWpah{XhN8HiA^f(GWa-NlhBU=8t@O3 zNHWzuS7-P^6WHJhUy=V$tSnw#Tl6e)2YsS}-oT`sl4({>`eLznj2F|u$ZYkzPyh1E z%)mOk9OF@=>z$@@?fG~ytR+7@5b#1Ygy6a#lklh7`VNFy#ZHny^jNl193h^r2fv0 z6wCAQ;a|)SnDv%&&Ewr_Lml1EzJHvF{fD~R1>{HU>Eg0i5CIE?Gs|sw$RI(Wo#LbN z+X0Cnkr3T~MfFx^~scnY_Ba(QH-jm(V&heQLy=JHjS! z{@F}5R$p3rIw{-y`!hlqo*kp+1dIYgn7W~(5>}Gqoh!7F%dOE@ zpVM17nTjHUt+^SKQgPa#I(;?HHMMgS%K+)5(03B12>G*CzPCQm`5rGqSaamrvq!DQ^f(uO7?-nwk#E zt1on?w#!odCv9@dBP}mLCJN795R=)}SBkcLx{r-Q0S}H|xDqDRC=Zdk4b9m(+NJ)< z%6V>h35tWv&`=FKQ&yyp!3@?q8*)G#^Y>uJq3e8a+7W-i;I!j;kP``IvD_} z;qQ*PV8OO*)hh6IU|^Bojda=MC!s(Ej3@RM8VuA zqt|sH(-aba`hc}bpIx;Sja%XPj1jZN;xQ&lE|V0Dy-u>4-8BksPt=a@7?WuFQ_}$b zL3PsL48T689~_zBBn@s7sxAtd0M9&`Qx{QEkUdJUe&An;YRo<1asclto}>B%=@bkA zNi4l@2;4#&;_p${9#;brx7S01cK~yefRm5Q?wn*NAMJ&h0Q? zQ}PTx3%4Dq2yh{P=HEF3PNj`z<`@l^gMv6s(Su4l?!}AaY0hL>xM}-1$YC0IJzN!P zX#WNQI6l`xQHDoXBJ$(iTUt0YO1O`xoH%s z_PRyXc;ab@qmSgOKNiLeaKh6wLahe15}6sC`IZs@3w)U03X>C@Ap~Ks_})NV&6@dE z-tnRg#g<4fJqJvYwq$rEZ5Nwi+4M4w0^WSSUtiRnpDhHsrK2NxbS zdh~9HP8rJ`)~vY_U$Uu0O~yNi8B0$W4oLR$B#z%vuyrI9LJ{BU=NeBp7&%gV_@;1y z+z1tENiP)@+{c(%Kvk!61giVL9qCTP9&pw7^B0Kh_V&SPdcut{?fOE!z^`ze0>(?% z$gbW`D&u#9qed7+$Hc@e{9?Ii5iZ!w1|$0vep!~ONR-f~#OD|JsF-}{w;}StxzTd< zx7*{($Z{7)Ifs4O<%>lI`h8(DI(DqZxpkcPrr<4XIL-q82vS#agnS5UkwZ~f^Rh^`%!60qqE3^|It@C#uFnnFXk@06j zmjTR!mNT=HBdHX(Ew^619T{!JO%3!E}a zb7YIoU5$y!+wkDbi%%G&UA?u}4;={9b*es=+W_B`tyezqj3eq&jH!czH)5}tHk$5w zXQcesoeZybFw$v_2hWYGU*W&OZEO6N*Ys4=|KrlzJZzKwmA~Jrny~Xse;?YKuWZhQ z3dW@%%CQBr&L?$q?QXk%J+D?+GfZ%BNkP86W_z8Jv$HDC77$!lH|0`kcuy(4vsa%h zvNy#nnLCE{s`1`W)%Hy2Eqy=KG`y*v?RDO{Lk;?AftO#asHZgE@4K4s6!3TSkBO$O{<$48^&)b*gG{FiO#Iqvvm?`yWXQynzK9jV4{SN@bi!Rv!^|1 zYTUuVMntUqaP{sN-J}t_6SwB1Q;pf1ZM;`zb|4f9fN!!b2n}ERGV;Kjo|Dfkcuk;w zRs6>jvT=SH6wy{ZodKGOw;mCj(Jn*h-A!nu31E`-{7g|GBh5^dpm;sL#Ja0|-w03TDbq&;n!=LJ|z^W!AUMZqhR)kbvvev-DH#d#^H*Q(O_W30GIo zmka)|PHQf&!%jhtJqp+J_rdWgEmjN^?63gat91@xgn_9_EuvR+5l_P`KjltnEA5twr+2;A%ZpX_QCZn-v!NFm6PR*-&%c+6iiil8%b1 z>UyVa#4Z6dH*VO_Qn1ujO#l5QbQilxbO>l70k0%)0Za=BiGo4UuAzI{vI2)dBBUY{N}<&Wey`7b>P599~|lJ5EWyZ8fA** zjiBU8QI4f!%ckYtSf&lPA0e_4^{IdF)3Tb3_wU}#)cSa;yc!7mmCxIJfb8di9u1Eytc8b^!j*4LUf2rV;=j27ZQ32y z`t_E&P7f20X=$JKJ5w)b5?0<= z#p>8^^SAOMy|WB9sUUNot0wr(z#m=gu43iqVx|UOu;+f(_0EAsv)sx`C&77qFb<2= z&-${H=8tdFw(V+qluDgDpMKz&i6LJ^@`8O z-=mcvlim=b+A*tib#*iDZ0wErd~KmwPibszy3gXIu)kmwqkoFC)0-VrIb`qgHdm21 z!F_pPv$-Z?E1r1j+cqU9tsN`gRa^@DU2OyoVHn<6{_;@cx1d};E#^rUM zm6iSW4aXOc89#nMzzpD0RArZJ?CdXIzy9J)MKe^iYmn{6`@X(DU8ep58AUB_WqCu;&TI)OU)&Zs; zSu?J7GP|$nT}eq!C*e0jASgCk77{5s+*^uY{Q!f>#B~^*c%t0AEx~rFq6yg=Bs^`! z>Bt#^Agw|(#$w09pC>@tq^vo&^*rq;X5=+!1iuWjDQWn6bIY1ZhHhgaskUa#wNV2WJe3*{t0~U|+@^c+2 z|HTGT6G`=gqo)*_*$}7OGeV9A*A&T;PBi?bB;d8xtAC3xtoia~6-;%I=N7AWtc?0- zd|FACo~bpaVY^=T-?}7pdT-@&(K!gR{&y9v1SPMUmxfDERq4}<78%ilXURKy<-BRG zzTS$)xsZTiAD$@Gio)EV1Zakk?VlqtLshvN!79V6r!q%XM8uXim_HU$1L^Q;(6PlasrmpX zuPpl{3@-vRnGLbYnpZ5ugFtUIzlGZwtam|?v#a}O^=`QA1{WBI4whXO{;0}z0v-xi zJaHK=T-j9Do5&W1H;9;vC;GsvG^Bw1)Ic}vJm88&E=_U#mOy2PQk2#>S-*&poH(Tp z&m2pZ;NZz6qg~e?Hmnm3UO_=Y8*HbE^h6l65qyLrlbDr2W#vCwzI5qQF|i21TDUv% z6SeP7nG1)mr?0O!U9SdyYZ4kuptjD~^LaE>ErL9@iexMUDWK$HWMpq)vY#?h$eDOTdXcu*8`l3y zRR8?CPTm`2@w zaID+?&|Aiy9DcQL_jIWU@oboV@b0zhM;4xifv$ehPxIz|4-I?bZ_?&KllZ{3&vk`++ewcj*T~R{|;o?OY@V3v65OY}Qa(GdvFPyhnSWBZp zX4G#e^DyWDv{LONQb{qEo(2jiH|y+7@MltNad6ULqfsDW2v*=L?^kP}9d@Ejwe8dE z0n<{1abB$RyY@O_$PJ61CTk}xw~7|@bX&(7%I!3k+`vmt#pK}5;_4s&g_^ngLbYxB zEm|}tNCBfOa)xl5_G#mcnGIVT-u;wG5W=aoFMf6KK%LV;L?ywH!2wH9Y zPB9~k*pzpa3{nV4wcNjS#qAvqFd{)EJc5cnjlq-9;xHR|Ker{kXwG8O#)Gx1X<$c_`k(S5K7KIH|)S#q^~sSb`A8uK2{x%{pwk<6Brr zNEhfxwNQOTt4(+|iTPmY`9{7!@!>#vyul~UUu!)gBS#EK*#^;;&n^b$;xa|E56T-O z5@x$MXm1rB)d^+R8rkEZLTuoT66g8`QPrtOZv)x8;4kvMpy$M8ccEg8t;Tv;GkbG#ZI z-*n*=hc3%#$40jY-A6b^>~&nbHehT$MeUueB$UG~oTEd19sFr*tfC(Sv+T52;MJ>U zE<;@JSKW47&kfIxPyTrf@+eU{z4cc)>+I-+&InSL%Idn%jwGBDF3{@F_TgkL|xFt|+pwTe(sTQLi9?WjaHh=5w?{^@?m< zCW^U3#maTWC&86N2=U4p?(^aYZU#`TP_yQ9Y=SLiej;wsW@-^z{cQ{b2Ov%C&9pnC zDOk@0;VbUlG&FF~7O$!JE8Uzp(5$tle<2;?+#NRjd9PD7mw#{=kULXvG|pbaZTee!O>hO`@YhMV{HDz2wZO%Ke|-HRM0et9=r3 zE4`ubEIZJ1N-PJpVb=Pi{=8}un2HK6`QsK;oW7?;G zvCjoNZCCO9M7L+t6M9jx4QaSE#y6R776k0MbC0Z1n16()cI_V4TY9Q|tn6<+x+n)x z(KjtIUv4SP_Ee-XY9GK8H*ep5+H4eI$p&4p-mzX^s;hrPawp~nFp0j++qC$U6Yk_6 z6o{O^o6)Fb77sHGy>sDAm*6MqE!#32i<7DC$i{~y@87SzQwpVUk4ma{&btMAlyNvq z953)>#X|KwJ$Ctl?=Sl@yNsYHOhZZaVU4Z*?D(as#?TsbI_9HqYiiOwQ zUM4ii$LNJVWL!+dQ97Nq<(^H4a12t9t?ep9FP{I`%gf|_w*gi?Je9k2iOOGcFOnz&+qlTy86*HdBYL^dcz$#F_#h$ zs|oP%s<68G2gUv?EvFs&=HrcwW?NGg6HQyYRcEf-%w?VYVfK~Fs*o#zZo^&Rp^F1d zk`%JBo5^CUjtekR=SBZIXF-|K4$uAS(Jrf3kA(N<`gCok?DbWirZ_nO$XZAQ1+vMn zRiSBxSj@wggttb=EFLt){|Y0ydd@(cGyL7FaZlL1Wy?ckobwheu-VpEeTn%q@7M1_ zrin9OA^)#!s!q|ne$D7*`uL(Z+g?Yn3;xxh3x6G%E?ZEjYtQ#qCkG;lcTiAZ1+y4zwEj|6b_P)Hl)+TJy zP0OHB@pmv{(fp>05TMI^S+SJiJGVRt;vD0S-bR(DCqpgG_<#Y4v z(Q4zg-9H@9N-@Sq*Z+~G6pmDZ4Lz2@E8MFV`q-%N__xlgM})LX5CnE>zhz%Y&QJ2^ z&{Apr(AKlX;YQOZ9%|*NUK1Gks&Qr$9(VA9w;NojJgPDwT0`G1J_Yx+SMybZ-R9CFgYWng`zNGq6 zLZ6k92S%*TaEV1Oqpj2uy;%9}KRnKTfW0j-?kI!0RtQT>`PuXH28D`O0xJ@#xnteQ zaL@J`PL8yTYC&e@p(#Wi!Fvx3`l)oz4{}gTF~SVxUA(o%K9gN6&7(W2R$(6TZmU6$ z4sDp&xn|rDD3Mf1(>v;;ToWw1z;d4bg=W!q_tlZHm$1?HM7S~S! zRkVYqs+@0ChG&}7*Si`!GLHE9u4(dXou8*$?_&6SRM_wVvf!(RM=^pA>^~EtH&%gh z6jO_i<#{e>FN65ueQ$$Q9+>hbXU*${0{mKqX`1q}7O~_JV(7<3dOw>Ue7&0bZ4FA> z)i>_exq0o|XOJ8=R<+adXYUKTZeC>V#2C52%Lxduos0aOKxYd+)wDbxS%^wdu=CNG zdRLJJ=6@P=+pkDND&AS0U+IFG#+^B^$ZyNuCA_Pj1AjE=mZMZtTB%h!vV-9XV7;eZxycIq_=F?EoCpJ zS+_e}wpnEN#EQy~H|YL&Yvk}ENA0M#LkY&84R;<16fe;{F< z7nOGC;VLm~k%MqReLoE~wK%wrq0H3~R7N+UA)_%SC?P1iE~Ra#L}$+agTG?Ee*I%x zQ_qio4#qsLJNp5>7=4o7=K7hB3|{K}$aJ4M1NO|nwihcF+I9G4?$J02H%V`BLE2-;P0PhCpvs zua`l#Vs2ktMa4*JcQJ_5`%w0UT+IveLaXTK#x7mT0S+jDBeE+`{^XW3-~sr*4#7qF z^9qgz`~xS}zHQ|_bozw$GK&6#pU1VH5=#k@7!(QjP2${33LGl@6NHLG_%;&Yy2s2( z%6)_@a~n!+Z*3*f1#GN+G|4chY2z@`2hfvlo9?ybXE}kzdHvy!Ut3L45#FnAUtXGO z`k91k+1>~VadI|>sM^Vw6#z-}z-Oso_1?amUQ*?Zt9PP3OuYjnG=_(_{brAC_huSG zjGqLgAU`LLe_r|OG>o48+S&{Z(1&}x@raEgQ8DoL#&D|fD zL?&89q*)}jIPB3?7hSxY#=Yf7$xF7}8(1Dgy)>)7lgw!08+er!6`M)Q5B65cC?B!D zDU+*+u`lDHG|AZtK2gxzu##EUPuR12cLfFthXSuyxli2n zGHCxJ2Y(VRqd&Ggg5UnN#GB1`D5NT>@1~1P8YwM*?_iWGb9!$5hD1hr(L`CnlK7Og z2-R=rp+3{jFF4CB{6x!#lS^s0#LrCMI)kDqsxqmsa-I|lpUcRin^+#&x;$ddnnl7|K%?zaI?VJ12@%|Ri-q9;2mHFKCtBg1R ziGq*>Iz7R#^XSuC?&Gf$Tm01ADI=b2S6R=uGwb=(gOk0TBkV_I+K)@y0)kWd_@r!m zR6}FmLunhPZ`@e2S3jt_^{FTCq=u~}f)E%M_OjIez#HO8;Ft1{^pe0Y+sti7swOo= zyX~?J+OC@V`0@Vu#4Z;Y#sC6>YOLgC-ShBco)^mVd$(DM;YrFdY{^#LSt{T%w@*(7 z7WBRbN7B*p_OondmEzHQ!W(6z+-;(gSI(a>0Cq3eeMG-exGy|jGn)CCPx8kOJ29~n ze5)-9=?b5exxW&{-$2pTcX%^->eM~)D<#?^+7j_uRfT3!*aE%Vi*NqUy%~{T^6wrj z1wXLagboty*Cc9h$p3I{@u}FZa3|#dSE}qrycaS`{;abiuK8OPE)cV8?+af=1^LVQ zf5n&NjO}7XB%WKe0r^xR=ugeb;VkS0?6h;b-4)k0w zr2WSa(4{KUYRz9-4EgZxopDXM!}rH1oEcR9-8I3Y-+$yEJ^D(?W14B_lvp!`#>4SA zq{7d#(4h)0X=_jz;aR4%dnaU$iw_=%ncvvQ?$*9|?V9Z@tqy)>?WU;ELn*E5@`lu> zB6ml*4oIt*Y65h`k?r=NKg!f0orNYgrh^Qrun=)k+G8__1CADWex)q0L7B9fJrSfT zrS@7-H;>}9fNYNs)qM00#-j;hNjzohJ}Am>3C|fconVpvPrtprP@|A#w&S;(J%g+% z>;OJ~+%QVcDJq=j#3~1E0y`+En69AP=CCU*xb66`_wLyF%a;10|c`aviX)r-q*^T5lyE0cliB>534DA`F*H3#9+zP=QwIHH0Ys@9Ke@!I$t`6-(}`fSPWJWvD^%>4z*fgJW5Xv4L%fC z&_Mq@YF)Dn#>Fa9p{gMyW{-OEertVWP0S;D;svW1;rXnpubLWs=Uw0@1*C=(^IC|f zcc%I2`8A9Uboa_@uS}F#%P=|JkUQzzJ%Ou#A#ZMrMf1Uf?RHHM+5Qu-z z5z_>N7|KrnlpPewfGENfjdv`JbZD7~Jd~l?2eJ3@4rTI(kkB@M37jOH&W>qKN}~Uj z=(1hB?arNhj<_vW&%3SnoXw*HA3Y#3ga(EHVCtVa*Vgh#9m7S$nb^_DH(4*BZx2zJ z@MBc8+#nTC0?A(D3$6m1k+4z*`evN5uwfcKx*MJNk*eoI4n`w+5D4X|C&G|93N>88 z#^Neh!8IqH=ivZfi!liXW%xPB-Xsw%{$8p`K|(X_o>zU#R)pEB*6ob5{d>S2Fj>3y z{TPi(7y|g~2AP)V>FdiHhIVCawc3%SBCYjY`iKbQ)oi$Ig$vEK%i`=&xX_&bABHsl zxqpnk=K4$`>3Z|WX;Ul|-|Y9i`Jl_)MPz7pA?xi0@sp_ zqaNV04yX#NG^7`M=M0z%o08fjp$gLoF~LemTFFRZ-c9A$R=|^7wJBybl8YD(Lh~08 zUMSUoy1~|I%X>=zkwckN0Bj;io2Fq|6wI5 zWK5D7Hueya9wSDBlORMc44rO&teQ-jTNeES;A+iHK$ALaj1|wiy-W;K#W%V8&2?R5 zDB3E+klu-=QtbM}$rP;|zy+TmmC@qJN5`YAuqmMpOcQl~2}U+T_bw6XfN<9-810+v z#f4+rcEl)&+I+IgjH0%{vOB(fLrJdF{b6%NYX+#0iuybo-mBvcOAdM)8##0)0pLrt z@ueXqm`&2+&cS2HD-NsIH?2yfb9fiErJFntp*`78TelF4k?xIRtS>x1XRP1`E{DUZ zRN0!%p0X*9nOqd&IQrgO{(y1|P2S7*iQR4D%cu?($9P1iK4-jJA82mdm1Goe{Ra$4 zDm@DpBLFzJ#;--n_v@nRi8KF0Lo?{c4KW)dd$BMR7|^PDJ*}IRZ0nz=cZO!6iArl` z*_x?JIWBk38L;haJ1pq6eV$#KH%L8B7aR4h_uk|?+Cm`Cb^AOw!%i=Xa;%o2+!{&q zo7I7VqXwYw));)_`gQgTMBXpXMj{a|`@T>lBpQ5+5a}Tumh1%QE`*fUvnYCQ4=Gu= zKzqr8MvfkhEcYk;_ zf(cbgzsvr^}WyWCu_I> zF(U_pXU#j zS>^MLIT8?tja@Z;lW|t)c=_dDmE#5F#9Z+h6=jb~ffDbpnXvM2E&u;N3j54|ehx*E zqF2#cSUFwN8F6&K*j6hQF{7gls}0!h{a|~eA)Si~dEWNg4F z;47NIKx^j3MH8kov24PGhI{-@q=$=7RL1bN zo2a|YZ08XEH{4n3)>s6K-xMf=p45fxja-e(-vJaRp2+QSObJ}e@`eV2H+S#&GRW;> ze=$*HCvw8d{hAW^V8RzbjNSwwCeV(=Ls~+4FFbF_VHELQ_#|;EDR9rw(0RmkLcsA0 z7mlK{WERI9=PS=whiRi7qjFFbq$~C{XZAP|3*BIIBnJ%vZ4j1$G^FX!ByK15^Md~Z zll3yxcz9!XU8{yjiWY=XpooYKg23bsruYbpILTyCOt4<&MeHM!gWIiRVBqrRvKXmm z!cojA+DEwGM0IEmMA%e#(^qPre#_gB{jJ3WF^s0#kj!I>FauB4yHOlhBHJZjnwmlC z%&Rd{FWrdJz~qw3qm`DHA1dnLp5S4!-9QgtZP8Q_>_eqW!|xRX#uUxXRV&@dOgj>@ z)fq>QjN+rjXo-ZnXEQvlK!5Yuv*SUw)#DuORPOg1Jh(lz$5gs3e+k*Ng~hwuWi;WL zuCW&j7m4Bl=6W|jz|@i|^ts-k8~2Q1ixZS|M_f?tD`kXOEKOlQk46x9T+FFPpvhxC ze^+Ax=1?H#9D0STtgQS}6-hRq6@qK%O*mr}K+Hu{Al*MtoO;(4@vA!s)KBBS)klOe zuU9N%LqCT&!2!qSV>5wU&zIrK`-KHh=z^d$TC95$S9eXf=lw$Xk!Uw-qLpoI?dnCHiH4% z7nGXGL)PBPoQKgfP$2T-e&fdV9CG^U<-9$D)0mL0czC^~Qg$3ESk8($`R(K5<29Rp z9DV9Z>!7rcTiNoypE{oq;dYbatRE&H*6Z2xPi_BAq<1|;`0(GSQSmvdg>Y%xCg+!bjj9xA)K!;^&Rx0)6N^7P{;z>tJhY_Sqgy#g-%uX0HYX`$ z%)wFpf6!|2#KrOOnE9V7OAfD&`el3H5TCS5H=SaOjI{XXT%qSA_YNx2h<$eO(@W=j z%lGcw=+yPN)h@~Oo-IEG6)*0&@N)Ktteltjr_X!)^nBmRm;&{zVjXzpM1xzhUo#G0DLcjH%p1JwrKPMF3Ewo)S zYjD*j#cx-V-Ot_i(qOxBLtXtJ(cXOqe~r4hd;YA3#Uk{Nh%3|2%j*+8FD|{Z|MrkK z1%t&8+6b||t>Q^tjvV{zyTKVv&V@RSkCIJm`>uR+Qh$P9qnrQApZ4v1XRLV#ux*ln zRD7$gBZF@^e97IYnRGyYQ|->4_=1g&M;C`$r5)T^zo9-lysad(Y)a~t%a7Ww+BWyl zqNzg)Jo#yCTEG$Y+J0Em=v3Iscv}#1=i%ns!h8`9 zle@|8}H%%nWH8kJCTB`|Q`9m;K}!srlS*p}r?hmRHu_zuC28CUQf!RML-iZRo}00`{y>V3TsqM%acAN|PtWMKExxAJ1{N%JyI7Vmsb_kD z$&L~8jp`E8vnxY;M*lq2qjHRQPR3ndi$62xrhNXIBG&gi0VrK{&q$v6ldD^TnT^^M zx7o*13uA)pr&=sL^~^xp&}*nPEh0aDprJ*VP6qXF#`(4IF?7|4E3-MGywE&&UCpD3 z{bzWb(@)~1w zHZ@W!qdAs+z3lbgj5!eTKReR?#_L(xXE%!Y4rnX z)8^>5P0Q;amrn1#;EbmWajJOyX!(VZCN10O?k_g?nR!COKR-@4n|9M=)$acTGL~CD diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5071399..1d29224 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,10 +27,10 @@ jobs: - name: run eslint run: | - CHANGED_JS=$(git --no-pager diff --name-only ..origin/master | grep '^src\/scripts\/.*\.js$' | xargs ls -d 2>/dev/null | paste -sd " " -) - if [[ -z $(sed -e 's/[[:space:]]*$//' <<<${CHANGED_JS}) ]]; then CHANGED_JS="src/scripts"; fi - echo $CHANGED_JS - node node_modules/eslint/bin/eslint.js $CHANGED_JS + CHANGED_TS=$(git --no-pager diff --name-only ..origin/master | grep '^src\/scripts\/.*\.ts$' | xargs ls -d 2>/dev/null | paste -sd " " -) + if [[ -z $(sed -e 's/[[:space:]]*$//' <<<${CHANGED_TS}) ]]; then CHANGED_TS="src/scripts"; fi + echo $CHANGED_TS + node node_modules/eslint/bin/eslint.js $CHANGED_TS - name: Lint JS bundle run: | diff --git a/.github/workflows/types.yml b/.github/workflows/types.yml deleted file mode 100644 index 395834d..0000000 --- a/.github/workflows/types.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: TypeScript Check - -on: - pull_request: - paths: - - 'types/index.d.ts' - -jobs: - tsc: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - - uses: actions/setup-node@v1 - with: - node-version: 12 - - - name: Install TypeScript - run: npm install -g typescript - - - name: Install required dependencies - run: npm i --only=production --no-optional --no-audit --ignore-scripts - - - name: Check typings file - run: tsc types/index.d.ts diff --git a/.mocharc.yml b/.mocharc.yml index 8a31a63..40fed2d 100644 --- a/.mocharc.yml +++ b/.mocharc.yml @@ -1,7 +1,8 @@ require: - - '@babel/register' + - 'ts-node/register' - './config/jsdom.js' - exit: true - -spec: src/**/*.test.js +spec: src/**/**/*.test.ts +extension: + - ts + - js diff --git a/.vscode/settings.json b/.vscode/settings.json index 71464a5..53ef4c8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,5 +59,8 @@ "fileMatch": [".prettierrc.json"], "url": "http://json.schemastore.org/prettierrc" } - ] + ], + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } } diff --git a/cypress/integration/select-multiple.spec.js b/cypress/integration/select-multiple.spec.ts similarity index 100% rename from cypress/integration/select-multiple.spec.js rename to cypress/integration/select-multiple.spec.ts diff --git a/cypress/integration/select-one.spec.js b/cypress/integration/select-one.spec.ts similarity index 100% rename from cypress/integration/select-one.spec.js rename to cypress/integration/select-one.spec.ts diff --git a/cypress/integration/text.spec.js b/cypress/integration/text.spec.ts similarity index 100% rename from cypress/integration/text.spec.js rename to cypress/integration/text.spec.ts diff --git a/package-lock.json b/package-lock.json index c19e828..7036d33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -950,6 +950,18 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@types/chai": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.7.tgz", + "integrity": "sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -967,12 +979,24 @@ "@types/node": "*" } }, + "@types/json-schema": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", + "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, "@types/node": { "version": "12.11.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.2.tgz", @@ -985,12 +1009,109 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, + "@types/sinon": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.1.tgz", + "integrity": "sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ==", + "dev": true + }, + "@types/sinon-chai": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.3.tgz", + "integrity": "sha512-TOUFS6vqS0PVL1I8NGVSNcFaNJtFoyZPXZ5zur+qlhDfOmQECZZM4H4kKgca6O8L+QceX/ymODZASfUfn+y4yQ==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, "@types/sizzle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz", + "integrity": "sha512-G2HHA1vpMN0EEbUuWubiCCfd0R3a30BB+UdvnFkxwZIxYEGOrWEXDv8tBFO9f44CWc47Xv9lLM3VSn4ORLI2bA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.11.0", + "eslint-utils": "^1.4.3", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.11.0.tgz", + "integrity": "sha512-YxcA/y0ZJaCc/fB/MClhcDxHI0nOBB7v2/WxBju2cOTanX7jO9ttQq6Fy4yW9UaY5bPd9xL3cun3lDVqk67sPQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.11.0", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.11.0.tgz", + "integrity": "sha512-DyGXeqhb3moMioEFZIHIp7oXBBh7dEfPTzGrlyP0Mi9ScCra4SWEGs3kPd18mG7Sy9Wy8z88zmrw5tSGL6r/6A==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.11.0", + "@typescript-eslint/typescript-estree": "2.11.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.11.0.tgz", + "integrity": "sha512-HGY4+d4MagO6cKMcKfIKaTMxcAv7dEVnji2Zi+vi5VV8uWAM631KjAB5GxFcexMYrwKT0EekRiiGK1/Sd7VFGA==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -1413,6 +1534,12 @@ "readable-stream": "^2.0.6" } }, + "arg": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz", + "integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -3681,9 +3808,9 @@ } }, "eslint": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.6.0.tgz", - "integrity": "sha512-PpEBq7b6qY/qrOmpYQ/jTMDYfuQMELR4g4WI1M/NaSDDD/bdcMb+dj4Hgks7p41kW2caXsPsEZAEAyAgjVVC0g==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -3701,7 +3828,7 @@ "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -3714,7 +3841,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -3731,16 +3858,39 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3767,6 +3917,12 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true } } }, @@ -3955,9 +4111,9 @@ } }, "eslint-plugin-cypress": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.7.0.tgz", - "integrity": "sha512-52Lq5ePCD/8jc536e1RqtLfj33BAy1s7BlYgCjbG39J5kqUitcTlRY5i3NRoeAyPHueDwETsq0eASF44ugLosQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.8.1.tgz", + "integrity": "sha512-jDpcP+MmjmqQO/x3bwIXgp4cl7Q66RYS5/IsuOQP4Qo2sEqE3DI8tTxBQ1EhnV5qEDd2Z2TYHR+5vYI6oCN4uw==", "dev": true, "requires": { "globals": "^11.12.0" @@ -5870,9 +6026,9 @@ "dev": true }, "fuse.js": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.5.tgz", - "integrity": "sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ==" + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.6.tgz", + "integrity": "sha512-H6aJY4UpLFwxj1+5nAvufom5b2BT2v45P1MkPvdGIK8fWjQx/7o6tTT1+ALV0yawQvbmvCF0ufl2et8eJ7v7Cg==" }, "gauge": { "version": "2.7.4", @@ -6653,9 +6809,9 @@ "dev": true }, "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -6667,25 +6823,25 @@ "lodash": "^4.17.15", "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", + "rxjs": "^6.5.3", "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", "dev": true, "requires": { - "type-fest": "^0.5.2" + "type-fest": "^0.8.1" } }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "cli-cursor": { @@ -6747,14 +6903,25 @@ } }, "string-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", - "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^5.2.0" + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, "strip-ansi": { @@ -6764,12 +6931,20 @@ "dev": true, "requires": { "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } }, "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true } } @@ -8064,6 +8239,12 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -8133,6 +8314,12 @@ "semver": "^5.6.0" } }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, "mamacro": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", @@ -10794,9 +10981,9 @@ "dev": true }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, "prettier-linter-helpers": { @@ -13195,12 +13382,63 @@ "glob": "^7.1.2" } }, + "ts-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.2.1.tgz", + "integrity": "sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^1.0.2", + "micromatch": "^4.0.0", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "ts-node": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", + "integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + }, + "dependencies": { + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + } + } + }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -13259,6 +13497,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz", + "integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==", + "dev": true + }, "uglify-js": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz", @@ -14667,6 +14911,12 @@ } } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -14891,6 +15141,12 @@ } } } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 8a7a44d..3fc6687 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,14 @@ "scripts": { "start": "run-p js:watch css:watch", "build": "run-p js:build css:build", - "lint": "eslint src/scripts", + "lint": "eslint src/scripts/**/*.ts", "bundlesize": "bundlesize", "cypress:run": "cypress run", "cypress:open": "cypress open", "cypress:ci": "cypress run --record --group $GITHUB_REF --ci-build-id $GITHUB_SHA", "test": "run-s test:unit test:e2e", - "test:unit": "NODE_ENV=test mocha", - "test:unit:watch": "NODE_ENV=test mocha --watch --inspect=5556", + "test:unit": "TS_NODE_TRANSPILE_ONLY=true NODE_ENV=test mocha", + "test:unit:watch": "npm run test:unit -- --watch --inspect=5556", "test:unit:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text --reporter=text-summary mocha", "test:e2e": "run-p --race start cypress:run", "js:watch": "cross-env NODE_ENV=development node server.js", @@ -56,6 +56,12 @@ "@babel/core": "^7.6.4", "@babel/preset-env": "^7.6.3", "@babel/register": "^7.6.2", + "@types/chai": "^4.2.7", + "@types/mocha": "^5.2.7", + "@types/sinon": "^7.5.1", + "@types/sinon-chai": "^3.2.3", + "@typescript-eslint/eslint-plugin": "^2.11.0", + "@typescript-eslint/parser": "^2.11.0", "autoprefixer": "^9.6.5", "babel-loader": "^8.0.6", "bundlesize": "^0.18.0", @@ -63,12 +69,12 @@ "cross-env": "^6.0.3", "csso-cli": "^3.0.0", "cypress": "3.6.0", - "eslint": "^6.6.0", + "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.0.0", "eslint-config-prettier": "^6.5.0", "eslint-loader": "^3.0.2", "eslint-plugin-compat": "3.3.0", - "eslint-plugin-cypress": "^2.7.0", + "eslint-plugin-cypress": "^2.8.1", "eslint-plugin-import": "^2.18.2", "eslint-plugin-prettier": "^3.1.1", "eslint-plugin-sort-class-members": "^1.6.0", @@ -82,9 +88,12 @@ "npm-run-all": "^4.1.5", "nyc": "^14.1.1", "postcss-cli": "^6.1.3", - "prettier": "^1.18.2", + "prettier": "^1.19.1", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", + "ts-loader": "^6.2.1", + "ts-node": "^8.5.4", + "typescript": "^3.7.3", "webpack": "^4.41.2", "webpack-cli": "^3.3.9", "webpack-dev-middleware": "^3.7.2", @@ -92,7 +101,7 @@ }, "dependencies": { "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", + "fuse.js": "^3.4.6", "redux": "^4.0.4" }, "npmName": "choices.js", diff --git a/public/assets/scripts/choices.js b/public/assets/scripts/choices.js index 98a61a7..ce3999d 100644 --- a/public/assets/scripts/choices.js +++ b/public/assets/scripts/choices.js @@ -92,7 +92,7 @@ return /******/ (function(modules) { // webpackBootstrap /******/ /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 4); +/******/ return __webpack_require__(__webpack_require__.s = 7); /******/ }) /************************************************************************/ /******/ ([ @@ -102,143 +102,321 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -var isMergeableObject = function isMergeableObject(value) { - return isNonNullObject(value) - && !isSpecial(value) +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var utils_1 = __webpack_require__(1); + +exports.DEFAULT_CLASSNAMES = { + containerOuter: 'choices', + containerInner: 'choices__inner', + input: 'choices__input', + inputCloned: 'choices__input--cloned', + list: 'choices__list', + listItems: 'choices__list--multiple', + listSingle: 'choices__list--single', + listDropdown: 'choices__list--dropdown', + item: 'choices__item', + itemSelectable: 'choices__item--selectable', + itemDisabled: 'choices__item--disabled', + itemChoice: 'choices__item--choice', + placeholder: 'choices__placeholder', + group: 'choices__group', + groupHeading: 'choices__heading', + button: 'choices__button', + activeState: 'is-active', + focusState: 'is-focused', + openState: 'is-open', + disabledState: 'is-disabled', + highlightedState: 'is-highlighted', + selectedState: 'is-selected', + flippedState: 'is-flipped', + loadingState: 'is-loading', + noResults: 'has-no-results', + noChoices: 'has-no-choices' }; - -function isNonNullObject(value) { - return !!value && typeof value === 'object' -} - -function isSpecial(value) { - var stringValue = Object.prototype.toString.call(value); - - return stringValue === '[object RegExp]' - || stringValue === '[object Date]' - || isReactElement(value) -} - -// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25 -var canUseSymbol = typeof Symbol === 'function' && Symbol.for; -var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7; - -function isReactElement(value) { - return value.$$typeof === REACT_ELEMENT_TYPE -} - -function emptyTarget(val) { - return Array.isArray(val) ? [] : {} -} - -function cloneUnlessOtherwiseSpecified(value, options) { - return (options.clone !== false && options.isMergeableObject(value)) - ? deepmerge(emptyTarget(value), value, options) - : value -} - -function defaultArrayMerge(target, source, options) { - return target.concat(source).map(function(element) { - return cloneUnlessOtherwiseSpecified(element, options) - }) -} - -function getMergeFunction(key, options) { - if (!options.customMerge) { - return deepmerge - } - var customMerge = options.customMerge(key); - return typeof customMerge === 'function' ? customMerge : deepmerge -} - -function getEnumerableOwnPropertySymbols(target) { - return Object.getOwnPropertySymbols - ? Object.getOwnPropertySymbols(target).filter(function(symbol) { - return target.propertyIsEnumerable(symbol) - }) - : [] -} - -function getKeys(target) { - return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target)) -} - -// Protects from prototype poisoning and unexpected merging up the prototype chain. -function propertyIsUnsafe(target, key) { - try { - return (key in target) // Properties are safe to merge if they don't exist in the target yet, - && !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain, - && Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable. - } catch (unused) { - // Counterintuitively, it's safe to merge any property on a target that causes the `in` operator to throw. - // This happens when trying to copy an object in the source over a plain string in the target. - return false - } -} - -function mergeObject(target, source, options) { - var destination = {}; - if (options.isMergeableObject(target)) { - getKeys(target).forEach(function(key) { - destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); - }); - } - getKeys(source).forEach(function(key) { - if (propertyIsUnsafe(target, key)) { - return - } - - if (!options.isMergeableObject(source[key]) || !target[key]) { - destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); - } else { - destination[key] = getMergeFunction(key, options)(target[key], source[key], options); - } - }); - return destination -} - -function deepmerge(target, source, options) { - options = options || {}; - options.arrayMerge = options.arrayMerge || defaultArrayMerge; - options.isMergeableObject = options.isMergeableObject || isMergeableObject; - // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge() - // implementations can use it. The caller may not replace it. - options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified; - - var sourceIsArray = Array.isArray(source); - var targetIsArray = Array.isArray(target); - var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; - - if (!sourceAndTargetTypesMatch) { - return cloneUnlessOtherwiseSpecified(source, options) - } else if (sourceIsArray) { - return options.arrayMerge(target, source, options) - } else { - return mergeObject(target, source, options) - } -} - -deepmerge.all = function deepmergeAll(array, options) { - if (!Array.isArray(array)) { - throw new Error('first argument should be an array') - } - - return array.reduce(function(prev, next) { - return deepmerge(prev, next, options) - }, {}) +exports.DEFAULT_CONFIG = { + items: [], + choices: [], + silent: false, + renderChoiceLimit: -1, + maxItemCount: -1, + addItems: true, + addItemFilter: null, + removeItems: true, + removeItemButton: false, + editItems: false, + duplicateItemsAllowed: true, + delimiter: ',', + paste: true, + searchEnabled: true, + searchChoices: true, + searchFloor: 1, + searchResultLimit: 4, + searchFields: ['label', 'value'], + position: 'auto', + resetScrollPosition: true, + shouldSort: true, + shouldSortItems: false, + sorter: utils_1.sortByAlpha, + placeholder: true, + placeholderValue: null, + searchPlaceholderValue: null, + prependValue: null, + appendValue: null, + renderSelectedChoices: 'auto', + loadingText: 'Loading...', + noResultsText: 'No results found', + noChoicesText: 'No choices to choose from', + itemSelectText: 'Press to select', + uniqueItemText: 'Only unique values can be added', + customAddItemText: 'Only values matching specific conditions can be added', + addItemText: function addItemText(value) { + return "Press Enter to add \"" + utils_1.sanitise(value) + "\""; + }, + maxItemText: function maxItemText(maxItemCount) { + return "Only " + maxItemCount + " values can be added"; + }, + valueComparer: function valueComparer(value1, value2) { + return value1 === value2; + }, + fuseOptions: { + includeScore: true + }, + callbackOnInit: null, + callbackOnCreateTemplates: null, + classNames: exports.DEFAULT_CLASSNAMES }; - -var deepmerge_1 = deepmerge; - -module.exports = deepmerge_1; - +exports.EVENTS = { + showDropdown: 'showDropdown', + hideDropdown: 'hideDropdown', + change: 'change', + choice: 'choice', + search: 'search', + addItem: 'addItem', + removeItem: 'removeItem', + highlightItem: 'highlightItem', + highlightChoice: 'highlightChoice', + unhighlightItem: 'unhighlightItem' +}; +exports.ACTION_TYPES = { + ADD_CHOICE: 'ADD_CHOICE', + FILTER_CHOICES: 'FILTER_CHOICES', + ACTIVATE_CHOICES: 'ACTIVATE_CHOICES', + CLEAR_CHOICES: 'CLEAR_CHOICES', + ADD_GROUP: 'ADD_GROUP', + ADD_ITEM: 'ADD_ITEM', + REMOVE_ITEM: 'REMOVE_ITEM', + HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM', + CLEAR_ALL: 'CLEAR_ALL', + RESET_TO: 'RESET_TO', + SET_IS_LOADING: 'SET_IS_LOADING' +}; +exports.KEY_CODES = { + BACK_KEY: 46, + DELETE_KEY: 8, + ENTER_KEY: 13, + A_KEY: 65, + ESC_KEY: 27, + UP_KEY: 38, + DOWN_KEY: 40, + PAGE_UP_KEY: 33, + PAGE_DOWN_KEY: 34 +}; +exports.TEXT_TYPE = 'text'; +exports.SELECT_ONE_TYPE = 'select-one'; +exports.SELECT_MULTIPLE_TYPE = 'select-multiple'; +exports.SCROLLING_SPEED = 4; /***/ }), /* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +/* eslint-disable @typescript-eslint/no-explicit-any */ + +exports.getRandomNumber = function (min, max) { + return Math.floor(Math.random() * (max - min) + min); +}; + +exports.generateChars = function (length) { + return Array.from({ + length: length + }, function () { + return exports.getRandomNumber(0, 36).toString(36); + }).join(''); +}; + +exports.generateId = function (element, prefix) { + var id = element.id || element.name && element.name + "-" + exports.generateChars(2) || exports.generateChars(4); + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = prefix + "-" + id; + return id; +}; + +exports.getType = function (obj) { + return Object.prototype.toString.call(obj).slice(8, -1); +}; + +exports.isType = function (type, obj) { + return obj !== undefined && obj !== null && exports.getType(obj) === type; +}; + +exports.wrap = function (element, wrapper) { + if (wrapper === void 0) { + wrapper = document.createElement('div'); + } + + if (element.nextSibling) { + element.parentNode && element.parentNode.insertBefore(wrapper, element.nextSibling); + } else { + element.parentNode && element.parentNode.appendChild(wrapper); + } + + return wrapper.appendChild(element); +}; + +exports.getAdjacentEl = function (startEl, selector, direction) { + if (direction === void 0) { + direction = 1; + } + + var prop = (direction > 0 ? 'next' : 'previous') + "ElementSibling"; + var sibling = startEl[prop]; + + while (sibling) { + if (sibling.matches(selector)) { + return sibling; + } + + sibling = sibling[prop]; + } + + return sibling; +}; + +exports.isScrolledIntoView = function (element, parent, direction) { + if (direction === void 0) { + direction = 1; + } + + if (!element) { + return false; + } + + var isVisible; + + if (direction > 0) { + // In view from bottom + isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight; + } else { + // In view from top + isVisible = element.offsetTop >= parent.scrollTop; + } + + return isVisible; +}; + +exports.sanitise = function (value) { + if (typeof value !== 'string') { + return value; + } + + return value.replace(/&/g, '&').replace(/>/g, '&rt;').replace(/1&&void 0!==arguments[1]?arguments[1]:{limit:!1};this._log('---------\nSearch pattern: "'.concat(e,'"'));var n=this._prepareSearchers(e),r=n.tokenSearchers,o=n.fullSearcher,i=this._search(r,o),a=i.weights,s=i.results;return this._computeScore(a,s),this.options.shouldSort&&this._sort(s),t.limit&&"number"==typeof t.limit&&(s=s.slice(0,t.limit)),this._format(s)}},{key:"_prepareSearchers",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var n=e.split(this.options.tokenSeparator),r=0,o=n.length;r0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,n=this.list,r={},o=[];if("string"==typeof n[0]){for(var i=0,a=n.length;i1)throw new Error("Key weight has to be > 0 and <= 1");d=d.name}else s[d]={weight:1};this._analyze({key:d,value:this.options.getFn(l,d),record:l,index:c},{resultMap:r,results:o,tokenSearchers:e,fullSearcher:t})}return{weights:s,results:o}}},{key:"_analyze",value:function(e,t){var n=e.key,r=e.arrayIndex,o=void 0===r?-1:r,i=e.value,a=e.record,c=e.index,h=t.tokenSearchers,l=void 0===h?[]:h,u=t.fullSearcher,f=void 0===u?[]:u,d=t.resultMap,v=void 0===d?{}:d,p=t.results,g=void 0===p?[]:p;if(null!=i){var y=!1,m=-1,k=0;if("string"==typeof i){this._log("\nKey: ".concat(""===n?"-":n));var S=f.search(i);if(this._log('Full text: "'.concat(i,'", score: ').concat(S.score)),this.options.tokenize){for(var x=i.split(this.options.tokenSeparator),b=[],M=0;M-1&&(P=(P+m)/2),this._log("Score average:",P);var F=!this.options.tokenize||!this.options.matchAllTokens||k>=l.length;if(this._log("\nCheck Matches: ".concat(F)),(y||S.isMatch)&&F){var T=v[c];T?T.output.push({key:n,arrayIndex:o,value:i,score:P,matchedIndices:S.matchedIndices}):(v[c]={item:a,output:[{key:n,arrayIndex:o,value:i,score:P,matchedIndices:S.matchedIndices}]},g.push(v[c]))}}else if(s(i))for(var z=0,E=i.length;z-1&&(a.arrayIndex=i.arrayIndex),t.matches.push(a)}}}),this.options.includeScore&&o.push(function(e,t){t.score=e.score});for(var i=0,a=e.length;in)return o(e,this.pattern,r);var a=this.options,s=a.location,c=a.distance,h=a.threshold,l=a.findAllMatches,u=a.minMatchCharLength;return i(e,this.pattern,this.patternAlphabet,{location:s,distance:c,threshold:h,findAllMatches:l,minMatchCharLength:u})}}])&&r(t.prototype,n),s&&r(t,s),e}();e.exports=s},function(e,t){var n=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:/ +/g,o=new RegExp(t.replace(n,"\\$&").replace(r,"|")),i=e.match(o),a=!!i,s=[];if(a)for(var c=0,h=i.length;c=P;z-=1){var E=z-1,K=n[e.charAt(E)];if(K&&(x[E]=1),T[z]=(T[z+1]<<1|1)&K,0!==I&&(T[z]|=(L[z+1]|L[z])<<1|1|L[z+1]),T[z]&C&&(w=r(t,{errors:I,currentLocation:E,expectedLocation:g,distance:h}))<=m){if(m=w,(k=E)<=g)break;P=Math.max(1,2*g-k)}}if(r(t,{errors:I+1,currentLocation:g,expectedLocation:g,distance:h})>m)break;L=T}return{isMatch:k>=0,score:0===w?.001:w,matchedIndices:o(x,p)}}},function(e,t){e.exports=function(e,t){var n=t.errors,r=void 0===n?0:n,o=t.currentLocation,i=void 0===o?0:o,a=t.expectedLocation,s=void 0===a?0:a,c=t.distance,h=void 0===c?100:c,l=r/e.length,u=Math.abs(s-i);return h?l+u/h:u?1:l}},function(e,t){e.exports=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=[],r=-1,o=-1,i=0,a=e.length;i=t&&n.push([r,o]),r=-1)}return e[i-1]&&i-r>=t&&n.push([r,i-1]),n}},function(e,t){e.exports=function(e){for(var t={},n=e.length,r=0;r -1) { - return state.map(function (obj) { - var choice = obj; - - if (choice.id === parseInt(action.choiceId, 10)) { - choice.selected = true; - } - - return choice; - }); - } - - return state; - } - - case 'REMOVE_ITEM': - { - // When an item is removed and it has an associated choice, - // we want to re-enable it so it can be chosen again - if (action.choiceId > -1) { - return state.map(function (obj) { - var choice = obj; - - if (choice.id === parseInt(action.choiceId, 10)) { - choice.selected = false; - } - - return choice; - }); - } - - return state; - } - - case 'FILTER_CHOICES': - { - return state.map(function (obj) { - var choice = obj; // Set active state based on whether choice is - // within filtered results - - choice.active = action.results.some(function (_ref) { - var item = _ref.item, - score = _ref.score; - - if (item.id === choice.id) { - choice.score = score; - return true; - } - - return false; - }); - return choice; - }); - } - - case 'ACTIVATE_CHOICES': - { - return state.map(function (obj) { - var choice = obj; - choice.active = action.active; - return choice; - }); - } - - case 'CLEAR_CHOICES': - { - return choices_defaultState; - } - - default: - { - return state; - } - } -} -// CONCATENATED MODULE: ./src/scripts/reducers/general.js -var general_defaultState = { - loading: false -}; - -var general = function general(state, action) { - if (state === void 0) { - state = general_defaultState; - } - - switch (action.type) { - case 'SET_IS_LOADING': - { - return { - loading: action.isLoading - }; - } - - default: - { - return state; - } - } -}; - -/* harmony default export */ var reducers_general = (general); -// CONCATENATED MODULE: ./src/scripts/lib/utils.js -/** - * @param {number} min - * @param {number} max - * @returns {number} - */ -var getRandomNumber = function getRandomNumber(min, max) { - return Math.floor(Math.random() * (max - min) + min); -}; -/** - * @param {number} length - * @returns {string} - */ - -var generateChars = function generateChars(length) { - return Array.from({ - length: length - }, function () { - return getRandomNumber(0, 36).toString(36); - }).join(''); -}; -/** - * @param {HTMLInputElement | HTMLSelectElement} element - * @param {string} prefix - * @returns {string} - */ - -var generateId = function generateId(element, prefix) { - var id = element.id || element.name && element.name + "-" + generateChars(2) || generateChars(4); - id = id.replace(/(:|\.|\[|\]|,)/g, ''); - id = prefix + "-" + id; - return id; -}; -/** - * @param {any} obj - * @returns {string} - */ - -var getType = function getType(obj) { - return Object.prototype.toString.call(obj).slice(8, -1); -}; -/** - * @param {string} type - * @param {any} obj - * @returns {boolean} - */ - -var isType = function isType(type, obj) { - return obj !== undefined && obj !== null && getType(obj) === type; -}; -/** - * @param {HTMLElement} element - * @param {HTMLElement} [wrapper={HTMLDivElement}] - * @returns {HTMLElement} - */ - -var utils_wrap = function wrap(element, wrapper) { - if (wrapper === void 0) { - wrapper = document.createElement('div'); - } - - if (element.nextSibling) { - element.parentNode.insertBefore(wrapper, element.nextSibling); - } else { - element.parentNode.appendChild(wrapper); - } - - return wrapper.appendChild(element); -}; -/** - * @param {Element} startEl - * @param {string} selector - * @param {1 | -1} direction - * @returns {Element | undefined} - */ - -var getAdjacentEl = function getAdjacentEl(startEl, selector, direction) { - if (direction === void 0) { - direction = 1; - } - - if (!(startEl instanceof Element) || typeof selector !== 'string') { - return undefined; - } - - var prop = (direction > 0 ? 'next' : 'previous') + "ElementSibling"; - var sibling = startEl[prop]; - - while (sibling) { - if (sibling.matches(selector)) { - return sibling; - } - - sibling = sibling[prop]; - } - - return sibling; -}; -/** - * @param {Element} element - * @param {Element} parent - * @param {-1 | 1} direction - * @returns {boolean} - */ - -var isScrolledIntoView = function isScrolledIntoView(element, parent, direction) { - if (direction === void 0) { - direction = 1; - } - - if (!element) { - return false; - } - - var isVisible; - - if (direction > 0) { - // In view from bottom - isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight; - } else { - // In view from top - isVisible = element.offsetTop >= parent.scrollTop; - } - - return isVisible; -}; -/** - * @param {any} value - * @returns {any} - */ - -var sanitise = function sanitise(value) { - if (typeof value !== 'string') { - return value; - } - - return value.replace(/&/g, '&').replace(/>/g, '&rt;').replace(/ (str: string) => Element} - */ - -var strToEl = function () { - var tmpEl = document.createElement('div'); - return function (str) { - var cleanedInput = str.trim(); - tmpEl.innerHTML = cleanedInput; - var firldChild = tmpEl.children[0]; - - while (tmpEl.firstChild) { - tmpEl.removeChild(tmpEl.firstChild); - } - - return firldChild; +var __importDefault = this && this.__importDefault || function (mod) { + return mod && mod.__esModule ? mod : { + "default": mod }; -}(); -/** - * @param {{ label?: string, value: string }} a - * @param {{ label?: string, value: string }} b - * @returns {number} - */ - -var sortByAlpha = function sortByAlpha(_ref, _ref2) { - var value = _ref.value, - _ref$label = _ref.label, - label = _ref$label === void 0 ? value : _ref$label; - var value2 = _ref2.value, - _ref2$label = _ref2.label, - label2 = _ref2$label === void 0 ? value2 : _ref2$label; - return label.localeCompare(label2, [], { - sensitivity: 'base', - ignorePunctuation: true, - numeric: true - }); }; -/** - * @param {{ score: number }} a - * @param {{ score: number }} b - */ -var sortByScore = function sortByScore(a, b) { - return a.score - b.score; -}; -/** - * @param {HTMLElement} element - * @param {string} type - * @param {object} customArgs - */ - -var dispatchEvent = function dispatchEvent(element, type, customArgs) { - if (customArgs === void 0) { - customArgs = null; - } - - var event = new CustomEvent(type, { - detail: customArgs, - bubbles: true, - cancelable: true - }); - return element.dispatchEvent(event); -}; -/** - * @param {array} array - * @param {any} value - * @param {string} [key="value"] - * @returns {boolean} - */ - -var existsInArray = function existsInArray(array, value, key) { - if (key === void 0) { - key = 'value'; - } - - return array.some(function (item) { - if (typeof value === 'string') { - return item[key] === value.trim(); - } - - return item[key] === value; - }); -}; -/** - * @param {any} obj - * @returns {any} - */ - -var cloneObject = function cloneObject(obj) { - return JSON.parse(JSON.stringify(obj)); -}; -/** - * Returns an array of keys present on the first but missing on the second object - * @param {object} a - * @param {object} b - * @returns {string[]} - */ - -var diff = function diff(a, b) { - var aKeys = Object.keys(a).sort(); - var bKeys = Object.keys(b).sort(); - return aKeys.filter(function (i) { - return bKeys.indexOf(i) < 0; - }); -}; -// CONCATENATED MODULE: ./src/scripts/reducers/index.js - - - - - - -var appReducer = combineReducers({ - items: items_items, - groups: groups, - choices: choices_choices, - general: reducers_general +Object.defineProperty(exports, "__esModule", { + value: true }); -var reducers_rootReducer = function rootReducer(passedState, action) { +var redux_1 = __webpack_require__(3); + +var items_1 = __importDefault(__webpack_require__(14)); + +var groups_1 = __importDefault(__webpack_require__(15)); + +var choices_1 = __importDefault(__webpack_require__(16)); + +var loading_1 = __importDefault(__webpack_require__(17)); + +var utils_1 = __webpack_require__(1); + +exports.defaultState = { + groups: [], + items: [], + choices: [], + loading: false +}; +var appReducer = redux_1.combineReducers({ + items: items_1.default, + groups: groups_1.default, + choices: choices_1.default, + loading: loading_1.default +}); + +var rootReducer = function rootReducer(passedState, action) { var state = passedState; // If we are clearing all items, groups and options we reassign // state and then pass that state to our proper reducer. This isn't // mutating our actual state // See: http://stackoverflow.com/a/35641992 if (action.type === 'CLEAR_ALL') { - state = undefined; + state = exports.defaultState; } else if (action.type === 'RESET_TO') { - return cloneObject(action.state); + return utils_1.cloneObject(action.state); } return appReducer(state, action); }; -/* harmony default export */ var reducers = (reducers_rootReducer); -// CONCATENATED MODULE: ./src/scripts/store/store.js -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +exports.default = rootReducer; -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); -/** - * @typedef {import('../../../types/index').Choices.Choice} Choice - * @typedef {import('../../../types/index').Choices.Group} Group - * @typedef {import('../../../types/index').Choices.Item} Item - */ +var utils_1 = __webpack_require__(1); -var store_Store = -/*#__PURE__*/ +var WrappedElement = +/** @class */ function () { - function Store() { - this._store = createStore(reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); - } - /** - * Subscribe store to function call (wrapped Redux method) - * @param {Function} onChange Function to trigger when state changes - * @return - */ - - - var _proto = Store.prototype; - - _proto.subscribe = function subscribe(onChange) { - this._store.subscribe(onChange); - } - /** - * Dispatch event to store (wrapped Redux method) - * @param {{ type: string, [x: string]: any }} action Action to trigger - * @return - */ - ; - - _proto.dispatch = function dispatch(action) { - this._store.dispatch(action); - } - /** - * Get store object (wrapping Redux method) - * @returns {object} State - */ - ; - - /** - * Get loading state from store - * @returns {boolean} Loading State - */ - _proto.isLoading = function isLoading() { - return this.state.general.loading; - } - /** - * Get single choice by it's ID - * @param {string} id - * @returns {Choice | undefined} Found choice - */ - ; - - _proto.getChoiceById = function getChoiceById(id) { - return this.activeChoices.find(function (choice) { - return choice.id === parseInt(id, 10); - }); - } - /** - * Get group by group id - * @param {number} id Group ID - * @returns {Group | undefined} Group data - */ - ; - - _proto.getGroupById = function getGroupById(id) { - return this.groups.find(function (group) { - return group.id === id; - }); - }; - - _createClass(Store, [{ - key: "state", - get: function get() { - return this._store.getState(); - } - /** - * Get items from store - * @returns {Item[]} Item objects - */ - - }, { - key: "items", - get: function get() { - return this.state.items; - } - /** - * Get active items from store - * @returns {Item[]} Item objects - */ - - }, { - key: "activeItems", - get: function get() { - return this.items.filter(function (item) { - return item.active === true; - }); - } - /** - * Get highlighted items from store - * @returns {Item[]} Item objects - */ - - }, { - key: "highlightedActiveItems", - get: function get() { - return this.items.filter(function (item) { - return item.active && item.highlighted; - }); - } - /** - * Get choices from store - * @returns {Choice[]} Option objects - */ - - }, { - key: "choices", - get: function get() { - return this.state.choices; - } - /** - * Get active choices from store - * @returns {Choice[]} Option objects - */ - - }, { - key: "activeChoices", - get: function get() { - return this.choices.filter(function (choice) { - return choice.active === true; - }); - } - /** - * Get selectable choices from store - * @returns {Choice[]} Option objects - */ - - }, { - key: "selectableChoices", - get: function get() { - return this.choices.filter(function (choice) { - return choice.disabled !== true; - }); - } - /** - * Get choices that can be searched (excluding placeholders) - * @returns {Choice[]} Option objects - */ - - }, { - key: "searchableChoices", - get: function get() { - return this.selectableChoices.filter(function (choice) { - return choice.placeholder !== true; - }); - } - /** - * Get placeholder choice from store - * @returns {Choice | undefined} Found placeholder - */ - - }, { - key: "placeholderChoice", - get: function get() { - return [].concat(this.choices).reverse().find(function (choice) { - return choice.placeholder === true; - }); - } - /** - * Get groups from store - * @returns {Group[]} Group objects - */ - - }, { - key: "groups", - get: function get() { - return this.state.groups; - } - /** - * Get active groups from store - * @returns {Group[]} Group objects - */ - - }, { - key: "activeGroups", - get: function get() { - var groups = this.groups, - choices = this.choices; - return groups.filter(function (group) { - var isActive = group.active === true && group.disabled === false; - var hasActiveOptions = choices.some(function (choice) { - return choice.active === true && choice.disabled === false; - }); - return isActive && hasActiveOptions; - }, []); - } - }]); - - return Store; -}(); - - -// CONCATENATED MODULE: ./src/scripts/components/dropdown.js -function dropdown_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function dropdown_createClass(Constructor, protoProps, staticProps) { if (protoProps) dropdown_defineProperties(Constructor.prototype, protoProps); if (staticProps) dropdown_defineProperties(Constructor, staticProps); return Constructor; } - -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ -var Dropdown = -/*#__PURE__*/ -function () { - /** - * @param {{ - * element: HTMLElement, - * type: passedElement['type'], - * classNames: ClassNames, - * }} args - */ - function Dropdown(_ref) { - var element = _ref.element, - type = _ref.type, - classNames = _ref.classNames; - this.element = element; - this.classNames = classNames; - this.type = type; - this.isActive = false; - } - /** - * Bottom position of dropdown in viewport coordinates - * @returns {number} Vertical position - */ - - - var _proto = Dropdown.prototype; - - /** - * Find element that matches passed selector - * @param {string} selector - * @returns {HTMLElement | null} - */ - _proto.getChild = function getChild(selector) { - return this.element.querySelector(selector); - } - /** - * Show dropdown to user by adding active state class - * @returns {this} - */ - ; - - _proto.show = function show() { - this.element.classList.add(this.classNames.activeState); - this.element.setAttribute('aria-expanded', 'true'); - this.isActive = true; - return this; - } - /** - * Hide dropdown from user - * @returns {this} - */ - ; - - _proto.hide = function hide() { - this.element.classList.remove(this.classNames.activeState); - this.element.setAttribute('aria-expanded', 'false'); - this.isActive = false; - return this; - }; - - dropdown_createClass(Dropdown, [{ - key: "distanceFromTopWindow", - get: function get() { - return this.element.getBoundingClientRect().bottom; - } - }]); - - return Dropdown; -}(); - - -// CONCATENATED MODULE: ./src/scripts/constants.js - -/** - * @typedef {import('../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../types/index').Choices.Options} Options - */ - -/** @type {ClassNames} */ - -var DEFAULT_CLASSNAMES = { - containerOuter: 'choices', - containerInner: 'choices__inner', - input: 'choices__input', - inputCloned: 'choices__input--cloned', - list: 'choices__list', - listItems: 'choices__list--multiple', - listSingle: 'choices__list--single', - listDropdown: 'choices__list--dropdown', - item: 'choices__item', - itemSelectable: 'choices__item--selectable', - itemDisabled: 'choices__item--disabled', - itemChoice: 'choices__item--choice', - placeholder: 'choices__placeholder', - group: 'choices__group', - groupHeading: 'choices__heading', - button: 'choices__button', - activeState: 'is-active', - focusState: 'is-focused', - openState: 'is-open', - disabledState: 'is-disabled', - highlightedState: 'is-highlighted', - selectedState: 'is-selected', - flippedState: 'is-flipped', - loadingState: 'is-loading', - noResults: 'has-no-results', - noChoices: 'has-no-choices' -}; -/** @type {Options} */ - -var DEFAULT_CONFIG = { - items: [], - choices: [], - silent: false, - renderChoiceLimit: -1, - maxItemCount: -1, - addItems: true, - addItemFilter: null, - removeItems: true, - removeItemButton: false, - editItems: false, - duplicateItemsAllowed: true, - delimiter: ',', - paste: true, - searchEnabled: true, - searchChoices: true, - searchFloor: 1, - searchResultLimit: 4, - searchFields: ['label', 'value'], - position: 'auto', - resetScrollPosition: true, - shouldSort: true, - shouldSortItems: false, - sorter: sortByAlpha, - placeholder: true, - placeholderValue: null, - searchPlaceholderValue: null, - prependValue: null, - appendValue: null, - renderSelectedChoices: 'auto', - loadingText: 'Loading...', - noResultsText: 'No results found', - noChoicesText: 'No choices to choose from', - itemSelectText: 'Press to select', - uniqueItemText: 'Only unique values can be added', - customAddItemText: 'Only values matching specific conditions can be added', - addItemText: function addItemText(value) { - return "Press Enter to add \"" + sanitise(value) + "\""; - }, - maxItemText: function maxItemText(maxItemCount) { - return "Only " + maxItemCount + " values can be added"; - }, - valueComparer: function valueComparer(value1, value2) { - return value1 === value2; - }, - fuseOptions: { - includeScore: true - }, - callbackOnInit: null, - callbackOnCreateTemplates: null, - classNames: DEFAULT_CLASSNAMES -}; -var EVENTS = { - showDropdown: 'showDropdown', - hideDropdown: 'hideDropdown', - change: 'change', - choice: 'choice', - search: 'search', - addItem: 'addItem', - removeItem: 'removeItem', - highlightItem: 'highlightItem', - highlightChoice: 'highlightChoice' -}; -var ACTION_TYPES = { - ADD_CHOICE: 'ADD_CHOICE', - FILTER_CHOICES: 'FILTER_CHOICES', - ACTIVATE_CHOICES: 'ACTIVATE_CHOICES', - CLEAR_CHOICES: 'CLEAR_CHOICES', - ADD_GROUP: 'ADD_GROUP', - ADD_ITEM: 'ADD_ITEM', - REMOVE_ITEM: 'REMOVE_ITEM', - HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM', - CLEAR_ALL: 'CLEAR_ALL' -}; -var KEY_CODES = { - BACK_KEY: 46, - DELETE_KEY: 8, - ENTER_KEY: 13, - A_KEY: 65, - ESC_KEY: 27, - UP_KEY: 38, - DOWN_KEY: 40, - PAGE_UP_KEY: 33, - PAGE_DOWN_KEY: 34 -}; -var TEXT_TYPE = 'text'; -var SELECT_ONE_TYPE = 'select-one'; -var SELECT_MULTIPLE_TYPE = 'select-multiple'; -var SCROLLING_SPEED = 4; -// CONCATENATED MODULE: ./src/scripts/components/container.js - - -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ - -var container_Container = -/*#__PURE__*/ -function () { - /** - * @param {{ - * element: HTMLElement, - * type: passedElement['type'], - * classNames: ClassNames, - * position - * }} args - */ - function Container(_ref) { - var element = _ref.element, - type = _ref.type, - classNames = _ref.classNames, - position = _ref.position; - this.element = element; - this.classNames = classNames; - this.type = type; - this.position = position; - this.isOpen = false; - this.isFlipped = false; - this.isFocussed = false; - this.isDisabled = false; - this.isLoading = false; - this._onFocus = this._onFocus.bind(this); - this._onBlur = this._onBlur.bind(this); - } - - var _proto = Container.prototype; - - _proto.addEventListeners = function addEventListeners() { - this.element.addEventListener('focus', this._onFocus); - this.element.addEventListener('blur', this._onBlur); - }; - - _proto.removeEventListeners = function removeEventListeners() { - this.element.removeEventListener('focus', this._onFocus); - this.element.removeEventListener('blur', this._onBlur); - } - /** - * Determine whether container should be flipped based on passed - * dropdown position - * @param {number} dropdownPos - * @returns {boolean} - */ - ; - - _proto.shouldFlip = function shouldFlip(dropdownPos) { - if (typeof dropdownPos !== 'number') { - return false; - } // If flip is enabled and the dropdown bottom position is - // greater than the window height flip the dropdown. - - - var shouldFlip = false; - - if (this.position === 'auto') { - shouldFlip = !window.matchMedia("(min-height: " + (dropdownPos + 1) + "px)").matches; - } else if (this.position === 'top') { - shouldFlip = true; - } - - return shouldFlip; - } - /** - * @param {string} activeDescendantID - */ - ; - - _proto.setActiveDescendant = function setActiveDescendant(activeDescendantID) { - this.element.setAttribute('aria-activedescendant', activeDescendantID); - }; - - _proto.removeActiveDescendant = function removeActiveDescendant() { - this.element.removeAttribute('aria-activedescendant'); - } - /** - * @param {number} dropdownPos - */ - ; - - _proto.open = function open(dropdownPos) { - this.element.classList.add(this.classNames.openState); - this.element.setAttribute('aria-expanded', 'true'); - this.isOpen = true; - - if (this.shouldFlip(dropdownPos)) { - this.element.classList.add(this.classNames.flippedState); - this.isFlipped = true; - } - }; - - _proto.close = function close() { - this.element.classList.remove(this.classNames.openState); - this.element.setAttribute('aria-expanded', 'false'); - this.removeActiveDescendant(); - this.isOpen = false; // A dropdown flips if it does not have space within the page - - if (this.isFlipped) { - this.element.classList.remove(this.classNames.flippedState); - this.isFlipped = false; - } - }; - - _proto.focus = function focus() { - if (!this.isFocussed) { - this.element.focus(); - } - }; - - _proto.addFocusState = function addFocusState() { - this.element.classList.add(this.classNames.focusState); - }; - - _proto.removeFocusState = function removeFocusState() { - this.element.classList.remove(this.classNames.focusState); - }; - - _proto.enable = function enable() { - this.element.classList.remove(this.classNames.disabledState); - this.element.removeAttribute('aria-disabled'); - - if (this.type === SELECT_ONE_TYPE) { - this.element.setAttribute('tabindex', '0'); - } - - this.isDisabled = false; - }; - - _proto.disable = function disable() { - this.element.classList.add(this.classNames.disabledState); - this.element.setAttribute('aria-disabled', 'true'); - - if (this.type === SELECT_ONE_TYPE) { - this.element.setAttribute('tabindex', '-1'); - } - - this.isDisabled = true; - } - /** - * @param {HTMLElement} element - */ - ; - - _proto.wrap = function wrap(element) { - utils_wrap(element, this.element); - } - /** - * @param {Element} element - */ - ; - - _proto.unwrap = function unwrap(element) { - // Move passed element outside this element - this.element.parentNode.insertBefore(element, this.element); // Remove this element - - this.element.parentNode.removeChild(this.element); - }; - - _proto.addLoadingState = function addLoadingState() { - this.element.classList.add(this.classNames.loadingState); - this.element.setAttribute('aria-busy', 'true'); - this.isLoading = true; - }; - - _proto.removeLoadingState = function removeLoadingState() { - this.element.classList.remove(this.classNames.loadingState); - this.element.removeAttribute('aria-busy'); - this.isLoading = false; - }; - - _proto._onFocus = function _onFocus() { - this.isFocussed = true; - }; - - _proto._onBlur = function _onBlur() { - this.isFocussed = false; - }; - - return Container; -}(); - - -// CONCATENATED MODULE: ./src/scripts/components/input.js -function input_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function input_createClass(Constructor, protoProps, staticProps) { if (protoProps) input_defineProperties(Constructor.prototype, protoProps); if (staticProps) input_defineProperties(Constructor, staticProps); return Constructor; } - - - -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ - -var input_Input = -/*#__PURE__*/ -function () { - /** - * @param {{ - * element: HTMLInputElement, - * type: passedElement['type'], - * classNames: ClassNames, - * preventPaste: boolean - * }} args - */ - function Input(_ref) { - var element = _ref.element, - type = _ref.type, - classNames = _ref.classNames, - preventPaste = _ref.preventPaste; - this.element = element; - this.type = type; - this.classNames = classNames; - this.preventPaste = preventPaste; - this.isFocussed = this.element === document.activeElement; - this.isDisabled = element.disabled; - this._onPaste = this._onPaste.bind(this); - this._onInput = this._onInput.bind(this); - this._onFocus = this._onFocus.bind(this); - this._onBlur = this._onBlur.bind(this); - } - /** - * @param {string} placeholder - */ - - - var _proto = Input.prototype; - - _proto.addEventListeners = function addEventListeners() { - this.element.addEventListener('paste', this._onPaste); - this.element.addEventListener('input', this._onInput, { - passive: true - }); - this.element.addEventListener('focus', this._onFocus, { - passive: true - }); - this.element.addEventListener('blur', this._onBlur, { - passive: true - }); - }; - - _proto.removeEventListeners = function removeEventListeners() { - this.element.removeEventListener('input', this._onInput, { - passive: true - }); - this.element.removeEventListener('paste', this._onPaste); - this.element.removeEventListener('focus', this._onFocus, { - passive: true - }); - this.element.removeEventListener('blur', this._onBlur, { - passive: true - }); - }; - - _proto.enable = function enable() { - this.element.removeAttribute('disabled'); - this.isDisabled = false; - }; - - _proto.disable = function disable() { - this.element.setAttribute('disabled', ''); - this.isDisabled = true; - }; - - _proto.focus = function focus() { - if (!this.isFocussed) { - this.element.focus(); - } - }; - - _proto.blur = function blur() { - if (this.isFocussed) { - this.element.blur(); - } - } - /** - * Set value of input to blank - * @param {boolean} setWidth - * @returns {this} - */ - ; - - _proto.clear = function clear(setWidth) { - if (setWidth === void 0) { - setWidth = true; - } - - if (this.element.value) { - this.element.value = ''; - } - - if (setWidth) { - this.setWidth(); - } - - return this; - } - /** - * Set the correct input width based on placeholder - * value or input value - */ - ; - - _proto.setWidth = function setWidth() { - // Resize input to contents or placeholder - var _this$element = this.element, - style = _this$element.style, - value = _this$element.value, - placeholder = _this$element.placeholder; - style.minWidth = placeholder.length + 1 + "ch"; - style.width = value.length + 1 + "ch"; - } - /** - * @param {string} activeDescendantID - */ - ; - - _proto.setActiveDescendant = function setActiveDescendant(activeDescendantID) { - this.element.setAttribute('aria-activedescendant', activeDescendantID); - }; - - _proto.removeActiveDescendant = function removeActiveDescendant() { - this.element.removeAttribute('aria-activedescendant'); - }; - - _proto._onInput = function _onInput() { - if (this.type !== SELECT_ONE_TYPE) { - this.setWidth(); - } - } - /** - * @param {Event} event - */ - ; - - _proto._onPaste = function _onPaste(event) { - if (this.preventPaste) { - event.preventDefault(); - } - }; - - _proto._onFocus = function _onFocus() { - this.isFocussed = true; - }; - - _proto._onBlur = function _onBlur() { - this.isFocussed = false; - }; - - input_createClass(Input, [{ - key: "placeholder", - set: function set(placeholder) { - this.element.placeholder = placeholder; - } - /** - * @returns {string} - */ - - }, { - key: "value", - get: function get() { - return sanitise(this.element.value); - } - /** - * @param {string} value - */ - , - set: function set(value) { - this.element.value = value; - } - }]); - - return Input; -}(); - - -// CONCATENATED MODULE: ./src/scripts/components/list.js - -/** - * @typedef {import('../../../types/index').Choices.Choice} Choice - */ - -var list_List = -/*#__PURE__*/ -function () { - /** - * @param {{ element: HTMLElement }} args - */ - function List(_ref) { - var element = _ref.element; - this.element = element; - this.scrollPos = this.element.scrollTop; - this.height = this.element.offsetHeight; - } - - var _proto = List.prototype; - - _proto.clear = function clear() { - this.element.innerHTML = ''; - } - /** - * @param {Element | DocumentFragment} node - */ - ; - - _proto.append = function append(node) { - this.element.appendChild(node); - } - /** - * @param {string} selector - * @returns {Element | null} - */ - ; - - _proto.getChild = function getChild(selector) { - return this.element.querySelector(selector); - } - /** - * @returns {boolean} - */ - ; - - _proto.hasChildren = function hasChildren() { - return this.element.hasChildNodes(); - }; - - _proto.scrollToTop = function scrollToTop() { - this.element.scrollTop = 0; - } - /** - * @param {Element} element - * @param {1 | -1} direction - */ - ; - - _proto.scrollToChildElement = function scrollToChildElement(element, direction) { - var _this = this; - - if (!element) { - return; - } - - var listHeight = this.element.offsetHeight; // Scroll position of dropdown - - var listScrollPosition = this.element.scrollTop + listHeight; - var elementHeight = element.offsetHeight; // Distance from bottom of element to top of parent - - var elementPos = element.offsetTop + elementHeight; // Difference between the element and scroll position - - var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop; - requestAnimationFrame(function () { - _this._animateScroll(destination, direction); - }); - } - /** - * @param {number} scrollPos - * @param {number} strength - * @param {number} destination - */ - ; - - _proto._scrollDown = function _scrollDown(scrollPos, strength, destination) { - var easing = (destination - scrollPos) / strength; - var distance = easing > 1 ? easing : 1; - this.element.scrollTop = scrollPos + distance; - } - /** - * @param {number} scrollPos - * @param {number} strength - * @param {number} destination - */ - ; - - _proto._scrollUp = function _scrollUp(scrollPos, strength, destination) { - var easing = (scrollPos - destination) / strength; - var distance = easing > 1 ? easing : 1; - this.element.scrollTop = scrollPos - distance; - } - /** - * @param {*} destination - * @param {*} direction - */ - ; - - _proto._animateScroll = function _animateScroll(destination, direction) { - var _this2 = this; - - var strength = SCROLLING_SPEED; - var choiceListScrollTop = this.element.scrollTop; - var continueAnimation = false; - - if (direction > 0) { - this._scrollDown(choiceListScrollTop, strength, destination); - - if (choiceListScrollTop < destination) { - continueAnimation = true; - } - } else { - this._scrollUp(choiceListScrollTop, strength, destination); - - if (choiceListScrollTop > destination) { - continueAnimation = true; - } - } - - if (continueAnimation) { - requestAnimationFrame(function () { - _this2._animateScroll(destination, direction); - }); - } - }; - - return List; -}(); - - -// CONCATENATED MODULE: ./src/scripts/components/wrapped-element.js -function wrapped_element_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function wrapped_element_createClass(Constructor, protoProps, staticProps) { if (protoProps) wrapped_element_defineProperties(Constructor.prototype, protoProps); if (staticProps) wrapped_element_defineProperties(Constructor, staticProps); return Constructor; } - - -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ - -var wrapped_element_WrappedElement = -/*#__PURE__*/ -function () { - /** - * @param {{ - * element: HTMLInputElement | HTMLSelectElement, - * classNames: ClassNames, - * }} args - */ - function WrappedElement(_ref) { - var element = _ref.element, - classNames = _ref.classNames; + function WrappedElement(_a) { + var element = _a.element, + classNames = _a.classNames; this.element = element; this.classNames = classNames; @@ -2515,9 +1187,33 @@ function () { this.isDisabled = false; } - var _proto = WrappedElement.prototype; + Object.defineProperty(WrappedElement.prototype, "isActive", { + get: function get() { + return this.element.dataset.choice === 'active'; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(WrappedElement.prototype, "dir", { + get: function get() { + return this.element.dir; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(WrappedElement.prototype, "value", { + get: function get() { + return this.element.value; + }, + set: function set(value) { + // you must define setter here otherwise it will be readonly property + this.element.value = value; + }, + enumerable: true, + configurable: true + }); - _proto.conceal = function conceal() { + WrappedElement.prototype.conceal = function () { // Hide passed input this.element.classList.add(this.classNames.input); this.element.hidden = true; // Remove element from tab index @@ -2533,7 +1229,7 @@ function () { this.element.setAttribute('data-choice', 'active'); }; - _proto.reveal = function reveal() { + WrappedElement.prototype.reveal = function () { // Reinstate passed element this.element.classList.remove(this.classNames.input); this.element.hidden = false; @@ -2554,809 +1250,127 @@ function () { this.element.value = this.element.value; // eslint-disable-line no-self-assign }; - _proto.enable = function enable() { + WrappedElement.prototype.enable = function () { this.element.removeAttribute('disabled'); this.element.disabled = false; this.isDisabled = false; }; - _proto.disable = function disable() { + WrappedElement.prototype.disable = function () { this.element.setAttribute('disabled', ''); this.element.disabled = true; this.isDisabled = true; }; - _proto.triggerEvent = function triggerEvent(eventType, data) { - dispatchEvent(this.element, eventType, data); + WrappedElement.prototype.triggerEvent = function (eventType, data) { + utils_1.dispatchEvent(this.element, eventType, data); }; - wrapped_element_createClass(WrappedElement, [{ - key: "isActive", - get: function get() { - return this.element.dataset.choice === 'active'; - } - }, { - key: "dir", - get: function get() { - return this.element.dir; - } - }, { - key: "value", - get: function get() { - return this.element.value; - }, - set: function set(value) { - // you must define setter here otherwise it will be readonly property - this.element.value = value; - } - }]); - return WrappedElement; }(); +exports.default = WrappedElement; -// CONCATENATED MODULE: ./src/scripts/components/wrapped-input.js -function wrapped_input_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -function wrapped_input_createClass(Constructor, protoProps, staticProps) { if (protoProps) wrapped_input_defineProperties(Constructor.prototype, protoProps); if (staticProps) wrapped_input_defineProperties(Constructor, staticProps); return Constructor; } +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return symbolObservablePonyfill; }); +function symbolObservablePonyfill(root) { + var result; + var Symbol = root.Symbol; -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + if (typeof Symbol === 'function') { + if (Symbol.observable) { + result = Symbol.observable; + } else { + result = Symbol('observable'); + Symbol.observable = result; + } + } else { + result = '@@observable'; + } + + return result; +}; -/** - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../../types/index').Choices.Item} Item - */ +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { -var WrappedInput = -/*#__PURE__*/ -function (_WrappedElement) { - _inheritsLoose(WrappedInput, _WrappedElement); - - /** - * @param {{ - * element: HTMLInputElement, - * classNames: ClassNames, - * delimiter: string - * }} args - */ - function WrappedInput(_ref) { - var _this; - - var element = _ref.element, - classNames = _ref.classNames, - delimiter = _ref.delimiter; - _this = _WrappedElement.call(this, { - element: element, - classNames: classNames - }) || this; - _this.delimiter = delimiter; - return _this; - } - /** - * @returns {string} - */ +module.exports = __webpack_require__(8); - wrapped_input_createClass(WrappedInput, [{ - key: "value", - get: function get() { - return this.element.value; - } - /** - * @param {Item[]} items - */ - , - set: function set(items) { - var itemValues = items.map(function (_ref2) { - var value = _ref2.value; - return value; - }); - var joinedValues = itemValues.join(this.delimiter); - this.element.setAttribute('value', joinedValues); - this.element.value = joinedValues; - } - }]); +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { - return WrappedInput; -}(wrapped_element_WrappedElement); +"use strict"; -// CONCATENATED MODULE: ./src/scripts/components/wrapped-select.js -function wrapped_select_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function wrapped_select_createClass(Constructor, protoProps, staticProps) { if (protoProps) wrapped_select_defineProperties(Constructor.prototype, protoProps); if (staticProps) wrapped_select_defineProperties(Constructor, staticProps); return Constructor; } - -function wrapped_select_inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - - -/** - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../../types/index').Choices.Item} Item - * @typedef {import('../../../types/index').Choices.Choice} Choice - */ - -var WrappedSelect = -/*#__PURE__*/ -function (_WrappedElement) { - wrapped_select_inheritsLoose(WrappedSelect, _WrappedElement); - - /** - * @param {{ - * element: HTMLSelectElement, - * classNames: ClassNames, - * delimiter: string - * template: function - * }} args - */ - function WrappedSelect(_ref) { - var _this; - - var element = _ref.element, - classNames = _ref.classNames, - template = _ref.template; - _this = _WrappedElement.call(this, { - element: element, - classNames: classNames - }) || this; - _this.template = template; - return _this; +var __spreadArrays = this && this.__spreadArrays || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) { + s += arguments[i].length; } - var _proto = WrappedSelect.prototype; - - /** - * @param {DocumentFragment} fragment - */ - _proto.appendDocFragment = function appendDocFragment(fragment) { - this.element.innerHTML = ''; - this.element.appendChild(fragment); - }; - - wrapped_select_createClass(WrappedSelect, [{ - key: "placeholderOption", - get: function get() { - return this.element.querySelector('option[value=""]') || // Backward compatibility layer for the non-standard placeholder attribute supported in older versions. - this.element.querySelector('option[placeholder]'); + for (var r = Array(s), k = 0, i = 0; i < il; i++) { + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) { + r[k] = a[j]; } - /** - * @returns {Element[]} - */ - - }, { - key: "optionGroups", - get: function get() { - return Array.from(this.element.getElementsByTagName('OPTGROUP')); - } - /** - * @returns {Item[] | Choice[]} - */ - - }, { - key: "options", - get: function get() { - return Array.from(this.element.options); - } - /** - * @param {Item[] | Choice[]} options - */ - , - set: function set(options) { - var _this2 = this; - - var fragment = document.createDocumentFragment(); - - var addOptionToFragment = function addOptionToFragment(data) { - // Create a standard select option - var option = _this2.template(data); // Append it to fragment - - - fragment.appendChild(option); - }; // Add each list item to list - - - options.forEach(function (optionData) { - return addOptionToFragment(optionData); - }); - this.appendDocFragment(fragment); - } - }]); - - return WrappedSelect; -}(wrapped_element_WrappedElement); - - -// CONCATENATED MODULE: ./src/scripts/components/index.js - - - - - - - -// CONCATENATED MODULE: ./src/scripts/templates.js -/** - * Helpers to create HTML elements used by Choices - * Can be overridden by providing `callbackOnCreateTemplates` option - * @typedef {import('../../types/index').Choices.Templates} Templates - * @typedef {import('../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../types/index').Choices.Options} Options - * @typedef {import('../../types/index').Choices.Item} Item - * @typedef {import('../../types/index').Choices.Choice} Choice - * @typedef {import('../../types/index').Choices.Group} Group - */ -var TEMPLATES = -/** @type {Templates} */ -{ - /** - * @param {Partial} classNames - * @param {"ltr" | "rtl" | "auto"} dir - * @param {boolean} isSelectElement - * @param {boolean} isSelectOneElement - * @param {boolean} searchEnabled - * @param {"select-one" | "select-multiple" | "text"} passedElementType - */ - containerOuter: function containerOuter(_ref, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType) { - var _containerOuter = _ref.containerOuter; - var div = Object.assign(document.createElement('div'), { - className: _containerOuter - }); - div.dataset.type = passedElementType; - - if (dir) { - div.dir = dir; - } - - if (isSelectOneElement) { - div.tabIndex = 0; - } - - if (isSelectElement) { - div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox'); - - if (searchEnabled) { - div.setAttribute('aria-autocomplete', 'list'); - } - } - - div.setAttribute('aria-haspopup', 'true'); - div.setAttribute('aria-expanded', 'false'); - return div; - }, - - /** - * @param {Partial} classNames - */ - containerInner: function containerInner(_ref2) { - var _containerInner = _ref2.containerInner; - return Object.assign(document.createElement('div'), { - className: _containerInner - }); - }, - - /** - * @param {Partial} classNames - * @param {boolean} isSelectOneElement - */ - itemList: function itemList(_ref3, isSelectOneElement) { - var list = _ref3.list, - listSingle = _ref3.listSingle, - listItems = _ref3.listItems; - return Object.assign(document.createElement('div'), { - className: list + " " + (isSelectOneElement ? listSingle : listItems) - }); - }, - - /** - * @param {Partial} classNames - * @param {string} value - */ - placeholder: function placeholder(_ref4, value) { - var _placeholder = _ref4.placeholder; - return Object.assign(document.createElement('div'), { - className: _placeholder, - innerHTML: value - }); - }, - - /** - * @param {Partial} classNames - * @param {Item} item - * @param {boolean} removeItemButton - */ - item: function item(_ref5, _ref6, removeItemButton) { - var _item = _ref5.item, - button = _ref5.button, - highlightedState = _ref5.highlightedState, - itemSelectable = _ref5.itemSelectable, - placeholder = _ref5.placeholder; - var id = _ref6.id, - value = _ref6.value, - label = _ref6.label, - customProperties = _ref6.customProperties, - active = _ref6.active, - disabled = _ref6.disabled, - highlighted = _ref6.highlighted, - isPlaceholder = _ref6.placeholder; - var div = Object.assign(document.createElement('div'), { - className: _item, - innerHTML: label - }); - Object.assign(div.dataset, { - item: '', - id: id, - value: value, - customProperties: customProperties - }); - - if (active) { - div.setAttribute('aria-selected', 'true'); - } - - if (disabled) { - div.setAttribute('aria-disabled', 'true'); - } - - if (isPlaceholder) { - div.classList.add(placeholder); - } - - div.classList.add(highlighted ? highlightedState : itemSelectable); - - if (removeItemButton) { - if (disabled) { - div.classList.remove(itemSelectable); - } - - div.dataset.deletable = ''; - /** @todo This MUST be localizable, not hardcoded! */ - - var REMOVE_ITEM_TEXT = 'Remove item'; - var removeButton = Object.assign(document.createElement('button'), { - type: 'button', - className: button, - innerHTML: REMOVE_ITEM_TEXT - }); - removeButton.setAttribute('aria-label', REMOVE_ITEM_TEXT + ": '" + value + "'"); - removeButton.dataset.button = ''; - div.appendChild(removeButton); - } - - return div; - }, - - /** - * @param {Partial} classNames - * @param {boolean} isSelectOneElement - */ - choiceList: function choiceList(_ref7, isSelectOneElement) { - var list = _ref7.list; - var div = Object.assign(document.createElement('div'), { - className: list - }); - - if (!isSelectOneElement) { - div.setAttribute('aria-multiselectable', 'true'); - } - - div.setAttribute('role', 'listbox'); - return div; - }, - - /** - * @param {Partial} classNames - * @param {Group} group - */ - choiceGroup: function choiceGroup(_ref8, _ref9) { - var group = _ref8.group, - groupHeading = _ref8.groupHeading, - itemDisabled = _ref8.itemDisabled; - var id = _ref9.id, - value = _ref9.value, - disabled = _ref9.disabled; - var div = Object.assign(document.createElement('div'), { - className: group + " " + (disabled ? itemDisabled : '') - }); - div.setAttribute('role', 'group'); - Object.assign(div.dataset, { - group: '', - id: id, - value: value - }); - - if (disabled) { - div.setAttribute('aria-disabled', 'true'); - } - - div.appendChild(Object.assign(document.createElement('div'), { - className: groupHeading, - innerHTML: value - })); - return div; - }, - - /** - * @param {Partial} classNames - * @param {Choice} choice - * @param {Options['itemSelectText']} selectText - */ - choice: function choice(_ref10, _ref11, selectText) { - var item = _ref10.item, - itemChoice = _ref10.itemChoice, - itemSelectable = _ref10.itemSelectable, - selectedState = _ref10.selectedState, - itemDisabled = _ref10.itemDisabled, - placeholder = _ref10.placeholder; - var id = _ref11.id, - value = _ref11.value, - label = _ref11.label, - groupId = _ref11.groupId, - elementId = _ref11.elementId, - isDisabled = _ref11.disabled, - isSelected = _ref11.selected, - isPlaceholder = _ref11.placeholder; - var div = Object.assign(document.createElement('div'), { - id: elementId, - innerHTML: label, - className: item + " " + itemChoice - }); - - if (isSelected) { - div.classList.add(selectedState); - } - - if (isPlaceholder) { - div.classList.add(placeholder); - } - - div.setAttribute('role', groupId > 0 ? 'treeitem' : 'option'); - Object.assign(div.dataset, { - choice: '', - id: id, - value: value, - selectText: selectText - }); - - if (isDisabled) { - div.classList.add(itemDisabled); - div.dataset.choiceDisabled = ''; - div.setAttribute('aria-disabled', 'true'); - } else { - div.classList.add(itemSelectable); - div.dataset.choiceSelectable = ''; - } - - return div; - }, - - /** - * @param {Partial} classNames - * @param {string} placeholderValue - */ - input: function input(_ref12, placeholderValue) { - var _input = _ref12.input, - inputCloned = _ref12.inputCloned; - var inp = Object.assign(document.createElement('input'), { - type: 'text', - className: _input + " " + inputCloned, - autocomplete: 'off', - autocapitalize: 'off', - spellcheck: false - }); - inp.setAttribute('role', 'textbox'); - inp.setAttribute('aria-autocomplete', 'list'); - inp.setAttribute('aria-label', placeholderValue); - return inp; - }, - - /** - * @param {Partial} classNames - */ - dropdown: function dropdown(_ref13) { - var list = _ref13.list, - listDropdown = _ref13.listDropdown; - var div = document.createElement('div'); - div.classList.add(list, listDropdown); - div.setAttribute('aria-expanded', 'false'); - return div; - }, - - /** - * - * @param {Partial} classNames - * @param {string} innerHTML - * @param {"no-choices" | "no-results" | ""} type - */ - notice: function notice(_ref14, innerHTML, type) { - var item = _ref14.item, - itemChoice = _ref14.itemChoice, - noResults = _ref14.noResults, - noChoices = _ref14.noChoices; - - if (type === void 0) { - type = ''; - } - - var classes = [item, itemChoice]; - - if (type === 'no-choices') { - classes.push(noChoices); - } else if (type === 'no-results') { - classes.push(noResults); - } - - return Object.assign(document.createElement('div'), { - innerHTML: innerHTML, - className: classes.join(' ') - }); - }, - - /** - * @param {Item} option - */ - option: function option(_ref15) { - var label = _ref15.label, - value = _ref15.value, - customProperties = _ref15.customProperties, - active = _ref15.active, - disabled = _ref15.disabled; - var opt = new Option(label, value, false, active); - - if (customProperties) { - opt.dataset.customProperties = customProperties; - } - - opt.disabled = disabled; - return opt; - } -}; -/* harmony default export */ var templates = (TEMPLATES); -// CONCATENATED MODULE: ./src/scripts/actions/choices.js -/** - * @typedef {import('redux').Action} Action - * @typedef {import('../../../types/index').Choices.Choice} Choice - */ - -/** - * @argument {Choice} choice - * @returns {Action & Choice} - */ - -var choices_addChoice = function addChoice(_ref) { - var value = _ref.value, - label = _ref.label, - id = _ref.id, - groupId = _ref.groupId, - disabled = _ref.disabled, - elementId = _ref.elementId, - customProperties = _ref.customProperties, - placeholder = _ref.placeholder, - keyCode = _ref.keyCode; - return { - type: ACTION_TYPES.ADD_CHOICE, - value: value, - label: label, - id: id, - groupId: groupId, - disabled: disabled, - elementId: elementId, - customProperties: customProperties, - placeholder: placeholder, - keyCode: keyCode - }; -}; -/** - * @argument {Choice[]} results - * @returns {Action & { results: Choice[] }} - */ - -var choices_filterChoices = function filterChoices(results) { - return { - type: ACTION_TYPES.FILTER_CHOICES, - results: results - }; -}; -/** - * @argument {boolean} active - * @returns {Action & { active: boolean }} - */ - -var choices_activateChoices = function activateChoices(active) { - if (active === void 0) { - active = true; } - return { - type: ACTION_TYPES.ACTIVATE_CHOICES, - active: active + return r; +}; + +var __importDefault = this && this.__importDefault || function (mod) { + return mod && mod.__esModule ? mod : { + "default": mod }; }; -/** - * @returns {Action} - */ -var choices_clearChoices = function clearChoices() { - return { - type: ACTION_TYPES.CLEAR_CHOICES - }; -}; -// CONCATENATED MODULE: ./src/scripts/actions/items.js - -/** - * @typedef {import('redux').Action} Action - * @typedef {import('../../../types/index').Choices.Item} Item - */ - -/** - * @param {Item} item - * @returns {Action & Item} - */ - -var items_addItem = function addItem(_ref) { - var value = _ref.value, - label = _ref.label, - id = _ref.id, - choiceId = _ref.choiceId, - groupId = _ref.groupId, - customProperties = _ref.customProperties, - placeholder = _ref.placeholder, - keyCode = _ref.keyCode; - return { - type: ACTION_TYPES.ADD_ITEM, - value: value, - label: label, - id: id, - choiceId: choiceId, - groupId: groupId, - customProperties: customProperties, - placeholder: placeholder, - keyCode: keyCode - }; -}; -/** - * @param {string} id - * @param {string} choiceId - * @returns {Action & { id: string, choiceId: string }} - */ - -var items_removeItem = function removeItem(id, choiceId) { - return { - type: ACTION_TYPES.REMOVE_ITEM, - id: id, - choiceId: choiceId - }; -}; -/** - * @param {string} id - * @param {boolean} highlighted - * @returns {Action & { id: string, highlighted: boolean }} - */ - -var items_highlightItem = function highlightItem(id, highlighted) { - return { - type: ACTION_TYPES.HIGHLIGHT_ITEM, - id: id, - highlighted: highlighted - }; -}; -// CONCATENATED MODULE: ./src/scripts/actions/groups.js - -/** - * @typedef {import('redux').Action} Action - * @typedef {import('../../../types/index').Choices.Group} Group - */ - -/** - * @param {Group} group - * @returns {Action & Group} - */ - -var groups_addGroup = function addGroup(_ref) { - var value = _ref.value, - id = _ref.id, - active = _ref.active, - disabled = _ref.disabled; - return { - type: ACTION_TYPES.ADD_GROUP, - value: value, - id: id, - active: active, - disabled: disabled - }; -}; -// CONCATENATED MODULE: ./src/scripts/actions/misc.js -/** - * @typedef {import('redux').Action} Action - */ - -/** - * @returns {Action} - */ -var clearAll = function clearAll() { - return { - type: 'CLEAR_ALL' - }; -}; -/** - * @param {any} state - * @returns {Action & { state: object }} - */ - -var resetTo = function resetTo(state) { - return { - type: 'RESET_TO', - state: state - }; -}; -/** - * @param {boolean} isLoading - * @returns {Action & { isLoading: boolean }} - */ - -var setIsLoading = function setIsLoading(isLoading) { - return { - type: 'SET_IS_LOADING', - isLoading: isLoading - }; -}; -// CONCATENATED MODULE: ./src/scripts/choices.js -function choices_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function choices_createClass(Constructor, protoProps, staticProps) { if (protoProps) choices_defineProperties(Constructor.prototype, protoProps); if (staticProps) choices_defineProperties(Constructor, staticProps); return Constructor; } +Object.defineProperty(exports, "__esModule", { + value: true +}); +/* eslint-disable @typescript-eslint/no-explicit-any */ +var fuse_js_1 = __importDefault(__webpack_require__(9)); +var deepmerge_1 = __importDefault(__webpack_require__(10)); +var store_1 = __importDefault(__webpack_require__(11)); +var components_1 = __webpack_require__(18); +var constants_1 = __webpack_require__(0); +var templates_1 = __importDefault(__webpack_require__(25)); +var choices_1 = __webpack_require__(26); +var items_1 = __webpack_require__(27); +var groups_1 = __webpack_require__(28); +var misc_1 = __webpack_require__(29); +var utils_1 = __webpack_require__(1); +var reducers_1 = __webpack_require__(4); /** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */ + var IS_IE11 = '-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style; -/** - * @typedef {import('../../types/index').Choices.Choice} Choice - * @typedef {import('../../types/index').Choices.Item} Item - * @typedef {import('../../types/index').Choices.Group} Group - * @typedef {import('../../types/index').Choices.Options} Options - */ - -/** @type {Partial} */ - var USER_DEFAULTS = {}; /** * Choices * @author Josh Johnson */ -var choices_Choices = -/*#__PURE__*/ +var Choices = +/** @class */ function () { - choices_createClass(Choices, null, [{ - key: "defaults", - get: function get() { - return Object.preventExtensions({ - get options() { - return USER_DEFAULTS; - }, - - get templates() { - return TEMPLATES; - } - - }); - } - /** - * @param {string | HTMLInputElement | HTMLSelectElement} element - * @param {Partial} userConfig - */ - - }]); - function Choices(element, userConfig) { var _this = this; @@ -3368,15 +1382,14 @@ function () { userConfig = {}; } - /** @type {Partial} */ - this.config = cjs_default.a.all([DEFAULT_CONFIG, Choices.defaults.options, userConfig], // When merging array configs, replace with a copy of the userConfig array, + this.config = deepmerge_1.default.all([constants_1.DEFAULT_CONFIG, Choices.defaults.options, userConfig], // When merging array configs, replace with a copy of the userConfig array, // instead of concatenating with the default array { arrayMerge: function arrayMerge(_, sourceArray) { - return [].concat(sourceArray); + return __spreadArrays(sourceArray); } }); - var invalidConfigOptions = diff(this.config, DEFAULT_CONFIG); + var invalidConfigOptions = utils_1.diff(this.config, constants_1.DEFAULT_CONFIG); if (invalidConfigOptions.length) { console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', ')); @@ -3388,13 +1401,13 @@ function () { throw TypeError('Expected one of the following types text|select-one|select-multiple'); } - this._isTextElement = passedElement.type === TEXT_TYPE; - this._isSelectOneElement = passedElement.type === SELECT_ONE_TYPE; - this._isSelectMultipleElement = passedElement.type === SELECT_MULTIPLE_TYPE; + this._isTextElement = passedElement.type === constants_1.TEXT_TYPE; + this._isSelectOneElement = passedElement.type === constants_1.SELECT_ONE_TYPE; + this._isSelectMultipleElement = passedElement.type === constants_1.SELECT_MULTIPLE_TYPE; this._isSelectElement = this._isSelectOneElement || this._isSelectMultipleElement; this.config.searchEnabled = this._isSelectMultipleElement || this.config.searchEnabled; - if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) { + if (!['auto', 'always'].includes("" + this.config.renderSelectedChoices)) { this.config.renderSelectedChoices = 'auto'; } @@ -3404,13 +1417,13 @@ function () { } if (this._isTextElement) { - this.passedElement = new WrappedInput({ + this.passedElement = new components_1.WrappedInput({ element: passedElement, classNames: this.config.classNames, delimiter: this.config.delimiter }); } else { - this.passedElement = new WrappedSelect({ + this.passedElement = new components_1.WrappedSelect({ element: passedElement, classNames: this.config.classNames, template: function template(data) { @@ -3420,31 +1433,27 @@ function () { } this.initialised = false; - this._store = new store_Store(); - this._initialState = {}; - this._currentState = {}; - this._prevState = {}; + this._store = new store_1.default(); + this._initialState = reducers_1.defaultState; + this._currentState = reducers_1.defaultState; + this._prevState = reducers_1.defaultState; this._currentValue = ''; - this._canSearch = this.config.searchEnabled; + this._canSearch = !!this.config.searchEnabled; this._isScrollingOnIe = false; this._highlightPosition = 0; this._wasTap = true; this._placeholderValue = this._generatePlaceholderValue(); - this._baseId = generateId(this.passedElement.element, 'choices-'); + this._baseId = utils_1.generateId(this.passedElement.element, 'choices-'); /** * setting direction in cases where it's explicitly set on passedElement * or when calculated direction is different from the document - * @type {HTMLElement['dir']} */ this._direction = this.passedElement.dir; if (!this._direction) { - var _window$getComputedSt = window.getComputedStyle(this.passedElement.element), - elementDirection = _window$getComputedSt.direction; - - var _window$getComputedSt2 = window.getComputedStyle(document.documentElement), - documentDirection = _window$getComputedSt2.direction; + var elementDirection = window.getComputedStyle(this.passedElement.element).direction; + var documentDirection = window.getComputedStyle(document.documentElement).direction; if (elementDirection !== documentDirection) { this._direction = elementDirection; @@ -3453,30 +1462,35 @@ function () { this._idNames = { itemChoice: 'item-choice' - }; // Assign preset groups from passed element + }; - this._presetGroups = this.passedElement.optionGroups; // Assign preset options from passed element + if (this._isSelectElement) { + // Assign preset groups from passed element + this._presetGroups = this.passedElement.optionGroups; // Assign preset options from passed element + + this._presetOptions = this.passedElement.options; + } // Assign preset choices from passed object - this._presetOptions = this.passedElement.options; // Assign preset choices from passed object this._presetChoices = this.config.choices; // Assign preset items from passed object first this._presetItems = this.config.items; // Add any values passed from attribute - if (this.passedElement.value) { - this._presetItems = this._presetItems.concat(this.passedElement.value.split(this.config.delimiter)); + if (this.passedElement.value && this._isTextElement) { + var splitValues = this.passedElement.value.split(this.config.delimiter); + this._presetItems = this._presetItems.concat(splitValues); } // Create array of choices from option elements if (this.passedElement.options) { - this.passedElement.options.forEach(function (o) { + this.passedElement.options.forEach(function (option) { _this._presetChoices.push({ - value: o.value, - label: o.innerHTML, - selected: o.selected, - disabled: o.disabled || o.parentNode.disabled, - placeholder: o.value === '' || o.hasAttribute('placeholder'), - customProperties: o.getAttribute('data-custom-properties') + value: option.value, + label: option.innerHTML, + selected: !!option.selected, + disabled: option.disabled || option.parentNode.disabled, + placeholder: option.value === '' || option.hasAttribute('placeholder'), + customProperties: option.dataset['custom-properties'] }); }); } @@ -3492,7 +1506,7 @@ function () { this._onMouseDown = this._onMouseDown.bind(this); this._onMouseOver = this._onMouseOver.bind(this); this._onFormReset = this._onFormReset.bind(this); - this._onAKey = this._onAKey.bind(this); + this._onSelectKey = this._onSelectKey.bind(this); this._onEnterKey = this._onEnterKey.bind(this); this._onEscapeKey = this._onEscapeKey.bind(this); this._onDirectionKey = this._onDirectionKey.bind(this); @@ -3500,7 +1514,9 @@ function () { if (this.passedElement.isActive) { if (!this.config.silent) { - console.warn('Trying to initialise Choices on element already initialised'); + console.warn('Trying to initialise Choices on element already initialised', { + element: element + }); } this.initialised = true; @@ -3511,9 +1527,24 @@ function () { this.init(); } - var _proto = Choices.prototype; + Object.defineProperty(Choices, "defaults", { + get: function get() { + return Object.preventExtensions({ + get options() { + return USER_DEFAULTS; + }, - _proto.init = function init() { + get templates() { + return templates_1.default; + } + + }); + }, + enumerable: true, + configurable: true + }); + + Choices.prototype.init = function () { if (this.initialised) { return; } @@ -3522,11 +1553,7 @@ function () { this._createElements(); - this._createStructure(); // Set initial state (We need to clone the state because some reducers - // modify the inner objects properties in the state) 🤢 - - - this._initialState = cloneObject(this._store.state); + this._createStructure(); this._store.subscribe(this._render); @@ -3548,7 +1575,7 @@ function () { } }; - _proto.destroy = function destroy() { + Choices.prototype.destroy = function () { if (!this.initialised) { return; } @@ -3563,11 +1590,11 @@ function () { this.passedElement.options = this._presetOptions; } - this._templates = null; + this._templates = templates_1.default; this.initialised = false; }; - _proto.enable = function enable() { + Choices.prototype.enable = function () { if (this.passedElement.isDisabled) { this.passedElement.enable(); } @@ -3582,7 +1609,7 @@ function () { return this; }; - _proto.disable = function disable() { + Choices.prototype.disable = function () { if (!this.passedElement.isDisabled) { this.passedElement.disable(); } @@ -3597,28 +1624,28 @@ function () { return this; }; - _proto.highlightItem = function highlightItem(item, runEvent) { + Choices.prototype.highlightItem = function (item, runEvent) { if (runEvent === void 0) { runEvent = true; } - if (!item) { + if (!item || !item.id) { return this; } var id = item.id, - _item$groupId = item.groupId, - groupId = _item$groupId === void 0 ? -1 : _item$groupId, - _item$value = item.value, - value = _item$value === void 0 ? '' : _item$value, - _item$label = item.label, - label = _item$label === void 0 ? '' : _item$label; + _a = item.groupId, + groupId = _a === void 0 ? -1 : _a, + _b = item.value, + value = _b === void 0 ? '' : _b, + _c = item.label, + label = _c === void 0 ? '' : _c; var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; - this._store.dispatch(items_highlightItem(id, true)); + this._store.dispatch(items_1.highlightItem(id, true)); if (runEvent) { - this.passedElement.triggerEvent(EVENTS.highlightItem, { + this.passedElement.triggerEvent(constants_1.EVENTS.highlightItem, { id: id, value: value, label: label, @@ -3629,23 +1656,23 @@ function () { return this; }; - _proto.unhighlightItem = function unhighlightItem(item) { - if (!item) { + Choices.prototype.unhighlightItem = function (item) { + if (!item || !item.id) { return this; } var id = item.id, - _item$groupId2 = item.groupId, - groupId = _item$groupId2 === void 0 ? -1 : _item$groupId2, - _item$value2 = item.value, - value = _item$value2 === void 0 ? '' : _item$value2, - _item$label2 = item.label, - label = _item$label2 === void 0 ? '' : _item$label2; + _a = item.groupId, + groupId = _a === void 0 ? -1 : _a, + _b = item.value, + value = _b === void 0 ? '' : _b, + _c = item.label, + label = _c === void 0 ? '' : _c; var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; - this._store.dispatch(items_highlightItem(id, false)); + this._store.dispatch(items_1.highlightItem(id, false)); - this.passedElement.triggerEvent(EVENTS.highlightItem, { + this.passedElement.triggerEvent(constants_1.EVENTS.highlightItem, { id: id, value: value, label: label, @@ -3654,116 +1681,116 @@ function () { return this; }; - _proto.highlightAll = function highlightAll() { - var _this2 = this; + Choices.prototype.highlightAll = function () { + var _this = this; this._store.items.forEach(function (item) { - return _this2.highlightItem(item); + return _this.highlightItem(item); }); return this; }; - _proto.unhighlightAll = function unhighlightAll() { - var _this3 = this; + Choices.prototype.unhighlightAll = function () { + var _this = this; this._store.items.forEach(function (item) { - return _this3.unhighlightItem(item); + return _this.unhighlightItem(item); }); return this; }; - _proto.removeActiveItemsByValue = function removeActiveItemsByValue(value) { - var _this4 = this; + Choices.prototype.removeActiveItemsByValue = function (value) { + var _this = this; this._store.activeItems.filter(function (item) { return item.value === value; }).forEach(function (item) { - return _this4._removeItem(item); + return _this._removeItem(item); }); return this; }; - _proto.removeActiveItems = function removeActiveItems(excludedId) { - var _this5 = this; + Choices.prototype.removeActiveItems = function (excludedId) { + var _this = this; - this._store.activeItems.filter(function (_ref) { - var id = _ref.id; + this._store.activeItems.filter(function (_a) { + var id = _a.id; return id !== excludedId; }).forEach(function (item) { - return _this5._removeItem(item); + return _this._removeItem(item); }); return this; }; - _proto.removeHighlightedItems = function removeHighlightedItems(runEvent) { - var _this6 = this; + Choices.prototype.removeHighlightedItems = function (runEvent) { + var _this = this; if (runEvent === void 0) { runEvent = false; } this._store.highlightedActiveItems.forEach(function (item) { - _this6._removeItem(item); // If this action was performed by the user + _this._removeItem(item); // If this action was performed by the user // trigger the event if (runEvent) { - _this6._triggerChange(item.value); + _this._triggerChange(item.value); } }); return this; }; - _proto.showDropdown = function showDropdown(preventInputFocus) { - var _this7 = this; + Choices.prototype.showDropdown = function (preventInputFocus) { + var _this = this; if (this.dropdown.isActive) { return this; } requestAnimationFrame(function () { - _this7.dropdown.show(); + _this.dropdown.show(); - _this7.containerOuter.open(_this7.dropdown.distanceFromTopWindow); + _this.containerOuter.open(_this.dropdown.distanceFromTopWindow); - if (!preventInputFocus && _this7._canSearch) { - _this7.input.focus(); + if (!preventInputFocus && _this._canSearch) { + _this.input.focus(); } - _this7.passedElement.triggerEvent(EVENTS.showDropdown, {}); + _this.passedElement.triggerEvent(constants_1.EVENTS.showDropdown, {}); }); return this; }; - _proto.hideDropdown = function hideDropdown(preventInputBlur) { - var _this8 = this; + Choices.prototype.hideDropdown = function (preventInputBlur) { + var _this = this; if (!this.dropdown.isActive) { return this; } requestAnimationFrame(function () { - _this8.dropdown.hide(); + _this.dropdown.hide(); - _this8.containerOuter.close(); + _this.containerOuter.close(); - if (!preventInputBlur && _this8._canSearch) { - _this8.input.removeActiveDescendant(); + if (!preventInputBlur && _this._canSearch) { + _this.input.removeActiveDescendant(); - _this8.input.blur(); + _this.input.blur(); } - _this8.passedElement.triggerEvent(EVENTS.hideDropdown, {}); + _this.passedElement.triggerEvent(constants_1.EVENTS.hideDropdown, {}); }); return this; }; - _proto.getValue = function getValue(valueOnly) { + Choices.prototype.getValue = function (valueOnly) { if (valueOnly === void 0) { valueOnly = false; } @@ -3775,27 +1802,23 @@ function () { }, []); return this._isSelectOneElement ? values[0] : values; - } - /** - * @param {string[] | import('../../types/index').Choices.Item[]} items - */ - ; + }; - _proto.setValue = function setValue(items) { - var _this9 = this; + Choices.prototype.setValue = function (items) { + var _this = this; if (!this.initialised) { return this; } items.forEach(function (value) { - return _this9._setChoiceOrItem(value); + return _this._setChoiceOrItem(value); }); return this; }; - _proto.setChoiceByValue = function setChoiceByValue(value) { - var _this10 = this; + Choices.prototype.setChoiceByValue = function (value) { + var _this = this; if (!this.initialised || this._isTextElement) { return this; @@ -3805,10 +1828,10 @@ function () { var choiceValue = Array.isArray(value) ? value : [value]; // Loop through each value and choiceValue.forEach(function (val) { - return _this10._findAndSelectChoiceByValue(val); + return _this._findAndSelectChoiceByValue(val); }); return this; - } + }; /** * Set choices of select input via an array of objects (or function that returns array of object or promise of it), * a value field name and a label field name. @@ -3818,13 +1841,6 @@ function () { * * **Input types affected:** select-one, select-multiple * - * @template {Choice[] | ((instance: Choices) => object[] | Promise)} T - * @param {T} [choicesArrayOrFetcher] - * @param {string} [value = 'value'] - name of `value` field - * @param {string} [label = 'label'] - name of 'label' field - * @param {boolean} [replaceChoices = false] - whether to replace of add choices - * @returns {this | Promise} - * * @example * ```js * const example = new Choices(element); @@ -3879,10 +1895,10 @@ function () { * }], 'value', 'label', false); * ``` */ - ; - _proto.setChoices = function setChoices(choicesArrayOrFetcher, value, label, replaceChoices) { - var _this11 = this; + + Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices) { + var _this = this; if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; @@ -3919,37 +1935,38 @@ function () { if (typeof choicesArrayOrFetcher === 'function') { // it's a choices fetcher function - var fetcher = choicesArrayOrFetcher(this); + var fetcher_1 = choicesArrayOrFetcher(this); - if (typeof Promise === 'function' && fetcher instanceof Promise) { + if (typeof Promise === 'function' && fetcher_1 instanceof Promise) { // that's a promise // eslint-disable-next-line compat/compat return new Promise(function (resolve) { return requestAnimationFrame(resolve); + }) // eslint-disable-line compat/compat + .then(function () { + return _this._handleLoadingState(true); }).then(function () { - return _this11._handleLoadingState(true); - }).then(function () { - return fetcher; + return fetcher_1; }).then(function (data) { - return _this11.setChoices(data, value, label, replaceChoices); + return _this.setChoices(data, value, label, replaceChoices); }).catch(function (err) { - if (!_this11.config.silent) { + if (!_this.config.silent) { console.error(err); } }).then(function () { - return _this11._handleLoadingState(false); + return _this._handleLoadingState(false); }).then(function () { - return _this11; + return _this; }); } // function returned something else than promise, let's check if it's an array of choices - if (!Array.isArray(fetcher)) { - throw new TypeError(".setChoices first argument function must return either array of choices or Promise, got: " + typeof fetcher); + if (!Array.isArray(fetcher_1)) { + throw new TypeError(".setChoices first argument function must return either array of choices or Promise, got: " + typeof fetcher_1); } // recursion with results, it's sync and choices were cleared already - return this.setChoices(fetcher, value, label, false); + return this.setChoices(fetcher_1, value, label, false); } if (!Array.isArray(choicesArrayOrFetcher)) { @@ -3962,20 +1979,22 @@ function () { choicesArrayOrFetcher.forEach(function (groupOrChoice) { if (groupOrChoice.choices) { - _this11._addGroup({ - id: parseInt(groupOrChoice.id, 10) || null, + _this._addGroup({ + id: groupOrChoice.id ? parseInt("" + groupOrChoice.id, 10) : null, group: groupOrChoice, valueKey: value, labelKey: label }); } else { - _this11._addChoice({ - value: groupOrChoice[value], - label: groupOrChoice[label], - isSelected: groupOrChoice.selected, - isDisabled: groupOrChoice.disabled, - customProperties: groupOrChoice.customProperties, - placeholder: groupOrChoice.placeholder + var choice = groupOrChoice; + + _this._addChoice({ + value: choice[value], + label: choice[label], + isSelected: !!choice.selected, + isDisabled: !!choice.disabled, + placeholder: !!choice.placeholder, + customProperties: choice.customProperties }); } }); @@ -3985,32 +2004,32 @@ function () { return this; }; - _proto.clearChoices = function clearChoices() { - this._store.dispatch(choices_clearChoices()); + Choices.prototype.clearChoices = function () { + this._store.dispatch(choices_1.clearChoices()); return this; }; - _proto.clearStore = function clearStore() { - this._store.dispatch(clearAll()); + Choices.prototype.clearStore = function () { + this._store.dispatch(misc_1.clearAll()); return this; }; - _proto.clearInput = function clearInput() { + Choices.prototype.clearInput = function () { var shouldSetInputWidth = !this._isSelectOneElement; this.input.clear(shouldSetInputWidth); if (!this._isTextElement && this._canSearch) { this._isSearching = false; - this._store.dispatch(choices_activateChoices(true)); + this._store.dispatch(choices_1.activateChoices(true)); } return this; }; - _proto._render = function _render() { + Choices.prototype._render = function () { if (this._store.isLoading()) { return; } @@ -4035,18 +2054,18 @@ function () { this._prevState = this._currentState; }; - _proto._renderChoices = function _renderChoices() { - var _this12 = this; + Choices.prototype._renderChoices = function () { + var _this = this; - var _this$_store = this._store, - activeGroups = _this$_store.activeGroups, - activeChoices = _this$_store.activeChoices; + var _a = this._store, + activeGroups = _a.activeGroups, + activeChoices = _a.activeChoices; var choiceListFragment = document.createDocumentFragment(); this.choiceList.clear(); if (this.config.resetScrollPosition) { requestAnimationFrame(function () { - return _this12.choiceList.scrollToTop(); + return _this.choiceList.scrollToTop(); }); } // If we have grouped options @@ -4079,13 +2098,14 @@ function () { this._highlightChoice(); } else { - // ...otherwise show a notice - this.choiceList.append(this._getTemplate('notice', canAddItem.notice)); + var notice = this._getTemplate('notice', canAddItem.notice); + + this.choiceList.append(notice); } } else { // Otherwise show a notice - var dropdownItem; - var notice; + var dropdownItem = void 0; + var notice = void 0; if (this._isSearching) { notice = typeof this.config.noResultsText === 'function' ? this.config.noResultsText() : this.config.noResultsText; @@ -4099,7 +2119,7 @@ function () { } }; - _proto._renderItems = function _renderItems() { + Choices.prototype._renderItems = function () { var activeItems = this._store.activeItems || []; this.itemList.clear(); // Create a fragment to store our list items // (so we don't have to update the DOM for each item) @@ -4112,8 +2132,8 @@ function () { } }; - _proto._createGroupsFragment = function _createGroupsFragment(groups, choices, fragment) { - var _this13 = this; + Choices.prototype._createGroupsFragment = function (groups, choices, fragment) { + var _this = this; if (fragment === void 0) { fragment = document.createDocumentFragment(); @@ -4121,11 +2141,11 @@ function () { var getGroupChoices = function getGroupChoices(group) { return choices.filter(function (choice) { - if (_this13._isSelectOneElement) { + if (_this._isSelectOneElement) { return choice.groupId === group.id; } - return choice.groupId === group.id && (_this13.config.renderSelectedChoices === 'always' || !choice.selected); + return choice.groupId === group.id && (_this.config.renderSelectedChoices === 'always' || !choice.selected); }); }; // If sorting is enabled, filter groups @@ -4138,18 +2158,18 @@ function () { var groupChoices = getGroupChoices(group); if (groupChoices.length >= 1) { - var dropdownGroup = _this13._getTemplate('choiceGroup', group); + var dropdownGroup = _this._getTemplate('choiceGroup', group); fragment.appendChild(dropdownGroup); - _this13._createChoicesFragment(groupChoices, fragment, true); + _this._createChoicesFragment(groupChoices, fragment, true); } }); return fragment; }; - _proto._createChoicesFragment = function _createChoicesFragment(choices, fragment, withinGroup) { - var _this14 = this; + Choices.prototype._createChoicesFragment = function (choices, fragment, withinGroup) { + var _this = this; if (fragment === void 0) { fragment = document.createDocumentFragment(); @@ -4157,20 +2177,20 @@ function () { if (withinGroup === void 0) { withinGroup = false; - } + } // Create a fragment to store our list items (so we don't have to update the DOM for each item) - // Create a fragment to store our list items (so we don't have to update the DOM for each item) - var _this$config = this.config, - renderSelectedChoices = _this$config.renderSelectedChoices, - searchResultLimit = _this$config.searchResultLimit, - renderChoiceLimit = _this$config.renderChoiceLimit; - var filter = this._isSearching ? sortByScore : this.config.sorter; + + var _a = this.config, + renderSelectedChoices = _a.renderSelectedChoices, + searchResultLimit = _a.searchResultLimit, + renderChoiceLimit = _a.renderChoiceLimit; + var filter = this._isSearching ? utils_1.sortByScore : this.config.sorter; var appendChoice = function appendChoice(choice) { - var shouldRender = renderSelectedChoices === 'auto' ? _this14._isSelectOneElement || !choice.selected : true; + var shouldRender = renderSelectedChoices === 'auto' ? _this._isSelectOneElement || !choice.selected : true; if (shouldRender) { - var dropdownItem = _this14._getTemplate('choice', choice, _this14.config.itemSelectText); + var dropdownItem = _this._getTemplate('choice', choice, _this.config.itemSelectText); fragment.appendChild(dropdownItem); } @@ -4185,7 +2205,7 @@ function () { } // Split array into placeholders and "normal" choices - var _rendererableChoices$ = rendererableChoices.reduce(function (acc, choice) { + var _b = rendererableChoices.reduce(function (acc, choice) { if (choice.placeholder) { acc.placeholderChoices.push(choice); } else { @@ -4197,8 +2217,8 @@ function () { placeholderChoices: [], normalChoices: [] }), - placeholderChoices = _rendererableChoices$.placeholderChoices, - normalChoices = _rendererableChoices$.normalChoices; // If sorting is enabled or the user is searching, filter choices + placeholderChoices = _b.placeholderChoices, + normalChoices = _b.normalChoices; // If sorting is enabled or the user is searching, filter choices if (this.config.shouldSort || this._isSearching) { @@ -4207,7 +2227,7 @@ function () { var choiceLimit = rendererableChoices.length; // Prepend placeholeder - var sortedChoices = this._isSelectOneElement ? [].concat(placeholderChoices, normalChoices) : normalChoices; + var sortedChoices = this._isSelectOneElement ? __spreadArrays(placeholderChoices, normalChoices) : normalChoices; if (this._isSearching) { choiceLimit = searchResultLimit; @@ -4225,18 +2245,18 @@ function () { return fragment; }; - _proto._createItemsFragment = function _createItemsFragment(items, fragment) { - var _this15 = this; + Choices.prototype._createItemsFragment = function (items, fragment) { + var _this = this; if (fragment === void 0) { fragment = document.createDocumentFragment(); - } + } // Create fragment to add elements to - // Create fragment to add elements to - var _this$config2 = this.config, - shouldSortItems = _this$config2.shouldSortItems, - sorter = _this$config2.sorter, - removeItemButton = _this$config2.removeItemButton; // If sorting is enabled, filter items + + var _a = this.config, + shouldSortItems = _a.shouldSortItems, + sorter = _a.sorter, + removeItemButton = _a.removeItemButton; // If sorting is enabled, filter items if (shouldSortItems && !this._isSelectOneElement) { items.sort(sorter); @@ -4244,7 +2264,10 @@ function () { if (this._isTextElement) { // Update the value of the hidden input - this.passedElement.value = items; + this.passedElement.value = items.map(function (_a) { + var value = _a.value; + return value; + }).join(this.config.delimiter); } else { // Update the options of the hidden input this.passedElement.options = items; @@ -4252,7 +2275,7 @@ function () { var addItemToFragment = function addItemToFragment(item) { // Create new list element - var listItem = _this15._getTemplate('item', item, removeItemButton); // Append it to list + var listItem = _this._getTemplate('item', item, removeItemButton); // Append it to list fragment.appendChild(listItem); @@ -4263,53 +2286,54 @@ function () { return fragment; }; - _proto._triggerChange = function _triggerChange(value) { + Choices.prototype._triggerChange = function (value) { if (value === undefined || value === null) { return; } - this.passedElement.triggerEvent(EVENTS.change, { + this.passedElement.triggerEvent(constants_1.EVENTS.change, { value: value }); }; - _proto._selectPlaceholderChoice = function _selectPlaceholderChoice() { - var placeholderChoice = this._store.placeholderChoice; + Choices.prototype._selectPlaceholderChoice = function (placeholderChoice) { + this._addItem({ + value: placeholderChoice.value, + label: placeholderChoice.label, + choiceId: placeholderChoice.id, + groupId: placeholderChoice.groupId, + placeholder: placeholderChoice.placeholder + }); - if (placeholderChoice) { - this._addItem({ - value: placeholderChoice.value, - label: placeholderChoice.label, - choiceId: placeholderChoice.id, - groupId: placeholderChoice.groupId, - placeholder: placeholderChoice.placeholder - }); - - this._triggerChange(placeholderChoice.value); - } + this._triggerChange(placeholderChoice.value); }; - _proto._handleButtonAction = function _handleButtonAction(activeItems, element) { + Choices.prototype._handleButtonAction = function (activeItems, element) { if (!activeItems || !element || !this.config.removeItems || !this.config.removeItemButton) { return; } - var itemId = element.parentNode.getAttribute('data-id'); - var itemToRemove = activeItems.find(function (item) { + var itemId = element.parentNode && element.parentNode.dataset.id; + var itemToRemove = itemId && activeItems.find(function (item) { return item.id === parseInt(itemId, 10); - }); // Remove item associated with button + }); + + if (!itemToRemove) { + return; + } // Remove item associated with button + this._removeItem(itemToRemove); this._triggerChange(itemToRemove.value); - if (this._isSelectOneElement) { - this._selectPlaceholderChoice(); + if (this._isSelectOneElement && this._store.placeholderChoice) { + this._selectPlaceholderChoice(this._store.placeholderChoice); } }; - _proto._handleItemAction = function _handleItemAction(activeItems, element, hasShiftKey) { - var _this16 = this; + Choices.prototype._handleItemAction = function (activeItems, element, hasShiftKey) { + var _this = this; if (hasShiftKey === void 0) { hasShiftKey = false; @@ -4319,15 +2343,15 @@ function () { return; } - var passedId = element.getAttribute('data-id'); // We only want to select one item with a click + var passedId = element.dataset.id; // We only want to select one item with a click // so we deselect any items that aren't the target // unless shift is being pressed activeItems.forEach(function (item) { - if (item.id === parseInt(passedId, 10) && !item.highlighted) { - _this16.highlightItem(item); + if (item.id === parseInt("" + passedId, 10) && !item.highlighted) { + _this.highlightItem(item); } else if (!hasShiftKey && item.highlighted) { - _this16.unhighlightItem(item); + _this.unhighlightItem(item); } }); // Focus input as without focus, a user cannot do anything with a // highlighted item @@ -4335,7 +2359,7 @@ function () { this.input.focus(); }; - _proto._handleChoiceAction = function _handleChoiceAction(activeItems, element) { + Choices.prototype._handleChoiceAction = function (activeItems, element) { if (!activeItems || !element) { return; } // If we are clicking on an option @@ -4343,17 +2367,17 @@ function () { var id = element.dataset.id; - var choice = this._store.getChoiceById(id); + var choice = id && this._store.getChoiceById(id); if (!choice) { return; } - var passedKeyCode = activeItems[0] && activeItems[0].keyCode ? activeItems[0].keyCode : null; + var passedKeyCode = activeItems[0] && activeItems[0].keyCode ? activeItems[0].keyCode : undefined; var hasActiveDropdown = this.dropdown.isActive; // Update choice keyCode choice.keyCode = passedKeyCode; - this.passedElement.triggerEvent(EVENTS.choice, { + this.passedElement.triggerEvent(constants_1.EVENTS.choice, { choice: choice }); @@ -4383,7 +2407,7 @@ function () { } }; - _proto._handleBackspace = function _handleBackspace(activeItems) { + Choices.prototype._handleBackspace = function (activeItems) { if (!this.config.removeItems || !activeItems) { return; } @@ -4411,15 +2435,15 @@ function () { } }; - _proto._startLoading = function _startLoading() { - this._store.dispatch(setIsLoading(true)); + Choices.prototype._startLoading = function () { + this._store.dispatch(misc_1.setIsLoading(true)); }; - _proto._stopLoading = function _stopLoading() { - this._store.dispatch(setIsLoading(false)); + Choices.prototype._stopLoading = function () { + this._store.dispatch(misc_1.setIsLoading(false)); }; - _proto._handleLoadingState = function _handleLoadingState(setLoading) { + Choices.prototype._handleLoadingState = function (setLoading) { if (setLoading === void 0) { setLoading = true; } @@ -4433,7 +2457,10 @@ function () { if (this._isSelectOneElement) { if (!placeholderItem) { placeholderItem = this._getTemplate('placeholder', this.config.loadingText); - this.itemList.append(placeholderItem); + + if (placeholderItem) { + this.itemList.append(placeholderItem); + } } else { placeholderItem.innerHTML = this.config.loadingText; } @@ -4445,22 +2472,24 @@ function () { this.containerOuter.removeLoadingState(); if (this._isSelectOneElement) { - placeholderItem.innerHTML = this._placeholderValue || ''; + if (placeholderItem) { + placeholderItem.innerHTML = this._placeholderValue || ''; + } } else { this.input.placeholder = this._placeholderValue || ''; } } }; - _proto._handleSearch = function _handleSearch(value) { + Choices.prototype._handleSearch = function (value) { if (!value || !this.input.isFocussed) { return; } var choices = this._store.choices; - var _this$config3 = this.config, - searchFloor = _this$config3.searchFloor, - searchChoices = _this$config3.searchChoices; + var _a = this.config, + searchFloor = _a.searchFloor, + searchChoices = _a.searchChoices; var hasUnactiveChoices = choices.some(function (option) { return !option.active; }); // Check that we have a value to search and the input was an alphanumeric character @@ -4468,7 +2497,7 @@ function () { if (value && value.length >= searchFloor) { var resultCount = searchChoices ? this._searchChoices(value) : 0; // Trigger search event - this.passedElement.triggerEvent(EVENTS.search, { + this.passedElement.triggerEvent(constants_1.EVENTS.search, { value: value, resultCount: resultCount }); @@ -4476,16 +2505,16 @@ function () { // Otherwise reset choices to active this._isSearching = false; - this._store.dispatch(choices_activateChoices(true)); + this._store.dispatch(choices_1.activateChoices(true)); } }; - _proto._canAddItem = function _canAddItem(activeItems, value) { + Choices.prototype._canAddItem = function (activeItems, value) { var canAddItem = true; var notice = typeof this.config.addItemText === 'function' ? this.config.addItemText(value) : this.config.addItemText; if (!this._isSelectOneElement) { - var isDuplicateValue = existsInArray(activeItems, value); + var isDuplicateValue = utils_1.existsInArray(activeItems, value); if (this.config.maxItemCount > 0 && this.config.maxItemCount <= activeItems.length) { // If there is a max entry limit and we have reached that limit @@ -4511,7 +2540,7 @@ function () { }; }; - _proto._searchChoices = function _searchChoices(value) { + Choices.prototype._searchChoices = function (value) { var newValue = typeof value === 'string' ? value.trim() : value; var currentValue = typeof this._currentValue === 'string' ? this._currentValue.trim() : this._currentValue; @@ -4522,24 +2551,27 @@ function () { var haystack = this._store.searchableChoices; var needle = newValue; - var keys = [].concat(this.config.searchFields); + + var keys = __spreadArrays(this.config.searchFields); + var options = Object.assign(this.config.fuseOptions, { - keys: keys + keys: keys, + includeMatches: true }); - var fuse = new fuse_default.a(haystack, options); - var results = fuse.search(needle); + var fuse = new fuse_js_1.default(haystack, options); + var results = fuse.search(needle); // see https://github.com/krisk/Fuse/issues/303 + this._currentValue = newValue; this._highlightPosition = 0; this._isSearching = true; - this._store.dispatch(choices_filterChoices(results)); + this._store.dispatch(choices_1.filterChoices(results)); return results.length; }; - _proto._addEventListeners = function _addEventListeners() { - var _document = document, - documentElement = _document.documentElement; // capture events - can cancel event processing or propagation + Choices.prototype._addEventListeners = function () { + var documentElement = document.documentElement; // capture events - can cancel event processing or propagation documentElement.addEventListener('touchend', this._onTouchEnd, true); this.containerOuter.element.addEventListener('keydown', this._onKeyDown, true); @@ -4583,9 +2615,8 @@ function () { this.input.addEventListeners(); }; - _proto._removeEventListeners = function _removeEventListeners() { - var _document2 = document, - documentElement = _document2.documentElement; + Choices.prototype._removeEventListeners = function () { + var documentElement = document.documentElement; documentElement.removeEventListener('touchend', this._onTouchEnd, true); this.containerOuter.element.removeEventListener('keydown', this._onKeyDown, true); this.containerOuter.element.removeEventListener('mousedown', this._onMouseDown, true); @@ -4607,15 +2638,9 @@ function () { } this.input.removeEventListeners(); - } - /** - * @param {KeyboardEvent} event - */ - ; - - _proto._onKeyDown = function _onKeyDown(event) { - var _keyDownActions; + }; + Choices.prototype._onKeyDown = function (event) { var keyCode = event.keyCode; var activeItems = this._store.activeItems; var hasFocusedInput = this.input.isFocussed; @@ -4623,15 +2648,15 @@ function () { var hasItems = this.itemList.hasChildren(); var keyString = String.fromCharCode(keyCode); var wasAlphaNumericChar = /[a-zA-Z0-9-_ ]/.test(keyString); - var BACK_KEY = KEY_CODES.BACK_KEY, - DELETE_KEY = KEY_CODES.DELETE_KEY, - ENTER_KEY = KEY_CODES.ENTER_KEY, - A_KEY = KEY_CODES.A_KEY, - ESC_KEY = KEY_CODES.ESC_KEY, - UP_KEY = KEY_CODES.UP_KEY, - DOWN_KEY = KEY_CODES.DOWN_KEY, - PAGE_UP_KEY = KEY_CODES.PAGE_UP_KEY, - PAGE_DOWN_KEY = KEY_CODES.PAGE_DOWN_KEY; + var BACK_KEY = constants_1.KEY_CODES.BACK_KEY, + DELETE_KEY = constants_1.KEY_CODES.DELETE_KEY, + ENTER_KEY = constants_1.KEY_CODES.ENTER_KEY, + A_KEY = constants_1.KEY_CODES.A_KEY, + ESC_KEY = constants_1.KEY_CODES.ESC_KEY, + UP_KEY = constants_1.KEY_CODES.UP_KEY, + DOWN_KEY = constants_1.KEY_CODES.DOWN_KEY, + PAGE_UP_KEY = constants_1.KEY_CODES.PAGE_UP_KEY, + PAGE_DOWN_KEY = constants_1.KEY_CODES.PAGE_DOWN_KEY; if (!this._isTextElement && !hasActiveDropdown && wasAlphaNumericChar) { this.showDropdown(); @@ -4644,32 +2669,42 @@ function () { */ this.input.value += keyString.toLowerCase(); } - } // Map keys to key actions + } + switch (keyCode) { + case A_KEY: + return this._onSelectKey(event, hasItems); - var keyDownActions = (_keyDownActions = {}, _keyDownActions[A_KEY] = this._onAKey, _keyDownActions[ENTER_KEY] = this._onEnterKey, _keyDownActions[ESC_KEY] = this._onEscapeKey, _keyDownActions[UP_KEY] = this._onDirectionKey, _keyDownActions[PAGE_UP_KEY] = this._onDirectionKey, _keyDownActions[DOWN_KEY] = this._onDirectionKey, _keyDownActions[PAGE_DOWN_KEY] = this._onDirectionKey, _keyDownActions[DELETE_KEY] = this._onDeleteKey, _keyDownActions[BACK_KEY] = this._onDeleteKey, _keyDownActions); + case ENTER_KEY: + return this._onEnterKey(event, activeItems, hasActiveDropdown); - if (keyDownActions[keyCode]) { - keyDownActions[keyCode]({ - event: event, - activeItems: activeItems, - hasFocusedInput: hasFocusedInput, - hasActiveDropdown: hasActiveDropdown, - hasItems: hasItems - }); + case ESC_KEY: + return this._onEscapeKey(hasActiveDropdown); + + case UP_KEY: + case PAGE_UP_KEY: + case DOWN_KEY: + case PAGE_DOWN_KEY: + return this._onDirectionKey(event, hasActiveDropdown); + + case DELETE_KEY: + case BACK_KEY: + return this._onDeleteKey(event, activeItems, hasFocusedInput); + + default: } }; - _proto._onKeyUp = function _onKeyUp(_ref2) { - var target = _ref2.target, - keyCode = _ref2.keyCode; + Choices.prototype._onKeyUp = function (_a) { + var target = _a.target, + keyCode = _a.keyCode; var value = this.input.value; var activeItems = this._store.activeItems; var canAddItem = this._canAddItem(activeItems, value); - var backKey = KEY_CODES.BACK_KEY, - deleteKey = KEY_CODES.DELETE_KEY; // We are typing into a text input and have a value, we want to show a dropdown + var backKey = constants_1.KEY_CODES.BACK_KEY, + deleteKey = constants_1.KEY_CODES.DELETE_KEY; // We are typing into a text input and have a value, we want to show a dropdown // notice. Otherwise hide the dropdown if (this._isTextElement) { @@ -4685,14 +2720,14 @@ function () { } } else { var wasRemovalKeyCode = keyCode === backKey || keyCode === deleteKey; - var userHasRemovedValue = wasRemovalKeyCode && !target.value; + var userHasRemovedValue = wasRemovalKeyCode && target && !target.value; var canReactivateChoices = !this._isTextElement && this._isSearching; var canSearch = this._canSearch && canAddItem.response; if (userHasRemovedValue && canReactivateChoices) { this._isSearching = false; - this._store.dispatch(choices_activateChoices(true)); + this._store.dispatch(choices_1.activateChoices(true)); } else if (canSearch) { this._handleSearch(this.input.value); } @@ -4701,9 +2736,7 @@ function () { this._canSearch = this.config.searchEnabled; }; - _proto._onAKey = function _onAKey(_ref3) { - var event = _ref3.event, - hasItems = _ref3.hasItems; + Choices.prototype._onSelectKey = function (event, hasItems) { var ctrlKey = event.ctrlKey, metaKey = event.metaKey; var hasCtrlDownKeyPressed = ctrlKey || metaKey; // If CTRL + A or CMD + A have been pressed and there are items to select @@ -4718,15 +2751,12 @@ function () { } }; - _proto._onEnterKey = function _onEnterKey(_ref4) { - var event = _ref4.event, - activeItems = _ref4.activeItems, - hasActiveDropdown = _ref4.hasActiveDropdown; + Choices.prototype._onEnterKey = function (event, activeItems, hasActiveDropdown) { var target = event.target; - var enterKey = KEY_CODES.ENTER_KEY; - var targetWasButton = target.hasAttribute('data-button'); + var enterKey = constants_1.KEY_CODES.ENTER_KEY; + var targetWasButton = target && target.hasAttribute('data-button'); - if (this._isTextElement && target.value) { + if (this._isTextElement && target && target.value) { var value = this.input.value; var canAddItem = this._canAddItem(activeItems, value); @@ -4769,23 +2799,19 @@ function () { } }; - _proto._onEscapeKey = function _onEscapeKey(_ref5) { - var hasActiveDropdown = _ref5.hasActiveDropdown; - + Choices.prototype._onEscapeKey = function (hasActiveDropdown) { if (hasActiveDropdown) { this.hideDropdown(true); this.containerOuter.focus(); } }; - _proto._onDirectionKey = function _onDirectionKey(_ref6) { - var event = _ref6.event, - hasActiveDropdown = _ref6.hasActiveDropdown; + Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) { var keyCode = event.keyCode, metaKey = event.metaKey; - var downKey = KEY_CODES.DOWN_KEY, - pageUpKey = KEY_CODES.PAGE_UP_KEY, - pageDownKey = KEY_CODES.PAGE_DOWN_KEY; // If up or down key is pressed, traverse through options + var downKey = constants_1.KEY_CODES.DOWN_KEY, + pageUpKey = constants_1.KEY_CODES.PAGE_UP_KEY, + pageDownKey = constants_1.KEY_CODES.PAGE_DOWN_KEY; // If up or down key is pressed, traverse through options if (hasActiveDropdown || this._isSelectOneElement) { this.showDropdown(); @@ -4793,7 +2819,7 @@ function () { var directionInt = keyCode === downKey || keyCode === pageDownKey ? 1 : -1; var skipKey = metaKey || keyCode === pageDownKey || keyCode === pageUpKey; var selectableChoiceIdentifier = '[data-choice-selectable]'; - var nextEl; + var nextEl = void 0; if (skipKey) { if (directionInt > 0) { @@ -4805,7 +2831,7 @@ function () { var currentEl = this.dropdown.element.querySelector("." + this.config.classNames.highlightedState); if (currentEl) { - nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt); + nextEl = utils_1.getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt); } else { nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier); } @@ -4814,7 +2840,7 @@ function () { if (nextEl) { // We prevent default to stop the cursor moving // when pressing the arrow - if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) { + if (!utils_1.isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) { this.choiceList.scrollToChildElement(nextEl, directionInt); } @@ -4827,29 +2853,24 @@ function () { } }; - _proto._onDeleteKey = function _onDeleteKey(_ref7) { - var event = _ref7.event, - hasFocusedInput = _ref7.hasFocusedInput, - activeItems = _ref7.activeItems; + Choices.prototype._onDeleteKey = function (event, activeItems, hasFocusedInput) { var target = event.target; // If backspace or delete key is pressed and the input has no value - if (hasFocusedInput && !target.value && !this._isSelectOneElement) { + if (!this._isSelectOneElement && !target.value && hasFocusedInput) { this._handleBackspace(activeItems); event.preventDefault(); } }; - _proto._onTouchMove = function _onTouchMove() { + Choices.prototype._onTouchMove = function () { if (this._wasTap) { this._wasTap = false; } }; - _proto._onTouchEnd = function _onTouchEnd(event) { - var _ref8 = event || event.touches[0], - target = _ref8.target; - + Choices.prototype._onTouchEnd = function (event) { + var target = (event || event.touches[0]).target; var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target); if (touchWasWithinContainer) { @@ -4868,14 +2889,13 @@ function () { } this._wasTap = true; - } + }; /** * Handles mousedown event in capture mode for containetOuter.element - * @param {MouseEvent} event */ - ; - _proto._onMouseDown = function _onMouseDown(event) { + + Choices.prototype._onMouseDown = function (event) { var target = event.target; if (!(target instanceof HTMLElement)) { @@ -4885,9 +2905,7 @@ function () { if (IS_IE11 && this.choiceList.element.contains(target)) { // check if click was on a scrollbar area - var firstChoice = - /** @type {HTMLElement} */ - this.choiceList.element.firstElementChild; + var firstChoice = this.choiceList.element.firstElementChild; var isOnScrollbar = this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft; this._isScrollingOnIe = isOnScrollbar; } @@ -4913,23 +2931,23 @@ function () { } event.preventDefault(); - } + }; /** * Handles mouseover event over this.dropdown * @param {MouseEvent} event */ - ; - _proto._onMouseOver = function _onMouseOver(_ref9) { - var target = _ref9.target; + + Choices.prototype._onMouseOver = function (_a) { + var target = _a.target; if (target instanceof HTMLElement && 'choice' in target.dataset) { this._highlightChoice(target); } }; - _proto._onClick = function _onClick(_ref10) { - var target = _ref10.target; + Choices.prototype._onClick = function (_a) { + var target = _a.target; var clickWasWithinContainer = this.containerOuter.element.contains(target); if (clickWasWithinContainer) { @@ -4957,79 +2975,80 @@ function () { } }; - _proto._onFocus = function _onFocus(_ref11) { - var _this17 = this, - _focusActions; + Choices.prototype._onFocus = function (_a) { + var _b; - var target = _ref11.target; - var focusWasWithinContainer = this.containerOuter.element.contains(target); + var _this = this; + + var target = _a.target; + var focusWasWithinContainer = target && this.containerOuter.element.contains(target); if (!focusWasWithinContainer) { return; } - var focusActions = (_focusActions = {}, _focusActions[TEXT_TYPE] = function () { - if (target === _this17.input.element) { - _this17.containerOuter.addFocusState(); + var focusActions = (_b = {}, _b[constants_1.TEXT_TYPE] = function () { + if (target === _this.input.element) { + _this.containerOuter.addFocusState(); } - }, _focusActions[SELECT_ONE_TYPE] = function () { - _this17.containerOuter.addFocusState(); + }, _b[constants_1.SELECT_ONE_TYPE] = function () { + _this.containerOuter.addFocusState(); - if (target === _this17.input.element) { - _this17.showDropdown(true); + if (target === _this.input.element) { + _this.showDropdown(true); } - }, _focusActions[SELECT_MULTIPLE_TYPE] = function () { - if (target === _this17.input.element) { - _this17.showDropdown(true); // If element is a select box, the focused element is the container and the dropdown + }, _b[constants_1.SELECT_MULTIPLE_TYPE] = function () { + if (target === _this.input.element) { + _this.showDropdown(true); // If element is a select box, the focused element is the container and the dropdown // isn't already open, focus and show dropdown - _this17.containerOuter.addFocusState(); + _this.containerOuter.addFocusState(); } - }, _focusActions); + }, _b); focusActions[this.passedElement.element.type](); }; - _proto._onBlur = function _onBlur(_ref12) { - var _this18 = this; + Choices.prototype._onBlur = function (_a) { + var _b; - var target = _ref12.target; - var blurWasWithinContainer = this.containerOuter.element.contains(target); + var _this = this; + + var target = _a.target; + var blurWasWithinContainer = target && this.containerOuter.element.contains(target); if (blurWasWithinContainer && !this._isScrollingOnIe) { - var _blurActions; - var activeItems = this._store.activeItems; - var hasHighlightedItems = activeItems.some(function (item) { + var hasHighlightedItems_1 = activeItems.some(function (item) { return item.highlighted; }); - var blurActions = (_blurActions = {}, _blurActions[TEXT_TYPE] = function () { - if (target === _this18.input.element) { - _this18.containerOuter.removeFocusState(); + var blurActions = (_b = {}, _b[constants_1.TEXT_TYPE] = function () { + if (target === _this.input.element) { + _this.containerOuter.removeFocusState(); - if (hasHighlightedItems) { - _this18.unhighlightAll(); + if (hasHighlightedItems_1) { + _this.unhighlightAll(); } - _this18.hideDropdown(true); + _this.hideDropdown(true); } - }, _blurActions[SELECT_ONE_TYPE] = function () { - _this18.containerOuter.removeFocusState(); + }, _b[constants_1.SELECT_ONE_TYPE] = function () { + _this.containerOuter.removeFocusState(); - if (target === _this18.input.element || target === _this18.containerOuter.element && !_this18._canSearch) { - _this18.hideDropdown(true); + if (target === _this.input.element || target === _this.containerOuter.element && !_this._canSearch) { + _this.hideDropdown(true); } - }, _blurActions[SELECT_MULTIPLE_TYPE] = function () { - if (target === _this18.input.element) { - _this18.containerOuter.removeFocusState(); + }, _b[constants_1.SELECT_MULTIPLE_TYPE] = function () { + if (target === _this.input.element) { + _this.containerOuter.removeFocusState(); - _this18.hideDropdown(true); + _this.hideDropdown(true); - if (hasHighlightedItems) { - _this18.unhighlightAll(); + if (hasHighlightedItems_1) { + _this.unhighlightAll(); } } - }, _blurActions); + }, _b); blurActions[this.passedElement.element.type](); } else { // On IE11, clicking the scollbar blurs our input and thus @@ -5040,12 +3059,12 @@ function () { } }; - _proto._onFormReset = function _onFormReset() { - this._store.dispatch(resetTo(this._initialState)); + Choices.prototype._onFormReset = function () { + this._store.dispatch(misc_1.resetTo(this._initialState)); }; - _proto._highlightChoice = function _highlightChoice(el) { - var _this19 = this; + Choices.prototype._highlightChoice = function (el) { + var _this = this; if (el === void 0) { el = null; @@ -5061,7 +3080,7 @@ function () { var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll("." + this.config.classNames.highlightedState)); // Remove any highlighted choices highlightedChoices.forEach(function (choice) { - choice.classList.remove(_this19.config.classNames.highlightedState); + choice.classList.remove(_this.config.classNames.highlightedState); choice.setAttribute('aria-selected', 'false'); }); @@ -5084,7 +3103,7 @@ function () { passedEl.classList.add(this.config.classNames.highlightedState); passedEl.setAttribute('aria-selected', 'true'); - this.passedElement.triggerEvent(EVENTS.highlightChoice, { + this.passedElement.triggerEvent(constants_1.EVENTS.highlightChoice, { el: passedEl }); @@ -5096,23 +3115,21 @@ function () { } }; - _proto._addItem = function _addItem(_ref13) { - var value = _ref13.value, - _ref13$label = _ref13.label, - label = _ref13$label === void 0 ? null : _ref13$label, - _ref13$choiceId = _ref13.choiceId, - choiceId = _ref13$choiceId === void 0 ? -1 : _ref13$choiceId, - _ref13$groupId = _ref13.groupId, - groupId = _ref13$groupId === void 0 ? -1 : _ref13$groupId, - _ref13$customProperti = _ref13.customProperties, - customProperties = _ref13$customProperti === void 0 ? null : _ref13$customProperti, - _ref13$placeholder = _ref13.placeholder, - placeholder = _ref13$placeholder === void 0 ? false : _ref13$placeholder, - _ref13$keyCode = _ref13.keyCode, - keyCode = _ref13$keyCode === void 0 ? null : _ref13$keyCode; + Choices.prototype._addItem = function (_a) { + var value = _a.value, + _b = _a.label, + label = _b === void 0 ? null : _b, + _c = _a.choiceId, + choiceId = _c === void 0 ? -1 : _c, + _d = _a.groupId, + groupId = _d === void 0 ? -1 : _d, + _e = _a.customProperties, + customProperties = _e === void 0 ? {} : _e, + _f = _a.placeholder, + placeholder = _f === void 0 ? false : _f, + _g = _a.keyCode, + keyCode = _g === void 0 ? -1 : _g; var passedValue = typeof value === 'string' ? value.trim() : value; - var passedKeyCode = keyCode; - var passedCustomProperties = customProperties; var items = this._store.items; var passedLabel = label || passedValue; var passedOptionId = choiceId || -1; @@ -5128,7 +3145,7 @@ function () { passedValue += this.config.appendValue.toString(); } - this._store.dispatch(items_addItem({ + this._store.dispatch(items_1.addItem({ value: passedValue, label: passedLabel, id: id, @@ -5136,7 +3153,7 @@ function () { groupId: groupId, customProperties: customProperties, placeholder: placeholder, - keyCode: passedKeyCode + keyCode: keyCode })); if (this._isSelectOneElement) { @@ -5144,65 +3161,56 @@ function () { } // Trigger change event - this.passedElement.triggerEvent(EVENTS.addItem, { + this.passedElement.triggerEvent(constants_1.EVENTS.addItem, { id: id, value: passedValue, label: passedLabel, - customProperties: passedCustomProperties, - groupValue: group && group.value ? group.value : undefined, - keyCode: passedKeyCode + customProperties: customProperties, + groupValue: group && group.value ? group.value : null, + keyCode: keyCode }); - return this; }; - _proto._removeItem = function _removeItem(item) { - if (!item || !isType('Object', item)) { - return this; - } - + Choices.prototype._removeItem = function (item) { var id = item.id, value = item.value, label = item.label, + customProperties = item.customProperties, choiceId = item.choiceId, groupId = item.groupId; - var group = groupId >= 0 ? this._store.getGroupById(groupId) : null; + var group = groupId && groupId >= 0 ? this._store.getGroupById(groupId) : null; - this._store.dispatch(items_removeItem(id, choiceId)); - - if (group && group.value) { - this.passedElement.triggerEvent(EVENTS.removeItem, { - id: id, - value: value, - label: label, - groupValue: group.value - }); - } else { - this.passedElement.triggerEvent(EVENTS.removeItem, { - id: id, - value: value, - label: label - }); + if (!id || !choiceId) { + return; } - return this; + this._store.dispatch(items_1.removeItem(id, choiceId)); + + this.passedElement.triggerEvent(constants_1.EVENTS.removeItem, { + id: id, + value: value, + label: label, + customProperties: customProperties, + groupValue: group && group.value ? group.value : null + }); }; - _proto._addChoice = function _addChoice(_ref14) { - var value = _ref14.value, - _ref14$label = _ref14.label, - label = _ref14$label === void 0 ? null : _ref14$label, - _ref14$isSelected = _ref14.isSelected, - isSelected = _ref14$isSelected === void 0 ? false : _ref14$isSelected, - _ref14$isDisabled = _ref14.isDisabled, - isDisabled = _ref14$isDisabled === void 0 ? false : _ref14$isDisabled, - _ref14$groupId = _ref14.groupId, - groupId = _ref14$groupId === void 0 ? -1 : _ref14$groupId, - _ref14$customProperti = _ref14.customProperties, - customProperties = _ref14$customProperti === void 0 ? null : _ref14$customProperti, - _ref14$placeholder = _ref14.placeholder, - placeholder = _ref14$placeholder === void 0 ? false : _ref14$placeholder, - _ref14$keyCode = _ref14.keyCode, - keyCode = _ref14$keyCode === void 0 ? null : _ref14$keyCode; + Choices.prototype._addChoice = function (_a) { + var value = _a.value, + _b = _a.label, + label = _b === void 0 ? null : _b, + _c = _a.isSelected, + isSelected = _c === void 0 ? false : _c, + _d = _a.isDisabled, + isDisabled = _d === void 0 ? false : _d, + _e = _a.groupId, + groupId = _e === void 0 ? -1 : _e, + _f = _a.customProperties, + customProperties = _f === void 0 ? {} : _f, + _g = _a.placeholder, + placeholder = _g === void 0 ? false : _g, + _h = _a.keyCode, + keyCode = _h === void 0 ? -1 : _h; if (typeof value === 'undefined' || value === null) { return; @@ -5214,7 +3222,7 @@ function () { var choiceId = choices ? choices.length + 1 : 1; var choiceElementId = this._baseId + "-" + this._idNames.itemChoice + "-" + choiceId; - this._store.dispatch(choices_addChoice({ + this._store.dispatch(choices_1.addChoice({ id: choiceId, groupId: groupId, elementId: choiceElementId, @@ -5238,21 +3246,21 @@ function () { } }; - _proto._addGroup = function _addGroup(_ref15) { - var _this20 = this; + Choices.prototype._addGroup = function (_a) { + var _this = this; - var group = _ref15.group, - id = _ref15.id, - _ref15$valueKey = _ref15.valueKey, - valueKey = _ref15$valueKey === void 0 ? 'value' : _ref15$valueKey, - _ref15$labelKey = _ref15.labelKey, - labelKey = _ref15$labelKey === void 0 ? 'label' : _ref15$labelKey; - var groupChoices = isType('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION')); + var group = _a.group, + id = _a.id, + _b = _a.valueKey, + valueKey = _b === void 0 ? 'value' : _b, + _c = _a.labelKey, + labelKey = _c === void 0 ? 'label' : _c; + var groupChoices = utils_1.isType('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION')); var groupId = id || Math.floor(new Date().valueOf() * Math.random()); var isDisabled = group.disabled ? group.disabled : false; if (groupChoices) { - this._store.dispatch(groups_addGroup({ + this._store.dispatch(groups_1.addGroup({ value: group.label, id: groupId, active: true, @@ -5262,9 +3270,9 @@ function () { var addGroupChoices = function addGroupChoices(choice) { var isOptDisabled = choice.disabled || choice.parentNode && choice.parentNode.disabled; - _this20._addChoice({ + _this._addChoice({ value: choice[valueKey], - label: isType('Object', choice) ? choice[labelKey] : choice.innerHTML, + label: utils_1.isType('Object', choice) ? choice[labelKey] : choice.innerHTML, isSelected: choice.selected, isDisabled: isOptDisabled, groupId: groupId, @@ -5275,7 +3283,7 @@ function () { groupChoices.forEach(addGroupChoices); } else { - this._store.dispatch(groups_addGroup({ + this._store.dispatch(groups_1.addGroup({ value: group.label, id: group.id, active: false, @@ -5284,66 +3292,63 @@ function () { } }; - _proto._getTemplate = function _getTemplate(template) { - var _this$_templates$temp; + Choices.prototype._getTemplate = function (template) { + var _a; - if (!template) { - return null; + var args = []; + + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; } var classNames = this.config.classNames; - - for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } - - return (_this$_templates$temp = this._templates[template]).call.apply(_this$_templates$temp, [this, classNames].concat(args)); + return (_a = this._templates[template]).call.apply(_a, __spreadArrays([this, classNames], args)); }; - _proto._createTemplates = function _createTemplates() { + Choices.prototype._createTemplates = function () { var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates; var userTemplates = {}; if (callbackOnCreateTemplates && typeof callbackOnCreateTemplates === 'function') { - userTemplates = callbackOnCreateTemplates.call(this, strToEl); + userTemplates = callbackOnCreateTemplates.call(this, utils_1.strToEl); } - this._templates = cjs_default()(TEMPLATES, userTemplates); + this._templates = deepmerge_1.default(templates_1.default, userTemplates); }; - _proto._createElements = function _createElements() { - this.containerOuter = new container_Container({ + Choices.prototype._createElements = function () { + this.containerOuter = new components_1.Container({ element: this._getTemplate('containerOuter', this._direction, this._isSelectElement, this._isSelectOneElement, this.config.searchEnabled, this.passedElement.element.type), classNames: this.config.classNames, type: this.passedElement.element.type, position: this.config.position }); - this.containerInner = new container_Container({ + this.containerInner = new components_1.Container({ element: this._getTemplate('containerInner'), classNames: this.config.classNames, type: this.passedElement.element.type, position: this.config.position }); - this.input = new input_Input({ + this.input = new components_1.Input({ element: this._getTemplate('input', this._placeholderValue), classNames: this.config.classNames, type: this.passedElement.element.type, preventPaste: !this.config.paste }); - this.choiceList = new list_List({ + this.choiceList = new components_1.List({ element: this._getTemplate('choiceList', this._isSelectOneElement) }); - this.itemList = new list_List({ + this.itemList = new components_1.List({ element: this._getTemplate('itemList', this._isSelectOneElement) }); - this.dropdown = new Dropdown({ + this.dropdown = new components_1.Dropdown({ element: this._getTemplate('dropdown'), classNames: this.config.classNames, type: this.passedElement.element.type }); }; - _proto._createStructure = function _createStructure() { + Choices.prototype._createStructure = function () { // Hide original element this.passedElement.conceal(); // Wrap input in container preserving DOM ordering @@ -5392,13 +3397,13 @@ function () { } }; - _proto._addPredefinedGroups = function _addPredefinedGroups(groups) { - var _this21 = this; + Choices.prototype._addPredefinedGroups = function (groups) { + var _this = this; // If we have a placeholder option + - // If we have a placeholder option var placeholderChoice = this.passedElement.placeholderOption; - if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') { + if (placeholderChoice && placeholderChoice.parentNode && placeholderChoice.parentNode.tagName === 'SELECT') { this._addChoice({ value: placeholderChoice.value, label: placeholderChoice.innerHTML, @@ -5409,17 +3414,17 @@ function () { } groups.forEach(function (group) { - return _this21._addGroup({ + return _this._addGroup({ group: group, id: group.id || null }); }); }; - _proto._addPredefinedChoices = function _addPredefinedChoices(choices) { - var _this22 = this; + Choices.prototype._addPredefinedChoices = function (choices) { + var _this = this; // If sorting is enabled or the user is searching, filter choices + - // If sorting is enabled or the user is searching, filter choices if (this.config.shouldSort) { choices.sort(this.config.sorter); } @@ -5431,15 +3436,16 @@ function () { return choice.disabled === undefined || !choice.disabled; }); choices.forEach(function (choice, index) { - var value = choice.value, + var _a = choice.value, + value = _a === void 0 ? '' : _a, label = choice.label, customProperties = choice.customProperties, placeholder = choice.placeholder; - if (_this22._isSelectElement) { + if (_this._isSelectElement) { // If the choice is actually a group if (choice.choices) { - _this22._addGroup({ + _this._addGroup({ group: choice, id: choice.id || null }); @@ -5450,42 +3456,39 @@ function () { * * Otherwise we pre-select the first enabled choice in the array ("select-one" only) */ - var shouldPreselect = _this22._isSelectOneElement && !hasSelectedChoice && index === firstEnabledChoiceIndex; + var shouldPreselect = _this._isSelectOneElement && !hasSelectedChoice && index === firstEnabledChoiceIndex; var isSelected = shouldPreselect ? true : choice.selected; var isDisabled = choice.disabled; + console.log(isDisabled, choice); - _this22._addChoice({ + _this._addChoice({ value: value, label: label, - isSelected: isSelected, - isDisabled: isDisabled, - customProperties: customProperties, - placeholder: placeholder + isSelected: !!isSelected, + isDisabled: !!isDisabled, + placeholder: !!placeholder, + customProperties: customProperties }); } } else { - _this22._addChoice({ + _this._addChoice({ value: value, label: label, - isSelected: choice.selected, - isDisabled: choice.disabled, - customProperties: customProperties, - placeholder: placeholder + isSelected: !!choice.selected, + isDisabled: !!choice.disabled, + placeholder: !!choice.placeholder, + customProperties: customProperties }); } }); - } - /** - * @param {Item[]} items - */ - ; + }; - _proto._addPredefinedItems = function _addPredefinedItems(items) { - var _this23 = this; + Choices.prototype._addPredefinedItems = function (items) { + var _this = this; items.forEach(function (item) { if (typeof item === 'object' && item.value) { - _this23._addItem({ + _this._addItem({ value: item.value, label: item.label, choiceId: item.id, @@ -5495,17 +3498,17 @@ function () { } if (typeof item === 'string') { - _this23._addItem({ + _this._addItem({ value: item }); } }); }; - _proto._setChoiceOrItem = function _setChoiceOrItem(item) { - var _this24 = this; + Choices.prototype._setChoiceOrItem = function (item) { + var _this = this; - var itemType = getType(item).toLowerCase(); + var itemType = utils_1.getType(item).toLowerCase(); var handleType = { object: function object() { if (!item.value) { @@ -5514,8 +3517,8 @@ function () { // that is then selected. For text inputs we can just add items normally. - if (!_this24._isTextElement) { - _this24._addChoice({ + if (!_this._isTextElement) { + _this._addChoice({ value: item.value, label: item.label, isSelected: true, @@ -5524,7 +3527,7 @@ function () { placeholder: item.placeholder }); } else { - _this24._addItem({ + _this._addItem({ value: item.value, label: item.label, choiceId: item.id, @@ -5534,15 +3537,15 @@ function () { } }, string: function string() { - if (!_this24._isTextElement) { - _this24._addChoice({ + if (!_this._isTextElement) { + _this._addChoice({ value: item, label: item, isSelected: true, isDisabled: false }); } else { - _this24._addItem({ + _this._addItem({ value: item }); } @@ -5551,13 +3554,13 @@ function () { handleType[itemType](); }; - _proto._findAndSelectChoiceByValue = function _findAndSelectChoiceByValue(val) { - var _this25 = this; + Choices.prototype._findAndSelectChoiceByValue = function (value) { + var _this = this; var choices = this._store.choices; // Check 'value' property exists and the choice isn't already selected var foundChoice = choices.find(function (choice) { - return _this25.config.valueComparer(choice.value, val); + return _this.config.valueComparer(choice.value, value); }); if (foundChoice && !foundChoice.selected) { @@ -5573,15 +3576,15 @@ function () { } }; - _proto._generatePlaceholderValue = function _generatePlaceholderValue() { + Choices.prototype._generatePlaceholderValue = function () { if (this._isSelectElement) { var placeholderOption = this.passedElement.placeholderOption; - return placeholderOption ? placeholderOption.text : false; + return placeholderOption ? placeholderOption.text : null; } - var _this$config4 = this.config, - placeholder = _this$config4.placeholder, - placeholderValue = _this$config4.placeholderValue; + var _a = this.config, + placeholder = _a.placeholder, + placeholderValue = _a.placeholderValue; var dataset = this.passedElement.element.dataset; if (placeholder) { @@ -5594,13 +3597,1962 @@ function () { } } - return false; + return null; }; return Choices; }(); -/* harmony default export */ var scripts_choices = __webpack_exports__["default"] = (choices_Choices); +exports.default = Choices; + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +/*! + * Fuse.js v3.4.6 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +!function(e,t){ true?module.exports=t():undefined}(this,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t){e.exports=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,n){function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{limit:!1};this._log('---------\nSearch pattern: "'.concat(e,'"'));var n=this._prepareSearchers(e),r=n.tokenSearchers,o=n.fullSearcher,i=this._search(r,o),a=i.weights,s=i.results;return this._computeScore(a,s),this.options.shouldSort&&this._sort(s),t.limit&&"number"==typeof t.limit&&(s=s.slice(0,t.limit)),this._format(s)}},{key:"_prepareSearchers",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var n=e.split(this.options.tokenSeparator),r=0,o=n.length;r0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,n=this.list,r={},o=[];if("string"==typeof n[0]){for(var i=0,a=n.length;i1)throw new Error("Key weight has to be > 0 and <= 1");d=d.name}else s[d]={weight:1};this._analyze({key:d,value:this.options.getFn(l,d),record:l,index:c},{resultMap:r,results:o,tokenSearchers:e,fullSearcher:t})}return{weights:s,results:o}}},{key:"_analyze",value:function(e,t){var n=e.key,r=e.arrayIndex,o=void 0===r?-1:r,i=e.value,a=e.record,c=e.index,h=t.tokenSearchers,l=void 0===h?[]:h,u=t.fullSearcher,f=void 0===u?[]:u,d=t.resultMap,v=void 0===d?{}:d,p=t.results,g=void 0===p?[]:p;if(null!=i){var y=!1,m=-1,k=0;if("string"==typeof i){this._log("\nKey: ".concat(""===n?"-":n));var S=f.search(i);if(this._log('Full text: "'.concat(i,'", score: ').concat(S.score)),this.options.tokenize){for(var x=i.split(this.options.tokenSeparator),b=[],M=0;M-1&&(P=(P+m)/2),this._log("Score average:",P);var F=!this.options.tokenize||!this.options.matchAllTokens||k>=l.length;if(this._log("\nCheck Matches: ".concat(F)),(y||S.isMatch)&&F){var T=v[c];T?T.output.push({key:n,arrayIndex:o,value:i,score:P,matchedIndices:S.matchedIndices}):(v[c]={item:a,output:[{key:n,arrayIndex:o,value:i,score:P,matchedIndices:S.matchedIndices}]},g.push(v[c]))}}else if(s(i))for(var z=0,E=i.length;z-1&&(a.arrayIndex=i.arrayIndex),t.matches.push(a)}}}),this.options.includeScore&&o.push(function(e,t){t.score=e.score});for(var i=0,a=e.length;in)return o(e,this.pattern,r);var a=this.options,s=a.location,c=a.distance,h=a.threshold,l=a.findAllMatches,u=a.minMatchCharLength;return i(e,this.pattern,this.patternAlphabet,{location:s,distance:c,threshold:h,findAllMatches:l,minMatchCharLength:u})}}])&&r(t.prototype,n),s&&r(t,s),e}();e.exports=s},function(e,t){var n=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:/ +/g,o=new RegExp(t.replace(n,"\\$&").replace(r,"|")),i=e.match(o),a=!!i,s=[];if(a)for(var c=0,h=i.length;c=P;z-=1){var E=z-1,K=n[e.charAt(E)];if(K&&(x[E]=1),T[z]=(T[z+1]<<1|1)&K,0!==I&&(T[z]|=(L[z+1]|L[z])<<1|1|L[z+1]),T[z]&C&&(w=r(t,{errors:I,currentLocation:E,expectedLocation:g,distance:h}))<=m){if(m=w,(k=E)<=g)break;P=Math.max(1,2*g-k)}}if(r(t,{errors:I+1,currentLocation:g,expectedLocation:g,distance:h})>m)break;L=T}return{isMatch:k>=0,score:0===w?.001:w,matchedIndices:o(x,p)}}},function(e,t){e.exports=function(e,t){var n=t.errors,r=void 0===n?0:n,o=t.currentLocation,i=void 0===o?0:o,a=t.expectedLocation,s=void 0===a?0:a,c=t.distance,h=void 0===c?100:c,l=r/e.length,u=Math.abs(s-i);return h?l+u/h:u?1:l}},function(e,t){e.exports=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=[],r=-1,o=-1,i=0,a=e.length;i=t&&n.push([r,o]),r=-1)}return e[i-1]&&i-r>=t&&n.push([r,i-1]),n}},function(e,t){e.exports=function(e){for(var t={},n=e.length,r=0;r -1) { + return state.map(function (obj) { + var choice = obj; + + if (choice.id === parseInt("" + addItemAction_1.choiceId, 10)) { + choice.selected = true; + } + + return choice; + }); + } + + return state; + } + + case 'REMOVE_ITEM': + { + var removeItemAction_1 = action; // When an item is removed and it has an associated choice, + // we want to re-enable it so it can be chosen again + + if (removeItemAction_1.choiceId && removeItemAction_1.choiceId > -1) { + return state.map(function (obj) { + var choice = obj; + + if (choice.id === parseInt("" + removeItemAction_1.choiceId, 10)) { + choice.selected = false; + } + + return choice; + }); + } + + return state; + } + + case 'FILTER_CHOICES': + { + var filterChoicesAction_1 = action; + return state.map(function (obj) { + var choice = obj; // Set active state based on whether choice is + // within filtered results + + choice.active = filterChoicesAction_1.results.some(function (_a) { + var item = _a.item, + score = _a.score; + + if (item.id === choice.id) { + choice.score = score; + return true; + } + + return false; + }); + return choice; + }); + } + + case 'ACTIVATE_CHOICES': + { + var activateChoicesAction_1 = action; + return state.map(function (obj) { + var choice = obj; + choice.active = activateChoicesAction_1.active; + return choice; + }); + } + + case 'CLEAR_CHOICES': + { + return exports.defaultState; + } + + default: + { + return state; + } + } +} + +exports.default = choices; + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.defaultState = false; + +var general = function general(state, action) { + if (state === void 0) { + state = exports.defaultState; + } + + switch (action.type) { + case 'SET_IS_LOADING': + { + return action.isLoading; + } + + default: + { + return state; + } + } +}; + +exports.default = general; + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var __importDefault = this && this.__importDefault || function (mod) { + return mod && mod.__esModule ? mod : { + "default": mod + }; +}; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var dropdown_1 = __importDefault(__webpack_require__(19)); + +exports.Dropdown = dropdown_1.default; + +var container_1 = __importDefault(__webpack_require__(20)); + +exports.Container = container_1.default; + +var input_1 = __importDefault(__webpack_require__(21)); + +exports.Input = input_1.default; + +var list_1 = __importDefault(__webpack_require__(22)); + +exports.List = list_1.default; + +var wrapped_input_1 = __importDefault(__webpack_require__(23)); + +exports.WrappedInput = wrapped_input_1.default; + +var wrapped_select_1 = __importDefault(__webpack_require__(24)); + +exports.WrappedSelect = wrapped_select_1.default; + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var Dropdown = +/** @class */ +function () { + function Dropdown(_a) { + var element = _a.element, + type = _a.type, + classNames = _a.classNames; + this.element = element; + this.classNames = classNames; + this.type = type; + this.isActive = false; + } + + Object.defineProperty(Dropdown.prototype, "distanceFromTopWindow", { + /** + * Bottom position of dropdown in viewport coordinates + */ + get: function get() { + return this.element.getBoundingClientRect().bottom; + }, + enumerable: true, + configurable: true + }); + + Dropdown.prototype.getChild = function (selector) { + return this.element.querySelector(selector); + }; + /** + * Show dropdown to user by adding active state class + */ + + + Dropdown.prototype.show = function () { + this.element.classList.add(this.classNames.activeState); + this.element.setAttribute('aria-expanded', 'true'); + this.isActive = true; + return this; + }; + /** + * Hide dropdown from user + */ + + + Dropdown.prototype.hide = function () { + this.element.classList.remove(this.classNames.activeState); + this.element.setAttribute('aria-expanded', 'false'); + this.isActive = false; + return this; + }; + + return Dropdown; +}(); + +exports.default = Dropdown; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var utils_1 = __webpack_require__(1); + +var constants_1 = __webpack_require__(0); + +var Container = +/** @class */ +function () { + function Container(_a) { + var element = _a.element, + type = _a.type, + classNames = _a.classNames, + position = _a.position; + this.element = element; + this.classNames = classNames; + this.type = type; + this.position = position; + this.isOpen = false; + this.isFlipped = false; + this.isFocussed = false; + this.isDisabled = false; + this.isLoading = false; + this._onFocus = this._onFocus.bind(this); + this._onBlur = this._onBlur.bind(this); + } + + Container.prototype.addEventListeners = function () { + this.element.addEventListener('focus', this._onFocus); + this.element.addEventListener('blur', this._onBlur); + }; + + Container.prototype.removeEventListeners = function () { + this.element.removeEventListener('focus', this._onFocus); + this.element.removeEventListener('blur', this._onBlur); + }; + /** + * Determine whether container should be flipped based on passed + * dropdown position + */ + + + Container.prototype.shouldFlip = function (dropdownPos) { + if (typeof dropdownPos !== 'number') { + return false; + } // If flip is enabled and the dropdown bottom position is + // greater than the window height flip the dropdown. + + + var shouldFlip = false; + + if (this.position === 'auto') { + shouldFlip = !window.matchMedia("(min-height: " + (dropdownPos + 1) + "px)").matches; + } else if (this.position === 'top') { + shouldFlip = true; + } + + return shouldFlip; + }; + + Container.prototype.setActiveDescendant = function (activeDescendantID) { + this.element.setAttribute('aria-activedescendant', activeDescendantID); + }; + + Container.prototype.removeActiveDescendant = function () { + this.element.removeAttribute('aria-activedescendant'); + }; + + Container.prototype.open = function (dropdownPos) { + this.element.classList.add(this.classNames.openState); + this.element.setAttribute('aria-expanded', 'true'); + this.isOpen = true; + + if (this.shouldFlip(dropdownPos)) { + this.element.classList.add(this.classNames.flippedState); + this.isFlipped = true; + } + }; + + Container.prototype.close = function () { + this.element.classList.remove(this.classNames.openState); + this.element.setAttribute('aria-expanded', 'false'); + this.removeActiveDescendant(); + this.isOpen = false; // A dropdown flips if it does not have space within the page + + if (this.isFlipped) { + this.element.classList.remove(this.classNames.flippedState); + this.isFlipped = false; + } + }; + + Container.prototype.focus = function () { + if (!this.isFocussed) { + this.element.focus(); + } + }; + + Container.prototype.addFocusState = function () { + this.element.classList.add(this.classNames.focusState); + }; + + Container.prototype.removeFocusState = function () { + this.element.classList.remove(this.classNames.focusState); + }; + + Container.prototype.enable = function () { + this.element.classList.remove(this.classNames.disabledState); + this.element.removeAttribute('aria-disabled'); + + if (this.type === constants_1.SELECT_ONE_TYPE) { + this.element.setAttribute('tabindex', '0'); + } + + this.isDisabled = false; + }; + + Container.prototype.disable = function () { + this.element.classList.add(this.classNames.disabledState); + this.element.setAttribute('aria-disabled', 'true'); + + if (this.type === constants_1.SELECT_ONE_TYPE) { + this.element.setAttribute('tabindex', '-1'); + } + + this.isDisabled = true; + }; + + Container.prototype.wrap = function (element) { + utils_1.wrap(element, this.element); + }; + + Container.prototype.unwrap = function (element) { + if (this.element.parentNode) { + // Move passed element outside this element + this.element.parentNode.insertBefore(element, this.element); // Remove this element + + this.element.parentNode.removeChild(this.element); + } + }; + + Container.prototype.addLoadingState = function () { + this.element.classList.add(this.classNames.loadingState); + this.element.setAttribute('aria-busy', 'true'); + this.isLoading = true; + }; + + Container.prototype.removeLoadingState = function () { + this.element.classList.remove(this.classNames.loadingState); + this.element.removeAttribute('aria-busy'); + this.isLoading = false; + }; + + Container.prototype._onFocus = function () { + this.isFocussed = true; + }; + + Container.prototype._onBlur = function () { + this.isFocussed = false; + }; + + return Container; +}(); + +exports.default = Container; + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var utils_1 = __webpack_require__(1); + +var constants_1 = __webpack_require__(0); + +var Input = +/** @class */ +function () { + function Input(_a) { + var element = _a.element, + type = _a.type, + classNames = _a.classNames, + preventPaste = _a.preventPaste; + this.element = element; + this.type = type; + this.classNames = classNames; + this.preventPaste = preventPaste; + this.isFocussed = this.element.isEqualNode(document.activeElement); + this.isDisabled = element.disabled; + this._onPaste = this._onPaste.bind(this); + this._onInput = this._onInput.bind(this); + this._onFocus = this._onFocus.bind(this); + this._onBlur = this._onBlur.bind(this); + } + + Object.defineProperty(Input.prototype, "placeholder", { + set: function set(placeholder) { + this.element.placeholder = placeholder; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Input.prototype, "value", { + get: function get() { + return utils_1.sanitise(this.element.value); + }, + set: function set(value) { + this.element.value = value; + }, + enumerable: true, + configurable: true + }); + + Input.prototype.addEventListeners = function () { + this.element.addEventListener('paste', this._onPaste); + this.element.addEventListener('input', this._onInput, { + passive: true + }); + this.element.addEventListener('focus', this._onFocus, { + passive: true + }); + this.element.addEventListener('blur', this._onBlur, { + passive: true + }); + }; + + Input.prototype.removeEventListeners = function () { + this.element.removeEventListener('input', this._onInput); + this.element.removeEventListener('paste', this._onPaste); + this.element.removeEventListener('focus', this._onFocus); + this.element.removeEventListener('blur', this._onBlur); + }; + + Input.prototype.enable = function () { + this.element.removeAttribute('disabled'); + this.isDisabled = false; + }; + + Input.prototype.disable = function () { + this.element.setAttribute('disabled', ''); + this.isDisabled = true; + }; + + Input.prototype.focus = function () { + if (!this.isFocussed) { + this.element.focus(); + } + }; + + Input.prototype.blur = function () { + if (this.isFocussed) { + this.element.blur(); + } + }; + + Input.prototype.clear = function (setWidth) { + if (setWidth === void 0) { + setWidth = true; + } + + if (this.element.value) { + this.element.value = ''; + } + + if (setWidth) { + this.setWidth(); + } + + return this; + }; + /** + * Set the correct input width based on placeholder + * value or input value + */ + + + Input.prototype.setWidth = function () { + // Resize input to contents or placeholder + var _a = this.element, + style = _a.style, + value = _a.value, + placeholder = _a.placeholder; + style.minWidth = placeholder.length + 1 + "ch"; + style.width = value.length + 1 + "ch"; + }; + + Input.prototype.setActiveDescendant = function (activeDescendantID) { + this.element.setAttribute('aria-activedescendant', activeDescendantID); + }; + + Input.prototype.removeActiveDescendant = function () { + this.element.removeAttribute('aria-activedescendant'); + }; + + Input.prototype._onInput = function () { + if (this.type !== constants_1.SELECT_ONE_TYPE) { + this.setWidth(); + } + }; + + Input.prototype._onPaste = function (event) { + if (this.preventPaste) { + event.preventDefault(); + } + }; + + Input.prototype._onFocus = function () { + this.isFocussed = true; + }; + + Input.prototype._onBlur = function () { + this.isFocussed = false; + }; + + return Input; +}(); + +exports.default = Input; + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var constants_1 = __webpack_require__(0); + +var List = +/** @class */ +function () { + function List(_a) { + var element = _a.element; + this.element = element; + this.scrollPos = this.element.scrollTop; + this.height = this.element.offsetHeight; + } + + List.prototype.clear = function () { + this.element.innerHTML = ''; + }; + + List.prototype.append = function (node) { + this.element.appendChild(node); + }; + + List.prototype.getChild = function (selector) { + return this.element.querySelector(selector); + }; + + List.prototype.hasChildren = function () { + return this.element.hasChildNodes(); + }; + + List.prototype.scrollToTop = function () { + this.element.scrollTop = 0; + }; + + List.prototype.scrollToChildElement = function (element, direction) { + var _this = this; + + if (!element) { + return; + } + + var listHeight = this.element.offsetHeight; // Scroll position of dropdown + + var listScrollPosition = this.element.scrollTop + listHeight; + var elementHeight = element.offsetHeight; // Distance from bottom of element to top of parent + + var elementPos = element.offsetTop + elementHeight; // Difference between the element and scroll position + + var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop; + requestAnimationFrame(function () { + _this._animateScroll(destination, direction); + }); + }; + + List.prototype._scrollDown = function (scrollPos, strength, destination) { + var easing = (destination - scrollPos) / strength; + var distance = easing > 1 ? easing : 1; + this.element.scrollTop = scrollPos + distance; + }; + + List.prototype._scrollUp = function (scrollPos, strength, destination) { + var easing = (scrollPos - destination) / strength; + var distance = easing > 1 ? easing : 1; + this.element.scrollTop = scrollPos - distance; + }; + + List.prototype._animateScroll = function (destination, direction) { + var _this = this; + + var strength = constants_1.SCROLLING_SPEED; + var choiceListScrollTop = this.element.scrollTop; + var continueAnimation = false; + + if (direction > 0) { + this._scrollDown(choiceListScrollTop, strength, destination); + + if (choiceListScrollTop < destination) { + continueAnimation = true; + } + } else { + this._scrollUp(choiceListScrollTop, strength, destination); + + if (choiceListScrollTop > destination) { + continueAnimation = true; + } + } + + if (continueAnimation) { + requestAnimationFrame(function () { + _this._animateScroll(destination, direction); + }); + } + }; + + return List; +}(); + +exports.default = List; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var __extends = this && this.__extends || function () { + var _extendStatics = function extendStatics(d, b) { + _extendStatics = Object.setPrototypeOf || { + __proto__: [] + } instanceof Array && function (d, b) { + d.__proto__ = b; + } || function (d, b) { + for (var p in b) { + if (b.hasOwnProperty(p)) d[p] = b[p]; + } + }; + + return _extendStatics(d, b); + }; + + return function (d, b) { + _extendStatics(d, b); + + function __() { + this.constructor = d; + } + + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +}(); + +var __importDefault = this && this.__importDefault || function (mod) { + return mod && mod.__esModule ? mod : { + "default": mod + }; +}; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var wrapped_element_1 = __importDefault(__webpack_require__(5)); + +var WrappedInput = +/** @class */ +function (_super) { + __extends(WrappedInput, _super); + + function WrappedInput(_a) { + var element = _a.element, + classNames = _a.classNames, + delimiter = _a.delimiter; + + var _this = _super.call(this, { + element: element, + classNames: classNames + }) || this; + + _this.delimiter = delimiter; + return _this; + } + + Object.defineProperty(WrappedInput.prototype, "value", { + get: function get() { + return this.element.value; + }, + set: function set(value) { + this.element.setAttribute('value', value); + this.element.value = value; + }, + enumerable: true, + configurable: true + }); + return WrappedInput; +}(wrapped_element_1.default); + +exports.default = WrappedInput; + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var __extends = this && this.__extends || function () { + var _extendStatics = function extendStatics(d, b) { + _extendStatics = Object.setPrototypeOf || { + __proto__: [] + } instanceof Array && function (d, b) { + d.__proto__ = b; + } || function (d, b) { + for (var p in b) { + if (b.hasOwnProperty(p)) d[p] = b[p]; + } + }; + + return _extendStatics(d, b); + }; + + return function (d, b) { + _extendStatics(d, b); + + function __() { + this.constructor = d; + } + + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +}(); + +var __importDefault = this && this.__importDefault || function (mod) { + return mod && mod.__esModule ? mod : { + "default": mod + }; +}; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var wrapped_element_1 = __importDefault(__webpack_require__(5)); + +var WrappedSelect = +/** @class */ +function (_super) { + __extends(WrappedSelect, _super); + + function WrappedSelect(_a) { + var element = _a.element, + classNames = _a.classNames, + template = _a.template; + + var _this = _super.call(this, { + element: element, + classNames: classNames + }) || this; + + _this.template = template; + return _this; + } + + Object.defineProperty(WrappedSelect.prototype, "placeholderOption", { + get: function get() { + return this.element.querySelector('option[value=""]') || // Backward compatibility layer for the non-standard placeholder attribute supported in older versions. + this.element.querySelector('option[placeholder]'); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(WrappedSelect.prototype, "optionGroups", { + get: function get() { + return Array.from(this.element.getElementsByTagName('OPTGROUP')); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(WrappedSelect.prototype, "options", { + get: function get() { + return Array.from(this.element.options); + }, + set: function set(options) { + var _this = this; + + var fragment = document.createDocumentFragment(); + + var addOptionToFragment = function addOptionToFragment(data) { + // Create a standard select option + var option = _this.template(data); // Append it to fragment + + + fragment.appendChild(option); + }; // Add each list item to list + + + options.forEach(function (optionData) { + return addOptionToFragment(optionData); + }); + this.appendDocFragment(fragment); + }, + enumerable: true, + configurable: true + }); + + WrappedSelect.prototype.appendDocFragment = function (fragment) { + this.element.innerHTML = ''; + this.element.appendChild(fragment); + }; + + return WrappedSelect; +}(wrapped_element_1.default); + +exports.default = WrappedSelect; + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +/** + * Helpers to create HTML elements used by Choices + * Can be overridden by providing `callbackOnCreateTemplates` option + */ + +var templates = { + containerOuter: function containerOuter(_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType) { + var containerOuter = _a.containerOuter; + var div = Object.assign(document.createElement('div'), { + className: containerOuter + }); + div.dataset.type = passedElementType; + + if (dir) { + div.dir = dir; + } + + if (isSelectOneElement) { + div.tabIndex = 0; + } + + if (isSelectElement) { + div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox'); + + if (searchEnabled) { + div.setAttribute('aria-autocomplete', 'list'); + } + } + + div.setAttribute('aria-haspopup', 'true'); + div.setAttribute('aria-expanded', 'false'); + return div; + }, + containerInner: function containerInner(_a) { + var containerInner = _a.containerInner; + return Object.assign(document.createElement('div'), { + className: containerInner + }); + }, + itemList: function itemList(_a, isSelectOneElement) { + var list = _a.list, + listSingle = _a.listSingle, + listItems = _a.listItems; + return Object.assign(document.createElement('div'), { + className: list + " " + (isSelectOneElement ? listSingle : listItems) + }); + }, + placeholder: function placeholder(_a, value) { + var placeholder = _a.placeholder; + return Object.assign(document.createElement('div'), { + className: placeholder, + innerHTML: value + }); + }, + item: function item(_a, _b, removeItemButton) { + var item = _a.item, + button = _a.button, + highlightedState = _a.highlightedState, + itemSelectable = _a.itemSelectable, + placeholder = _a.placeholder; + var id = _b.id, + value = _b.value, + label = _b.label, + customProperties = _b.customProperties, + active = _b.active, + disabled = _b.disabled, + highlighted = _b.highlighted, + isPlaceholder = _b.placeholder; + var div = Object.assign(document.createElement('div'), { + className: item, + innerHTML: label + }); + Object.assign(div.dataset, { + item: '', + id: id, + value: value, + customProperties: customProperties + }); + + if (active) { + div.setAttribute('aria-selected', 'true'); + } + + if (disabled) { + div.setAttribute('aria-disabled', 'true'); + } + + if (isPlaceholder) { + div.classList.add(placeholder); + } + + div.classList.add(highlighted ? highlightedState : itemSelectable); + + if (removeItemButton) { + if (disabled) { + div.classList.remove(itemSelectable); + } + + div.dataset.deletable = ''; + /** @todo This MUST be localizable, not hardcoded! */ + + var REMOVE_ITEM_TEXT = 'Remove item'; + var removeButton = Object.assign(document.createElement('button'), { + type: 'button', + className: button, + innerHTML: REMOVE_ITEM_TEXT + }); + removeButton.setAttribute('aria-label', REMOVE_ITEM_TEXT + ": '" + value + "'"); + removeButton.dataset.button = ''; + div.appendChild(removeButton); + } + + return div; + }, + choiceList: function choiceList(_a, isSelectOneElement) { + var list = _a.list; + var div = Object.assign(document.createElement('div'), { + className: list + }); + + if (!isSelectOneElement) { + div.setAttribute('aria-multiselectable', 'true'); + } + + div.setAttribute('role', 'listbox'); + return div; + }, + choiceGroup: function choiceGroup(_a, _b) { + var group = _a.group, + groupHeading = _a.groupHeading, + itemDisabled = _a.itemDisabled; + var id = _b.id, + value = _b.value, + disabled = _b.disabled; + var div = Object.assign(document.createElement('div'), { + className: group + " " + (disabled ? itemDisabled : '') + }); + div.setAttribute('role', 'group'); + Object.assign(div.dataset, { + group: '', + id: id, + value: value + }); + + if (disabled) { + div.setAttribute('aria-disabled', 'true'); + } + + div.appendChild(Object.assign(document.createElement('div'), { + className: groupHeading, + innerHTML: value + })); + return div; + }, + choice: function choice(_a, _b, selectText) { + var item = _a.item, + itemChoice = _a.itemChoice, + itemSelectable = _a.itemSelectable, + selectedState = _a.selectedState, + itemDisabled = _a.itemDisabled, + placeholder = _a.placeholder; + var id = _b.id, + value = _b.value, + label = _b.label, + groupId = _b.groupId, + elementId = _b.elementId, + isDisabled = _b.disabled, + isSelected = _b.selected, + isPlaceholder = _b.placeholder; + var div = Object.assign(document.createElement('div'), { + id: elementId, + innerHTML: label, + className: item + " " + itemChoice + }); + + if (isSelected) { + div.classList.add(selectedState); + } + + if (isPlaceholder) { + div.classList.add(placeholder); + } + + div.setAttribute('role', groupId && groupId > 0 ? 'treeitem' : 'option'); + Object.assign(div.dataset, { + choice: '', + id: id, + value: value, + selectText: selectText + }); + + if (isDisabled) { + div.classList.add(itemDisabled); + div.dataset.choiceDisabled = ''; + div.setAttribute('aria-disabled', 'true'); + } else { + div.classList.add(itemSelectable); + div.dataset.choiceSelectable = ''; + } + + return div; + }, + input: function input(_a, placeholderValue) { + var input = _a.input, + inputCloned = _a.inputCloned; + var inp = Object.assign(document.createElement('input'), { + type: 'text', + className: input + " " + inputCloned, + autocomplete: 'off', + autocapitalize: 'off', + spellcheck: false + }); + inp.setAttribute('role', 'textbox'); + inp.setAttribute('aria-autocomplete', 'list'); + inp.setAttribute('aria-label', placeholderValue); + return inp; + }, + dropdown: function dropdown(_a) { + var list = _a.list, + listDropdown = _a.listDropdown; + var div = document.createElement('div'); + div.classList.add(list, listDropdown); + div.setAttribute('aria-expanded', 'false'); + return div; + }, + notice: function notice(_a, innerHTML, type) { + var item = _a.item, + itemChoice = _a.itemChoice, + noResults = _a.noResults, + noChoices = _a.noChoices; + + if (type === void 0) { + type = ''; + } + + var classes = [item, itemChoice]; + + if (type === 'no-choices') { + classes.push(noChoices); + } else if (type === 'no-results') { + classes.push(noResults); + } + + return Object.assign(document.createElement('div'), { + innerHTML: innerHTML, + className: classes.join(' ') + }); + }, + option: function option(_a) { + var label = _a.label, + value = _a.value, + customProperties = _a.customProperties, + active = _a.active, + disabled = _a.disabled; + var opt = new Option(label, value, false, active); + + if (customProperties) { + opt.dataset.customProperties = "" + customProperties; + } + + opt.disabled = !!disabled; + return opt; + } +}; +exports.default = templates; + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var constants_1 = __webpack_require__(0); + +exports.addChoice = function (_a) { + var value = _a.value, + label = _a.label, + id = _a.id, + groupId = _a.groupId, + disabled = _a.disabled, + elementId = _a.elementId, + customProperties = _a.customProperties, + placeholder = _a.placeholder, + keyCode = _a.keyCode; + return { + type: constants_1.ACTION_TYPES.ADD_CHOICE, + value: value, + label: label, + id: id, + groupId: groupId, + disabled: disabled, + elementId: elementId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: keyCode + }; +}; + +exports.filterChoices = function (results) { + return { + type: constants_1.ACTION_TYPES.FILTER_CHOICES, + results: results + }; +}; + +exports.activateChoices = function (active) { + if (active === void 0) { + active = true; + } + + return { + type: constants_1.ACTION_TYPES.ACTIVATE_CHOICES, + active: active + }; +}; + +exports.clearChoices = function () { + return { + type: constants_1.ACTION_TYPES.CLEAR_CHOICES + }; +}; + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var constants_1 = __webpack_require__(0); + +exports.addItem = function (_a) { + var value = _a.value, + label = _a.label, + id = _a.id, + choiceId = _a.choiceId, + groupId = _a.groupId, + customProperties = _a.customProperties, + placeholder = _a.placeholder, + keyCode = _a.keyCode; + return { + type: constants_1.ACTION_TYPES.ADD_ITEM, + value: value, + label: label, + id: id, + choiceId: choiceId, + groupId: groupId, + customProperties: customProperties, + placeholder: placeholder, + keyCode: keyCode + }; +}; + +exports.removeItem = function (id, choiceId) { + return { + type: constants_1.ACTION_TYPES.REMOVE_ITEM, + id: id, + choiceId: choiceId + }; +}; + +exports.highlightItem = function (id, highlighted) { + return { + type: constants_1.ACTION_TYPES.HIGHLIGHT_ITEM, + id: id, + highlighted: highlighted + }; +}; + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var constants_1 = __webpack_require__(0); + +exports.addGroup = function (_a) { + var value = _a.value, + id = _a.id, + active = _a.active, + disabled = _a.disabled; + return { + type: constants_1.ACTION_TYPES.ADD_GROUP, + value: value, + id: id, + active: active, + disabled: disabled + }; +}; + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var constants_1 = __webpack_require__(0); + +exports.clearAll = function () { + return { + type: constants_1.ACTION_TYPES.CLEAR_ALL + }; +}; + +exports.resetTo = function (state) { + return { + type: constants_1.ACTION_TYPES.RESET_TO, + state: state + }; +}; + +exports.setIsLoading = function (isLoading) { + return { + type: constants_1.ACTION_TYPES.SET_IS_LOADING, + isLoading: isLoading + }; +}; /***/ }) /******/ ])["default"]; diff --git a/public/assets/scripts/choices.min.js b/public/assets/scripts/choices.min.js index 8223c62..eb8462b 100644 --- a/public/assets/scripts/choices.min.js +++ b/public/assets/scripts/choices.min.js @@ -1,11 +1,11 @@ /*! choices.js v9.0.1 | © 2019 Josh Johnson | https://github.com/jshjohnson/Choices#readme */ -window.Choices=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/public/assets/scripts/",i(i.s=4)}([function(e,t,i){"use strict";var n=function(e){return function(e){return!!e&&"object"==typeof e}(e)&&!function(e){var t=Object.prototype.toString.call(e);return"[object RegExp]"===t||"[object Date]"===t||function(e){return e.$$typeof===s}(e)}(e)};var s="function"==typeof Symbol&&Symbol.for?Symbol.for("react.element"):60103;function r(e,t){return!1!==t.clone&&t.isMergeableObject(e)?l((i=e,Array.isArray(i)?[]:{}),e,t):e;var i}function o(e,t,i){return e.concat(t).map((function(e){return r(e,i)}))}function a(e){return Object.keys(e).concat(function(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter((function(t){return e.propertyIsEnumerable(t)})):[]}(e))}function c(e,t,i){var n={};return i.isMergeableObject(e)&&a(e).forEach((function(t){n[t]=r(e[t],i)})),a(t).forEach((function(s){(function(e,t){try{return t in e&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}catch(e){return!1}})(e,s)||(i.isMergeableObject(t[s])&&e[s]?n[s]=function(e,t){if(!t.customMerge)return l;var i=t.customMerge(e);return"function"==typeof i?i:l}(s,i)(e[s],t[s],i):n[s]=r(t[s],i))})),n}function l(e,t,i){(i=i||{}).arrayMerge=i.arrayMerge||o,i.isMergeableObject=i.isMergeableObject||n,i.cloneUnlessOtherwiseSpecified=r;var s=Array.isArray(t);return s===Array.isArray(e)?s?i.arrayMerge(e,t,i):c(e,t,i):r(t,i)}l.all=function(e,t){if(!Array.isArray(e))throw new Error("first argument should be an array");return e.reduce((function(e,i){return l(e,i,t)}),{})};var h=l;e.exports=h},function(e,t,i){"use strict";(function(e,n){var s,r=i(3);s="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==e?e:n;var o=Object(r.a)(s);t.a=o}).call(this,i(5),i(6)(e))},function(e,t,i){ +window.Choices=function(e){var t={};function i(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/public/assets/scripts/",i(i.s=7)}([function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(1);t.DEFAULT_CLASSNAMES={containerOuter:"choices",containerInner:"choices__inner",input:"choices__input",inputCloned:"choices__input--cloned",list:"choices__list",listItems:"choices__list--multiple",listSingle:"choices__list--single",listDropdown:"choices__list--dropdown",item:"choices__item",itemSelectable:"choices__item--selectable",itemDisabled:"choices__item--disabled",itemChoice:"choices__item--choice",placeholder:"choices__placeholder",group:"choices__group",groupHeading:"choices__heading",button:"choices__button",activeState:"is-active",focusState:"is-focused",openState:"is-open",disabledState:"is-disabled",highlightedState:"is-highlighted",selectedState:"is-selected",flippedState:"is-flipped",loadingState:"is-loading",noResults:"has-no-results",noChoices:"has-no-choices"},t.DEFAULT_CONFIG={items:[],choices:[],silent:!1,renderChoiceLimit:-1,maxItemCount:-1,addItems:!0,addItemFilter:null,removeItems:!0,removeItemButton:!1,editItems:!1,duplicateItemsAllowed:!0,delimiter:",",paste:!0,searchEnabled:!0,searchChoices:!0,searchFloor:1,searchResultLimit:4,searchFields:["label","value"],position:"auto",resetScrollPosition:!0,shouldSort:!0,shouldSortItems:!1,sorter:n.sortByAlpha,placeholder:!0,placeholderValue:null,searchPlaceholderValue:null,prependValue:null,appendValue:null,renderSelectedChoices:"auto",loadingText:"Loading...",noResultsText:"No results found",noChoicesText:"No choices to choose from",itemSelectText:"Press to select",uniqueItemText:"Only unique values can be added",customAddItemText:"Only values matching specific conditions can be added",addItemText:function(e){return'Press Enter to add "'+n.sanitise(e)+'"'},maxItemText:function(e){return"Only "+e+" values can be added"},valueComparer:function(e,t){return e===t},fuseOptions:{includeScore:!0},callbackOnInit:null,callbackOnCreateTemplates:null,classNames:t.DEFAULT_CLASSNAMES},t.EVENTS={showDropdown:"showDropdown",hideDropdown:"hideDropdown",change:"change",choice:"choice",search:"search",addItem:"addItem",removeItem:"removeItem",highlightItem:"highlightItem",highlightChoice:"highlightChoice",unhighlightItem:"unhighlightItem"},t.ACTION_TYPES={ADD_CHOICE:"ADD_CHOICE",FILTER_CHOICES:"FILTER_CHOICES",ACTIVATE_CHOICES:"ACTIVATE_CHOICES",CLEAR_CHOICES:"CLEAR_CHOICES",ADD_GROUP:"ADD_GROUP",ADD_ITEM:"ADD_ITEM",REMOVE_ITEM:"REMOVE_ITEM",HIGHLIGHT_ITEM:"HIGHLIGHT_ITEM",CLEAR_ALL:"CLEAR_ALL",RESET_TO:"RESET_TO",SET_IS_LOADING:"SET_IS_LOADING"},t.KEY_CODES={BACK_KEY:46,DELETE_KEY:8,ENTER_KEY:13,A_KEY:65,ESC_KEY:27,UP_KEY:38,DOWN_KEY:40,PAGE_UP_KEY:33,PAGE_DOWN_KEY:34},t.TEXT_TYPE="text",t.SELECT_ONE_TYPE="select-one",t.SELECT_MULTIPLE_TYPE="select-multiple",t.SCROLLING_SPEED=4},function(e,t,i){"use strict";var n;Object.defineProperty(t,"__esModule",{value:!0}),t.getRandomNumber=function(e,t){return Math.floor(Math.random()*(t-e)+e)},t.generateChars=function(e){return Array.from({length:e},(function(){return t.getRandomNumber(0,36).toString(36)})).join("")},t.generateId=function(e,i){var n=e.id||e.name&&e.name+"-"+t.generateChars(2)||t.generateChars(4);return n=i+"-"+(n=n.replace(/(:|\.|\[|\]|,)/g,""))},t.getType=function(e){return Object.prototype.toString.call(e).slice(8,-1)},t.isType=function(e,i){return null!=i&&t.getType(i)===e},t.wrap=function(e,t){return void 0===t&&(t=document.createElement("div")),e.nextSibling?e.parentNode&&e.parentNode.insertBefore(t,e.nextSibling):e.parentNode&&e.parentNode.appendChild(t),t.appendChild(e)},t.getAdjacentEl=function(e,t,i){void 0===i&&(i=1);for(var n=(i>0?"next":"previous")+"ElementSibling",r=e[n];r;){if(r.matches(t))return r;r=r[n]}return r},t.isScrolledIntoView=function(e,t,i){return void 0===i&&(i=1),!!e&&(i>0?t.scrollTop+t.offsetHeight>=e.offsetTop+e.offsetHeight:e.offsetTop>=t.scrollTop)},t.sanitise=function(e){return"string"!=typeof e?e:e.replace(/&/g,"&").replace(/>/g,"&rt;").replace(/=0?this._store.getGroupById(r):null;return this._store.dispatch(d.highlightItem(i,!0)),t&&this.passedElement.triggerEvent(l.EVENTS.highlightItem,{id:i,value:s,label:c,groupValue:u&&u.value?u.value:null}),this},e.prototype.unhighlightItem=function(e){if(!e||!e.id)return this;var t=e.id,i=e.groupId,n=void 0===i?-1:i,r=e.value,o=void 0===r?"":r,s=e.label,a=void 0===s?"":s,c=n>=0?this._store.getGroupById(n):null;return this._store.dispatch(d.highlightItem(t,!1)),this.passedElement.triggerEvent(l.EVENTS.highlightItem,{id:t,value:o,label:a,groupValue:c&&c.value?c.value:null}),this},e.prototype.highlightAll=function(){var e=this;return this._store.items.forEach((function(t){return e.highlightItem(t)})),this},e.prototype.unhighlightAll=function(){var e=this;return this._store.items.forEach((function(t){return e.unhighlightItem(t)})),this},e.prototype.removeActiveItemsByValue=function(e){var t=this;return this._store.activeItems.filter((function(t){return t.value===e})).forEach((function(e){return t._removeItem(e)})),this},e.prototype.removeActiveItems=function(e){var t=this;return this._store.activeItems.filter((function(t){return t.id!==e})).forEach((function(e){return t._removeItem(e)})),this},e.prototype.removeHighlightedItems=function(e){var t=this;return void 0===e&&(e=!1),this._store.highlightedActiveItems.forEach((function(i){t._removeItem(i),e&&t._triggerChange(i.value)})),this},e.prototype.showDropdown=function(e){var t=this;return this.dropdown.isActive?this:(requestAnimationFrame((function(){t.dropdown.show(),t.containerOuter.open(t.dropdown.distanceFromTopWindow),!e&&t._canSearch&&t.input.focus(),t.passedElement.triggerEvent(l.EVENTS.showDropdown,{})})),this)},e.prototype.hideDropdown=function(e){var t=this;return this.dropdown.isActive?(requestAnimationFrame((function(){t.dropdown.hide(),t.containerOuter.close(),!e&&t._canSearch&&(t.input.removeActiveDescendant(),t.input.blur()),t.passedElement.triggerEvent(l.EVENTS.hideDropdown,{})})),this):this},e.prototype.getValue=function(e){void 0===e&&(e=!1);var t=this._store.activeItems.reduce((function(t,i){var n=e?i.value:i;return t.push(n),t}),[]);return this._isSelectOneElement?t[0]:t},e.prototype.setValue=function(e){var t=this;return this.initialised?(e.forEach((function(e){return t._setChoiceOrItem(e)})),this):this},e.prototype.setChoiceByValue=function(e){var t=this;return!this.initialised||this._isTextElement?this:((Array.isArray(e)?e:[e]).forEach((function(e){return t._findAndSelectChoiceByValue(e)})),this)},e.prototype.setChoices=function(e,t,i,n){var r=this;if(void 0===e&&(e=[]),void 0===t&&(t="value"),void 0===i&&(i="label"),void 0===n&&(n=!1),!this.initialised)throw new ReferenceError("setChoices was called on a non-initialized instance of Choices");if(!this._isSelectElement)throw new TypeError("setChoices can't be used with INPUT based Choices");if("string"!=typeof t||!t)throw new TypeError("value parameter must be a name of 'value' field in passed objects");if(n&&this.clearChoices(),"function"==typeof e){var o=e(this);if("function"==typeof Promise&&o instanceof Promise)return new Promise((function(e){return requestAnimationFrame(e)})).then((function(){return r._handleLoadingState(!0)})).then((function(){return o})).then((function(e){return r.setChoices(e,t,i,n)})).catch((function(e){r.config.silent||console.error(e)})).then((function(){return r._handleLoadingState(!1)})).then((function(){return r}));if(!Array.isArray(o))throw new TypeError(".setChoices first argument function must return either array of choices or Promise, got: "+typeof o);return this.setChoices(o,t,i,!1)}if(!Array.isArray(e))throw new TypeError(".setChoices must be called either with array of choices with a function resulting into Promise of array of choices");return this.containerOuter.removeLoadingState(),this._startLoading(),e.forEach((function(e){if(e.choices)r._addGroup({id:e.id?parseInt(""+e.id,10):null,group:e,valueKey:t,labelKey:i});else{var n=e;r._addChoice({value:n[t],label:n[i],isSelected:!!n.selected,isDisabled:!!n.disabled,placeholder:!!n.placeholder,customProperties:n.customProperties})}})),this._stopLoading(),this},e.prototype.clearChoices=function(){return this._store.dispatch(h.clearChoices()),this},e.prototype.clearStore=function(){return this._store.dispatch(f.clearAll()),this},e.prototype.clearInput=function(){var e=!this._isSelectOneElement;return this.input.clear(e),!this._isTextElement&&this._canSearch&&(this._isSearching=!1,this._store.dispatch(h.activateChoices(!0))),this},e.prototype._render=function(){if(!this._store.isLoading()){this._currentState=this._store.state;var e=this._currentState.choices!==this._prevState.choices||this._currentState.groups!==this._prevState.groups||this._currentState.items!==this._prevState.items,t=this._isSelectElement,i=this._currentState.items!==this._prevState.items;e&&(t&&this._renderChoices(),i&&this._renderItems(),this._prevState=this._currentState)}},e.prototype._renderChoices=function(){var e=this,t=this._store,i=t.activeGroups,n=t.activeChoices,r=document.createDocumentFragment();if(this.choiceList.clear(),this.config.resetScrollPosition&&requestAnimationFrame((function(){return e.choiceList.scrollToTop()})),i.length>=1&&!this._isSearching){var o=n.filter((function(e){return!0===e.placeholder&&-1===e.groupId}));o.length>=1&&(r=this._createChoicesFragment(o,r)),r=this._createGroupsFragment(i,n,r)}else n.length>=1&&(r=this._createChoicesFragment(n,r));if(r.childNodes&&r.childNodes.length>0){var s=this._store.activeItems,a=this._canAddItem(s,this.input.value);if(a.response)this.choiceList.append(r),this._highlightChoice();else{var c=this._getTemplate("notice",a.notice);this.choiceList.append(c)}}else{var l=void 0;c=void 0;this._isSearching?(c="function"==typeof this.config.noResultsText?this.config.noResultsText():this.config.noResultsText,l=this._getTemplate("notice",c,"no-results")):(c="function"==typeof this.config.noChoicesText?this.config.noChoicesText():this.config.noChoicesText,l=this._getTemplate("notice",c,"no-choices")),this.choiceList.append(l)}},e.prototype._renderItems=function(){var e=this._store.activeItems||[];this.itemList.clear();var t=this._createItemsFragment(e);t.childNodes&&this.itemList.append(t)},e.prototype._createGroupsFragment=function(e,t,i){var n=this;void 0===i&&(i=document.createDocumentFragment());return this.config.shouldSort&&e.sort(this.config.sorter),e.forEach((function(e){var r=function(e){return t.filter((function(t){return n._isSelectOneElement?t.groupId===e.id:t.groupId===e.id&&("always"===n.config.renderSelectedChoices||!t.selected)}))}(e);if(r.length>=1){var o=n._getTemplate("choiceGroup",e);i.appendChild(o),n._createChoicesFragment(r,i,!0)}})),i},e.prototype._createChoicesFragment=function(e,t,i){var r=this;void 0===t&&(t=document.createDocumentFragment()),void 0===i&&(i=!1);var o=this.config,s=o.renderSelectedChoices,a=o.searchResultLimit,c=o.renderChoiceLimit,l=this._isSearching?m.sortByScore:this.config.sorter,u=function(e){if("auto"!==s||(r._isSelectOneElement||!e.selected)){var i=r._getTemplate("choice",e,r.config.itemSelectText);t.appendChild(i)}},h=e;"auto"!==s||this._isSelectOneElement||(h=e.filter((function(e){return!e.selected})));var d=h.reduce((function(e,t){return t.placeholder?e.placeholderChoices.push(t):e.normalChoices.push(t),e}),{placeholderChoices:[],normalChoices:[]}),p=d.placeholderChoices,f=d.normalChoices;(this.config.shouldSort||this._isSearching)&&f.sort(l);var v=h.length,_=this._isSelectOneElement?n(p,f):f;this._isSearching?v=a:c&&c>0&&!i&&(v=c);for(var g=0;g=n){var s=r?this._searchChoices(e):0;this.passedElement.triggerEvent(l.EVENTS.search,{value:e,resultCount:s})}else o&&(this._isSearching=!1,this._store.dispatch(h.activateChoices(!0)))}},e.prototype._canAddItem=function(e,t){var i=!0,n="function"==typeof this.config.addItemText?this.config.addItemText(t):this.config.addItemText;if(!this._isSelectOneElement){var r=m.existsInArray(e,t);this.config.maxItemCount>0&&this.config.maxItemCount<=e.length&&(i=!1,n="function"==typeof this.config.maxItemText?this.config.maxItemText(this.config.maxItemCount):this.config.maxItemText),!this.config.duplicateItemsAllowed&&r&&i&&(i=!1,n="function"==typeof this.config.uniqueItemText?this.config.uniqueItemText(t):this.config.uniqueItemText),this._isTextElement&&this.config.addItems&&i&&"function"==typeof this.config.addItemFilter&&!this.config.addItemFilter(t)&&(i=!1,n="function"==typeof this.config.customAddItemText?this.config.customAddItemText(t):this.config.customAddItemText)}return{response:i,notice:n}},e.prototype._searchChoices=function(e){var t="string"==typeof e?e.trim():e,i="string"==typeof this._currentValue?this._currentValue.trim():this._currentValue;if(t.length<1&&t===i+" ")return 0;var r=this._store.searchableChoices,s=t,a=n(this.config.searchFields),c=Object.assign(this.config.fuseOptions,{keys:a,includeMatches:!0}),l=new o.default(r,c).search(s);return this._currentValue=t,this._highlightPosition=0,this._isSearching=!0,this._store.dispatch(h.filterChoices(l)),l.length},e.prototype._addEventListeners=function(){var e=document.documentElement;e.addEventListener("touchend",this._onTouchEnd,!0),this.containerOuter.element.addEventListener("keydown",this._onKeyDown,!0),this.containerOuter.element.addEventListener("mousedown",this._onMouseDown,!0),e.addEventListener("click",this._onClick,{passive:!0}),e.addEventListener("touchmove",this._onTouchMove,{passive:!0}),this.dropdown.element.addEventListener("mouseover",this._onMouseOver,{passive:!0}),this._isSelectOneElement&&(this.containerOuter.element.addEventListener("focus",this._onFocus,{passive:!0}),this.containerOuter.element.addEventListener("blur",this._onBlur,{passive:!0})),this.input.element.addEventListener("keyup",this._onKeyUp,{passive:!0}),this.input.element.addEventListener("focus",this._onFocus,{passive:!0}),this.input.element.addEventListener("blur",this._onBlur,{passive:!0}),this.input.element.form&&this.input.element.form.addEventListener("reset",this._onFormReset,{passive:!0}),this.input.addEventListeners()},e.prototype._removeEventListeners=function(){var e=document.documentElement;e.removeEventListener("touchend",this._onTouchEnd,!0),this.containerOuter.element.removeEventListener("keydown",this._onKeyDown,!0),this.containerOuter.element.removeEventListener("mousedown",this._onMouseDown,!0),e.removeEventListener("click",this._onClick),e.removeEventListener("touchmove",this._onTouchMove),this.dropdown.element.removeEventListener("mouseover",this._onMouseOver),this._isSelectOneElement&&(this.containerOuter.element.removeEventListener("focus",this._onFocus),this.containerOuter.element.removeEventListener("blur",this._onBlur)),this.input.element.removeEventListener("keyup",this._onKeyUp),this.input.element.removeEventListener("focus",this._onFocus),this.input.element.removeEventListener("blur",this._onBlur),this.input.element.form&&this.input.element.form.removeEventListener("reset",this._onFormReset),this.input.removeEventListeners()},e.prototype._onKeyDown=function(e){var t=e.keyCode,i=this._store.activeItems,n=this.input.isFocussed,r=this.dropdown.isActive,o=this.itemList.hasChildren(),s=String.fromCharCode(t),a=/[a-zA-Z0-9-_ ]/.test(s),c=l.KEY_CODES.BACK_KEY,u=l.KEY_CODES.DELETE_KEY,h=l.KEY_CODES.ENTER_KEY,d=l.KEY_CODES.A_KEY,p=l.KEY_CODES.ESC_KEY,f=l.KEY_CODES.UP_KEY,m=l.KEY_CODES.DOWN_KEY,v=l.KEY_CODES.PAGE_UP_KEY,_=l.KEY_CODES.PAGE_DOWN_KEY;switch(this._isTextElement||r||!a||(this.showDropdown(),this.input.isFocussed||(this.input.value+=s.toLowerCase())),t){case d:return this._onSelectKey(e,o);case h:return this._onEnterKey(e,i,r);case p:return this._onEscapeKey(r);case f:case v:case m:case _:return this._onDirectionKey(e,r);case u:case c:return this._onDeleteKey(e,i,n)}},e.prototype._onKeyUp=function(e){var t=e.target,i=e.keyCode,n=this.input.value,r=this._store.activeItems,o=this._canAddItem(r,n),s=l.KEY_CODES.BACK_KEY,a=l.KEY_CODES.DELETE_KEY;if(this._isTextElement){if(o.notice&&n){var c=this._getTemplate("notice",o.notice);this.dropdown.element.innerHTML=c.outerHTML,this.showDropdown(!0)}else this.hideDropdown(!0)}else{var u=(i===s||i===a)&&t&&!t.value,d=!this._isTextElement&&this._isSearching,p=this._canSearch&&o.response;u&&d?(this._isSearching=!1,this._store.dispatch(h.activateChoices(!0))):p&&this._handleSearch(this.input.value)}this._canSearch=this.config.searchEnabled},e.prototype._onSelectKey=function(e,t){var i=e.ctrlKey,n=e.metaKey;(i||n)&&t&&(this._canSearch=!1,this.config.removeItems&&!this.input.value&&this.input.element===document.activeElement&&this.highlightAll())},e.prototype._onEnterKey=function(e,t,i){var n=e.target,r=l.KEY_CODES.ENTER_KEY,o=n&&n.hasAttribute("data-button");if(this._isTextElement&&n&&n.value){var s=this.input.value;this._canAddItem(t,s).response&&(this.hideDropdown(!0),this._addItem({value:s}),this._triggerChange(s),this.clearInput())}if(o&&(this._handleButtonAction(t,n),e.preventDefault()),i){var a=this.dropdown.getChild("."+this.config.classNames.highlightedState);a&&(t[0]&&(t[0].keyCode=r),this._handleChoiceAction(t,a)),e.preventDefault()}else this._isSelectOneElement&&(this.showDropdown(),e.preventDefault())},e.prototype._onEscapeKey=function(e){e&&(this.hideDropdown(!0),this.containerOuter.focus())},e.prototype._onDirectionKey=function(e,t){var i=e.keyCode,n=e.metaKey,r=l.KEY_CODES.DOWN_KEY,o=l.KEY_CODES.PAGE_UP_KEY,s=l.KEY_CODES.PAGE_DOWN_KEY;if(t||this._isSelectOneElement){this.showDropdown(),this._canSearch=!1;var a=i===r||i===s?1:-1,c=void 0;if(n||i===s||i===o)c=a>0?this.dropdown.element.querySelector("[data-choice-selectable]:last-of-type"):this.dropdown.element.querySelector("[data-choice-selectable]");else{var u=this.dropdown.element.querySelector("."+this.config.classNames.highlightedState);c=u?m.getAdjacentEl(u,"[data-choice-selectable]",a):this.dropdown.element.querySelector("[data-choice-selectable]")}c&&(m.isScrolledIntoView(c,this.choiceList.element,a)||this.choiceList.scrollToChildElement(c,a),this._highlightChoice(c)),e.preventDefault()}},e.prototype._onDeleteKey=function(e,t,i){var n=e.target;this._isSelectOneElement||n.value||!i||(this._handleBackspace(t),e.preventDefault())},e.prototype._onTouchMove=function(){this._wasTap&&(this._wasTap=!1)},e.prototype._onTouchEnd=function(e){var t=(e||e.touches[0]).target;this._wasTap&&this.containerOuter.element.contains(t)&&((t===this.containerOuter.element||t===this.containerInner.element)&&(this._isTextElement?this.input.focus():this._isSelectMultipleElement&&this.showDropdown()),e.stopPropagation());this._wasTap=!0},e.prototype._onMouseDown=function(e){var t=e.target;if(t instanceof HTMLElement){if(_&&this.choiceList.element.contains(t)){var i=this.choiceList.element.firstElementChild,n="ltr"===this._direction?e.offsetX>=i.offsetWidth:e.offsetX0&&this.unhighlightAll(),this.containerOuter.removeFocusState(),this.hideDropdown(!0))},e.prototype._onFocus=function(e){var t,i=this,n=e.target;n&&this.containerOuter.element.contains(n)&&((t={})[l.TEXT_TYPE]=function(){n===i.input.element&&i.containerOuter.addFocusState()},t[l.SELECT_ONE_TYPE]=function(){i.containerOuter.addFocusState(),n===i.input.element&&i.showDropdown(!0)},t[l.SELECT_MULTIPLE_TYPE]=function(){n===i.input.element&&(i.showDropdown(!0),i.containerOuter.addFocusState())},t)[this.passedElement.element.type]()},e.prototype._onBlur=function(e){var t,i=this,n=e.target;if(n&&this.containerOuter.element.contains(n)&&!this._isScrollingOnIe){var r=this._store.activeItems.some((function(e){return e.highlighted}));((t={})[l.TEXT_TYPE]=function(){n===i.input.element&&(i.containerOuter.removeFocusState(),r&&i.unhighlightAll(),i.hideDropdown(!0))},t[l.SELECT_ONE_TYPE]=function(){i.containerOuter.removeFocusState(),(n===i.input.element||n===i.containerOuter.element&&!i._canSearch)&&i.hideDropdown(!0)},t[l.SELECT_MULTIPLE_TYPE]=function(){n===i.input.element&&(i.containerOuter.removeFocusState(),i.hideDropdown(!0),r&&i.unhighlightAll())},t)[this.passedElement.element.type]()}else this._isScrollingOnIe=!1,this.input.element.focus()},e.prototype._onFormReset=function(){this._store.dispatch(f.resetTo(this._initialState))},e.prototype._highlightChoice=function(e){var t=this;void 0===e&&(e=null);var i=Array.from(this.dropdown.element.querySelectorAll("[data-choice-selectable]"));if(i.length){var n=e;Array.from(this.dropdown.element.querySelectorAll("."+this.config.classNames.highlightedState)).forEach((function(e){e.classList.remove(t.config.classNames.highlightedState),e.setAttribute("aria-selected","false")})),n?this._highlightPosition=i.indexOf(n):(n=i.length>this._highlightPosition?i[this._highlightPosition]:i[i.length-1])||(n=i[0]),n.classList.add(this.config.classNames.highlightedState),n.setAttribute("aria-selected","true"),this.passedElement.triggerEvent(l.EVENTS.highlightChoice,{el:n}),this.dropdown.isActive&&(this.input.setActiveDescendant(n.id),this.containerOuter.setActiveDescendant(n.id))}},e.prototype._addItem=function(e){var t=e.value,i=e.label,n=void 0===i?null:i,r=e.choiceId,o=void 0===r?-1:r,s=e.groupId,a=void 0===s?-1:s,c=e.customProperties,u=void 0===c?{}:c,h=e.placeholder,p=void 0!==h&&h,f=e.keyCode,m=void 0===f?-1:f,v="string"==typeof t?t.trim():t,_=this._store.items,g=n||v,y=o||-1,b=a>=0?this._store.getGroupById(a):null,E=_?_.length+1:1;this.config.prependValue&&(v=this.config.prependValue+v.toString()),this.config.appendValue&&(v+=this.config.appendValue.toString()),this._store.dispatch(d.addItem({value:v,label:g,id:E,choiceId:y,groupId:a,customProperties:u,placeholder:p,keyCode:m})),this._isSelectOneElement&&this.removeActiveItems(E),this.passedElement.triggerEvent(l.EVENTS.addItem,{id:E,value:v,label:g,customProperties:u,groupValue:b&&b.value?b.value:null,keyCode:m})},e.prototype._removeItem=function(e){var t=e.id,i=e.value,n=e.label,r=e.customProperties,o=e.choiceId,s=e.groupId,a=s&&s>=0?this._store.getGroupById(s):null;t&&o&&(this._store.dispatch(d.removeItem(t,o)),this.passedElement.triggerEvent(l.EVENTS.removeItem,{id:t,value:i,label:n,customProperties:r,groupValue:a&&a.value?a.value:null}))},e.prototype._addChoice=function(e){var t=e.value,i=e.label,n=void 0===i?null:i,r=e.isSelected,o=void 0!==r&&r,s=e.isDisabled,a=void 0!==s&&s,c=e.groupId,l=void 0===c?-1:c,u=e.customProperties,d=void 0===u?{}:u,p=e.placeholder,f=void 0!==p&&p,m=e.keyCode,v=void 0===m?-1:m;if(null!=t){var _=this._store.choices,g=n||t,y=_?_.length+1:1,b=this._baseId+"-"+this._idNames.itemChoice+"-"+y;this._store.dispatch(h.addChoice({id:y,groupId:l,elementId:b,value:t,label:g,disabled:a,customProperties:d,placeholder:f,keyCode:v})),o&&this._addItem({value:t,label:g,choiceId:y,customProperties:d,placeholder:f,keyCode:v})}},e.prototype._addGroup=function(e){var t=this,i=e.group,n=e.id,r=e.valueKey,o=void 0===r?"value":r,s=e.labelKey,a=void 0===s?"label":s,c=m.isType("Object",i)?i.choices:Array.from(i.getElementsByTagName("OPTION")),l=n||Math.floor((new Date).valueOf()*Math.random()),u=!!i.disabled&&i.disabled;if(c){this._store.dispatch(p.addGroup({value:i.label,id:l,active:!0,disabled:u}));c.forEach((function(e){var i=e.disabled||e.parentNode&&e.parentNode.disabled;t._addChoice({value:e[o],label:m.isType("Object",e)?e[a]:e.innerHTML,isSelected:e.selected,isDisabled:i,groupId:l,customProperties:e.customProperties,placeholder:e.placeholder})}))}else this._store.dispatch(p.addGroup({value:i.label,id:i.id,active:!1,disabled:i.disabled}))},e.prototype._getTemplate=function(e){for(var t,i=[],r=1;r1&&void 0!==arguments[1]?arguments[1]:{limit:!1};this._log('---------\nSearch pattern: "'.concat(e,'"'));var i=this._prepareSearchers(e),n=i.tokenSearchers,s=i.fullSearcher,r=this._search(n,s),o=r.weights,a=r.results;return this._computeScore(o,a),this.options.shouldSort&&this._sort(a),t.limit&&"number"==typeof t.limit&&(a=a.slice(0,t.limit)),this._format(a)}},{key:"_prepareSearchers",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var i=e.split(this.options.tokenSeparator),n=0,s=i.length;n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,i=this.list,n={},s=[];if("string"==typeof i[0]){for(var r=0,o=i.length;r1)throw new Error("Key weight has to be > 0 and <= 1");p=p.name}else a[p]={weight:1};this._analyze({key:p,value:this.options.getFn(h,p),record:h,index:c},{resultMap:n,results:s,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:s}}},{key:"_analyze",value:function(e,t){var i=e.key,n=e.arrayIndex,s=void 0===n?-1:n,r=e.value,o=e.record,c=e.index,l=t.tokenSearchers,h=void 0===l?[]:l,u=t.fullSearcher,d=void 0===u?[]:u,p=t.resultMap,m=void 0===p?{}:p,f=t.results,v=void 0===f?[]:f;if(null!=r){var g=!1,_=-1,b=0;if("string"==typeof r){this._log("\nKey: ".concat(""===i?"-":i));var y=d.search(r);if(this._log('Full text: "'.concat(r,'", score: ').concat(y.score)),this.options.tokenize){for(var E=r.split(this.options.tokenSeparator),I=[],S=0;S-1&&(P=(P+_)/2),this._log("Score average:",P);var D=!this.options.tokenize||!this.options.matchAllTokens||b>=h.length;if(this._log("\nCheck Matches: ".concat(D)),(g||y.isMatch)&&D){var M=m[c];M?M.output.push({key:i,arrayIndex:s,value:r,score:P,matchedIndices:y.matchedIndices}):(m[c]={item:o,output:[{key:i,arrayIndex:s,value:r,score:P,matchedIndices:y.matchedIndices}]},v.push(m[c]))}}else if(a(r))for(var N=0,F=r.length;N-1&&(o.arrayIndex=r.arrayIndex),t.matches.push(o)}}})),this.options.includeScore&&s.push((function(e,t){t.score=e.score}));for(var r=0,o=e.length;ri)return s(e,this.pattern,n);var o=this.options,a=o.location,c=o.distance,l=o.threshold,h=o.findAllMatches,u=o.minMatchCharLength;return r(e,this.pattern,this.patternAlphabet,{location:a,distance:c,threshold:l,findAllMatches:h,minMatchCharLength:u})}}])&&n(t.prototype,i),e}();e.exports=a},function(e,t){var i=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:/ +/g,s=new RegExp(t.replace(i,"\\$&").replace(n,"|")),r=e.match(s),o=!!r,a=[];if(o)for(var c=0,l=r.length;c=P;N-=1){var F=N-1,j=i[e.charAt(F)];if(j&&(E[F]=1),M[N]=(M[N+1]<<1|1)&j,0!==T&&(M[N]|=(O[N+1]|O[N])<<1|1|O[N+1]),M[N]&L&&(C=n(t,{errors:T,currentLocation:F,expectedLocation:v,distance:l}))<=_){if(_=C,(b=F)<=v)break;P=Math.max(1,2*v-b)}}if(n(t,{errors:T+1,currentLocation:v,expectedLocation:v,distance:l})>_)break;O=M}return{isMatch:b>=0,score:0===C?.001:C,matchedIndices:s(E,f)}}},function(e,t){e.exports=function(e,t){var i=t.errors,n=void 0===i?0:i,s=t.currentLocation,r=void 0===s?0:s,o=t.expectedLocation,a=void 0===o?0:o,c=t.distance,l=void 0===c?100:c,h=n/e.length,u=Math.abs(a-r);return l?h+u/l:u?1:h}},function(e,t){e.exports=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=[],n=-1,s=-1,r=0,o=e.length;r=t&&i.push([n,s]),n=-1)}return e[r-1]&&r-n>=t&&i.push([n,r-1]),i}},function(e,t){e.exports=function(e){for(var t={},i=e.length,n=0;n/g,"&rt;").replace(/-1?e.map((function(e){var i=e;return i.id===parseInt(t.choiceId,10)&&(i.selected=!0),i})):e;case"REMOVE_ITEM":return t.choiceId>-1?e.map((function(e){var i=e;return i.id===parseInt(t.choiceId,10)&&(i.selected=!1),i})):e;case"FILTER_CHOICES":return e.map((function(e){var i=e;return i.active=t.results.some((function(e){var t=e.item,n=e.score;return t.id===i.id&&(i.score=n,!0)})),i}));case"ACTIVATE_CHOICES":return e.map((function(e){var i=e;return i.active=t.active,i}));case"CLEAR_CHOICES":return f;default:return e}},general:_}),T=function(e,t){var i=e;if("CLEAR_ALL"===t.type)i=void 0;else if("RESET_TO"===t.type)return C(t.state);return L(i,t)};function x(e,t){for(var i=0;i"'+S(e)+'"'},maxItemText:function(e){return"Only "+e+" values can be added"},valueComparer:function(e,t){return e===t},fuseOptions:{includeScore:!0},callbackOnInit:null,callbackOnCreateTemplates:null,classNames:{containerOuter:"choices",containerInner:"choices__inner",input:"choices__input",inputCloned:"choices__input--cloned",list:"choices__list",listItems:"choices__list--multiple",listSingle:"choices__list--single",listDropdown:"choices__list--dropdown",item:"choices__item",itemSelectable:"choices__item--selectable",itemDisabled:"choices__item--disabled",itemChoice:"choices__item--choice",placeholder:"choices__placeholder",group:"choices__group",groupHeading:"choices__heading",button:"choices__button",activeState:"is-active",focusState:"is-focused",openState:"is-open",disabledState:"is-disabled",highlightedState:"is-highlighted",selectedState:"is-selected",flippedState:"is-flipped",loadingState:"is-loading",noResults:"has-no-results",noChoices:"has-no-choices"}},N="showDropdown",F="hideDropdown",j="change",R="choice",H="search",K="addItem",B="removeItem",V="highlightItem",G="highlightChoice",q="ADD_CHOICE",U="FILTER_CHOICES",z="ACTIVATE_CHOICES",W="CLEAR_CHOICES",X="ADD_GROUP",$="ADD_ITEM",J="REMOVE_ITEM",Y="HIGHLIGHT_ITEM",Z=46,Q=8,ee=13,te=65,ie=27,ne=38,se=40,re=33,oe=34,ae="text",ce="select-one",le="select-multiple",he=function(){function e(e){var t=e.element,i=e.type,n=e.classNames,s=e.position;this.element=t,this.classNames=n,this.type=i,this.position=s,this.isOpen=!1,this.isFlipped=!1,this.isFocussed=!1,this.isDisabled=!1,this.isLoading=!1,this._onFocus=this._onFocus.bind(this),this._onBlur=this._onBlur.bind(this)}var t=e.prototype;return t.addEventListeners=function(){this.element.addEventListener("focus",this._onFocus),this.element.addEventListener("blur",this._onBlur)},t.removeEventListeners=function(){this.element.removeEventListener("focus",this._onFocus),this.element.removeEventListener("blur",this._onBlur)},t.shouldFlip=function(e){if("number"!=typeof e)return!1;var t=!1;return"auto"===this.position?t=!window.matchMedia("(min-height: "+(e+1)+"px)").matches:"top"===this.position&&(t=!0),t},t.setActiveDescendant=function(e){this.element.setAttribute("aria-activedescendant",e)},t.removeActiveDescendant=function(){this.element.removeAttribute("aria-activedescendant")},t.open=function(e){this.element.classList.add(this.classNames.openState),this.element.setAttribute("aria-expanded","true"),this.isOpen=!0,this.shouldFlip(e)&&(this.element.classList.add(this.classNames.flippedState),this.isFlipped=!0)},t.close=function(){this.element.classList.remove(this.classNames.openState),this.element.setAttribute("aria-expanded","false"),this.removeActiveDescendant(),this.isOpen=!1,this.isFlipped&&(this.element.classList.remove(this.classNames.flippedState),this.isFlipped=!1)},t.focus=function(){this.isFocussed||this.element.focus()},t.addFocusState=function(){this.element.classList.add(this.classNames.focusState)},t.removeFocusState=function(){this.element.classList.remove(this.classNames.focusState)},t.enable=function(){this.element.classList.remove(this.classNames.disabledState),this.element.removeAttribute("aria-disabled"),this.type===ce&&this.element.setAttribute("tabindex","0"),this.isDisabled=!1},t.disable=function(){this.element.classList.add(this.classNames.disabledState),this.element.setAttribute("aria-disabled","true"),this.type===ce&&this.element.setAttribute("tabindex","-1"),this.isDisabled=!0},t.wrap=function(e){!function(e,t){void 0===t&&(t=document.createElement("div")),e.nextSibling?e.parentNode.insertBefore(t,e.nextSibling):e.parentNode.appendChild(t),t.appendChild(e)}(e,this.element)},t.unwrap=function(e){this.element.parentNode.insertBefore(e,this.element),this.element.parentNode.removeChild(this.element)},t.addLoadingState=function(){this.element.classList.add(this.classNames.loadingState),this.element.setAttribute("aria-busy","true"),this.isLoading=!0},t.removeLoadingState=function(){this.element.classList.remove(this.classNames.loadingState),this.element.removeAttribute("aria-busy"),this.isLoading=!1},t._onFocus=function(){this.isFocussed=!0},t._onBlur=function(){this.isFocussed=!1},e}();function ue(e,t){for(var i=0;i0?this.element.scrollTop+o-s:e.offsetTop;requestAnimationFrame((function(){i._animateScroll(a,t)}))}},t._scrollDown=function(e,t,i){var n=(i-e)/t,s=n>1?n:1;this.element.scrollTop=e+s},t._scrollUp=function(e,t,i){var n=(e-i)/t,s=n>1?n:1;this.element.scrollTop=e-s},t._animateScroll=function(e,t){var i=this,n=this.element.scrollTop,s=!1;t>0?(this._scrollDown(n,4,e),ne&&(s=!0)),s&&requestAnimationFrame((function(){i._animateScroll(e,t)}))},e}();function me(e,t){for(var i=0;i0?"treeitem":"option"),Object.assign(g.dataset,{choice:"",id:l,value:h,selectText:i}),m?(g.classList.add(a),g.dataset.choiceDisabled="",g.setAttribute("aria-disabled","true")):(g.classList.add(r),g.dataset.choiceSelectable=""),g},input:function(e,t){var i=e.input,n=e.inputCloned,s=Object.assign(document.createElement("input"),{type:"text",className:i+" "+n,autocomplete:"off",autocapitalize:"off",spellcheck:!1});return s.setAttribute("role","textbox"),s.setAttribute("aria-autocomplete","list"),s.setAttribute("aria-label",t),s},dropdown:function(e){var t=e.list,i=e.listDropdown,n=document.createElement("div");return n.classList.add(t,i),n.setAttribute("aria-expanded","false"),n},notice:function(e,t,i){var n=e.item,s=e.itemChoice,r=e.noResults,o=e.noChoices;void 0===i&&(i="");var a=[n,s];return"no-choices"===i?a.push(o):"no-results"===i&&a.push(r),Object.assign(document.createElement("div"),{innerHTML:t,className:a.join(" ")})},option:function(e){var t=e.label,i=e.value,n=e.customProperties,s=e.active,r=e.disabled,o=new Option(t,i,!1,s);return n&&(o.dataset.customProperties=n),o.disabled=r,o}},Ee=function(e){return void 0===e&&(e=!0),{type:z,active:e}},Ie=function(e,t){return{type:Y,id:e,highlighted:t}},Se=function(e){var t=e.value,i=e.id,n=e.active,s=e.disabled;return{type:X,value:t,id:i,active:n,disabled:s}},we=function(e){return{type:"SET_IS_LOADING",isLoading:e}};function Oe(e,t){for(var i=0;i=0?this._store.getGroupById(s):null;return this._store.dispatch(Ie(i,!0)),t&&this.passedElement.triggerEvent(V,{id:i,value:o,label:c,groupValue:l&&l.value?l.value:null}),this},r.unhighlightItem=function(e){if(!e)return this;var t=e.id,i=e.groupId,n=void 0===i?-1:i,s=e.value,r=void 0===s?"":s,o=e.label,a=void 0===o?"":o,c=n>=0?this._store.getGroupById(n):null;return this._store.dispatch(Ie(t,!1)),this.passedElement.triggerEvent(V,{id:t,value:r,label:a,groupValue:c&&c.value?c.value:null}),this},r.highlightAll=function(){var e=this;return this._store.items.forEach((function(t){return e.highlightItem(t)})),this},r.unhighlightAll=function(){var e=this;return this._store.items.forEach((function(t){return e.unhighlightItem(t)})),this},r.removeActiveItemsByValue=function(e){var t=this;return this._store.activeItems.filter((function(t){return t.value===e})).forEach((function(e){return t._removeItem(e)})),this},r.removeActiveItems=function(e){var t=this;return this._store.activeItems.filter((function(t){return t.id!==e})).forEach((function(e){return t._removeItem(e)})),this},r.removeHighlightedItems=function(e){var t=this;return void 0===e&&(e=!1),this._store.highlightedActiveItems.forEach((function(i){t._removeItem(i),e&&t._triggerChange(i.value)})),this},r.showDropdown=function(e){var t=this;return this.dropdown.isActive?this:(requestAnimationFrame((function(){t.dropdown.show(),t.containerOuter.open(t.dropdown.distanceFromTopWindow),!e&&t._canSearch&&t.input.focus(),t.passedElement.triggerEvent(N,{})})),this)},r.hideDropdown=function(e){var t=this;return this.dropdown.isActive?(requestAnimationFrame((function(){t.dropdown.hide(),t.containerOuter.close(),!e&&t._canSearch&&(t.input.removeActiveDescendant(),t.input.blur()),t.passedElement.triggerEvent(F,{})})),this):this},r.getValue=function(e){void 0===e&&(e=!1);var t=this._store.activeItems.reduce((function(t,i){var n=e?i.value:i;return t.push(n),t}),[]);return this._isSelectOneElement?t[0]:t},r.setValue=function(e){var t=this;return this.initialised?(e.forEach((function(e){return t._setChoiceOrItem(e)})),this):this},r.setChoiceByValue=function(e){var t=this;return!this.initialised||this._isTextElement?this:((Array.isArray(e)?e:[e]).forEach((function(e){return t._findAndSelectChoiceByValue(e)})),this)},r.setChoices=function(e,t,i,n){var s=this;if(void 0===e&&(e=[]),void 0===t&&(t="value"),void 0===i&&(i="label"),void 0===n&&(n=!1),!this.initialised)throw new ReferenceError("setChoices was called on a non-initialized instance of Choices");if(!this._isSelectElement)throw new TypeError("setChoices can't be used with INPUT based Choices");if("string"!=typeof t||!t)throw new TypeError("value parameter must be a name of 'value' field in passed objects");if(n&&this.clearChoices(),"function"==typeof e){var r=e(this);if("function"==typeof Promise&&r instanceof Promise)return new Promise((function(e){return requestAnimationFrame(e)})).then((function(){return s._handleLoadingState(!0)})).then((function(){return r})).then((function(e){return s.setChoices(e,t,i,n)})).catch((function(e){s.config.silent||console.error(e)})).then((function(){return s._handleLoadingState(!1)})).then((function(){return s}));if(!Array.isArray(r))throw new TypeError(".setChoices first argument function must return either array of choices or Promise, got: "+typeof r);return this.setChoices(r,t,i,!1)}if(!Array.isArray(e))throw new TypeError(".setChoices must be called either with array of choices with a function resulting into Promise of array of choices");return this.containerOuter.removeLoadingState(),this._startLoading(),e.forEach((function(e){e.choices?s._addGroup({id:parseInt(e.id,10)||null,group:e,valueKey:t,labelKey:i}):s._addChoice({value:e[t],label:e[i],isSelected:e.selected,isDisabled:e.disabled,customProperties:e.customProperties,placeholder:e.placeholder})})),this._stopLoading(),this},r.clearChoices=function(){return this._store.dispatch({type:W}),this},r.clearStore=function(){return this._store.dispatch({type:"CLEAR_ALL"}),this},r.clearInput=function(){var e=!this._isSelectOneElement;return this.input.clear(e),!this._isTextElement&&this._canSearch&&(this._isSearching=!1,this._store.dispatch(Ee(!0))),this},r._render=function(){if(!this._store.isLoading()){this._currentState=this._store.state;var e=this._currentState.choices!==this._prevState.choices||this._currentState.groups!==this._prevState.groups||this._currentState.items!==this._prevState.items,t=this._isSelectElement,i=this._currentState.items!==this._prevState.items;e&&(t&&this._renderChoices(),i&&this._renderItems(),this._prevState=this._currentState)}},r._renderChoices=function(){var e=this,t=this._store,i=t.activeGroups,n=t.activeChoices,s=document.createDocumentFragment();if(this.choiceList.clear(),this.config.resetScrollPosition&&requestAnimationFrame((function(){return e.choiceList.scrollToTop()})),i.length>=1&&!this._isSearching){var r=n.filter((function(e){return!0===e.placeholder&&-1===e.groupId}));r.length>=1&&(s=this._createChoicesFragment(r,s)),s=this._createGroupsFragment(i,n,s)}else n.length>=1&&(s=this._createChoicesFragment(n,s));if(s.childNodes&&s.childNodes.length>0){var o=this._store.activeItems,a=this._canAddItem(o,this.input.value);a.response?(this.choiceList.append(s),this._highlightChoice()):this.choiceList.append(this._getTemplate("notice",a.notice))}else{var c,l;this._isSearching?(l="function"==typeof this.config.noResultsText?this.config.noResultsText():this.config.noResultsText,c=this._getTemplate("notice",l,"no-results")):(l="function"==typeof this.config.noChoicesText?this.config.noChoicesText():this.config.noChoicesText,c=this._getTemplate("notice",l,"no-choices")),this.choiceList.append(c)}},r._renderItems=function(){var e=this._store.activeItems||[];this.itemList.clear();var t=this._createItemsFragment(e);t.childNodes&&this.itemList.append(t)},r._createGroupsFragment=function(e,t,i){var n=this;void 0===i&&(i=document.createDocumentFragment());return this.config.shouldSort&&e.sort(this.config.sorter),e.forEach((function(e){var s=function(e){return t.filter((function(t){return n._isSelectOneElement?t.groupId===e.id:t.groupId===e.id&&("always"===n.config.renderSelectedChoices||!t.selected)}))}(e);if(s.length>=1){var r=n._getTemplate("choiceGroup",e);i.appendChild(r),n._createChoicesFragment(s,i,!0)}})),i},r._createChoicesFragment=function(e,t,i){var n=this;void 0===t&&(t=document.createDocumentFragment()),void 0===i&&(i=!1);var s=this.config,r=s.renderSelectedChoices,o=s.searchResultLimit,a=s.renderChoiceLimit,c=this._isSearching?O:this.config.sorter,l=function(e){if("auto"!==r||(n._isSelectOneElement||!e.selected)){var i=n._getTemplate("choice",e,n.config.itemSelectText);t.appendChild(i)}},h=e;"auto"!==r||this._isSelectOneElement||(h=e.filter((function(e){return!e.selected})));var u=h.reduce((function(e,t){return t.placeholder?e.placeholderChoices.push(t):e.normalChoices.push(t),e}),{placeholderChoices:[],normalChoices:[]}),d=u.placeholderChoices,p=u.normalChoices;(this.config.shouldSort||this._isSearching)&&p.sort(c);var m=h.length,f=this._isSelectOneElement?[].concat(d,p):p;this._isSearching?m=o:a&&a>0&&!i&&(m=a);for(var v=0;v=n){var o=s?this._searchChoices(e):0;this.passedElement.triggerEvent(H,{value:e,resultCount:o})}else r&&(this._isSearching=!1,this._store.dispatch(Ee(!0)))}},r._canAddItem=function(e,t){var i=!0,n="function"==typeof this.config.addItemText?this.config.addItemText(t):this.config.addItemText;if(!this._isSelectOneElement){var s=function(e,t,i){return void 0===i&&(i="value"),e.some((function(e){return"string"==typeof t?e[i]===t.trim():e[i]===t}))}(e,t);this.config.maxItemCount>0&&this.config.maxItemCount<=e.length&&(i=!1,n="function"==typeof this.config.maxItemText?this.config.maxItemText(this.config.maxItemCount):this.config.maxItemText),!this.config.duplicateItemsAllowed&&s&&i&&(i=!1,n="function"==typeof this.config.uniqueItemText?this.config.uniqueItemText(t):this.config.uniqueItemText),this._isTextElement&&this.config.addItems&&i&&"function"==typeof this.config.addItemFilter&&!this.config.addItemFilter(t)&&(i=!1,n="function"==typeof this.config.customAddItemText?this.config.customAddItemText(t):this.config.customAddItemText)}return{response:i,notice:n}},r._searchChoices=function(e){var t="string"==typeof e?e.trim():e,i="string"==typeof this._currentValue?this._currentValue.trim():this._currentValue;if(t.length<1&&t===i+" ")return 0;var n=this._store.searchableChoices,r=t,o=[].concat(this.config.searchFields),a=Object.assign(this.config.fuseOptions,{keys:o}),c=new s.a(n,a).search(r);return this._currentValue=t,this._highlightPosition=0,this._isSearching=!0,this._store.dispatch(function(e){return{type:U,results:e}}(c)),c.length},r._addEventListeners=function(){var e=document.documentElement;e.addEventListener("touchend",this._onTouchEnd,!0),this.containerOuter.element.addEventListener("keydown",this._onKeyDown,!0),this.containerOuter.element.addEventListener("mousedown",this._onMouseDown,!0),e.addEventListener("click",this._onClick,{passive:!0}),e.addEventListener("touchmove",this._onTouchMove,{passive:!0}),this.dropdown.element.addEventListener("mouseover",this._onMouseOver,{passive:!0}),this._isSelectOneElement&&(this.containerOuter.element.addEventListener("focus",this._onFocus,{passive:!0}),this.containerOuter.element.addEventListener("blur",this._onBlur,{passive:!0})),this.input.element.addEventListener("keyup",this._onKeyUp,{passive:!0}),this.input.element.addEventListener("focus",this._onFocus,{passive:!0}),this.input.element.addEventListener("blur",this._onBlur,{passive:!0}),this.input.element.form&&this.input.element.form.addEventListener("reset",this._onFormReset,{passive:!0}),this.input.addEventListeners()},r._removeEventListeners=function(){var e=document.documentElement;e.removeEventListener("touchend",this._onTouchEnd,!0),this.containerOuter.element.removeEventListener("keydown",this._onKeyDown,!0),this.containerOuter.element.removeEventListener("mousedown",this._onMouseDown,!0),e.removeEventListener("click",this._onClick),e.removeEventListener("touchmove",this._onTouchMove),this.dropdown.element.removeEventListener("mouseover",this._onMouseOver),this._isSelectOneElement&&(this.containerOuter.element.removeEventListener("focus",this._onFocus),this.containerOuter.element.removeEventListener("blur",this._onBlur)),this.input.element.removeEventListener("keyup",this._onKeyUp),this.input.element.removeEventListener("focus",this._onFocus),this.input.element.removeEventListener("blur",this._onBlur),this.input.element.form&&this.input.element.form.removeEventListener("reset",this._onFormReset),this.input.removeEventListeners()},r._onKeyDown=function(e){var t,i=e.keyCode,n=this._store.activeItems,s=this.input.isFocussed,r=this.dropdown.isActive,o=this.itemList.hasChildren(),a=String.fromCharCode(i),c=/[a-zA-Z0-9-_ ]/.test(a),l=Z,h=Q,u=ee,d=te,p=ie,m=ne,f=se,v=re,g=oe;this._isTextElement||r||!c||(this.showDropdown(),this.input.isFocussed||(this.input.value+=a.toLowerCase()));var _=((t={})[d]=this._onAKey,t[u]=this._onEnterKey,t[p]=this._onEscapeKey,t[m]=this._onDirectionKey,t[v]=this._onDirectionKey,t[f]=this._onDirectionKey,t[g]=this._onDirectionKey,t[h]=this._onDeleteKey,t[l]=this._onDeleteKey,t);_[i]&&_[i]({event:e,activeItems:n,hasFocusedInput:s,hasActiveDropdown:r,hasItems:o})},r._onKeyUp=function(e){var t=e.target,i=e.keyCode,n=this.input.value,s=this._store.activeItems,r=this._canAddItem(s,n),o=Z,a=Q;if(this._isTextElement){if(r.notice&&n){var c=this._getTemplate("notice",r.notice);this.dropdown.element.innerHTML=c.outerHTML,this.showDropdown(!0)}else this.hideDropdown(!0)}else{var l=(i===o||i===a)&&!t.value,h=!this._isTextElement&&this._isSearching,u=this._canSearch&&r.response;l&&h?(this._isSearching=!1,this._store.dispatch(Ee(!0))):u&&this._handleSearch(this.input.value)}this._canSearch=this.config.searchEnabled},r._onAKey=function(e){var t=e.event,i=e.hasItems,n=t.ctrlKey,s=t.metaKey;(n||s)&&i&&(this._canSearch=!1,this.config.removeItems&&!this.input.value&&this.input.element===document.activeElement&&this.highlightAll())},r._onEnterKey=function(e){var t=e.event,i=e.activeItems,n=e.hasActiveDropdown,s=t.target,r=ee,o=s.hasAttribute("data-button");if(this._isTextElement&&s.value){var a=this.input.value;this._canAddItem(i,a).response&&(this.hideDropdown(!0),this._addItem({value:a}),this._triggerChange(a),this.clearInput())}if(o&&(this._handleButtonAction(i,s),t.preventDefault()),n){var c=this.dropdown.getChild("."+this.config.classNames.highlightedState);c&&(i[0]&&(i[0].keyCode=r),this._handleChoiceAction(i,c)),t.preventDefault()}else this._isSelectOneElement&&(this.showDropdown(),t.preventDefault())},r._onEscapeKey=function(e){e.hasActiveDropdown&&(this.hideDropdown(!0),this.containerOuter.focus())},r._onDirectionKey=function(e){var t,i,n,s=e.event,r=e.hasActiveDropdown,o=s.keyCode,a=s.metaKey,c=se,l=re,h=oe;if(r||this._isSelectOneElement){this.showDropdown(),this._canSearch=!1;var u,d=o===c||o===h?1:-1;if(a||o===h||o===l)u=d>0?this.dropdown.element.querySelector("[data-choice-selectable]:last-of-type"):this.dropdown.element.querySelector("[data-choice-selectable]");else{var p=this.dropdown.element.querySelector("."+this.config.classNames.highlightedState);u=p?function(e,t,i){if(void 0===i&&(i=1),e instanceof Element&&"string"==typeof t){for(var n=(i>0?"next":"previous")+"ElementSibling",s=e[n];s;){if(s.matches(t))return s;s=s[n]}return s}}(p,"[data-choice-selectable]",d):this.dropdown.element.querySelector("[data-choice-selectable]")}u&&(t=u,i=this.choiceList.element,void 0===(n=d)&&(n=1),t&&(n>0?i.scrollTop+i.offsetHeight>=t.offsetTop+t.offsetHeight:t.offsetTop>=i.scrollTop)||this.choiceList.scrollToChildElement(u,d),this._highlightChoice(u)),s.preventDefault()}},r._onDeleteKey=function(e){var t=e.event,i=e.hasFocusedInput,n=e.activeItems,s=t.target;!i||s.value||this._isSelectOneElement||(this._handleBackspace(n),t.preventDefault())},r._onTouchMove=function(){this._wasTap&&(this._wasTap=!1)},r._onTouchEnd=function(e){var t=(e||e.touches[0]).target;this._wasTap&&this.containerOuter.element.contains(t)&&((t===this.containerOuter.element||t===this.containerInner.element)&&(this._isTextElement?this.input.focus():this._isSelectMultipleElement&&this.showDropdown()),e.stopPropagation());this._wasTap=!0},r._onMouseDown=function(e){var t=e.target;if(t instanceof HTMLElement){if(Ce&&this.choiceList.element.contains(t)){var i=this.choiceList.element.firstElementChild,n="ltr"===this._direction?e.offsetX>=i.offsetWidth:e.offsetX0&&this.unhighlightAll(),this.containerOuter.removeFocusState(),this.hideDropdown(!0))},r._onFocus=function(e){var t,i=this,n=e.target;this.containerOuter.element.contains(n)&&((t={})[ae]=function(){n===i.input.element&&i.containerOuter.addFocusState()},t[ce]=function(){i.containerOuter.addFocusState(),n===i.input.element&&i.showDropdown(!0)},t[le]=function(){n===i.input.element&&(i.showDropdown(!0),i.containerOuter.addFocusState())},t)[this.passedElement.element.type]()},r._onBlur=function(e){var t=this,i=e.target;if(this.containerOuter.element.contains(i)&&!this._isScrollingOnIe){var n,s=this._store.activeItems.some((function(e){return e.highlighted}));((n={})[ae]=function(){i===t.input.element&&(t.containerOuter.removeFocusState(),s&&t.unhighlightAll(),t.hideDropdown(!0))},n[ce]=function(){t.containerOuter.removeFocusState(),(i===t.input.element||i===t.containerOuter.element&&!t._canSearch)&&t.hideDropdown(!0)},n[le]=function(){i===t.input.element&&(t.containerOuter.removeFocusState(),t.hideDropdown(!0),s&&t.unhighlightAll())},n)[this.passedElement.element.type]()}else this._isScrollingOnIe=!1,this.input.element.focus()},r._onFormReset=function(){this._store.dispatch({type:"RESET_TO",state:this._initialState})},r._highlightChoice=function(e){var t=this;void 0===e&&(e=null);var i=Array.from(this.dropdown.element.querySelectorAll("[data-choice-selectable]"));if(i.length){var n=e;Array.from(this.dropdown.element.querySelectorAll("."+this.config.classNames.highlightedState)).forEach((function(e){e.classList.remove(t.config.classNames.highlightedState),e.setAttribute("aria-selected","false")})),n?this._highlightPosition=i.indexOf(n):(n=i.length>this._highlightPosition?i[this._highlightPosition]:i[i.length-1])||(n=i[0]),n.classList.add(this.config.classNames.highlightedState),n.setAttribute("aria-selected","true"),this.passedElement.triggerEvent(G,{el:n}),this.dropdown.isActive&&(this.input.setActiveDescendant(n.id),this.containerOuter.setActiveDescendant(n.id))}},r._addItem=function(e){var t=e.value,i=e.label,n=void 0===i?null:i,s=e.choiceId,r=void 0===s?-1:s,o=e.groupId,a=void 0===o?-1:o,c=e.customProperties,l=void 0===c?null:c,h=e.placeholder,u=void 0!==h&&h,d=e.keyCode,p=void 0===d?null:d,m="string"==typeof t?t.trim():t,f=p,v=l,g=this._store.items,_=n||m,b=r||-1,y=a>=0?this._store.getGroupById(a):null,E=g?g.length+1:1;return this.config.prependValue&&(m=this.config.prependValue+m.toString()),this.config.appendValue&&(m+=this.config.appendValue.toString()),this._store.dispatch(function(e){var t=e.value,i=e.label,n=e.id,s=e.choiceId,r=e.groupId,o=e.customProperties,a=e.placeholder,c=e.keyCode;return{type:$,value:t,label:i,id:n,choiceId:s,groupId:r,customProperties:o,placeholder:a,keyCode:c}}({value:m,label:_,id:E,choiceId:b,groupId:a,customProperties:l,placeholder:u,keyCode:f})),this._isSelectOneElement&&this.removeActiveItems(E),this.passedElement.triggerEvent(K,{id:E,value:m,label:_,customProperties:v,groupValue:y&&y.value?y.value:void 0,keyCode:f}),this},r._removeItem=function(e){if(!e||!I("Object",e))return this;var t=e.id,i=e.value,n=e.label,s=e.choiceId,r=e.groupId,o=r>=0?this._store.getGroupById(r):null;return this._store.dispatch(function(e,t){return{type:J,id:e,choiceId:t}}(t,s)),o&&o.value?this.passedElement.triggerEvent(B,{id:t,value:i,label:n,groupValue:o.value}):this.passedElement.triggerEvent(B,{id:t,value:i,label:n}),this},r._addChoice=function(e){var t=e.value,i=e.label,n=void 0===i?null:i,s=e.isSelected,r=void 0!==s&&s,o=e.isDisabled,a=void 0!==o&&o,c=e.groupId,l=void 0===c?-1:c,h=e.customProperties,u=void 0===h?null:h,d=e.placeholder,p=void 0!==d&&d,m=e.keyCode,f=void 0===m?null:m;if(null!=t){var v=this._store.choices,g=n||t,_=v?v.length+1:1,b=this._baseId+"-"+this._idNames.itemChoice+"-"+_;this._store.dispatch(function(e){var t=e.value,i=e.label,n=e.id,s=e.groupId,r=e.disabled,o=e.elementId,a=e.customProperties,c=e.placeholder,l=e.keyCode;return{type:q,value:t,label:i,id:n,groupId:s,disabled:r,elementId:o,customProperties:a,placeholder:c,keyCode:l}}({id:_,groupId:l,elementId:b,value:t,label:g,disabled:a,customProperties:u,placeholder:p,keyCode:f})),r&&this._addItem({value:t,label:g,choiceId:_,customProperties:u,placeholder:p,keyCode:f})}},r._addGroup=function(e){var t=this,i=e.group,n=e.id,s=e.valueKey,r=void 0===s?"value":s,o=e.labelKey,a=void 0===o?"label":o,c=I("Object",i)?i.choices:Array.from(i.getElementsByTagName("OPTION")),l=n||Math.floor((new Date).valueOf()*Math.random()),h=!!i.disabled&&i.disabled;if(c){this._store.dispatch(Se({value:i.label,id:l,active:!0,disabled:h}));c.forEach((function(e){var i=e.disabled||e.parentNode&&e.parentNode.disabled;t._addChoice({value:e[r],label:I("Object",e)?e[a]:e.innerHTML,isSelected:e.selected,isDisabled:i,groupId:l,customProperties:e.customProperties,placeholder:e.placeholder})}))}else this._store.dispatch(Se({value:i.label,id:i.id,active:!1,disabled:i.disabled}))},r._getTemplate=function(e){var t;if(!e)return null;for(var i=this.config.classNames,n=arguments.length,s=new Array(n>1?n-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:{limit:!1};this._log('---------\nSearch pattern: "'.concat(e,'"'));var i=this._prepareSearchers(e),n=i.tokenSearchers,r=i.fullSearcher,o=this._search(n,r),s=o.weights,a=o.results;return this._computeScore(s,a),this.options.shouldSort&&this._sort(a),t.limit&&"number"==typeof t.limit&&(a=a.slice(0,t.limit)),this._format(a)}},{key:"_prepareSearchers",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var i=e.split(this.options.tokenSeparator),n=0,r=i.length;n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,i=this.list,n={},r=[];if("string"==typeof i[0]){for(var o=0,s=i.length;o1)throw new Error("Key weight has to be > 0 and <= 1");p=p.name}else a[p]={weight:1};this._analyze({key:p,value:this.options.getFn(u,p),record:u,index:c},{resultMap:n,results:r,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:r}}},{key:"_analyze",value:function(e,t){var i=e.key,n=e.arrayIndex,r=void 0===n?-1:n,o=e.value,s=e.record,c=e.index,l=t.tokenSearchers,u=void 0===l?[]:l,h=t.fullSearcher,d=void 0===h?[]:h,p=t.resultMap,f=void 0===p?{}:p,m=t.results,v=void 0===m?[]:m;if(null!=o){var _=!1,g=-1,y=0;if("string"==typeof o){this._log("\nKey: ".concat(""===i?"-":i));var b=d.search(o);if(this._log('Full text: "'.concat(o,'", score: ').concat(b.score)),this.options.tokenize){for(var E=o.split(this.options.tokenSeparator),S=[],I=0;I-1&&(x=(x+g)/2),this._log("Score average:",x);var N=!this.options.tokenize||!this.options.matchAllTokens||y>=u.length;if(this._log("\nCheck Matches: ".concat(N)),(_||b.isMatch)&&N){var M=f[c];M?M.output.push({key:i,arrayIndex:r,value:o,score:x,matchedIndices:b.matchedIndices}):(f[c]={item:s,output:[{key:i,arrayIndex:r,value:o,score:x,matchedIndices:b.matchedIndices}]},v.push(f[c]))}}else if(a(o))for(var j=0,k=o.length;j-1&&(s.arrayIndex=o.arrayIndex),t.matches.push(s)}}})),this.options.includeScore&&r.push((function(e,t){t.score=e.score}));for(var o=0,s=e.length;oi)return r(e,this.pattern,n);var s=this.options,a=s.location,c=s.distance,l=s.threshold,u=s.findAllMatches,h=s.minMatchCharLength;return o(e,this.pattern,this.patternAlphabet,{location:a,distance:c,threshold:l,findAllMatches:u,minMatchCharLength:h})}}])&&n(t.prototype,i),e}();e.exports=a},function(e,t){var i=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:/ +/g,r=new RegExp(t.replace(i,"\\$&").replace(n,"|")),o=e.match(r),s=!!o,a=[];if(s)for(var c=0,l=o.length;c=x;j-=1){var k=j-1,F=i[e.charAt(k)];if(F&&(E[k]=1),M[j]=(M[j+1]<<1|1)&F,0!==L&&(M[j]|=(C[j+1]|C[j])<<1|1|C[j+1]),M[j]&A&&(T=n(t,{errors:L,currentLocation:k,expectedLocation:v,distance:l}))<=g){if(g=T,(y=k)<=v)break;x=Math.max(1,2*v-y)}}if(n(t,{errors:L+1,currentLocation:v,expectedLocation:v,distance:l})>g)break;C=M}return{isMatch:y>=0,score:0===T?.001:T,matchedIndices:r(E,m)}}},function(e,t){e.exports=function(e,t){var i=t.errors,n=void 0===i?0:i,r=t.currentLocation,o=void 0===r?0:r,s=t.expectedLocation,a=void 0===s?0:s,c=t.distance,l=void 0===c?100:c,u=n/e.length,h=Math.abs(a-o);return l?u+h/l:h?1:u}},function(e,t){e.exports=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=[],n=-1,r=-1,o=0,s=e.length;o=t&&i.push([n,r]),n=-1)}return e[o-1]&&o-n>=t&&i.push([n,o-1]),i}},function(e,t){e.exports=function(e){for(var t={},i=e.length,n=0;n-1?e.map((function(e){var t=e;return t.id===parseInt(""+s.choiceId,10)&&(t.selected=!0),t})):e;case"REMOVE_ITEM":var a=i;return a.choiceId&&a.choiceId>-1?e.map((function(e){var t=e;return t.id===parseInt(""+a.choiceId,10)&&(t.selected=!1),t})):e;case"FILTER_CHOICES":var c=i;return e.map((function(e){var t=e;return t.active=c.results.some((function(e){var i=e.item,n=e.score;return i.id===t.id&&(t.score=n,!0)})),t}));case"ACTIVATE_CHOICES":var l=i;return e.map((function(e){var t=e;return t.active=l.active,t}));case"CLEAR_CHOICES":return t.defaultState;default:return e}}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultState=!1;t.default=function(e,i){switch(void 0===e&&(e=t.defaultState),i.type){case"SET_IS_LOADING":return i.isLoading;default:return e}}},function(e,t,i){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var r=n(i(19));t.Dropdown=r.default;var o=n(i(20));t.Container=o.default;var s=n(i(21));t.Input=s.default;var a=n(i(22));t.List=a.default;var c=n(i(23));t.WrappedInput=c.default;var l=n(i(24));t.WrappedSelect=l.default},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e){var t=e.element,i=e.type,n=e.classNames;this.element=t,this.classNames=n,this.type=i,this.isActive=!1}return Object.defineProperty(e.prototype,"distanceFromTopWindow",{get:function(){return this.element.getBoundingClientRect().bottom},enumerable:!0,configurable:!0}),e.prototype.getChild=function(e){return this.element.querySelector(e)},e.prototype.show=function(){return this.element.classList.add(this.classNames.activeState),this.element.setAttribute("aria-expanded","true"),this.isActive=!0,this},e.prototype.hide=function(){return this.element.classList.remove(this.classNames.activeState),this.element.setAttribute("aria-expanded","false"),this.isActive=!1,this},e}();t.default=n},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(1),r=i(0),o=function(){function e(e){var t=e.element,i=e.type,n=e.classNames,r=e.position;this.element=t,this.classNames=n,this.type=i,this.position=r,this.isOpen=!1,this.isFlipped=!1,this.isFocussed=!1,this.isDisabled=!1,this.isLoading=!1,this._onFocus=this._onFocus.bind(this),this._onBlur=this._onBlur.bind(this)}return e.prototype.addEventListeners=function(){this.element.addEventListener("focus",this._onFocus),this.element.addEventListener("blur",this._onBlur)},e.prototype.removeEventListeners=function(){this.element.removeEventListener("focus",this._onFocus),this.element.removeEventListener("blur",this._onBlur)},e.prototype.shouldFlip=function(e){if("number"!=typeof e)return!1;var t=!1;return"auto"===this.position?t=!window.matchMedia("(min-height: "+(e+1)+"px)").matches:"top"===this.position&&(t=!0),t},e.prototype.setActiveDescendant=function(e){this.element.setAttribute("aria-activedescendant",e)},e.prototype.removeActiveDescendant=function(){this.element.removeAttribute("aria-activedescendant")},e.prototype.open=function(e){this.element.classList.add(this.classNames.openState),this.element.setAttribute("aria-expanded","true"),this.isOpen=!0,this.shouldFlip(e)&&(this.element.classList.add(this.classNames.flippedState),this.isFlipped=!0)},e.prototype.close=function(){this.element.classList.remove(this.classNames.openState),this.element.setAttribute("aria-expanded","false"),this.removeActiveDescendant(),this.isOpen=!1,this.isFlipped&&(this.element.classList.remove(this.classNames.flippedState),this.isFlipped=!1)},e.prototype.focus=function(){this.isFocussed||this.element.focus()},e.prototype.addFocusState=function(){this.element.classList.add(this.classNames.focusState)},e.prototype.removeFocusState=function(){this.element.classList.remove(this.classNames.focusState)},e.prototype.enable=function(){this.element.classList.remove(this.classNames.disabledState),this.element.removeAttribute("aria-disabled"),this.type===r.SELECT_ONE_TYPE&&this.element.setAttribute("tabindex","0"),this.isDisabled=!1},e.prototype.disable=function(){this.element.classList.add(this.classNames.disabledState),this.element.setAttribute("aria-disabled","true"),this.type===r.SELECT_ONE_TYPE&&this.element.setAttribute("tabindex","-1"),this.isDisabled=!0},e.prototype.wrap=function(e){n.wrap(e,this.element)},e.prototype.unwrap=function(e){this.element.parentNode&&(this.element.parentNode.insertBefore(e,this.element),this.element.parentNode.removeChild(this.element))},e.prototype.addLoadingState=function(){this.element.classList.add(this.classNames.loadingState),this.element.setAttribute("aria-busy","true"),this.isLoading=!0},e.prototype.removeLoadingState=function(){this.element.classList.remove(this.classNames.loadingState),this.element.removeAttribute("aria-busy"),this.isLoading=!1},e.prototype._onFocus=function(){this.isFocussed=!0},e.prototype._onBlur=function(){this.isFocussed=!1},e}();t.default=o},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(1),r=i(0),o=function(){function e(e){var t=e.element,i=e.type,n=e.classNames,r=e.preventPaste;this.element=t,this.type=i,this.classNames=n,this.preventPaste=r,this.isFocussed=this.element.isEqualNode(document.activeElement),this.isDisabled=t.disabled,this._onPaste=this._onPaste.bind(this),this._onInput=this._onInput.bind(this),this._onFocus=this._onFocus.bind(this),this._onBlur=this._onBlur.bind(this)}return Object.defineProperty(e.prototype,"placeholder",{set:function(e){this.element.placeholder=e},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"value",{get:function(){return n.sanitise(this.element.value)},set:function(e){this.element.value=e},enumerable:!0,configurable:!0}),e.prototype.addEventListeners=function(){this.element.addEventListener("paste",this._onPaste),this.element.addEventListener("input",this._onInput,{passive:!0}),this.element.addEventListener("focus",this._onFocus,{passive:!0}),this.element.addEventListener("blur",this._onBlur,{passive:!0})},e.prototype.removeEventListeners=function(){this.element.removeEventListener("input",this._onInput),this.element.removeEventListener("paste",this._onPaste),this.element.removeEventListener("focus",this._onFocus),this.element.removeEventListener("blur",this._onBlur)},e.prototype.enable=function(){this.element.removeAttribute("disabled"),this.isDisabled=!1},e.prototype.disable=function(){this.element.setAttribute("disabled",""),this.isDisabled=!0},e.prototype.focus=function(){this.isFocussed||this.element.focus()},e.prototype.blur=function(){this.isFocussed&&this.element.blur()},e.prototype.clear=function(e){return void 0===e&&(e=!0),this.element.value&&(this.element.value=""),e&&this.setWidth(),this},e.prototype.setWidth=function(){var e=this.element,t=e.style,i=e.value,n=e.placeholder;t.minWidth=n.length+1+"ch",t.width=i.length+1+"ch"},e.prototype.setActiveDescendant=function(e){this.element.setAttribute("aria-activedescendant",e)},e.prototype.removeActiveDescendant=function(){this.element.removeAttribute("aria-activedescendant")},e.prototype._onInput=function(){this.type!==r.SELECT_ONE_TYPE&&this.setWidth()},e.prototype._onPaste=function(e){this.preventPaste&&e.preventDefault()},e.prototype._onFocus=function(){this.isFocussed=!0},e.prototype._onBlur=function(){this.isFocussed=!1},e}();t.default=o},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(0),r=function(){function e(e){var t=e.element;this.element=t,this.scrollPos=this.element.scrollTop,this.height=this.element.offsetHeight}return e.prototype.clear=function(){this.element.innerHTML=""},e.prototype.append=function(e){this.element.appendChild(e)},e.prototype.getChild=function(e){return this.element.querySelector(e)},e.prototype.hasChildren=function(){return this.element.hasChildNodes()},e.prototype.scrollToTop=function(){this.element.scrollTop=0},e.prototype.scrollToChildElement=function(e,t){var i=this;if(e){var n=this.element.offsetHeight,r=this.element.scrollTop+n,o=e.offsetHeight,s=e.offsetTop+o,a=t>0?this.element.scrollTop+s-r:e.offsetTop;requestAnimationFrame((function(){i._animateScroll(a,t)}))}},e.prototype._scrollDown=function(e,t,i){var n=(i-e)/t,r=n>1?n:1;this.element.scrollTop=e+r},e.prototype._scrollUp=function(e,t,i){var n=(e-i)/t,r=n>1?n:1;this.element.scrollTop=e-r},e.prototype._animateScroll=function(e,t){var i=this,r=n.SCROLLING_SPEED,o=this.element.scrollTop,s=!1;t>0?(this._scrollDown(o,r,e),oe&&(s=!0)),s&&requestAnimationFrame((function(){i._animateScroll(e,t)}))},e}();t.default=r},function(e,t,i){"use strict";var n,r=this&&this.__extends||(n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var i in t)t.hasOwnProperty(i)&&(e[i]=t[i])})(e,t)},function(e,t){function i(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(i.prototype=t.prototype,new i)}),o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(t){var i=t.element,n=t.classNames,r=t.delimiter,o=e.call(this,{element:i,classNames:n})||this;return o.delimiter=r,o}return r(t,e),Object.defineProperty(t.prototype,"value",{get:function(){return this.element.value},set:function(e){this.element.setAttribute("value",e),this.element.value=e},enumerable:!0,configurable:!0}),t}(o(i(5)).default);t.default=s},function(e,t,i){"use strict";var n,r=this&&this.__extends||(n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var i in t)t.hasOwnProperty(i)&&(e[i]=t[i])})(e,t)},function(e,t){function i(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(i.prototype=t.prototype,new i)}),o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(t){var i=t.element,n=t.classNames,r=t.template,o=e.call(this,{element:i,classNames:n})||this;return o.template=r,o}return r(t,e),Object.defineProperty(t.prototype,"placeholderOption",{get:function(){return this.element.querySelector('option[value=""]')||this.element.querySelector("option[placeholder]")},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"optionGroups",{get:function(){return Array.from(this.element.getElementsByTagName("OPTGROUP"))},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"options",{get:function(){return Array.from(this.element.options)},set:function(e){var t=this,i=document.createDocumentFragment();e.forEach((function(e){return n=e,r=t.template(n),void i.appendChild(r);var n,r})),this.appendDocFragment(i)},enumerable:!0,configurable:!0}),t.prototype.appendDocFragment=function(e){this.element.innerHTML="",this.element.appendChild(e)},t}(o(i(5)).default);t.default=s},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n={containerOuter:function(e,t,i,n,r,o){var s=e.containerOuter,a=Object.assign(document.createElement("div"),{className:s});return a.dataset.type=o,t&&(a.dir=t),n&&(a.tabIndex=0),i&&(a.setAttribute("role",r?"combobox":"listbox"),r&&a.setAttribute("aria-autocomplete","list")),a.setAttribute("aria-haspopup","true"),a.setAttribute("aria-expanded","false"),a},containerInner:function(e){var t=e.containerInner;return Object.assign(document.createElement("div"),{className:t})},itemList:function(e,t){var i=e.list,n=e.listSingle,r=e.listItems;return Object.assign(document.createElement("div"),{className:i+" "+(t?n:r)})},placeholder:function(e,t){var i=e.placeholder;return Object.assign(document.createElement("div"),{className:i,innerHTML:t})},item:function(e,t,i){var n=e.item,r=e.button,o=e.highlightedState,s=e.itemSelectable,a=e.placeholder,c=t.id,l=t.value,u=t.label,h=t.customProperties,d=t.active,p=t.disabled,f=t.highlighted,m=t.placeholder,v=Object.assign(document.createElement("div"),{className:n,innerHTML:u});if(Object.assign(v.dataset,{item:"",id:c,value:l,customProperties:h}),d&&v.setAttribute("aria-selected","true"),p&&v.setAttribute("aria-disabled","true"),m&&v.classList.add(a),v.classList.add(f?o:s),i){p&&v.classList.remove(s),v.dataset.deletable="";var _=Object.assign(document.createElement("button"),{type:"button",className:r,innerHTML:"Remove item"});_.setAttribute("aria-label","Remove item: '"+l+"'"),_.dataset.button="",v.appendChild(_)}return v},choiceList:function(e,t){var i=e.list,n=Object.assign(document.createElement("div"),{className:i});return t||n.setAttribute("aria-multiselectable","true"),n.setAttribute("role","listbox"),n},choiceGroup:function(e,t){var i=e.group,n=e.groupHeading,r=e.itemDisabled,o=t.id,s=t.value,a=t.disabled,c=Object.assign(document.createElement("div"),{className:i+" "+(a?r:"")});return c.setAttribute("role","group"),Object.assign(c.dataset,{group:"",id:o,value:s}),a&&c.setAttribute("aria-disabled","true"),c.appendChild(Object.assign(document.createElement("div"),{className:n,innerHTML:s})),c},choice:function(e,t,i){var n=e.item,r=e.itemChoice,o=e.itemSelectable,s=e.selectedState,a=e.itemDisabled,c=e.placeholder,l=t.id,u=t.value,h=t.label,d=t.groupId,p=t.elementId,f=t.disabled,m=t.selected,v=t.placeholder,_=Object.assign(document.createElement("div"),{id:p,innerHTML:h,className:n+" "+r});return m&&_.classList.add(s),v&&_.classList.add(c),_.setAttribute("role",d&&d>0?"treeitem":"option"),Object.assign(_.dataset,{choice:"",id:l,value:u,selectText:i}),f?(_.classList.add(a),_.dataset.choiceDisabled="",_.setAttribute("aria-disabled","true")):(_.classList.add(o),_.dataset.choiceSelectable=""),_},input:function(e,t){var i=e.input,n=e.inputCloned,r=Object.assign(document.createElement("input"),{type:"text",className:i+" "+n,autocomplete:"off",autocapitalize:"off",spellcheck:!1});return r.setAttribute("role","textbox"),r.setAttribute("aria-autocomplete","list"),r.setAttribute("aria-label",t),r},dropdown:function(e){var t=e.list,i=e.listDropdown,n=document.createElement("div");return n.classList.add(t,i),n.setAttribute("aria-expanded","false"),n},notice:function(e,t,i){var n=e.item,r=e.itemChoice,o=e.noResults,s=e.noChoices;void 0===i&&(i="");var a=[n,r];return"no-choices"===i?a.push(s):"no-results"===i&&a.push(o),Object.assign(document.createElement("div"),{innerHTML:t,className:a.join(" ")})},option:function(e){var t=e.label,i=e.value,n=e.customProperties,r=e.active,o=e.disabled,s=new Option(t,i,!1,r);return n&&(s.dataset.customProperties=""+n),s.disabled=!!o,s}};t.default=n},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(0);t.addChoice=function(e){var t=e.value,i=e.label,r=e.id,o=e.groupId,s=e.disabled,a=e.elementId,c=e.customProperties,l=e.placeholder,u=e.keyCode;return{type:n.ACTION_TYPES.ADD_CHOICE,value:t,label:i,id:r,groupId:o,disabled:s,elementId:a,customProperties:c,placeholder:l,keyCode:u}},t.filterChoices=function(e){return{type:n.ACTION_TYPES.FILTER_CHOICES,results:e}},t.activateChoices=function(e){return void 0===e&&(e=!0),{type:n.ACTION_TYPES.ACTIVATE_CHOICES,active:e}},t.clearChoices=function(){return{type:n.ACTION_TYPES.CLEAR_CHOICES}}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(0);t.addItem=function(e){var t=e.value,i=e.label,r=e.id,o=e.choiceId,s=e.groupId,a=e.customProperties,c=e.placeholder,l=e.keyCode;return{type:n.ACTION_TYPES.ADD_ITEM,value:t,label:i,id:r,choiceId:o,groupId:s,customProperties:a,placeholder:c,keyCode:l}},t.removeItem=function(e,t){return{type:n.ACTION_TYPES.REMOVE_ITEM,id:e,choiceId:t}},t.highlightItem=function(e,t){return{type:n.ACTION_TYPES.HIGHLIGHT_ITEM,id:e,highlighted:t}}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(0);t.addGroup=function(e){var t=e.value,i=e.id,r=e.active,o=e.disabled;return{type:n.ACTION_TYPES.ADD_GROUP,value:t,id:i,active:r,disabled:o}}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=i(0);t.clearAll=function(){return{type:n.ACTION_TYPES.CLEAR_ALL}},t.resetTo=function(e){return{type:n.ACTION_TYPES.RESET_TO,state:e}},t.setIsLoading=function(e){return{type:n.ACTION_TYPES.SET_IS_LOADING,isLoading:e}}}]).default; \ No newline at end of file diff --git a/public/test/select-multiple/index.html b/public/test/select-multiple/index.html index c97eeca..113fe48 100644 --- a/public/test/select-multiple/index.html +++ b/public/test/select-multiple/index.html @@ -43,18 +43,12 @@ - + - - + + diff --git a/public/test/select-one/index.html b/public/test/select-one/index.html index b567b28..e54b391 100644 --- a/public/test/select-one/index.html +++ b/public/test/select-one/index.html @@ -43,18 +43,12 @@ - + - - + + diff --git a/public/test/text/index.html b/public/test/text/index.html index cb86435..1fc30d4 100644 --- a/public/test/text/index.html +++ b/public/test/text/index.html @@ -43,18 +43,12 @@ - + - - + + diff --git a/src/scripts/actions/choices.js b/src/scripts/actions/choices.js deleted file mode 100644 index ad22b29..0000000 --- a/src/scripts/actions/choices.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @typedef {import('redux').Action} Action - * @typedef {import('../../../types/index').Choices.Choice} Choice - */ - -import { ACTION_TYPES } from '../constants'; - -/** - * @argument {Choice} choice - * @returns {Action & Choice} - */ -export const addChoice = ({ - value, - label, - id, - groupId, - disabled, - elementId, - customProperties, - placeholder, - keyCode, -}) => ({ - type: ACTION_TYPES.ADD_CHOICE, - value, - label, - id, - groupId, - disabled, - elementId, - customProperties, - placeholder, - keyCode, -}); - -/** - * @argument {Choice[]} results - * @returns {Action & { results: Choice[] }} - */ -export const filterChoices = results => ({ - type: ACTION_TYPES.FILTER_CHOICES, - results, -}); - -/** - * @argument {boolean} active - * @returns {Action & { active: boolean }} - */ -export const activateChoices = (active = true) => ({ - type: ACTION_TYPES.ACTIVATE_CHOICES, - active, -}); - -/** - * @returns {Action} - */ -export const clearChoices = () => ({ - type: ACTION_TYPES.CLEAR_CHOICES, -}); diff --git a/src/scripts/actions/choices.test.js b/src/scripts/actions/choices.test.ts similarity index 80% rename from src/scripts/actions/choices.test.js rename to src/scripts/actions/choices.test.ts index aedb0fd..d023b25 100644 --- a/src/scripts/actions/choices.test.js +++ b/src/scripts/actions/choices.test.ts @@ -6,15 +6,15 @@ describe('actions/choices', () => { it('returns ADD_CHOICE action', () => { const value = 'test'; const label = 'test'; - const id = 'test'; - const groupId = 'test'; + const id = 1; + const groupId = 1; const disabled = false; - const elementId = 'test'; - const customProperties = 'test'; - const placeholder = 'test'; + const elementId = 1; + const customProperties = { test: true }; + const placeholder = true; const keyCode = 10; - const expectedAction = { + const expectedAction: actions.AddChoiceAction = { type: 'ADD_CHOICE', value, label, @@ -46,7 +46,7 @@ describe('actions/choices', () => { describe('filterChoices action', () => { it('returns FILTER_CHOICES action', () => { const results = Array(10); - const expectedAction = { + const expectedAction: actions.FilterChoicesAction = { type: 'FILTER_CHOICES', results, }; @@ -58,7 +58,7 @@ describe('actions/choices', () => { describe('activateChoices action', () => { describe('not passing active parameter', () => { it('returns ACTIVATE_CHOICES action', () => { - const expectedAction = { + const expectedAction: actions.ActivateChoicesAction = { type: 'ACTIVATE_CHOICES', active: true, }; @@ -70,7 +70,7 @@ describe('actions/choices', () => { describe('passing active parameter', () => { it('returns ACTIVATE_CHOICES action', () => { const active = true; - const expectedAction = { + const expectedAction: actions.ActivateChoicesAction = { type: 'ACTIVATE_CHOICES', active, }; @@ -82,7 +82,7 @@ describe('actions/choices', () => { describe('clearChoices action', () => { it('returns CLEAR_CHOICES action', () => { - const expectedAction = { + const expectedAction: actions.ClearChoicesAction = { type: 'CLEAR_CHOICES', }; diff --git a/src/scripts/actions/choices.ts b/src/scripts/actions/choices.ts new file mode 100644 index 0000000..526f4d4 --- /dev/null +++ b/src/scripts/actions/choices.ts @@ -0,0 +1,73 @@ +import { ACTION_TYPES } from '../constants'; +import { Choice } from '../interfaces'; + +export interface AddChoiceAction { + type: typeof ACTION_TYPES.ADD_CHOICE; + id: number; + value: string; + label: string; + groupId: number; + disabled: boolean; + elementId: number; + customProperties: object; + placeholder: boolean; + keyCode: number; +} + +export interface Result { + item: T; + score: number; +} + +export interface FilterChoicesAction { + type: typeof ACTION_TYPES.FILTER_CHOICES; + results: Result[]; +} + +export interface ActivateChoicesAction { + type: typeof ACTION_TYPES.ACTIVATE_CHOICES; + active: boolean; +} + +export interface ClearChoicesAction { + type: typeof ACTION_TYPES.CLEAR_CHOICES; +} + +export const addChoice = ({ + value, + label, + id, + groupId, + disabled, + elementId, + customProperties, + placeholder, + keyCode, +}): AddChoiceAction => ({ + type: ACTION_TYPES.ADD_CHOICE, + value, + label, + id, + groupId, + disabled, + elementId, + customProperties, + placeholder, + keyCode, +}); + +export const filterChoices = ( + results: Result[], +): FilterChoicesAction => ({ + type: ACTION_TYPES.FILTER_CHOICES, + results, +}); + +export const activateChoices = (active = true): ActivateChoicesAction => ({ + type: ACTION_TYPES.ACTIVATE_CHOICES, + active, +}); + +export const clearChoices = (): ClearChoicesAction => ({ + type: ACTION_TYPES.CLEAR_CHOICES, +}); diff --git a/src/scripts/actions/groups.js b/src/scripts/actions/groups.js deleted file mode 100644 index 41ac60c..0000000 --- a/src/scripts/actions/groups.js +++ /dev/null @@ -1,18 +0,0 @@ -import { ACTION_TYPES } from '../constants'; - -/** - * @typedef {import('redux').Action} Action - * @typedef {import('../../../types/index').Choices.Group} Group - */ - -/** - * @param {Group} group - * @returns {Action & Group} - */ -export const addGroup = ({ value, id, active, disabled }) => ({ - type: ACTION_TYPES.ADD_GROUP, - value, - id, - active, - disabled, -}); diff --git a/src/scripts/actions/groups.test.js b/src/scripts/actions/groups.test.ts similarity index 86% rename from src/scripts/actions/groups.test.js rename to src/scripts/actions/groups.test.ts index 07d501d..f56e29c 100644 --- a/src/scripts/actions/groups.test.js +++ b/src/scripts/actions/groups.test.ts @@ -5,10 +5,11 @@ describe('actions/groups', () => { describe('addGroup action', () => { it('returns ADD_GROUP action', () => { const value = 'test'; - const id = 'test'; + const id = 1; const active = true; const disabled = false; - const expectedAction = { + + const expectedAction: actions.AddGroupAction = { type: 'ADD_GROUP', value, id, diff --git a/src/scripts/actions/groups.ts b/src/scripts/actions/groups.ts new file mode 100644 index 0000000..9c4a24e --- /dev/null +++ b/src/scripts/actions/groups.ts @@ -0,0 +1,27 @@ +import { ACTION_TYPES } from '../constants'; + +export interface AddGroupAction { + type: typeof ACTION_TYPES.ADD_GROUP; + id: number; + value: string; + active: boolean; + disabled: boolean; +} + +export const addGroup = ({ + value, + id, + active, + disabled, +}: { + id: number; + value: string; + active: boolean; + disabled: boolean; +}): AddGroupAction => ({ + type: ACTION_TYPES.ADD_GROUP, + value, + id, + active, + disabled, +}); diff --git a/src/scripts/actions/items.js b/src/scripts/actions/items.js deleted file mode 100644 index e280759..0000000 --- a/src/scripts/actions/items.js +++ /dev/null @@ -1,53 +0,0 @@ -import { ACTION_TYPES } from '../constants'; - -/** - * @typedef {import('redux').Action} Action - * @typedef {import('../../../types/index').Choices.Item} Item - */ - -/** - * @param {Item} item - * @returns {Action & Item} - */ -export const addItem = ({ - value, - label, - id, - choiceId, - groupId, - customProperties, - placeholder, - keyCode, -}) => ({ - type: ACTION_TYPES.ADD_ITEM, - value, - label, - id, - choiceId, - groupId, - customProperties, - placeholder, - keyCode, -}); - -/** - * @param {number} id - * @param {number} choiceId - * @returns {Action & { id: number, choiceId: number }} - */ -export const removeItem = (id, choiceId) => ({ - type: ACTION_TYPES.REMOVE_ITEM, - id, - choiceId, -}); - -/** - * @param {number} id - * @param {boolean} highlighted - * @returns {Action & { id: number, highlighted: boolean }} - */ -export const highlightItem = (id, highlighted) => ({ - type: ACTION_TYPES.HIGHLIGHT_ITEM, - id, - highlighted, -}); diff --git a/src/scripts/actions/items.test.js b/src/scripts/actions/items.test.ts similarity index 80% rename from src/scripts/actions/items.test.js rename to src/scripts/actions/items.test.ts index c637975..28b9ba0 100644 --- a/src/scripts/actions/items.test.js +++ b/src/scripts/actions/items.test.ts @@ -6,14 +6,14 @@ describe('actions/items', () => { it('returns ADD_ITEM action', () => { const value = 'test'; const label = 'test'; - const id = '1234'; - const choiceId = '1234'; - const groupId = 'test'; + const id = 1; + const choiceId = 1; + const groupId = 1; const customProperties = { test: true }; const placeholder = true; const keyCode = 10; - const expectedAction = { + const expectedAction: actions.AddItemAction = { type: 'ADD_ITEM', value, label, @@ -42,9 +42,10 @@ describe('actions/items', () => { describe('removeItem action', () => { it('returns REMOVE_ITEM action', () => { - const id = '1234'; - const choiceId = '1'; - const expectedAction = { + const id = 1; + const choiceId = 1; + + const expectedAction: actions.RemoveItemAction = { type: 'REMOVE_ITEM', id, choiceId, @@ -56,10 +57,10 @@ describe('actions/items', () => { describe('highlightItem action', () => { it('returns HIGHLIGHT_ITEM action', () => { - const id = '1234'; + const id = 1; const highlighted = true; - const expectedAction = { + const expectedAction: actions.HighlightItemAction = { type: 'HIGHLIGHT_ITEM', id, highlighted, diff --git a/src/scripts/actions/items.ts b/src/scripts/actions/items.ts new file mode 100644 index 0000000..e7ec8a4 --- /dev/null +++ b/src/scripts/actions/items.ts @@ -0,0 +1,70 @@ +import { ACTION_TYPES } from '../constants'; + +export interface AddItemAction { + type: typeof ACTION_TYPES.ADD_ITEM; + id: number; + value: string; + label: string; + choiceId: number; + groupId: number; + customProperties: object; + placeholder: boolean; + keyCode: number; +} + +export interface RemoveItemAction { + type: typeof ACTION_TYPES.REMOVE_ITEM; + id: number; + choiceId: number; +} + +export interface HighlightItemAction { + type: typeof ACTION_TYPES.HIGHLIGHT_ITEM; + id: number; + highlighted: boolean; +} + +export const addItem = ({ + value, + label, + id, + choiceId, + groupId, + customProperties, + placeholder, + keyCode, +}: { + id: number; + value: string; + label: string; + choiceId: number; + groupId: number; + customProperties: object; + placeholder: boolean; + keyCode: number; +}): AddItemAction => ({ + type: ACTION_TYPES.ADD_ITEM, + value, + label, + id, + choiceId, + groupId, + customProperties, + placeholder, + keyCode, +}); + +export const removeItem = (id: number, choiceId: number): RemoveItemAction => ({ + type: ACTION_TYPES.REMOVE_ITEM, + id, + choiceId, +}); + +export const highlightItem = ( + id: number, + highlighted: boolean, +): HighlightItemAction => ({ + type: ACTION_TYPES.HIGHLIGHT_ITEM, + id, + highlighted, +}); diff --git a/src/scripts/actions/misc.js b/src/scripts/actions/misc.js deleted file mode 100644 index e512610..0000000 --- a/src/scripts/actions/misc.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @typedef {import('redux').Action} Action - */ - -/** - * @returns {Action} - */ -export const clearAll = () => ({ - type: 'CLEAR_ALL', -}); - -/** - * @param {any} state - * @returns {Action & { state: object }} - */ -export const resetTo = state => ({ - type: 'RESET_TO', - state, -}); - -/** - * @param {boolean} isLoading - * @returns {Action & { isLoading: boolean }} - */ -export const setIsLoading = isLoading => ({ - type: 'SET_IS_LOADING', - isLoading, -}); diff --git a/src/scripts/actions/misc.test.js b/src/scripts/actions/misc.test.ts similarity index 73% rename from src/scripts/actions/misc.test.js rename to src/scripts/actions/misc.test.ts index 7842444..b1577b4 100644 --- a/src/scripts/actions/misc.test.js +++ b/src/scripts/actions/misc.test.ts @@ -1,10 +1,11 @@ import { expect } from 'chai'; import * as actions from './misc'; +import { State } from '../interfaces'; describe('actions/misc', () => { describe('clearAll action', () => { it('returns CLEAR_ALL action', () => { - const expectedAction = { + const expectedAction: actions.ClearAllAction = { type: 'CLEAR_ALL', }; @@ -14,8 +15,13 @@ describe('actions/misc', () => { describe('resetTo action', () => { it('returns RESET_TO action', () => { - const state = { test: true }; - const expectedAction = { + const state: State = { + choices: [], + items: [], + groups: [], + loading: false, + }; + const expectedAction: actions.ResetToAction = { type: 'RESET_TO', state, }; @@ -27,7 +33,7 @@ describe('actions/misc', () => { describe('setIsLoading action', () => { describe('setting loading state to true', () => { it('returns expected action', () => { - const expectedAction = { + const expectedAction: actions.SetIsLoadingAction = { type: 'SET_IS_LOADING', isLoading: true, }; @@ -38,7 +44,7 @@ describe('actions/misc', () => { describe('setting loading state to false', () => { it('returns expected action', () => { - const expectedAction = { + const expectedAction: actions.SetIsLoadingAction = { type: 'SET_IS_LOADING', isLoading: false, }; diff --git a/src/scripts/actions/misc.ts b/src/scripts/actions/misc.ts new file mode 100644 index 0000000..24a6f5a --- /dev/null +++ b/src/scripts/actions/misc.ts @@ -0,0 +1,30 @@ +import { State } from '../interfaces'; +import { ACTION_TYPES } from '../constants'; + +export interface ClearAllAction { + type: typeof ACTION_TYPES.CLEAR_ALL; +} + +export interface ResetToAction { + type: typeof ACTION_TYPES.RESET_TO; + state: State; +} + +export interface SetIsLoadingAction { + type: typeof ACTION_TYPES.SET_IS_LOADING; + isLoading: boolean; +} + +export const clearAll = (): ClearAllAction => ({ + type: ACTION_TYPES.CLEAR_ALL, +}); + +export const resetTo = (state: State): ResetToAction => ({ + type: ACTION_TYPES.RESET_TO, + state, +}); + +export const setIsLoading = (isLoading: boolean): SetIsLoadingAction => ({ + type: ACTION_TYPES.SET_IS_LOADING, + isLoading, +}); diff --git a/src/scripts/choices.test.js b/src/scripts/choices.test.ts similarity index 91% rename from src/scripts/choices.test.js rename to src/scripts/choices.test.ts index f5c0bd1..d229265 100644 --- a/src/scripts/choices.test.js +++ b/src/scripts/choices.test.ts @@ -3,9 +3,12 @@ import { spy, stub } from 'sinon'; import sinonChai from 'sinon-chai'; import Choices from './choices'; + import { EVENTS, ACTION_TYPES, DEFAULT_CONFIG, KEY_CODES } from './constants'; import { WrappedSelect, WrappedInput } from './components/index'; import { removeItem } from './actions/items'; +import { Item, Choice, Group } from './interfaces'; +import templates from './templates'; chai.use(sinonChai); @@ -28,12 +31,6 @@ describe('choices', () => { instance = null; }); - const returnsInstance = () => { - it('returns this', () => { - expect(output).to.eql(instance); - }); - }; - describe('constructor', () => { describe('config', () => { describe('not passing config options', () => { @@ -88,7 +85,7 @@ describe('choices', () => { `; instance = new Choices('[data-choice]', { - renderSelectedChoices: 'test', + renderSelectedChoices: 'test' as any, }); expect(instance.config.renderSelectedChoices).to.equal('auto'); @@ -211,7 +208,7 @@ describe('choices', () => { `; - instance = new Choices(document.querySelector('[data-choice]')); + instance = new Choices('[data-choice]'); expect(instance.passedElement).to.be.an.instanceOf(WrappedInput); }); @@ -223,7 +220,7 @@ describe('choices', () => { `; - instance = new Choices(document.querySelector('[data-choice]')); + instance = new Choices('[data-choice]'); expect(instance.passedElement).to.be.an.instanceOf(WrappedSelect); }); @@ -386,8 +383,8 @@ describe('choices', () => { expect(clearStoreSpy.called).to.equal(true); }); - it('nullifys templates config', () => { - expect(instance._templates).to.equal(null); + it('restes templates config', () => { + expect(instance._templates).to.deep.equal(templates); }); it('resets initialise flag', () => { @@ -423,7 +420,9 @@ describe('choices', () => { output = instance.enable(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(passedElementEnableSpy.called).to.equal(false); @@ -481,7 +480,9 @@ describe('choices', () => { output = instance.disable(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(removeEventListenersSpy.called).to.equal(false); @@ -638,7 +639,9 @@ describe('choices', () => { output = instance.hideDropdown(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(containerOuterCloseSpy.called).to.equal(false); @@ -735,7 +738,9 @@ describe('choices', () => { output = instance.highlightItem(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(passedElementTriggerEventStub.called).to.equal(false); @@ -745,7 +750,7 @@ describe('choices', () => { }); describe('item passed', () => { - const item = { + const item: Item = { id: 1234, value: 'Test', label: 'Test', @@ -756,7 +761,9 @@ describe('choices', () => { output = instance.highlightItem(item, true); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('dispatches highlightItem action with correct arguments', () => { expect(storeDispatchSpy.called).to.equal(true); @@ -817,7 +824,9 @@ describe('choices', () => { expect(passedElementTriggerEventStub.called).to.equal(false); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); }); }); }); @@ -850,7 +859,9 @@ describe('choices', () => { output = instance.unhighlightItem(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(passedElementTriggerEventStub.called).to.equal(false); @@ -860,7 +871,7 @@ describe('choices', () => { }); describe('item passed', () => { - const item = { + const item: Item = { id: 1234, value: 'Test', label: 'Test', @@ -871,7 +882,9 @@ describe('choices', () => { output = instance.unhighlightItem(item, true); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('dispatches highlightItem action with correct arguments', () => { expect(storeDispatchSpy.called).to.equal(true); @@ -932,7 +945,9 @@ describe('choices', () => { expect(passedElementTriggerEventStub.called).to.equal(false); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); }); }); }); @@ -966,7 +981,9 @@ describe('choices', () => { storeGetItemsStub.reset(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('highlights each item in store', () => { expect(highlightItemStub.callCount).to.equal(items.length); @@ -1004,7 +1021,9 @@ describe('choices', () => { storeGetItemsStub.reset(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('unhighlights each item in store', () => { expect(unhighlightItemStub.callCount).to.equal(items.length); @@ -1027,7 +1046,9 @@ describe('choices', () => { instance._store.dispatch.reset(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('dispatches clearChoices action', () => { expect(storeDispatchStub.lastCall.args[0]).to.eql({ @@ -1050,7 +1071,9 @@ describe('choices', () => { instance._store.dispatch.reset(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('dispatches clearAll action', () => { expect(storeDispatchStub.lastCall.args[0]).to.eql({ @@ -1075,7 +1098,9 @@ describe('choices', () => { instance._store.dispatch.reset(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); describe('text element', () => { beforeEach(() => { @@ -1164,14 +1189,14 @@ describe('choices', () => { const handleLoadingStateSpy = spy(choice, '_handleLoadingState'); let fetcherCalled = false; - const fetcher = async inst => { + const fetcher = async (inst): Promise => { expect(inst).to.eq(choice); fetcherCalled = true; await new Promise(resolve => setTimeout(resolve, 800)); return [ - { label: 'l1', value: 'v1', customProperties: 'prop1' }, - { label: 'l2', value: 'v2', customProperties: 'prop2' }, + { label: 'l1', value: 'v1', customProperties: { prop1: true } }, + { label: 'l2', value: 'v2', customProperties: { prop2: false } }, ]; }; expect(choice._store.choices.length).to.equal(0); @@ -1182,7 +1207,9 @@ describe('choices', () => { expect(handleLoadingStateSpy.callCount).to.equal(2); expect(choice._store.choices[1].value).to.equal('v2'); expect(choice._store.choices[1].label).to.equal('l2'); - expect(choice._store.choices[1].customProperties).to.equal('prop2'); + expect(choice._store.choices[1].customProperties).to.deep.equal({ + prop2: false, + }); }); }); }); @@ -1211,7 +1238,9 @@ describe('choices', () => { output = instance.setValue(values); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(setChoiceOrItemStub.called).to.equal(false); @@ -1224,7 +1253,9 @@ describe('choices', () => { output = instance.setValue(values); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('sets each value', () => { expect(setChoiceOrItemStub.callCount).to.equal(2); @@ -1252,7 +1283,9 @@ describe('choices', () => { output = instance.setChoiceByValue([]); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('returns early', () => { expect(findAndSelectChoiceByValueStub.called).to.equal(false); @@ -1272,7 +1305,9 @@ describe('choices', () => { output = instance.setChoiceByValue(value); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('sets each choice with same value', () => { expect(findAndSelectChoiceByValueStub.called).to.equal(true); @@ -1289,7 +1324,9 @@ describe('choices', () => { output = instance.setChoiceByValue(values); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('sets each choice with same value', () => { expect(findAndSelectChoiceByValueStub.callCount).to.equal(2); @@ -1509,7 +1546,9 @@ describe('choices', () => { output = instance.removeHighlightedItems(); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('removes each highlighted item in store', () => { expect(removeItemStub.callCount).to.equal(2); @@ -1521,7 +1560,9 @@ describe('choices', () => { output = instance.removeHighlightedItems(true); }); - returnsInstance(output); + it('returns this', () => { + expect(output).to.eql(instance); + }); it('triggers event with item value', () => { expect(triggerChangeStub.callCount).to.equal(2); @@ -1538,19 +1579,23 @@ describe('choices', () => { let containerOuterRemoveLoadingStateStub; const value = 'value'; const label = 'label'; - const choices = [ + const choices: Choice[] = [ { id: 1, value: '1', label: 'Test 1', + selected: false, + disabled: false, }, { id: 2, value: '2', label: 'Test 2', + selected: false, + disabled: true, }, ]; - const groups = [ + const groups: Group[] = [ { ...choices[0], choices, @@ -1634,10 +1679,10 @@ describe('choices', () => { expect(call.args[0]).to.eql({ value: choices[index][value], label: choices[index][label], - isSelected: choices[index].selected, - isDisabled: choices[index].disabled, + isSelected: !!choices[index].selected, + isDisabled: !!choices[index].disabled, customProperties: choices[index].customProperties, - placeholder: choices[index].placeholder, + placeholder: !!choices[index].placeholder, }); }); }); @@ -1679,7 +1724,7 @@ describe('choices', () => { describe('private methods', () => { describe('_createGroupsFragment', () => { let _createChoicesFragmentStub; - const choices = [ + const choices: Choice[] = [ { id: 1, selected: true, @@ -1703,7 +1748,7 @@ describe('choices', () => { }, ]; - const groups = [ + const groups: Group[] = [ { id: 2, value: 'Group 2', @@ -1925,12 +1970,12 @@ describe('choices', () => { }); describe('when a placeholder option is not defined', () => { - it('returns false', () => { + it('returns null', () => { instance._isSelectElement = true; instance.passedElement.placeholderOption = undefined; const value = instance._generatePlaceholderValue(); - expect(value).to.equal(false); + expect(value).to.equal(null); }); }); }); @@ -1970,7 +2015,7 @@ describe('choices', () => { }); describe('when the placeholder attribute is not defined on the passed element', () => { - it('returns false', () => { + it('returns null', () => { instance._isSelectElement = false; instance.config.placeholder = true; instance.config.placeholderValue = undefined; @@ -1981,32 +2026,25 @@ describe('choices', () => { }; const value = instance._generatePlaceholderValue(); - expect(value).to.equal(false); + expect(value).to.equal(null); }); }); }); }); describe('when the placeholder config option is set to false', () => { - it('returns false', () => { + it('returns null', () => { instance._isSelectElement = false; instance.config.placeholder = false; const value = instance._generatePlaceholderValue(); - expect(value).to.equal(false); + expect(value).to.equal(null); }); }); }); }); describe('_getTemplate', () => { - describe('when not passing a template key', () => { - it('returns null', () => { - output = instance._getTemplate(); - expect(output).to.equal(null); - }); - }); - describe('when passing a template key', () => { it('returns the generated template for the given template key', () => { const templateKey = 'test'; @@ -2028,130 +2066,96 @@ describe('choices', () => { }); describe('_onKeyDown', () => { + let activeItems; + let hasItems; + let hasActiveDropdown; + let hasFocussedInput; + beforeEach(() => { instance.showDropdown = stub(); - instance._onAKey = stub(); + instance._onSelectKey = stub(); instance._onEnterKey = stub(); instance._onEscapeKey = stub(); instance._onDirectionKey = stub(); instance._onDeleteKey = stub(); + + ({ activeItems } = instance._store); + hasItems = instance.itemList.hasChildren(); + hasActiveDropdown = instance.dropdown.isActive; + hasFocussedInput = instance.input.isFocussed; }); - const scenarios = [ - { - keyCode: KEY_CODES.BACK_KEY, - expectedFunctionCall: '_onDeleteKey', - }, - { - keyCode: KEY_CODES.DELETE_KEY, - expectedFunctionCall: '_onDeleteKey', - }, - { - keyCode: KEY_CODES.A_KEY, - expectedFunctionCall: '_onAKey', - }, - { - keyCode: KEY_CODES.ENTER_KEY, - expectedFunctionCall: '_onEnterKey', - }, - { - keyCode: KEY_CODES.UP_KEY, - expectedFunctionCall: '_onDirectionKey', - }, - { - keyCode: KEY_CODES.DOWN_KEY, - expectedFunctionCall: '_onDirectionKey', - }, - { - keyCode: KEY_CODES.DOWN_KEY, - expectedFunctionCall: '_onDirectionKey', - }, - { - keyCode: KEY_CODES.ESC_KEY, - expectedFunctionCall: '_onEscapeKey', - }, - ]; + describe('direction key', () => { + const keyCodes = [ + KEY_CODES.UP_KEY, + KEY_CODES.DOWN_KEY, + KEY_CODES.PAGE_UP_KEY, + KEY_CODES.PAGE_DOWN_KEY, + ]; - describe('when called with a keydown event', () => { - scenarios.forEach(({ keyCode, expectedFunctionCall }) => { - describe(`when the keyCode is ${keyCode}`, () => { - it(`calls ${expectedFunctionCall} with the expected arguments`, () => { - const mockEvent = { - keyCode, - }; + keyCodes.forEach(keyCode => { + it(`calls _onDirectionKey with the expected arguments`, () => { + const event = { + keyCode, + }; - instance._onKeyDown(mockEvent); + instance._onKeyDown(event); - expect(instance[expectedFunctionCall]).to.have.been.calledWith({ - event: mockEvent, - activeItems: instance._store.activeItems, - hasActiveDropdown: instance.dropdown.isActive, - hasFocusedInput: instance.input.isFocussed, - hasItems: instance.itemList.hasChildren(), - }); - }); + expect(instance._onDirectionKey).to.have.been.calledWith( + event, + hasActiveDropdown, + ); }); }); + }); - describe('select input', () => { - describe('when the dropdown is not active', () => { - describe('when the key was alpha-numeric', () => { - beforeEach(() => { - instance._isTextElement = false; - instance.dropdown.isActive = false; - }); + describe('select key', () => { + it(`calls _onSelectKey with the expected arguments`, () => { + const event = { + keyCode: KEY_CODES.A_KEY, + }; - it('shows the dropdown', () => { - instance._onKeyDown({ - keyCode: KEY_CODES.A_KEY, - }); + instance._onKeyDown(event); - expect(instance.showDropdown).to.have.been.calledWith(); - }); + expect(instance._onSelectKey).to.have.been.calledWith( + event, + hasItems, + ); + }); + }); - describe('when the input is not focussed', () => { - beforeEach(() => { - instance.input.isFocussed = false; - }); + describe('enter key', () => { + it(`calls _onEnterKey with the expected arguments`, () => { + const event = { + keyCode: KEY_CODES.ENTER_KEY, + }; - it('updates the input value with the character corresponding to the key code', () => { - instance._onKeyDown({ - keyCode: KEY_CODES.A_KEY, - }); + instance._onKeyDown(event); - expect(instance.input.value).to.contain('a'); - }); - }); + expect(instance._onEnterKey).to.have.been.calledWith( + event, + activeItems, + hasActiveDropdown, + ); + }); + }); - describe('when the input is focussed', () => { - beforeEach(() => { - instance.input.isFocussed = true; - }); + describe('delete key', () => { + const keyCodes = [KEY_CODES.DELETE_KEY, KEY_CODES.BACK_KEY]; - it('does not update the input value', () => { - instance._onKeyDown({ - keyCode: KEY_CODES.A_KEY, - }); + keyCodes.forEach(keyCode => { + it(`calls _onDeleteKey with the expected arguments`, () => { + const event = { + keyCode, + }; - expect(instance.input.value).to.not.contain('a'); - }); - }); - }); + instance._onKeyDown(event); - describe('when the input was not alpha-numeric', () => { - beforeEach(() => { - instance._isTextElement = false; - instance.dropdown.isActive = false; - }); - - it('does not show the dropdown', () => { - instance._onKeyDown({ - keyCode: KEY_CODES.DELETE_KEY, - }); - - expect(instance.showDropdown).to.not.have.been.called; - }); - }); + expect(instance._onDeleteKey).to.have.been.calledWith( + event, + activeItems, + hasFocussedInput, + ); }); }); }); diff --git a/src/scripts/choices.js b/src/scripts/choices.ts similarity index 80% rename from src/scripts/choices.js rename to src/scripts/choices.ts index a889829..238bef8 100644 --- a/src/scripts/choices.js +++ b/src/scripts/choices.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import Fuse from 'fuse.js'; import merge from 'deepmerge'; @@ -18,12 +19,13 @@ import { SELECT_ONE_TYPE, SELECT_MULTIPLE_TYPE, } from './constants'; -import { TEMPLATES } from './templates'; +import templates from './templates'; import { addChoice, filterChoices, activateChoices, clearChoices, + Result, } from './actions/choices'; import { addItem, removeItem, highlightItem } from './actions/items'; import { addGroup } from './actions/groups'; @@ -37,48 +39,90 @@ import { sortByScore, generateId, existsInArray, - cloneObject, diff, } from './lib/utils'; +import { + Options, + Choice, + Item, + Group, + Notice, + State, + PassedElement, +} from './interfaces'; +import { defaultState } from './reducers'; /** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */ const IS_IE11 = '-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style; -/** - * @typedef {import('../../types/index').Choices.Choice} Choice - * @typedef {import('../../types/index').Choices.Item} Item - * @typedef {import('../../types/index').Choices.Group} Group - * @typedef {import('../../types/index').Choices.Options} Options - */ - -/** @type {Partial} */ -const USER_DEFAULTS = {}; +const USER_DEFAULTS: Partial = {}; /** * Choices * @author Josh Johnson */ class Choices { - static get defaults() { + static get defaults(): { + options: Partial; + templates: typeof templates; + } { return Object.preventExtensions({ - get options() { + get options(): Partial { return USER_DEFAULTS; }, - get templates() { - return TEMPLATES; + get templates(): typeof templates { + return templates; }, }); } - /** - * @param {string | HTMLInputElement | HTMLSelectElement} element - * @param {Partial} userConfig - */ - constructor(element = '[data-choice]', userConfig = {}) { - /** @type {Partial} */ - this.config = merge.all( + initialised: boolean; + config: Options; + passedElement: WrappedInput | WrappedSelect; + containerOuter: Container; + containerInner: Container; + choiceList: List; + itemList: List; + input: Input; + dropdown: Dropdown; + + _isTextElement: boolean; + _isSelectOneElement: boolean; + _isSelectMultipleElement: boolean; + _isSelectElement: boolean; + _store: Store; + _templates: typeof templates; + _initialState: State; + _currentState: State; + _prevState: State; + _currentValue: string; + _canSearch: boolean; + _isScrollingOnIe: boolean; + _highlightPosition: number; + _wasTap: boolean; + _isSearching: boolean; + _placeholderValue: string | null; + _baseId: string; + _direction: HTMLElement['dir']; + _idNames: { + itemChoice: string; + }; + _presetGroups: Group[] | HTMLOptGroupElement[] | Element[]; + _presetOptions: Item[] | HTMLOptionElement[]; + _presetChoices: Partial[]; + _presetItems: Item[] | string[]; + + constructor( + element: + | string + | Element + | HTMLInputElement + | HTMLSelectElement = '[data-choice]', + userConfig: Partial = {}, + ) { + this.config = merge.all( [DEFAULT_CONFIG, Choices.defaults.options, userConfig], // When merging array configs, replace with a copy of the userConfig array, // instead of concatenating with the default array @@ -116,7 +160,7 @@ class Choices { this.config.searchEnabled = this._isSelectMultipleElement || this.config.searchEnabled; - if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) { + if (!['auto', 'always'].includes(`${this.config.renderSelectedChoices}`)) { this.config.renderSelectedChoices = 'auto'; } @@ -134,35 +178,36 @@ class Choices { if (this._isTextElement) { this.passedElement = new WrappedInput({ - element: passedElement, + element: passedElement as HTMLInputElement, classNames: this.config.classNames, delimiter: this.config.delimiter, }); } else { this.passedElement = new WrappedSelect({ - element: passedElement, + element: passedElement as HTMLSelectElement, classNames: this.config.classNames, - template: data => this._templates.option(data), + template: (data: Item): HTMLOptionElement => + this._templates.option(data), }); } this.initialised = false; this._store = new Store(); - this._initialState = {}; - this._currentState = {}; - this._prevState = {}; + this._initialState = defaultState; + this._currentState = defaultState; + this._prevState = defaultState; this._currentValue = ''; - this._canSearch = this.config.searchEnabled; + this._canSearch = !!this.config.searchEnabled; this._isScrollingOnIe = false; this._highlightPosition = 0; this._wasTap = true; this._placeholderValue = this._generatePlaceholderValue(); this._baseId = generateId(this.passedElement.element, 'choices-'); + /** * setting direction in cases where it's explicitly set on passedElement * or when calculated direction is different from the document - * @type {HTMLElement['dir']} */ this._direction = this.passedElement.dir; @@ -181,30 +226,36 @@ class Choices { this._idNames = { itemChoice: 'item-choice', }; - // Assign preset groups from passed element - this._presetGroups = this.passedElement.optionGroups; - // Assign preset options from passed element - this._presetOptions = this.passedElement.options; + + if (this._isSelectElement) { + // Assign preset groups from passed element + this._presetGroups = (this.passedElement as WrappedSelect).optionGroups; + // Assign preset options from passed element + this._presetOptions = (this.passedElement as WrappedSelect).options; + } + // Assign preset choices from passed object this._presetChoices = this.config.choices; // Assign preset items from passed object first this._presetItems = this.config.items; // Add any values passed from attribute - if (this.passedElement.value) { - this._presetItems = this._presetItems.concat( - this.passedElement.value.split(this.config.delimiter), + if (this.passedElement.value && this._isTextElement) { + const splitValues: string[] = this.passedElement.value.split( + this.config.delimiter, ); + this._presetItems = (this._presetItems as string[]).concat(splitValues); } // Create array of choices from option elements - if (this.passedElement.options) { - this.passedElement.options.forEach(o => { + if ((this.passedElement as WrappedSelect).options) { + (this.passedElement as WrappedSelect).options.forEach(option => { this._presetChoices.push({ - value: o.value, - label: o.innerHTML, - selected: o.selected, - disabled: o.disabled || o.parentNode.disabled, - placeholder: o.value === '' || o.hasAttribute('placeholder'), - customProperties: o.getAttribute('data-custom-properties'), + value: option.value, + label: option.innerHTML, + selected: !!option.selected, + disabled: option.disabled || option.parentNode.disabled, + placeholder: + option.value === '' || option.hasAttribute('placeholder'), + customProperties: option.dataset['custom-properties'], }); }); } @@ -220,7 +271,7 @@ class Choices { this._onMouseDown = this._onMouseDown.bind(this); this._onMouseOver = this._onMouseOver.bind(this); this._onFormReset = this._onFormReset.bind(this); - this._onAKey = this._onAKey.bind(this); + this._onSelectKey = this._onSelectKey.bind(this); this._onEnterKey = this._onEnterKey.bind(this); this._onEscapeKey = this._onEscapeKey.bind(this); this._onDirectionKey = this._onDirectionKey.bind(this); @@ -244,7 +295,7 @@ class Choices { this.init(); } - init() { + init(): void { if (this.initialised) { return; } @@ -253,10 +304,8 @@ class Choices { this._createElements(); this._createStructure(); - // Set initial state (We need to clone the state because some reducers - // modify the inner objects properties in the state) 🤢 - this._initialState = cloneObject(this._store.state); this._store.subscribe(this._render); + this._render(); this._addEventListeners(); @@ -277,7 +326,7 @@ class Choices { } } - destroy() { + destroy(): void { if (!this.initialised) { return; } @@ -289,14 +338,14 @@ class Choices { this.clearStore(); if (this._isSelectElement) { - this.passedElement.options = this._presetOptions; + (this.passedElement as WrappedSelect).options = this._presetOptions; } - this._templates = null; + this._templates = templates; this.initialised = false; } - enable() { + enable(): this { if (this.passedElement.isDisabled) { this.passedElement.enable(); } @@ -310,7 +359,7 @@ class Choices { return this; } - disable() { + disable(): this { if (!this.passedElement.isDisabled) { this.passedElement.disable(); } @@ -324,8 +373,8 @@ class Choices { return this; } - highlightItem(item, runEvent = true) { - if (!item) { + highlightItem(item: Item, runEvent = true): this { + if (!item || !item.id) { return this; } @@ -346,8 +395,8 @@ class Choices { return this; } - unhighlightItem(item) { - if (!item) { + unhighlightItem(item: Item): this { + if (!item || !item.id) { return this; } @@ -365,19 +414,19 @@ class Choices { return this; } - highlightAll() { + highlightAll(): this { this._store.items.forEach(item => this.highlightItem(item)); return this; } - unhighlightAll() { + unhighlightAll(): this { this._store.items.forEach(item => this.unhighlightItem(item)); return this; } - removeActiveItemsByValue(value) { + removeActiveItemsByValue(value: string): this { this._store.activeItems .filter(item => item.value === value) .forEach(item => this._removeItem(item)); @@ -385,7 +434,7 @@ class Choices { return this; } - removeActiveItems(excludedId) { + removeActiveItems(excludedId: number): this { this._store.activeItems .filter(({ id }) => id !== excludedId) .forEach(item => this._removeItem(item)); @@ -393,7 +442,7 @@ class Choices { return this; } - removeHighlightedItems(runEvent = false) { + removeHighlightedItems(runEvent = false): this { this._store.highlightedActiveItems.forEach(item => { this._removeItem(item); // If this action was performed by the user @@ -406,7 +455,7 @@ class Choices { return this; } - showDropdown(preventInputFocus) { + showDropdown(preventInputFocus?: boolean): this { if (this.dropdown.isActive) { return this; } @@ -425,7 +474,7 @@ class Choices { return this; } - hideDropdown(preventInputBlur) { + hideDropdown(preventInputBlur?: boolean): this { if (!this.dropdown.isActive) { return this; } @@ -445,21 +494,21 @@ class Choices { return this; } - getValue(valueOnly = false) { - const values = this._store.activeItems.reduce((selectedItems, item) => { - const itemValue = valueOnly ? item.value : item; - selectedItems.push(itemValue); + getValue(valueOnly = false): string[] | Item[] | Item | string { + const values = this._store.activeItems.reduce( + (selectedItems, item) => { + const itemValue = valueOnly ? item.value : item; + selectedItems.push(itemValue); - return selectedItems; - }, []); + return selectedItems; + }, + [], + ); return this._isSelectOneElement ? values[0] : values; } - /** - * @param {string[] | Item[]} items - */ - setValue(items) { + setValue(items: string[] | Item[]): this { if (!this.initialised) { return this; } @@ -469,7 +518,7 @@ class Choices { return this; } - setChoiceByValue(value) { + setChoiceByValue(value: string): this { if (!this.initialised || this._isTextElement) { return this; } @@ -492,13 +541,6 @@ class Choices { * * **Input types affected:** select-one, select-multiple * - * @template {Choice[] | ((instance: Choices) => object[] | Promise)} T - * @param {T} [choicesArrayOrFetcher] - * @param {string} [value = 'value'] - name of `value` field - * @param {string} [label = 'label'] - name of 'label' field - * @param {boolean} [replaceChoices = false] - whether to replace of add choices - * @returns {this | Promise} - * * @example * ```js * const example = new Choices(element); @@ -554,11 +596,14 @@ class Choices { * ``` */ setChoices( - choicesArrayOrFetcher = [], + choicesArrayOrFetcher: + | Choice[] + | Group[] + | ((instance: Choices) => Choice[] | Promise) = [], value = 'value', label = 'label', replaceChoices = false, - ) { + ): this | Promise { if (!this.initialised) { throw new ReferenceError( `setChoices was called on a non-initialized instance of Choices`, @@ -586,10 +631,12 @@ class Choices { if (typeof Promise === 'function' && fetcher instanceof Promise) { // that's a promise // eslint-disable-next-line compat/compat - return new Promise(resolve => requestAnimationFrame(resolve)) + return new Promise(resolve => requestAnimationFrame(resolve)) // eslint-disable-line compat/compat .then(() => this._handleLoadingState(true)) .then(() => fetcher) - .then(data => this.setChoices(data, value, label, replaceChoices)) + .then((data: Choice[]) => + this.setChoices(data, value, label, replaceChoices), + ) .catch(err => { if (!this.config.silent) { console.error(err); @@ -620,22 +667,28 @@ class Choices { this._startLoading(); - choicesArrayOrFetcher.forEach(groupOrChoice => { - if (groupOrChoice.choices) { + type ChoiceGroup = { + id: string; + choices: Choice[]; + }; + + choicesArrayOrFetcher.forEach((groupOrChoice: ChoiceGroup | Choice) => { + if ((groupOrChoice as ChoiceGroup).choices) { this._addGroup({ - id: parseInt(groupOrChoice.id, 10) || null, + id: groupOrChoice.id ? parseInt(`${groupOrChoice.id}`, 10) : null, group: groupOrChoice, valueKey: value, labelKey: label, }); } else { + const choice = groupOrChoice as Choice; this._addChoice({ - value: groupOrChoice[value], - label: groupOrChoice[label], - isSelected: groupOrChoice.selected, - isDisabled: groupOrChoice.disabled, - customProperties: groupOrChoice.customProperties, - placeholder: groupOrChoice.placeholder, + value: choice[value], + label: choice[label], + isSelected: !!choice.selected, + isDisabled: !!choice.disabled, + placeholder: !!choice.placeholder, + customProperties: choice.customProperties, }); } }); @@ -645,19 +698,19 @@ class Choices { return this; } - clearChoices() { + clearChoices(): this { this._store.dispatch(clearChoices()); return this; } - clearStore() { + clearStore(): this { this._store.dispatch(clearAll()); return this; } - clearInput() { + clearInput(): this { const shouldSetInputWidth = !this._isSelectOneElement; this.input.clear(shouldSetInputWidth); @@ -669,7 +722,7 @@ class Choices { return this; } - _render() { + _render(): void { if (this._store.isLoading()) { return; } @@ -699,7 +752,7 @@ class Choices { this._prevState = this._currentState; } - _renderChoices() { + _renderChoices(): void { const { activeGroups, activeChoices } = this._store; let choiceListFragment = document.createDocumentFragment(); @@ -748,8 +801,8 @@ class Choices { this.choiceList.append(choiceListFragment); this._highlightChoice(); } else { - // ...otherwise show a notice - this.choiceList.append(this._getTemplate('notice', canAddItem.notice)); + const notice = this._getTemplate('notice', canAddItem.notice); + this.choiceList.append(notice); } } else { // Otherwise show a notice @@ -776,7 +829,7 @@ class Choices { } } - _renderItems() { + _renderItems(): void { const activeItems = this._store.activeItems || []; this.itemList.clear(); @@ -791,11 +844,11 @@ class Choices { } _createGroupsFragment( - groups, - choices, - fragment = document.createDocumentFragment(), - ) { - const getGroupChoices = group => + groups: Group[], + choices: Choice[], + fragment: DocumentFragment = document.createDocumentFragment(), + ): DocumentFragment { + const getGroupChoices = (group): Choice[] => choices.filter(choice => { if (this._isSelectOneElement) { return choice.groupId === group.id; @@ -825,10 +878,10 @@ class Choices { } _createChoicesFragment( - choices, - fragment = document.createDocumentFragment(), + choices: Choice[], + fragment: DocumentFragment = document.createDocumentFragment(), withinGroup = false, - ) { + ): DocumentFragment { // Create a fragment to store our list items (so we don't have to update the DOM for each item) const { renderSelectedChoices, @@ -836,17 +889,19 @@ class Choices { renderChoiceLimit, } = this.config; const filter = this._isSearching ? sortByScore : this.config.sorter; - const appendChoice = choice => { + const appendChoice = (choice: Choice): void => { const shouldRender = renderSelectedChoices === 'auto' ? this._isSelectOneElement || !choice.selected : true; + if (shouldRender) { const dropdownItem = this._getTemplate( 'choice', choice, this.config.itemSelectText, ); + fragment.appendChild(dropdownItem); } }; @@ -859,7 +914,7 @@ class Choices { // Split array into placeholders and "normal" choices const { placeholderChoices, normalChoices } = rendererableChoices.reduce( - (acc, choice) => { + (acc, choice: Choice) => { if (choice.placeholder) { acc.placeholderChoices.push(choice); } else { @@ -868,7 +923,10 @@ class Choices { return acc; }, - { placeholderChoices: [], normalChoices: [] }, + { + placeholderChoices: [] as Choice[], + normalChoices: [] as Choice[], + }, ); // If sorting is enabled or the user is searching, filter choices @@ -899,7 +957,10 @@ class Choices { return fragment; } - _createItemsFragment(items, fragment = document.createDocumentFragment()) { + _createItemsFragment( + items: Item[], + fragment: DocumentFragment = document.createDocumentFragment(), + ): DocumentFragment { // Create fragment to add elements to const { shouldSortItems, sorter, removeItemButton } = this.config; @@ -910,13 +971,15 @@ class Choices { if (this._isTextElement) { // Update the value of the hidden input - this.passedElement.value = items; + this.passedElement.value = items + .map(({ value }) => value) + .join(this.config.delimiter); } else { // Update the options of the hidden input - this.passedElement.options = items; + (this.passedElement as WrappedSelect).options = items; } - const addItemToFragment = item => { + const addItemToFragment = (item: Item): void => { // Create new list element const listItem = this._getTemplate('item', item, removeItemButton); // Append it to list @@ -929,7 +992,7 @@ class Choices { return fragment; } - _triggerChange(value) { + _triggerChange(value): void { if (value === undefined || value === null) { return; } @@ -939,23 +1002,19 @@ class Choices { }); } - _selectPlaceholderChoice() { - const { placeholderChoice } = this._store; + _selectPlaceholderChoice(placeholderChoice: Choice): void { + this._addItem({ + value: placeholderChoice.value, + label: placeholderChoice.label, + choiceId: placeholderChoice.id, + groupId: placeholderChoice.groupId, + placeholder: placeholderChoice.placeholder, + }); - if (placeholderChoice) { - this._addItem({ - value: placeholderChoice.value, - label: placeholderChoice.label, - choiceId: placeholderChoice.id, - groupId: placeholderChoice.groupId, - placeholder: placeholderChoice.placeholder, - }); - - this._triggerChange(placeholderChoice.value); - } + this._triggerChange(placeholderChoice.value); } - _handleButtonAction(activeItems, element) { + _handleButtonAction(activeItems?: Item[], element?: HTMLElement): void { if ( !activeItems || !element || @@ -965,21 +1024,29 @@ class Choices { return; } - const itemId = element.parentNode.getAttribute('data-id'); - const itemToRemove = activeItems.find( - item => item.id === parseInt(itemId, 10), - ); + const itemId = + element.parentNode && (element.parentNode as HTMLElement).dataset.id; + const itemToRemove = + itemId && activeItems.find(item => item.id === parseInt(itemId, 10)); + + if (!itemToRemove) { + return; + } // Remove item associated with button this._removeItem(itemToRemove); this._triggerChange(itemToRemove.value); - if (this._isSelectOneElement) { - this._selectPlaceholderChoice(); + if (this._isSelectOneElement && this._store.placeholderChoice) { + this._selectPlaceholderChoice(this._store.placeholderChoice); } } - _handleItemAction(activeItems, element, hasShiftKey = false) { + _handleItemAction( + activeItems?: Item[], + element?: HTMLElement, + hasShiftKey = false, + ): void { if ( !activeItems || !element || @@ -989,13 +1056,13 @@ class Choices { return; } - const passedId = element.getAttribute('data-id'); + const passedId = element.dataset.id; // We only want to select one item with a click // so we deselect any items that aren't the target // unless shift is being pressed activeItems.forEach(item => { - if (item.id === parseInt(passedId, 10) && !item.highlighted) { + if (item.id === parseInt(`${passedId}`, 10) && !item.highlighted) { this.highlightItem(item); } else if (!hasShiftKey && item.highlighted) { this.unhighlightItem(item); @@ -1007,19 +1074,22 @@ class Choices { this.input.focus(); } - _handleChoiceAction(activeItems, element) { + _handleChoiceAction(activeItems?: Item[], element?: HTMLElement): void { if (!activeItems || !element) { return; } // If we are clicking on an option const { id } = element.dataset; - const choice = this._store.getChoiceById(id); + const choice = id && this._store.getChoiceById(id); if (!choice) { return; } + const passedKeyCode = - activeItems[0] && activeItems[0].keyCode ? activeItems[0].keyCode : null; + activeItems[0] && activeItems[0].keyCode + ? activeItems[0].keyCode + : undefined; const hasActiveDropdown = this.dropdown.isActive; // Update choice keyCode @@ -1056,7 +1126,7 @@ class Choices { } } - _handleBackspace(activeItems) { + _handleBackspace(activeItems?: Item[]): void { if (!this.config.removeItems || !activeItems) { return; } @@ -1080,15 +1150,15 @@ class Choices { } } - _startLoading() { + _startLoading(): void { this._store.dispatch(setIsLoading(true)); } - _stopLoading() { + _stopLoading(): void { this._store.dispatch(setIsLoading(false)); } - _handleLoadingState(setLoading = true) { + _handleLoadingState(setLoading = true): void { let placeholderItem = this.itemList.getChild( `.${this.config.classNames.placeholder}`, ); @@ -1103,7 +1173,10 @@ class Choices { 'placeholder', this.config.loadingText, ); - this.itemList.append(placeholderItem); + + if (placeholderItem) { + this.itemList.append(placeholderItem); + } } else { placeholderItem.innerHTML = this.config.loadingText; } @@ -1115,14 +1188,16 @@ class Choices { this.containerOuter.removeLoadingState(); if (this._isSelectOneElement) { - placeholderItem.innerHTML = this._placeholderValue || ''; + if (placeholderItem) { + placeholderItem.innerHTML = this._placeholderValue || ''; + } } else { this.input.placeholder = this._placeholderValue || ''; } } } - _handleSearch(value) { + _handleSearch(value: string): void { if (!value || !this.input.isFocussed) { return; } @@ -1146,7 +1221,7 @@ class Choices { } } - _canAddItem(activeItems, value) { + _canAddItem(activeItems: Item[], value: string): Notice { let canAddItem = true; let notice = typeof this.config.addItemText === 'function' @@ -1202,7 +1277,7 @@ class Choices { }; } - _searchChoices(value) { + _searchChoices(value: string): number { const newValue = typeof value === 'string' ? value.trim() : value; const currentValue = typeof this._currentValue === 'string' @@ -1217,9 +1292,12 @@ class Choices { const haystack = this._store.searchableChoices; const needle = newValue; const keys = [...this.config.searchFields]; - const options = Object.assign(this.config.fuseOptions, { keys }); + const options = Object.assign(this.config.fuseOptions, { + keys, + includeMatches: true, + }); const fuse = new Fuse(haystack, options); - const results = fuse.search(needle); + const results: Result[] = fuse.search(needle) as any[]; // see https://github.com/krisk/Fuse/issues/303 this._currentValue = newValue; this._highlightPosition = 0; @@ -1229,7 +1307,7 @@ class Choices { return results.length; } - _addEventListeners() { + _addEventListeners(): void { const { documentElement } = document; // capture events - can cancel event processing or propagation @@ -1283,7 +1361,7 @@ class Choices { this.input.addEventListeners(); } - _removeEventListeners() { + _removeEventListeners(): void { const { documentElement } = document; documentElement.removeEventListener('touchend', this._onTouchEnd, true); @@ -1318,10 +1396,7 @@ class Choices { this.input.removeEventListeners(); } - /** - * @param {KeyboardEvent} event - */ - _onKeyDown(event) { + _onKeyDown(event: KeyboardEvent): void { const { keyCode } = event; const { activeItems } = this._store; const hasFocusedInput = this.input.isFocussed; @@ -1355,31 +1430,29 @@ class Choices { } } - // Map keys to key actions - const keyDownActions = { - [A_KEY]: this._onAKey, - [ENTER_KEY]: this._onEnterKey, - [ESC_KEY]: this._onEscapeKey, - [UP_KEY]: this._onDirectionKey, - [PAGE_UP_KEY]: this._onDirectionKey, - [DOWN_KEY]: this._onDirectionKey, - [PAGE_DOWN_KEY]: this._onDirectionKey, - [DELETE_KEY]: this._onDeleteKey, - [BACK_KEY]: this._onDeleteKey, - }; - - if (keyDownActions[keyCode]) { - keyDownActions[keyCode]({ - event, - activeItems, - hasFocusedInput, - hasActiveDropdown, - hasItems, - }); + switch (keyCode) { + case A_KEY: + return this._onSelectKey(event, hasItems); + case ENTER_KEY: + return this._onEnterKey(event, activeItems, hasActiveDropdown); + case ESC_KEY: + return this._onEscapeKey(hasActiveDropdown); + case UP_KEY: + case PAGE_UP_KEY: + case DOWN_KEY: + case PAGE_DOWN_KEY: + return this._onDirectionKey(event, hasActiveDropdown); + case DELETE_KEY: + case BACK_KEY: + return this._onDeleteKey(event, activeItems, hasFocusedInput); + default: } } - _onKeyUp({ target, keyCode }) { + _onKeyUp({ + target, + keyCode, + }: Pick): void { const { value } = this.input; const { activeItems } = this._store; const canAddItem = this._canAddItem(activeItems, value); @@ -1399,7 +1472,8 @@ class Choices { } } else { const wasRemovalKeyCode = keyCode === backKey || keyCode === deleteKey; - const userHasRemovedValue = wasRemovalKeyCode && !target.value; + const userHasRemovedValue = + wasRemovalKeyCode && target && !(target as HTMLSelectElement).value; const canReactivateChoices = !this._isTextElement && this._isSearching; const canSearch = this._canSearch && canAddItem.response; @@ -1414,7 +1488,7 @@ class Choices { this._canSearch = this.config.searchEnabled; } - _onAKey({ event, hasItems }) { + _onSelectKey(event: KeyboardEvent, hasItems: boolean): void { const { ctrlKey, metaKey } = event; const hasCtrlDownKeyPressed = ctrlKey || metaKey; @@ -1433,12 +1507,17 @@ class Choices { } } - _onEnterKey({ event, activeItems, hasActiveDropdown }) { + _onEnterKey( + event: KeyboardEvent, + activeItems: Item[], + hasActiveDropdown: boolean, + ): void { const { target } = event; const { ENTER_KEY: enterKey } = KEY_CODES; - const targetWasButton = target.hasAttribute('data-button'); + const targetWasButton = + target && (target as HTMLElement).hasAttribute('data-button'); - if (this._isTextElement && target.value) { + if (this._isTextElement && target && (target as HTMLInputElement).value) { const { value } = this.input; const canAddItem = this._canAddItem(activeItems, value); @@ -1451,7 +1530,7 @@ class Choices { } if (targetWasButton) { - this._handleButtonAction(activeItems, target); + this._handleButtonAction(activeItems, target as HTMLElement); event.preventDefault(); } @@ -1475,14 +1554,14 @@ class Choices { } } - _onEscapeKey({ hasActiveDropdown }) { + _onEscapeKey(hasActiveDropdown: boolean): void { if (hasActiveDropdown) { this.hideDropdown(true); this.containerOuter.focus(); } } - _onDirectionKey({ event, hasActiveDropdown }) { + _onDirectionKey(event: KeyboardEvent, hasActiveDropdown: boolean): void { const { keyCode, metaKey } = event; const { DOWN_KEY: downKey, @@ -1546,25 +1625,33 @@ class Choices { } } - _onDeleteKey({ event, hasFocusedInput, activeItems }) { + _onDeleteKey( + event: KeyboardEvent, + activeItems: Item[], + hasFocusedInput: boolean, + ): void { const { target } = event; // If backspace or delete key is pressed and the input has no value - if (hasFocusedInput && !target.value && !this._isSelectOneElement) { + if ( + !this._isSelectOneElement && + !(target as HTMLInputElement).value && + hasFocusedInput + ) { this._handleBackspace(activeItems); event.preventDefault(); } } - _onTouchMove() { + _onTouchMove(): void { if (this._wasTap) { this._wasTap = false; } } - _onTouchEnd(event) { - const { target } = event || event.touches[0]; + _onTouchEnd(event: TouchEvent): void { + const { target } = event || (event as TouchEvent).touches[0]; const touchWasWithinContainer = - this._wasTap && this.containerOuter.element.contains(target); + this._wasTap && this.containerOuter.element.contains(target as Node); if (touchWasWithinContainer) { const containerWasExactTarget = @@ -1588,9 +1675,8 @@ class Choices { /** * Handles mousedown event in capture mode for containetOuter.element - * @param {MouseEvent} event */ - _onMouseDown(event) { + _onMouseDown(event: MouseEvent): void { const { target } = event; if (!(target instanceof HTMLElement)) { return; @@ -1599,8 +1685,9 @@ class Choices { // If we have our mouse down on the scrollbar and are on IE11... if (IS_IE11 && this.choiceList.element.contains(target)) { // check if click was on a scrollbar area - const firstChoice = /** @type {HTMLElement} */ (this.choiceList.element - .firstElementChild); + const firstChoice = this.choiceList.element + .firstElementChild as HTMLElement; + const isOnScrollbar = this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth @@ -1634,15 +1721,15 @@ class Choices { * Handles mouseover event over this.dropdown * @param {MouseEvent} event */ - _onMouseOver({ target }) { + _onMouseOver({ target }: Pick): void { if (target instanceof HTMLElement && 'choice' in target.dataset) { this._highlightChoice(target); } } - _onClick({ target }) { + _onClick({ target }: Pick): void { const clickWasWithinContainer = this.containerOuter.element.contains( - target, + target as Node, ); if (clickWasWithinContainer) { @@ -1658,7 +1745,7 @@ class Choices { } else if ( this._isSelectOneElement && target !== this.input.element && - !this.dropdown.element.contains(target) + !this.dropdown.element.contains(target as Node) ) { this.hideDropdown(); } @@ -1674,28 +1761,27 @@ class Choices { } } - _onFocus({ target }) { - const focusWasWithinContainer = this.containerOuter.element.contains( - target, - ); + _onFocus({ target }: Pick): void { + const focusWasWithinContainer = + target && this.containerOuter.element.contains(target as Node); if (!focusWasWithinContainer) { return; } const focusActions = { - [TEXT_TYPE]: () => { + [TEXT_TYPE]: (): void => { if (target === this.input.element) { this.containerOuter.addFocusState(); } }, - [SELECT_ONE_TYPE]: () => { + [SELECT_ONE_TYPE]: (): void => { this.containerOuter.addFocusState(); if (target === this.input.element) { this.showDropdown(true); } }, - [SELECT_MULTIPLE_TYPE]: () => { + [SELECT_MULTIPLE_TYPE]: (): void => { if (target === this.input.element) { this.showDropdown(true); // If element is a select box, the focused element is the container and the dropdown @@ -1708,14 +1794,15 @@ class Choices { focusActions[this.passedElement.element.type](); } - _onBlur({ target }) { - const blurWasWithinContainer = this.containerOuter.element.contains(target); + _onBlur({ target }: Pick): void { + const blurWasWithinContainer = + target && this.containerOuter.element.contains(target as Node); if (blurWasWithinContainer && !this._isScrollingOnIe) { const { activeItems } = this._store; const hasHighlightedItems = activeItems.some(item => item.highlighted); const blurActions = { - [TEXT_TYPE]: () => { + [TEXT_TYPE]: (): void => { if (target === this.input.element) { this.containerOuter.removeFocusState(); if (hasHighlightedItems) { @@ -1724,7 +1811,7 @@ class Choices { this.hideDropdown(true); } }, - [SELECT_ONE_TYPE]: () => { + [SELECT_ONE_TYPE]: (): void => { this.containerOuter.removeFocusState(); if ( target === this.input.element || @@ -1733,7 +1820,7 @@ class Choices { this.hideDropdown(true); } }, - [SELECT_MULTIPLE_TYPE]: () => { + [SELECT_MULTIPLE_TYPE]: (): void => { if (target === this.input.element) { this.containerOuter.removeFocusState(); this.hideDropdown(true); @@ -1754,12 +1841,12 @@ class Choices { } } - _onFormReset() { + _onFormReset(): void { this._store.dispatch(resetTo(this._initialState)); } - _highlightChoice(el = null) { - const choices = Array.from( + _highlightChoice(el: HTMLElement | null = null): void { + const choices: HTMLElement[] = Array.from( this.dropdown.element.querySelectorAll('[data-choice-selectable]'), ); @@ -1814,14 +1901,20 @@ class Choices { label = null, choiceId = -1, groupId = -1, - customProperties = null, + customProperties = {}, placeholder = false, - keyCode = null, - }) { + keyCode = -1, + }: { + value: string; + label?: string | null; + choiceId?: number; + groupId?: number; + customProperties?: object; + placeholder?: boolean; + keyCode?: number; + }): void { let passedValue = typeof value === 'string' ? value.trim() : value; - const passedKeyCode = keyCode; - const passedCustomProperties = customProperties; const { items } = this._store; const passedLabel = label || passedValue; const passedOptionId = choiceId || -1; @@ -1847,7 +1940,7 @@ class Choices { groupId, customProperties, placeholder, - keyCode: passedKeyCode, + keyCode, }), ); @@ -1860,18 +1953,20 @@ class Choices { id, value: passedValue, label: passedLabel, - customProperties: passedCustomProperties, + customProperties, groupValue: group && group.value ? group.value : null, - keyCode: passedKeyCode, + keyCode, }); } - /** - * @param {Item} item - */ - _removeItem(item) { + _removeItem(item: Item): void { const { id, value, label, customProperties, choiceId, groupId } = item; - const group = groupId >= 0 ? this._store.getGroupById(groupId) : null; + const group = + groupId && groupId >= 0 ? this._store.getGroupById(groupId) : null; + + if (!id || !choiceId) { + return; + } this._store.dispatch(removeItem(id, choiceId)); this.passedElement.triggerEvent(EVENTS.removeItem, { @@ -1889,10 +1984,19 @@ class Choices { isSelected = false, isDisabled = false, groupId = -1, - customProperties = null, + customProperties = {}, placeholder = false, - keyCode = null, - }) { + keyCode = -1, + }: { + value: string; + label?: string | null; + isSelected?: boolean; + isDisabled?: boolean; + groupId?: number; + customProperties?: Record; + placeholder?: boolean; + keyCode?: number; + }): void { if (typeof value === 'undefined' || value === null) { return; } @@ -1929,8 +2033,8 @@ class Choices { } } - _addGroup({ group, id, valueKey = 'value', labelKey = 'label' }) { - const groupChoices = isType('Object', group) + _addGroup({ group, id, valueKey = 'value', labelKey = 'label' }): void { + const groupChoices: Choice[] | HTMLOptionElement[] = isType('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION')); const groupId = id || Math.floor(new Date().valueOf() * Math.random()); @@ -1946,7 +2050,7 @@ class Choices { }), ); - const addGroupChoices = choice => { + const addGroupChoices = (choice: any): void => { const isOptDisabled = choice.disabled || (choice.parentNode && choice.parentNode.disabled); @@ -1974,17 +2078,13 @@ class Choices { } } - _getTemplate(template, ...args) { - if (!template) { - return null; - } - + _getTemplate(template: string, ...args: any): any { const { classNames } = this.config; return this._templates[template].call(this, classNames, ...args); } - _createTemplates() { + _createTemplates(): void { const { callbackOnCreateTemplates } = this.config; let userTemplates = {}; @@ -1995,10 +2095,10 @@ class Choices { userTemplates = callbackOnCreateTemplates.call(this, strToEl); } - this._templates = merge(TEMPLATES, userTemplates); + this._templates = merge(templates, userTemplates); } - _createElements() { + _createElements(): void { this.containerOuter = new Container({ element: this._getTemplate( 'containerOuter', @@ -2009,21 +2109,21 @@ class Choices { this.passedElement.element.type, ), classNames: this.config.classNames, - type: this.passedElement.element.type, + type: this.passedElement.element.type as PassedElement['type'], position: this.config.position, }); this.containerInner = new Container({ element: this._getTemplate('containerInner'), classNames: this.config.classNames, - type: this.passedElement.element.type, + type: this.passedElement.element.type as PassedElement['type'], position: this.config.position, }); this.input = new Input({ element: this._getTemplate('input', this._placeholderValue), classNames: this.config.classNames, - type: this.passedElement.element.type, + type: this.passedElement.element.type as PassedElement['type'], preventPaste: !this.config.paste, }); @@ -2038,11 +2138,11 @@ class Choices { this.dropdown = new Dropdown({ element: this._getTemplate('dropdown'), classNames: this.config.classNames, - type: this.passedElement.element.type, + type: this.passedElement.element.type as PassedElement['type'], }); } - _createStructure() { + _createStructure(): void { // Hide original element this.passedElement.conceal(); // Wrap input in container preserving DOM ordering @@ -2093,12 +2193,17 @@ class Choices { } } - _addPredefinedGroups(groups) { + _addPredefinedGroups( + groups: Group[] | HTMLOptGroupElement[] | Element[], + ): void { // If we have a placeholder option - const placeholderChoice = this.passedElement.placeholderOption; + const placeholderChoice = (this.passedElement as WrappedSelect) + .placeholderOption; + if ( placeholderChoice && - placeholderChoice.parentNode.tagName === 'SELECT' + placeholderChoice.parentNode && + (placeholderChoice.parentNode as HTMLElement).tagName === 'SELECT' ) { this._addChoice({ value: placeholderChoice.value, @@ -2117,7 +2222,7 @@ class Choices { ); } - _addPredefinedChoices(choices) { + _addPredefinedChoices(choices: Partial[]): void { // If sorting is enabled or the user is searching, filter choices if (this.config.shouldSort) { choices.sort(this.config.sorter); @@ -2129,7 +2234,7 @@ class Choices { ); choices.forEach((choice, index) => { - const { value, label, customProperties, placeholder } = choice; + const { value = '', label, customProperties, placeholder } = choice; if (this._isSelectElement) { // If the choice is actually a group @@ -2153,32 +2258,31 @@ class Choices { const isSelected = shouldPreselect ? true : choice.selected; const isDisabled = choice.disabled; + console.log(isDisabled, choice); + this._addChoice({ value, label, - isSelected, - isDisabled, + isSelected: !!isSelected, + isDisabled: !!isDisabled, + placeholder: !!placeholder, customProperties, - placeholder, }); } } else { this._addChoice({ value, label, - isSelected: choice.selected, - isDisabled: choice.disabled, + isSelected: !!choice.selected, + isDisabled: !!choice.disabled, + placeholder: !!choice.placeholder, customProperties, - placeholder, }); } }); } - /** - * @param {Item[]} items - */ - _addPredefinedItems(items) { + _addPredefinedItems(items: Item[] | string[]): void { items.forEach(item => { if (typeof item === 'object' && item.value) { this._addItem({ @@ -2198,10 +2302,10 @@ class Choices { }); } - _setChoiceOrItem(item) { + _setChoiceOrItem(item: any): void { const itemType = getType(item).toLowerCase(); const handleType = { - object: () => { + object: (): void => { if (!item.value) { return; } @@ -2227,7 +2331,7 @@ class Choices { }); } }, - string: () => { + string: (): void => { if (!this._isTextElement) { this._addChoice({ value: item, @@ -2246,11 +2350,11 @@ class Choices { handleType[itemType](); } - _findAndSelectChoiceByValue(val) { + _findAndSelectChoiceByValue(value: string): void { const { choices } = this._store; // Check 'value' property exists and the choice isn't already selected const foundChoice = choices.find(choice => - this.config.valueComparer(choice.value, val), + this.config.valueComparer(choice.value, value), ); if (foundChoice && !foundChoice.selected) { @@ -2266,11 +2370,14 @@ class Choices { } } - _generatePlaceholderValue() { - if (this._isSelectElement) { - const { placeholderOption } = this.passedElement; + _generatePlaceholderValue(): string | null { + if ( + this._isSelectElement && + (this.passedElement as WrappedSelect).placeholderOption + ) { + const { placeholderOption } = this.passedElement as WrappedSelect; - return placeholderOption ? placeholderOption.text : false; + return placeholderOption ? placeholderOption.text : null; } const { placeholder, placeholderValue } = this.config; @@ -2288,7 +2395,7 @@ class Choices { } } - return false; + return null; } } diff --git a/src/scripts/components/container.test.js b/src/scripts/components/container.test.ts similarity index 98% rename from src/scripts/components/container.test.js rename to src/scripts/components/container.test.ts index a10cb97..065576e 100644 --- a/src/scripts/components/container.test.js +++ b/src/scripts/components/container.test.ts @@ -13,7 +13,7 @@ describe('components/container', () => { document.body.appendChild(element); instance = new Container({ - element: document.getElementById('container'), + element: document.getElementById('container') as HTMLElement, classNames: DEFAULT_CLASSNAMES, position: 'auto', type: 'text', @@ -383,7 +383,7 @@ describe('components/container', () => { }); afterEach(() => { - document.getElementById('wrap-test').remove(); + document.getElementById('wrap-test')!.remove(); }); it('wraps passed element inside element', () => { @@ -406,7 +406,7 @@ describe('components/container', () => { }); afterEach(() => { - document.body.removeChild(document.getElementById('unwrap-test')); + document.body.removeChild(document.getElementById('unwrap-test') as Node); }); it('moves wrapped element outside of element', () => { diff --git a/src/scripts/components/container.js b/src/scripts/components/container.ts similarity index 70% rename from src/scripts/components/container.js rename to src/scripts/components/container.ts index 9867d67..6413615 100644 --- a/src/scripts/components/container.js +++ b/src/scripts/components/container.ts @@ -1,20 +1,29 @@ import { wrap } from '../lib/utils'; import { SELECT_ONE_TYPE } from '../constants'; +import { PassedElement, ClassNames, Options } from '../interfaces'; -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ export default class Container { - /** - * @param {{ - * element: HTMLElement, - * type: passedElement['type'], - * classNames: ClassNames, - * position - * }} args - */ - constructor({ element, type, classNames, position }) { + element: HTMLElement; + type: PassedElement['type']; + classNames: ClassNames; + position: Options['position']; + isOpen: boolean; + isFlipped: boolean; + isFocussed: boolean; + isDisabled: boolean; + isLoading: boolean; + + constructor({ + element, + type, + classNames, + position, + }: { + element: HTMLElement; + type: PassedElement['type']; + classNames: ClassNames; + position: Options['position']; + }) { this.element = element; this.classNames = classNames; this.type = type; @@ -28,12 +37,12 @@ export default class Container { this._onBlur = this._onBlur.bind(this); } - addEventListeners() { + addEventListeners(): void { this.element.addEventListener('focus', this._onFocus); this.element.addEventListener('blur', this._onBlur); } - removeEventListeners() { + removeEventListeners(): void { this.element.removeEventListener('focus', this._onFocus); this.element.removeEventListener('blur', this._onBlur); } @@ -41,10 +50,8 @@ export default class Container { /** * Determine whether container should be flipped based on passed * dropdown position - * @param {number} dropdownPos - * @returns {boolean} */ - shouldFlip(dropdownPos) { + shouldFlip(dropdownPos: number): boolean { if (typeof dropdownPos !== 'number') { return false; } @@ -62,21 +69,15 @@ export default class Container { return shouldFlip; } - /** - * @param {string} activeDescendantID - */ - setActiveDescendant(activeDescendantID) { + setActiveDescendant(activeDescendantID: string): void { this.element.setAttribute('aria-activedescendant', activeDescendantID); } - removeActiveDescendant() { + removeActiveDescendant(): void { this.element.removeAttribute('aria-activedescendant'); } - /** - * @param {number} dropdownPos - */ - open(dropdownPos) { + open(dropdownPos: number): void { this.element.classList.add(this.classNames.openState); this.element.setAttribute('aria-expanded', 'true'); this.isOpen = true; @@ -87,7 +88,7 @@ export default class Container { } } - close() { + close(): void { this.element.classList.remove(this.classNames.openState); this.element.setAttribute('aria-expanded', 'false'); this.removeActiveDescendant(); @@ -100,21 +101,21 @@ export default class Container { } } - focus() { + focus(): void { if (!this.isFocussed) { this.element.focus(); } } - addFocusState() { + addFocusState(): void { this.element.classList.add(this.classNames.focusState); } - removeFocusState() { + removeFocusState(): void { this.element.classList.remove(this.classNames.focusState); } - enable() { + enable(): void { this.element.classList.remove(this.classNames.disabledState); this.element.removeAttribute('aria-disabled'); if (this.type === SELECT_ONE_TYPE) { @@ -123,7 +124,7 @@ export default class Container { this.isDisabled = false; } - disable() { + disable(): void { this.element.classList.add(this.classNames.disabledState); this.element.setAttribute('aria-disabled', 'true'); if (this.type === SELECT_ONE_TYPE) { @@ -132,40 +133,36 @@ export default class Container { this.isDisabled = true; } - /** - * @param {HTMLElement} element - */ - wrap(element) { + wrap(element: HTMLSelectElement | HTMLInputElement | HTMLElement): void { wrap(element, this.element); } - /** - * @param {Element} element - */ - unwrap(element) { - // Move passed element outside this element - this.element.parentNode.insertBefore(element, this.element); - // Remove this element - this.element.parentNode.removeChild(this.element); + unwrap(element: HTMLElement): void { + if (this.element.parentNode) { + // Move passed element outside this element + this.element.parentNode.insertBefore(element, this.element); + // Remove this element + this.element.parentNode.removeChild(this.element); + } } - addLoadingState() { + addLoadingState(): void { this.element.classList.add(this.classNames.loadingState); this.element.setAttribute('aria-busy', 'true'); this.isLoading = true; } - removeLoadingState() { + removeLoadingState(): void { this.element.classList.remove(this.classNames.loadingState); this.element.removeAttribute('aria-busy'); this.isLoading = false; } - _onFocus() { + _onFocus(): void { this.isFocussed = true; } - _onBlur() { + _onBlur(): void { this.isFocussed = false; } } diff --git a/src/scripts/components/dropdown.test.js b/src/scripts/components/dropdown.test.ts similarity index 100% rename from src/scripts/components/dropdown.test.js rename to src/scripts/components/dropdown.test.ts diff --git a/src/scripts/components/dropdown.js b/src/scripts/components/dropdown.ts similarity index 55% rename from src/scripts/components/dropdown.js rename to src/scripts/components/dropdown.ts index 78d55f4..ea188ae 100644 --- a/src/scripts/components/dropdown.js +++ b/src/scripts/components/dropdown.ts @@ -1,17 +1,20 @@ -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ +import { PassedElement, ClassNames } from '../interfaces'; export default class Dropdown { - /** - * @param {{ - * element: HTMLElement, - * type: passedElement['type'], - * classNames: ClassNames, - * }} args - */ - constructor({ element, type, classNames }) { + element: HTMLElement; + type: PassedElement['type']; + classNames: ClassNames; + isActive: boolean; + + constructor({ + element, + type, + classNames, + }: { + element: HTMLElement; + type: PassedElement['type']; + classNames: ClassNames; + }) { this.element = element; this.classNames = classNames; this.type = type; @@ -20,26 +23,19 @@ export default class Dropdown { /** * Bottom position of dropdown in viewport coordinates - * @returns {number} Vertical position */ - get distanceFromTopWindow() { + get distanceFromTopWindow(): number { return this.element.getBoundingClientRect().bottom; } - /** - * Find element that matches passed selector - * @param {string} selector - * @returns {HTMLElement | null} - */ - getChild(selector) { + getChild(selector: string): HTMLElement | null { return this.element.querySelector(selector); } /** * Show dropdown to user by adding active state class - * @returns {this} */ - show() { + show(): this { this.element.classList.add(this.classNames.activeState); this.element.setAttribute('aria-expanded', 'true'); this.isActive = true; @@ -49,9 +45,8 @@ export default class Dropdown { /** * Hide dropdown from user - * @returns {this} */ - hide() { + hide(): this { this.element.classList.remove(this.classNames.activeState); this.element.setAttribute('aria-expanded', 'false'); this.isActive = false; diff --git a/src/scripts/components/index.js b/src/scripts/components/index.ts similarity index 100% rename from src/scripts/components/index.js rename to src/scripts/components/index.ts diff --git a/src/scripts/components/input.test.js b/src/scripts/components/input.test.ts similarity index 99% rename from src/scripts/components/input.test.js rename to src/scripts/components/input.test.ts index 3ea3d71..9f3f394 100644 --- a/src/scripts/components/input.test.js +++ b/src/scripts/components/input.test.ts @@ -13,7 +13,6 @@ describe('components/input', () => { element: choicesElement, type: 'text', classNames: DEFAULT_CLASSNAMES, - placeholderValue: null, preventPaste: false, }); }); @@ -49,7 +48,7 @@ describe('components/input', () => { expect(['input', 'paste', 'focus', 'blur']).to.have.members( Array.from( { length: addEventListenerStub.callCount }, - (v, i) => addEventListenerStub.getCall(i).args[0], + (_, i) => addEventListenerStub.getCall(i).args[0], ), ); }); diff --git a/src/scripts/components/input.js b/src/scripts/components/input.ts similarity index 60% rename from src/scripts/components/input.js rename to src/scripts/components/input.ts index 9f47ff2..8e44def 100644 --- a/src/scripts/components/input.js +++ b/src/scripts/components/input.ts @@ -1,27 +1,32 @@ import { sanitise } from '../lib/utils'; import { SELECT_ONE_TYPE } from '../constants'; - -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ +import { PassedElement, ClassNames } from '../interfaces'; export default class Input { - /** - * @param {{ - * element: HTMLInputElement, - * type: passedElement['type'], - * classNames: ClassNames, - * preventPaste: boolean - * }} args - */ - constructor({ element, type, classNames, preventPaste }) { + element: HTMLInputElement; + type: PassedElement['type']; + classNames: ClassNames; + preventPaste: boolean; + isFocussed: boolean; + isDisabled: boolean; + + constructor({ + element, + type, + classNames, + preventPaste, + }: { + element: HTMLInputElement; + type: PassedElement['type']; + classNames: ClassNames; + preventPaste: boolean; + }) { this.element = element; this.type = type; this.classNames = classNames; this.preventPaste = preventPaste; - this.isFocussed = this.element === document.activeElement; + this.isFocussed = this.element.isEqualNode(document.activeElement); this.isDisabled = element.disabled; this._onPaste = this._onPaste.bind(this); this._onInput = this._onInput.bind(this); @@ -29,28 +34,19 @@ export default class Input { this._onBlur = this._onBlur.bind(this); } - /** - * @param {string} placeholder - */ - set placeholder(placeholder) { + set placeholder(placeholder: string) { this.element.placeholder = placeholder; } - /** - * @returns {string} - */ - get value() { + get value(): string { return sanitise(this.element.value); } - /** - * @param {string} value - */ - set value(value) { + set value(value: string) { this.element.value = value; } - addEventListeners() { + addEventListeners(): void { this.element.addEventListener('paste', this._onPaste); this.element.addEventListener('input', this._onInput, { passive: true, @@ -63,47 +59,36 @@ export default class Input { }); } - removeEventListeners() { - this.element.removeEventListener('input', this._onInput, { - passive: true, - }); + removeEventListeners(): void { + this.element.removeEventListener('input', this._onInput); this.element.removeEventListener('paste', this._onPaste); - this.element.removeEventListener('focus', this._onFocus, { - passive: true, - }); - this.element.removeEventListener('blur', this._onBlur, { - passive: true, - }); + this.element.removeEventListener('focus', this._onFocus); + this.element.removeEventListener('blur', this._onBlur); } - enable() { + enable(): void { this.element.removeAttribute('disabled'); this.isDisabled = false; } - disable() { + disable(): void { this.element.setAttribute('disabled', ''); this.isDisabled = true; } - focus() { + focus(): void { if (!this.isFocussed) { this.element.focus(); } } - blur() { + blur(): void { if (this.isFocussed) { this.element.blur(); } } - /** - * Set value of input to blank - * @param {boolean} setWidth - * @returns {this} - */ - clear(setWidth = true) { + clear(setWidth = true): this { if (this.element.value) { this.element.value = ''; } @@ -119,44 +104,38 @@ export default class Input { * Set the correct input width based on placeholder * value or input value */ - setWidth() { + setWidth(): void { // Resize input to contents or placeholder const { style, value, placeholder } = this.element; style.minWidth = `${placeholder.length + 1}ch`; style.width = `${value.length + 1}ch`; } - /** - * @param {string} activeDescendantID - */ - setActiveDescendant(activeDescendantID) { + setActiveDescendant(activeDescendantID: string): void { this.element.setAttribute('aria-activedescendant', activeDescendantID); } - removeActiveDescendant() { + removeActiveDescendant(): void { this.element.removeAttribute('aria-activedescendant'); } - _onInput() { + _onInput(): void { if (this.type !== SELECT_ONE_TYPE) { this.setWidth(); } } - /** - * @param {Event} event - */ - _onPaste(event) { + _onPaste(event: ClipboardEvent): void { if (this.preventPaste) { event.preventDefault(); } } - _onFocus() { + _onFocus(): void { this.isFocussed = true; } - _onBlur() { + _onBlur(): void { this.isFocussed = false; } } diff --git a/src/scripts/components/list.test.js b/src/scripts/components/list.test.ts similarity index 100% rename from src/scripts/components/list.test.js rename to src/scripts/components/list.test.ts diff --git a/src/scripts/components/list.js b/src/scripts/components/list.ts similarity index 67% rename from src/scripts/components/list.js rename to src/scripts/components/list.ts index 2474b92..26facb0 100644 --- a/src/scripts/components/list.js +++ b/src/scripts/components/list.ts @@ -1,53 +1,37 @@ import { SCROLLING_SPEED } from '../constants'; -/** - * @typedef {import('../../../types/index').Choices.Choice} Choice - */ export default class List { - /** - * @param {{ element: HTMLElement }} args - */ - constructor({ element }) { + element: HTMLElement; + scrollPos: number; + height: number; + + constructor({ element }: { element: HTMLElement }) { this.element = element; this.scrollPos = this.element.scrollTop; this.height = this.element.offsetHeight; } - clear() { + clear(): void { this.element.innerHTML = ''; } - /** - * @param {Element | DocumentFragment} node - */ - append(node) { + append(node: Element | DocumentFragment): void { this.element.appendChild(node); } - /** - * @param {string} selector - * @returns {Element | null} - */ - getChild(selector) { + getChild(selector: string): HTMLElement | null { return this.element.querySelector(selector); } - /** - * @returns {boolean} - */ - hasChildren() { + hasChildren(): boolean { return this.element.hasChildNodes(); } - scrollToTop() { + scrollToTop(): void { this.element.scrollTop = 0; } - /** - * @param {Element} element - * @param {1 | -1} direction - */ - scrollToChildElement(element, direction) { + scrollToChildElement(element: HTMLElement, direction: 1 | -1): void { if (!element) { return; } @@ -71,35 +55,21 @@ export default class List { }); } - /** - * @param {number} scrollPos - * @param {number} strength - * @param {number} destination - */ - _scrollDown(scrollPos, strength, destination) { + _scrollDown(scrollPos: number, strength: number, destination: number): void { const easing = (destination - scrollPos) / strength; const distance = easing > 1 ? easing : 1; this.element.scrollTop = scrollPos + distance; } - /** - * @param {number} scrollPos - * @param {number} strength - * @param {number} destination - */ - _scrollUp(scrollPos, strength, destination) { + _scrollUp(scrollPos: number, strength: number, destination: number): void { const easing = (scrollPos - destination) / strength; const distance = easing > 1 ? easing : 1; this.element.scrollTop = scrollPos - distance; } - /** - * @param {*} destination - * @param {*} direction - */ - _animateScroll(destination, direction) { + _animateScroll(destination: number, direction: number): void { const strength = SCROLLING_SPEED; const choiceListScrollTop = this.element.scrollTop; let continueAnimation = false; diff --git a/src/scripts/components/wrapped-element.test.js b/src/scripts/components/wrapped-element.test.ts similarity index 100% rename from src/scripts/components/wrapped-element.test.js rename to src/scripts/components/wrapped-element.test.ts diff --git a/src/scripts/components/wrapped-element.js b/src/scripts/components/wrapped-element.ts similarity index 82% rename from src/scripts/components/wrapped-element.js rename to src/scripts/components/wrapped-element.ts index c42e3b8..17af9dc 100644 --- a/src/scripts/components/wrapped-element.js +++ b/src/scripts/components/wrapped-element.ts @@ -1,17 +1,11 @@ import { dispatchEvent } from '../lib/utils'; - -/** - * @typedef {import('../../../types/index').Choices.passedElement} passedElement - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - */ +import { ClassNames, EventMap } from '../interfaces'; export default class WrappedElement { - /** - * @param {{ - * element: HTMLInputElement | HTMLSelectElement, - * classNames: ClassNames, - * }} args - */ + element: HTMLInputElement | HTMLSelectElement; + classNames: ClassNames; + isDisabled: boolean; + constructor({ element, classNames }) { this.element = element; this.classNames = classNames; @@ -26,24 +20,24 @@ export default class WrappedElement { this.isDisabled = false; } - get isActive() { + get isActive(): boolean { return this.element.dataset.choice === 'active'; } - get dir() { + get dir(): string { return this.element.dir; } - get value() { + get value(): string { return this.element.value; } - set value(value) { + set value(value: string) { // you must define setter here otherwise it will be readonly property this.element.value = value; } - conceal() { + conceal(): void { // Hide passed input this.element.classList.add(this.classNames.input); this.element.hidden = true; @@ -61,7 +55,7 @@ export default class WrappedElement { this.element.setAttribute('data-choice', 'active'); } - reveal() { + reveal(): void { // Reinstate passed element this.element.classList.remove(this.classNames.input); this.element.hidden = false; @@ -83,19 +77,19 @@ export default class WrappedElement { this.element.value = this.element.value; // eslint-disable-line no-self-assign } - enable() { + enable(): void { this.element.removeAttribute('disabled'); this.element.disabled = false; this.isDisabled = false; } - disable() { + disable(): void { this.element.setAttribute('disabled', ''); this.element.disabled = true; this.isDisabled = true; } - triggerEvent(eventType, data) { + triggerEvent(eventType: K, data?: object): void { dispatchEvent(this.element, eventType, data); } } diff --git a/src/scripts/components/wrapped-input.js b/src/scripts/components/wrapped-input.js deleted file mode 100644 index 8bf2545..0000000 --- a/src/scripts/components/wrapped-input.js +++ /dev/null @@ -1,38 +0,0 @@ -import WrappedElement from './wrapped-element'; - -/** - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../../types/index').Choices.Item} Item - */ - -export default class WrappedInput extends WrappedElement { - /** - * @param {{ - * element: HTMLInputElement, - * classNames: ClassNames, - * delimiter: string - * }} args - */ - constructor({ element, classNames, delimiter }) { - super({ element, classNames }); - this.delimiter = delimiter; - } - - /** - * @returns {string} - */ - get value() { - return this.element.value; - } - - /** - * @param {Item[]} items - */ - set value(items) { - const itemValues = items.map(({ value }) => value); - const joinedValues = itemValues.join(this.delimiter); - - this.element.setAttribute('value', joinedValues); - this.element.value = joinedValues; - } -} diff --git a/src/scripts/components/wrapped-input.test.js b/src/scripts/components/wrapped-input.test.ts similarity index 72% rename from src/scripts/components/wrapped-input.test.js rename to src/scripts/components/wrapped-input.test.ts index 48adf84..36426f0 100644 --- a/src/scripts/components/wrapped-input.test.js +++ b/src/scripts/components/wrapped-input.test.ts @@ -34,10 +34,12 @@ describe('components/wrappedInput', () => { }); describe('inherited methods', () => { - ['conceal', 'reveal', 'enable', 'disable'].forEach(method => { + const methods: string[] = ['conceal', 'reveal', 'enable', 'disable']; + + methods.forEach(method => { describe(method, () => { beforeEach(() => { - stub(WrappedElement.prototype, method); + stub(WrappedElement.prototype, method as keyof WrappedElement); }); afterEach(() => { @@ -54,27 +56,11 @@ describe('components/wrappedInput', () => { }); describe('value setter', () => { - const data = [ - { - id: 'ID 1', - value: 'Value 1', - }, - { - id: 'ID 2', - value: 'Value 2', - }, - { - id: 'ID 3', - value: 'Value 3', - }, - ]; - - it('sets delimited value of element based on passed data', () => { + it('sets the value of the input to the given value', () => { + const newValue = 'Value 1, Value 2, Value 3'; expect(instance.element.value).to.equal(''); - instance.value = data; - expect(instance.value).to.equal( - `Value 1${delimiter}Value 2${delimiter}Value 3`, - ); + instance.value = newValue; + expect(instance.value).to.equal(newValue); }); }); }); diff --git a/src/scripts/components/wrapped-input.ts b/src/scripts/components/wrapped-input.ts new file mode 100644 index 0000000..b5a1c98 --- /dev/null +++ b/src/scripts/components/wrapped-input.ts @@ -0,0 +1,29 @@ +import WrappedElement from './wrapped-element'; +import { ClassNames } from '../interfaces'; + +export default class WrappedInput extends WrappedElement { + element: HTMLInputElement; + delimiter: string; + + constructor({ + element, + classNames, + delimiter, + }: { + element: HTMLInputElement; + classNames: ClassNames; + delimiter: string; + }) { + super({ element, classNames }); + this.delimiter = delimiter; + } + + get value(): string { + return this.element.value; + } + + set value(value: string) { + this.element.setAttribute('value', value); + this.element.value = value; + } +} diff --git a/src/scripts/components/wrapped-select.test.js b/src/scripts/components/wrapped-select.test.ts similarity index 95% rename from src/scripts/components/wrapped-select.test.js rename to src/scripts/components/wrapped-select.test.ts index 58efd3d..4f723e6 100644 --- a/src/scripts/components/wrapped-select.test.js +++ b/src/scripts/components/wrapped-select.test.ts @@ -32,7 +32,7 @@ describe('components/wrappedSelect', () => { document.body.appendChild(element); instance = new WrappedSelect({ - element: document.getElementById('target'), + element: document.getElementById('target') as HTMLSelectElement, classNames: DEFAULT_CLASSNAMES, template: spy(Templates.option), }); @@ -54,9 +54,11 @@ describe('components/wrappedSelect', () => { }); describe('inherited methods', () => { - ['conceal', 'reveal', 'enable', 'disable'].forEach(method => { + const methods: string[] = ['conceal', 'reveal', 'enable', 'disable']; + + methods.forEach(method => { beforeEach(() => { - stub(WrappedElement.prototype, method); + stub(WrappedElement.prototype, method as keyof WrappedElement); }); afterEach(() => { diff --git a/src/scripts/components/wrapped-select.js b/src/scripts/components/wrapped-select.ts similarity index 56% rename from src/scripts/components/wrapped-select.js rename to src/scripts/components/wrapped-select.ts index 35671a1..eb82eeb 100644 --- a/src/scripts/components/wrapped-select.js +++ b/src/scripts/components/wrapped-select.ts @@ -1,26 +1,25 @@ import WrappedElement from './wrapped-element'; - -/** - * @typedef {import('../../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../../types/index').Choices.Item} Item - * @typedef {import('../../../types/index').Choices.Choice} Choice - */ +import { ClassNames, Item } from '../interfaces'; export default class WrappedSelect extends WrappedElement { - /** - * @param {{ - * element: HTMLSelectElement, - * classNames: ClassNames, - * delimiter: string - * template: function - * }} args - */ - constructor({ element, classNames, template }) { + element: HTMLSelectElement; + classNames: ClassNames; + template: (data: object) => HTMLOptionElement; + + constructor({ + element, + classNames, + template, + }: { + element: HTMLSelectElement; + classNames: ClassNames; + template: (data: object) => HTMLOptionElement; + }) { super({ element, classNames }); this.template = template; } - get placeholderOption() { + get placeholderOption(): HTMLOptionElement | null { return ( this.element.querySelector('option[value=""]') || // Backward compatibility layer for the non-standard placeholder attribute supported in older versions. @@ -28,26 +27,17 @@ export default class WrappedSelect extends WrappedElement { ); } - /** - * @returns {Element[]} - */ - get optionGroups() { + get optionGroups(): Element[] { return Array.from(this.element.getElementsByTagName('OPTGROUP')); } - /** - * @returns {Item[] | Choice[]} - */ - get options() { + get options(): Item[] | HTMLOptionElement[] { return Array.from(this.element.options); } - /** - * @param {Item[] | Choice[]} options - */ - set options(options) { + set options(options: Item[] | HTMLOptionElement[]) { const fragment = document.createDocumentFragment(); - const addOptionToFragment = data => { + const addOptionToFragment = (data): void => { // Create a standard select option const option = this.template(data); // Append it to fragment @@ -60,10 +50,7 @@ export default class WrappedSelect extends WrappedElement { this.appendDocFragment(fragment); } - /** - * @param {DocumentFragment} fragment - */ - appendDocFragment(fragment) { + appendDocFragment(fragment: DocumentFragment): void { this.element.innerHTML = ''; this.element.appendChild(fragment); } diff --git a/src/scripts/constants.test.js b/src/scripts/constants.test.ts similarity index 98% rename from src/scripts/constants.test.js rename to src/scripts/constants.test.ts index 3579dcb..f415bc6 100644 --- a/src/scripts/constants.test.js +++ b/src/scripts/constants.test.ts @@ -104,6 +104,7 @@ describe('constants', () => { 'removeItem', 'highlightItem', 'highlightChoice', + 'unhighlightItem', ]); }); }); @@ -121,6 +122,8 @@ describe('constants', () => { 'REMOVE_ITEM', 'HIGHLIGHT_ITEM', 'CLEAR_ALL', + 'RESET_TO', + 'SET_IS_LOADING', ]); }); }); diff --git a/src/scripts/constants.js b/src/scripts/constants.ts similarity index 81% rename from src/scripts/constants.js rename to src/scripts/constants.ts index 5718c1c..e833807 100644 --- a/src/scripts/constants.js +++ b/src/scripts/constants.ts @@ -1,12 +1,13 @@ import { sanitise, sortByAlpha } from './lib/utils'; +import { + Options, + ClassNames, + EventMap, + ActionType, + KeyCodeMap, +} from './interfaces'; -/** - * @typedef {import('../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../types/index').Choices.Options} Options - */ - -/** @type {ClassNames} */ -export const DEFAULT_CLASSNAMES = { +export const DEFAULT_CLASSNAMES: ClassNames = { containerOuter: 'choices', containerInner: 'choices__inner', input: 'choices__input', @@ -35,8 +36,7 @@ export const DEFAULT_CLASSNAMES = { noChoices: 'has-no-choices', }; -/** @type {Options} */ -export const DEFAULT_CONFIG = { +export const DEFAULT_CONFIG: Options = { items: [], choices: [], silent: false, @@ -83,7 +83,7 @@ export const DEFAULT_CONFIG = { classNames: DEFAULT_CLASSNAMES, }; -export const EVENTS = { +export const EVENTS: Record = { showDropdown: 'showDropdown', hideDropdown: 'hideDropdown', change: 'change', @@ -93,9 +93,10 @@ export const EVENTS = { removeItem: 'removeItem', highlightItem: 'highlightItem', highlightChoice: 'highlightChoice', + unhighlightItem: 'unhighlightItem', }; -export const ACTION_TYPES = { +export const ACTION_TYPES: Record = { ADD_CHOICE: 'ADD_CHOICE', FILTER_CHOICES: 'FILTER_CHOICES', ACTIVATE_CHOICES: 'ACTIVATE_CHOICES', @@ -105,9 +106,11 @@ export const ACTION_TYPES = { REMOVE_ITEM: 'REMOVE_ITEM', HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM', CLEAR_ALL: 'CLEAR_ALL', + RESET_TO: 'RESET_TO', + SET_IS_LOADING: 'SET_IS_LOADING', }; -export const KEY_CODES = { +export const KEY_CODES: KeyCodeMap = { BACK_KEY: 46, DELETE_KEY: 8, ENTER_KEY: 13, @@ -119,8 +122,9 @@ export const KEY_CODES = { PAGE_DOWN_KEY: 34, }; -export const TEXT_TYPE = 'text'; -export const SELECT_ONE_TYPE = 'select-one'; -export const SELECT_MULTIPLE_TYPE = 'select-multiple'; +export const TEXT_TYPE: HTMLInputElement['type'] = 'text'; +export const SELECT_ONE_TYPE: HTMLSelectElement['type'] = 'select-one'; +export const SELECT_MULTIPLE_TYPE: HTMLSelectElement['type'] = + 'select-multiple'; export const SCROLLING_SPEED = 4; diff --git a/src/scripts/interfaces.ts b/src/scripts/interfaces.ts new file mode 100644 index 0000000..9d02368 --- /dev/null +++ b/src/scripts/interfaces.ts @@ -0,0 +1,754 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { FuseOptions } from 'fuse.js'; +import Choices from './choices'; + +export namespace Types { + export type strToEl = ( + str: string, + ) => HTMLElement | HTMLInputElement | HTMLOptionElement; + export type stringFunction = () => string; + export type noticeStringFunction = (value: string) => string; + export type noticeLimitFunction = (maxItemCount: number) => string; + export type filterFunction = (value: string) => boolean; + export type valueCompareFunction = ( + value1: string, + value2: string, + ) => boolean; +} + +export interface Choice { + id?: number; + customProperties?: Record; + disabled?: boolean; + active?: boolean; + elementId?: number; + groupId?: number; + keyCode?: number; + label: string; + placeholder?: boolean; + selected?: boolean; + value: string; + score?: number; + choices?: Choice[]; +} + +export interface Group { + id?: number; + active?: boolean; + disabled?: boolean; + value: any; +} +export interface Item extends Choice { + choiceId?: number; + highlighted?: boolean; +} + +/** + * Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object. + */ +export interface EventMap { + /** + * Triggered each time an item is added (programmatically or by the user). + * + * **Input types affected:** text, select-one, select-multiple + * + * Arguments: id, value, label, groupValue, keyCode + */ + addItem: CustomEvent<{ + id: number; + value: string; + label: string; + groupValue: string; + keyCode: number; + }>; + + /** + * Triggered each time an item is removed (programmatically or by the user). + * + * **Input types affected:** text, select-one, select-multiple + * + * Arguments: id, value, label, groupValue + */ + removeItem: CustomEvent<{ + id: number; + value: string; + label: string; + groupValue: string; + }>; + + /** + * Triggered each time an item is highlighted. + * + * **Input types affected:** text, select-multiple + * + * Arguments: id, value, label, groupValue + */ + highlightItem: CustomEvent<{ + id: number; + value: string; + label: string; + groupValue: string; + }>; + + /** + * Triggered each time an item is unhighlighted. + * + * **Input types affected:** text, select-multiple + * + * Arguments: id, value, label, groupValue + */ + unhighlightItem: CustomEvent<{ + id: number; + value: string; + label: string; + groupValue: string; + }>; + + /** + * Triggered each time a choice is selected **by a user**, regardless if it changes the value of the input. + * + * **Input types affected:** select-one, select-multiple + * + * Arguments: choice: Choice + */ + choice: CustomEvent<{ choice: Choice }>; + + /** + * Triggered each time an item is added/removed **by a user**. + * + * **Input types affected:** text, select-one, select-multiple + * + * Arguments: value + */ + change: CustomEvent<{ value: string }>; + + /** + * Triggered when a user types into an input to search choices. + * + * **Input types affected:** select-one, select-multiple + * + * Arguments: value, resultCount + */ + search: CustomEvent<{ value: string; resultCount: number }>; + + /** + * Triggered when the dropdown is shown. + * + * **Input types affected:** select-one, select-multiple + * + * Arguments: - + */ + showDropdown: CustomEvent; + + /** + * Triggered when the dropdown is hidden. + * + * **Input types affected:** select-one, select-multiple + * + * Arguments: - + */ + hideDropdown: CustomEvent; + + /** + * Triggered when a choice from the dropdown is highlighted. + * + * Input types affected: select-one, select-multiple + * Arguments: el is the choice.passedElement that was affected. + */ + highlightChoice: CustomEvent<{ el: PassedElement }>; +} + +export interface KeyCodeMap { + BACK_KEY: 46; + DELETE_KEY: 8; + ENTER_KEY: 13; + A_KEY: 65; + ESC_KEY: 27; + UP_KEY: 38; + DOWN_KEY: 40; + PAGE_UP_KEY: 33; + PAGE_DOWN_KEY: 34; +} + +export type ActionType = + | 'ADD_CHOICE' + | 'FILTER_CHOICES' + | 'ACTIVATE_CHOICES' + | 'CLEAR_CHOICES' + | 'ADD_GROUP' + | 'ADD_ITEM' + | 'REMOVE_ITEM' + | 'HIGHLIGHT_ITEM' + | 'CLEAR_ALL' + | 'RESET_TO' + | 'SET_IS_LOADING'; + +/** Classes added to HTML generated by By default classnames follow the BEM notation. */ +export interface ClassNames { + /** @default 'choices' */ + containerOuter: string; + /** @default 'choices__inner' */ + containerInner: string; + /** @default 'choices__input' */ + input: string; + /** @default 'choices__input--cloned' */ + inputCloned: string; + /** @default 'choices__list' */ + list: string; + /** @default 'choices__list--multiple' */ + listItems: string; + /** @default 'choices__list--single' */ + listSingle: string; + /** @default 'choices__list--dropdown' */ + listDropdown: string; + /** @default 'choices__item' */ + item: string; + /** @default 'choices__item--selectable' */ + itemSelectable: string; + /** @default 'choices__item--disabled' */ + itemDisabled: string; + /** @default 'choices__item--choice' */ + itemChoice: string; + /** @default 'choices__placeholder' */ + placeholder: string; + /** @default 'choices__group' */ + group: string; + /** @default 'choices__heading' */ + groupHeading: string; + /** @default 'choices__button' */ + button: string; + /** @default 'is-active' */ + activeState: string; + /** @default 'is-focused' */ + focusState: string; + /** @default 'is-open' */ + openState: string; + /** @default 'is-disabled' */ + disabledState: string; + /** @default 'is-highlighted' */ + highlightedState: string; + /** @default 'is-selected' */ + selectedState: string; + /** @default 'is-flipped' */ + flippedState: string; + /** @default 'is-loading' */ + loadingState: string; + /** @default 'has-no-results' */ + noResults: string; + /** @default 'has-no-choices' */ + noChoices: string; +} + +export interface PassedElement extends HTMLElement { + classNames: ClassNames; + element: (HTMLInputElement | HTMLSelectElement) & { + // Extends HTMLElement addEventListener with Choices events + addEventListener( + type: K, + listener: ( + this: HTMLInputElement | HTMLSelectElement, + ev: EventMap[K], + ) => void, + options?: boolean | AddEventListenerOptions, + ): void; + }; + type: 'text' | 'select-one' | 'select-multiple'; + isDisabled: boolean; + parentInstance: Choices; +} + +/** + * Choices options interface + * + * **Terminology** + * + * - **Choice:** A choice is a value a user can select. A choice would be equivalent to the `` element within a select input. + * - **Group:** A group is a collection of choices. A group should be seen as equivalent to a `` element within a select input. + * - **Item:** An item is an inputted value **_(text input)_** or a selected choice **_(select element)_**. In the context of a select element, an item is equivelent to a selected option element: `` whereas in the context of a text input an item is equivelant to `` + */ +export interface Options { + /** + * Optionally suppress console errors and warnings. + * + * **Input types affected:** text, select-single, select-multiple + * + * @default false + */ + silent: boolean; + + /** + * Add pre-selected items (see terminology) to text input. + * + * **Input types affected:** text + * + * @example + * ``` + * ['value 1', 'value 2', 'value 3'] + * ``` + * + * @example + * ``` + * [{ + * value: 'Value 1', + * label: 'Label 1', + * id: 1 + * }, + * { + * value: 'Value 2', + * label: 'Label 2', + * id: 2, + * customProperties: { + * random: 'I am a custom property' + * } + * }] + * ``` + * + * @default [] + */ + items: string[] | Choice[]; + + /** + * Add choices (see terminology) to select input. + * + * **Input types affected:** select-one, select-multiple + * + * @example + * ``` + * [{ + * value: 'Option 1', + * label: 'Option 1', + * selected: true, + * disabled: false, + * }, + * { + * value: 'Option 2', + * label: 'Option 2', + * selected: false, + * disabled: true, + * customProperties: { + * description: 'Custom description about Option 2', + * random: 'Another random custom property' + * }, + * }] + * ``` + * + * @default [] + */ + choices: Choice[]; + + /** + * The amount of choices to be rendered within the dropdown list `("-1" indicates no limit)`. This is useful if you have a lot of choices where it is easier for a user to use the search area to find a choice. + * + * **Input types affected:** select-one, select-multiple + * + * @default -1 + */ + renderChoiceLimit: number; + + /** + * The amount of items a user can input/select `("-1" indicates no limit)`. + * + * **Input types affected:** text, select-multiple + * + * @default -1 + */ + maxItemCount: number; + + /** + * Whether a user can add items. + * + * **Input types affected:** text + * + * @default true + */ + addItems: boolean; + + /** + * A filter that will need to pass for a user to successfully add an item. + * + * **Input types affected:** text + * + * @default null + */ + addItemFilter: string | RegExp | Types.filterFunction | null; + + /** + * The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string. + * + * **Input types affected:** text + * + * @default + * ``` + * (value) => `Press Enter to add "${value}"`; + * ``` + */ + addItemText: string | Types.noticeStringFunction; + + /** + * Whether a user can remove items. + * + * **Input types affected:** text, select-multiple + * + * @default true + */ + removeItems: boolean; + + /** + * Whether each item should have a remove button. + * + * **Input types affected:** text, select-one, select-multiple + * + * @default false + */ + removeItemButton: boolean; + + /** + * Whether a user can edit items. An item's value can be edited by pressing the backspace. + * + * **Input types affected:** text + * + * @default false + */ + editItems: boolean; + + /** + * Whether each inputted/chosen item should be unique. + * + * **Input types affected:** text, select-multiple + * + * @default true + */ + duplicateItemsAllowed: boolean; + + /** + * What divides each value. The default delimiter separates each value with a comma: `"Value 1, Value 2, Value 3"`. + * + * **Input types affected:** text + * + * @default ',' + */ + delimiter: string; + + /** + * Whether a user can paste into the input. + * + * **Input types affected:** text, select-multiple + * + * @default true + */ + paste: boolean; + + /** + * Whether a search area should be shown. + * + * @note Multiple select boxes will always show search areas. + * + * **Input types affected:** select-one + * + * @default true + */ + searchEnabled: boolean; + + /** + * Whether choices should be filtered by input or not. If `false`, the search event will still emit, but choices will not be filtered. + * + * **Input types affected:** select-one + * + * @default true + */ + searchChoices: boolean; + + /** + * The minimum length a search value should be before choices are searched. + * + * **Input types affected:** select-one, select-multiple + * + * @default 1 + */ + searchFloor: number; + + /** + * The maximum amount of search results to show. + * + * **Input types affected:** select-one, select-multiple + * + * @default 4 + */ + searchResultLimit: number; + + /** + * Specify which fields should be used when a user is searching. If you have added custom properties to your choices, you can add these values thus: `['label', 'value', 'customProperties.example']`. + * + * Input types affected:select-one, select-multiple + * + * @default ['label', 'value'] + */ + searchFields: string[]; + + /** + * Whether the dropdown should appear above `(top)` or below `(bottom)` the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it. + * + * **Input types affected:** select-one, select-multiple + * + * @default 'auto' + */ + position: 'auto' | 'top' | 'bottom'; + + /** + * Whether the scroll position should reset after adding an item. + * + * **Input types affected:** select-multiple + * + * @default true + */ + resetScrollPosition: boolean; + + /** + * Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given. + * + * **Input types affected:** select-one, select-multiple + * + * @default true + */ + shouldSort: boolean; + + /** + * Whether items should be sorted. If false, items will appear in the order they were selected. + * + * **Input types affected:** text, select-multiple + * + * @default false + */ + shouldSortItems: boolean; + + /** + * The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order. + * + * **Input types affected:** select-one, select-multiple + * + * @example + * ``` + * // Sorting via length of label from largest to smallest + * const example = new Choices(element, { + * sorter: function(a, b) { + * return b.label.length - a.label.length; + * }, + * }; + * ``` + * + * @default sortByAlpha + */ + sorter: (current: Choice, next: Choice) => number; + + /** + * Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value. + * + * **Input types affected:** text, select-multiple + * + * @note For single select boxes, the recommended way of adding a placeholder is as follows: + * ``` + * + * ``` + * + * @default true + */ + placeholder: boolean; + + /** + * The value of the inputs placeholder. + * + * **Input types affected:** text, select-multiple + * + * @default null + */ + placeholderValue: string | null; + + /** + * The value of the search inputs placeholder. + * + * **Input types affected:** select-one + * + * @default null + */ + searchPlaceholderValue: string | null; + + /** + * Prepend a value to each item added/selected. + * + * **Input types affected:** text, select-one, select-multiple + * + * @default null + */ + prependValue: string | null; + + /** + * Append a value to each item added/selected. + * + * **Input types affected:** text, select-one, select-multiple + * + * @default null + */ + appendValue: string | null; + + /** + * Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass `always`. + * + * **Input types affected:** select-one, select-multiple + * + * @default 'auto'; + */ + renderSelectedChoices: 'auto' | 'always'; + + /** + * The text that is shown whilst choices are being populated via AJAX. + * + * **Input types affected:** select-one, select-multiple + * + * @default 'Loading...' + */ + loadingText: string; + + /** + * The text that is shown when a user's search has returned no results. Optionally pass a function returning a string. + * + * **Input types affected:** select-one, select-multiple + * + * @default 'No results found' + */ + noResultsText: string | Types.stringFunction; + + /** + * The text that is shown when a user has selected all possible choices. Optionally pass a function returning a string. + * + * **Input types affected:** select-multiple + * + * @default 'No choices to choose from' + */ + noChoicesText: string | Types.stringFunction; + + /** + * The text that is shown when a user hovers over a selectable choice. + * + * **Input types affected:** select-multiple, select-one + * + * @default 'Press to select' + */ + itemSelectText: string; + + /** + * The text that is shown when a user has focus on the input but has already reached the **max item count** [https://github.com/jshjohnson/Choices#maxitemcount]. To access the max item count, pass a function with a `maxItemCount` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string. + * + * **Input types affected:** text + * + * @default + * ``` + * (maxItemCount) => `Only ${maxItemCount} values can be added.`; + * ``` + */ + maxItemText: string | Types.noticeLimitFunction; + + /** + * If no duplicates are allowed, and the value already exists in the array. + * + * @default 'Only unique values can be added' + */ + uniqueItemText: string | Types.noticeStringFunction; + + /** + * The text that is shown when addItemFilter is passed and it returns false + * + * **Input types affected:** text + * + * @default 'Only values matching specific conditions can be added' + */ + customAddItemText: string | Types.noticeStringFunction; + + /** + * Compare choice and value in appropriate way (e.g. deep equality for objects). To compare choice and value, pass a function with a `valueComparer` argument (see the [default config](https://github.com/jshjohnson/Choices#setup) for an example). + * + * **Input types affected:** select-one, select-multiple + * + * @default + * ``` + * (choice, item) => choice === item; + * ``` + */ + valueComparer: Types.valueCompareFunction; + + /** + * Classes added to HTML generated by By default classnames follow the BEM notation. + * + * **Input types affected:** text, select-one, select-multiple + */ + classNames: ClassNames; + + /** + * Choices uses the great Fuse library for searching. You can find more options here: https://github.com/krisk/Fuse#options + */ + fuseOptions: FuseOptions; + + /** + * Function to run once Choices initialises. + * + * **Input types affected:** text, select-one, select-multiple + * + * @note For each callback, this refers to the current instance of This can be useful if you need access to methods `(this.disable())` or the config object `(this.config)`. + * + * @default null + */ + callbackOnInit: ((this: Choices) => void) | null; + + /** + * Function to run on template creation. Through this callback it is possible to provide custom templates for the various components of Choices (see terminology). For Choices to work with custom templates, it is important you maintain the various data attributes defined here [https://github.com/jshjohnson/Choices/blob/67f29c286aa21d88847adfcd6304dc7d068dc01f/assets/scripts/src/choices.js#L1993-L2067]. + * + * **Input types affected:** text, select-one, select-multiple + * + * @note For each callback, this refers to the current instance of This can be useful if you need access to methods `(this.disable())` or the config object `(this.config)`. + * + * @example + * ``` + * const example = new Choices(element, { + * callbackOnCreateTemplates: function (template) { + * var classNames = this.config.classNames; + * return { + * item: (data) => { + * return template(` + *

+ * ${data.label} + *
+ * `); + * }, + * choice: (data) => { + * return template(` + *
0 ? 'role="treeitem"' : 'role="option"'}> + * ${data.label} + *
+ * `); + * }, + * }; + * } + * }); + * ``` + * + * @default null + */ + callbackOnCreateTemplates: ((template: Types.strToEl) => void) | null; +} + +// @todo rename +export interface Notice { + response: boolean; + notice: string; +} + +export interface State { + choices: Choice[]; + groups: Group[]; + items: Item[]; + loading: boolean; +} diff --git a/src/scripts/lib/utils.js b/src/scripts/lib/utils.js deleted file mode 100644 index 8cbd576..0000000 --- a/src/scripts/lib/utils.js +++ /dev/null @@ -1,214 +0,0 @@ -/** - * @param {number} min - * @param {number} max - * @returns {number} - */ -export const getRandomNumber = (min, max) => - Math.floor(Math.random() * (max - min) + min); - -/** - * @param {number} length - * @returns {string} - */ -export const generateChars = length => - Array.from({ length }, () => getRandomNumber(0, 36).toString(36)).join(''); - -/** - * @param {HTMLInputElement | HTMLSelectElement} element - * @param {string} prefix - * @returns {string} - */ -export const generateId = (element, prefix) => { - let id = - element.id || - (element.name && `${element.name}-${generateChars(2)}`) || - generateChars(4); - id = id.replace(/(:|\.|\[|\]|,)/g, ''); - id = `${prefix}-${id}`; - - return id; -}; - -/** - * @param {any} obj - * @returns {string} - */ -export const getType = obj => Object.prototype.toString.call(obj).slice(8, -1); - -/** - * @param {string} type - * @param {any} obj - * @returns {boolean} - */ -export const isType = (type, obj) => - obj !== undefined && obj !== null && getType(obj) === type; - -/** - * @param {HTMLElement} element - * @param {HTMLElement} [wrapper={HTMLDivElement}] - * @returns {HTMLElement} - */ -export const wrap = (element, wrapper = document.createElement('div')) => { - if (element.nextSibling) { - element.parentNode.insertBefore(wrapper, element.nextSibling); - } else { - element.parentNode.appendChild(wrapper); - } - - return wrapper.appendChild(element); -}; - -/** - * @param {Element} startEl - * @param {string} selector - * @param {1 | -1} direction - * @returns {Element | undefined} - */ -export const getAdjacentEl = (startEl, selector, direction = 1) => { - if (!(startEl instanceof Element) || typeof selector !== 'string') { - return undefined; - } - - const prop = `${direction > 0 ? 'next' : 'previous'}ElementSibling`; - - let sibling = startEl[prop]; - while (sibling) { - if (sibling.matches(selector)) { - return sibling; - } - sibling = sibling[prop]; - } - - return sibling; -}; - -/** - * @param {Element} element - * @param {Element} parent - * @param {-1 | 1} direction - * @returns {boolean} - */ -export const isScrolledIntoView = (element, parent, direction = 1) => { - if (!element) { - return false; - } - - let isVisible; - - if (direction > 0) { - // In view from bottom - isVisible = - parent.scrollTop + parent.offsetHeight >= - element.offsetTop + element.offsetHeight; - } else { - // In view from top - isVisible = element.offsetTop >= parent.scrollTop; - } - - return isVisible; -}; - -/** - * @param {any} value - * @returns {any} - */ -export const sanitise = value => { - if (typeof value !== 'string') { - return value; - } - - return value - .replace(/&/g, '&') - .replace(/>/g, '&rt;') - .replace(/ (str: string) => Element} - */ -export const strToEl = (() => { - const tmpEl = document.createElement('div'); - - return str => { - const cleanedInput = str.trim(); - tmpEl.innerHTML = cleanedInput; - const firldChild = tmpEl.children[0]; - - while (tmpEl.firstChild) { - tmpEl.removeChild(tmpEl.firstChild); - } - - return firldChild; - }; -})(); - -/** - * @param {{ label?: string, value: string }} a - * @param {{ label?: string, value: string }} b - * @returns {number} - */ -export const sortByAlpha = ( - { value, label = value }, - { value: value2, label: label2 = value2 }, -) => - label.localeCompare(label2, [], { - sensitivity: 'base', - ignorePunctuation: true, - numeric: true, - }); - -/** - * @param {{ score: number }} a - * @param {{ score: number }} b - */ -export const sortByScore = (a, b) => a.score - b.score; - -/** - * @param {HTMLElement} element - * @param {string} type - * @param {object} customArgs - */ -export const dispatchEvent = (element, type, customArgs = null) => { - const event = new CustomEvent(type, { - detail: customArgs, - bubbles: true, - cancelable: true, - }); - - return element.dispatchEvent(event); -}; - -/** - * @param {array} array - * @param {any} value - * @param {string} [key="value"] - * @returns {boolean} - */ -export const existsInArray = (array, value, key = 'value') => - array.some(item => { - if (typeof value === 'string') { - return item[key] === value.trim(); - } - - return item[key] === value; - }); - -/** - * @param {any} obj - * @returns {any} - */ -export const cloneObject = obj => JSON.parse(JSON.stringify(obj)); - -/** - * Returns an array of keys present on the first but missing on the second object - * @param {object} a - * @param {object} b - * @returns {string[]} - */ -export const diff = (a, b) => { - const aKeys = Object.keys(a).sort(); - const bKeys = Object.keys(b).sort(); - - return aKeys.filter(i => bKeys.indexOf(i) < 0); -}; diff --git a/src/scripts/lib/utils.test.js b/src/scripts/lib/utils.test.ts similarity index 92% rename from src/scripts/lib/utils.test.js rename to src/scripts/lib/utils.test.ts index 2366f56..3cac1a1 100644 --- a/src/scripts/lib/utils.test.js +++ b/src/scripts/lib/utils.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-new-wrappers */ import { expect } from 'chai'; import { stub } from 'sinon'; import { @@ -140,19 +141,19 @@ describe('utils', () => { it('sorts by label alphabetically', () => { const values = [ - { label: 'The Strokes' }, - { label: 'Arctic Monkeys' }, - { label: 'Oasis' }, - { label: 'Tame Impala' }, + { value: '0', label: 'The Strokes' }, + { value: '0', label: 'Arctic Monkeys' }, + { value: '0', label: 'Oasis' }, + { value: '0', label: 'Tame Impala' }, ]; const output = values.sort(sortByAlpha); expect(output).to.eql([ - { label: 'Arctic Monkeys' }, - { label: 'Oasis' }, - { label: 'Tame Impala' }, - { label: 'The Strokes' }, + { value: '0', label: 'Arctic Monkeys' }, + { value: '0', label: 'Oasis' }, + { value: '0', label: 'Tame Impala' }, + { value: '0', label: 'The Strokes' }, ]); }); }); @@ -185,12 +186,12 @@ describe('utils', () => { const fakeElement = { dispatchEvent: stub(), }; - const eventType = 'testEvent'; + const eventType = 'addItem'; const customArgs = { testing: true, }; - dispatchEvent(fakeElement, eventType, customArgs); + dispatchEvent(fakeElement as any, eventType, customArgs); expect(fakeElement.dispatchEvent.called).to.equal(true); const event = fakeElement.dispatchEvent.lastCall.args[0]; diff --git a/src/scripts/lib/utils.ts b/src/scripts/lib/utils.ts new file mode 100644 index 0000000..1508e09 --- /dev/null +++ b/src/scripts/lib/utils.ts @@ -0,0 +1,180 @@ +import { EventMap, Choice } from '../interfaces'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export const getRandomNumber = (min: number, max: number): number => + Math.floor(Math.random() * (max - min) + min); + +export const generateChars = (length: number): string => + Array.from({ length }, () => getRandomNumber(0, 36).toString(36)).join(''); + +export const generateId = ( + element: HTMLInputElement | HTMLSelectElement, + prefix: string, +): string => { + let id = + element.id || + (element.name && `${element.name}-${generateChars(2)}`) || + generateChars(4); + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = `${prefix}-${id}`; + + return id; +}; + +export const getType = (obj: any): string => + Object.prototype.toString.call(obj).slice(8, -1); + +export const isType = (type: string, obj: any): boolean => + obj !== undefined && obj !== null && getType(obj) === type; + +export const wrap = ( + element: HTMLElement, + wrapper: HTMLElement = document.createElement('div'), +): HTMLElement => { + if (element.nextSibling) { + element.parentNode && + element.parentNode.insertBefore(wrapper, element.nextSibling); + } else { + element.parentNode && element.parentNode.appendChild(wrapper); + } + + return wrapper.appendChild(element); +}; + +export const getAdjacentEl = ( + startEl: Element, + selector: string, + direction = 1, +): Element => { + const prop = `${direction > 0 ? 'next' : 'previous'}ElementSibling`; + + let sibling = startEl[prop]; + while (sibling) { + if (sibling.matches(selector)) { + return sibling; + } + sibling = sibling[prop]; + } + + return sibling; +}; + +export const isScrolledIntoView = ( + element: HTMLElement, + parent: HTMLElement, + direction = 1, +): boolean => { + if (!element) { + return false; + } + + let isVisible; + + if (direction > 0) { + // In view from bottom + isVisible = + parent.scrollTop + parent.offsetHeight >= + element.offsetTop + element.offsetHeight; + } else { + // In view from top + isVisible = element.offsetTop >= parent.scrollTop; + } + + return isVisible; +}; + +export const sanitise = (value: T | string): T | string => { + if (typeof value !== 'string') { + return value; + } + + return value + .replace(/&/g, '&') + .replace(/>/g, '&rt;') + .replace(/ Element) => { + const tmpEl = document.createElement('div'); + + return (str): Element => { + const cleanedInput = str.trim(); + tmpEl.innerHTML = cleanedInput; + const firldChild = tmpEl.children[0]; + + while (tmpEl.firstChild) { + tmpEl.removeChild(tmpEl.firstChild); + } + + return firldChild; + }; +})(); + +interface RecordToCompare { + value: string; + label?: string; +} +export const sortByAlpha = ( + { value, label = value }: RecordToCompare, + { value: value2, label: label2 = value2 }: RecordToCompare, +): number => + label.localeCompare(label2, [], { + sensitivity: 'base', + ignorePunctuation: true, + numeric: true, + }); + +export const sortByScore = ( + a: Pick, + b: Pick, +): number => { + const { score: scoreA = 0 } = a; + const { score: scoreB = 0 } = b; + + return scoreA - scoreB; +}; + +export const dispatchEvent = ( + element: HTMLElement, + type: keyof EventMap, + customArgs: object | null = null, +): boolean => { + const event = new CustomEvent(type, { + detail: customArgs, + bubbles: true, + cancelable: true, + }); + + return element.dispatchEvent(event); +}; + +export const existsInArray = ( + array: any[], + value: string, + key = 'value', +): boolean => + array.some(item => { + if (typeof value === 'string') { + return item[key] === value.trim(); + } + + return item[key] === value; + }); + +export const cloneObject = (obj: object): object => + JSON.parse(JSON.stringify(obj)); + +/** + * Returns an array of keys present on the first but missing on the second object + */ +export const diff = ( + a: Record, + b: Record, +): string[] => { + const aKeys = Object.keys(a).sort(); + const bKeys = Object.keys(b).sort(); + + return aKeys.filter(i => bKeys.indexOf(i) < 0); +}; diff --git a/src/scripts/reducers/choices.js b/src/scripts/reducers/choices.js deleted file mode 100644 index 8f10516..0000000 --- a/src/scripts/reducers/choices.js +++ /dev/null @@ -1,110 +0,0 @@ -export const defaultState = []; - -export default function choices(state = defaultState, action) { - switch (action.type) { - case 'ADD_CHOICE': { - /* - A disabled choice appears in the choice dropdown but cannot be selected - A selected choice has been added to the passed input's value (added as an item) - An active choice appears within the choice dropdown - */ - return [ - ...state, - { - id: action.id, - elementId: action.elementId, - groupId: action.groupId, - value: action.value, - label: action.label || action.value, - disabled: action.disabled || false, - selected: false, - active: true, - score: 9999, - customProperties: action.customProperties, - placeholder: action.placeholder || false, - keyCode: null, - }, - ]; - } - - case 'ADD_ITEM': { - // If all choices need to be activated - if (action.activateOptions) { - return state.map(obj => { - const choice = obj; - choice.active = action.active; - - return choice; - }); - } - - // When an item is added and it has an associated choice, - // we want to disable it so it can't be chosen again - if (action.choiceId > -1) { - return state.map(obj => { - const choice = obj; - if (choice.id === parseInt(action.choiceId, 10)) { - choice.selected = true; - } - - return choice; - }); - } - - return state; - } - - case 'REMOVE_ITEM': { - // When an item is removed and it has an associated choice, - // we want to re-enable it so it can be chosen again - if (action.choiceId > -1) { - return state.map(obj => { - const choice = obj; - if (choice.id === parseInt(action.choiceId, 10)) { - choice.selected = false; - } - - return choice; - }); - } - - return state; - } - - case 'FILTER_CHOICES': { - return state.map(obj => { - const choice = obj; - // Set active state based on whether choice is - // within filtered results - choice.active = action.results.some(({ item, score }) => { - if (item.id === choice.id) { - choice.score = score; - - return true; - } - - return false; - }); - - return choice; - }); - } - - case 'ACTIVATE_CHOICES': { - return state.map(obj => { - const choice = obj; - choice.active = action.active; - - return choice; - }); - } - - case 'CLEAR_CHOICES': { - return defaultState; - } - - default: { - return state; - } - } -} diff --git a/src/scripts/reducers/choices.test.js b/src/scripts/reducers/choices.test.ts similarity index 81% rename from src/scripts/reducers/choices.test.js rename to src/scripts/reducers/choices.test.ts index 9563f6c..a46c1ee 100644 --- a/src/scripts/reducers/choices.test.js +++ b/src/scripts/reducers/choices.test.ts @@ -1,21 +1,22 @@ import { expect } from 'chai'; import choices, { defaultState } from './choices'; +import { Choice } from '../interfaces'; describe('reducers/choices', () => { it('should return same state when no action matches', () => { - expect(choices(defaultState, {})).to.equal(defaultState); + expect(choices(defaultState, {} as any)).to.equal(defaultState); }); describe('when choices do not exist', () => { describe('ADD_CHOICE', () => { const value = 'test'; const label = 'test'; - const id = 'test'; - const groupId = 'test'; + const id = 1; + const groupId = 1; const disabled = false; - const elementId = 'test'; - const customProperties = 'test'; - const placeholder = 'test'; + const elementId = 1; + const customProperties = { test: true }; + const placeholder = true; describe('passing expected values', () => { it('adds choice', () => { @@ -32,7 +33,6 @@ describe('reducers/choices', () => { selected: false, active: true, score: 9999, - keyCode: null, }, ]; @@ -68,14 +68,13 @@ describe('reducers/choices', () => { selected: false, active: true, score: 9999, - keyCode: null, }, ]; const actualResponse = choices(undefined, { type: 'ADD_CHOICE', value, - label: null, + label: undefined, id, groupId, disabled, @@ -103,14 +102,13 @@ describe('reducers/choices', () => { selected: false, active: true, score: 9999, - keyCode: null, }, ]; const actualResponse = choices(undefined, { type: 'ADD_CHOICE', value, - label: null, + label: undefined, id, groupId, disabled, @@ -143,7 +141,6 @@ describe('reducers/choices', () => { score: 9999, customProperties: null, placeholder: false, - keyCode: null, }, { id: 2, @@ -157,7 +154,6 @@ describe('reducers/choices', () => { score: 9999, customProperties: null, placeholder: false, - keyCode: null, }, ]; }); @@ -178,9 +174,7 @@ describe('reducers/choices', () => { type: 'FILTER_CHOICES', results: [ { - item: { - id, - }, + item: { id } as Choice, score, }, ], @@ -227,45 +221,34 @@ describe('reducers/choices', () => { }); describe('ADD_ITEM', () => { - it('disables choice if action has choice id', () => { - const id = 2; - const clonedState = state.slice(0); - const expectedResponse = [ - { - ...state[0], - }, - { - ...state[1], - selected: true, - }, - ]; + describe('when action has a choice id', () => { + it('disables choice corresponding with id', () => { + const id = 2; + const clonedState = state.slice(0); + const expectedResponse = [ + { + ...state[0], + }, + { + ...state[1], + selected: true, + }, + ]; - const actualResponse = choices(clonedState, { - type: 'ADD_ITEM', - choiceId: id, + const actualResponse = choices(clonedState, { + type: 'ADD_ITEM', + choiceId: id, + }); + + expect(actualResponse).to.eql(expectedResponse); }); - - expect(actualResponse).to.eql(expectedResponse); }); - it('activates all choices if activateOptions flag passed', () => { - const clonedState = state.slice(0); - const actualResponse = choices(clonedState, { - type: 'ADD_ITEM', - activateOptions: true, - active: true, - }); - - expect(actualResponse[0].active).to.equal(true); - expect(actualResponse[1].active).to.equal(true); - }); - - describe('neither of the above conditions are satisified', () => { + describe('when action has no choice id', () => { it('returns state', () => { const clonedState = state.slice(0); const actualResponse = choices(clonedState, { type: 'ADD_ITEM', - activateOptions: false, choiceId: undefined, }); diff --git a/src/scripts/reducers/choices.ts b/src/scripts/reducers/choices.ts new file mode 100644 index 0000000..bd73e19 --- /dev/null +++ b/src/scripts/reducers/choices.ts @@ -0,0 +1,127 @@ +import { Choice } from '../interfaces'; +import { + AddChoiceAction, + FilterChoicesAction, + ActivateChoicesAction, + ClearChoicesAction, +} from '../actions/choices'; +import { AddItemAction, RemoveItemAction } from '../actions/items'; + +export const defaultState = []; + +type ActionTypes = + | AddChoiceAction + | FilterChoicesAction + | ActivateChoicesAction + | ClearChoicesAction + | AddItemAction + | RemoveItemAction; + +export default function choices( + state: Choice[] = defaultState, + action: ActionTypes, +): Choice[] { + switch (action.type) { + case 'ADD_CHOICE': { + const addChoiceAction = action as AddChoiceAction; + const choice = { + id: addChoiceAction.id, + elementId: addChoiceAction.elementId, + groupId: addChoiceAction.groupId, + value: addChoiceAction.value, + label: addChoiceAction.label || addChoiceAction.value, + disabled: addChoiceAction.disabled || false, + selected: false, + active: true, + score: 9999, + customProperties: addChoiceAction.customProperties, + placeholder: addChoiceAction.placeholder || false, + }; + + /* + A disabled choice appears in the choice dropdown but cannot be selected + A selected choice has been added to the passed input's value (added as an item) + An active choice appears within the choice dropdown + */ + return [...state, choice as Choice]; + } + + case 'ADD_ITEM': { + const addItemAction = action as AddItemAction; + + // When an item is added and it has an associated choice, + // we want to disable it so it can't be chosen again + if (addItemAction.choiceId > -1) { + return state.map(obj => { + const choice = obj; + if (choice.id === parseInt(`${addItemAction.choiceId}`, 10)) { + choice.selected = true; + } + + return choice; + }); + } + + return state; + } + + case 'REMOVE_ITEM': { + const removeItemAction = action as RemoveItemAction; + + // When an item is removed and it has an associated choice, + // we want to re-enable it so it can be chosen again + if (removeItemAction.choiceId && removeItemAction.choiceId > -1) { + return state.map(obj => { + const choice = obj; + if (choice.id === parseInt(`${removeItemAction.choiceId}`, 10)) { + choice.selected = false; + } + + return choice; + }); + } + + return state; + } + + case 'FILTER_CHOICES': { + const filterChoicesAction = action as FilterChoicesAction; + + return state.map(obj => { + const choice = obj; + // Set active state based on whether choice is + // within filtered results + choice.active = filterChoicesAction.results.some(({ item, score }) => { + if (item.id === choice.id) { + choice.score = score; + + return true; + } + + return false; + }); + + return choice; + }); + } + + case 'ACTIVATE_CHOICES': { + const activateChoicesAction = action as ActivateChoicesAction; + + return state.map(obj => { + const choice = obj; + choice.active = activateChoicesAction.active; + + return choice; + }); + } + + case 'CLEAR_CHOICES': { + return defaultState; + } + + default: { + return state; + } + } +} diff --git a/src/scripts/reducers/general.js b/src/scripts/reducers/general.js deleted file mode 100644 index 2a72cb3..0000000 --- a/src/scripts/reducers/general.js +++ /dev/null @@ -1,19 +0,0 @@ -export const defaultState = { - loading: false, -}; - -const general = (state = defaultState, action) => { - switch (action.type) { - case 'SET_IS_LOADING': { - return { - loading: action.isLoading, - }; - } - - default: { - return state; - } - } -}; - -export default general; diff --git a/src/scripts/reducers/groups.js b/src/scripts/reducers/groups.js deleted file mode 100644 index d704e92..0000000 --- a/src/scripts/reducers/groups.js +++ /dev/null @@ -1,25 +0,0 @@ -export const defaultState = []; - -export default function groups(state = defaultState, action) { - switch (action.type) { - case 'ADD_GROUP': { - return [ - ...state, - { - id: action.id, - value: action.value, - active: action.active, - disabled: action.disabled, - }, - ]; - } - - case 'CLEAR_CHOICES': { - return []; - } - - default: { - return state; - } - } -} diff --git a/src/scripts/reducers/groups.test.js b/src/scripts/reducers/groups.test.ts similarity index 94% rename from src/scripts/reducers/groups.test.js rename to src/scripts/reducers/groups.test.ts index e67ee04..95008ef 100644 --- a/src/scripts/reducers/groups.test.js +++ b/src/scripts/reducers/groups.test.ts @@ -3,13 +3,13 @@ import groups, { defaultState } from './groups'; describe('reducers/groups', () => { it('should return same state when no action matches', () => { - expect(groups(defaultState, {})).to.equal(defaultState); + expect(groups(defaultState, {} as any)).to.equal(defaultState); }); describe('when groups do not exist', () => { describe('ADD_GROUP', () => { it('adds group', () => { - const id = '1'; + const id = 1; const value = 'Group one'; const active = true; const disabled = false; diff --git a/src/scripts/reducers/groups.ts b/src/scripts/reducers/groups.ts new file mode 100644 index 0000000..c845e91 --- /dev/null +++ b/src/scripts/reducers/groups.ts @@ -0,0 +1,36 @@ +import { Group, State } from '../interfaces'; +import { AddGroupAction } from '../actions/groups'; +import { ClearChoicesAction } from '../actions/choices'; + +export const defaultState = []; + +type ActionTypes = AddGroupAction | ClearChoicesAction; + +export default function groups( + state: Group[] = defaultState, + action: ActionTypes, +): State['groups'] { + switch (action.type) { + case 'ADD_GROUP': { + const addGroupAction = action as AddGroupAction; + + return [ + ...state, + { + id: addGroupAction.id, + value: addGroupAction.value, + active: addGroupAction.active, + disabled: addGroupAction.disabled, + }, + ]; + } + + case 'CLEAR_CHOICES': { + return []; + } + + default: { + return state; + } + } +} diff --git a/src/scripts/reducers/index.test.js b/src/scripts/reducers/index.test.ts similarity index 75% rename from src/scripts/reducers/index.test.js rename to src/scripts/reducers/index.test.ts index c662cc8..50e252c 100644 --- a/src/scripts/reducers/index.test.js +++ b/src/scripts/reducers/index.test.ts @@ -1,9 +1,10 @@ import { createStore } from 'redux'; import { expect } from 'chai'; -import rootReducer from './index'; +import rootReducer from '.'; import groups from './groups'; import choices from './choices'; import items from './items'; +import loading from './loading'; describe('reducers/rootReducer', () => { const store = createStore(rootReducer); @@ -11,9 +12,10 @@ describe('reducers/rootReducer', () => { it('returns expected reducers', () => { const state = store.getState(); - expect(state.groups).to.equal(groups(undefined, {})); - expect(state.choices).to.equal(choices(undefined, {})); - expect(state.items).to.equal(items(undefined, {})); + expect(state.groups).to.equal(groups(undefined, {} as any)); + expect(state.choices).to.equal(choices(undefined, {} as any)); + expect(state.items).to.equal(items(undefined, {} as any)); + expect(state.loading).to.equal(loading(undefined, {} as any)); }); describe('CLEAR_ALL', () => { @@ -33,9 +35,7 @@ describe('reducers/rootReducer', () => { items: [], groups: [], choices: [], - general: { - loading: false, - }, + loading: false, }); }); }); diff --git a/src/scripts/reducers/index.js b/src/scripts/reducers/index.ts similarity index 75% rename from src/scripts/reducers/index.js rename to src/scripts/reducers/index.ts index 31dc7b3..92b10e4 100644 --- a/src/scripts/reducers/index.js +++ b/src/scripts/reducers/index.ts @@ -2,24 +2,31 @@ import { combineReducers } from 'redux'; import items from './items'; import groups from './groups'; import choices from './choices'; -import general from './general'; +import loading from './loading'; import { cloneObject } from '../lib/utils'; +export const defaultState = { + groups: [], + items: [], + choices: [], + loading: false, +}; + const appReducer = combineReducers({ items, groups, choices, - general, + loading, }); -const rootReducer = (passedState, action) => { +const rootReducer = (passedState, action): object => { let state = passedState; // If we are clearing all items, groups and options we reassign // state and then pass that state to our proper reducer. This isn't // mutating our actual state // See: http://stackoverflow.com/a/35641992 if (action.type === 'CLEAR_ALL') { - state = undefined; + state = defaultState; } else if (action.type === 'RESET_TO') { return cloneObject(action.state); } diff --git a/src/scripts/reducers/items.js b/src/scripts/reducers/items.js deleted file mode 100644 index 2a520f9..0000000 --- a/src/scripts/reducers/items.js +++ /dev/null @@ -1,58 +0,0 @@ -export const defaultState = []; - -export default function items(state = defaultState, action) { - switch (action.type) { - case 'ADD_ITEM': { - // Add object to items array - const newState = [ - ...state, - { - id: action.id, - choiceId: action.choiceId, - groupId: action.groupId, - value: action.value, - label: action.label, - active: true, - highlighted: false, - customProperties: action.customProperties, - placeholder: action.placeholder || false, - keyCode: null, - }, - ]; - - return newState.map(obj => { - const item = obj; - item.highlighted = false; - - return item; - }); - } - - case 'REMOVE_ITEM': { - // Set item to inactive - return state.map(obj => { - const item = obj; - if (item.id === action.id) { - item.active = false; - } - - return item; - }); - } - - case 'HIGHLIGHT_ITEM': { - return state.map(obj => { - const item = obj; - if (item.id === action.id) { - item.highlighted = action.highlighted; - } - - return item; - }); - } - - default: { - return state; - } - } -} diff --git a/src/scripts/reducers/items.test.js b/src/scripts/reducers/items.test.ts similarity index 95% rename from src/scripts/reducers/items.test.js rename to src/scripts/reducers/items.test.ts index 4041a3b..0a7262f 100644 --- a/src/scripts/reducers/items.test.js +++ b/src/scripts/reducers/items.test.ts @@ -1,9 +1,10 @@ import { expect } from 'chai'; import items, { defaultState } from './items'; +import { RemoveItemAction } from '../actions/items'; describe('reducers/items', () => { it('should return same state when no action matches', () => { - expect(items(defaultState, {})).to.equal(defaultState); + expect(items(defaultState, {} as any)).to.equal(defaultState); }); describe('when items do not exist', () => { @@ -16,7 +17,7 @@ describe('reducers/items', () => { const customProperties = { property: 'value', }; - const placeholder = 'This is a placeholder'; + const placeholder = true; const keyCode = 10; describe('passing expected values', () => { @@ -148,7 +149,7 @@ describe('reducers/items', () => { const actualResponse = items(clonedState, { type: 'REMOVE_ITEM', id, - }); + } as RemoveItemAction); expect(actualResponse).to.eql(expectedResponse); }); diff --git a/src/scripts/reducers/items.ts b/src/scripts/reducers/items.ts new file mode 100644 index 0000000..fb8432a --- /dev/null +++ b/src/scripts/reducers/items.ts @@ -0,0 +1,73 @@ +import { Item, State } from '../interfaces'; +import { + AddItemAction, + RemoveItemAction, + HighlightItemAction, +} from '../actions/items'; + +export const defaultState = []; + +type ActionTypes = AddItemAction | RemoveItemAction | HighlightItemAction; + +export default function items( + state: Item[] = defaultState, + action: ActionTypes, +): State['items'] { + switch (action.type) { + case 'ADD_ITEM': { + const addItemAction = action as AddItemAction; + // Add object to items array + const newState = [ + ...state, + { + id: addItemAction.id, + choiceId: addItemAction.choiceId, + groupId: addItemAction.groupId, + value: addItemAction.value, + label: addItemAction.label, + active: true, + highlighted: false, + customProperties: addItemAction.customProperties, + placeholder: addItemAction.placeholder || false, + keyCode: null, + }, + ]; + + return newState.map((obj: Item) => { + const item = obj; + item.highlighted = false; + + return item; + }); + } + + case 'REMOVE_ITEM': { + // Set item to inactive + return state.map(obj => { + const item = obj; + if (item.id === action.id) { + item.active = false; + } + + return item; + }); + } + + case 'HIGHLIGHT_ITEM': { + const highlightItemAction = action as HighlightItemAction; + + return state.map(obj => { + const item = obj; + if (item.id === highlightItemAction.id) { + item.highlighted = highlightItemAction.highlighted; + } + + return item; + }); + } + + default: { + return state; + } + } +} diff --git a/src/scripts/reducers/general.test.js b/src/scripts/reducers/loading.test.ts similarity index 62% rename from src/scripts/reducers/general.test.js rename to src/scripts/reducers/loading.test.ts index 01203dc..cbf9c4b 100644 --- a/src/scripts/reducers/general.test.js +++ b/src/scripts/reducers/loading.test.ts @@ -1,16 +1,14 @@ import { expect } from 'chai'; -import general, { defaultState } from './general'; +import general, { defaultState } from './loading'; -describe('reducers/general', () => { +describe('reducers/loading', () => { it('should return same state when no action matches', () => { - expect(general(defaultState, {})).to.equal(defaultState); + expect(general(defaultState, {} as any)).to.equal(defaultState); }); describe('SET_IS_LOADING', () => { it('sets loading state', () => { - const expectedState = { - loading: true, - }; + const expectedState = true; const actualState = general(undefined, { type: 'SET_IS_LOADING', diff --git a/src/scripts/reducers/loading.ts b/src/scripts/reducers/loading.ts new file mode 100644 index 0000000..58f6469 --- /dev/null +++ b/src/scripts/reducers/loading.ts @@ -0,0 +1,23 @@ +import { SetIsLoadingAction } from '../actions/misc'; +import { State } from '../interfaces'; + +export const defaultState = false; + +type ActionTypes = SetIsLoadingAction; + +const general = ( + state = defaultState, + action: ActionTypes, +): State['loading'] => { + switch (action.type) { + case 'SET_IS_LOADING': { + return action.isLoading; + } + + default: { + return state; + } + } +}; + +export default general; diff --git a/src/scripts/store/store.test.js b/src/scripts/store/store.test.ts similarity index 99% rename from src/scripts/store/store.test.js rename to src/scripts/store/store.test.ts index 63ebcc5..44fcaac 100644 --- a/src/scripts/store/store.test.js +++ b/src/scripts/store/store.test.ts @@ -33,7 +33,7 @@ describe('reducers/store', () => { describe('subscribe', () => { it('wraps redux subscribe method', () => { - const onChange = () => {}; + const onChange = (): void => {}; expect(subscribeStub.callCount).to.equal(0); instance.subscribe(onChange); expect(subscribeStub.callCount).to.equal(1); diff --git a/src/scripts/store/store.js b/src/scripts/store/store.ts similarity index 58% rename from src/scripts/store/store.js rename to src/scripts/store/store.ts index 4fb7888..cffbf51 100644 --- a/src/scripts/store/store.js +++ b/src/scripts/store/store.ts @@ -1,108 +1,93 @@ -import { createStore } from 'redux'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { createStore, Store as IStore, AnyAction } from 'redux'; import rootReducer from '../reducers/index'; - -/** - * @typedef {import('../../../types/index').Choices.Choice} Choice - * @typedef {import('../../../types/index').Choices.Group} Group - * @typedef {import('../../../types/index').Choices.Item} Item - */ +import { Choice, Group, Item, State } from '../interfaces'; export default class Store { + _store: IStore; + constructor() { this._store = createStore( rootReducer, - window.__REDUX_DEVTOOLS_EXTENSION__ && - window.__REDUX_DEVTOOLS_EXTENSION__(), + (window as any).__REDUX_DEVTOOLS_EXTENSION__ && + (window as any).__REDUX_DEVTOOLS_EXTENSION__(), ); } /** * Subscribe store to function call (wrapped Redux method) - * @param {Function} onChange Function to trigger when state changes - * @return */ - subscribe(onChange) { + subscribe(onChange: () => void): void { this._store.subscribe(onChange); } /** * Dispatch event to store (wrapped Redux method) - * @param {{ type: string, [x: string]: any }} action Action to trigger - * @return */ - dispatch(action) { + dispatch(action: AnyAction): void { this._store.dispatch(action); } /** * Get store object (wrapping Redux method) - * @returns {object} State */ - get state() { + get state(): State { return this._store.getState(); } /** * Get items from store - * @returns {Item[]} Item objects */ - get items() { + get items(): Item[] { return this.state.items; } /** * Get active items from store - * @returns {Item[]} Item objects */ - get activeItems() { + get activeItems(): Item[] { return this.items.filter(item => item.active === true); } /** * Get highlighted items from store - * @returns {Item[]} Item objects */ - get highlightedActiveItems() { + get highlightedActiveItems(): Item[] { return this.items.filter(item => item.active && item.highlighted); } /** * Get choices from store - * @returns {Choice[]} Option objects */ - get choices() { + get choices(): Choice[] { return this.state.choices; } /** * Get active choices from store - * @returns {Choice[]} Option objects */ - get activeChoices() { + get activeChoices(): Choice[] { return this.choices.filter(choice => choice.active === true); } /** * Get selectable choices from store - * @returns {Choice[]} Option objects */ - get selectableChoices() { + get selectableChoices(): Choice[] { return this.choices.filter(choice => choice.disabled !== true); } /** * Get choices that can be searched (excluding placeholders) - * @returns {Choice[]} Option objects */ - get searchableChoices() { + get searchableChoices(): Choice[] { return this.selectableChoices.filter(choice => choice.placeholder !== true); } /** * Get placeholder choice from store - * @returns {Choice | undefined} Found placeholder */ - get placeholderChoice() { + get placeholderChoice(): Choice | undefined { return [...this.choices] .reverse() .find(choice => choice.placeholder === true); @@ -110,17 +95,15 @@ export default class Store { /** * Get groups from store - * @returns {Group[]} Group objects */ - get groups() { + get groups(): Group[] { return this.state.groups; } /** * Get active groups from store - * @returns {Group[]} Group objects */ - get activeGroups() { + get activeGroups(): Group[] { const { groups, choices } = this; return groups.filter(group => { @@ -135,27 +118,22 @@ export default class Store { /** * Get loading state from store - * @returns {boolean} Loading State */ - isLoading() { - return this.state.general.loading; + isLoading(): boolean { + return this.state.loading; } /** * Get single choice by it's ID - * @param {string} id - * @returns {Choice | undefined} Found choice */ - getChoiceById(id) { + getChoiceById(id: string): Choice | undefined { return this.activeChoices.find(choice => choice.id === parseInt(id, 10)); } /** * Get group by group id - * @param {number} id Group ID - * @returns {Group | undefined} Group data */ - getGroupById(id) { + getGroupById(id: number): Group | undefined { return this.groups.find(group => group.id === id); } } diff --git a/src/scripts/templates.test.js b/src/scripts/templates.test.ts similarity index 99% rename from src/scripts/templates.test.js rename to src/scripts/templates.test.ts index 2db8ed8..363cfa7 100644 --- a/src/scripts/templates.test.js +++ b/src/scripts/templates.test.ts @@ -3,11 +3,10 @@ import templates from './templates'; import { strToEl } from './lib/utils'; /** - * * @param {HTMLElement} element1 * @param {HTMLElement} element2 */ -function expectEqualElements(element1, element2) { +function expectEqualElements(element1, element2): void { expect(element1.tagName).to.equal(element2.tagName); expect(element1.attributes.length).to.equal(element2.attributes.length); expect(Object.keys(element1.dataset)).to.have.members( @@ -516,11 +515,10 @@ describe('templates', () => { }; it('returns expected html', () => { - const value = 'test'; const expectedOutput = strToEl( ``, ); - const actualOutput = templates.dropdown(classes, value); + const actualOutput = templates.dropdown(classes); expectEqualElements(actualOutput, expectedOutput); }); diff --git a/src/scripts/templates.js b/src/scripts/templates.ts similarity index 65% rename from src/scripts/templates.js rename to src/scripts/templates.ts index eb4f2ea..cb56921 100644 --- a/src/scripts/templates.js +++ b/src/scripts/templates.ts @@ -1,31 +1,19 @@ +import { ClassNames, Item, Choice, Group, PassedElement } from './interfaces'; + /** * Helpers to create HTML elements used by Choices * Can be overridden by providing `callbackOnCreateTemplates` option - * @typedef {import('../../types/index').Choices.Templates} Templates - * @typedef {import('../../types/index').Choices.ClassNames} ClassNames - * @typedef {import('../../types/index').Choices.Options} Options - * @typedef {import('../../types/index').Choices.Item} Item - * @typedef {import('../../types/index').Choices.Choice} Choice - * @typedef {import('../../types/index').Choices.Group} Group */ -export const TEMPLATES = /** @type {Templates} */ ({ - /** - * @param {Partial} classNames - * @param {"ltr" | "rtl" | "auto"} dir - * @param {boolean} isSelectElement - * @param {boolean} isSelectOneElement - * @param {boolean} searchEnabled - * @param {"select-one" | "select-multiple" | "text"} passedElementType - */ +const templates = { containerOuter( - { containerOuter }, - dir, - isSelectElement, - isSelectOneElement, - searchEnabled, - passedElementType, - ) { + { containerOuter }: Pick, + dir: HTMLElement['dir'], + isSelectElement: boolean, + isSelectOneElement: boolean, + searchEnabled: boolean, + passedElementType: PassedElement['type'], + ): HTMLDivElement { const div = Object.assign(document.createElement('div'), { className: containerOuter, }); @@ -53,43 +41,48 @@ export const TEMPLATES = /** @type {Templates} */ ({ return div; }, - /** - * @param {Partial} classNames - */ - containerInner({ containerInner }) { + containerInner({ + containerInner, + }: Pick): HTMLDivElement { return Object.assign(document.createElement('div'), { className: containerInner, }); }, - /** - * @param {Partial} classNames - * @param {boolean} isSelectOneElement - */ - itemList({ list, listSingle, listItems }, isSelectOneElement) { + itemList( + { + list, + listSingle, + listItems, + }: Pick, + isSelectOneElement: boolean, + ): HTMLDivElement { return Object.assign(document.createElement('div'), { className: `${list} ${isSelectOneElement ? listSingle : listItems}`, }); }, - /** - * @param {Partial} classNames - * @param {string} value - */ - placeholder({ placeholder }, value) { + placeholder( + { placeholder }: Pick, + value: string, + ): HTMLDivElement { return Object.assign(document.createElement('div'), { className: placeholder, innerHTML: value, }); }, - /** - * @param {Partial} classNames - * @param {Item} item - * @param {boolean} removeItemButton - */ item( - { item, button, highlightedState, itemSelectable, placeholder }, + { + item, + button, + highlightedState, + itemSelectable, + placeholder, + }: Pick< + ClassNames, + 'item' | 'button' | 'highlightedState' | 'itemSelectable' | 'placeholder' + >, { id, value, @@ -99,9 +92,9 @@ export const TEMPLATES = /** @type {Templates} */ ({ disabled, highlighted, placeholder: isPlaceholder, - }, - removeItemButton, - ) { + }: Item, + removeItemButton: boolean, + ): HTMLDivElement { const div = Object.assign(document.createElement('div'), { className: item, innerHTML: label, @@ -151,11 +144,10 @@ export const TEMPLATES = /** @type {Templates} */ ({ return div; }, - /** - * @param {Partial} classNames - * @param {boolean} isSelectOneElement - */ - choiceList({ list }, isSelectOneElement) { + choiceList( + { list }: Pick, + isSelectOneElement: boolean, + ): HTMLDivElement { const div = Object.assign(document.createElement('div'), { className: list, }); @@ -168,11 +160,14 @@ export const TEMPLATES = /** @type {Templates} */ ({ return div; }, - /** - * @param {Partial} classNames - * @param {Group} group - */ - choiceGroup({ group, groupHeading, itemDisabled }, { id, value, disabled }) { + choiceGroup( + { + group, + groupHeading, + itemDisabled, + }: Pick, + { id, value, disabled }: Group, + ): HTMLDivElement { const div = Object.assign(document.createElement('div'), { className: `${group} ${disabled ? itemDisabled : ''}`, }); @@ -199,11 +194,6 @@ export const TEMPLATES = /** @type {Templates} */ ({ return div; }, - /** - * @param {Partial} classNames - * @param {Choice} choice - * @param {Options['itemSelectText']} selectText - */ choice( { item, @@ -212,7 +202,15 @@ export const TEMPLATES = /** @type {Templates} */ ({ selectedState, itemDisabled, placeholder, - }, + }: Pick< + ClassNames, + | 'item' + | 'itemChoice' + | 'itemSelectable' + | 'selectedState' + | 'itemDisabled' + | 'placeholder' + >, { id, value, @@ -222,9 +220,9 @@ export const TEMPLATES = /** @type {Templates} */ ({ disabled: isDisabled, selected: isSelected, placeholder: isPlaceholder, - }, - selectText, - ) { + }: Choice, + selectText: string, + ): HTMLDivElement { const div = Object.assign(document.createElement('div'), { id: elementId, innerHTML: label, @@ -239,7 +237,7 @@ export const TEMPLATES = /** @type {Templates} */ ({ div.classList.add(placeholder); } - div.setAttribute('role', groupId > 0 ? 'treeitem' : 'option'); + div.setAttribute('role', groupId && groupId > 0 ? 'treeitem' : 'option'); Object.assign(div.dataset, { choice: '', @@ -260,11 +258,10 @@ export const TEMPLATES = /** @type {Templates} */ ({ return div; }, - /** - * @param {Partial} classNames - * @param {string} placeholderValue - */ - input({ input, inputCloned }, placeholderValue) { + input( + { input, inputCloned }: Pick, + placeholderValue: string, + ): HTMLInputElement { const inp = Object.assign(document.createElement('input'), { type: 'text', className: `${input} ${inputCloned}`, @@ -280,10 +277,10 @@ export const TEMPLATES = /** @type {Templates} */ ({ return inp; }, - /** - * @param {Partial} classNames - */ - dropdown({ list, listDropdown }) { + dropdown({ + list, + listDropdown, + }: Pick): HTMLDivElement { const div = document.createElement('div'); div.classList.add(list, listDropdown); @@ -292,13 +289,16 @@ export const TEMPLATES = /** @type {Templates} */ ({ return div; }, - /** - * - * @param {Partial} classNames - * @param {string} innerHTML - * @param {"no-choices" | "no-results" | ""} type - */ - notice({ item, itemChoice, noResults, noChoices }, innerHTML, type = '') { + notice( + { + item, + itemChoice, + noResults, + noChoices, + }: Pick, + innerHTML: string, + type: 'no-choices' | 'no-results' | '' = '', + ): HTMLDivElement { const classes = [item, itemChoice]; if (type === 'no-choices') { @@ -313,19 +313,23 @@ export const TEMPLATES = /** @type {Templates} */ ({ }); }, - /** - * @param {Item} option - */ - option({ label, value, customProperties, active, disabled }) { + option({ + label, + value, + customProperties, + active, + disabled, + }: Item): HTMLOptionElement { const opt = new Option(label, value, false, active); if (customProperties) { - opt.dataset.customProperties = customProperties; + opt.dataset.customProperties = `${customProperties}`; } - opt.disabled = disabled; + + opt.disabled = !!disabled; return opt; }, -}); +}; -export default TEMPLATES; +export default templates; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fa16413 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "baseUrl": "/", + "outDir": "./dist/", + "allowJs": true, + "sourceMap": true, + "module": "commonjs", + "esModuleInterop": true, + "target": "es5", + "lib": ["es2017", "dom"], + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitAny": false, + "strictNullChecks": true, + "types": ["cypress"] + }, + "include": ["./src/**/*", "./cypress/**/*"] +} diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index d3520bd..0000000 --- a/types/index.d.ts +++ /dev/null @@ -1,1041 +0,0 @@ -// Type definitions for Choices.js -// Project: https://github.com/jshjohnson/Choices -// Definitions by: -// Arthur vasconcelos , -// Josh Johnson , -// Zack Schuster -// Konstantin Vyatkin -// Definitions: https://github.com/jshjohnson/Choices - -import { FuseOptions } from 'fuse.js'; - -// Choices Namespace -declare namespace Choices { - namespace Types { - type strToEl = ( - str: string, - ) => HTMLElement | HTMLInputElement | HTMLOptionElement; - type stringFunction = () => string; - type noticeStringFunction = (value: string) => string; - type noticeLimitFunction = (maxItemCount: number) => string; - type filterFunction = (value: string) => boolean; - type valueCompareFunction = (value1: string, value2: string) => boolean; - } - - interface Choice { - id?: number; - customProperties?: Record; - disabled?: boolean; - active?: boolean; - elementId?: string; - groupId?: number; - keyCode?: number; - label: string; - placeholder?: boolean; - selected?: boolean; - value: string; - } - - interface Group { - id?: number; - active?: boolean; - disabled?: boolean; - value: any; - } - - interface Item extends Choice { - choiceId?: number; - keyCode?: number; - highlighted?: boolean; - } - - /** - * Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object. - */ - interface EventMap { - /** - * Triggered each time an item is added (programmatically or by the user). - * - * **Input types affected:** text, select-one, select-multiple - * - * Arguments: id, value, label, groupValue, keyCode - */ - addItem: CustomEvent<{ - id: number; - value: string; - label: string; - groupValue: string; - keyCode: number; - }>; - - /** - * Triggered each time an item is removed (programmatically or by the user). - * - * **Input types affected:** text, select-one, select-multiple - * - * Arguments: id, value, label, groupValue - */ - removeItem: CustomEvent<{ - id: number; - value: string; - label: string; - groupValue: string; - }>; - - /** - * Triggered each time an item is highlighted. - * - * **Input types affected:** text, select-multiple - * - * Arguments: id, value, label, groupValue - */ - highlightItem: CustomEvent<{ - id: number; - value: string; - label: string; - groupValue: string; - }>; - - /** - * Triggered each time an item is unhighlighted. - * - * **Input types affected:** text, select-multiple - * - * Arguments: id, value, label, groupValue - */ - unhighlightItem: CustomEvent<{ - id: number; - value: string; - label: string; - groupValue: string; - }>; - - /** - * Triggered each time a choice is selected **by a user**, regardless if it changes the value of the input. - * - * **Input types affected:** select-one, select-multiple - * - * Arguments: choice: Choice - */ - choice: CustomEvent<{ choice: Choices.Choice }>; - - /** - * Triggered each time an item is added/removed **by a user**. - * - * **Input types affected:** text, select-one, select-multiple - * - * Arguments: value - */ - change: CustomEvent<{ value: string }>; - - /** - * Triggered when a user types into an input to search choices. - * - * **Input types affected:** select-one, select-multiple - * - * Arguments: value, resultCount - */ - search: CustomEvent<{ value: string; resultCount: number }>; - - /** - * Triggered when the dropdown is shown. - * - * **Input types affected:** select-one, select-multiple - * - * Arguments: - - */ - showDropdown: CustomEvent; - - /** - * Triggered when the dropdown is hidden. - * - * **Input types affected:** select-one, select-multiple - * - * Arguments: - - */ - hideDropdown: CustomEvent; - - /** - * Triggered when a choice from the dropdown is highlighted. - * - * Input types affected: select-one, select-multiple - * Arguments: el is the choice.passedElement that was affected. - */ - highlightChoice: CustomEvent<{ el: Choices.passedElement }>; - } - - interface Templates { - containerOuter: ( - this: Choices, - classNames: ClassNames, - direction: HTMLElement['dir'], - isSelectElement: boolean, - isSelectOneElement: boolean, - searchEnabled: boolean, - passedElementType: passedElement['type'], - ) => HTMLElement; - containerInner: (this: Choices, classNames: ClassNames) => HTMLElement; - itemList: ( - this: Choices, - classNames: ClassNames, - isSelectOneElement: boolean, - ) => HTMLElement; - placeholder: ( - this: Choices, - classNames: ClassNames, - value: string, - ) => HTMLElement; - item: ( - this: Choices, - classNames: ClassNames, - data: Choice, - removeItemButton: boolean, - ) => HTMLElement; - choiceList: ( - this: Choices, - classNames: ClassNames, - isSelectOneElement: boolean, - ) => HTMLElement; - choiceGroup: ( - this: Choices, - classNames: ClassNames, - data: Choice, - ) => HTMLElement; - choice: ( - this: Choices, - classNames: ClassNames, - data: Choice, - selectText: string, - ) => HTMLElement; - input: ( - this: Choices, - classNames: ClassNames, - placeholderValue: string, - ) => HTMLInputElement; - dropdown: (this: Choices, classNames: ClassNames) => HTMLElement; - notice: ( - this: Choices, - classNames: ClassNames, - label: string, - type: '' | 'no-results' | 'no-choices', - ) => HTMLElement; - option: (data: Choice) => HTMLOptionElement; - } - - /** Classes added to HTML generated by Choices. By default classnames follow the BEM notation. */ - interface ClassNames { - /** @default 'choices' */ - containerOuter: string; - /** @default 'choices__inner' */ - containerInner: string; - /** @default 'choices__input' */ - input: string; - /** @default 'choices__input--cloned' */ - inputCloned: string; - /** @default 'choices__list' */ - list: string; - /** @default 'choices__list--multiple' */ - listItems: string; - /** @default 'choices__list--single' */ - listSingle: string; - /** @default 'choices__list--dropdown' */ - listDropdown: string; - /** @default 'choices__item' */ - item: string; - /** @default 'choices__item--selectable' */ - itemSelectable: string; - /** @default 'choices__item--disabled' */ - itemDisabled: string; - /** @default 'choices__item--choice' */ - itemChoice: string; - /** @default 'choices__placeholder' */ - placeholder: string; - /** @default 'choices__group' */ - group: string; - /** @default 'choices__heading' */ - groupHeading: string; - /** @default 'choices__button' */ - button: string; - /** @default 'is-active' */ - activeState: string; - /** @default 'is-focused' */ - focusState: string; - /** @default 'is-open' */ - openState: string; - /** @default 'is-disabled' */ - disabledState: string; - /** @default 'is-highlighted' */ - highlightedState: string; - /** @default 'is-selected' */ - selectedState: string; - /** @default 'is-flipped' */ - flippedState: string; - /** @default 'is-loading' */ - loadingState: string; - /** @default 'has-no-results' */ - noResults: string; - /** @default 'has-no-choices' */ - noChoices: string; - } - - interface passedElement { - classNames: Choices.ClassNames; - element: (HTMLInputElement | HTMLSelectElement) & { - // Extends HTMLElement addEventListener with Choices events - addEventListener( - type: K, - listener: ( - this: HTMLInputElement | HTMLSelectElement, - ev: Choices.EventMap[K], - ) => void, - options?: boolean | AddEventListenerOptions, - ): void; - }; - type: 'text' | 'select-one' | 'select-multiple'; - isDisabled: boolean; - parentInstance: Choices; - } - - /** - * Choices options interface - * - * **Terminology** - * - * - **Choice:** A choice is a value a user can select. A choice would be equivalent to the `` element within a select input. - * - **Group:** A group is a collection of choices. A group should be seen as equivalent to a `` element within a select input. - * - **Item:** An item is an inputted value **_(text input)_** or a selected choice **_(select element)_**. In the context of a select element, an item is equivelent to a selected option element: `` whereas in the context of a text input an item is equivelant to `` - */ - interface Options { - /** - * Optionally suppress console errors and warnings. - * - * **Input types affected:** text, select-single, select-multiple - * - * @default false - */ - silent: boolean; - - /** - * Add pre-selected items (see terminology) to text input. - * - * **Input types affected:** text - * - * @example - * ``` - * ['value 1', 'value 2', 'value 3'] - * ``` - * - * @example - * ``` - * [{ - * value: 'Value 1', - * label: 'Label 1', - * id: 1 - * }, - * { - * value: 'Value 2', - * label: 'Label 2', - * id: 2, - * customProperties: { - * random: 'I am a custom property' - * } - * }] - * ``` - * - * @default [] - */ - items: string[] | Choice[]; - - /** - * Add choices (see terminology) to select input. - * - * **Input types affected:** select-one, select-multiple - * - * @example - * ``` - * [{ - * value: 'Option 1', - * label: 'Option 1', - * selected: true, - * disabled: false, - * }, - * { - * value: 'Option 2', - * label: 'Option 2', - * selected: false, - * disabled: true, - * customProperties: { - * description: 'Custom description about Option 2', - * random: 'Another random custom property' - * }, - * }] - * ``` - * - * @default [] - */ - choices: Choice[]; - - /** - * The amount of choices to be rendered within the dropdown list `("-1" indicates no limit)`. This is useful if you have a lot of choices where it is easier for a user to use the search area to find a choice. - * - * **Input types affected:** select-one, select-multiple - * - * @default -1 - */ - renderChoiceLimit: number; - - /** - * The amount of items a user can input/select `("-1" indicates no limit)`. - * - * **Input types affected:** text, select-multiple - * - * @default -1 - */ - maxItemCount: number; - - /** - * Whether a user can add items. - * - * **Input types affected:** text - * - * @default true - */ - addItems: boolean; - - /** - * A filter that will need to pass for a user to successfully add an item. - * - * **Input types affected:** text - * - * @default null - */ - addItemFilter: string | RegExp | Choices.Types.filterFunction | null; - - /** - * The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string. - * - * **Input types affected:** text - * - * @default - * ``` - * (value) => `Press Enter to add "${value}"`; - * ``` - */ - addItemText: string | Choices.Types.noticeStringFunction; - - /** - * Whether a user can remove items. - * - * **Input types affected:** text, select-multiple - * - * @default true - */ - removeItems: boolean; - - /** - * Whether each item should have a remove button. - * - * **Input types affected:** text, select-one, select-multiple - * - * @default false - */ - removeItemButton: boolean; - - /** - * Whether a user can edit items. An item's value can be edited by pressing the backspace. - * - * **Input types affected:** text - * - * @default false - */ - editItems: boolean; - - /** - * Whether each inputted/chosen item should be unique. - * - * **Input types affected:** text, select-multiple - * - * @default true - */ - duplicateItemsAllowed: boolean; - - /** - * What divides each value. The default delimiter separates each value with a comma: `"Value 1, Value 2, Value 3"`. - * - * **Input types affected:** text - * - * @default ',' - */ - delimiter: string; - - /** - * Whether a user can paste into the input. - * - * **Input types affected:** text, select-multiple - * - * @default true - */ - paste: boolean; - - /** - * Whether a search area should be shown. - * - * @note Multiple select boxes will always show search areas. - * - * **Input types affected:** select-one - * - * @default true - */ - searchEnabled: boolean; - - /** - * Whether choices should be filtered by input or not. If `false`, the search event will still emit, but choices will not be filtered. - * - * **Input types affected:** select-one - * - * @default true - */ - searchChoices: boolean; - - /** - * The minimum length a search value should be before choices are searched. - * - * **Input types affected:** select-one, select-multiple - * - * @default 1 - */ - searchFloor: number; - - /** - * The maximum amount of search results to show. - * - * **Input types affected:** select-one, select-multiple - * - * @default 4 - */ - searchResultLimit: number; - - /** - * Specify which fields should be used when a user is searching. If you have added custom properties to your choices, you can add these values thus: `['label', 'value', 'customProperties.example']`. - * - * Input types affected:select-one, select-multiple - * - * @default ['label', 'value'] - */ - searchFields: string[]; - - /** - * Whether the dropdown should appear above `(top)` or below `(bottom)` the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it. - * - * **Input types affected:** select-one, select-multiple - * - * @default 'auto' - */ - position: 'auto' | 'top'; - - /** - * Whether the scroll position should reset after adding an item. - * - * **Input types affected:** select-multiple - * - * @default true - */ - resetScrollPosition: boolean; - - /** - * Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given. - * - * **Input types affected:** select-one, select-multiple - * - * @default true - */ - shouldSort: boolean; - - /** - * Whether items should be sorted. If false, items will appear in the order they were selected. - * - * **Input types affected:** text, select-multiple - * - * @default false - */ - shouldSortItems: boolean; - - /** - * The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order. - * - * **Input types affected:** select-one, select-multiple - * - * @example - * ``` - * // Sorting via length of label from largest to smallest - * const example = new Choices(element, { - * sorter: function(a, b) { - * return b.label.length - a.label.length; - * }, - * }; - * ``` - * - * @default sortByAlpha - */ - sorter: (current: Choice, next: Choice) => number; - - /** - * Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value. - * - * **Input types affected:** text, select-multiple - * - * @note For single select boxes, the recommended way of adding a placeholder is as follows: - * ``` - * - * ``` - * - * @default true - */ - placeholder: boolean; - - /** - * The value of the inputs placeholder. - * - * **Input types affected:** text, select-multiple - * - * @default null - */ - placeholderValue: string | null; - - /** - * The value of the search inputs placeholder. - * - * **Input types affected:** select-one - * - * @default null - */ - searchPlaceholderValue: string | null; - - /** - * Prepend a value to each item added/selected. - * - * **Input types affected:** text, select-one, select-multiple - * - * @default null - */ - prependValue: string | null; - - /** - * Append a value to each item added/selected. - * - * **Input types affected:** text, select-one, select-multiple - * - * @default null - */ - appendValue: string | null; - - /** - * Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass `always`. - * - * **Input types affected:** select-one, select-multiple - * - * @default 'auto'; - */ - renderSelectedChoices: 'auto' | 'always'; - - /** - * The text that is shown whilst choices are being populated via AJAX. - * - * **Input types affected:** select-one, select-multiple - * - * @default 'Loading...' - */ - loadingText: string; - - /** - * The text that is shown when a user's search has returned no results. Optionally pass a function returning a string. - * - * **Input types affected:** select-one, select-multiple - * - * @default 'No results found' - */ - noResultsText: string | Choices.Types.stringFunction; - - /** - * The text that is shown when a user has selected all possible choices. Optionally pass a function returning a string. - * - * **Input types affected:** select-multiple - * - * @default 'No choices to choose from' - */ - noChoicesText: string | Choices.Types.stringFunction; - - /** - * The text that is shown when a user hovers over a selectable choice. - * - * **Input types affected:** select-multiple, select-one - * - * @default 'Press to select' - */ - itemSelectText: string; - - /** - * The text that is shown when a user has focus on the input but has already reached the **max item count** [https://github.com/jshjohnson/Choices#maxitemcount]. To access the max item count, pass a function with a `maxItemCount` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string. - * - * **Input types affected:** text - * - * @default - * ``` - * (maxItemCount) => `Only ${maxItemCount} values can be added.`; - * ``` - */ - maxItemText: string | Choices.Types.noticeLimitFunction; - - /** - * If no duplicates are allowed, and the value already exists in the array. - * - * @default 'Only unique values can be added' - */ - uniqueItemText: string | Choices.Types.noticeStringFunction; - - /** - * The text that is shown when addItemFilter is passed and it returns false - * - * **Input types affected:** text - * - * @default 'Only values matching specific conditions can be added' - */ - customAddItemText: string | Choices.Types.noticeStringFunction; - - /** - * Compare choice and value in appropriate way (e.g. deep equality for objects). To compare choice and value, pass a function with a `valueComparer` argument (see the [default config](https://github.com/jshjohnson/Choices#setup) for an example). - * - * **Input types affected:** select-one, select-multiple - * - * @default - * ``` - * (choice, item) => choice === item; - * ``` - */ - valueComparer: Choices.Types.valueCompareFunction; - - /** - * Classes added to HTML generated by Choices. By default classnames follow the BEM notation. - * - * **Input types affected:** text, select-one, select-multiple - */ - classNames: Choices.ClassNames; - - /** - * Choices uses the great Fuse library for searching. You can find more options here: https://github.com/krisk/Fuse#options - */ - fuseOptions: FuseOptions; - - /** - * Function to run once Choices initialises. - * - * **Input types affected:** text, select-one, select-multiple - * - * @note For each callback, this refers to the current instance of Choices. This can be useful if you need access to methods `(this.disable())` or the config object `(this.config)`. - * - * @default null - */ - callbackOnInit: ((this: Choices) => void) | null; - - /** - * Function to run on template creation. Through this callback it is possible to provide custom templates for the various components of Choices (see terminology). For Choices to work with custom templates, it is important you maintain the various data attributes defined here [https://github.com/jshjohnson/Choices/blob/67f29c286aa21d88847adfcd6304dc7d068dc01f/assets/scripts/src/choices.js#L1993-L2067]. - * - * **Input types affected:** text, select-one, select-multiple - * - * @note For each callback, this refers to the current instance of Choices. This can be useful if you need access to methods `(this.disable())` or the config object `(this.config)`. - * - * @example - * ``` - * const example = new Choices(element, { - * callbackOnCreateTemplates: function (template) { - * var classNames = this.config.classNames; - * return { - * item: (data) => { - * return template(` - *
- * ${data.label} - *
- * `); - * }, - * choice: (data) => { - * return template(` - *
0 ? 'role="treeitem"' : 'role="option"'}> - * ${data.label} - *
- * `); - * }, - * }; - * } - * }); - * ``` - * - * @default null - */ - callbackOnCreateTemplates: - | ((template: Choices.Types.strToEl) => Partial) - | null; - } - - interface KeyDownAction { - event: KeyboardEvent; - activeItems: Item[]; - hasFocusedInput: boolean; - hasActiveDropdown: boolean; - hasItems: boolean; - } -} - -// Exporting default class -export default class Choices { - static readonly defaults: { - readonly options: Partial; - readonly templates: Choices.Templates; - }; - readonly config: Choices.Options; - - // State Tracking - initialised: boolean; - - // Element - readonly passedElement: Choices.passedElement; - - placeholder: boolean; - - constructor( - selectorOrElement: string | HTMLInputElement | HTMLSelectElement, - userConfig?: Partial, - ); - - /** - * Creates a new instance of Choices, adds event listeners, creates templates and renders a Choices element to the DOM. - * - * @note This is called implicitly when a new instance of Choices is created. This would be used after a Choices instance had already been destroyed `(using destroy())`. - * - * **Input types affected:** text, select-multiple, select-one - */ - init(): void; - - /** - * Kills the instance of Choices, removes all event listeners and returns passed input to its initial state. - * - * **Input types affected:** text, select-multiple, select-one - */ - destroy(): void; - - /** Select item (a selected item can be deleted) */ - highlightItem(item: Element, runEvent?: boolean): this; - - /** Deselect item */ - unhighlightItem(item: Element): this; - - /** - * Highlight each chosen item (selected items can be removed). - * - * **Input types affected:** text, select-multiple - */ - highlightAll(): this; - - /** - * Un-highlight each chosen item. - * - * **Input types affected:** text, select-multiple - */ - unhighlightAll(): this; - - /** - * Remove each item by a given value. - * - * **Input types affected:** text, select-multiple - */ - removeActiveItemsByValue(value: string): this; - - /** - * Remove each selectable item. - * - * **Input types affected:** text, select-multiple - */ - removeActiveItems(excludedId: number): this; - - /** - * Remove each item the user has selected. - * - * **Input types affected:** text, select-multiple - */ - removeHighlightedItems(runEvent?: boolean): this; - - /** - * Show option list dropdown (only affects select inputs). - * - * **Input types affected:** select-one, select-multiple - */ - showDropdown(focusInput?: boolean): this; - - /** - * Hide option list dropdown (only affects select inputs). - * - * **Input types affected:** text, select-multiple - */ - hideDropdown(blurInput?: boolean): this; - - /** - * Get value(s) of input (i.e. inputted items (text) or selected choices (select)). Optionally pass an argument of `true` to only return values rather than value objects. - * - * **Input types affected:** text, select-one, select-multiple - * - * @example - * ``` - * const example = new Choices(element); - * const values = example.getValue(true); // returns ['value 1', 'value 2']; - * const valueArray = example.getValue(); // returns [{ active: true, choiceId: 1, highlighted: false, id: 1, label: 'Label 1', value: 'Value 1'}, { active: true, choiceId: 2, highlighted: false, id: 2, label: 'Label 2', value: 'Value 2'}]; - * ``` - */ - getValue(valueOnly?: boolean): string | string[]; - - /** Direct populate choices - * - * @param {string[] | Choices.Item[]} items - */ - setValue(items: string[] | Choices.Item[]): this; - - /** - * Set value of input based on existing Choice. `value` can be either a single string or an array of strings - * - * **Input types affected:** select-one, select-multiple - * - * @example - * ``` - * const example = new Choices(element, { - * choices: [ - * {value: 'One', label: 'Label One'}, - * {value: 'Two', label: 'Label Two', disabled: true}, - * {value: 'Three', label: 'Label Three'}, - * ], - * }); - * - * example.setChoiceByValue('Two'); // Choice with value of 'Two' has now been selected. - * ``` - */ - setChoiceByValue(value: string | string[]): this; - - /** - * Set choices of select input via an array of objects (or function that returns array of object or promise of it), - * a value field name and a label field name. - * This behaves the same as passing items via the choices option but can be called after initialising Choices. - * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices. - * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc). - * - * **Input types affected:** select-one, select-multiple - * - * @param {string} [value = 'value'] - name of `value` field - * @param {string} [label = 'label'] - name of 'label' field - * @param {boolean} [replaceChoices = false] - whether to replace of add choices - * - * @example - * ```js - * const example = new Choices(element); - * - * example.setChoices([ - * {value: 'One', label: 'Label One', disabled: true}, - * {value: 'Two', label: 'Label Two', selected: true}, - * {value: 'Three', label: 'Label Three'}, - * ], 'value', 'label', false); - * ``` - * - * @example - * ```js - * const example = new Choices(element); - * - * example.setChoices(async () => { - * try { - * const items = await fetch('/items'); - * return items.json() - * } catch(err) { - * console.error(err) - * } - * }); - * ``` - * - * @example - * ```js - * const example = new Choices(element); - * - * example.setChoices([{ - * label: 'Group one', - * id: 1, - * disabled: false, - * choices: [ - * {value: 'Child One', label: 'Child One', selected: true}, - * {value: 'Child Two', label: 'Child Two', disabled: true}, - * {value: 'Child Three', label: 'Child Three'}, - * ] - * }, - * { - * label: 'Group two', - * id: 2, - * disabled: false, - * choices: [ - * {value: 'Child Four', label: 'Child Four', disabled: true}, - * {value: 'Child Five', label: 'Child Five'}, - * {value: 'Child Six', label: 'Child Six', customProperties: { - * description: 'Custom description about child six', - * random: 'Another random custom property' - * }}, - * ] - * }], 'value', 'label', false); - * ``` - */ - setChoices< - T extends object[] | ((instance: Choices) => object[] | Promise) - >( - choices: T, - value?: string, - label?: string, - replaceChoices?: boolean, - ): T extends object[] ? this : Promise; - - /** - * Clear all choices from select. - * - * **Input types affected:** select-one, select-multiple - */ - clearChoices(): this; - - /** - * Removes all items, choices and groups. Use with caution. - * - * **Input types affected:** text, select-one, select-multiple - */ - clearStore(): this; - - /** - * Clear input of any user inputted text. - * - * **Input types affected:** text - */ - clearInput(): this; - - /** - * Enables input to accept new values/select further choices. - * - * **Input types affected:** text, select-one, select-multiple - */ - enable(): this; - - /** - * Disables input from accepting new value/selecting further choices. - * - * **Input types affected:** text, select-one, select-multiple - */ - disable(): this; - - _onEnterKey(keyDownAction: Partial): void; - _onAKey(keyDownAction: Partial): void; - _onEscapeKey(keyDownAction: Partial): void; - _onDirectionKey(keyDownAction: Partial): void; - _onDeleteKey(keyDownAction: Partial): void; -} diff --git a/webpack.config.base.js b/webpack.config.base.js index 44e4438..9372e77 100644 --- a/webpack.config.base.js +++ b/webpack.config.base.js @@ -8,12 +8,6 @@ const exclude = /node_modules/; */ module.exports = { entry: ['./src/scripts/choices'], - output: { - library: 'Choices', - libraryTarget: 'window', - libraryExport: 'default', - globalObject: 'window', - }, module: { rules: [ { @@ -28,13 +22,28 @@ module.exports = { }, { loader: 'babel-loader', - test: /\.js?$/, + test: /\.ts?$/, include, exclude, options: { babelrc: true, }, }, + { + loader: 'ts-loader', + test: /\.ts?$/, + include, + exclude + } ], }, + resolve: { + extensions: [".ts", ".js"] + }, + output: { + library: 'Choices', + libraryTarget: 'window', + libraryExport: 'default', + globalObject: 'window', + }, };