APP.input.keypress = function (event) {
  event.preventDefault();
}
APP.input.keydown = function (event) {
  //TODO: this keydown handler could be abstracted to some sort of action runner in the actions.js, so I could use an action say like APP.actions('selectUp', key, context, sel); so I could then add for example a 'selectTo' action and a selectTo entry to the keymap, which would then become actionmap and have pointer events too.
  var sel = APP.selection;
  var keydef = keysight(event); //TODO: use as module
  var key = keydef.key;
  var char = keydef.char;
  var context = APP.input.getContext(event);
  var mod = APP.input.getKeyModifiers(event);
  var keymap = APP.input.getKeymap(key, context, mod);

  for (action in keymap) {
    if (
        keymap.hasOwnProperty(action) &&
        keymap[action].keypress &&
        keymap[action].context
    ) {
      //TODO: check if action returns a new selection and modify selection only if it does
      console.log('action', action+':', keymap[action]);
      var newSel = APP.actions[action](key, context, sel);
      if (keymap[action].preventDefault) {
        event.preventDefault();
      }
    }
  }
  APP.selection = newSel || sel;
}

APP.input.textInput = function (event) {
  //TODO: use getContext here too so the important bits can be scoped to editing a props text
  var sel = APP.selection;
  var selElmType = APP.doc.prop.getType(sel.elm);
  //var whitelist = /[a-z0-9!"#$%&'()*+,.\/:;<=>?@\[\] ^_`{|}~-]/; //TODO: whitelisted or blacklisted characters should be based on language definition
  //Like blacklisting startsWith & endsWith characters inside a prop, then highlighting them
  var textContent = sel.elm.textContent;
  var textSel = window.getSelection();
  var textRange = textSel.getRangeAt(0);
  var allSelected = sel.elm.textContent.length === textRange.startOffset + textRange.endOffset

  sel = APP.doc.prop.validate(sel);

  //if prop is of default type, try figuring out what type the user wants by looking at the first typed character(s?)
  if (textContent.length < 3 && selElmType === 0) {
    for (var i = 0; i < APP.language.types.length; i++) {
      if (APP.language.types[i].startsWith.indexOf(textContent) !== -1) {
        sel = APP.doc.prop.init(sel);
        sel = APP.doc.prop.setType(sel, i);
        APP.selection = sel;
        return;
      }
    }
  }
  //if the prop has some content, check the last char of the prop to determine if the user wants to start a new prop of some type
  else if (textContent.length > 1) {
    var lastChar = textContent.substring(textContent.length - 1);
    var nextType = APP.language.types[selElmType].endsWith.indexOf(lastChar);

    if (nextType !== -1) {
      nextType = APP.language.types[selElmType].next[nextType];
      for (var i = 0; i < APP.language.types.length; i++) {
        if (APP.language.types[i].name === nextType) {
          sel.elm.innerHTML = textContent.substr(0, textContent.length - 1);
          sel = APP.doc.prop.new(sel, i);
          APP.selection = sel;
          return;
        }
      }
    }
  }
}

@@ -1331,19 +1331,19 @@
  text%0A  
-var
+let
  sel = A
@@ -1358,19 +1358,53 @@
 tion;%0A  
-var
+let types = APP.language.types;%0A  let
  selElmT
@@ -1446,256 +1446,11 @@
 ;%0A  
-//var whitelist = /%5Ba-z0-9!%22#$%25&'()*+,.%5C/:;%3C=%3E?@%5C%5B%5C%5D %5E_%60%7B%7C%7D~-%5D/; //TODO: whitelisted or blacklisted characters should be based on language definition%0A  //Like blacklisting startsWith & endsWith characters inside a prop, then highlighting them%0A  var
+let
  tex
@@ -1479,27 +1479,27 @@
 tContent;%0A  
-var
+let
  textSel = w
@@ -1522,19 +1522,19 @@
 on();%0A  
-var
+let
  textRan
@@ -1563,19 +1563,19 @@
 t(0);%0A  
-var
+let
  allSele
@@ -1659,16 +1659,18 @@
 fset%0A%0A  
+//
 sel = AP
@@ -1704,36 +1704,8 @@
   //
-if prop is of default type, 
 try 
@@ -1785,12 +1785,8 @@
 cter
-(s?)
 %0A  i
@@ -1811,292 +1811,334 @@
 gth 
-%3C 3 && selElmType === 0) %7B%0A    for (var i = 0; i %3C APP.language.types.length; i++) %7B%0A      if (APP.language.types%5Bi%5D.startsWith.indexOf(textContent) !== -1) %7B%0A        sel = APP.doc.prop.init(sel);%0A        sel = APP.doc.prop.setType(sel, i);%0A        APP.selection = sel;%0A        return
+=== 1) %7B%0A    let char = textContent;%0A    for (let key in types) %7B%0A      let type = types%5Bkey%5D;%0A      let prevTypeName = APP.doc.prop.getType(sel.elm.previousSibling);%0A      if (type.startsWith.indexOf(char) !== -1 && (type.prev.indexOf(prevTypeName) !== -1 %7C%7C type.prev === 'any')) %7B%0A        sel = APP.doc.prop.init(sel, type)
 ;%0A  
@@ -2328,17 +2328,13 @@
     
-var lastC
+let c
 har 
@@ -2386,19 +2386,19 @@
 1);%0A    
-var
+let
  nextTyp
@@ -2398,32 +2398,23 @@
 nextType
- = APP.language.
+Name = 
 types%5Bse
@@ -2444,36 +2444,27 @@
 xOf(
-lastC
+c
 har);%0A
-%0A
     
-if (
 nextType
  !==
@@ -2463,202 +2463,86 @@
 Type
- !== -1) %7B%0A      nextType = APP.language.types%5BselElmType%5D.next%5BnextType%5D;%0A      for (var i = 0; i %3C APP.language.types.length; i++) %7B%0A 
+Name = types%5BselElmType%5D.next%5BnextTypeName%5D;%0A
     
-   
 if (
-APP.language.types%5Bi%5D.name === nextT
+nextTypeName in t
 ype
+s
 ) %7B%0A
-    
     
@@ -2612,28 +2612,24 @@
 - 1);%0A      
-    
 sel = APP.do
@@ -2648,16 +2648,23 @@
 el, 
-i);%0A    
+nextTypeName);%0A
     
@@ -2694,48 +2694,36 @@
     
-      return;%0A        %7D%0A      %7D%0A    %7D%0A  %7D
+%7D%0A  %7D%0A%0A  APP.selection = sel;
 %0A%7D%0A

fix the logic for determining prop type based on text input of first or last char