Skip to content
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

Annotation label <foreignobject> render #1383

Merged
merged 5 commits into from
Jan 21, 2022

Conversation

valtism
Copy link
Contributor

@valtism valtism commented Nov 26, 2021

🚀 Enhancements

Add option to pass in an element to render as a label as a child.
Uses to allow user to pass in an HTML element.

Related to this discussion: #1173

This has the benefit of letting the element handle text reflow, with
the drawback being that the user need to manage min and max width of
the container element they render.

This approach seems much better imo, favouring composability over
configuration which is much more in line with the philosophy of d3.

Add option to pass in an element to render as a label as a child.
Uses <foreignObject> to allow user to pass in an HTML element.

Related to this discussion: airbnb#1173

This has the benefit of letting the element handle text reflow, with
the drawback being that the user need to manage min and max width of
the container element they render.

This approach seems much better imo, favouring composability over
configuration which is much more in line with the philosophy of d3.
Add witdth and height to <foreignObject>. Worked for Chrome but was not
displaying anything for Safari.
Not sure how idomatic all the `dive()`s are, but I've heard complaints
about them so I'm guess it's the way to go.
@valtism
Copy link
Contributor Author

valtism commented Nov 26, 2021

Example of the annotation in action. Notice the <div> handles text reflow much better. The label is also much easier to style how you want.

Screen.Recording.2021-11-26.at.3.31.39.pm.mov

@williaster Let me know what you think. Made this non-breaking as possible.

Copy link
Collaborator

@gazcn007 gazcn007 left a comment

Choose a reason for hiding this comment

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

LGTM

@williaster
Copy link
Collaborator

hey @valtism , sorry I was away for all of Dec and am just getting back into the swing of things. will try to review/land this asap! (next day or two)

Copy link
Collaborator

@williaster williaster left a comment

Choose a reason for hiding this comment

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

Woweee @valtism this one looks great 💯 thanks for adding this, it's a huge improvement for additional flexibility! 🔥 Can't wait to use it.

I had a couple suggestions, mostly about moving out the html-based label into its own file to support easier import and documentation.

@@ -15,6 +15,8 @@ export type LabelProps = {
backgroundPadding?: number | { top?: number; right?: number; bottom?: number; left?: number };
/** Additional props to be passed to background SVGRectElement. */
backgroundProps?: React.SVGProps<SVGRectElement>;
/** Pass in a custom element as the label to style as you like. Renders inside a <foreignObject> */
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit – period for docs.

Suggested change
/** Pass in a custom element as the label to style as you like. Renders inside a <foreignObject> */
/** Pass in a custom element as the label to style as you like. Renders inside a <foreignObject>. */

I wonder also if it'd be worth noting from the original issue something like

Note that copy/pasting content from a browser may not work if you use this option because not all non-browser SVG renderers render HTML <foreignObject>s

I'm actually not sure if this is true since the DOM tree in the implementation has a div <foreignObject><div>... so maybe don't have to worry about it for now. cc @richsilv

packages/visx-annotation/src/components/Label.tsx Outdated Show resolved Hide resolved
packages/visx-annotation/src/components/Label.tsx Outdated Show resolved Hide resolved
packages/visx-annotation/src/components/Label.tsx Outdated Show resolved Hide resolved
packages/visx-annotation/src/components/Label.tsx Outdated Show resolved Hide resolved
packages/visx-annotation/src/components/Label.tsx Outdated Show resolved Hide resolved
Rename ForeignObjectLabel -> HtmlLabel

Split out HtmlLabel and LabelAnchorLine to separate components.

Export HtmlLabel as a separate component as it uses a small subset of the shared props.
@valtism
Copy link
Contributor Author

valtism commented Jan 20, 2022

@williaster thanks for the great feedback! I've incorporated everything you mentioned, but I'm not entirely sure how to test to see if the new HtmlLabel displays properly in the docs. Let me know if I missed anything.

Copy link
Collaborator

@williaster williaster left a comment

Choose a reason for hiding this comment

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

thanks for iterating 🙌 docs look good!

fyi you can check by

  • rebuilding the package of interest yarn build:workspaces --workspaces=@visx/drag --esm --watch (the demo site pulls from the esm/ build, this is documented in CONTRIBUTING.md but is subtle)
  • start the demo site dev server yarn dev:demo (or from packages/visx-demo run yarn dev)
  • visit http://localhost:3000/docs/annotation (or whatever)

I had two minor comments based on playing with it a bit. I might follow up with adding an svg <> html toggle in the demo for easier testing, so I'm happy to make those two tweaks in that PR if you'd rather merge as is.

pointerEvents="none"
className={cx('visx-annotationlabel', className)}
>
{showAnchorLine && (
Copy link
Collaborator

Choose a reason for hiding this comment

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

one thing I noticed while playing with this is that the line renders behind the HTML, do you think we should flip this and render the anchor line after foreignObject?

/>
)}
<foreignObject width={width} height={height} overflow="visible">
<div ref={labelRef} style={wrapperStyle}>
Copy link
Collaborator

@williaster williaster Jan 20, 2022

Choose a reason for hiding this comment

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

when I was playing with this I found myself adding a bunch of styles to a div in children, I wonder if we should just expose this so users don't need an extra DOM element? something like containerStyle?: React.CSSProperties and then we can spread it in like style={containerStyle ? { ...wrapperStyle, containerStyle } : wrapperStyle

shallow(
<Label title="title test" showBackground resizeObserverPolyfill={ResizeObserver} />,
).find('rect'),
shallow(<Label title="title test" showBackground resizeObserverPolyfill={ResizeObserver} />)
Copy link
Collaborator

Choose a reason for hiding this comment

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

🙏 thanks for fixing these

@williaster
Copy link
Collaborator

Hey @valtism I have some time today so am gonna land this and make those changes in another PR. Awesome job here! 🎉

@williaster williaster merged commit ae47109 into airbnb:master Jan 21, 2022
@github-actions
Copy link

🎉 This PR is included in version v2.7.0 of the packages modified 🎉

@valtism
Copy link
Contributor Author

valtism commented Jan 23, 2022

@williaster Perfect. I'm not precious about my code, so thanks for making those fixes. Look forward to using it 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants