UNPKG

ink-scroll

Version:
214 lines (183 loc) 5.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _ink = require("ink"); var _propTypes = _interopRequireDefault(require("prop-types")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class Scroll extends _ink.Component { constructor(props, state) { super(props, state); const { height } = props; this.state = { cursorPosition: 0, startingIndex: 0, endingIndex: height - 1 }; this.updateCursor = this.updateCursor.bind(this); this.updateIndexRange = this.updateIndexRange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); } componentDidMount() { process.stdin.on('keypress', this.handleKeyPress); } componentWillUnmount() { process.stdin.removeListener('keypress', this.handleKeyPress); } componentWillReceiveProps(nextProps) { const { cursorPosition } = this.state; const { cursorPosition: newCursorPosition } = nextProps; if (newCursorPosition !== undefined && cursorPosition !== newCursorPosition) { this.updateCursor(newCursorPosition); } } componentDidUpdate() { this.updateIndexRange(); } async updateCursor(cursorPosition) { const { children, onPositionChange } = this.props; const maxIndex = children.length - 1; if (cursorPosition > maxIndex) { cursorPosition = maxIndex; onPositionChange && onPositionChange(cursorPosition); } else if (cursorPosition < 0) { cursorPosition = 0; onPositionChange && onPositionChange(cursorPosition); } await this.setState({ cursorPosition }); } updateIndexRange() { const { cursorPosition, startingIndex, endingIndex } = this.state; const { children, height } = this.props; const maxIndex = children.length - 1; let newStartingIndex; let newEndingIndex; if (children.length <= height) { newStartingIndex = 0; newEndingIndex = maxIndex; } else if (cursorPosition === maxIndex || endingIndex > maxIndex) { newEndingIndex = maxIndex; newStartingIndex = newEndingIndex - (height - 1); } else if (cursorPosition === 0 || startingIndex < 0) { newStartingIndex = 0; newEndingIndex = newStartingIndex + (height - 1); } else if (cursorPosition >= endingIndex) { newEndingIndex = cursorPosition + 1; newStartingIndex = newEndingIndex - (height - 1); } else if (cursorPosition <= startingIndex) { newStartingIndex = cursorPosition - 1; newEndingIndex = newStartingIndex + (height - 1); } else { newStartingIndex = startingIndex; newEndingIndex = endingIndex; } if (newStartingIndex !== startingIndex || newEndingIndex !== endingIndex) { this.setState({ startingIndex: newStartingIndex, endingIndex: newEndingIndex }); this.updateCursor(cursorPosition); } } async handleKeyPress(_, key) { const { cursorPosition } = this.state; const { children, focused, onPositionChange, onLimitHit, onSelect, cursorPosition: myCursorPosition } = this.props; if (!focused) { return; } switch (key.name) { case 'down': if (cursorPosition < children.length - 1) { onPositionChange && onPositionChange(cursorPosition + 1); if (myCursorPosition === undefined) { this.updateCursor(cursorPosition + 1); } } if (cursorPosition + 1 === children.length - 1) { onLimitHit && onLimitHit(cursorPosition + 1); } break; case 'up': if (cursorPosition > 0) { onPositionChange && onPositionChange(cursorPosition - 1); if (myCursorPosition === undefined) { this.updateCursor(cursorPosition - 1); } } if (cursorPosition - 1 === 0) { onLimitHit && onLimitHit(cursorPosition - 1); } break; case 'return': onSelect && onSelect(cursorPosition); break; default: break; } } render() { const { cursorPosition, startingIndex, endingIndex } = this.state; const { children, cursorColor, cursorChar } = this.props; return (0, _ink.h)("span", null, children.slice(startingIndex, endingIndex + 1).map((child, index) => index === cursorPosition - startingIndex ? (0, _ink.h)("div", null, (0, _ink.h)(_ink.Color, { keyword: cursorColor }, `${cursorChar} `), child) : (0, _ink.h)("div", null, " ", child))); } } Scroll.propTypes = { focused: _propTypes.default.bool, height: _propTypes.default.number, onPositionChange: _propTypes.default.func, cursorPosition: _propTypes.default.number, onLimitHit: _propTypes.default.func, onSelect: _propTypes.default.func, cursorColor: _propTypes.default.string, cursorChar: _propTypes.default.string }; Scroll.defaultProps = { focused: true, height: 5, onPositionChange: undefined, cursorPosition: undefined, onLimitHit: undefined, onSelect: undefined, cursorColor: 'grey', cursorChar: '>' }; var _default = Scroll; exports.default = _default;