@nxgt/material 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/README.md +46 -1
  3. package/dist/components/components.css +2 -0
  4. package/dist/components/theme-tokens.css +84 -72
  5. package/dist/components/tones/tokens.css +5 -5
  6. package/dist/components/ui/display/chip/chip-hairline.css +1 -1
  7. package/dist/components/ui/layout/sidebar/sidebar-tokens.css +1 -1
  8. package/dist/components/ui/overlays/dialog/dialog.css +2 -2
  9. package/dist/components/ui/primitives/field-box/field-box-tokens.css +1 -1
  10. package/dist/components/ui/primitives/toggle-group/toggle-group-segmented.css +2 -2
  11. package/dist/components/ui/primitives/toggle-group/toggle-group-separate.css +1 -1
  12. package/dist/components/ui/widgets/drawing/drawing-animate.css +123 -0
  13. package/dist/components/ui/widgets/drawing/drawing.css +459 -0
  14. package/dist/{components-CXpL1zEs.js → components-BX4icy-g.js} +734 -734
  15. package/dist/components.js +16 -16
  16. package/dist/{dialog-JQT6iETD.js → dialog-DdJ1C4BR.js} +168 -168
  17. package/dist/dnd.js +1 -1
  18. package/dist/draw-animate.js +106 -0
  19. package/dist/draw-png.js +2 -0
  20. package/dist/draw-sketch.js +38 -0
  21. package/dist/draw.js +65 -0
  22. package/dist/drawing-B8VuG7nx.js +390 -0
  23. package/dist/drawing-context-CeKeZE6b.js +10 -0
  24. package/dist/editor.js +110 -110
  25. package/dist/{icon-badge-C30yKsAM.js → icon-badge-Bb5-73XP.js} +18 -18
  26. package/dist/{icon-button-BXlI3DJ_.js → icon-button-5A6Mrj6w.js} +60 -90
  27. package/dist/lib/components/ui/display/shape/use-shape-morph.d.ts +1 -0
  28. package/dist/lib/components/ui/widgets/drawing/drawing-a11y.d.ts +20 -0
  29. package/dist/lib/components/ui/widgets/drawing/drawing-context.d.ts +23 -0
  30. package/dist/lib/components/ui/widgets/drawing/drawing-types.d.ts +63 -0
  31. package/dist/lib/components/ui/widgets/drawing/drawing.d.ts +17 -0
  32. package/dist/lib/components/ui/widgets/drawing/index.d.ts +5 -0
  33. package/dist/lib/components/ui/widgets/drawing/partials/drawing-root.d.ts +17 -0
  34. package/dist/lib/components/ui/widgets/drawing/partials/interactive-node.d.ts +22 -0
  35. package/dist/lib/components/ui/widgets/drawing/partials/primitives/content.d.ts +20 -0
  36. package/dist/lib/components/ui/widgets/drawing/partials/primitives/path.d.ts +29 -0
  37. package/dist/lib/components/ui/widgets/drawing/partials/primitives/primitive.d.ts +19 -0
  38. package/dist/lib/components/ui/widgets/drawing/partials/primitives/shapes.d.ts +18 -0
  39. package/dist/lib/components/ui/widgets/drawing/partials/react-attrs.d.ts +5 -0
  40. package/dist/lib/components/ui/widgets/drawing/partials/ring.d.ts +9 -0
  41. package/dist/lib/components/ui/widgets/drawing/partials/svg-tree.d.ts +29 -0
  42. package/dist/lib/components/ui/widgets/drawing/use-exact-text.d.ts +16 -0
  43. package/dist/lib/draw/index.d.ts +32 -0
  44. package/dist/lib/draw-animate/index.d.ts +19 -0
  45. package/dist/lib/draw-animate/morph-drawing.d.ts +32 -0
  46. package/dist/lib/draw-animate/reduced-motion.d.ts +2 -0
  47. package/dist/lib/draw-animate/use-drawing-controls.d.ts +27 -0
  48. package/dist/lib/draw-animate/use-scene-morph.d.ts +15 -0
  49. package/dist/lib/draw-png/index.d.ts +11 -0
  50. package/dist/lib/draw-sketch/index.d.ts +17 -0
  51. package/dist/lib/draw-sketch/sketch.d.ts +19 -0
  52. package/dist/lib/print/components/print-drawing.d.ts +16 -0
  53. package/dist/lib/print/index.d.ts +2 -1
  54. package/dist/main.js +21 -21
  55. package/dist/map.js +63 -63
  56. package/dist/material.css +1 -1
  57. package/dist/pdf-reader.js +1 -1
  58. package/dist/print.js +123 -115
  59. package/dist/{public-Cde8_SN8.js → public-CBlV2XuA.js} +742 -742
  60. package/dist/{sortable-provider-DYlpq8lP.js → sortable-provider-BvD98s8Y.js} +19 -19
  61. package/dist/{use-chat-composer-BwpSgP_D.js → use-chat-composer-BhdPNmYm.js} +912 -911
  62. package/dist/use-shape-morph-BKA_R5P5.js +35 -0
  63. package/docs/README.md +1 -0
  64. package/docs/components/data-display.md +2 -2
  65. package/docs/components/rich-widgets.md +196 -0
  66. package/docs/guides/drawing.md +499 -0
  67. package/docs/guides/printing.md +47 -0
  68. package/docs/guides/theming.md +86 -43
  69. package/docs/previews/rich-widgets-drawing.webp +0 -0
  70. package/docs/roadmap.md +17 -0
  71. package/docs/troubleshooting.md +166 -2
  72. package/lib/components/components.css +2 -0
  73. package/lib/components/theme-tokens.css +84 -72
  74. package/lib/components/tones/tokens.css +5 -5
  75. package/lib/components/ui/display/chip/chip-hairline.css +1 -1
  76. package/lib/components/ui/layout/sidebar/sidebar-tokens.css +1 -1
  77. package/lib/components/ui/overlays/dialog/dialog.css +2 -2
  78. package/lib/components/ui/primitives/field-box/field-box-tokens.css +1 -1
  79. package/lib/components/ui/primitives/toggle-group/toggle-group-segmented.css +2 -2
  80. package/lib/components/ui/primitives/toggle-group/toggle-group-separate.css +1 -1
  81. package/lib/components/ui/widgets/drawing/drawing-animate.css +123 -0
  82. package/lib/components/ui/widgets/drawing/drawing.css +459 -0
  83. package/package.json +22 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,97 @@
1
1
  # @nxgt/material
2
2
 
