Skip to content

Implement Improved Card UX#385

Merged
PauloMFJ merged 7 commits into
datacommonsorg:mainfrom
madebypxlp:paulo/card-selection
Jul 2, 2026
Merged

Implement Improved Card UX#385
PauloMFJ merged 7 commits into
datacommonsorg:mainfrom
madebypxlp:paulo/card-selection

Conversation

@PauloMFJ

@PauloMFJ PauloMFJ commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Overview

Card auto-height

  • New useCardAutoHeight hook — syncs a card shape's h to its rendered content height (via ResizeObserver + scrollHeight), capped at the variant max, with epsilon guards to avoid feedback loops and ignoring culled / off-screen measurements. Writes are history-ignored so they don't pollute the undo stack.
  • Renamed CARD_VARIANT_SIZECARD_VARIANT_MAX; h now means maximum height rather than fixed. Cards start at the max footprint on placement, then shrink to real content height.
  • Geometry/hit-area now tracks content, so clicking empty space below a short card no longer selects it.

Card drag handle

  • New useCardDragHandle hook — makes the actions bar a drag handle, since it sits outside the shape's geometry and tldraw can't drag it natively. Translates the shape by pointer delta (screen→page via zoom) using pointer capture.
  • Actions bar gets cursor: grab/grabbing and is wired up via the new onActionsPointerDown prop.

Selection & text behavior

  • Renamed children-containercontent-container; content is now a selectable text surface (cursor: auto, user-select: text in single-selection mode) instead of a drag handle.
  • In single selection, content pointerdown stops propagation so the canvas doesn't start a gesture; unselected/multi-selected events pass through to tldraw.
  • New reactor clears any highlighted text when a card loses single-selection focus.
  • Removed the "View chart" button from the multi-select toolbar (was a not-yet-supported placeholder toast).

Sizing / spacing / styling

  • Bumped DISTANCE_FROM_OTHER_CARDS 40 → 56. This was done to account for initial placement of cards relative to grid and fact that actions bar now moves above card. The bar is 48 pixels tall so this ensures it doesn't get cropped before user moves canvas.
  • Reworked card selection UI. Now actions moves up without moving card content down + sped up animation from (0.5s → 0.3s).
  • Fix missing home prompt background --color-query-surface--color-query-surface-raised.

Refactor

  • Moved use_streaming_query.ts out of the hooks/ subfolder into the atlas/ scope root. As part of this change dropped hooks folder.

@PauloMFJ PauloMFJ self-assigned this Jun 30, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces dynamic auto-height adjustments and custom drag handles for card shapes on the canvas, improving the user experience when interacting with and moving cards. The feedback highlights several critical improvements: handling the lostpointercapture event and marking history stopping points in the drag handler to prevent stuck states, utilizing requestAnimationFrame in the auto-height hook to avoid layout thrashing and ResizeObserver loop errors, and scoping the text selection clearing logic to the specific card container to prevent global selection issues.

Comment thread dataweaver/apps/web/src/components/scopes/atlas/shapes/card.tsx Outdated
@PauloMFJ PauloMFJ force-pushed the paulo/card-selection branch from bc64872 to 1735a8e Compare July 1, 2026 10:22

@nick-nlb nick-nlb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you Paulo!

The primary comments I put in here actually relate more to the previous PR. You could either do them here or roll them out to the tracker and do them separately.

I've also added a couple of other items to the tracker that relate to these changes that you could do either here or separately.


export const QueryProvider = ({ children }: QueryProviderProps) => {
const { editor } = useAtlas();
const selectedShapeIds = editor ? editor.getSelectedShapeIds() : [];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't part of this PR, but I noticed this as I was testing:

If you select a card (putting the chip into the prompt box) and then submit a new query, the submitted query is one card selection behind.

I.e. Run query -> Select card A -> Run query [as if no card is selected] -> Select card A & B -> Run query [As if only card A is selected] etc.

The reason may be that this call to get the selectedShapeIds isn't "reactive" - i.e. selectedShapeIds() doesn't trigger here when a new item is selected, meaning that the dependency below isn't triggered either. If that's the case, we could fix this by removing this selectedShapesId here, and move it to inside runPrompt().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed here! #390 Good spot

Comment thread dataweaver/apps/web/src/components/scopes/atlas/query_provider.tsx

// tldraw forces 'user-select: none' on all nested nodes. This ensures we
// allow selecting text when in single selection mode
:is([data-selection="single"]) & * {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a heavy hammer, as it cascades down into every node (including buttons). Once we have follow up cards, etc appearing in the card, we may have to make this more selective.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree unfortunately tldraw adds:

.tl-container * {
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    scrollbar-highlight-color: transparent;
    -webkit-user-select: none;
    user-select: none;
    box-sizing: border-box;
    outline: none;
}

So we're pretty much fighting this to ensure we can select text :/

@PauloMFJ PauloMFJ merged commit cdb5bf6 into datacommonsorg:main Jul 2, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants