layerchart
layerchart copied to clipboard
Investigate css-only usage (no `tailwindcss` by user)
While fully removing tailwindcss is unlikely as it enables simplified integration with Svelte UX, shadcn-svelte, Skeleton, etc, I could foresee exposing a prebuilt layerchart.css export using tailwindcss cli.
Something like:
tailwindcss -i ./src/main.css -o ./dist/layerchart.css --minify
Would need to create a separate tailwind.config.cjs file with something like...
module.exports = {
content: ['./src/lib/**/*.svelte'],
}
and main.css with
@tailwind base;
@tailwind components;
@tailwind utilities;
since this is currently defined in +layout.svelte for the docs (and includes some additional global styles for the docs)
Would be interested in this
I would love to have this as well!
Ideally, I would probably need some way to isolate the generated CSS under a root selector. I found that some of the tailwind-generated CSS needed for LayerChart was colliding / conflicting with our native CSS.
For now, my workaround was to use Tailwind 3 with the following config options:
content: [
// Target only the files where LayerChart is used
'./src/lib/charts/**/*.{html,js,svelte,ts}',
'./node_modules/layerchart/**/*.{svelte,js}'
],
important: '.tailwind', // All styles will be scoped under this selector
…and then generate my own layerchart.css, which is imported into a <ChartWrapper> component that applies the tailwind class.
It works… but dropping the Tailwind dependency would certainly simplify things 😄.
Since Tailwind 4 is moving away from a config file (although you can use @config but is considered legacy), we might be able to use something like postcss-prefix-selector to apply the prefix/transform.
it would be nice to have .LayerChart class as a prefix, although this won't work for Tooltip's if we decided to portal them outside the current DOM hierarchy (just above </body>).
Striking the right balance so LayerChart works well within Tailwind environments (such as Svelte UX, shadcn-svelte, Skeleton, Daisy UI, etc) but also with standalone css is going to be the challenge, but worth the effort for sure.
Would also be interested in this!
Instead of pre-generating a tailwind-based .css file, we could also consider just moving many of these styles to <style> and it just work
For example, in Tooltip...
<div
{...props.root}
class={cls(
layerClass('tooltip-root'),
'absolute z-50 select-none',
!pointerEvents && 'pointer-events-none',
classes.root,
props.root?.class
)}
style:top="{motionY.current}px"
style:left="{motionX.current}px"
...
>
<div
{...props.container}
class={cls(
layerClass('tooltip-container'),
variant !== 'none' && ['text-sm py-1 px-2 h-full rounded-sm elevation-1'],
{
default: [
'bg-surface-100/90 dark:bg-surface-300/90 backdrop-filter backdrop-blur-[2px] text-surface-content',
'[&_.label]:text-surface-content/75',
],
invert: [
'bg-surface-content/90 backdrop-filter backdrop-blur-[2px] text-surface-100 border border-surface-content',
'[&_.label]:text-surface-100/50',
],
none: '',
}[variant],
classes.container,
props.container?.class,
className
)}
>
{#if children}
<div {...props.content} class={cls(layerClass('tooltip-content'), classes.content)}>
{@render children({ data: tooltipCtx.data, payload: tooltipCtx.payload })}
</div>
{/if}
</div>
</div>
could become something like (just quickly coded up, likely not 100%)...
<div
{...props.root}
class={cls(
layerClass('tooltip-root'),
tooltip-root,
!pointerEvents && 'pointer-events-none',
classes.root,
props.root?.class
)}
style:top="{motionY.current}px"
style:left="{motionX.current}px"
...
>
<div
{...props.container}
class={cls(
layerClass('tooltip-container'),
variant !== 'none' && 'variant-base',
`${variant-{variant}}`,
classes.container,
props.container?.class,
className
)}
>
{#if children}
<div {...props.content} class={cls(layerClass('tooltip-content'), classes.content)}>
{@render children({ data: tooltipCtx.data, payload: tooltipCtx.payload })}
</div>
{/if}
</div>
</div>
<style>
.tooltip-root {
position: absolute;
z-index: 50;
user-select: none;
}
.pointer-events-none {
pointer-events: none;
}
.variant-base {
font-size: text-sm;
padding: 0.25rem 0.5rem;
height: 100%;
border-radius: 0.125rem;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
}
.variant-default {
background-color: color-mix(in oklab, var(--color-surface-100) 90%, transparent);
color: var(--surface-content);
backdrop-filter: blur(2px);
& .label {
color: color-mix(in oklab, var(--color-surface-content) 75%, transparent);
}
}
/* or `:global(html.dark) .variant-default { ... }` */
@media (prefers-color-scheme: dark) {
.variant-default {
background-color: color-mix(in oklab, var(--color-surface-300) 90%, transparent);
}
}
.variant-invert {
background-color: color-mix(in oklab, var(--color-surface-content) 90%, transparent);
color: var(--surface-100);
border: 1px solid var(--surface-content);
backdrop-filter: blur(2px);
& .label {
color: color-mix(in oklab, var(--color-surface-100) 50%, transparent);
}
}
</style>
Would need to think what the user story would be for:
- Overriding these styles (which is currently handled by
cls()and tailwind-merge under the hood to allow user-level overrides, when needed - Should the css-only approach only provide the bare minimal styles (i.e. no variants with light/dark mode handling, etc)?
- Is pre-generating
layerchart.cssfrom the Tailwind authored classes the better approach? - Any issue with passing these classes/styles to the
utils/canvas.ts'sgetComputedStyles()
This is just one use case, but in general there are not a ton of pre-defined classes/styles in LayerChart beyond a default fill/stroke on primitives (Rect, Text, etc), so Tooltip is likely the most difficult to reason through. It's also HTML-only so the canvas question does not apply.
Few updates in layerchart@next:
- All components now have a global
classavailable vialayerClass('...')util- ex. Text =>
.lc-text-svg
- ex. Text =>
- shadcn-svelte Charts makes use of these global classes and do not pull in any LayerChart component defined classes (via
@source '../node_modules/layerchart/dist';)- For default styling, they leverage these global styles in their ChartContainer component
- This targeting is good feedback on potentially modifying some defaults or providing better extension. Once LayerChart supports settings() like Svelte UX, adding these classes would also be possible via context instead of global targeting
Setting up a new project without Tailwind and leveraging css-only to target these classes is the next step. Some exploration / iteration to investigating:
- Determine if we should provide a global
layerchart.cssfor any initial any values, or add to<style>withinChart - Expose / document a set of css variables for easy design changes
- Remove / change any defaults (tooltip variants, etc)
- Passing classes directly component only (no global class targeting)
- How does this work for canvas (directly setting class/style would work)?
Quick update: making great progress removing the Tailwind dependency (but still providing first-class Tailwind integration, especially with libraries such as shadcn-svelte, Skeleton, Svelte UX, Daisy UI, etc).
This PR also provides HTML layer support for many primitives including Circle, Ellipse, Group, Line, Rect, and Text (and many components that use these primitives such as Axis, Grid, etc).
Still a lot to update and validate, but all the primitives have now been updated and have a good pattern.
CSS-only usage is now available in 2.0.0-next.39 which means import {... } from 'layerchart' "just works"!
See also the newly added standalone example or REPL (which now works!)
Amazing!