feat: add scoped shortcuts
This commit is contained in:
@@ -6,7 +6,7 @@ export interface DialogState {
|
||||
close?: () => void;
|
||||
}
|
||||
export const Context = createContext<DialogState>({
|
||||
close: () => { },
|
||||
close: () => {},
|
||||
});
|
||||
|
||||
interface ProviderProps {
|
||||
@@ -21,7 +21,7 @@ export function Provider({ children, visible, close }: ProviderProps) {
|
||||
{/* <Pressable onPress={() => close && close()} style={{ justifyContent: 'center', alignItems: 'center', flex: 1, backgroundColor: 'rgba(0,0,0,0.2)', }}> */}
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
// justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flex: 1,
|
||||
backgroundColor: "rgba(0,0,0,0.2)",
|
||||
@@ -39,12 +39,10 @@ interface ContentProps {
|
||||
}
|
||||
export function Content({ children }: ContentProps) {
|
||||
const { close } = use(Context);
|
||||
useShortcut("escape", () => close?.());
|
||||
useShortcut("escape", () => close?.(), "dialog");
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{ backgroundColor: "white", padding: 12, alignItems: "center" }}
|
||||
>
|
||||
<View style={{ backgroundColor: "white", alignItems: "center", top: 120 }}>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import {
|
||||
createContext,
|
||||
use,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { createContext, use, useEffect, useState, type ReactNode } from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import type { KeyEvent } from "@opentui/core";
|
||||
import { useShortcut } from "../lib/shortcuts/hooks";
|
||||
import type { Key } from "../lib/shortcuts";
|
||||
|
||||
const HEADER_COLOR = "#7158e2";
|
||||
const TABLE_COLORS = ["#ddd", "#eee"];
|
||||
const SELECTED_COLOR = "#f7b730";
|
||||
|
||||
const COLORS = {
|
||||
focused: "#ddd",
|
||||
selected: "#eaebf6",
|
||||
focused_selected: "#d5d7ef",
|
||||
};
|
||||
|
||||
const EXTRA = 5;
|
||||
|
||||
@@ -24,7 +20,7 @@ interface TableState {
|
||||
columns: Column[];
|
||||
columnMap: Map<string, number>;
|
||||
idx: number;
|
||||
selectedFrom: number | undefined;
|
||||
selectedIdx: Set<number>;
|
||||
}
|
||||
|
||||
const INITAL_STATE = {
|
||||
@@ -32,7 +28,7 @@ const INITAL_STATE = {
|
||||
columns: [],
|
||||
columnMap: new Map(),
|
||||
idx: 0,
|
||||
selectedFrom: undefined,
|
||||
selectedIdx: new Set(),
|
||||
} satisfies TableState;
|
||||
|
||||
export const Context = createContext<TableState>(INITAL_STATE);
|
||||
@@ -69,7 +65,7 @@ export function Provider<T extends ValidRecord>({
|
||||
shortcuts,
|
||||
}: ProviderProps<T>) {
|
||||
const [idx, setIdx] = useState(0);
|
||||
const [selectedFrom, setSelectedFrom] = useState<number>();
|
||||
const [selectedIdx, setSelectedIdx] = useState(new Set<number>());
|
||||
|
||||
useShortcut("j", () => {
|
||||
setIdx((prev) => Math.min(prev + 1, data.length - 1));
|
||||
@@ -84,6 +80,17 @@ export function Provider<T extends ValidRecord>({
|
||||
setIdx((prev) => Math.max(prev - 1, 0));
|
||||
});
|
||||
|
||||
useShortcut("escape", () => {
|
||||
setSelectedIdx(new Set());
|
||||
});
|
||||
useShortcut("x", () => {
|
||||
setSelectedIdx((last) => {
|
||||
const newSelected = new Set(last);
|
||||
newSelected.add(idx);
|
||||
return newSelected;
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setIdx((prev) => Math.max(Math.min(prev, data.length - 1), 0));
|
||||
}, [data]);
|
||||
@@ -91,9 +98,9 @@ export function Provider<T extends ValidRecord>({
|
||||
if (shortcuts) {
|
||||
for (const shortcut of shortcuts) {
|
||||
useShortcut(shortcut.key, () => {
|
||||
const from = selectedFrom ? Math.min(idx, selectedFrom) : idx;
|
||||
const to = selectedFrom ? Math.max(idx, selectedFrom) : idx;
|
||||
const selected = data.slice(from, to + 1);
|
||||
const selected = data.filter(
|
||||
(_, index) => idx == index || selectedIdx.has(index),
|
||||
);
|
||||
shortcut.handler({ selected, index: idx });
|
||||
});
|
||||
}
|
||||
@@ -112,14 +119,14 @@ export function Provider<T extends ValidRecord>({
|
||||
);
|
||||
|
||||
return (
|
||||
<Context.Provider value={{ data, columns, columnMap, idx, selectedFrom }}>
|
||||
<Context.Provider value={{ data, columns, columnMap, idx, selectedIdx }}>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function Body() {
|
||||
const { columns, data, columnMap, idx, selectedFrom } = use(Context);
|
||||
const { columns, data, columnMap, idx, selectedIdx } = use(Context);
|
||||
return (
|
||||
<View>
|
||||
<View style={{ backgroundColor: HEADER_COLOR, flexDirection: "row" }}>
|
||||
@@ -136,19 +143,21 @@ export function Body() {
|
||||
))}
|
||||
</View>
|
||||
{data.map((row, index) => {
|
||||
const isSelected =
|
||||
index == idx ||
|
||||
(selectedFrom != undefined &&
|
||||
((selectedFrom <= index && index <= idx) ||
|
||||
(idx <= index && index <= selectedFrom)));
|
||||
const isSelected = selectedIdx.has(index);
|
||||
const isFocused = index == idx;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={index}
|
||||
style={{
|
||||
backgroundColor: isSelected
|
||||
? SELECTED_COLOR
|
||||
: TABLE_COLORS[index % 2],
|
||||
backgroundColor:
|
||||
isSelected && isFocused
|
||||
? COLORS.focused_selected
|
||||
: isFocused
|
||||
? COLORS.focused
|
||||
: isSelected
|
||||
? COLORS.selected
|
||||
: undefined,
|
||||
}}
|
||||
>
|
||||
<TableRow
|
||||
|
||||
Reference in New Issue
Block a user