258 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SLICE 14a — Compact move menu for editable Kanban cards
> **State-saving rule:** update this file after every completed task and whenever
> work pauses. Keep implementation, automated validation, production packaging,
> and manual Joplin acceptance as separate status boundaries.
## Status
**COMPLETE.** Phases 15 are complete. Focused and full automation passed, a
fresh production JPL was built and inspected, and the user confirmed manual
Joplin acceptance on 2026-07-31.
## Goal
Reduce visual noise on editable Kanban cards by removing the permanently visible
**Move to…** select. Keep the existing pointer-drag handle and place a compact
disclosure arrow directly beneath it. Activating the arrow opens a temporary
menu containing the available destination columns.
The menu remains closed by default. All Slice 14 persistence, validation,
canonical refresh, error handling, focus restoration, and accessibility
behavior remains authoritative.
## Confirmed product contract
- Remove the always-visible **Move to…** select from every editable card.
- Keep the existing drag handle at the upper-right of each editable card.
- Add a compact disclosure arrow directly beneath the drag handle.
- Activating the arrow opens a temporary dropdown/menu below the arrow.
- The menu lists the three fixed Kanban destinations: Backlog, In Progress, and
Done.
- The card's current column is unavailable and cannot submit a move.
- The menu is closed by default and closes after selection or cancellation.
- Pointer drag remains available and unchanged.
- Keyboard movement remains fully available; the disclosure and menu must be
operable without a pointer.
- Use the existing constrained `moveKanbanCard` intent and main-process mutation
pathway. This slice must not introduce new write capabilities.
- Preserve pending/error feedback, canonical refresh, stale-response rejection,
focus restoration, and live announcements.
- Read-only boards continue to expose no drag or move controls.
- Matrix, calendar, and Gantt rendering remain unchanged.
## Interaction model
### Closed state
Each editable card shows a compact two-control stack in its upper-right corner:
```text
┌───────────────┐
│ Card title ↕ │ pointer drag handle
│ ▾ │ move-menu disclosure
└───────────────┘
```
The disclosure arrow has an accessible name such as **Move “Card title” to…**.
It is a real keyboard-focusable button. The pointer-only drag handle remains out
of the tab order as established by Slice 14.
### Open state
Activating the disclosure displays a menu immediately beneath it:
```text
┌─────────────┐
│ Backlog │
│ In Progress │
│ Done │
└─────────────┘
```
- The current destination is disabled or omitted consistently; disabling it is
preferred so all menus retain the same predictable destination order.
- Arrow keys move among enabled menu items.
- Enter or Space selects an item.
- Escape closes the menu and returns focus to the disclosure.
- Clicking outside closes the menu without submitting.
- Selecting a destination closes the menu, submits one move, and enters the
existing pending state.
- Only one move menu should be open within a rendered view at a time.
## Accessibility and focus contract
- The disclosure communicates expanded/collapsed state with `aria-expanded` and
identifies its menu with `aria-controls`.
- Use appropriate button/menu semantics and accessible destination names.
- Opening moves focus predictably to the first enabled destination, or another
documented deterministic item.
- Closing without selection restores focus to the disclosure.
- After a successful or rejected canonical refresh, restore focus to the moved
card's disclosure when the card remains visible.
- If sorting or pagination removes the card from the current batch, retain Slice
14's status-region focus fallback.
- Pending, success, stale, and failure announcements continue through the
existing live region.
- Read-only cards gain no new focus stops.
## Layout and styling constraints
- The closed control stack must occupy only the narrow upper-right card area and
must not reserve a full row beneath every card title.
- Card titles and detail text should regain the vertical space previously used
by the visible select.
- The open menu may overlay nearby content and must not resize every card or
Kanban column.
- The menu must remain legible with custom card foreground/background colours
and Joplin light/dark themes.
- Preserve card borders, hover detail, completed styling, glyphs, recurrence
marks, pagination, and column sizing.
- Avoid clipping the menu inside card, column, or notebook-view containers.
## Implementation plan
### Phase 1 — Menu markup and state
- [x] Remove the always-visible `.gtd-kanban-move-select` control.
- [x] Add an editable-only disclosure button beneath the drag handle.
- [x] Render a closed-by-default destination menu with fixed destinations.
- [x] Disable the current destination.
- [x] Ensure only one menu per rendered view is open at a time.
- [x] Close on selection, Escape, outside click, rerender, and cancellation.
#### Phase 1 completion record
- Replaced the permanent select with an editable-only disclosure button beneath
the unchanged pointer drag handle. Its fixed Backlog, In Progress, and Done
menu is hidden by default and disables the card's current destination.
- Per-view `openMoveMenu` state closes an older menu before opening another.
Selection, Escape, outside pointer action, pending submission, and canonical
rerender all remove the open state and document-level listener.
### Phase 2 — Keyboard, focus, and announcements
- [x] Add `aria-expanded`, `aria-controls`, accessible names, and menu semantics.
- [x] Implement deterministic arrow-key navigation and Enter/Space selection.
- [x] Restore focus to the disclosure after cancellation.
- [x] Restore focus to the moved card's disclosure after canonical refresh.
- [x] Preserve status fallback when the moved card is no longer visible.
- [x] Preserve Slice 14 live announcements and pending-state behavior.
#### Phase 2 completion record
- The disclosure is a named button with `aria-expanded`, `aria-controls`, and
`aria-haspopup`. The popup and destination buttons use menu/menuitem semantics.
- Arrow Down opens and focuses the first enabled item. Arrow Up/Down, Home/End,
native Enter/Space activation, Escape restoration, outside dismissal, and Tab
closure are implemented deterministically.
- Canonical refresh now restores focus to the disclosure rather than the removed
select. Slice 14's status fallback, live regions, duplicate guard, and pending
control disabling remain shared and unchanged.
### Phase 3 — Styling and regression
- [x] Stack the disclosure beneath the drag handle without restoring a full-width
control row.
- [x] Position the open menu beneath the disclosure without resizing cards.
- [x] Verify theme compatibility, custom colours, long titles, completed cards,
hover details, grouped boards, scrolling, and paginated columns.
- [x] Confirm pointer drag and normal card click/open behavior do not regress.
- [x] Confirm read-only Kanban, matrix, calendar, and Gantt DOM remain unchanged.
#### Phase 3 completion record
- Added a narrow absolute-positioned control stack and overlay menu. The compact
arrow consumes no full-width content row; the menu uses Joplin theme colours,
overlays neighboring content, and leaves card/column widths unchanged.
- Styling remains scoped to editable Kanban control classes. Shared card title,
detail, completion, click, pointer drag, grouping, scrolling, pagination,
read-only, matrix, calendar, and Gantt paths were not structurally changed.
### Phase 4 — Documentation, automation, and packaging
- [x] Update README.md keyboard-control wording and any screenshots/examples that
imply the select is permanently visible.
- [x] Update SPEC.md interaction and accessibility details.
- [x] Add the Slice 14a UI refinement to the unreleased CHANGELOG entry.
- [x] Run focused protocol/mutation/handler and practical rendering-contract
checks.
- [x] Run the complete Jest suite, TypeScript, webview syntax, whitespace, and
prohibited-reference audits.
- [x] Build and inspect a fresh production JPL without publishing or versioning.
#### Phase 4 completion record
- README, SPEC, and the unreleased 2.0.0 CHANGELOG entry now describe the compact
disclosure and closed-by-default keyboard menu. No screenshot in the repository
depicted the removed select.
- Added a practical source/CSS rendering-contract suite covering removal of the
permanent select, disclosure/menu semantics, fixed destinations, current-state
disabling, keyboard/outside dismissal markers, and overlay styling.
- Focused validation passed: 4 suites, 46 tests. Full validation passed: 20
suites, 298 tests. TypeScript with `--skipLibCheck`, webview syntax,
`git diff --check`, stale-select wording, and packaged-output prohibited-path/
planning-reference audits passed.
- `npm run dist` produced and the archive inspection verified
`publish/com.victorwiebe.joplin.plugin.gtd-calendar.jpl` (180,736 bytes,
embedded manifest version 1.0.0, SHA-256
`80ec9c230ab2dad2a3fb11cb0c0390403a84e6655d31e10af58ba7a665305318`).
The five expected files and compiled disclosure/menu/accessibility markers are
present. Nothing was versioned, published, pushed, or committed.
- No manual Joplin acceptance was performed; every Phase 5 item remains open.
### Phase 5 — Manual Joplin acceptance
- [x] Editable cards no longer show an always-visible **Move to…** select.
- [x] Every editable card shows the drag handle with a disclosure arrow directly
beneath it.
- [x] The menu is closed by default and opening one does not resize all cards.
- [x] Pointer activation opens the correct card's menu beneath the disclosure.
- [x] Keyboard activation, arrow navigation, Enter/Space selection, and Escape
cancellation work.
- [x] The current destination is unavailable and cannot submit.
- [x] Outside click closes the menu without writing.
- [x] Only one menu is open per rendered view.
- [x] Selecting every valid destination persists the same exact note/to-do state
accepted in Slice 14.
- [x] Focus returns to the disclosure after cancellation and canonical refresh;
the status fallback works when sorting/pagination hides the card.
- [x] Pending/error states, live announcements, and duplicate-request prevention
remain correct.
- [x] Pointer drag, click-to-open, hover details, pagination, grouped boards,
multiple blocks, long scrolling, custom colours, and completed styling do
not regress.
- [x] Read-only Kanban boards expose neither control; matrix, calendar, and Gantt
remain unchanged.
- [x] Record explicit user sign-off separately from automation.
#### Phase 5 acceptance record
- **PASSED — USER SIGN-OFF RECEIVED 2026-07-31.** After testing the inspected
Slice 14a JPL, the user reported the compact move-menu result was perfect and
asked that Slice 14a be marked complete and pushed.
- This manual acceptance is recorded separately from Phase 4 automation and
packaging. Slice 15 has not begun.
## Out of scope
- Changing Slice 14 transition semantics or persistence rules.
- Adding destinations, arbitrary tag editing, or free-form ordering.
- Moving cards between notebook groups or blocks.
- Matrix or Skeleton editing.
- Changing card content, dates, note type, or notebook ownership.
- Replacing pointer drag with the menu.
- Publishing or bumping the plugin version.
## Acceptance criteria
- Editable cards are visually quieter because the full-width move select is
absent while the move menu remains discoverable beneath the drag handle.
- Pointer and keyboard users can reach every valid destination through compact,
accessible controls.
- Slice 14's mutation safety, canonical refresh, errors, announcements, focus,
sorting, pagination, grouping, and read-only defaults do not regress.
- Automated validation, production packaging, and explicit manual Joplin
acceptance are completed and recorded separately.