ink-scroll
Version:
Scroll component for Ink
214 lines (183 loc) • 5.35 kB
JavaScript
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;
;