@@ -14,6 +14,7 @@ import {
1414 start ,
1515 accumulate ,
1616 onceStateChangesTo ,
17+ readContext ,
1718} from "./index" ;
1819
1920test ( "node version " + process . version , ( ) => { } ) ;
@@ -707,32 +708,205 @@ describe("Wrapping AbortController as a state machine", () => {
707708
708709describe ( "Button click" , ( ) => {
709710 function ButtonClickListener ( button : HTMLButtonElement ) {
710- function * initial ( ) {
711- yield on ( "click" , clicked ) ;
711+ function * Initial ( ) {
712+ yield on ( "click" , Clicked ) ;
712713 yield listenTo ( button , "click" ) ;
713714 }
714- function * clicked ( ) { }
715+ function * Clicked ( ) { }
715716
716- return initial ;
717+ return Initial ;
717718 }
718719
719720 it ( "listens when button clicks" , ( ) => {
720721 const button = document . createElement ( 'button' ) ;
721722 const machine = start ( ButtonClickListener . bind ( null , button ) ) ;
722723
723- expect ( machine . current ) . toEqual ( "initial " ) ;
724+ expect ( machine . current ) . toEqual ( "Initial " ) ;
724725 expect ( machine . changeCount ) . toEqual ( 0 ) ;
725726
726727 button . click ( ) ;
727- expect ( machine . current ) . toEqual ( "clicked " ) ;
728+ expect ( machine . current ) . toEqual ( "Clicked " ) ;
728729 expect ( machine . changeCount ) . toEqual ( 1 ) ;
729730
730731 button . click ( ) ;
731- expect ( machine . current ) . toEqual ( "clicked " ) ;
732+ expect ( machine . current ) . toEqual ( "Clicked " ) ;
732733 expect ( machine . changeCount ) . toEqual ( 1 ) ;
733734 } ) ;
734735} ) ;
735736
737+ describe ( "FIXME: Key shortcut click highlighting too many event listeners bug" , ( ) => {
738+ function KeyShortcutListener ( el : HTMLElement ) {
739+ function * Open ( ) {
740+ yield on ( "keydown" , OpenCheckingKey ) ;
741+ yield listenTo ( el , "keydown" ) ;
742+ }
743+ function * OpenCheckingKey ( ) {
744+ const event : KeyboardEvent = yield readContext ( "event" ) ;
745+ yield cond ( event . key === 'Escape' , Closed ) ;
746+ // yield revert();
747+ yield always ( Open ) ;
748+ }
749+ function * Closed ( ) {
750+ yield on ( "keydown" , ClosedCheckingKey ) ;
751+ yield listenTo ( el , "keydown" ) ;
752+ }
753+ function * ClosedCheckingKey ( ) {
754+ const event : KeyboardEvent = yield readContext ( "event" ) ;
755+ yield cond ( event . key === 'Enter' , Open ) ;
756+ // yield revert();
757+ yield always ( Closed ) ;
758+ }
759+
760+ return Closed ;
761+ }
762+
763+ it ( "listens when keys are pressed" , ( ) => {
764+ // FIXME: there’s lots of event listeners being created!
765+ const input = document . createElement ( 'input' ) ;
766+ const machine = start ( KeyShortcutListener . bind ( null , input ) ) ;
767+
768+ expect ( machine . current ) . toEqual ( "Closed" ) ;
769+ expect ( machine . changeCount ) . toEqual ( 0 ) ;
770+
771+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Enter' } ) ) ;
772+ expect ( machine . current ) . toEqual ( "Open" ) ;
773+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
774+
775+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Enter' } ) ) ;
776+ expect ( machine . current ) . toEqual ( "Open" ) ;
777+ expect ( machine . changeCount ) . toEqual ( 6 ) ;
778+
779+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'a' } ) ) ;
780+ expect ( machine . current ) . toEqual ( "Open" ) ;
781+ expect ( machine . changeCount ) . toEqual ( 14 ) ;
782+
783+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Escape' } ) ) ;
784+ expect ( machine . current ) . toEqual ( "Closed" ) ;
785+ expect ( machine . changeCount ) . toEqual ( 30 ) ;
786+
787+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'a' } ) ) ;
788+ expect ( machine . current ) . toEqual ( "Closed" ) ;
789+ expect ( machine . changeCount ) . toEqual ( 62 ) ;
790+
791+ machine . abort ( ) ;
792+ } ) ;
793+ } ) ;
794+
795+ describe ( "Key shortcut cond reading event" , ( ) => {
796+ function KeyShortcutListener ( el : HTMLElement ) {
797+ function * Open ( ) {
798+ yield listenTo ( el , "keydown" ) ;
799+ yield on (
800+ "keydown" ,
801+ cond ( ( readContext ) => {
802+ const event = readContext ( "event" ) as KeyboardEvent ;
803+ return event . key === "Escape" ;
804+ } , Closed )
805+ ) ;
806+ }
807+ function * Closed ( ) {
808+ yield listenTo ( el , "keydown" ) ;
809+ yield on (
810+ "keydown" ,
811+ cond ( ( readContext ) => {
812+ const event = readContext ( "event" ) as KeyboardEvent ;
813+ return event . key === "Enter" ;
814+ } , Open )
815+ ) ;
816+ }
817+
818+ return Closed ;
819+ }
820+
821+ it ( "listens when keys are pressed" , ( ) => {
822+ const input = document . createElement ( 'input' ) ;
823+ const machine = start ( KeyShortcutListener . bind ( null , input ) ) ;
824+
825+ expect ( machine . current ) . toEqual ( "Closed" ) ;
826+ expect ( machine . changeCount ) . toEqual ( 0 ) ;
827+
828+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Enter' } ) ) ;
829+ expect ( machine . current ) . toEqual ( "Open" ) ;
830+ expect ( machine . changeCount ) . toEqual ( 1 ) ;
831+
832+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Enter' } ) ) ;
833+ expect ( machine . current ) . toEqual ( "Open" ) ;
834+ expect ( machine . changeCount ) . toEqual ( 1 ) ;
835+
836+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'a' } ) ) ;
837+ expect ( machine . current ) . toEqual ( "Open" ) ;
838+ expect ( machine . changeCount ) . toEqual ( 1 ) ;
839+
840+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Escape' } ) ) ;
841+ expect ( machine . current ) . toEqual ( "Closed" ) ;
842+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
843+
844+ input . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'a' } ) ) ;
845+ expect ( machine . current ) . toEqual ( "Closed" ) ;
846+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
847+
848+ machine . abort ( ) ;
849+ } ) ;
850+ } ) ;
851+
852+ describe ( "Element focus" , ( ) => {
853+ function * ButtonFocusListener ( el : HTMLElement ) {
854+ yield listenTo ( el . ownerDocument , "focusin" ) ;
855+ yield on ( "focusin" , compound ( CheckingActive ) ) ;
856+
857+ function * Inactive ( ) { }
858+ function * Active ( ) { }
859+ function * CheckingActive ( ) {
860+ yield cond ( el . ownerDocument . activeElement === el , Active ) ;
861+ yield always ( Inactive ) ;
862+ }
863+
864+ return CheckingActive ;
865+ }
866+
867+ it ( "listens when element receives and loses focus" , ( ) => {
868+ const button = document . body . appendChild ( document . createElement ( 'button' ) ) ;
869+ const input = document . body . appendChild ( document . createElement ( 'input' ) ) ;
870+
871+ const machine = start ( ButtonFocusListener . bind ( null , button ) ) ;
872+
873+ expect ( machine . current ) . toEqual ( "Inactive" ) ;
874+ expect ( machine . changeCount ) . toEqual ( 0 ) ;
875+
876+ button . focus ( ) ;
877+ expect ( machine . current ) . toEqual ( "Active" ) ;
878+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
879+
880+ button . focus ( ) ;
881+ expect ( machine . current ) . toEqual ( "Active" ) ;
882+ expect ( machine . changeCount ) . toEqual ( 2 ) ;
883+
884+ input . focus ( ) ;
885+ expect ( machine . current ) . toEqual ( "Inactive" ) ;
886+ expect ( machine . changeCount ) . toEqual ( 4 ) ;
887+
888+ button . focus ( ) ;
889+ expect ( machine . current ) . toEqual ( "Active" ) ;
890+ expect ( machine . changeCount ) . toEqual ( 6 ) ;
891+
892+ machine . abort ( ) ;
893+ button . remove ( ) ;
894+ input . remove ( ) ;
895+ } ) ;
896+
897+ it ( "is initially Active if element is already focused when starting" , ( ) => {
898+ const button = document . body . appendChild ( document . createElement ( 'button' ) ) ;
899+
900+ button . focus ( ) ;
901+ const machine = start ( ButtonFocusListener . bind ( null , button ) ) ;
902+
903+ expect ( machine . current ) . toEqual ( "Active" ) ;
904+ expect ( machine . changeCount ) . toEqual ( 0 ) ;
905+
906+ button . remove ( ) ;
907+ } )
908+ } ) ;
909+
736910describe ( "accumulate()" , ( ) => {
737911 const messagesKey = Symbol ( "messages" ) ;
738912
0 commit comments