|
| 1 | +# CSS Variables Plugin |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The `CSSVariablesLayer` plugin enables seamless synchronization between CSS variables and graph appearance settings (colors and constants). Instead of using JavaScript API methods like `graph.setColors()` or `graph.setConstants()`, you can control the graph's visual styling through standard CSS variables. |
| 6 | + |
| 7 | +This layer creates an invisible HTML div element with a specified CSS class and monitors CSS variable changes using the `style-observer` package. When CSS variables change (e.g., through theme switching, media queries, or dynamic style updates), the layer automatically maps these changes to the corresponding `TGraphColors` and `TGraphConstants` properties and applies them to the graph. |
| 8 | + |
| 9 | +## Features |
| 10 | + |
| 11 | +1. **CSS-based Styling:** |
| 12 | + * Control graph appearance using CSS variables instead of JavaScript API. |
| 13 | + * Enables integration with CSS frameworks, design systems, and theme providers. |
| 14 | + * Supports dynamic theme switching without JavaScript code changes. |
| 15 | + |
| 16 | +2. **Real-time Synchronization:** |
| 17 | + * Automatically detects CSS variable changes using `style-observer`. |
| 18 | + * Instantly applies changes to graph colors and constants. |
| 19 | + * No manual update calls required. |
| 20 | + |
| 21 | +3. **Comprehensive Variable Support:** |
| 22 | + * Colors: canvas, blocks, anchors, connections, connection labels, selection. |
| 23 | + * Constants: block dimensions, grid size, camera settings, text properties. |
| 24 | + * See [Supported CSS Variables](#supported-css-variables) section for the complete list. |
| 25 | + |
| 26 | +4. **Type Safety:** |
| 27 | + * Automatic type conversion (color strings, floats, integers). |
| 28 | + * Validates and converts CSS values to appropriate graph property types. |
| 29 | + |
| 30 | +5. **Developer-friendly:** |
| 31 | + * Optional debug mode for logging changes. |
| 32 | + * Change callback for custom handling. |
| 33 | + * Lightweight invisible container with no visual impact. |
| 34 | + |
| 35 | +## Usage |
| 36 | + |
| 37 | +The `CSSVariablesLayer` can be added to the graph like any other layer. |
| 38 | + |
| 39 | +### 1. Via Graph Configuration |
| 40 | + |
| 41 | +```typescript |
| 42 | +import { Graph, CSSVariablesLayer } from "@gravity-ui/graph"; |
| 43 | + |
| 44 | +const graph = new Graph({ |
| 45 | + // ... other graph settings |
| 46 | + layers: [ |
| 47 | + // Other layers... |
| 48 | + [CSSVariablesLayer, { |
| 49 | + containerClass: "graph-theme", // CSS class for the container |
| 50 | + debug: false, // Enable debug logging |
| 51 | + onChange: (changes) => { |
| 52 | + console.log("CSS variables changed:", changes); |
| 53 | + } |
| 54 | + }] |
| 55 | + ] |
| 56 | +}); |
| 57 | +``` |
| 58 | + |
| 59 | +### 2. Dynamic Addition |
| 60 | + |
| 61 | +```typescript |
| 62 | +import { CSSVariablesLayer } from "@gravity-ui/graph"; |
| 63 | + |
| 64 | +// Assuming 'graph' is an existing Graph instance |
| 65 | +graph.addLayer(CSSVariablesLayer, { |
| 66 | + containerClass: "graph-theme", |
| 67 | + debug: true, |
| 68 | +}); |
| 69 | +``` |
| 70 | + |
| 71 | +### 3. With React (`useLayer` Hook) |
| 72 | + |
| 73 | +This is the recommended way when using the React bindings. |
| 74 | + |
| 75 | +```tsx |
| 76 | +import React from 'react'; |
| 77 | +import { useGraph, GraphCanvas, useLayer, CSSVariablesLayer } from '@gravity-ui/graph'; |
| 78 | + |
| 79 | +function MyGraphComponent() { |
| 80 | + const { graph } = useGraph({ /* ... initial config ... */ }); |
| 81 | + |
| 82 | + // Add the CSS Variables layer using the hook |
| 83 | + useLayer(graph, CSSVariablesLayer, { |
| 84 | + containerClass: "graph-theme", // Match your theme container class |
| 85 | + debug: false, |
| 86 | + onChange: (changes) => { |
| 87 | + // Optional: handle changes |
| 88 | + console.log("CSS variables updated:", changes); |
| 89 | + }, |
| 90 | + }); |
| 91 | + |
| 92 | + // ... useEffect to load data and start graph ... |
| 93 | + |
| 94 | + return ( |
| 95 | + <div className="graph-theme graph-theme-light"> |
| 96 | + <GraphCanvas graph={graph} renderBlock={/* ... */} /> |
| 97 | + </div> |
| 98 | + ); |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +## Configuration Options (`CSSVariablesLayerProps`) |
| 103 | + |
| 104 | +The layer accepts the following options (extending base `LayerProps`), with defaults defined in `DEFAULT_CSS_VARIABLES_LAYER_PROPS`: |
| 105 | + |
| 106 | +| Prop | Type | Default | Description | |
| 107 | +| :------------------------- | :-------------------------------------------- | :----------------------------- | :-------------------------------------------------------------------------- | |
| 108 | +| `containerClass` | `string` | **(required)** | CSS class name applied to the invisible container div. Used to observe CSS variables. | |
| 109 | +| `onChange` | `(changes: CSSVariableChange[]) => void` | `undefined` | Optional callback invoked when CSS variables change. Receives array of changes. | |
| 110 | +| `debug` | `boolean` | `false` | Enables debug logging to console for CSS variable changes and layer operations. | |
| 111 | + |
| 112 | +*Note: Base `LayerProps` like `graph`, `camera`, `root`, `emitter` are provided automatically when using `graph.addLayer` or `useLayer`.* |
| 113 | + |
| 114 | +## Supported CSS Variables |
| 115 | + |
| 116 | +The layer supports the following CSS variables, automatically mapped to graph properties: |
| 117 | + |
| 118 | +### Canvas Colors |
| 119 | + |
| 120 | +| CSS Variable | Graph Property | Type | |
| 121 | +| :------------------------------------ | :------------------------------ | :------ | |
| 122 | +| `--graph-canvas-background` | `canvas.layerBackground` | Color | |
| 123 | +| `--graph-canvas-below-background` | `canvas.belowLayerBackground` | Color | |
| 124 | +| `--graph-canvas-dots` | `canvas.dots` | Color | |
| 125 | +| `--graph-canvas-border` | `canvas.border` | Color | |
| 126 | + |
| 127 | +### Block Colors |
| 128 | + |
| 129 | +| CSS Variable | Graph Property | Type | |
| 130 | +| :------------------------------------ | :------------------------------ | :------ | |
| 131 | +| `--graph-block-background` | `block.background` | Color | |
| 132 | +| `--graph-block-border` | `block.border` | Color | |
| 133 | +| `--graph-block-text` | `block.text` | Color | |
| 134 | +| `--graph-block-selected-border` | `block.selectedBorder` | Color | |
| 135 | + |
| 136 | +### Anchor Colors |
| 137 | + |
| 138 | +| CSS Variable | Graph Property | Type | |
| 139 | +| :------------------------------------ | :------------------------------ | :------ | |
| 140 | +| `--graph-anchor-background` | `anchor.background` | Color | |
| 141 | +| `--graph-anchor-selected-border` | `anchor.selectedBorder` | Color | |
| 142 | + |
| 143 | +### Connection Colors |
| 144 | + |
| 145 | +| CSS Variable | Graph Property | Type | |
| 146 | +| :------------------------------------ | :------------------------------ | :------ | |
| 147 | +| `--graph-connection-background` | `connection.background` | Color | |
| 148 | +| `--graph-connection-selected-background` | `connection.selectedBackground` | Color | |
| 149 | + |
| 150 | +### Connection Label Colors |
| 151 | + |
| 152 | +| CSS Variable | Graph Property | Type | |
| 153 | +| :------------------------------------ | :------------------------------ | :------ | |
| 154 | +| `--graph-connection-label-background` | `connectionLabel.background` | Color | |
| 155 | +| `--graph-connection-label-hover-background` | `connectionLabel.hoverBackground` | Color | |
| 156 | +| `--graph-connection-label-selected-background` | `connectionLabel.selectedBackground` | Color | |
| 157 | +| `--graph-connection-label-text` | `connectionLabel.text` | Color | |
| 158 | +| `--graph-connection-label-hover-text` | `connectionLabel.hoverText` | Color | |
| 159 | +| `--graph-connection-label-selected-text` | `connectionLabel.selectedText` | Color | |
| 160 | + |
| 161 | +### Selection Colors |
| 162 | + |
| 163 | +| CSS Variable | Graph Property | Type | |
| 164 | +| :------------------------------------ | :------------------------------ | :------ | |
| 165 | +| `--graph-selection-background` | `selection.background` | Color | |
| 166 | +| `--graph-selection-border` | `selection.border` | Color | |
| 167 | + |
| 168 | +### Block Constants |
| 169 | + |
| 170 | +| CSS Variable | Graph Property | Type | |
| 171 | +| :------------------------------------ | :------------------------------ | :------ | |
| 172 | +| `--graph-block-width` | `block.WIDTH` | Float | |
| 173 | +| `--graph-block-height` | `block.HEIGHT` | Float | |
| 174 | +| `--graph-block-width-min` | `block.WIDTH_MIN` | Float | |
| 175 | +| `--graph-block-head-height` | `block.HEAD_HEIGHT` | Float | |
| 176 | +| `--graph-block-body-padding` | `block.BODY_PADDING` | Float | |
| 177 | + |
| 178 | +### System Constants |
| 179 | + |
| 180 | +| CSS Variable | Graph Property | Type | |
| 181 | +| :------------------------------------ | :------------------------------ | :------ | |
| 182 | +| `--graph-grid-size` | `system.GRID_SIZE` | Int | |
| 183 | +| `--graph-usable-rect-gap` | `system.USABLE_RECT_GAP` | Float | |
| 184 | + |
| 185 | +### Camera Constants |
| 186 | + |
| 187 | +| CSS Variable | Graph Property | Type | |
| 188 | +| :------------------------------------ | :------------------------------ | :------ | |
| 189 | +| `--graph-camera-speed` | `camera.SPEED` | Float | |
| 190 | +| `--graph-camera-step` | `camera.STEP` | Float | |
| 191 | + |
| 192 | +### Text Constants |
| 193 | + |
| 194 | +| CSS Variable | Graph Property | Type | |
| 195 | +| :------------------------------------ | :------------------------------ | :------ | |
| 196 | +| `--graph-text-base-font-size` | `text.BASE_FONT_SIZE` | Float | |
| 197 | +| `--graph-text-padding` | `text.PADDING` | Float | |
| 198 | + |
| 199 | +## CSS Example |
| 200 | + |
| 201 | +Here's an example of defining graph styles using CSS variables: |
| 202 | + |
| 203 | +```css |
| 204 | +/* Light theme */ |
| 205 | +.graph-theme-light { |
| 206 | + --graph-canvas-background: #ffffff; |
| 207 | + --graph-block-background: #f5f5f5; |
| 208 | + --graph-block-border: #e0e0e0; |
| 209 | + --graph-block-selected-border: #ffbe5c; |
| 210 | + --graph-connection-background: rgba(0, 0, 0, 0.3); |
| 211 | + --graph-connection-selected-background: #eac94a; |
| 212 | +} |
| 213 | + |
| 214 | +/* Dark theme */ |
| 215 | +.graph-theme-dark { |
| 216 | + --graph-canvas-background: #1a1a1a; |
| 217 | + --graph-block-background: #2d2d2d; |
| 218 | + --graph-block-border: #404040; |
| 219 | + --graph-block-selected-border: #ffbe5c; |
| 220 | + --graph-connection-background: rgba(255, 255, 255, 0.5); |
| 221 | + --graph-connection-selected-background: #eac94a; |
| 222 | +} |
| 223 | + |
| 224 | +/* Custom block sizes */ |
| 225 | +.graph-theme { |
| 226 | + --graph-block-width: 240px; |
| 227 | + --graph-block-height: 120px; |
| 228 | + --graph-block-head-height: 32px; |
| 229 | + --graph-grid-size: 20; |
| 230 | +} |
| 231 | +``` |
| 232 | + |
| 233 | +## Best Practices |
| 234 | + |
| 235 | +1. **Container Class Naming:** Use a consistent CSS class name that matches your theme structure (e.g., `graph-theme`). |
| 236 | +2. **Theme Organization:** Group related variables together in your CSS files for better maintainability. |
| 237 | +3. **Debug Mode:** Enable `debug: true` during development to track variable changes in the console. |
| 238 | +4. **Performance:** The layer is optimized and uses efficient observers, but avoid excessive CSS variable changes in tight loops. |
| 239 | +5. **Fallbacks:** Define default values in your CSS to ensure proper rendering if variables are not set. |
| 240 | +6. **Type Consistency:** Use appropriate CSS value formats: |
| 241 | + * Colors: `#hex`, `rgb()`, `rgba()`, or named colors |
| 242 | + * Numbers: Include units for dimensions (`px`, `em`, etc.) or use unitless values |
| 243 | + * Integers: Whole numbers for properties like `GRID_SIZE` |
| 244 | + |
| 245 | +## Integration with Design Systems |
| 246 | + |
| 247 | +The CSS Variables Layer integrates seamlessly with design system tokens and theme providers: |
| 248 | + |
| 249 | +```tsx |
| 250 | +// Example with a design system |
| 251 | +import { ThemeProvider } from '@my-design-system/react'; |
| 252 | + |
| 253 | +function App() { |
| 254 | + const { graph } = useGraph(); |
| 255 | + |
| 256 | + useLayer(graph, CSSVariablesLayer, { |
| 257 | + containerClass: 'my-design-system-theme', |
| 258 | + }); |
| 259 | + |
| 260 | + return ( |
| 261 | + <ThemeProvider theme="light"> |
| 262 | + <div className="my-design-system-theme"> |
| 263 | + <GraphCanvas graph={graph} /> |
| 264 | + </div> |
| 265 | + </ThemeProvider> |
| 266 | + ); |
| 267 | +} |
| 268 | +``` |
| 269 | + |
| 270 | +## Troubleshooting |
| 271 | + |
| 272 | +**Variables not updating:** |
| 273 | +- Ensure the `containerClass` matches an actual CSS class in your DOM. |
| 274 | +- Check that CSS variables are properly defined with the `--graph-` prefix. |
| 275 | +- Enable `debug: true` to see which variables are being detected. |
| 276 | + |
| 277 | +**Wrong colors/values:** |
| 278 | +- Verify CSS variable values use correct formats (valid colors, numbers with units). |
| 279 | +- Check the browser DevTools to inspect computed CSS variable values. |
| 280 | +- Ensure variable names exactly match the supported list. |
| 281 | + |
| 282 | +**Performance issues:** |
| 283 | +- Avoid changing too many variables simultaneously. |
| 284 | +- Consider debouncing rapid theme changes. |
| 285 | +- Use the `onChange` callback to batch updates if needed. |
| 286 | + |
0 commit comments