UNPKG

4.47 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const react_1 = __importDefault(require("react"));
7const ink_1 = require("ink");
8const ARROW_UP = '\u001B[A';
9const ARROW_DOWN = '\u001B[B';
10class Scroll extends react_1.default.Component {
11 constructor() {
12 super(...arguments);
13 /* Number of items displayed in the list at once. */
14 this.window = 5;
15 this.state = {
16 cursor: 0,
17 };
18 this.handleInput = (data) => {
19 const { active, values } = this.props;
20 const { cursor } = this.state;
21 /* Prevent any action if element is out of focus. */
22 if (!active)
23 return;
24 /* Decode char */
25 const char = String(data);
26 switch (char) {
27 case ARROW_UP:
28 if (cursor - 1 >= 0)
29 this.setState({ cursor: cursor - 1 });
30 break;
31 case ARROW_DOWN:
32 if (cursor + 1 < values.length)
33 this.setState({ cursor: cursor + 1 });
34 break;
35 }
36 };
37 /**
38 * Calculates the mask begining position.
39 */
40 this.getMask = () => {
41 const values = this.props.values;
42 const cursor = this.state.cursor;
43 const size = this.window;
44 /** Distance from the cursor to the top of mask. */
45 const offset = Math.floor(size / 2);
46 /** Items are shorter than mask. */
47 if (values.length <= size)
48 return 0;
49 /** Cursor has moved above the middle point of the mask. */
50 if (cursor - offset <= 0)
51 return 0;
52 /** Cursor has moved past the middle point of the mask. */
53 if (cursor + offset >= values.length)
54 return values.length - size;
55 /** Cursor is in the "middle" of the list. */
56 return cursor - offset;
57 };
58 }
59 componentDidMount() {
60 const { stdin, setRawMode } = this.props;
61 if (setRawMode)
62 setRawMode(true);
63 stdin.on('data', this.handleInput);
64 }
65 componentWillUnmount() {
66 const { stdin, setRawMode } = this.props;
67 stdin.removeListener('data', this.handleInput);
68 if (setRawMode)
69 setRawMode(false);
70 }
71 /**
72 *
73 * This ensures that cursor stays in sync with the most recent props.
74 *
75 * @param props
76 * @param state
77 */
78 static getDerivedStateFromProps(props, state) {
79 if (props.active === false)
80 return Object.assign({}, state, { cursor: 0 });
81 if (props.values.length < state.cursor) {
82 return Object.assign({}, state, { cursor: props.values.length });
83 }
84 return null;
85 }
86 /**
87 *
88 * Makes sure that the outside world knows where we are.
89 *
90 * @param props
91 * @param state
92 */
93 componentDidUpdate(props, state) {
94 const cursor = this.state.cursor;
95 /**
96 * Trigger onWillReachEnd on the second last item in the list.
97 */
98 if (cursor === this.props.values.length - 2)
99 this.props.onWillReachEnd();
100 }
101 render() {
102 const mask = this.getMask(), cursor = this.state.cursor, size = this.window, values = this.props.values.slice(mask, mask + size), render = this.props.children;
103 return (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
104 values.length === 0 && (react_1.default.createElement(ink_1.Text, null,
105 react_1.default.createElement(ink_1.Color, { grey: true }, "Start typing or change query so we can find something!"))),
106 values.map((value, i) => render(Object.assign({}, value, { active: this.props.active && i + mask === cursor })))));
107 }
108}
109/**
110 * Wraps the component in stdin consumer.
111 */
112class ScrollWithStdin extends react_1.default.Component {
113 render() {
114 return (react_1.default.createElement(ink_1.StdinContext.Consumer, null, ({ stdin, setRawMode }) => (react_1.default.createElement(Scroll, Object.assign({}, this.props, { stdin: stdin, setRawMode: setRawMode })))));
115 }
116}
117exports.default = ScrollWithStdin;
118//# sourceMappingURL=Scroll.js.map
\No newline at end of file