3
+ ## 3.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1362](https://github.com/softistx/nxgt-material/pull/1362) [`bd12b85`](https://github.com/softistx/nxgt-material/commit/bd12b85722ff941b4d0411c646ea547e69056c8e) Thanks [@SteveGT96](https://github.com/SteveGT96)! - Vector drawing in React, on the framework-free scenes of `@nxgt/material-core/draw`: accessible, themeable SVG that is strict-CSP safe (no inline `style`, no `<style>`) and hydration safe (no `<title>`, deterministic ids).
8
+
9
+ - `@nxgt/material/draw`: `Drawing` renders a `scene` of plain data or JSX primitives (`Rect`, `Ellipse`, `Circle`, `Line`, `Polygon`, `Path`, `Text`, `Group`, `Image`). Its type requires a `title` or `decorative`. Colours are theme roles, `tone()` or free colours, mapped to classes in `styles.css`, so a drawing follows light and dark. Interactive nodes are focusable buttons with a focus ring and Enter/Space, their events given by scene id (`handlers`, `onNodeClick`) or as primitive props. Wrapped text is laid out with Inter's metrics and refined by the browser once mounted (`exactText`). The builders, paints, `toSVG`, `shape`, `morph` and the layout helpers are re-exported by name from core.
10
+ - `@nxgt/material/draw/sketch`: `<Sketch seed fill>` and `sketch()`, the seeded hand-drawn style.
11
+ - `@nxgt/material/draw/animate`: `drawOn` and `appear` (animated by `styles.css`, stopped under reduced motion), `useDrawingControls(ref)` to replay, pause or finish them, `MorphDrawing` and `useSceneMorph` to spring between two scenes, `morphScenes`.
12
+ - `@nxgt/material/draw/png`: `drawingToPng` and `downloadDrawingPng`.
13
+ - `@nxgt/material/print`: the `drawing(scene, { width, align })` node and the `PrintDrawing` block, a vector drawing in a PDF document.
14
+
15
+ Nothing to change in an existing app: each is its own entry, not in `/components` or the main entry. Keep `@nxgt/material/styles.css` imported, and render `Drawing`, `Sketch` and the animation hooks from a `'use client'` file (the built entries carry no directive). `text` and `image` from `/draw` clash with `/print`'s: import one under another name (`import { text as drawText }`). See the Drawing guide (`docs/guides/drawing.md`).
16
+
17
+ ### Patch Changes
18
+
19
+ - [#1364](https://github.com/softistx/nxgt-material/pull/1364) [`174b543`](https://github.com/softistx/nxgt-material/commit/174b54343e62d9faa6451a24bace205b9975a503) Thanks [@SteveGT96](https://github.com/SteveGT96)! - Fix two contrast regressions of the violet-tinted neutrals. The dark `--error-text` is lightened (76 % `--error` mixed with white, was 80 %): 4.78:1 instead of 4.45:1 on a focused error menu item, and still above 5:1 on `--background` and `--card`. The light `--ring` (and `--sidebar-ring`) is darkened to `oklch(0.62 0.04 291)`, so the focus indicator reaches 3.4:1 on `--background`, 3.7:1 on `--card` and 3.2:1 on `--muted` (was 2.4, 2.7 and 2.3:1; WCAG 1.4.11). Fixes [#1363](https://github.com/softistx/nxgt-material/issues/1363).
20
+ - Updated dependencies [[`bd12b85`](https://github.com/softistx/nxgt-material/commit/bd12b85722ff941b4d0411c646ea547e69056c8e)]:
21
+ - @nxgt/material-core@0.27.0
22
+
23
+ ## 3.6.0
24
+
25
+ ### Minor Changes
26
+
27
+ - [#1358](https://github.com/softistx/nxgt-material/pull/1358) [`74ef6b1`](https://github.com/softistx/nxgt-material/commit/74ef6b152c24a7e94bdf709c66c846b019eb829d) Thanks [@SteveGT96](https://github.com/SteveGT96)! - The neutrals of both themes move from a blue slate (hue 247 to 266; the dark background was a deep navy) to a softly violet-tinted palette (hue about 290, low chroma). Primary, the status hues and the layout do not change; `@nxgt/material-vue` ships the same token file, so it follows.
28
+
29
+ Light, old to new:
30
+
31
+ | Token | Old | New |
32
+ | --- | --- | --- |
33
+ | `--background` | `oklch(1 0 0)` | `oklch(0.973 0.008 293.9)` (`#f6f5fb`) |
34
+ | `--foreground`, `--card-foreground`, `--popover-foreground`, `--accent-foreground`, `--sidebar-foreground`, `--sidebar-primary`, `--sidebar-accent-foreground` | `oklch(0.14 0.036 258.53)` / `oklch(0.129 0.042 264.695)` / `oklch(0.216 0.006 56.043)` / `oklch(0.208 0.042 265.755)` | `oklch(0.227 0.017 290)` |
35
+ | `--muted`, `--track`, `--sidebar-accent` | `oklch(0.968 0.007 247.896)` | `oklch(0.955 0.012 292)` |
36
+ | `--muted-foreground` | `oklch(0.52 0.046 257.417)` | `oklch(0.478 0.032 292)` |
37
+ | `--accent` | `oklch(0.9182 0.0077 228.86)` | `oklch(0.91 0.016 293)` |
38
+ | `--border`, `--input`, `--sidebar-border` | `oklch(0.929 0.013 255.508)` | `oklch(0.912 0.016 293.7)` |
39
+ | `--ring`, `--sidebar-ring` | `oklch(0.704 0.04 256.788)` | `oklch(0.704 0.04 291)` |
40
+ | `--sidebar` | `oklch(0.984 0.003 247.858)` | `oklch(0.985 0.006 293.9)` |
41
+ | `--tooltip` | `oklch(0.446 0.043 257.281)` | `oklch(0.446 0.043 291)` |
42
+ | `--secondary` / `--success` / `--info` | lightness 0.50 / 0.48 / 0.50 | 0.48 / 0.46 / 0.48 |
43
+ | `--primary-text` (light) | `var(--primary)` | `color-mix(in oklab, var(--primary) 96%, black)` (the fill `--primary` is unchanged) |
44
+ | `--nxgt-tone-ring-share` | `65%` | `68%` |
45
+ | `--nxgt-field-border` (light) | 13 % of `--foreground` | 14 % |
46
+ | `--error-text` | `color-mix(in oklab, var(--error) 94%, black)` | `... 92%, black)` |
47
+
48
+ Dark, old to new:
49
+
50
+ | Token | Old | New |
51
+ | --- | --- | --- |
52
+ | `--background` | `oklch(0.14 0.036 258.53)` | `oklch(0.192 0.016 290.5)` (`#14131b`) |
53
+ | `--card`, `--popover`, `--sidebar` | `oklch(0.208 0.042 265.755)` | `oklch(0.232 0.019 289.4)` (`#1d1c26`) |
54
+ | `--foreground`, `--card-foreground`, `--popover-foreground`, `--accent-foreground`, `--sidebar-foreground`, `--sidebar-accent-foreground` | `oklch(0.984 0.003 247.858)` / `oklch(0.985 0.001 106.423)` | `oklch(0.943 0.012 291.3)` (`#ecebf4`) |
55
+ | `--primary-foreground`, `--secondary-foreground`, `--success-foreground`, `--info-foreground`, `--warning-foreground`, `--error-foreground`, `--sidebar-primary-foreground` | `oklch(0.984 0.003 247.858)` | `oklch(0.995 0.002 291.3)` |
56
+ | `--tertiary-foreground` | `oklch(0.14 0.036 258.53)` | `oklch(0.192 0.016 290.5)` |
57
+ | `--muted`, `--sidebar-accent` | `oklch(0.279 0.041 260.031)` | `oklch(0.27 0.022 290)` |
58
+ | `--accent` | `oklch(0.268 0.007 34.298)` | `oklch(0.27 0.022 290)` |
59
+ | `--muted-foreground` | `oklch(0.66 0.046 257.417)` | `oklch(0.725 0.03 292.2)` |
60
+ | `--border`, `--sidebar-border` | `oklch(1 0 0 / 10%)` | `oklch(0.301 0.025 291.4)` (`#2e2c3a`) |
61
+ | `--input` | `oklch(1 0 0 / 15%)` | `oklch(0.34 0.027 291.4)` |
62
+ | `--ring`, `--sidebar-ring` | `oklch(0.551 0.027 264.364)` | `oklch(0.551 0.03 290)` |
63
+ | `--track` | `oklch(0.52 0.03 257.417)` | `oklch(0.53 0.03 290)` |
64
+ | `--tooltip` / `--tooltip-foreground` | `oklch(0.929 0.013 255.508)` / `oklch(0.446 0.043 257.281)` | `oklch(0.925 0.012 291.3)` / `oklch(0.446 0.043 291)` |
65
+ | `--secondary` | `oklch(0.66 0.1135 245.65)` | `oklch(0.675 0.1135 245.65)` |
66
+
67
+ The lightness nudges (light `--secondary`, `--success`, `--info`, `--error-text`; dark `--secondary`) keep every contrast the token comments and the theming guide state at 4.5:1 (text) or 3:1 (UI) on the new surfaces. The dialog scrim, the lightbox backdrop and a few shadows took the same hue.
68
+
69
+ To keep the old slate, redefine the tokens after importing the stylesheet, under the same selectors, with the values in the "Old" columns above, for example:
70
+
71
+ ```css
72
+ :root {
73
+ --background: oklch(1 0 0);
74
+ --foreground: oklch(0.14 0.036 258.53);
75
+ --muted: oklch(0.968 0.007 247.896);
76
+ --muted-foreground: oklch(0.52 0.046 257.417);
77
+ --border: oklch(0.929 0.013 255.508);
78
+ --input: oklch(0.929 0.013 255.508);
79
+ }
80
+ .dark,
81
+ [data-theme="dark"] {
82
+ --background: oklch(0.14 0.036 258.53);
83
+ --foreground: oklch(0.984 0.003 247.858);
84
+ --card: oklch(0.208 0.042 265.755);
85
+ --popover: oklch(0.208 0.042 265.755);
86
+ --muted: oklch(0.279 0.041 260.031);
87
+ --muted-foreground: oklch(0.66 0.046 257.417);
88
+ --border: oklch(1 0 0 / 10%);
89
+ --input: oklch(1 0 0 / 15%);
90
+ }
91
+ ```
92
+
93
+ Screenshot tests of an app on the default theme need new baselines.
94
+
3
95
  ## 3.5.0
4
96
 
5
97
  ### Minor Changes
package/README.md CHANGED
@@ -157,9 +157,11 @@ into a tarball. A missing sheet renders nothing, with no error and no fallback.
157
157
  | --- | --- |
158
158
  | `@nxgt/material` | Everything below in one barrel, plus the compiled `style` condition (`dist/material.css`, for apps without Tailwind) |
159
159
  | `@nxgt/material/components` | UI components, `*FormField` wrappers and `useCodeResolver` ([Components](#components)) |
160
- | `@nxgt/material/print` | PDF documents over `@react-pdf/renderer`: the `PrintDocument` page shell, the print blocks, and `PrintDataTable`, `PrintKeyValue` and `PrintMetric` from column definitions and plain rows; documents as plain data (`pdfDocument` and its builders); `downloadPdf`, `openPdf`, `usePdfFile` and `pdfResponse` to get the file in one call — **its own entry, and not in the barrel above** ([printing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/printing.md)) |
160
+ | `@nxgt/material/print` | PDF documents over `@react-pdf/renderer`: the `PrintDocument` page shell, the print blocks, `PrintDrawing` and the `drawing(scene)` node (a vector drawing from `@nxgt/material-core/draw` printed as vectors), and `PrintDataTable`, `PrintKeyValue` and `PrintMetric` from column definitions and plain rows; documents as plain data (`pdfDocument` and its builders); `downloadPdf`, `openPdf`, `usePdfFile` and `pdfResponse` to get the file in one call — **its own entry, and not in the barrel above** ([printing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/printing.md)) |
161
161
  | `@nxgt/material/pdf-reader` | `PdfReader`, the redesigned PDF reader (header, floating page pill, rail and panel; `embedded`, `dialog`, `page` and `fullscreen` modes; single page and two-page layouts; `look="expressive"` by default, `"classic"` to opt out, type `PdfReaderLook`) and `configurePdfReader` for pdf.js's worker and assets. **Its own entry, browser-only** (pdf.js loads on first render); also exported as `PdfReader` from `/components` since 3.0 ([guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/pdf-reader.md)) |
162
162
  | `@nxgt/material/charts` | Native SVG charts (d3-scale and d3-shape for the maths only) with keyboard point navigation, a screen-reader summary, a "View data" table and `patterns`: `LineChart` and `AreaChart` (`LineChartProps`, `AreaChartProps`, `ChartCurve`), `BarChart` (`BarChartProps`, `BarLayout`, `BarOrientation`), `PieChart` (`PieChartProps`), `DonutChart` (`DonutChartProps`), `Gauge` (`GaugeProps`, `GaugeSize`), `RadialBarChart` (`RadialBarChartProps`), `FunnelChart` (`FunnelChartProps`), `HeatmapChart` (`HeatmapChartProps`, `HeatColumn`), `RadarChart` (`RadarChartProps`), `ScatterChart` (`ScatterChartProps`, `ScatterSeries`, `ScatterPoint`), `ComboChart` (`ComboChartProps`, `ComboSeries`: bars, areas and lines, each on a left or a right axis), `zoom` (a mini overview with a window and two slider handles that picks the rows shown; `range`, `defaultRange`, `onRangeChange`) and `scroll` (a dense plot scrolls sideways on a phone, the value axis pinned) on the line, area, bar and combo charts (`ChartRangeProps`, `ChartZoomOptions`, `ChartScrollOptions`, `ChartRange`), `onPointClick` on every chart but `Gauge`, `palette` (`'soft'`: the soft palette, or `data-chart-palette="soft"` on an ancestor; `ChartPalette`) on every chart, and the shared types (`ChartSlice`, `ChartRow`, `ChartValue`, `ChartColor`, `ChartShape`, `ChartSeries`, `ChartAxis`, `ChartXAxis`, `ChartPoint`, `ChartBaseProps`). `categoryLabel` names the "View data" table's category column: on Line, Area, Bar and Combo it defaults to the x axis label, on Radar and Heatmap it is always "Category" unless set. **Its own entry, client-only** (import it from a `'use client'` file), not in the barrel above; replaces the Nivo charts (removed in 3.0) of `/components` ([guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/charts.md)) |
163
+ | `@nxgt/material/draw` | Vector drawing: a scene of plain data or JSX primitives drawn as accessible, themeable SVG that is safe under a strict CSP and identical on the server and in the browser. `Drawing` (`DrawingProps`, `NodeHandlers`; `scene` or `w`/`h` with children; a `title` or `decorative`, enforced by the type), the primitives `Rect`, `Ellipse`, `Circle`, `Line`, `Polygon`, `Path` (takes `node`), `Text`, `Group` and `Image`, and the builders of `@nxgt/material-core/draw` re-exported by name (`scene`, `rect`, `ellipse`, `circle`, `line`, `polygon`, `path`, `text`, `group`, `image`, `linear`, `radial`, `pattern`, `hatch`, `tone`, `toSVG`, `compileScene`, `ROLES`, `DRAW_PALETTE`, and the types `Scene`, `DrawNode`, `Paint`, `Role`, `ToneRef`), plus Material 3 Expressive's shapes (`shape`, `morph`, `SHAPE_NAMES`, `toCubics`) and the layout helpers (`bbox`, `stack`, `grid`, `align`, `distribute`) re-exported by name. Colours are theme roles (`primary-container`, `on-surface`...) mapped to classes in `styles.css`, so import it. Interactive nodes are focusable `button`s with a focus ring; wrapped text is re-measured by the browser once mounted. **Its own entry, client-only** (render `Drawing` from a `'use client'` file; the builders and `toSVG` run anywhere), not in the barrel above ([drawing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/drawing.md)) |
164
+ | `@nxgt/material/draw/sketch` | The sketchy, hand-drawn style for a drawing: `Sketch` (`seed`, `roughness`, `bowing`, `fill`: `hachure`, `cross-hatch`, `solid` or `none`, `hachureAngle`, `hachureGap`, `strokeWidth`) wraps a `Drawing`, or primitives inside one, and draws shapes as double wobbling strokes with hatched fills; `sketch(sceneOrNode, options)` does it to plain data for `toSVG`. Seeded, so the server and the client draw the same lines; ids, labels, focus rings and events keep working. **Its own entry, client-only** (render `Sketch` from a `'use client'` file), not in the barrel above ([drawing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/drawing.md#sketch)) |
163
165
  | `@nxgt/material/map` | Leaflet maps, markers, a location field — **its own entry, not in the barrel, and browser-only** ([maps guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/maps.md)) |
164
166
  | `@nxgt/material/backgrounds` | Background presets: `Background` (a superset of the `/components` one: `preset`, `animated`, `grain`, `seed`, `fill` and `motif`), `AVAILABLE_BACKGROUND_PRESETS` and `AvailableBackgroundPreset` (the 44 ids `Background` draws), `MOTIF_SHAPES_ALL` (the 22 motif shapes), the types and tables (`BACKGROUND_PRESETS`, `BACKGROUND_TONES`, ...) re-exported from `@nxgt/material-core/backgrounds`; its own entry, with an opt-in stylesheet ([backgrounds guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/backgrounds.md)) |
165
167
  | `@nxgt/material/editor` | The rich text editor: `DocumentEditor` and `DocumentEditorFormField` (with an `outline`, a block handle, focus mode, find and replace, `onUpload`, `onAssist` and `comments`), `CompactEditor` and `CompactEditorFormField`, `RichChatComposer`, `EditorRoot` and the parts (`EditorToolbar`, `EditorContent`, `EditorFooter`, `EditorAssistantPanel`, ...), `useEditor`, the kits (`documentKit`, `compactKit`, `chatKit`, `formNodesKit`), `withFeatures` / `withoutFeatures` and `defineFeature`, and the converters `toHtml`, `toJson`, `toMarkdown`, `fromMarkdown` and `looksLikeMarkdown` — **its own entry, and not in the barrel above**. **Client-only**: import it from a `'use client'` file; `/editor/viewer` is the server-safe one. The `.nxgt-prose` page styles ship in `styles.css` with the component CSS ([DocumentEditor](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#documenteditor)) |
@@ -168,6 +170,8 @@ into a tarball. A missing sheet renders nothing, with no error and no fallback.
168
170
  | `@nxgt/material/editor/collab` | `collaboration({ doc, provider, user, seed, ready, field })`: real-time editing of a Yjs document **your app supplies** (the library ships no server and no provider), for `DocumentEditor`'s `collaboration` prop; carets, undo and the `EditorPresence` avatars and connection chip (`useEditorPresence` for your own UI; both from `/editor`). Its own entry with optional peers `yjs` and `y-protocols` ([Collaboration](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#collaboration)) |
169
171
  | `@nxgt/material/editor/pm` | The editor's own tiptap and ProseMirror (`Extension`, `Node`, `Mark`, `mergeAttributes`, the input and paste rules, `Plugin`, `PluginKey`, `TextSelection`, `NodeSelection`, `ProseMirrorNode`, `Fragment`, `Slice`, `Decoration`, `DecorationSet`, …) for a custom feature's extensions, so its `instanceof` checks and the nodes it builds agree with the editor. Shares the editor's code (next to `/editor`, a list of exports, not a second copy), **server-safe** ([A custom feature](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#a-custom-feature)) |
170
172
  | `@nxgt/material/media-hls` | `hlsStreaming()` (options `HlsStreamingOptions`, module type `HlsModule`), the HLS adapter for `MediaPlayer`'s `streaming` prop: `hls.js` (an optional peer) loaded lazily wherever the browser has MSE, native HLS otherwise (or with `preferNative`), its levels as the quality menu; its own entry ([streaming guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/media-streaming.md)) |
173
+ | `@nxgt/material/draw/animate` | Animation for `/draw`: `drawOn(scene)` traces strokes and `appear(scene)` fades nodes in, one after the next (`staggerSteps`; they add class names that `styles.css` animates, so a server renders them and there is no inline style); `useDrawingControls(ref)` replays, pauses, plays and finishes them (Web Animations); `morphScenes(a, b, t)`, `useSceneMorph(from, to, active)` and `MorphDrawing` (`from`, `to`, `active`) spring one scene into another. All stop under reduced motion and show the last frame; its own entry, client-only for the hooks ([drawing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/drawing.md#animate), [reference](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/docs/draw.md#animation-nxgtmaterial-coredrawanimate)) |
174
+ | `@nxgt/material/draw/png` | `drawingToPng(sceneOrSvg, { scale?, background?, colorsFrom? })` and `downloadDrawingPng(source, fileName)` — a drawing (a scene, or a live `<svg>` such as `svgRef.current` of a `<Drawing ref={svgRef}>`) as a PNG `Blob` in the browser, with the page's theme colours resolved, `data:` images inlined and CORS errors named; its own entry, DOM only when called ([drawing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/drawing.md#png), [reference](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/docs/draw.md#png-nxgtmaterial-coredrawpng)) |
171
175
  | `@nxgt/material/vite` | build-time helpers for consumers: `nxgtMaterial()` (a strict CSP by hash or nonce, self-hosted fonts, a styles check, serves the pdf.js worker on the Vite 5–7 dev server, PDFs on a bundled server with `nxgtMaterial({ pdf: { bundle: true } })`: [Vite plugin guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/vite-plugin.md)), `pdfkitStandardFonts()` ([printing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/printing.md)), `cspAssetsInlineLimit`, a `build.assetsInlineLimit` that never inlines a font ([CSP guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/csp.md#katex-fonts)) |
172
176
  | `@nxgt/material/next` | `withNxgtPrint(nextConfig)`: the `next.config.ts` a Next.js route handler that imports `/print` needs, `output: 'standalone'` included. Node only, no dependency on `next` ([printing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/printing.md#nextjs-serverexternalpackages-and-output-standalone)) |
173
177
  | `@nxgt/material/hooks` | `useTheme`, `useIsClient`, `useIsMobile`, `useLocalizedDate`, `useCspNonce`, `useFocusOnMount`, `useSubmitOnce`, … ([helpers](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/helpers.md#nxgtmaterialhooks)) |
@@ -301,6 +305,45 @@ It adds `'@nxgt/material'` to `serverExternalPackages` and, when
301
305
  `outputFileTracingIncludes`, merged with what your config already has. More:
302
306
  [Next.js](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/printing.md#nextjs-serverexternalpackages-and-output-standalone).
303
307
 
308
+ ### Drawings
309
+
310
+ `@nxgt/material/draw` draws a scene (plain data) or JSX primitives as accessible
311
+ SVG in the theme's colours, with no inline `style`, so it is safe under a strict
312
+ CSP and the same on the server and in the browser. Render `Drawing` from a
313
+ `'use client'` file; colour roles come from `styles.css`.
314
+
315
+ ```tsx
316
+ 'use client';
317
+
318
+ import { Drawing, path, rect, scene, text, tone } from '@nxgt/material/draw';
319
+
320
+ const flow = scene({ w: 240, h: 120 }, [
321
+ rect({ x: 8, y: 8, w: 224, h: 104, r: 16, fill: 'primary-container', stroke: 'outline' }),
322
+ path((p) => p.moveTo(24, 90).curveTo(60, 20, 120, 20, 200, 60), {
323
+ stroke: tone('success'),
324
+ strokeWidth: 3,
325
+ arrow: { end: 'triangle' },
326
+ }),
327
+ text('Shipped', { x: 120, y: 64, anchor: 'middle', size: 18, weight: 600, fill: 'on-primary-container' }),
328
+ ]);
329
+
330
+ export const Flow = () => <Drawing scene={flow} title="Release flow" />;
331
+ ```
332
+
333
+ Three more entries, each loaded only by the apps that use it:
334
+
335
+ ```tsx
336
+ import { Sketch } from '@nxgt/material/draw/sketch'; // hand-drawn: <Sketch seed={7}><Drawing … /></Sketch>
337
+ import { drawOn, useDrawingControls } from '@nxgt/material/draw/animate'; // <Drawing scene={drawOn(flow)} … />
338
+ import { downloadDrawingPng } from '@nxgt/material/draw/png'; // await downloadDrawingPng(flow, 'release-flow')
339
+ ```
340
+
341
+ `toSVG(flow, { standalone: true, theme: 'light' })` (from `@nxgt/material/draw`)
342
+ gives an SVG string with literal colours, for a file or an e-mail, and `drawing(flow)`
343
+ from `@nxgt/material/print` puts it in a PDF as vectors. The
344
+ [drawing guide](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/drawing.md)
345
+ covers colours, accessibility, events, sketch, animation, PNG, PDF and e-mail.
346
+
304
347
  ## Guides
305
348
 
306
349
  Each area a consumer starts from has its own page under `docs/guides/`.
@@ -314,6 +357,7 @@ Each area a consumer starts from has its own page under `docs/guides/`.
314
357
  | [Printing](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/printing.md) | producing PDFs with `@nxgt/material/print` and getting the file in one call (download, new tab, preview, server `Response`) — its own entry since 2.0.0, with optional peers, a bundling trap on SSR servers, and the `next.config.ts` a Next.js route handler (and `output: 'standalone'`) needs |
315
358
  | [Maps](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/maps.md) | using `@nxgt/material/map` — browser-only, optional leaflet peers, `map.css` |
316
359
  | [Charts](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/charts.md) | drawing charts with `@nxgt/material/charts` (client-only): the twelve charts, shared props, legend, View data, `onPointClick`, zoom and phone scroll, right-to-left pages, keyboard and accessibility, theming the `--chart-*` tokens, and migrating from the Nivo charts, removed in 3.0 |
360
+ | [Drawing](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/drawing.md) | drawing diagrams, badges and illustrations from code with `@nxgt/material/draw`: a scene or JSX, theme roles and tones, strict CSP, accessibility, events, sketch, animation, PNG, PDF and e-mail |
317
361
  | [Backgrounds](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/backgrounds.md) | tones, intensity, the opt-in `backgrounds.css` and per-preset files, custom tone tokens, motion and CSP |
318
362
  | [Media players](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/media.md) | `MediaPlayer`, `AudioPlayer`, playlists, chapters and transcript, sound that keeps playing across pages (`MediaPlayerHost`), the lightbox, HLS, CSP and keyboard |
319
363
  | [Streaming (HLS)](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/guides/media-streaming.md) | `hlsStreaming()` from `@nxgt/material/media-hls`, the optional `hls.js` peer, native HLS, the quality menu, the CSP worker line |
@@ -626,6 +670,7 @@ Not components: what the stylesheet gives any element.
626
670
  | <img src="https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/previews/rich-widgets-codeeditor.webp" width="120" alt="CodeEditor"> | [`CodeEditor`](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#codeeditor) · `CodeEditorFormField` | Monaco code field in theme presets (App, Moonlight, Soft, or your own `defineCodeTheme`), with a floating tool pill, a status bar, `markers` for your own problems, a `readOnly` reader look, view props, a `ref` handle, file tabs (`files`) and full screen. From `@nxgt/material/code-editor`. | `CodeEditor`, `CodeEditorFormField` |
627
671
  | <img src="https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/previews/rich-widgets-codeeditor-diff.webp" width="120" alt="CodeDiff"> | [`CodeDiff`](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#codediff) | A Monaco diff in the code editor's frame and themes: side by side or inline (always inline on a phone), previous/next change, `+N −M` counts and copy. From `@nxgt/material/code-editor`. | `CodeDiff` |
628
672
  | <img src="https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/previews/rich-widgets-quiz.webp" width="120" alt="Quiz"> | [`Quiz`](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#quiz), `QuestionCard` | Exam or practice quizzes: step progress, instant feedback with explanations and hints, a time limit, keyboard shortcuts, and a results screen with a score ring, a breakdown and a retry of the misses. Container queries. | `Quiz`, `QuestionCard` (modes and results: React only for now) |
673
+ | <img src="https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/previews/rich-widgets-drawing.webp" width="120" alt="Drawing"> | [`Drawing`, `Rect`, `Ellipse`, `Circle`, `Line`, `Polygon`, `Path`, `Text`, `Group`, `Image`](https://cdn.jsdelivr.net/npm/@nxgt/material@3/docs/components/rich-widgets.md#drawing) from `@nxgt/material/draw` | Vector drawings from a scene of plain data or from JSX: theme-role colours that follow light and dark, no inline style (strict CSP), a `title` or `decorative` enforced by the type, focusable nodes with `onClick` and a focus ring, text that wraps with Inter's metrics and is refined by the browser. Client-only entry. | React only for now |
629
674
 
630
675
  `RadioGroupField`, `SliderField` and `SwitchField` are aliases of the
631
676
  labelled `RadioGroup`, `Slider` and `Switch`, under the names
@@ -196,3 +196,5 @@
196
196
  @import "../backgrounds/css/base.css";
197
197
  @import "../backgrounds/css/gradient.css";
198
198
  @import "../backgrounds/css/motion.css";
199
+ @import "./ui/widgets/drawing/drawing.css"; /* @nxgt/material/draw: role colours, focus ring */
200
+ @import "./ui/widgets/drawing/drawing-animate.css";
@@ -3,52 +3,59 @@
3
3
  * after importing the stylesheet, under the same selectors. */
4
4
  :root {
5
5
  --radius: 0.625rem;
6
- --background: oklch(1 0 0);
7
- --foreground: oklch(0.14 0.036 258.53);
6
+ --background: oklch(0.973 0.008 293.9);
7
+ --foreground: oklch(0.227 0.017 290);
8
8
  --card: oklch(1 0 0);
9
- --card-foreground: oklch(0.129 0.042 264.695);
9
+ --card-foreground: oklch(0.227 0.017 290);
10
10
  --strix: oklch(45.91% 0.1864 310.75);
11
11
  --popover: oklch(1 0 0);
12
- --popover-foreground: oklch(0.129 0.042 264.695);
12
+ --popover-foreground: oklch(0.227 0.017 290);
13
13
  --primary: oklch(46% 0.1135 276.35);
14
14
  --primary-foreground: oklch(0.984 0.003 247.858);
15
15
  /* Primary drawn as text or an icon on a normal surface (`text-primary-text`):
16
- the colour itself in light; the dark theme lifts it. */
17
- --primary-text: var(--primary);
18
- --secondary: oklch(50% 0.1135 245.65);
16
+ the colour mixed 4 % toward black in light, which keeps it 7.3:1 or more on
17
+ the violet page (7.9:1 on a Card; the colour itself gives 6.8:1 on the
18
+ page); the dark theme lifts it. */
19
+ --primary-text: color-mix(in oklab, var(--primary) 96%, black);
20
+ /* --secondary, --success and --info are 0.02 darker than before: on the
21
+ violet page tint (--background, 97.3 %) their own 15 % tonal tint gave the
22
+ text 4.3 to 4.5:1; now 4.7:1 or more on the page and on a Card. */
23
+ --secondary: oklch(48% 0.1135 245.65);
19
24
  --secondary-foreground: oklch(0.984 0.003 247.858);
20
- --muted: oklch(0.968 0.007 247.896);
21
- --muted-foreground: oklch(0.52 0.046 257.417);
25
+ --muted: oklch(0.955 0.012 292);
26
+ --muted-foreground: oklch(0.478 0.032 292);
22
27
  /* Non-text (WCAG 1.4.11): the empty part of a slider, a meter, a drawer
23
28
  handle. Light keeps the pale track; the value reads from the thumb. */
24
- --track: oklch(0.968 0.007 247.896);
29
+ --track: oklch(0.955 0.012 292);
25
30
  --track-fill: var(--primary);
26
- --tooltip: oklch(0.446 0.043 257.281);
31
+ --tooltip: oklch(0.446 0.043 291);
27
32
  --tooltip-foreground: oklch(1 0 0);
28
- --accent: oklch(0.9182 0.0077 228.86);
29
- --accent-foreground: oklch(0.216 0.006 56.043);
33
+ --accent: oklch(0.91 0.016 293);
34
+ --accent-foreground: oklch(0.227 0.017 290);
30
35
  /* Darker than the dark theme's: near-white text on a filled error surface
31
36
  reaches 4.8:1 (4.6 at 0.577), and the colour as text 5.0:1 on white. */
32
37
  --error: oklch(0.56 0.245 27.325);
33
38
  --error-foreground: oklch(0.984 0.003 247.858);
34
39
  /* Error drawn as text (a field's message, HelperText, a focused error menu
35
- item): 5.7:1 on white and 4.8:1 on the menu's bg-error/10 tint, where
36
- --error itself gives 5.0 and 4.2:1. */
37
- --error-text: color-mix(in oklab, var(--error) 94%, black);
40
+ item): 6.0:1 on white and 5.0:1 on the menu's bg-error/10 tint (4.7:1 on that
41
+ tint over the violet page), where --error itself gives 5.0 and 4.2:1. */
42
+ --error-text: color-mix(in oklab, var(--error) 92%, black);
38
43
  /* The foregrounds are near-white: these three are dark enough for WCAG AA
39
44
  text (4.5:1) on them, and for the same colours used as text on white. */
40
- --success: oklch(0.48 0.118 184.704);
45
+ --success: oklch(0.46 0.118 184.704);
41
46
  --success-foreground: oklch(0.984 0.003 247.858);
42
- --info: oklch(0.5 0.165 254.624);
47
+ --info: oklch(0.48 0.165 254.624);
43
48
  --info-foreground: oklch(0.984 0.003 247.858);
44
49
  /* Amber, a hue apart from --error (27): a warning must not read as a
45
50
  failure. 5.7:1 as text on white, 5.0:1 on its 10% tint, 5.5:1 under near-white text. */
46
51
  --warning: oklch(0.52 0.13 62);
47
52
  --warning-foreground: oklch(0.984 0.003 247.858);
48
53
  --destructive: var(--error);
49
- --border: oklch(0.929 0.013 255.508);
50
- --input: oklch(0.929 0.013 255.508);
51
- --ring: oklch(0.704 0.04 256.788);
54
+ --border: oklch(0.912 0.016 293.7);
55
+ --input: oklch(0.912 0.016 293.7);
56
+ /* The focus indicator (WCAG 1.4.11, 3:1): 3.40:1 on --background, 3.69:1 on
57
+ --card, 3.23:1 on --muted. */
58
+ --ring: oklch(0.62 0.04 291);
52
59
  --chart-1: oklch(0.646 0.222 41.116);
53
60
  --chart-2: oklch(0.6 0.118 184.704);
54
61
  --chart-3: oklch(0.398 0.07 227.392);
@@ -74,63 +81,68 @@
74
81
  --chart-soft-4-ink: oklch(0.52 0.16 310);
75
82
  --chart-soft-5: oklch(0.9 0.05 25);
76
83
  --chart-soft-5-ink: oklch(0.56 0.15 25);
77
- --sidebar: oklch(0.984 0.003 247.858);
78
- --sidebar-foreground: oklch(0.129 0.042 264.695);
79
- --sidebar-primary: oklch(0.208 0.042 265.755);
84
+ --sidebar: oklch(0.985 0.006 293.9);
85
+ --sidebar-foreground: oklch(0.227 0.017 290);
86
+ --sidebar-primary: oklch(0.227 0.017 290);
80
87
  --sidebar-primary-foreground: oklch(0.984 0.003 247.858);
81
- --sidebar-accent: oklch(0.968 0.007 247.896);
82
- --sidebar-accent-foreground: oklch(0.208 0.042 265.755);
83
- --sidebar-border: oklch(0.929 0.013 255.508);
84
- --sidebar-ring: oklch(0.704 0.04 256.788);
88
+ --sidebar-accent: oklch(0.955 0.012 292);
89
+ --sidebar-accent-foreground: oklch(0.227 0.017 290);
90
+ --sidebar-border: oklch(0.912 0.016 293.7);
91
+ --sidebar-ring: oklch(0.62 0.04 291);
85
92
  }
86
93
 
87
94
  .dark,
88
95
  [data-theme="dark"] {
89
- --background: oklch(0.14 0.036 258.53);
90
- --foreground: oklch(0.984 0.003 247.858);
91
- --card: oklch(0.208 0.042 265.755);
92
- --card-foreground: oklch(0.984 0.003 247.858);
93
- --popover: oklch(0.208 0.042 265.755);
94
- --popover-foreground: oklch(0.984 0.003 247.858);
96
+ --background: oklch(0.192 0.016 290.5);
97
+ --foreground: oklch(0.943 0.012 291.3);
98
+ --card: oklch(0.232 0.019 289.4);
99
+ --card-foreground: oklch(0.943 0.012 291.3);
100
+ --popover: oklch(0.232 0.019 289.4);
101
+ --popover-foreground: oklch(0.943 0.012 291.3);
95
102
  --primary: oklch(46% 0.1135 276.35);
96
- --primary-foreground: oklch(0.984 0.003 247.858);
103
+ --primary-foreground: oklch(0.995 0.002 291.3);
97
104
  /* Mixed 60 % toward white (the tonal Button labels' recipe): readable as text
98
105
  on --background and --card. */
99
106
  --primary-text: color-mix(in oklab, var(--primary) 40%, white);
100
- /* Brighter than the light one: it is read as text on the dark surfaces (6.5:1
101
- on --background, 5.8:1 on --card); a filled secondary surface mixes it toward --background
102
- (the opaque 70 % mix) to keep 5.2:1 under its near-white text. */
103
- --secondary: oklch(0.66 0.1135 245.65);
104
- --secondary-foreground: oklch(0.984 0.003 247.858);
105
- --muted: oklch(0.279 0.041 260.031);
106
- --muted-foreground: oklch(0.66 0.046 257.417);
107
- /* 3.6:1 on --background, 3.2:1 on --card; the fill 3.4:1 on the track. */
108
- --track: oklch(0.52 0.03 257.417);
107
+ /* Brighter than the light one: it is read as text on the dark surfaces (6.3:1
108
+ on --background, 5.8:1 on --card; 4.6:1 on its own 15 % tonal tint over a
109
+ Card). A filled secondary surface mixes it toward --background (the opaque
110
+ 70 % mix) to keep 5.2:1 under its near-white text (4.9:1 over a Card). */
111
+ --secondary: oklch(0.675 0.1135 245.65);
112
+ --secondary-foreground: oklch(0.995 0.002 291.3);
113
+ --muted: oklch(0.27 0.022 290);
114
+ --muted-foreground: oklch(0.725 0.03 292.2);
115
+ /* 3.5:1 on --background, 3.2:1 on --card; the fill 3.3:1 on the track. */
116
+ --track: oklch(0.53 0.03 290);
109
117
  --track-fill: oklch(0.85 0.09 276.35);
110
- --tooltip: oklch(0.929 0.013 255.508);
111
- --tooltip-foreground: oklch(0.446 0.043 257.281);
112
- --accent: oklch(0.268 0.007 34.298);
113
- --accent-foreground: oklch(0.985 0.001 106.423);
118
+ --tooltip: oklch(0.925 0.012 291.3);
119
+ --tooltip-foreground: oklch(0.446 0.043 291);
120
+ --accent: oklch(0.27 0.022 290);
121
+ --accent-foreground: oklch(0.943 0.012 291.3);
114
122
  --error: oklch(0.577 0.245 27.325);
115
- --error-foreground: oklch(0.984 0.003 247.858);
123
+ --error-foreground: oklch(0.995 0.002 291.3);
116
124
  /* --error stays the fill under near-white text; as text it would give only
117
- 4.2:1 on --background and 3.8:1 on --card. Lightened, 5.9 and 5.3:1. */
118
- --error-text: color-mix(in oklab, var(--error) 80%, white);
125
+ 3.9:1 on --background and 3.5:1 on --card. Lightened (76 % --error), 5.85
126
+ and 5.35:1, and 4.78:1 on a focused error menu item (bg-error/20 over the
127
+ popover; 4.45:1 at the former 80 %, which missed 4.5:1 once rendered). */
128
+ --error-text: color-mix(in oklab, var(--error) 76%, white);
119
129
  /* The light brights: on the dark surfaces they read as text and as the
120
- badge's 60% tint, which keeps its contrast (7.3, 5.7 and 7.5:1). */
130
+ badge's 60% tint, which keeps its contrast under near-white text (success
131
+ 7.1:1, info 5.6:1, error 9.1:1). */
121
132
  --success: oklch(0.6 0.118 184.704);
122
- --success-foreground: oklch(0.984 0.003 247.858);
133
+ --success-foreground: oklch(0.995 0.002 291.3);
123
134
  --info: oklch(0.707 0.165 254.624);
124
- --info-foreground: oklch(0.984 0.003 247.858);
125
- /* Amber too, as text: 7.3:1 on --background and 6.5:1 on --card, 6.6:1 and
126
- 5.8:1 on its 10% tint; the badge's 60% fill under near-white text is
127
- 6.0:1 on a page and 5.6:1 on a Card. */
135
+ --info-foreground: oklch(0.995 0.002 291.3);
136
+ /* Amber too, as text: 6.7:1 on --background and 6.1:1 on --card, 5.9:1 and
137
+ 5.3:1 on its 10% tint; the badge's 60% fill under near-white text is
138
+ 5.8:1 on a page and 5.5:1 on a Card. */
128
139
  --warning: oklch(0.7 0.15 70);
129
- --warning-foreground: oklch(0.984 0.003 247.858);
140
+ --warning-foreground: oklch(0.995 0.002 291.3);
130
141
  --destructive: oklch(0.704 0.191 22.216);
131
- --border: oklch(1 0 0 / 10%);
132
- --input: oklch(1 0 0 / 15%);
133
- --ring: oklch(0.551 0.027 264.364);
142
+ --border: oklch(0.301 0.025 291.4);
143
+ --input: oklch(0.34 0.027 291.4);
144
+ /* 3.78:1 on --background, 3.45:1 on --card, 3.09:1 on --muted. */
145
+ --ring: oklch(0.551 0.03 290);
134
146
  --chart-1: oklch(0.488 0.243 264.376);
135
147
  --chart-2: oklch(0.696 0.17 162.48);
136
148
  --chart-3: oklch(0.769 0.188 70.08);
@@ -138,7 +150,7 @@
138
150
  --chart-5: oklch(0.645 0.246 16.439);
139
151
  /* The soft palette on the dark card: mid-tone fills (L 0.49, the sand a
140
152
  warmer 0.5 0.1 75), light inks of the same hues. Ink on the card:
141
- 1 8.90:1, 2 10.01, 3 10.80, 4 8.48, 5 8.52; at the 0.85 dim 6.44:1 or
153
+ 1 8.44:1, 2 9.46, 3 10.17, 4 8.03, 5 8.06; at the 0.85 dim 6.17:1 or
142
154
  more. Ink on its own fill (the outline): 1 3.13:1, 2 3.40, 3 3.69,
143
155
  4 3.11, 5 3.13. Every pair at least 54 degrees and ΔEOK 0.109 apart. */
144
156
  --chart-soft-1: oklch(0.49 0.08 255);
@@ -151,14 +163,14 @@
151
163
  --chart-soft-4-ink: oklch(0.78 0.13 310);
152
164
  --chart-soft-5: oklch(0.49 0.09 25);
153
165
  --chart-soft-5-ink: oklch(0.78 0.11 25);
154
- --sidebar: oklch(0.208 0.042 265.755);
155
- --sidebar-foreground: oklch(0.984 0.003 247.858);
166
+ --sidebar: oklch(0.232 0.019 289.4);
167
+ --sidebar-foreground: oklch(0.943 0.012 291.3);
156
168
  --sidebar-primary: oklch(0.488 0.243 264.376);
157
- --sidebar-primary-foreground: oklch(0.984 0.003 247.858);
158
- --sidebar-accent: oklch(0.279 0.041 260.031);
159
- --sidebar-accent-foreground: oklch(0.984 0.003 247.858);
160
- --sidebar-border: oklch(1 0 0 / 10%);
161
- --sidebar-ring: oklch(0.551 0.027 264.364);
169
+ --sidebar-primary-foreground: oklch(0.995 0.002 291.3);
170
+ --sidebar-accent: oklch(0.27 0.022 290);
171
+ --sidebar-accent-foreground: oklch(0.943 0.012 291.3);
172
+ --sidebar-border: oklch(0.301 0.025 291.4);
173
+ --sidebar-ring: oklch(0.551 0.03 290);
162
174
  }
163
175
 
164
176
  /* The tertiary colour (the strix violet), for accents and backgrounds beside
@@ -168,10 +180,10 @@
168
180
  --tertiary-foreground: oklch(0.984 0.003 247.858);
169
181
  }
170
182
 
171
- /* Dark: lifted like --secondary, as it is read as text (7.0:1 on --background,
172
- 6.3:1 on --card); its foreground is the dark surface, 7.0:1 on the fill. */
183
+ /* Dark: lifted like --secondary, as it is read as text (6.5:1 on --background,
184
+ 5.9:1 on --card); its foreground is the dark surface, 6.5:1 on the fill. */
173
185
  .dark,
174
186
  [data-theme="dark"] {
175
187
  --tertiary: oklch(0.7 0.15 310.75);
176
- --tertiary-foreground: oklch(0.14 0.036 258.53);
188
+ --tertiary-foreground: oklch(0.192 0.016 290.5);
177
189
  }
@@ -23,14 +23,14 @@
23
23
  * one, which the zone never touches. */
24
24
  --nxgt-tint-status: 20%;
25
25
  /* The share of the tone's text colour in a hairline (--nxgt-tone-ring): 3:1
26
- * or more against the surface in light and dark at 65 %. */
27
- --nxgt-tone-ring-share: 65%;
26
+ * or more against the surface in light and dark at 68 %. */
27
+ --nxgt-tone-ring-share: 68%;
28
28
 
29
29
  /* Neutral, the grey tone: the muted foreground, on the page colour. */
30
30
  --neutral: var(--muted-foreground);
31
31
  --neutral-foreground: var(--background);
32
32
 
33
- /* Text: the tone darkened (80 % tone, 20 % black), 6.6:1 or more on
33
+ /* Text: the tone darkened (80 % tone, 20 % black), 6.1:1 or more on
34
34
  * --background and --card and on its own container (over either). Primary and error keep
35
35
  * the tokens theme-tokens.css defines. */
36
36
  --secondary-text: color-mix(in oklab, var(--secondary) 80%, black);
@@ -88,8 +88,8 @@
88
88
  --neutral-text: color-mix(in oklab, var(--neutral) 75%, white);
89
89
 
90
90
  /* On the fill: the dark theme lifts these tones, and near-white on them
91
- * would give 2.5 to 3.5:1. The page colour is 5.4:1 or more on each.
92
- * Primary, tertiary and error keep their foreground (7.0, 7.0, 4.6:1). */
91
+ * would give 2.5 to 3.5:1. The page colour is 5.0:1 or more on each.
92
+ * Primary, tertiary and error keep their foreground (7.2, 6.5, 4.7:1). */
93
93
  --primary-on: var(--primary-foreground);
94
94
  --tertiary-on: var(--tertiary-foreground);
95
95
  --error-on: var(--error-foreground);
@@ -27,7 +27,7 @@
27
27
  --chip-face: var(--background);
28
28
  border-color: var(--chip-line);
29
29
  background: var(--chip-face);
30
- box-shadow: 0 1px 1px oklch(0.2 0.03 265 / 0.05);
30
+ box-shadow: 0 1px 1px oklch(0.2 0.03 290 / 0.05);
31
31
  }
32
32
  .nxgt-chip[data-look="hairline"][data-size="sm"] {
33
33
  --chip-r: 0.4375rem;
@@ -20,7 +20,7 @@
20
20
  .dark,
21
21
  [data-theme="dark"] {
22
22
  /* The dark theme's primary is too dark to read on its surfaces (2.5:1), so
23
- * the rail's label is a saturated lavender of its hue (6.3:1: lightness
23
+ * the rail's label is a saturated lavender of its hue (5.3:1: lightness
24
24
  * 0.72, chroma 0.15) on a denser pill (30 %, 35 % hovered). Light keeps the
25
25
  * lightness and chroma of primary (the `l` and `c` fallbacks). */
26
26
  --nxgt-sidebar-active-share: 30%;
@@ -10,10 +10,10 @@
10
10
  * motion: reduced-motion.css ends every animation at once. */
11
11
  @layer components {
12
12
  .nxgt-scrim {
13
- background-color: oklch(0.2 0.035 265 / 0.42);
13
+ background-color: oklch(0.2 0.035 290 / 0.42);
14
14
  }
15
15
  :where(.dark, [data-theme="dark"]) .nxgt-scrim {
16
- background-color: oklch(0.04 0.01 265 / 0.62);
16
+ background-color: oklch(0.04 0.01 290 / 0.62);
17
17
  }
18
18
  .nxgt-scrim[data-scrim="blur"] {
19
19
  -webkit-backdrop-filter: blur(6px) saturate(1.15);
@@ -26,7 +26,7 @@
26
26
  var(--error) 5%,
27
27
  var(--background)
28
28
  );
29
- --nxgt-field-border: color-mix(in oklab, var(--foreground) 13%, transparent);
29
+ --nxgt-field-border: color-mix(in oklab, var(--foreground) 14%, transparent);
30
30
  --nxgt-field-border-hover: color-mix(
31
31
  in oklab,
32
32
  var(--foreground) 24%,
@@ -13,8 +13,8 @@
13
13
  --tg-pill: color-mix(in oklab, var(--primary) 10%, var(--background));
14
14
  --tg-ring: color-mix(in oklab, var(--primary-text) 82%, var(--background));
15
15
  --tg-lift:
16
- 0 1px 2px oklch(0.2 0.04 265 / 0.1),
17
- 0 2px 6px -2px oklch(0.2 0.04 265 / 0.12);
16
+ 0 1px 2px oklch(0.2 0.04 290 / 0.1),
17
+ 0 2px 6px -2px oklch(0.2 0.04 290 / 0.12);
18
18
  --tg-i: 0;
19
19
  --tg-n: 1;
20
20
  position: relative;
@@ -23,7 +23,7 @@
23
23
  --tg-lift:
24
24
  0 1px 2px oklch(0.25 0.06 270 / 0.08),
25
25
  0 3px 8px -3px oklch(0.35 0.1 276 / 0.22);
26
- --tg-rest: 0 1px 1px oklch(0.2 0.03 265 / 0.04);
26
+ --tg-rest: 0 1px 1px oklch(0.2 0.03 290 / 0.04);
27
27
  gap: 0.375rem;
28
28
  }
29
29
  .nxgt-toggle-group[data-variant="separate"][data-size="sm"] {