@nick-skriabin/glyph 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -536,6 +536,211 @@ var Terminal = class {
536
536
  };
537
537
 
538
538
  // src/runtime/input.ts
539
+ function getKeyNameFromCode(code) {
540
+ switch (code) {
541
+ // Standard ASCII
542
+ case 9:
543
+ return "tab";
544
+ case 13:
545
+ return "return";
546
+ case 27:
547
+ return "escape";
548
+ case 32:
549
+ return " ";
550
+ case 127:
551
+ return "backspace";
552
+ // Kitty protocol special keys
553
+ case 57358:
554
+ return "capslock";
555
+ case 57359:
556
+ return "scrolllock";
557
+ case 57360:
558
+ return "numlock";
559
+ case 57361:
560
+ return "printscreen";
561
+ case 57362:
562
+ return "pause";
563
+ case 57363:
564
+ return "menu";
565
+ // Function keys (kitty uses these codes)
566
+ case 57364:
567
+ return "f13";
568
+ case 57365:
569
+ return "f14";
570
+ case 57366:
571
+ return "f15";
572
+ case 57367:
573
+ return "f16";
574
+ case 57368:
575
+ return "f17";
576
+ case 57369:
577
+ return "f18";
578
+ case 57370:
579
+ return "f19";
580
+ case 57371:
581
+ return "f20";
582
+ case 57372:
583
+ return "f21";
584
+ case 57373:
585
+ return "f22";
586
+ case 57374:
587
+ return "f23";
588
+ case 57375:
589
+ return "f24";
590
+ case 57376:
591
+ return "f25";
592
+ // Keypad keys
593
+ case 57399:
594
+ return "kp0";
595
+ case 57400:
596
+ return "kp1";
597
+ case 57401:
598
+ return "kp2";
599
+ case 57402:
600
+ return "kp3";
601
+ case 57403:
602
+ return "kp4";
603
+ case 57404:
604
+ return "kp5";
605
+ case 57405:
606
+ return "kp6";
607
+ case 57406:
608
+ return "kp7";
609
+ case 57407:
610
+ return "kp8";
611
+ case 57408:
612
+ return "kp9";
613
+ case 57409:
614
+ return "kpdecimal";
615
+ case 57410:
616
+ return "kpdivide";
617
+ case 57411:
618
+ return "kpmultiply";
619
+ case 57412:
620
+ return "kpminus";
621
+ case 57413:
622
+ return "kpplus";
623
+ case 57414:
624
+ return "kpenter";
625
+ case 57415:
626
+ return "kpequal";
627
+ // Navigation (kitty protocol)
628
+ case 57416:
629
+ return "kpleft";
630
+ case 57417:
631
+ return "kpright";
632
+ case 57418:
633
+ return "kpup";
634
+ case 57419:
635
+ return "kpdown";
636
+ case 57420:
637
+ return "kppageup";
638
+ case 57421:
639
+ return "kppagedown";
640
+ case 57422:
641
+ return "kphome";
642
+ case 57423:
643
+ return "kpend";
644
+ case 57424:
645
+ return "kpinsert";
646
+ case 57425:
647
+ return "kpdelete";
648
+ // Media keys
649
+ case 57428:
650
+ return "mediaplaypause";
651
+ case 57429:
652
+ return "mediastop";
653
+ case 57430:
654
+ return "mediaprev";
655
+ case 57431:
656
+ return "medianext";
657
+ case 57432:
658
+ return "mediarewind";
659
+ case 57433:
660
+ return "mediafastforward";
661
+ case 57434:
662
+ return "mediamute";
663
+ case 57435:
664
+ return "volumedown";
665
+ case 57436:
666
+ return "volumeup";
667
+ default:
668
+ if (code >= 32 && code <= 126) {
669
+ return String.fromCharCode(code).toLowerCase();
670
+ }
671
+ return "unknown";
672
+ }
673
+ }
674
+ function getTildeKeyName(param) {
675
+ const baseParam = param.split(";")[0];
676
+ switch (baseParam) {
677
+ case "1":
678
+ return "home";
679
+ case "2":
680
+ return "insert";
681
+ case "3":
682
+ return "delete";
683
+ case "4":
684
+ return "end";
685
+ case "5":
686
+ return "pageup";
687
+ case "6":
688
+ return "pagedown";
689
+ case "7":
690
+ return "home";
691
+ case "8":
692
+ return "end";
693
+ case "11":
694
+ return "f1";
695
+ case "12":
696
+ return "f2";
697
+ case "13":
698
+ return "f3";
699
+ case "14":
700
+ return "f4";
701
+ case "15":
702
+ return "f5";
703
+ case "17":
704
+ return "f6";
705
+ case "18":
706
+ return "f7";
707
+ case "19":
708
+ return "f8";
709
+ case "20":
710
+ return "f9";
711
+ case "21":
712
+ return "f10";
713
+ case "23":
714
+ return "f11";
715
+ case "24":
716
+ return "f12";
717
+ case "25":
718
+ return "f13";
719
+ case "26":
720
+ return "f14";
721
+ case "28":
722
+ return "f15";
723
+ case "29":
724
+ return "f16";
725
+ case "31":
726
+ return "f17";
727
+ case "32":
728
+ return "f18";
729
+ case "33":
730
+ return "f19";
731
+ case "34":
732
+ return "f20";
733
+ default:
734
+ return "unknown";
735
+ }
736
+ }
737
+ function applyModifiers(key, mod) {
738
+ const m = mod - 1;
739
+ if (m & 1) key.shift = true;
740
+ if (m & 2) key.alt = true;
741
+ if (m & 4) key.ctrl = true;
742
+ if (m & 8) key.meta = true;
743
+ }
539
744
  function parseKeySequence(data) {
540
745
  const keys = [];
541
746
  let i = 0;
@@ -551,9 +756,17 @@ function parseKeySequence(data) {
551
756
  continue;
552
757
  }
553
758
  }
