Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/10021-legend-swatch-custom-property.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@object-ui/plugin-charts': patch
---

fix(plugin-charts): the legend swatch carries its series colour as a custom property

`ChartLegendContent` painted each swatch with an inline `backgroundColor`, the
colour-bearing property AGENTS.md's styling carve-out names as forbidden. The
swatch now publishes the author-declared colour as `--color-bg` and a static
`bg-(--color-bg)` utility consumes it, the same shape the tooltip indicator in
the same file already uses, so the theme keeps control of the rule. The
rendered colour is unchanged.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* ObjectUI
* Copyright (c) 2024-present ObjectStack Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* The legend swatch carries the series colour the way AGENTS.md's styling
* carve-out prescribes (objectui#10021).
*
* A series colour is author-declared, so it may reach the DOM through
* `style={{}}` — but only as a CSS custom property that a STATIC Tailwind
* utility consumes, never as a colour-bearing property (`backgroundColor`)
* written inline. The swatch used to write `backgroundColor: item.color`; the
* tooltip indicator in the same file already used the compliant shape
* (`bg-(--color-bg)` + `"--color-bg"`), and the swatch now copies it.
*/

import React from 'react';
import { describe, it, expect, vi, afterEach } from 'vitest';
import { render, cleanup } from '@testing-library/react';

// ResponsiveContainer measures 0x0 under happy-dom; a passthrough keeps the
// legend content (rendered as a plain child) in the tree.
vi.mock('recharts', async () => {
const actual = await vi.importActual<Record<string, unknown>>('recharts');
return {
...actual,
ResponsiveContainer: ({ children }: { children: React.ReactElement }) => children,
};
});

import { ChartContainer, ChartLegendContent } from './ChartContainerImpl';

afterEach(() => {
cleanup();
});

function renderSwatch(color: string): HTMLElement {
const { container } = render(
<ChartContainer config={{}}>
<ChartLegendContent
payload={[{ value: 'Revenue', dataKey: 'revenue', type: 'square', color }]}
/>
</ChartContainer>,
);
const swatch = container.querySelector<HTMLElement>('.rounded-\\[2px\\]');
expect(swatch).not.toBeNull();
return swatch!;
}

describe('ChartLegendContent swatch colour (objectui#10021)', () => {
it('writes no colour-bearing property inline', () => {
const swatch = renderSwatch('#ff0000');
expect(swatch.style.backgroundColor).toBe('');
expect(swatch.style.color).toBe('');
expect(swatch.getAttribute('style') ?? '').not.toMatch(/background|(^|;)\s*color\s*:/i);
});

it('publishes the author colour as a custom property a static utility consumes', () => {
const swatch = renderSwatch('#ff0000');
expect(swatch.style.getPropertyValue('--color-bg')).toBe('#ff0000');
expect(swatch.classList.contains('bg-(--color-bg)')).toBe(true);
});
});
14 changes: 10 additions & 4 deletions packages/plugin-charts/src/ChartContainerImpl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,17 @@ function ChartLegendContent({
{itemConfig?.icon && !hideIcon ? (
<itemConfig.icon />
) : (
// The series colour is author-declared, so it reaches the DOM
// only as a custom property a static utility consumes — the
// same shape as the tooltip indicator above (AGENTS.md styling
// carve-out; objectui#10021).
<div
className="h-2 w-2 shrink-0 rounded-[2px]"
style={{
backgroundColor: item.color,
}}
className="h-2 w-2 shrink-0 rounded-[2px] bg-(--color-bg)"
style={
{
"--color-bg": item.color,
} as React.CSSProperties
}
/>
)}
{/* Fall back to the series name recharts itself put on the
Expand Down
Loading