-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: highlight editable cells on hover #1087
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing some issues here:
Screen.Recording.2024-11-19.at.1.48.13.PM.mov
- Shouldn't be any layout shifts on hover
- When the field is changed and then re-entered it's formatting is lost
Followup question: How do you plan on implementing the changed value highlight?
...{ | ||
[`.${editableOnRowHoverClass} .textFieldBaseWrapper`]: Css.pl1.mlPx(-8).br4.ba.bcTransparent.bgTransparent.$, | ||
[`.${editableOnRowHoverClass} .textFieldBaseWrapper > *`]: Css.bgTransparent.$, | ||
[`.${editableOnRowHoverClass}:hover .textFieldBaseWrapper`]: Css.bgBlue100.$, | ||
[`:hover:not(:has(.${editableOnRowHoverClass}:hover)) > .${editableOnRowHoverClass} .textFieldBaseWrapper, .${editableOnRowHoverClass}:hover .textFieldBaseWrapper`]: | ||
Css.ba.bc(style.rowEditableCellBorderColor ?? Palette.Blue300).$, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this is whats causing the weird focus change issue we talked about. Just leave a comment about it and the date fields
...{ | ||
[`.${editableOnRowHoverClass} .textFieldBaseWrapper`]: Css.pl1.mlPx(-8).br4.ba.bcTransparent.bgTransparent.$, | ||
[`.${editableOnRowHoverClass} .textFieldBaseWrapper > *`]: Css.bgTransparent.$, | ||
[`.${editableOnRowHoverClass}:hover .textFieldBaseWrapper`]: Css.bgBlue100.$, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0ces cc @apattersonATX-HB (sorry, I'm just getting to this PR) this is a ~fairly intrusive way to "reach into" the text field and muck with its internal state / styling / etc...
Like it gets the job done, but a maintainer of TextField
would have no idea this behavior is happening, and could unwittingly break it while updating/maintaining TextField
.
I would generally/greatly prefer some sort of "signal" from GridTable to TextField
to tell it "please style yourself (this way/that way)".
Granted, it would have to be a context, given we want to cross component boundaries / we're not passing props directly to TextField
.
My off-the-top-of-my-head suggestion would be to use PresentationContext
, which is already how GridTable will broadcast to child/cell components "btw you're in a table,k you should render slightly differently".
Can we add something like that, for this ask / hopefully in this PR (it seems like a quick thing to try/experiment with)? Like a ... PresentationContext.visuallyEditable
? That would kinda match the current visuallyDisabled
prop...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it looks like GridTable is already setting PresentationContext.borderless: true
, to tell components "hide your borders", and it seems like the real ask here is tweaking/adding a borderless: "until-hovered"
sort of thing ...
Or maybe having the GridTable flip borderless: true / false
based on when the row itself is hovered?
Granted, context changes mean a React re-render to change the flag from true/false, instead of just doing the :hover
... but I think that's probably fine?
@@ -34,6 +34,8 @@ export type GridCellContent = { | |||
revealOnRowHover?: true; | |||
/** Tooltip to add to a cell */ | |||
tooltip?: ReactNode; | |||
/** Allows cell to be editable when hovering, and also highlights the field on hover */ | |||
editableOnHover?: true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0ces cc @apattersonATX-HB do we want this to be a per-cell flag? Kinda thinking that the entire table should be consistent about "all columns/cells are editableOnHover
yes/no"...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting at the table makes sense. Maybe have an override on the cell/column level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can articulate a reason why a cell/column legitimately should not follow the "hover draws borders" behavior, yeah we could, but otherwise I'd prefer not to provide the option as a strong recommendation to the engineer/UX designer that "you should not be doing this".
(I.e. without a strong Figma-based design system driving consistency from the UX side, we've basically been using Beam's "opinionated APIs" to drive consistency back to the design team.)
src/components/Table/TableStyles.tsx
Outdated
@@ -42,6 +42,8 @@ export interface GridStyle { | |||
firstRowMessageCss?: Properties; | |||
/** Applied on hover if a row has a rowLink/onClick set. */ | |||
rowHoverColor?: Palette | "none"; | |||
/** Applied on hover to a cell TextFieldBase */ | |||
rowEditableCellBorderColor?: Palette; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0ces afaict we're not really setting this on "the cell", but instead pushing it down into the child TextField
's DOM? If so, maybe it shouldn't really be a "table style" and instead each component can know how to style itself has "editable" or "borderless: unless-hovered" or what not.
@@ -34,6 +34,8 @@ export type GridCellContent = { | |||
revealOnRowHover?: true; | |||
/** Tooltip to add to a cell */ | |||
tooltip?: ReactNode; | |||
/** Allows cell to be editable when hovering, and also highlights the field on hover */ | |||
editableOnHover?: true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit/suggestion: editableOnHover
doesn't really tell me whats happening here. Really we're just putting a border around fields on hover. The field doesn't actually become editable on hover, it just has a border now 🤷.
Taking a step back, this feels like something that should be globally applied, not just for one or two tables with inputs. I would request more design direction here. The issue with Blueprint is that every page is so different. This is just going to add to that problem.
Also, when a user uses their tab
key to go between fields, then we don't get the same "bordered" treatment, unless they're hovering that row. As this PR stands, it's creating an inconsistent experience that I don't believe provides a better UX for our users. I would ask Design to fully flush this idea out, and figure out if this should be the global pattern. If not the global pattern, have rules that define when to use this pattern vs not. We should be doing this as it is best for our users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah damn, I was pushing towards "each table itself should at least be consistent" (instead of a per cell decision), but ngl I like Brandon's push about "do they (design) just want all tables in BP to act this way?"
Because that is actually easier for us to globally roll out, and per Brandon's point likely (surely?) better for users (consistency), to just have our tables "always do that" (whatever the latest/greatest UX is), vs. picking tables onsey-twosy that do/do not get the special behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK this is a new design thing, I can ask design if this will be the new standard, I tried not to impose massive changes, this is the figma that I've been following for this PR: https://www.figma.com/design/xQ3iNLHJCFEJeOi7boONY4/Q1-2024-%7C-Dynamic-Schedules?node-id=11225-33807&t=BgAyiY5hjDNYwF9v-1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0ces cool, feel free to loop me into any design discussions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is supposed to be the new global standard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stephenh the feedback that I got from design:
As I understand it design does want to make this to make this the new standard but with a slow rollout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this comment mean by "non-table cells"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would like to see some attempts/iteration on a PresentationContext-based approach, changing borderless: true
to "something something hover" before this lands. Happy to chat/VC about it/approaches.
+1 to this. Still good work here @0ces! I found I was able to fix a few other issues by updating the |
@@ -88,6 +88,7 @@ function RowImpl<R extends Kinded, S>(props: RowProps<R>): ReactElement { | |||
const sortOn = tableState.sortConfig?.on; | |||
|
|||
const revealOnRowHoverClass = "revealOnRowHover"; | |||
const editableOnRowHoverClass = "editableOnRowHover"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0ces I'm still reading the PR (on mobile 😅) but can't this special class name go away with the PC based approach?
I.e. my primary concern with the original PR was that TextField was being told "don't show your border" ... And then later GridTable had a bunch of special "reach into TextFields DOM and tell it to do something else", which is a brittle approach/breaks encapsulation.
...I suppose you're staying with the special class name to take advantage of :hover psuedo-selector?
I'm not totally against using the :hover selector, but I'd like any "what does TextFields border look like when borderless but hovered" to be owned/live directly in TextField, and not GridTable.
Wdyt, in terms of approaches to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stephenh yeah, I'm keeping that class just to propagate the :hover state to the cells when hovering the rows and not the actual field, I really don't know a better way of doing the propagation, also as this is just CSS just for it not to cause a ton of re-renders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0ces right, but can we get the hover psuedo-selectors at least placed within the TextField class itself? I.e. GridTable will only "turn on" the hiber behavior, but the actual render details are in the TF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can give it a try
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Still reading, posting a few comments while in meetings)
}, | ||
]); | ||
|
||
const handleCellChange = (rowId: string, field: keyof EditableRowData["data"], value: any) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is just a story, but can we rename this to setRow
, which better describes what it does? Also would prefer a function
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this story is a react component I'll change it to be a useCallback
|
||
enum EditableRowStatus { | ||
Active = "Active", | ||
Inactive = "Inactive", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this enum supposed to be actively changing the coloring/styling/behavior of the style, or is it just a dummy enum to show what a select field looks like in the table?
If it's just a dummy enum, can we make the enum values something like Foo = "Foo"
and Bar = "Bar
"` just to highlight their meaningless-ness?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few more asks for in-source comments, removing a few now-unused (afaict) lines, and maybe renaming the special className
consts, but other lgtm!
The hover-unless-other-cell-hovered selector is neat, and makes sense; I think we've arrived at a pretty great solution, that still leverages :hover
selectors (something I was personally willing to give up on, but you've made work well), while keeping the components in control of their own styling. Thanks!
src/inputs/TextFieldBase.tsx
Outdated
@@ -259,6 +274,8 @@ export function TextFieldBase<X extends Only<TextFieldXss, X>>(props: TextFieldB | |||
...(errorMsg && !inputProps.disabled ? fieldStyles.error : {}), | |||
...Css.if(multiline).aifs.oh.mhPx(textAreaMinHeight).$, | |||
}} | |||
// Class name used for the grid table on row hover for highlighting | |||
className="textFieldBaseWrapper" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could envision eventually needing other non-TextFieldBase
components controlling the same "I'm hovered, so don't hover the other editable components in the row anymore", so I think it'd potentially be neat to:
- Rename
ROW_CSS_SELECTOR
toBorderHoverParent
- Extract
textFieldBaseWrapper
and name itBorderHoverChild
To have the names align to the general capability we're adding, which is that should a component have borderOnHover=true
set, it will hook up its styles to "whatever BorderHoverParent", as long as said BHP doesn't already have a hovered BHC.
## [2.371.0](v2.370.2...v2.371.0) (2024-12-03) ### Features * highlight editable cells on hover ([#1087](#1087)) ([007119b](007119b))
🎉 This PR is included in version 2.371.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
No description provided.