@0xbigboss/ghostty-web 0.4.0 → 0.5.0

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.d.ts CHANGED
@@ -699,27 +699,43 @@ export declare interface ILinkProvider {
699
699
  */
700
700
  export declare function init(): Promise<void>;
701
701
 
702
- /**
703
- * InputHandler class
704
- * Attaches keyboard event listeners to a container and converts
705
- * keyboard events to terminal input data
706
- */
707
702
  export declare class InputHandler {
708
703
  private encoder;
709
704
  private container;
705
+ private inputElement?;
710
706
  private onDataCallback;
711
707
  private onBellCallback;
712
708
  private onKeyCallback?;
713
709
  private customKeyEventHandler?;
714
710
  private getModeCallback?;
711
+ private onCopyCallback?;
712
+ private mouseConfig?;
713
+ private macOptionIsMeta;
714
+ private isMac;
715
715
  private keydownListener;
716
716
  private keypressListener;
717
717
  private pasteListener;
718
+ private beforeInputListener;
718
719
  private compositionStartListener;
719
720
  private compositionUpdateListener;
720
721
  private compositionEndListener;
722
+ private mousedownListener;
723
+ private mouseupListener;
724
+ private mousemoveListener;
725
+ private wheelListener;
721
726
  private isComposing;
722
727
  private isDisposed;
728
+ private mouseButtonsPressed;
729
+ private lastKeyDownData;
730
+ private lastKeyDownTime;
731
+ private lastPasteData;
732
+ private lastPasteTime;
733
+ private lastPasteSource;
734
+ private lastCompositionData;
735
+ private lastCompositionTime;
736
+ private lastBeforeInputData;
737
+ private lastBeforeInputTime;
738
+ private static readonly BEFORE_INPUT_IGNORE_MS;
723
739
  /**
724
740
  * Create a new InputHandler
725
741
  * @param ghostty - Ghostty instance (for creating KeyEncoder)
@@ -729,8 +745,12 @@ export declare class InputHandler {
729
745
  * @param onKey - Optional callback for raw key events
730
746
  * @param customKeyEventHandler - Optional custom key event handler
731
747
  * @param getMode - Optional callback to query terminal mode state (for application cursor mode)
748
+ * @param onCopy - Optional callback to handle copy (Cmd+C/Ctrl+C with selection)
749
+ * @param inputElement - Optional input element for beforeinput events
750
+ * @param mouseConfig - Optional mouse tracking configuration
751
+ * @param macOptionIsMeta - Treat Option key as Meta on Mac (sends ESC prefix)
732
752
  */
733
- constructor(ghostty: Ghostty, container: HTMLElement, onData: (data: string) => void, onBell: () => void, onKey?: (keyEvent: IKeyEvent) => void, customKeyEventHandler?: (event: KeyboardEvent) => boolean | undefined, getMode?: (mode: number) => boolean);
753
+ constructor(ghostty: Ghostty, container: HTMLElement, onData: (data: string) => void, onBell: () => void, onKey?: (keyEvent: IKeyEvent) => void, customKeyEventHandler?: (event: KeyboardEvent) => boolean | undefined, getMode?: (mode: number) => boolean, onCopy?: () => boolean, inputElement?: HTMLElement, mouseConfig?: MouseTrackingConfig, macOptionIsMeta?: boolean);
734
754
  /**
735
755
  * Set custom key event handler (for runtime updates)
736
756
  * Returns: true = terminal handles it, false = let it bubble, undefined = default processing
@@ -763,11 +783,23 @@ export declare class InputHandler {
763
783
  * @param event - KeyboardEvent
764
784
  */
765
785
  private handleKeyDown;
786
+ /**
787
+ * Handle Option key as Meta on Mac (sends ESC prefix)
788
+ * This enables word navigation shortcuts like Option+Left/Right
789
+ * @param event - KeyboardEvent with altKey pressed
790
+ * @returns true if the event was handled
791
+ */
792
+ private handleOptionAsMeta;
766
793
  /**
767
794
  * Handle paste event from clipboard
768
795
  * @param event - ClipboardEvent
769
796
  */
770
797
  private handlePaste;
798
+ /**
799
+ * Handle beforeinput event (mobile/IME input)
800
+ * @param event - InputEvent
801
+ */
802
+ private handleBeforeInput;
771
803
  /**
772
804
  * Handle compositionstart event
773
805
  */
@@ -780,6 +812,88 @@ export declare class InputHandler {
780
812
  * Handle compositionend event
781
813
  */
782
814
  private handleCompositionEnd;
815
+ /**
816
+ * Cleanup text nodes in container after composition
817
+ */
818
+ private cleanupCompositionTextNodes;
819
+ /**
820
+ * Convert pixel coordinates to terminal cell coordinates
821
+ */
822
+ private pixelToCell;
823
+ /**
824
+ * Get modifier flags for mouse event
825
+ */
826
+ private getMouseModifiers;
827
+ /**
828
+ * Encode mouse event as SGR sequence
829
+ * SGR format: \x1b[<Btn;Col;RowM (press/motion) or \x1b[<Btn;Col;Rowm (release)
830
+ */
831
+ private encodeMouseSGR;
832
+ /**
833
+ * Encode mouse event as X10/normal sequence (legacy format)
834
+ * Format: \x1b[M<Btn+32><Col+32><Row+32>
835
+ */
836
+ private encodeMouseX10;
837
+ /**
838
+ * Send mouse event to terminal
839
+ */
840
+ private sendMouseEvent;
841
+ /**
842
+ * Handle mousedown event
843
+ */
844
+ private handleMouseDown;
845
+ /**
846
+ * Handle mouseup event
847
+ */
848
+ private handleMouseUp;
849
+ /**
850
+ * Handle mousemove event
851
+ */
852
+ private handleMouseMove;
853
+ /**
854
+ * Handle wheel event (scroll)
855
+ */
856
+ private handleWheel;
857
+ /**
858
+ * Emit paste data with bracketed paste support
859
+ */
860
+ private emitPasteData;
861
+ /**
862
+ * Record keydown data for beforeinput de-duplication
863
+ */
864
+ private recordKeyDownData;
865
+ /**
866
+ * Record paste data for beforeinput de-duplication
867
+ */
868
+ private recordPasteData;
869
+ /**
870
+ * Check if beforeinput should be ignored due to a recent keydown
871
+ */
872
+ private shouldIgnoreBeforeInput;
873
+ /**
874
+ * Check if beforeinput text should be ignored due to a recent composition end
875
+ */
876
+ private shouldIgnoreBeforeInputFromComposition;
877
+ /**
878
+ * Check if composition end should be ignored due to a recent beforeinput text
879
+ */
880
+ private shouldIgnoreCompositionEnd;
881
+ /**
882
+ * Record beforeinput text for composition de-duplication
883
+ */
884
+ private recordBeforeInputData;
885
+ /**
886
+ * Record composition end data for beforeinput de-duplication
887
+ */
888
+ private recordCompositionData;
889
+ /**
890
+ * Check if paste should be ignored due to a recent paste event from another source
891
+ */
892
+ private shouldIgnorePasteEvent;
893
+ /**
894
+ * Get current time in milliseconds
895
+ */
896
+ private getNow;
783
897
  /**
784
898
  * Dispose the InputHandler and remove event listeners
785
899
  */
@@ -896,6 +1010,7 @@ export declare interface ITerminalOptions {
896
1010
  convertEol?: boolean;
897
1011
  disableStdin?: boolean;
898
1012
  smoothScrollDuration?: number;
1013
+ macOptionIsMeta?: boolean;
899
1014
  onLinkClick?: (url: string, event: MouseEvent) => boolean;
900
1015
  ghostty?: Ghostty;
901
1016
  }
@@ -1237,6 +1352,31 @@ export declare enum Mods {
1237
1352
  NUMLOCK = 32
1238
1353
  }
1239
1354
 
1355
+ /**
1356
+ * InputHandler class
1357
+ * Attaches keyboard event listeners to a container and converts
1358
+ * keyboard events to terminal input data
1359
+ */
1360
+ /**
1361
+ * Mouse tracking configuration
1362
+ */
1363
+ declare interface MouseTrackingConfig {
1364
+ /** Check if any mouse tracking mode is enabled */
1365
+ hasMouseTracking: () => boolean;
1366
+ /** Check if SGR extended mouse mode is enabled (mode 1006) */
1367
+ hasSgrMouseMode: () => boolean;
1368
+ /** Get cell dimensions for pixel to cell conversion */
1369
+ getCellDimensions: () => {
1370
+ width: number;
1371
+ height: number;
1372
+ };
1373
+ /** Get canvas/container offset for accurate position calculation */
1374
+ getCanvasOffset: () => {
1375
+ left: number;
1376
+ top: number;
1377
+ };
1378
+ }
1379
+
1240
1380
  /**
1241
1381
  * OSC 8 Hyperlink Provider
1242
1382
  *
@@ -1317,7 +1457,6 @@ export declare class SelectionManager {
1317
1457
  private selectionEnd;
1318
1458
  private isSelecting;
1319
1459
  private mouseDownTarget;
1320
- private mouseButtonsPressed;
1321
1460
  private dirtySelectionRows;
1322
1461
  private selectionChangedEmitter;
1323
1462
  private boundMouseUpHandler;
@@ -1351,6 +1490,11 @@ export declare class SelectionManager {
1351
1490
  * Check if there's an active selection
1352
1491
  */
1353
1492
  hasSelection(): boolean;
1493
+ /**
1494
+ * Copy the current selection to clipboard
1495
+ * @returns true if there was text to copy, false otherwise
1496
+ */
1497
+ copySelection(): boolean;
1354
1498
  /**
1355
1499
  * Clear the selection
1356
1500
  */
@@ -1412,42 +1556,6 @@ export declare class SelectionManager {
1412
1556
  * Cleanup resources
1413
1557
  */
1414
1558
  dispose(): void;
1415
- /**
1416
- * Check if SGR mouse format (DEC mode 1006) is enabled.
1417
- * When 1006 is not enabled, applications expect X10 format which we don't yet support.
1418
- * Returns true if SGR mode is enabled, false otherwise.
1419
- */
1420
- private hasSGRMouseMode;
1421
- /**
1422
- * Check if motion events should be reported based on tracking mode.
1423
- * - Mode 1000 (NORMAL): Only button press/release, no motion
1424
- * - Mode 1002 (BUTTON): Motion only while button is held
1425
- * - Mode 1003 (ANY): All motion events
1426
- */
1427
- private shouldReportMotion;
1428
- /**
1429
- * Map browser button codes to SGR button codes.
1430
- * Only buttons 0, 1, 2 are valid; others return null.
1431
- */
1432
- private mapButton;
1433
- /**
1434
- * Encode modifier keys into button code.
1435
- * Shift: +4, Alt/Meta: +8, Ctrl: +16
1436
- */
1437
- private encodeModifiers;
1438
- /**
1439
- * Generate SGR mouse sequence and send to terminal.
1440
- * SGR format: CSI < button ; col ; row M (press) or m (release)
1441
- * Button code includes: base button (0-2) + motion flag (32) + modifiers (4/8/16) + scroll (64/65)
1442
- *
1443
- * Only sends if DEC mode 1006 (SGR) is enabled. Without 1006, applications expect
1444
- * X10 format which encodes differently and has coordinate limits.
1445
- */
1446
- private sendMouseEvent;
1447
- /**
1448
- * Send scroll wheel event with modifiers.
1449
- */
1450
- private sendScrollEvent;
1451
1559
  /**
1452
1560
  * Attach mouse event listeners to canvas
1453
1561
  */
@@ -1483,8 +1591,22 @@ export declare class SelectionManager {
1483
1591
  private getWordAtCell;
1484
1592
  /**
1485
1593
  * Copy text to clipboard
1594
+ *
1595
+ * Strategy (modern APIs first):
1596
+ * 1. Try ClipboardItem API (works in Safari and modern browsers)
1597
+ * - Safari requires the ClipboardItem to be created synchronously within user gesture
1598
+ * 2. Try navigator.clipboard.writeText (modern async API, may fail in Safari)
1599
+ * 3. Fall back to execCommand (legacy, for older browsers)
1486
1600
  */
1487
1601
  private copyToClipboard;
1602
+ /**
1603
+ * Copy using navigator.clipboard.writeText
1604
+ */
1605
+ private copyWithWriteText;
1606
+ /**
1607
+ * Copy using legacy execCommand (fallback for older browsers)
1608
+ */
1609
+ private copyWithExecCommand;
1488
1610
  /**
1489
1611
  * Request a render update (triggers selection overlay redraw)
1490
1612
  */
@@ -1536,9 +1658,6 @@ export declare class Terminal implements ITerminalCore {
1536
1658
  private isOpen;
1537
1659
  private isDisposed;
1538
1660
  private animationFrameId?;
1539
- private _isResizing;
1540
- private _writeQueue;
1541
- private _resizeFlushFrameId?;
1542
1661
  private addons;
1543
1662
  private customKeyEventHandler?;
1544
1663
  private currentTitle;
@@ -1610,17 +1729,8 @@ export declare class Terminal implements ITerminalCore {
1610
1729
  input(data: string, wasUserInput?: boolean): void;
1611
1730
  /**
1612
1731
  * Resize terminal
1613
- *
1614
- * Note: We pause the render loop and queue writes during resize to prevent
1615
- * race conditions. The WASM terminal reallocates internal buffers during
1616
- * resize, and if the render loop or writes access those buffers concurrently,
1617
- * it can cause a crash.
1618
1732
  */
1619
1733
  resize(cols: number, rows: number): void;
1620
- /**
1621
- * Flush queued writes that were blocked during resize
1622
- */
1623
- private flushWriteQueue;
1624
1734
  /**
1625
1735
  * Clear terminal screen
1626
1736
  */
@@ -1653,6 +1763,11 @@ export declare class Terminal implements ITerminalCore {
1653
1763
  * Clear the current selection
1654
1764
  */
1655
1765
  clearSelection(): void;
1766
+ /**
1767
+ * Copy the current selection to clipboard
1768
+ * @returns true if there was text to copy, false otherwise
1769
+ */
1770
+ copySelection(): boolean;
1656
1771
  /**
1657
1772
  * Select all text in the terminal
1658
1773
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@0xbigboss/ghostty-web",
3
- "version": "0.4.0",
4
- "description": "Web-based terminal emulator using Ghostty's VT100 parser via WebAssembly. Fork with enhanced selection handling.",
3
+ "version": "0.5.0",
4
+ "description": "Web-based terminal emulator using Ghostty's VT100 parser via WebAssembly",
5
5
  "type": "module",
6
6
  "main": "./dist/ghostty-web.umd.cjs",
7
7
  "module": "./dist/ghostty-web.js",
@@ -29,20 +29,16 @@
29
29
  "wasm",
30
30
  "webassembly",
31
31
  "ansi",
32
- "tty",
33
- "vscode"
32
+ "tty"
34
33
  ],
35
34
  "repository": {
36
35
  "type": "git",
37
- "url": "https://github.com/0xBigBoss/ghostty-web.git"
36
+ "url": "https://github.com/coder/ghostty-web.git"
38
37
  },
39
- "bugs": "https://github.com/0xBigBoss/ghostty-web/issues",
40
- "homepage": "https://github.com/0xBigBoss/ghostty-web#readme",
38
+ "bugs": "https://github.com/coder/ghostty-web/issues",
39
+ "homepage": "https://github.com/coder/ghostty-web#readme",
41
40
  "license": "MIT",
42
- "author": "0xBigBoss",
43
- "contributors": [
44
- "Coder (https://github.com/coder)"
45
- ],
41
+ "author": "Coder",
46
42
  "publishConfig": {
47
43
  "access": "public"
48
44
  },