keyboard-operable ClideTappable + palette nav (T-100)
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m5s
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m5s
Plug widgets into the keymap layer landed in T-117.
ClideTappable:
- Wrap in `Actions(ActivateIntent → onTap)` outside a `Focus` so
dispatch from the focused context walks up and hits the action.
- Add a focus ring via `tokens.globalFocus` (DecoratedBox foreground
overlay, transparent border when unfocused, no layout shift).
- Disabled (`onTap == null`) skips focus traversal and shows the
forbidden cursor.
ClidePalette:
- Register Actions for the four palette intents
(selectNext / selectPrev / accept / dismiss).
- Publish `palette.open` scope flag via `KeymapService.setScopeFlag`
so when-clauses can scope future bindings to "palette only".
- Highlight the selected row with `listItemSelectedBackground`;
scroll it into view on nav.
- `PaletteController` grows `selectedIndex` + `selectNext` /
`selectPrevious` / `acceptSelected`; index resets on open /
filter change.
Intents.dart drops the `ClideIntent` base — `ActivateIntent` and
`DismissIntent` come from Flutter; clide owns the palette and text-
scale and command-bridge subclasses. `parseIntentId('activate')` →
Flutter's class; same for dismiss. Widget code uses the canonical
Flutter Intent types where they fit.
App root grows a PaletteOpenIntent action that calls
`services.palette.open()`, completing the ctrl/cmd+shift+p path
end-to-end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,13 +9,26 @@ class PaletteController extends ChangeNotifier {
|
||||
|
||||
bool _open = false;
|
||||
String _filter = '';
|
||||
int _selectedIndex = 0;
|
||||
|
||||
bool get isOpen => _open;
|
||||
String get filter => _filter;
|
||||
|
||||
/// Index of the highlighted entry inside the currently-filtered
|
||||
/// list. Clamped to `[0, filtered().length - 1]` on read. Returns 0
|
||||
/// when the filter excludes everything.
|
||||
int get selectedIndex {
|
||||
final n = filtered().length;
|
||||
if (n == 0) return 0;
|
||||
if (_selectedIndex < 0) return 0;
|
||||
if (_selectedIndex >= n) return n - 1;
|
||||
return _selectedIndex;
|
||||
}
|
||||
|
||||
void open() {
|
||||
if (_open) return;
|
||||
_open = true;
|
||||
_selectedIndex = 0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -23,6 +36,7 @@ class PaletteController extends ChangeNotifier {
|
||||
if (!_open) return;
|
||||
_open = false;
|
||||
_filter = '';
|
||||
_selectedIndex = 0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -31,9 +45,35 @@ class PaletteController extends ChangeNotifier {
|
||||
void setFilter(String f) {
|
||||
if (_filter == f) return;
|
||||
_filter = f;
|
||||
_selectedIndex = 0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Highlight the next entry, wrapping at the end. No-op when the
|
||||
/// filtered list has fewer than 2 entries.
|
||||
void selectNext() {
|
||||
final n = filtered().length;
|
||||
if (n < 2) return;
|
||||
_selectedIndex = (selectedIndex + 1) % n;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Highlight the previous entry, wrapping at the start.
|
||||
void selectPrevious() {
|
||||
final n = filtered().length;
|
||||
if (n < 2) return;
|
||||
_selectedIndex = (selectedIndex - 1 + n) % n;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Invoke whatever's currently highlighted; no-op when the filter
|
||||
/// excludes everything.
|
||||
Future<void> acceptSelected() async {
|
||||
final list = filtered();
|
||||
if (list.isEmpty) return;
|
||||
await invoke(list[selectedIndex].command);
|
||||
}
|
||||
|
||||
List<CommandContribution> filtered() {
|
||||
if (_filter.isEmpty) return _registry.all.toList();
|
||||
final q = _filter.toLowerCase();
|
||||
|
||||
Reference in New Issue
Block a user