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

[charts] HTML Labels #15813

Merged
merged 22 commits into from
Dec 11, 2024
Merged

[charts] HTML Labels #15813

merged 22 commits into from
Dec 11, 2024

Conversation

JCQuintas
Copy link
Member

@JCQuintas JCQuintas commented Dec 9, 2024

Note: The contents of this PR are marked as @ignore only for now.

The goal is to make the actual Legend PR simpler.

These are the smaller building blocks for the Legend and Tooltip

Regarding why not go for ChartsCircleLabelMark+ChartsSquareLabelMark+.... While it makes each component slightly simpler, it increases the surface area of our components to our users, and the code is mostly the same, so it would require a lot of duplications.

My api target goal is that the eventual labelMark property can be set on the series and series.data for pie charts, while only on the series for other types.

This would accepts our defined label types of 'square' | 'circle' | 'line', but also allow "custom" or any other string the user wants, so they can create custom mark handlers and control it through the series. Eg:

Example custom mark
const MyCustomLegend = () => {
  const { items } = useLegend();
  return (
    <div>
      {items.map((item) => {
        if (item.markType === 'star') {
          return <div key={item.label}>{item.label} - 🌟</div>;
        }

        return <ChartsLabelMark key={item.label} type={item.markType} />;
      })}
    </div>
  );
};

<ChartDataProvider
  height={300}
  width={300}
  series={[
    { 
      // 'star'
      labelMarkType: 'star',
      type: 'line', label: 'Line 1', data: [10, 20] 
    },
    { type: 'line', label: 'Line 2', data: [50, 40] },
  ]}
>
  <ChartsSurface />
  <MyCustomLegend />
</ChartDataProvider>

Test Sandbox

https://codesandbox.io/p/sandbox/html-labels-15813-pt8rwp

@JCQuintas JCQuintas added component: charts This is the name of the generic UI component, not the React module! design This is about UI or UX design, please involve a designer labels Dec 9, 2024
@JCQuintas JCQuintas self-assigned this Dec 9, 2024
@mui-bot
Copy link

mui-bot commented Dec 9, 2024

Deploy preview: https://deploy-preview-15813--material-ui-x.netlify.app/

Generated by 🚫 dangerJS against 436b169

Copy link

codspeed-hq bot commented Dec 9, 2024

CodSpeed Performance Report

Merging #15813 will not alter performance

Comparing JCQuintas:html-labels (436b169) with master (05b5028)

Summary

✅ 6 untouched benchmarks

