opentui
opentui copied to clipboard
Allow for <select> to have no currently selected option, or allow to hide that the option is selected when the <select> is not focused
I have four <select> elements side-by-side:
In the screenshot, the second <select> is focused.
I would like the possibility to have no selected option when an select isn't focused.
Meaning: no triangle, no yellow text, no blue background.
An alternative could be that the selected option looks different when the <select> is not focused compared to when it is focused.
Below is my sample code. You can change the focused <select> using the left and right arrow keys.
import { render, useKeyboard } from "@opentui/react"
import type { SelectOption } from "@opentui/core"
import { useState } from "react"
function App() {
const [focused, setFocused] = useState<0 | 1 | 2 | 3>(0)
useKeyboard((key) => {
if (key.name === "left") {
if (focused === 0) {
// none
} else if (focused === 1) {
setFocused(0)
} else if (focused === 2) {
setFocused(1)
} else if (focused === 3) {
setFocused(2)
}
} else if (key.name === "right") {
if (focused === 0) {
setFocused(1)
} else if (focused === 1) {
setFocused(2)
} else if (focused === 2) {
setFocused(3)
} else if (focused === 3) {
// none
}
}
})
const options: SelectOption[] = [
{ name: "Option 1", description: "Option 1 description", value: "opt1" },
{ name: "Option 2", description: "Option 2 description", value: "opt2" },
{ name: "Option 3", description: "Option 3 description", value: "opt3" },
]
return (
<box style={{ flexDirection: 'row', width: '100%' }}>
<box style={{ border: true, height: '100%', width: '25%' }}>
<select
style={{ height: '100%', width: '100%' }}
options={options}
focused={focused === 0}
/>
</box>
<box style={{ border: true, height: '100%', width: '25%' }}>
<select
style={{ height: '100%', width: '100%' }}
options={options}
focused={focused === 1}
/>
</box>
<box style={{ border: true, height: '100%', width: '25%' }}>
<select
style={{ height: '100%', width: '100%' }}
options={options}
focused={focused === 2}
/>
</box>
<box style={{ border: true, height: '100%', width: '25%' }}>
<select
style={{ height: '100%', width: '100%' }}
options={options}
focused={focused === 3}
/>
</box>
</box>
)
}
render(<App />)
I am trying to make a kanban board I only want one option that looks currently selected (at most) because is where the "cursor" is located. I hope that makes some sense.
Yeah that makes sense.
A bit more research:
The behavior that Textual does by default: when a <select> has a selected option, and the <select> becomes unfocused, the color of the selected option changes.
Demo:
@pizzaisdavid this can also be solved as a consumer by setting the selectedTextColor, selectedBackgroundColor and selectedDescriptionColor properties.
Example 👇
import type { SelectOption, SelectRenderableOptions } from "@opentui/core"
import { render, useKeyboard } from "@opentui/react"
import { useState } from "react"
function App() {
const [focused, setFocused] = useState<"left" | "right">("left")
useKeyboard((key) => {
if (key.name === "right" || key.name === "left") {
setFocused((prev) => (prev === "left" ? "right" : "left"))
}
})
const options: SelectOption[] = [
{ name: "Option 1", description: "Description #1", value: "opt_1" },
{ name: "Option 2", description: "Description #2", value: "opt_2" },
{ name: "Option 3", description: "Description #3", value: "opt_3" },
]
const focusedStyle = {
selectedBackgroundColor: "#334455",
selectedTextColor: "#FFFF00",
selectedDescriptionColor: "#CCCCCC",
} satisfies SelectRenderableOptions
const unfocusedStyle = {
selectedBackgroundColor: "gray",
selectedTextColor: "white",
selectedDescriptionColor: "white",
} satisfies SelectRenderableOptions
return (
<box style={{ flexDirection: "row", width: "100%" }}>
<box style={{ border: true, flexGrow: 1 }}>
<select
style={{
height: "100%",
width: "100%",
...(focused !== "left" ? unfocusedStyle : focusedStyle),
}}
options={options}
focused={focused === "left"}
/>
</box>
<box style={{ border: true, flexGrow: 1 }}>
<select
style={{
height: "100%",
width: "100%",
...(focused !== "right" ? unfocusedStyle : focusedStyle),
}}
options={options}
focused={focused === "right"}
/>
</box>
</box>
)
}
render(<App />)
Can I take it?
import type { SelectOption } from "@opentui/core"
import { useState } from "react"
function App() {
const [focused, setFocused] = useState<0 | 1 | 2 | 3>(0)
useKeyboard((key) => {
if (key.name === "left") {
if (focused === 0) {
// none
} else if (focused === 1) {
setFocused(0)
} else if (focused === 2) {
setFocused(1)
} else if (focused === 3) {
setFocused(2)
}
} else if (key.name === "right") {
if (focused === 0) {
setFocused(1)
} else if (focused === 1) {
setFocused(2)
} else if (focused === 2) {
setFocused(3)
} else if (focused === 3) {
// none
}
}
})
const options: SelectOption[] = [
{ name: "Option 1", description: "Option 1 description", value: "opt1" },
{ name: "Option 2", description: "Option 2 description", value: "opt2" },
{ name: "Option 3", description: "Option 3 description", value: "opt3" },
]
return (
<box style={{ flexDirection: "row", width: "100%" }}>
<box style={{ border: true, height: "100%", width: "25%" }}>
<select
style={{ height: "100%", width: "100%" }}
options={options}
focused={focused === 0}
selectedIndex={focused !== 0 ? -1 : 0}
/>
</box>
<box style={{ border: true, height: "100%", width: "25%" }}>
<select
style={{ height: "100%", width: "100%" }}
options={options}
focused={focused === 1}
selectedIndex={focused !== 1 ? -1 : 0}
/>
</box>
<box style={{ border: true, height: "100%", width: "25%" }}>
<select
style={{ height: "100%", width: "100%" }}
options={options}
focused={focused === 2}
selectedIndex={focused !== 2 ? -1 : 0}
/>
</box>
<box style={{ border: true, height: "100%", width: "25%" }}>
<select
style={{ height: "100%", width: "100%" }}
options={options}
focused={focused === 3}
selectedIndex={focused !== 3 ? -1: 0}
/>
</box>
</box>
);
}
render(<App />);