feat: initial commit
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { useState, type ComponentProps, type ReactNode } from "react";
|
||||
import { useManagedFocus } from "../../contexts/FocusManager.js";
|
||||
import { Box, Text, useInput } from "ink";
|
||||
|
||||
export function Button({
|
||||
children,
|
||||
onClick,
|
||||
autoFocus,
|
||||
focusId,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
onClick: () => void;
|
||||
autoFocus?: boolean;
|
||||
focusId?: string;
|
||||
}) {
|
||||
const { isFocused } = useManagedFocus({ autoFocus, id: focusId });
|
||||
useInput(
|
||||
(input, key) => {
|
||||
if (input === " " || key.return) onClick();
|
||||
},
|
||||
{ isActive: isFocused }
|
||||
);
|
||||
|
||||
return <Text inverse={isFocused}>[{children}]</Text>;
|
||||
}
|
||||
|
||||
export type ButtonListItem = {
|
||||
children: ReactNode;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export function ButtonList({
|
||||
buttons,
|
||||
autoFocus,
|
||||
focusId,
|
||||
isFocused: forceFocus,
|
||||
horizontal = false,
|
||||
vertical = false,
|
||||
...props
|
||||
}: {
|
||||
buttons: ButtonListItem[];
|
||||
autoFocus?: boolean;
|
||||
focusId?: string;
|
||||
isFocused?: boolean;
|
||||
horizontal?: boolean;
|
||||
vertical?: boolean;
|
||||
} & Omit<ComponentProps<typeof Box>, "children">) {
|
||||
if (!horizontal && !vertical) horizontal = true;
|
||||
|
||||
const [selected, setSelected] = useState(0);
|
||||
const { isFocused } = useManagedFocus({
|
||||
autoFocus,
|
||||
id: focusId,
|
||||
isActive: forceFocus === undefined,
|
||||
});
|
||||
useInput(
|
||||
(input, key) => {
|
||||
if (input === " " || key.return) {
|
||||
buttons[selected].onClick();
|
||||
} else if (
|
||||
(vertical && key.downArrow) ||
|
||||
(horizontal && key.rightArrow)
|
||||
) {
|
||||
setSelected((prev) => (prev + 1) % buttons.length);
|
||||
} else if ((vertical && key.upArrow) || (horizontal && key.leftArrow)) {
|
||||
setSelected((prev) => (prev - 1 + buttons.length) % buttons.length);
|
||||
}
|
||||
},
|
||||
{ isActive: isFocused || forceFocus || false }
|
||||
);
|
||||
|
||||
return (
|
||||
<Box gap={1} {...props}>
|
||||
{buttons.map((button, i) => (
|
||||
<Text inverse={(isFocused || forceFocus) && i === selected}>
|
||||
[{button.children}]
|
||||
</Text>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user