759
+ if (data[i + 1] === "O") {
760
+ const seq = parseSs3Sequence(data, i);
761
+ if (seq) {
762
+ keys.push(seq.key);
763
+ i = seq.end;
764
+ continue;
765
+ }
766
+ }
554
767
  if (i + 1 < data.length && data.charCodeAt(i + 1) >= 32) {
555
768
  keys.push({
556
- name: data[i + 1],
769
+ name: data[i + 1].toLowerCase(),
557
770
  sequence: data.substring(i, i + 2),
558
771
  alt: true
559
772
  });
@@ -588,6 +801,102 @@ function parseKeySequence(data) {
588
801
  }
589
802
  return keys;
590
803
  }
804
+ function parseSs3Sequence(data, start) {
805
+ if (start + 2 >= data.length) return null;
806
+ const final = data[start + 2];
807
+ const sequence = data.substring(start, start + 3);
808
+ let key;
809
+ switch (final) {
810
+ // Arrow keys (some terminals)
811
+ case "A":
812
+ key = { name: "up", sequence };
813
+ break;
814
+ case "B":
815
+ key = { name: "down", sequence };
816
+ break;
817
+ case "C":
818
+ key = { name: "right", sequence };
819
+ break;
820
+ case "D":
821
+ key = { name: "left", sequence };
822
+ break;
823
+ // Home/End (some terminals)
824
+ case "H":
825
+ key = { name: "home", sequence };
826
+ break;
827
+ case "F":
828
+ key = { name: "end", sequence };
829
+ break;
830
+ // Function keys F1-F4
831
+ case "P":
832
+ key = { name: "f1", sequence };
833
+ break;
834
+ case "Q":
835
+ key = { name: "f2", sequence };
836
+ break;
837
+ case "R":
838
+ key = { name: "f3", sequence };
839
+ break;
840
+ case "S":
841
+ key = { name: "f4", sequence };
842
+ break;
843
+ // Keypad (application mode)
844
+ case "j":
845
+ key = { name: "kpmultiply", sequence };
846
+ break;
847
+ case "k":
848
+ key = { name: "kpplus", sequence };
849
+ break;
850
+ case "l":
851
+ key = { name: "kpcomma", sequence };
852
+ break;
853
+ case "m":
854
+ key = { name: "kpminus", sequence };
855
+ break;
856
+ case "n":
857
+ key = { name: "kpdecimal", sequence };
858
+ break;
859
+ case "o":
860
+ key = { name: "kpdivide", sequence };
861
+ break;
862
+ case "p":
863
+ key = { name: "kp0", sequence };
864
+ break;
865
+ case "q":
866
+ key = { name: "kp1", sequence };
867
+ break;
868
+ case "r":
869
+ key = { name: "kp2", sequence };
870
+ break;
871
+ case "s":
872
+ key = { name: "kp3", sequence };
873
+ break;
874
+ case "t":
875
+ key = { name: "kp4", sequence };
876
+ break;
877
+ case "u":
878
+ key = { name: "kp5", sequence };
879
+ break;
880
+ case "v":
881
+ key = { name: "kp6", sequence };
882
+ break;
883
+ case "w":
884
+ key = { name: "kp7", sequence };
885
+ break;
886
+ case "x":
887
+ key = { name: "kp8", sequence };
888
+ break;
889
+ case "y":
890
+ key = { name: "kp9", sequence };
891
+ break;
892
+ case "M":
893
+ key = { name: "kpenter", sequence };
894
+ break;
895
+ default:
896
+ return null;
897
+ }
898
+ return { key, end: start + 3 };
899
+ }
591
900
  function parseCsiSequence(data, start) {
592
901
  let i = start + 2;
593
902
  let params = "";
@@ -606,6 +915,7 @@ function parseCsiSequence(data, start) {
606
915
  i++;
607
916
  let key;
608
917
  switch (final) {
918
+ // Arrow keys
609
919
  case "A":
610
920
  key = { name: "up", sequence };
611
921
  break;
@@ -618,43 +928,73 @@ function parseCsiSequence(data, start) {
618
928
  case "D":
619
929
  key = { name: "left", sequence };
620
930
  break;
931
+ // Home/End
621
932
  case "H":
622
933
  key = { name: "home", sequence };
623
934
  break;
624
935
  case "F":
625
936
  key = { name: "end", sequence };
626
937
  break;
938
+ // Shift+Tab
627
939
  case "Z":
628
940
  key = { name: "tab", sequence, shift: true };
629
941
  break;
942
+ // Function keys (some terminals)
943
+ case "P":
944
+ key = { name: "f1", sequence };
945
+ break;
946
+ case "Q":
947
+ key = { name: "f2", sequence };
948
+ break;
949
+ case "R":
950
+ key = { name: "f3", sequence };
951
+ break;
952
+ case "S":
953
+ key = { name: "f4", sequence };
954
+ break;
955
+ // ~ terminated sequences (VT-style)
630
956
  case "~": {
631
- switch (params) {
632
- case "2":
633
- key = { name: "insert", sequence };
634
- break;
635
- case "3":
636
- key = { name: "delete", sequence };
637
- break;
638
- case "5":
639
- key = { name: "pageup", sequence };
640
- break;
641
- case "6":
642
- key = { name: "pagedown", sequence };
643
- break;
644
- default:
645
- key = { name: "unknown", sequence };
957
+ if (params.startsWith("27;")) {
958
+ const modParts = params.split(";");
959
+ const mod = parseInt(modParts[1] ?? "1", 10);
960
+ const keyCode = parseInt(modParts[2] ?? "0", 10);
961
+ key = { name: getKeyNameFromCode(keyCode), sequence };
962
+ applyModifiers(key, mod);
963
+ break;
964
+ }
965
+ key = { name: getTildeKeyName(params), sequence };
966
+ if (params.includes(";")) {
967
+ const parts = params.split(";");
968
+ const mod = parseInt(parts[1] ?? "1", 10);
969
+ applyModifiers(key, mod);
646
970
  }
647
971
  break;
648
972
  }
973
+ // Kitty keyboard protocol: CSI code;mod u
974
+ case "u": {
975
+ const parts = params.split(";");
976
+ const keyCode = parseInt(parts[0] ?? "0", 10);
977
+ const mod = parseInt(parts[1] ?? "1", 10);
978
+ key = { name: getKeyNameFromCode(keyCode), sequence };
979
+ applyModifiers(key, mod);
980
+ break;
981
+ }
982
+ // Focus events (if terminal reports them)
983
+ case "I":
984
+ key = { name: "focus", sequence };
985
+ break;
986
+ case "O":
987
+ key = { name: "blur", sequence };
988
+ break;
649
989
  default:
650
990
  key = { name: "unknown", sequence };
651
991
  }
652
- if (params.includes(";")) {
992
+ if (params.includes(";") && !["~", "u"].includes(final)) {
653
993
  const parts = params.split(";");
654
- const mod = parseInt(parts[1] ?? "1", 10) - 1;
655
- if (mod & 1) key.shift = true;
656
- if (mod & 2) key.alt = true;
657
- if (mod & 4) key.ctrl = true;
994
+ const mod = parseInt(parts[parts.length - 1] ?? "1", 10);
995
+ if (mod >= 1 && mod <= 16) {
996
+ applyModifiers(key, mod);
997
+ }
658
998
  }
659
999
  return { key, end: i };
660
1000
  }
@@ -1591,12 +1931,17 @@ function render(element, opts = {}) {
1591
1931
  const currentFb = new Framebuffer(terminal.columns, terminal.rows);
1592
1932
  let fullRedraw = true;
1593
1933
  const inputHandlers = /* @__PURE__ */ new Set();
1934
+ const priorityHandlers = /* @__PURE__ */ new Set();
1594
1935
  const focusedInputHandlers = /* @__PURE__ */ new Map();
1595
1936
  const inputContextValue = {
1596
1937
  subscribe(handler) {
1597
1938
  inputHandlers.add(handler);
1598
1939
  return () => inputHandlers.delete(handler);
1599
1940
  },
1941
+ subscribePriority(handler) {
1942
+ priorityHandlers.add(handler);
1943
+ return () => priorityHandlers.delete(handler);
1944
+ },
1600
1945
  registerInputHandler(focusId, handler) {
1601
1946
  focusedInputHandlers.set(focusId, handler);
1602
1947
  return () => focusedInputHandlers.delete(focusId);
@@ -1842,7 +2187,13 @@ function render(element, opts = {}) {
1842
2187
  continue;
1843
2188
  }
1844
2189
  let consumed = false;
1845
- if (focusedId) {
2190
+ for (const handler of priorityHandlers) {
2191
+ if (handler(key)) {
2192
+ consumed = true;
2193
+ break;
2194
+ }
2195
+ }
2196
+ if (!consumed && focusedId) {
1846
2197
  const inputHandler = focusedInputHandlers.get(focusedId);
1847
2198
  if (inputHandler) {
1848
2199
  consumed = inputHandler(key);
@@ -2346,7 +2697,8 @@ function parseKeyDescriptor(descriptor) {
2346
2697
  name,
2347
2698
  ctrl: parts.includes("ctrl"),
2348
2699
  alt: parts.includes("alt"),
2349
- shift: parts.includes("shift")
2700
+ shift: parts.includes("shift"),
2701
+ meta: parts.includes("meta") || parts.includes("cmd") || parts.includes("super") || parts.includes("win")
2350
2702
  };
2351
2703
  }
2352
2704
  function matchesKey(matcher, key) {
@@ -2354,12 +2706,14 @@ function matchesKey(matcher, key) {
2354
2706
  if (matcher.ctrl !== !!key.ctrl) return false;
2355
2707
  if (matcher.alt !== !!key.alt) return false;
2356
2708
  if (matcher.shift !== !!key.shift) return false;
2709
+ if (matcher.meta !== !!key.meta) return false;
2357
2710
  return true;
2358
2711
  }
2359
2712
  function Keybind({
2360
2713
  keypress,
2361
2714
  onPress,
2362
2715
  whenFocused,
2716
+ priority,
2363
2717
  disabled
2364
2718
  }) {
2365
2719
  const inputCtx = React15.useContext(InputContext);
@@ -2370,13 +2724,23 @@ function Keybind({
2370
2724
  matcherRef.current = parseKeyDescriptor(keypress);
2371
2725
  React15.useEffect(() => {
2372
2726
  if (!inputCtx || disabled) return;
2373
- const handler = (key) => {
2374
- if (!matchesKey(matcherRef.current, key)) return;
2375
- if (whenFocused && focusCtx?.focusedId !== whenFocused) return;
2376
- onPressRef.current();
2377
- };
2378
- return inputCtx.subscribe(handler);
2379
- }, [inputCtx, focusCtx, whenFocused, disabled]);
2727
+ if (priority) {
2728
+ const handler = (key) => {
2729
+ if (!matchesKey(matcherRef.current, key)) return false;
2730
+ if (whenFocused && focusCtx?.focusedId !== whenFocused) return false;
2731
+ onPressRef.current();
2732
+ return true;
2733
+ };
2734
+ return inputCtx.subscribePriority(handler);
2735
+ } else {
2736
+ const handler = (key) => {
2737
+ if (!matchesKey(matcherRef.current, key)) return;
2738
+ if (whenFocused && focusCtx?.focusedId !== whenFocused) return;
2739
+ onPressRef.current();
2740
+ };
2741
+ return inputCtx.subscribe(handler);
2742
+ }
2743
+ }, [inputCtx, focusCtx, whenFocused, priority, disabled]);
2380
2744
  return null;
2381
2745
  }
2382
2746
  function Portal({ children, zIndex = 1e3 }) {