overridesResolver: (props, styles) => styles.root,
})<{ ownerState: ChartsLabelProps }>(({ theme, ownerState }) => ({
...theme.typography.caption,
color: (theme.vars || theme).palette.text.primary,
Copy link
Member Author

Choose a reason for hiding this comment

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

We currently use theme colors for this, but the designs suggest other colors. I'm not sure how to proceed. If we follow the design, where do these colors come from?

https://www.figma.com/design/upttiqJUQYGUu3xo6w7COx/Design-refinement?node-id=45-334&node-type=frame&t=kteCWeOvyprNETmc-0

* @param {Function} options.classesResolver A function that returns the classes for the component. It receives the props, after theme props and defaults have been applied. And the theme object as the second argument.
* @param InComponent The component to render if the slot is not provided.
*/
export const consumeThemeProps = <
Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure this should be here or in other packages. Left here for now as we have full control of our own package... 🙃

The idea is to handle all the boilerplate we do for theme and default props to before the component even receives them. Simplifying the business logic of the component itself.

Ofc it is not a silver bullet, but it should handle simple cases like the components in this PR. Name/functionality up to discussion.

Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

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

it increases the surface area of our components to our users, and the code is mostly the same, so it would require a lot of duplications.

About the surface of components provided, it would just be similar to what MUI is doing for material icons

For the code duplication. It's still possible to have a wrapper for the duplicate part. Something like the SvgIcon.

It may be because I don't see how you will make the type property extendable.

If you allow ChartsLabelMark to be a slot, then devs will have to do something like that to be able to get both the default and their custom

const CustomLableMark = (props) => props.type === "line" ? <ChartsLabelMark {...props} /> : <MyCustomSVG {...props} />

If you give access to what is inside <svg/> you might prevent them from using HTML

If you give access to the SVG itself. You're fairly similar to the SvgIconCompoent. And I would be infavor of exporting the wrapper and one component per icon

packages/x-charts/src/ChartsLabel/ChartsLabel.tsx Outdated Show resolved Hide resolved
Comment on lines +14 to +19
/**
* A unique identifier for the gradient.
*
* The `gradientId` will be used as `fill="url(#gradientId)"`.
*/
gradientId: string;
Copy link
Member

Choose a reason for hiding this comment

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

WHat about removing this gradientId and directly rendering the ChartsContinuousGradientProps inside the component. Like

function ChartsLabelGradient(){
  const id = useId()
  return <svg>
    <ChartsContinuousGradientProps  id={id}/>
    <rect fill={`url(#${id})`} />
  </svg>
}

Otherwise you get a kind of duplicate information. If you want to switch from row to column, you need to define again the gradient

gradientId="paint_0_row" direction="row"

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried it at first, my main gripe with adding the gradient inside it that this component loses a bit of flexibility.

I'll try something new and report back

Copy link
Member Author

Choose a reason for hiding this comment

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

I can work by removing the hardcoded sizes in the svg and adding some CSS

Copy link
Member Author

Choose a reason for hiding this comment

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

updated the sandbox

packages/x-charts/src/ChartsLabel/ChartsLabelMark.tsx Outdated Show resolved Hide resolved
display: 'flex',
alignItems: 'center',
'> div': {
height: ownerState.lineWidth,
Copy link
Member

Choose a reason for hiding this comment

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

That line is a bit weird

Copy link
Member Author

Choose a reason for hiding this comment

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

Why?

The main thing here is that the line SVG is actually a rectangle with w=100% & h=100%. We use the div's border radius to add the radius, which simplifies a lot the svgs.

Or do you mean that line WIDTH goes into HEIGHT? I got it from stroke-width 😂

Copy link
Member

Choose a reason for hiding this comment

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

Yes, having somethinf called lineWidth used to define a height feels unexpected

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you have suggestions? I felt lineSize odd, lineWidth and borderWidth are css, lineHeight is a different thing, could be confusing?

ref={ref}
{...other}
>
<div>
Copy link
Member

Choose a reason for hiding this comment

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

Why having a div inside a styled div 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

For the line shape. I use the outside div for width=16px so it takes the size necessary, but the line is thin, so there is no need for the component to take height=16px, this way we can let the Root take the width it needs, then the line takes the height defined by lineWidth

@JCQuintas
Copy link
Member Author

@alexfauquette created a small PR on my own fork to show changes to use a defined SVG shape instead of rectangle.

JCQuintas#8

I'm still more biased towards the current approach though 😆

IMO the dom structure is cleaner and it should be easier to target CSS, since it is not deep.

But it is not as trivial to change the shape anymore, since it is an SVG, users would still need to target the rect to change border radius or line width for example.

Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

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

Good for me. Could you remove the exports from the two index.ts such that those components do not get exposed before the PR that introduces the HTML legend?

It's not strictly speaking necessary, but, would be nice to check their DX works well with the legend/tooltip before exposing them

Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

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

Nice, I'm impatient to see the result in the main PR :)

@JCQuintas JCQuintas merged commit 99ce15c into mui:master Dec 11, 2024
19 checks passed
@JCQuintas
Copy link
Member Author

Nice, I'm impatient to see the result in the main PR :)

You can always checkout the PR 😆

lauri865 pushed a commit to lauri865/mui-x that referenced this pull request Dec 19, 2024
Signed-off-by: Jose C Quintas Jr <juniorquintas@gmail.com>
Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com>
LukasTy pushed a commit to LukasTy/mui-x that referenced this pull request Dec 19, 2024
Signed-off-by: Jose C Quintas Jr <juniorquintas@gmail.com>
Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: charts This is the name of the generic UI component, not the React module! design This is about UI or UX design, please involve a designer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants