# ccf-gpui-widgets
Reusable GPUI widgets for building desktop applications.
## Features
- **Themeable**: All widgets support custom themes via global context or per-widget override
- **Accessible**: Keyboard navigation support where applicable
- **Event-driven**: All widgets emit events for state changes
- **Builder pattern**: Fluent API for widget configuration
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
ccf-gpui-widgets = "0.1"
# For file/directory pickers (adds rfd and dirs dependencies)
# ccf-gpui-widgets = { version = "0.1", features = ["file-picker"] }
```
## Quick Start
```rust
use gpui::*;
use ccf_gpui_widgets::{Theme, widgets::*};
register_all_keybindings(cx);
// Optionally set a global theme
cx.set_global(Theme::dark());
cx.open_window(WindowOptions::default(), |_window, cx| {
cx.new(|cx| MyView::new(cx))
}).unwrap();
cx.activate(true);
});
```
## Available Widgets
### Input Widgets
| `TextInput` | Full-featured text input with cursor, selection, clipboard |
| `PasswordInput` | Text input with visibility toggle |
| `NumberStepper` | Numeric input with +/- buttons |
| `Slider` | Horizontal slider for numeric ranges |
### Selection Widgets
| `Checkbox` | Simple checkbox with optional label |
| `ToggleSwitch` | On/off toggle with configurable label position |
| `Dropdown` | Select/dropdown with keyboard navigation |
| `RadioGroup` | Single-selection from multiple choices |
| `CheckboxGroup` | Multi-selection from multiple choices |
| `ColorSwatch` | Color picker with hex input, HSV canvas |
### Display Widgets
| `Tooltip` | Hover tooltip |
| `ProgressBar` | Progress indicator (determinate/indeterminate) |
| `Spinner` | Loading spinner in multiple sizes |
### Layout & Navigation
| `Collapsible` | Expandable/collapsible section |
| `TabBar` | Tab navigation with keyboard support |
| `ConfirmationDialog` | Modal dialogs (Info/Default/Warning/Danger styles) |
### Repeatable Widgets
| `RepeatableTextInput` | Text input with add/remove for lists |
### File Widgets (requires `file-picker` feature)
| `FilePicker` | File selection with native dialog |
| `DirectoryPicker` | Directory selection with native dialog |
| `RepeatableFilePicker` | File picker with add/remove for lists |
| `RepeatableDirectoryPicker` | Directory picker with add/remove for lists |
### Utilities
| `primary_button()` | Blue/accent styled button |
| `secondary_button()` | Gray styled button |
| `danger_button()` | Red styled button |
| `with_focus_actions()` | Add Tab/Shift-Tab focus navigation to elements |
## Theming
Widgets use a `Theme` struct for colors. You can:
1. Set a global theme: `cx.set_global(Theme::dark())`
2. Use per-widget themes: `TextInput::new(cx).theme(my_theme)`
3. Use the default (dark theme) if nothing is set
```rust
use ccf_gpui_widgets::Theme;
// Built-in themes
let dark = Theme::dark();
let light = Theme::light();
// Customize with builder methods
let custom = Theme::dark()
.with_accent(0x00ff00)
.with_primary(0xff0000);
```
## Widget Usage Examples
### TextInput
```rust
.placeholder("Enter text...")
.select_on_focus(true)
});
```rust
.choices(vec!["Option 1".into(), "Option 2".into()])
.with_selected_index(0)
});
```rust
.with_value("#3b82f6") // Initial color (hex or CSS name like "coral")
.with_alpha(true) // Enable alpha channel
});
```rust
.with_on(true)
.label("Dark mode")
.label_position(LabelPosition::Left)
});
```rust
.style(DialogStyle::Warning)
.title("Delete Item")
.message("Are you sure you want to delete this item? This action cannot be undone.")
.primary_label("Delete")
.secondary_label("Cancel")
});
Some widgets require keybindings to be registered at startup. Call `register_all_keybindings(cx)` once during app initialization:
```rust
// ...
});
```
Or register individual widgets:
```rust
ccf_gpui_widgets::widgets::text_input::register_keybindings(cx);
ccf_gpui_widgets::widgets::dropdown::register_keybindings(cx);
```
## License
MIT OR Apache-2.0