Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions skills/leaf/assets/runtime/keyboard/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
an edge of the list; from a beside-panel, `g p` returns focus to the page while keeping
the panel open. Uppercase mnemonics remain named
global destinations: `g T` Threads, `g A` Asks, `g L` All leaves, `g M` the searchable
Page map, `g V` Versions, and `g D` the unsent draft the composer put away. Completing
one exchanges the transient sequence for a return
frame which restores the standing and workspace captured before `g` armed.
Page map, `g V` Versions, and `g D` the unsent draft the composer put away. A named
panel address toggles that panel, matching its visible control. Completing one that
opens a surface exchanges the transient sequence for a return frame which restores the
standing and workspace captured before `g` armed; completing it again closes the
surface without adding a frame.

`BUILTIN_DIRECT_DESTINATIONS` declares the uppercase destinations this owner implements;
another owner contributes a complete row through `directDestinations`. `TARGET_KINDS`
Expand Down Expand Up @@ -218,15 +220,17 @@ export function createAddress({
}
}

// One-off direct travel is one vocabulary too. The mnemonic completes the trip, and
// every destination owns the liveness and landing that make its surface useful rather
// than leaving the dispatcher to know which furniture it enters.
// One-off direct travel is one vocabulary too. The mnemonic completes the trip or closes
// the named panel already standing, and every destination owns the liveness, landing, and
// close that make its surface useful rather than leaving the dispatcher to know which
// furniture it enters.
const BUILTIN_DIRECT_DESTINATIONS = [
{
id: "navigation.panel.threads",
key: "Shift+t",
does: "Go to the Threads panel",
line: "Threads panel",
does: () =>
panelIsOpen() ? "Close the Threads panel" : "Go to the Threads panel",
line: () => (panelIsOpen() ? "close Threads panel" : "Threads panel"),
control: () => toggleBtn,
when: () => true,
go: () => {
Expand All @@ -238,32 +242,43 @@ export function createAddress({
}
},
active: (...args) => panelIsOpen(...args),
close: () => setPanel(false),
toggle: true,
},
{
id: "navigation.panel.asks",
key: "Shift+a",
does: "Go to the Asks panel",
line: "Asks panel",
does: () =>
currentTray() === "asks" ? "Close the Asks panel" : "Go to the Asks panel",
line: () => (currentTray() === "asks" ? "close Asks panel" : "Asks panel"),
control: () => asksBtn,
when: (...args) => asksOffered(...args),
go: () => {
showTray("asks");
(askRows()[0] ?? asksPanel).focus({ preventScroll: true });
},
active: () => currentTray() === "asks",
close: () => showTray(null),
toggle: true,
},
{
id: "navigation.panel.leaves",
key: "Shift+l",
does: "Go to the All leaves panel",
line: "All leaves panel",
does: () =>
currentTray() === "leaves"
? "Close the All leaves panel"
: "Go to the All leaves panel",
line: () =>
currentTray() === "leaves" ? "close All leaves panel" : "All leaves panel",
control: () => othersBtn,
when: (...args) => leavesOffered(...args),
go: () => {
showTray("leaves");
(othersLinks()[0] ?? othersPanel).focus({ preventScroll: true });
},
active: () => currentTray() === "leaves",
close: () => showTray(null),
toggle: true,
},
{
id: "navigation.page-map",
Expand Down Expand Up @@ -860,13 +875,15 @@ export function createAddress({
destination.close?.();
return restoreWorkspace(workspace);
},
does: `Return from ${destination.line}`,
does: `Return from ${word(destination.line)}`,
line: "back",
};
},
run: () => {
const closing = destination.toggle && destination.active();
setSequence(false);
destination.go();
if (closing) destination.close();
else destination.go();
},
})),
// A destination whose control belongs to another runtime owner joins this one
Expand Down
41 changes: 38 additions & 3 deletions tests/test_render_navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4112,8 +4112,10 @@ def test_clamped_leaf_lists_share_the_walk_position(browser, serve, live_leaf):
page.close()


def test_a_g_panel_destination_survives_a_completed_asks_tray(browser, serve):
"""An open panel remains reachable after working its last row completes it."""
def test_a_completed_asks_tray_stays_reachable_through_its_toggle_address(
browser, serve
):
"""An answered tray can close and reopen through its panel address."""
page, errors = open_page(
browser,
serve(
Expand Down Expand Up @@ -4141,7 +4143,11 @@ def test_a_g_panel_destination_survives_a_completed_asks_tray(browser, serve):
expect(page.locator(".lf-asks-panel")).to_have_class(re.compile(r"\bopen\b"))

page.keyboard.press("g")
expect(page.locator(".lf-shortcut-bar")).to_contain_text("Asks panel")
expect(page.locator(".lf-shortcut-bar")).to_contain_text("close Asks panel")
page.keyboard.press("Shift+a")
expect(page.locator(".lf-asks-panel")).to_be_hidden()

page.keyboard.press("g")
page.keyboard.press("Shift+a")
expect(page.locator(".lf-asks-row")).to_be_focused()
assert errors == []
Expand Down Expand Up @@ -5308,6 +5314,35 @@ def test_the_arrows_say_which_way_the_section_under_the_reader_goes(browser, ser
page.close()


def test_named_workspace_chords_toggle_their_panels(browser, serve, live_leaf):
"""Repeating a panel's complete address closes the panel it opened."""
live_leaf("second", "A second leaf")
page, errors = open_page(browser, serve(ASKS_PAGE, comments=1))

for key, command, name, surface, control in (
("Shift+t", "threads", "Threads", ".lf-panel", ".lf-threads-toggle"),
("Shift+a", "asks", "Asks", ".lf-asks-panel", ".lf-asks"),
("Shift+l", "leaves", "All leaves", ".lf-others-panel", ".lf-others"),
):
page.keyboard.press("g")
page.keyboard.press(key)
expect(page.locator(surface)).to_be_visible()

page.keyboard.press("g")
expect(page.locator("body")).to_have_attribute("data-lf-goto", "")
close_hint = page.locator(
f'.lf-shortcut-bar .lf-key[data-lf-commands~="navigation.panel.{command}"]'
)
expect(close_hint).to_be_visible()
expect(close_hint).to_contain_text(f"close {name} panel")
page.keyboard.press(key)
expect(page.locator(surface)).to_be_hidden()
expect(page.locator(control)).to_have_attribute("aria-expanded", "false")

assert errors == []
page.close()


def test_the_key_line_says_what_a_press_will_do(browser, serve):
"""The shortcut bar and dispatcher read one return frame for each keyboard entry."""
url = serve(NOTED_PAGE)
Expand Down
74 changes: 37 additions & 37 deletions worker/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
"smol-toml": "1.5.2",
"typescript": "^7.0.2",
"vitest": "^5.0.0",
"wrangler": "^4.129.0"
"wrangler": "^4.130.0"
}
}
Loading