githubnext/chopinPublic

Let's compose rich plans together

Disclose table rails per track, with grips and seam inserts #359

MergedMaggieAppletonmerged 4 commits intomainfromrefs/pull/359/head
  1. MA

    ## Why Table rails showed every row and column as soon as any cell was hovered. Their controls were cramped, and row tooltips covered nearby actions.

    ## What changed - Show the grip for the pointed track, with faint grips while the caret is in the table. Rails fade in and respect reduced motion. - Reveal insert controls at the aimed seam with a line across the table. Give remove and align controls larger, borderless targets. - Keep the rails clipped to the document scroller and their container pointer-transparent outside active controls. - Move row tooltips to the left, retain keyboard shortcuts and the existing phone toolbar. - Renew the reviewed design hash after checking the integrated rail source.

    ## Verification 49 focused table tests, `bun run types`, `bun run ci`, and `bun run build` pass on the restacked branch. GitHub's browser suite will check the two new rail scenarios on the final published head.

    ## Known follow-up Tab and Shift+Tab do not yet leave the editor, so the rail grips are reached by screen reader or programmatic focus. Their existing keyboard move shortcuts work once focused.

    ## Visuals ![Table rail before](https://github.com/user-attachments/assets/3dea78e7-351a-4740-9e0c-136bb09f5ae1)

    ![Table rail after](https://github.com/user-attachments/assets/350cc9ec-7fe6-479c-9638-c42aabb86823)

    ![Insert seam](https://github.com/user-attachments/assets/b7625096-098a-4c49-9a28-345574603978)

  2. MA
    Author

    **Review:** Changes needed

    Checked in a real browser (1440x900, 390x844 touch and narrow, reduced motion) against a seeded document: 3-column table, 20-column table, 100-row table, tables right under a paragraph.

    **Blocking**

    1. `packages/editor/src/table/rails.tsx:61-63` (`GRIP` 12 + `TOOL` 24 = `DEPTH` 36, up from 28). The column rail is a 36px-tall opaque hit area directly above the table (measured: rail y 359-395, table y 395). When the table has the caret, or the pointer is over it, `DIV.plan-rail` is the `elementFromPoint` winner over the paragraph above. With the caret in a cell, I could click the first line of the paragraph above but not its last line (rail covered it at y 363-371, and `click` landed nowhere, selection did not move into the paragraph). The paragraph above a table is the most common thing to click next. The 8px increase makes it worse than main. Suggest keeping the tool lane out of the hit area until a track is hot: make `.plan-rail` itself `pointer-events: none` and give only the grips and the hot track's tool buttons `pointer-events: auto`. If that conflicts with the `pointerleave` flicker note in `styles.css`, shrink the column rail's overlap to the grip lane (12px) and put the column tool buttons inside the table's top edge or in the grip lane.

    **Non-blocking**

    2. A table near the top of the pane: the column rail is `position: fixed` and not clipped to the scroller. With the table top at 8px below the pane top, the rail sits 28px above it, over the Document/Decisions tab bar. When the table scrolls partly under the top, its column grip floats in the app chrome above the pane (third frame of my top-of-pane capture) and overlaps the Decisions tab. Clip the rail to the scroller rect, or hide it when the table's top leaves the viewport. 3. `rails.tsx` ~line 580-615: Remove (x) shows only after the pointer is on that row's grip. With the pointer on the cell, nothing but the grip hints it. Fine and calm, but the `+` insert (seam) and the `x` of the next row end up stacked (24px boxes, ~13px apart, 5px overlap on 38px rows) with a destructive control directly under an insert. The z-index fix makes the x win, so a click aimed at the lower part of the + hits Remove. Consider more separation or putting Remove on the far side of the grip. 4. `rails.tsx` `over` handler calls `setPointed(...)` with a new object on every `pointerover`, so it re-renders on every element crossed within the same cell. Skip the update when row/column/table are unchanged, as `setCaretCell` does. 5. Tab order: Tab and Shift+Tab never leave the editor (the editor keeps focus), so the grips are reachable only via screen reader or programmatic focus. This is not new, and the Cmd/Ctrl+Arrow moves work once a grip has focus (rows, columns, and header-neighbour no-op all verified), but `aria-keyshortcuts` on something a keyboard user cannot reach is thin. Out of scope here, worth a follow-up. 6. Raw sizes in the grip dots (`8px`, `12px`, `4px`, `1px/1.25px`) and `padding: 2px`; fine as a drawn glyph but they will want a note in the design-contract review.

    **What works well**

    - Hover across rows, columns, and rails: 0 rail unmounts over ~80 pointer moves (no flicker), the track grip appears with a ~120ms rail fade. - Insert/remove row and column, keyboard move rows/columns, header row has no grip: all correct. - Limits: 20-column and 100-row tables show no insert buttons. The wide table still scrolls. - Seam insert with the brand line across the table, left-opening row tooltips, 24px targets: calm and Linear-like; the faint 0.35 grips while the caret is in the table keep things discoverable. - Reduced motion: `animation: none`, `transition-duration: 0s`. Touch phone: bottom toolbar, no rails, no overflow. Narrow desktop: 12px grips only. - Merged cells: cannot be created from MDX; not exercised.

    **CI**: only the design-contract review hashes fail (`rails.tsx` lines 496, 512, 598, 617, 644, 661, "reviewed dynamic owner changed"). Acceptable per the audit rules. e2e and container pass.

  3. MA
    Author

    Thanks. All five points are addressed on `design/table-rails`:

    1. **Blocker:** `.plan-rail` is now `pointer-events: none`. Only grips, shown remove and align buttons, and the two seams beside the pointed track (`data-plan-live`) take the pointer. The caret alone never makes a seam live. New e2e: `the paragraph above a table stays clickable while its rails show`. It puts the caret in a cell, clicks the paragraph's last line inside the rail's box, and checks that the selection lands in that paragraph. 2. Rails and the seam line are clipped with `clip-path` to the document scroller's top and bottom, so they no longer float over the tab bar. The clip is vertical only. A row rail sits in the gutter outside the scroller box, and a horizontal clip cut off its buttons (that caused the first CI e2e failure). 3. Remove hides while an insert on the same axis is aimed. Inserts come later in the rail, so wherever the two overlap the + wins, and a destructive control never sits under an add. 4. `setPointed` skips the update when the table, row and column are unchanged (same helper as `setCaretCell`). 5. Grip dots and padding now use `--spacing`. The gradient stops are percentages.

    Tab reachability is noted as a follow-up in the PR body. CI: e2e and container pass. The only failure is the `rails.tsx` design-contract hash; the new hash is in the PR body.

  4. MaggieAppletonhead-ref-force-pushed 77c27540bcd8last month on GitHub

  5. MaggieAppletonauto-rebase-enabledlast month on GitHub

  6. MaggieAppletonmerged 519d11681154last month on GitHub

  7. MaggieAppletonclosedlast month on GitHub

  8. MaggieAppletonhead-ref-deletedlast month on GitHub