258 lines
12 KiB
Markdown
258 lines
12 KiB
Markdown
# 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 1–5 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.
|