@teammates/consolonia 0.7.1 → 0.7.3
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/__tests__/ansi.test.js +116 -26
- package/dist/__tests__/pixel.test.js +38 -0
- package/dist/__tests__/styled.test.js +1 -1
- package/dist/app.js +2 -3
- package/dist/index.d.ts +1 -1
- package/dist/pixel/symbol.js +102 -36
- package/package.json +1 -1
|
@@ -534,7 +534,10 @@ describe("detectTerminal", () => {
|
|
|
534
534
|
}
|
|
535
535
|
Object.assign(process.env, origEnv);
|
|
536
536
|
Object.defineProperty(process, "platform", { value: origPlatform });
|
|
537
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
537
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
538
|
+
value: origIsTTY,
|
|
539
|
+
writable: true,
|
|
540
|
+
});
|
|
538
541
|
});
|
|
539
542
|
function setEnv(overrides) {
|
|
540
543
|
for (const [k, v] of Object.entries(overrides)) {
|
|
@@ -545,7 +548,10 @@ describe("detectTerminal", () => {
|
|
|
545
548
|
}
|
|
546
549
|
}
|
|
547
550
|
it("returns pipe caps when stdout is not a TTY", () => {
|
|
548
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
551
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
552
|
+
value: false,
|
|
553
|
+
writable: true,
|
|
554
|
+
});
|
|
549
555
|
const caps = detectTerminal();
|
|
550
556
|
expect(caps.isTTY).toBe(false);
|
|
551
557
|
expect(caps.mouse).toBe(false);
|
|
@@ -554,7 +560,10 @@ describe("detectTerminal", () => {
|
|
|
554
560
|
});
|
|
555
561
|
it("detects Windows Terminal via WT_SESSION", () => {
|
|
556
562
|
Object.defineProperty(process, "platform", { value: "win32" });
|
|
557
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
563
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
564
|
+
value: true,
|
|
565
|
+
writable: true,
|
|
566
|
+
});
|
|
558
567
|
setEnv({ WT_SESSION: "some-guid" });
|
|
559
568
|
const caps = detectTerminal();
|
|
560
569
|
expect(caps.name).toBe("windows-terminal");
|
|
@@ -563,7 +572,10 @@ describe("detectTerminal", () => {
|
|
|
563
572
|
});
|
|
564
573
|
it("detects VS Code terminal on Windows", () => {
|
|
565
574
|
Object.defineProperty(process, "platform", { value: "win32" });
|
|
566
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
575
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
576
|
+
value: true,
|
|
577
|
+
writable: true,
|
|
578
|
+
});
|
|
567
579
|
setEnv({ WT_SESSION: undefined, TERM_PROGRAM: "vscode" });
|
|
568
580
|
const caps = detectTerminal();
|
|
569
581
|
expect(caps.name).toBe("vscode");
|
|
@@ -571,21 +583,40 @@ describe("detectTerminal", () => {
|
|
|
571
583
|
});
|
|
572
584
|
it("detects ConEmu on Windows", () => {
|
|
573
585
|
Object.defineProperty(process, "platform", { value: "win32" });
|
|
574
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
575
|
-
|
|
586
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
587
|
+
value: true,
|
|
588
|
+
writable: true,
|
|
589
|
+
});
|
|
590
|
+
setEnv({
|
|
591
|
+
WT_SESSION: undefined,
|
|
592
|
+
TERM_PROGRAM: undefined,
|
|
593
|
+
ConEmuPID: "1234",
|
|
594
|
+
});
|
|
576
595
|
const caps = detectTerminal();
|
|
577
596
|
expect(caps.name).toBe("conemu");
|
|
578
597
|
});
|
|
579
598
|
it("detects mintty via TERM + MSYSTEM", () => {
|
|
580
599
|
Object.defineProperty(process, "platform", { value: "win32" });
|
|
581
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
582
|
-
|
|
600
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
601
|
+
value: true,
|
|
602
|
+
writable: true,
|
|
603
|
+
});
|
|
604
|
+
setEnv({
|
|
605
|
+
WT_SESSION: undefined,
|
|
606
|
+
TERM_PROGRAM: undefined,
|
|
607
|
+
ConEmuPID: undefined,
|
|
608
|
+
TERM: "xterm-256color",
|
|
609
|
+
MSYSTEM: "MINGW64",
|
|
610
|
+
});
|
|
583
611
|
const caps = detectTerminal();
|
|
584
612
|
expect(caps.name).toBe("mintty");
|
|
585
613
|
});
|
|
586
614
|
it("detects tmux on Unix", () => {
|
|
587
615
|
Object.defineProperty(process, "platform", { value: "linux" });
|
|
588
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
616
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
617
|
+
value: true,
|
|
618
|
+
writable: true,
|
|
619
|
+
});
|
|
589
620
|
setEnv({ TMUX: "/tmp/tmux-1000/default,1234,0", TERM: "screen-256color" });
|
|
590
621
|
const caps = detectTerminal();
|
|
591
622
|
expect(caps.name).toBe("tmux");
|
|
@@ -593,8 +624,16 @@ describe("detectTerminal", () => {
|
|
|
593
624
|
});
|
|
594
625
|
it("detects GNU screen with limited caps", () => {
|
|
595
626
|
Object.defineProperty(process, "platform", { value: "linux" });
|
|
596
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
597
|
-
|
|
627
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
628
|
+
value: true,
|
|
629
|
+
writable: true,
|
|
630
|
+
});
|
|
631
|
+
setEnv({
|
|
632
|
+
TMUX: undefined,
|
|
633
|
+
TERM: "screen",
|
|
634
|
+
TERM_PROGRAM: undefined,
|
|
635
|
+
ITERM_SESSION_ID: undefined,
|
|
636
|
+
});
|
|
598
637
|
const caps = detectTerminal();
|
|
599
638
|
expect(caps.name).toBe("screen");
|
|
600
639
|
expect(caps.sgrMouse).toBe(false);
|
|
@@ -602,24 +641,48 @@ describe("detectTerminal", () => {
|
|
|
602
641
|
});
|
|
603
642
|
it("detects iTerm2", () => {
|
|
604
643
|
Object.defineProperty(process, "platform", { value: "darwin" });
|
|
605
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
606
|
-
|
|
644
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
645
|
+
value: true,
|
|
646
|
+
writable: true,
|
|
647
|
+
});
|
|
648
|
+
setEnv({
|
|
649
|
+
TMUX: undefined,
|
|
650
|
+
TERM: "xterm-256color",
|
|
651
|
+
TERM_PROGRAM: "iTerm.app",
|
|
652
|
+
});
|
|
607
653
|
const caps = detectTerminal();
|
|
608
654
|
expect(caps.name).toBe("iterm2");
|
|
609
655
|
expect(caps.truecolor).toBe(true);
|
|
610
656
|
});
|
|
611
657
|
it("detects xterm-compatible with COLORTERM truecolor", () => {
|
|
612
658
|
Object.defineProperty(process, "platform", { value: "linux" });
|
|
613
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
614
|
-
|
|
659
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
660
|
+
value: true,
|
|
661
|
+
writable: true,
|
|
662
|
+
});
|
|
663
|
+
setEnv({
|
|
664
|
+
TMUX: undefined,
|
|
665
|
+
TERM: "xterm-256color",
|
|
666
|
+
TERM_PROGRAM: undefined,
|
|
667
|
+
ITERM_SESSION_ID: undefined,
|
|
668
|
+
COLORTERM: "truecolor",
|
|
669
|
+
});
|
|
615
670
|
const caps = detectTerminal();
|
|
616
671
|
expect(caps.truecolor).toBe(true);
|
|
617
672
|
expect(caps.color256).toBe(true);
|
|
618
673
|
});
|
|
619
674
|
it("detects dumb terminal with minimal caps", () => {
|
|
620
675
|
Object.defineProperty(process, "platform", { value: "linux" });
|
|
621
|
-
Object.defineProperty(process.stdout, "isTTY", {
|
|
622
|
-
|
|
676
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
677
|
+
value: true,
|
|
678
|
+
writable: true,
|
|
679
|
+
});
|
|
680
|
+
setEnv({
|
|
681
|
+
TMUX: undefined,
|
|
682
|
+
TERM: "dumb",
|
|
683
|
+
TERM_PROGRAM: undefined,
|
|
684
|
+
ITERM_SESSION_ID: undefined,
|
|
685
|
+
});
|
|
623
686
|
const caps = detectTerminal();
|
|
624
687
|
expect(caps.name).toBe("dumb");
|
|
625
688
|
expect(caps.mouse).toBe(false);
|
|
@@ -667,7 +730,10 @@ describe("esc environment-aware sequences", () => {
|
|
|
667
730
|
describe("initSequence", () => {
|
|
668
731
|
it("includes all features for a full-caps terminal", () => {
|
|
669
732
|
const caps = makeCaps();
|
|
670
|
-
const seq = esc.initSequence(caps, {
|
|
733
|
+
const seq = esc.initSequence(caps, {
|
|
734
|
+
alternateScreen: true,
|
|
735
|
+
mouse: true,
|
|
736
|
+
});
|
|
671
737
|
expect(seq).toContain(esc.alternateScreenOn);
|
|
672
738
|
expect(seq).toContain(esc.hideCursor);
|
|
673
739
|
expect(seq).toContain(esc.bracketedPasteOn);
|
|
@@ -676,34 +742,52 @@ describe("esc environment-aware sequences", () => {
|
|
|
676
742
|
});
|
|
677
743
|
it("skips alternate screen when not supported", () => {
|
|
678
744
|
const caps = makeCaps({ alternateScreen: false });
|
|
679
|
-
const seq = esc.initSequence(caps, {
|
|
745
|
+
const seq = esc.initSequence(caps, {
|
|
746
|
+
alternateScreen: true,
|
|
747
|
+
mouse: false,
|
|
748
|
+
});
|
|
680
749
|
expect(seq).not.toContain(esc.alternateScreenOn);
|
|
681
750
|
});
|
|
682
751
|
it("skips alternate screen when app opts out", () => {
|
|
683
752
|
const caps = makeCaps();
|
|
684
|
-
const seq = esc.initSequence(caps, {
|
|
753
|
+
const seq = esc.initSequence(caps, {
|
|
754
|
+
alternateScreen: false,
|
|
755
|
+
mouse: false,
|
|
756
|
+
});
|
|
685
757
|
expect(seq).not.toContain(esc.alternateScreenOn);
|
|
686
758
|
});
|
|
687
759
|
it("skips bracketed paste when not supported", () => {
|
|
688
760
|
const caps = makeCaps({ bracketedPaste: false });
|
|
689
|
-
const seq = esc.initSequence(caps, {
|
|
761
|
+
const seq = esc.initSequence(caps, {
|
|
762
|
+
alternateScreen: false,
|
|
763
|
+
mouse: false,
|
|
764
|
+
});
|
|
690
765
|
expect(seq).not.toContain(esc.bracketedPasteOn);
|
|
691
766
|
});
|
|
692
767
|
it("skips mouse when app opts out even if caps support it", () => {
|
|
693
768
|
const caps = makeCaps();
|
|
694
|
-
const seq = esc.initSequence(caps, {
|
|
769
|
+
const seq = esc.initSequence(caps, {
|
|
770
|
+
alternateScreen: false,
|
|
771
|
+
mouse: false,
|
|
772
|
+
});
|
|
695
773
|
expect(seq).not.toContain("?1000h");
|
|
696
774
|
});
|
|
697
775
|
it("returns empty string for non-TTY", () => {
|
|
698
776
|
const caps = makeCaps({ isTTY: false });
|
|
699
|
-
const seq = esc.initSequence(caps, {
|
|
777
|
+
const seq = esc.initSequence(caps, {
|
|
778
|
+
alternateScreen: true,
|
|
779
|
+
mouse: true,
|
|
780
|
+
});
|
|
700
781
|
expect(seq).toBe("");
|
|
701
782
|
});
|
|
702
783
|
});
|
|
703
784
|
describe("restoreSequence", () => {
|
|
704
785
|
it("includes all restore features for a full-caps terminal", () => {
|
|
705
786
|
const caps = makeCaps();
|
|
706
|
-
const seq = esc.restoreSequence(caps, {
|
|
787
|
+
const seq = esc.restoreSequence(caps, {
|
|
788
|
+
alternateScreen: true,
|
|
789
|
+
mouse: true,
|
|
790
|
+
});
|
|
707
791
|
expect(seq).toContain(esc.reset);
|
|
708
792
|
expect(seq).toContain(esc.mouseTrackingOff);
|
|
709
793
|
expect(seq).toContain(esc.bracketedPasteOff);
|
|
@@ -712,14 +796,20 @@ describe("esc environment-aware sequences", () => {
|
|
|
712
796
|
});
|
|
713
797
|
it("mirrors initSequence — skips what init skipped", () => {
|
|
714
798
|
const caps = makeCaps({ bracketedPaste: false, alternateScreen: false });
|
|
715
|
-
const seq = esc.restoreSequence(caps, {
|
|
799
|
+
const seq = esc.restoreSequence(caps, {
|
|
800
|
+
alternateScreen: true,
|
|
801
|
+
mouse: false,
|
|
802
|
+
});
|
|
716
803
|
expect(seq).not.toContain(esc.bracketedPasteOff);
|
|
717
804
|
expect(seq).not.toContain(esc.alternateScreenOff);
|
|
718
805
|
expect(seq).not.toContain(esc.mouseTrackingOff);
|
|
719
806
|
});
|
|
720
807
|
it("returns empty string for non-TTY", () => {
|
|
721
808
|
const caps = makeCaps({ isTTY: false });
|
|
722
|
-
const seq = esc.restoreSequence(caps, {
|
|
809
|
+
const seq = esc.restoreSequence(caps, {
|
|
810
|
+
alternateScreen: true,
|
|
811
|
+
mouse: true,
|
|
812
|
+
});
|
|
723
813
|
expect(seq).toBe("");
|
|
724
814
|
});
|
|
725
815
|
});
|
|
@@ -296,6 +296,44 @@ describe("symbol", () => {
|
|
|
296
296
|
// U+1F600 = grinning face (in emoji range 0x1f000-0x1faff)
|
|
297
297
|
expect(charWidth(0x1f600)).toBe(2);
|
|
298
298
|
});
|
|
299
|
+
it("text-presentation symbols that remain width 1", () => {
|
|
300
|
+
// These render as 1 cell even on Windows Terminal
|
|
301
|
+
expect(charWidth(0x2713)).toBe(1); // ✓ Check Mark
|
|
302
|
+
expect(charWidth(0x2702)).toBe(1); // ✂ Scissors
|
|
303
|
+
expect(charWidth(0x00a9)).toBe(1); // © Copyright
|
|
304
|
+
expect(charWidth(0x00ae)).toBe(1); // ® Registered
|
|
305
|
+
});
|
|
306
|
+
it("emoji-presentation symbols are width 2", () => {
|
|
307
|
+
// These have Emoji_Presentation=Yes and render as 2 cells
|
|
308
|
+
expect(charWidth(0x2614)).toBe(2); // ☔ Umbrella with Rain Drops
|
|
309
|
+
expect(charWidth(0x2615)).toBe(2); // ☕ Hot Beverage
|
|
310
|
+
expect(charWidth(0x2705)).toBe(2); // ✅ White Heavy Check Mark
|
|
311
|
+
expect(charWidth(0x274c)).toBe(2); // ❌ Cross Mark
|
|
312
|
+
expect(charWidth(0x2757)).toBe(2); // ❗ Heavy Exclamation Mark
|
|
313
|
+
expect(charWidth(0x26bd)).toBe(2); // ⚽ Soccer Ball
|
|
314
|
+
expect(charWidth(0x26fd)).toBe(2); // ⛽ Fuel Pump
|
|
315
|
+
expect(charWidth(0x2b50)).toBe(2); // ⭐ White Medium Star
|
|
316
|
+
});
|
|
317
|
+
it("Windows Terminal wide symbols are width 2", () => {
|
|
318
|
+
// Text-presentation chars that Windows Terminal renders as double-width
|
|
319
|
+
expect(charWidth(0x2139)).toBe(2); // ℹ Information Source
|
|
320
|
+
expect(charWidth(0x2605)).toBe(2); // ★ Black Star
|
|
321
|
+
expect(charWidth(0x2606)).toBe(2); // ☆ White Star
|
|
322
|
+
expect(charWidth(0x2660)).toBe(2); // ♠ Black Spade Suit
|
|
323
|
+
expect(charWidth(0x2663)).toBe(2); // ♣ Black Club Suit
|
|
324
|
+
expect(charWidth(0x2665)).toBe(2); // ♥ Black Heart Suit
|
|
325
|
+
expect(charWidth(0x2666)).toBe(2); // ♦ Black Diamond Suit
|
|
326
|
+
expect(charWidth(0x2690)).toBe(2); // ⚐ White Flag
|
|
327
|
+
expect(charWidth(0x2691)).toBe(2); // ⚑ Black Flag
|
|
328
|
+
expect(charWidth(0x2699)).toBe(2); // ⚙ Gear
|
|
329
|
+
expect(charWidth(0x26a0)).toBe(2); // ⚠ Warning Sign
|
|
330
|
+
expect(charWidth(0x2714)).toBe(2); // ✔ Heavy Check Mark
|
|
331
|
+
expect(charWidth(0x2716)).toBe(2); // ✖ Heavy Multiplication X
|
|
332
|
+
expect(charWidth(0x279c)).toBe(2); // ➜ Heavy Round-Tipped Arrow
|
|
333
|
+
expect(charWidth(0x27a4)).toBe(2); // ➤ Black Right Arrowhead
|
|
334
|
+
expect(charWidth(0x25b6)).toBe(2); // ▶ Black Right Triangle
|
|
335
|
+
expect(charWidth(0x23f1)).toBe(2); // ⏱ Stopwatch
|
|
336
|
+
});
|
|
299
337
|
});
|
|
300
338
|
describe("sym() factory", () => {
|
|
301
339
|
it("creates a symbol with auto-detected width 1 for ASCII", () => {
|
|
@@ -80,7 +80,7 @@ describe("concat", () => {
|
|
|
80
80
|
const s = concat(pen.green("✔ "), pen.white("done"));
|
|
81
81
|
expect(s).toHaveLength(2);
|
|
82
82
|
expect(spanText(s)).toBe("✔ done");
|
|
83
|
-
expect(spanLength(s)).toBe(7); // ✔ is width 2 (
|
|
83
|
+
expect(spanLength(s)).toBe(7); // ✔ is width 2 (renders wide on Windows Terminal)
|
|
84
84
|
});
|
|
85
85
|
it("accepts plain strings", () => {
|
|
86
86
|
const s = concat("hello ", pen.cyan("world"));
|
package/dist/app.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import * as esc from "./ansi/esc.js";
|
|
9
9
|
import { AnsiOutput } from "./ansi/output.js";
|
|
10
|
-
import { detectTerminal
|
|
10
|
+
import { detectTerminal } from "./ansi/terminal-env.js";
|
|
11
11
|
import { DrawingContext } from "./drawing/context.js";
|
|
12
12
|
import { createInputProcessor } from "./input/processor.js";
|
|
13
13
|
import { disableRawMode, enableRawMode } from "./input/raw-mode.js";
|
|
@@ -99,8 +99,7 @@ export class App {
|
|
|
99
99
|
enableRawMode();
|
|
100
100
|
// 2. Create ANSI output
|
|
101
101
|
this._output = new AnsiOutput(stdout);
|
|
102
|
-
// 3. Prepare terminal (
|
|
103
|
-
// so we can conditionally enable mouse tracking)
|
|
102
|
+
// 3. Prepare terminal (ANSI sequences for alternate screen, mouse, etc.)
|
|
104
103
|
this._prepareTerminal();
|
|
105
104
|
// 4. Set terminal title
|
|
106
105
|
if (this._title) {
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export type { Constraint, Point, Rect, Size, } from "./layout/types.js";
|
|
|
16
16
|
export * as esc from "./ansi/esc.js";
|
|
17
17
|
export { AnsiOutput } from "./ansi/output.js";
|
|
18
18
|
export { stripAnsi, truncateAnsi, visibleLength, } from "./ansi/strip.js";
|
|
19
|
-
export { type TerminalCaps,
|
|
19
|
+
export { detectTerminal, type TerminalCaps, } from "./ansi/terminal-env.js";
|
|
20
20
|
export { DirtyRegions, DirtySnapshot } from "./render/regions.js";
|
|
21
21
|
export { RenderTarget } from "./render/render-target.js";
|
|
22
22
|
export { EscapeMatcher } from "./input/escape-matcher.js";
|
package/dist/pixel/symbol.js
CHANGED
|
@@ -114,49 +114,115 @@ export function charWidth(codePoint) {
|
|
|
114
114
|
// CJK Compatibility Ideographs Supplement
|
|
115
115
|
if (codePoint >= 0x2f800 && codePoint <= 0x2fa1f)
|
|
116
116
|
return 2;
|
|
117
|
-
// ── Emoji
|
|
118
|
-
//
|
|
117
|
+
// ── Emoji with Emoji_Presentation=Yes (rendered as 2 cells by default) ──
|
|
118
|
+
// Only characters that terminals render as wide WITHOUT a variation selector.
|
|
119
|
+
// ── Text-presentation characters that Windows Terminal renders as wide ──
|
|
120
|
+
// These have Emoji_Presentation=No in Unicode but modern terminals (Windows
|
|
121
|
+
// Terminal, VS Code integrated terminal) render them as double-width emoji.
|
|
122
|
+
if (codePoint === 0x2139)
|
|
123
|
+
return 2; // ℹ Information Source
|
|
124
|
+
if (codePoint === 0x2605 || codePoint === 0x2606)
|
|
125
|
+
return 2; // ★☆ Stars
|
|
126
|
+
if (codePoint === 0x2660)
|
|
127
|
+
return 2; // ♠ Black Spade Suit
|
|
128
|
+
if (codePoint === 0x2663)
|
|
129
|
+
return 2; // ♣ Black Club Suit
|
|
130
|
+
if (codePoint === 0x2665)
|
|
131
|
+
return 2; // ♥ Black Heart Suit
|
|
132
|
+
if (codePoint === 0x2666)
|
|
133
|
+
return 2; // ♦ Black Diamond Suit
|
|
134
|
+
if (codePoint === 0x2690 || codePoint === 0x2691)
|
|
135
|
+
return 2; // ⚐⚑ Flags
|
|
136
|
+
if (codePoint === 0x2699)
|
|
137
|
+
return 2; // ⚙ Gear
|
|
138
|
+
if (codePoint === 0x26a0)
|
|
139
|
+
return 2; // ⚠ Warning Sign
|
|
140
|
+
if (codePoint === 0x2714)
|
|
141
|
+
return 2; // ✔ Heavy Check Mark
|
|
142
|
+
if (codePoint === 0x2716)
|
|
143
|
+
return 2; // ✖ Heavy Multiplication X
|
|
144
|
+
if (codePoint === 0x279c)
|
|
145
|
+
return 2; // ➜ Heavy Round-Tipped Arrow
|
|
146
|
+
if (codePoint === 0x27a4)
|
|
147
|
+
return 2; // ➤ Black Right Arrowhead
|
|
148
|
+
if (codePoint === 0x25b6)
|
|
149
|
+
return 2; // ▶ Black Right Triangle
|
|
150
|
+
if (codePoint === 0x23f1)
|
|
151
|
+
return 2; // ⏱ Stopwatch
|
|
152
|
+
// Hourglass + Watch (⌚⌛)
|
|
119
153
|
if (codePoint === 0x231a || codePoint === 0x231b)
|
|
120
154
|
return 2;
|
|
121
|
-
//
|
|
122
|
-
if (codePoint >= 0x23e9 && codePoint <=
|
|
123
|
-
return 2;
|
|
124
|
-
//
|
|
125
|
-
if (codePoint
|
|
126
|
-
return 2;
|
|
127
|
-
//
|
|
128
|
-
if (codePoint ===
|
|
129
|
-
return 2;
|
|
130
|
-
//
|
|
131
|
-
if (codePoint
|
|
132
|
-
return 2;
|
|
133
|
-
//
|
|
134
|
-
if (codePoint
|
|
135
|
-
return 2;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (codePoint ===
|
|
141
|
-
return 2;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (codePoint
|
|
147
|
-
return 2;
|
|
155
|
+
// Fast-forward through rewind (⏩⏪⏫⏬)
|
|
156
|
+
if (codePoint >= 0x23e9 && codePoint <= 0x23ec)
|
|
157
|
+
return 2;
|
|
158
|
+
// Alarm clock (⏰)
|
|
159
|
+
if (codePoint === 0x23f0)
|
|
160
|
+
return 2;
|
|
161
|
+
// Hourglass flowing (⏳)
|
|
162
|
+
if (codePoint === 0x23f3)
|
|
163
|
+
return 2;
|
|
164
|
+
// White/black medium small square with emoji pres (◽◾)
|
|
165
|
+
if (codePoint === 0x25fd || codePoint === 0x25fe)
|
|
166
|
+
return 2;
|
|
167
|
+
// Misc Symbols — only Emoji_Presentation=Yes entries
|
|
168
|
+
if (codePoint === 0x2614 || codePoint === 0x2615)
|
|
169
|
+
return 2; // ☔☕
|
|
170
|
+
if (codePoint >= 0x2648 && codePoint <= 0x2653)
|
|
171
|
+
return 2; // ♈-♓
|
|
172
|
+
if (codePoint === 0x267f)
|
|
173
|
+
return 2; // ♿
|
|
174
|
+
if (codePoint === 0x2693)
|
|
175
|
+
return 2; // ⚓
|
|
176
|
+
if (codePoint === 0x26a1)
|
|
177
|
+
return 2; // ⚡
|
|
178
|
+
if (codePoint === 0x26aa || codePoint === 0x26ab)
|
|
179
|
+
return 2; // ⚪⚫
|
|
180
|
+
if (codePoint === 0x26bd || codePoint === 0x26be)
|
|
181
|
+
return 2; // ⚽⚾
|
|
182
|
+
if (codePoint === 0x26c4 || codePoint === 0x26c5)
|
|
183
|
+
return 2; // ⛄⛅
|
|
184
|
+
if (codePoint === 0x26ce)
|
|
185
|
+
return 2; // ⛎
|
|
186
|
+
if (codePoint === 0x26d4)
|
|
187
|
+
return 2; // ⛔
|
|
188
|
+
if (codePoint === 0x26ea)
|
|
189
|
+
return 2; // ⛪
|
|
190
|
+
if (codePoint === 0x26f2 || codePoint === 0x26f3)
|
|
191
|
+
return 2; // ⛲⛳
|
|
192
|
+
if (codePoint === 0x26f5)
|
|
193
|
+
return 2; // ⛵
|
|
194
|
+
if (codePoint === 0x26fa)
|
|
195
|
+
return 2; // ⛺
|
|
196
|
+
if (codePoint === 0x26fd)
|
|
197
|
+
return 2; // ⛽
|
|
198
|
+
// Dingbats — only Emoji_Presentation=Yes entries
|
|
199
|
+
if (codePoint === 0x2705)
|
|
200
|
+
return 2; // ✅
|
|
201
|
+
if (codePoint === 0x270a || codePoint === 0x270b)
|
|
202
|
+
return 2; // ✊✋
|
|
203
|
+
if (codePoint === 0x2728)
|
|
204
|
+
return 2; // ✨
|
|
205
|
+
if (codePoint === 0x274c)
|
|
206
|
+
return 2; // ❌
|
|
207
|
+
if (codePoint === 0x274e)
|
|
208
|
+
return 2; // ❎
|
|
209
|
+
if (codePoint >= 0x2753 && codePoint <= 0x2755)
|
|
210
|
+
return 2; // ❓❔❕
|
|
211
|
+
if (codePoint === 0x2757)
|
|
212
|
+
return 2; // ❗
|
|
213
|
+
if (codePoint === 0x2764)
|
|
214
|
+
return 2; // ❤
|
|
215
|
+
if (codePoint >= 0x2795 && codePoint <= 0x2797)
|
|
216
|
+
return 2; // ➕➖➗
|
|
217
|
+
// Curly loop / double curly loop (➰➿)
|
|
218
|
+
if (codePoint === 0x27b0 || codePoint === 0x27bf)
|
|
219
|
+
return 2;
|
|
220
|
+
// Black large square/circle, star, hollow circle (⬛⬜⭐⭕)
|
|
148
221
|
if (codePoint === 0x2b1b || codePoint === 0x2b1c)
|
|
149
222
|
return 2;
|
|
150
223
|
if (codePoint === 0x2b50 || codePoint === 0x2b55)
|
|
151
224
|
return 2;
|
|
152
|
-
// Copyright / Registered / TM (when emoji-styled)
|
|
153
|
-
if (codePoint === 0x00a9 || codePoint === 0x00ae)
|
|
154
|
-
return 2;
|
|
155
|
-
// Wavy dash, part alternation mark
|
|
156
|
-
if (codePoint === 0x3030 || codePoint === 0x303d)
|
|
157
|
-
return 2;
|
|
158
225
|
// SMP Emoji: Mahjong through Symbols & Pictographs Extended-A
|
|
159
|
-
// Covers emoticons, transport, flags, supplemental symbols, etc.
|
|
160
226
|
if (codePoint >= 0x1f000 && codePoint <= 0x1faff)
|
|
161
227
|
return 2;
|
|
162
228
|
return 1;
|
package/package.json
CHANGED