From 6628d25a4eeabe3784b370545c57208a308df1c9 Mon Sep 17 00:00:00 2001 From: Einar Date: Sun, 27 Sep 2026 16:30:53 +0200 Subject: [PATCH] Let hosts theme the canvas minimap grid and default item color The minimap drew its dot grid and its uncolored items from inline styles, so a host could only change them by changing surface-border and the text color for everything else too. Two component tokens, --cratis-canvas-minimap-grid-color and --cratis-canvas-minimap-item-color, now take precedence. They are deliberately left undefined and read with a fallback, so they resolve on the minimap itself and follow a dark subtree; the fallbacks are today's values, so nothing changes until a host sets them. --- Documentation/Canvas/pan-and-zoom.md | 1 + Documentation/Styling/cratis-tokens.md | 4 ++- Source/Canvas/CanvasMinimap.tsx | 4 +-- .../when_rendering_on_the_server.tsx | 34 +++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 Source/Canvas/for_CanvasMinimap/when_rendering_on_the_server.tsx diff --git a/Documentation/Canvas/pan-and-zoom.md b/Documentation/Canvas/pan-and-zoom.md index 9b9a652f..529a00e2 100644 --- a/Documentation/Canvas/pan-and-zoom.md +++ b/Documentation/Canvas/pan-and-zoom.md @@ -53,6 +53,7 @@ Safari/WebKit's non-standard trackpad gesture events are also handled, so pinch- - `controlsPlacement` (default `'bottom-left'`) — `'bottom-left'` or `'bottom-right'`. - `minimapWorldWidth` / `minimapWorldHeight` — the world-space area the minimap represents. `CanvasMinimap` defaults these to `4000`×`3000` when omitted. - `minimapItems` — explicit item boxes to draw on the minimap. When omitted, `Canvas` builds this list automatically from every mounted `CanvasItem`'s reported position and size, so the minimap works out of the box for the declarative-children approach without any extra wiring. +- The minimap draws its dot grid in `--cratis-canvas-minimap-grid-color` and every item without its own `color` in `--cratis-canvas-minimap-item-color`. Neither is defined by default; they fall back to `--cratis-surface-border` and to the text color at 25% opacity. See [Component tokens](../Styling/cratis-tokens.md#component-tokens). ## `CanvasHandle` — imperative camera control diff --git a/Documentation/Styling/cratis-tokens.md b/Documentation/Styling/cratis-tokens.md index 0291a398..9cb31d3d 100644 --- a/Documentation/Styling/cratis-tokens.md +++ b/Documentation/Styling/cratis-tokens.md @@ -57,7 +57,7 @@ The `--cratis-*` variables are the supported theming boundary. The `tokens` entr ## Component tokens -A few tokens tune one component. The first three have defaults in `tokens`; the last two are not defined anywhere, and the component falls back to the listed value until you set them. +A few tokens tune one component. The first three have defaults in `tokens`; the rest are not defined anywhere, and the component falls back to the listed value until you set them. | Token | Default | Surface | | --------------------------------------------- | ------------------------------------ | ---------------------------------------------------------- | @@ -66,6 +66,8 @@ A few tokens tune one component. The first three have defaults in `tokens`; the | `--cratis-number-input-step-background-hover` | `var(--cratis-surface-hover)` | Hovered NumberInput step button. | | `--cratis-shadow-card` | `none` (fallback) | Selected ToggleGroup option. | | `--cratis-filter-option-list-max-height` | `14rem` (fallback) | `CheckboxListFilter` option list (Filter and PivotViewer). | +| `--cratis-canvas-minimap-grid-color` | `var(--cratis-surface-border)` (fallback) | Canvas minimap dot grid. | +| `--cratis-canvas-minimap-item-color` | `var(--cratis-text-color)` at 25% (fallback) | Canvas minimap items without their own `color`. | ## Overlay stacking diff --git a/Source/Canvas/CanvasMinimap.tsx b/Source/Canvas/CanvasMinimap.tsx index 0dea3a3d..1face80c 100644 --- a/Source/Canvas/CanvasMinimap.tsx +++ b/Source/Canvas/CanvasMinimap.tsx @@ -161,7 +161,7 @@ export const CanvasMinimap = forwardRef position: 'absolute', inset: 0, backgroundImage: - 'radial-gradient(circle, var(--cratis-surface-border) 1px, transparent 1px)', + 'radial-gradient(circle, var(--cratis-canvas-minimap-grid-color, var(--cratis-surface-border)) 1px, transparent 1px)', backgroundSize: '10px 10px', pointerEvents: 'none', }} @@ -180,7 +180,7 @@ export const CanvasMinimap = forwardRef height: Math.max(2, item.height * scaleYConst), background: item.color ?? - 'color-mix(in srgb, var(--cratis-text-color) 25%, transparent)', + 'var(--cratis-canvas-minimap-item-color, color-mix(in srgb, var(--cratis-text-color) 25%, transparent))', borderRadius: 2, pointerEvents: 'none', }} diff --git a/Source/Canvas/for_CanvasMinimap/when_rendering_on_the_server.tsx b/Source/Canvas/for_CanvasMinimap/when_rendering_on_the_server.tsx new file mode 100644 index 00000000..b307bd35 --- /dev/null +++ b/Source/Canvas/for_CanvasMinimap/when_rendering_on_the_server.tsx @@ -0,0 +1,34 @@ +// Copyright (c) Cratis. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import { renderToStaticMarkup } from 'react-dom/server'; +import { expect } from 'chai'; +import { describe, it } from 'vitest'; +import { CanvasMinimap } from '../CanvasMinimap'; + +describe('when rendering the minimap on the server', () => { + const html = renderToStaticMarkup( + , + ); + + it('should_draw_the_grid_from_the_grid_token_falling_back_to_the_surface_border', () => { + expect(html).to.contain( + 'var(--cratis-canvas-minimap-grid-color, var(--cratis-surface-border))', + ); + }); + + it('should_draw_an_uncolored_item_from_the_item_token_falling_back_to_the_text_color', () => { + expect(html).to.contain( + 'var(--cratis-canvas-minimap-item-color, color-mix(in srgb, var(--cratis-text-color) 25%, transparent))', + ); + }); + + it('should_keep_an_items_own_color', () => { + expect(html).to.contain('background:rgb(1, 2, 3)'); + }); +});