@nxgt/material 3.6.0 → 3.7.1

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 (97) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +46 -1
  3. package/dist/{button-1Fornjtn.js → button--cF4gY14.js} +1 -1
  4. package/dist/charts.js +1 -1
  5. package/dist/{code-editor-DeZYlIO2.js → code-editor-0CdGwKDg.js} +3 -3
  6. package/dist/code-editor.js +3 -3
  7. package/dist/{code-language-items-Bb7afEj-.js → code-language-items-CGARRbVm.js} +1 -1
  8. package/dist/components/animations/scroll.css +1 -1
  9. package/dist/components/base-content.css +1 -1
  10. package/dist/components/base.css +1 -1
  11. package/dist/components/components.css +2 -0
  12. package/dist/components/editor-field-expressive.css +5 -0
  13. package/dist/components/editor-prose.css +1 -1
  14. package/dist/components/theme-tokens.css +17 -4
  15. package/dist/components/ui/display/period-cards/period-cards.css +2 -2
  16. package/dist/components/ui/media/pdf-viewer/pdf-viewer.css +1 -1
  17. package/dist/components/ui/widgets/drawing/drawing-animate.css +123 -0
  18. package/dist/components/ui/widgets/drawing/drawing.css +459 -0
  19. package/dist/{components-BCYZgeoV.js → components-bYGPzyKd.js} +761 -761
  20. package/dist/components.js +18 -18
  21. package/dist/{dialog-JQT6iETD.js → dialog-DdJ1C4BR.js} +168 -168
  22. package/dist/dnd.js +1 -1
  23. package/dist/draw-animate.js +106 -0
  24. package/dist/draw-png.js +2 -0
  25. package/dist/draw-sketch.js +38 -0
  26. package/dist/draw.js +65 -0
  27. package/dist/drawing-B8VuG7nx.js +390 -0
  28. package/dist/drawing-context-CeKeZE6b.js +10 -0
  29. package/dist/{dropdown-menu-DiZvX4tG.js → dropdown-menu-DWtgUVW7.js} +1 -1
  30. package/dist/editor-viewer.js +1 -1
  31. package/dist/editor.js +120 -120
  32. package/dist/{empty-state-Cpvsmk0R.js → empty-state-CRWLQ1sM.js} +2 -2
  33. package/dist/{icon-badge-C30yKsAM.js → icon-badge-Bb5-73XP.js} +18 -18
  34. package/dist/{icon-button-BXlI3DJ_.js → icon-button-5A6Mrj6w.js} +60 -90
  35. package/dist/lib/components/ui/display/shape/use-shape-morph.d.ts +1 -0
  36. package/dist/lib/components/ui/widgets/drawing/drawing-a11y.d.ts +20 -0
  37. package/dist/lib/components/ui/widgets/drawing/drawing-context.d.ts +23 -0
  38. package/dist/lib/components/ui/widgets/drawing/drawing-types.d.ts +63 -0
  39. package/dist/lib/components/ui/widgets/drawing/drawing.d.ts +17 -0
  40. package/dist/lib/components/ui/widgets/drawing/index.d.ts +5 -0
  41. package/dist/lib/components/ui/widgets/drawing/partials/drawing-root.d.ts +17 -0
  42. package/dist/lib/components/ui/widgets/drawing/partials/interactive-node.d.ts +22 -0
  43. package/dist/lib/components/ui/widgets/drawing/partials/primitives/content.d.ts +20 -0
  44. package/dist/lib/components/ui/widgets/drawing/partials/primitives/path.d.ts +29 -0
  45. package/dist/lib/components/ui/widgets/drawing/partials/primitives/primitive.d.ts +19 -0
  46. package/dist/lib/components/ui/widgets/drawing/partials/primitives/shapes.d.ts +18 -0
  47. package/dist/lib/components/ui/widgets/drawing/partials/react-attrs.d.ts +5 -0
  48. package/dist/lib/components/ui/widgets/drawing/partials/ring.d.ts +9 -0
  49. package/dist/lib/components/ui/widgets/drawing/partials/svg-tree.d.ts +29 -0
  50. package/dist/lib/components/ui/widgets/drawing/use-exact-text.d.ts +16 -0
  51. package/dist/lib/draw/index.d.ts +32 -0
  52. package/dist/lib/draw-animate/index.d.ts +19 -0
  53. package/dist/lib/draw-animate/morph-drawing.d.ts +32 -0
  54. package/dist/lib/draw-animate/reduced-motion.d.ts +2 -0
  55. package/dist/lib/draw-animate/use-drawing-controls.d.ts +27 -0
  56. package/dist/lib/draw-animate/use-scene-morph.d.ts +15 -0
  57. package/dist/lib/draw-png/index.d.ts +11 -0
  58. package/dist/lib/draw-sketch/index.d.ts +17 -0
  59. package/dist/lib/draw-sketch/sketch.d.ts +19 -0
  60. package/dist/lib/print/components/print-drawing.d.ts +16 -0
  61. package/dist/lib/print/index.d.ts +2 -1
  62. package/dist/main.js +23 -23
  63. package/dist/map.js +63 -63
  64. package/dist/material.css +1 -1
  65. package/dist/pdf-reader.js +1 -1
  66. package/dist/print.js +123 -115
  67. package/dist/{public-Cde8_SN8.js → public-SsiazLEv.js} +743 -743
  68. package/dist/{render-json-BwJX1jZ2.js → render-json-DyFYFIkZ.js} +1 -1
  69. package/dist/{rich-code-block-yxMXBuGd.js → rich-code-block-CwNwQs5z.js} +3 -3
  70. package/dist/{rich-text-viewer-Bq-2vTVm.js → rich-text-viewer-LO1IZCWs.js} +1 -1
  71. package/dist/{sortable-provider-DYlpq8lP.js → sortable-provider-BvD98s8Y.js} +19 -19
  72. package/dist/{spinner-D-FE_mTW.js → spinner-CtGCPza-.js} +4 -4
  73. package/dist/styles.css +1 -0
  74. package/dist/{toolbar-items-DnkS3bDY.js → toolbar-items-DsDDD5AY.js} +1 -1
  75. package/dist/{use-chat-composer-BwpSgP_D.js → use-chat-composer-DZ01a16D.js} +923 -922
  76. package/dist/use-shape-morph-BKA_R5P5.js +35 -0
  77. package/docs/README.md +1 -0
  78. package/docs/components/rich-widgets.md +196 -0
  79. package/docs/guides/drawing.md +499 -0
  80. package/docs/guides/printing.md +47 -0
  81. package/docs/guides/theming.md +3 -2
  82. package/docs/previews/rich-widgets-drawing.webp +0 -0
  83. package/docs/roadmap.md +17 -0
  84. package/docs/troubleshooting.md +145 -1
  85. package/lib/components/animations/scroll.css +1 -1
  86. package/lib/components/base-content.css +1 -1
  87. package/lib/components/base.css +1 -1
  88. package/lib/components/components.css +2 -0
  89. package/lib/components/editor-field-expressive.css +5 -0
  90. package/lib/components/editor-prose.css +1 -1
  91. package/lib/components/theme-tokens.css +17 -4
  92. package/lib/components/ui/display/period-cards/period-cards.css +2 -2
  93. package/lib/components/ui/media/pdf-viewer/pdf-viewer.css +1 -1
  94. package/lib/components/ui/widgets/drawing/drawing-animate.css +123 -0
  95. package/lib/components/ui/widgets/drawing/drawing.css +459 -0
  96. package/lib/styles.css +1 -0
  97. package/package.json +22 -2
@@ -0,0 +1,35 @@
1
+ import { morph as e, morphAt as t, toSvgPath as n } from "@nxgt/material-core/shapes";
2
+ import { useLayoutEffect as r, useRef as i } from "react";
3
+ //#region lib/components/ui/display/shape/use-shape-morph.ts
4
+ var a = .8, o = 14, s = o * Math.sqrt(1 - a * a);
5
+ function c(e) {
6
+ let t = e / 1e3;
7
+ return 1 - Math.exp(-.8 * o * t) * (Math.cos(s * t) + a * o / s * Math.sin(s * t));
8
+ }
9
+ var l = () => typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
10
+ function u(a, o, s) {
11
+ let u = i(o);
12
+ r(() => {
13
+ let r = a.current, i = u.current;
14
+ if (!r || i === o || !s || l()) {
15
+ r && i !== o && r.setAttribute("d", n(o)), u.current = o;
16
+ return;
17
+ }
18
+ let d = e(i, o), f = n(o), p = 0, m = performance.now(), h = (e) => {
19
+ let i = e - m;
20
+ if (i >= 520) {
21
+ u.current = o, r.setAttribute("d", f);
22
+ return;
23
+ }
24
+ let a = t(d, c(i));
25
+ u.current = a, r.setAttribute("d", n(a)), p = requestAnimationFrame(h);
26
+ };
27
+ return r.setAttribute("d", n(d.from)), p = requestAnimationFrame(h), () => cancelAnimationFrame(p);
28
+ }, [
29
+ a,
30
+ o,
31
+ s
32
+ ]);
33
+ }
34
+ //#endregion
35
+ export { u as n, c as t };
package/docs/README.md CHANGED
@@ -21,6 +21,7 @@ detail: every option, the second example, and the traps.
21
21
  | [Media players](guides/media.md) | You play video or audio: embedded, audio cards, playlists, chapters and transcript, sound across pages with `MediaPlayerHost`, the lightbox, CSP and keyboard |
22
22
  | [Streaming (HLS)](guides/media-streaming.md) | You play `.m3u8` streams in `MediaPlayer` with `@nxgt/material/media-hls` |
23
23
  | [Maps](guides/maps.md) | You render Leaflet maps or a location field with `@nxgt/material/map` |
24
+ | [Drawing](guides/drawing.md) | You draw diagrams, badges or illustrations from code with `@nxgt/material/draw`: scenes and JSX primitives, roles and tones, a strict CSP, accessibility and events, sketch, animation, PNG, PDF and e-mail |
24
25
  | [Backgrounds](guides/backgrounds.md) | You want a gradient or patterned backdrop: tones, intensity, the opt-in `backgrounds.css`, custom colours, motion and CSP |
25
26
  | [SSR](guides/ssr.md) | Your app renders on a server and bundles this package |
26
27
  | [Content Security Policy](guides/csp.md) | Your app sends a strict CSP: the directives to use, the components that still inject a `<style>`, the zod and KaTeX settings, self-hosting a font, the per-request nonce |
@@ -10,6 +10,7 @@ the app owns the data.
10
10
  | <img src="../previews/rich-widgets-kanban.webp" width="96" alt=""> | [Kanban](#kanban) | Board with columns, swimlanes, WIP limits and drag-and-drop |
11
11
  | <img src="../previews/rich-widgets-eventcalendar.webp" width="96" alt=""> | [EventCalendar](#eventcalendar) | Month / week / day / agenda calendar, phone to desktop |
12
12
  | <img src="../previews/rich-widgets-native-charts-linechart.webp" width="96" alt=""> | [Charts](#charts) | Native SVG charts (line, area, bar, pie, donut, gauge, radial, funnel, heat map, radar, scatter, combo) with keyboard, summary and View data; the Nivo ones were removed in 3.0 |
13
+ | <img src="../previews/rich-widgets-drawing.webp" width="96" alt=""> | [Drawing](#drawing) | Vector drawing from a scene of plain data or JSX primitives: theme colours, accessible, focusable nodes, strict-CSP safe |
13
14
  | <img src="../previews/rich-widgets-emojipicker.webp" width="96" alt=""> | [EmojiPicker](#emojipicker) | Shared emoji picker and list |
14
15
  | <img src="../previews/rich-widgets-mentionlist.webp" width="96" alt=""> | [MentionList](#mentionlist) | `@` mention list with local search |
15
16
  | <img src="../previews/rich-widgets-documenteditor.webp" width="96" alt=""> | [DocumentEditor](#documenteditor) | Rich text editor for long-form writing, built on a headless core |
@@ -309,6 +310,201 @@ Parts: `LineChart`, `AreaChart`, `BarChart`, `PieChart`, `DonutChart`, `Gauge`,
309
310
 
310
311
  ---
311
312
 
313
+ ## Drawing
314
+
315
+ ![Drawing](../previews/rich-widgets-drawing.webp)
316
+
317
+ Vector drawings from `@nxgt/material/draw`: a **scene** of plain data (the
318
+ builders `scene`, `rect`, `path`, `text`... of `@nxgt/material-core/draw`,
319
+ re-exported here) or JSX **primitives** (`Rect`, `Ellipse`, `Circle`, `Line`,
320
+ `Polygon`, `Path`, `Text`, `Group`, `Image`) inside a `Drawing`. Colours are
321
+ theme roles (`primary-container`, `on-primary-container`, `surface`,
322
+ `outline`...), `tone('success')` or free colours; roles are classes that
323
+ `styles.css` maps to the theme's variables, so a drawing follows light and dark
324
+ with no inline `style` (a strict CSP is satisfied). The names `text` and `image`
325
+ clash with `@nxgt/material/print`'s: import one under
326
+ another name. **Its own entry, client-only** (render `Drawing` from a
327
+ `'use client'` file; the builders and `toSVG` run anywhere).
328
+
329
+ ```tsx
330
+ 'use client';
331
+
332
+ import { Circle, Drawing, Rect, Text } from '@nxgt/material/draw';
333
+
334
+ <Drawing w={200} h={80} title="Release status">
335
+ <Rect x={0} y={0} w={200} h={80} r={16} fill="primary-container" />
336
+ <Circle cx={36} cy={40} r={14} fill="primary" />
337
+ <Text x={64} y={46} fill="on-primary-container">Shipped</Text>
338
+ </Drawing>;
339
+ ```
340
+
341
+ The same drawing from a scene, which a server can send as JSON:
342
+
343
+ ```tsx
344
+ import { Drawing, rect, scene, text } from '@nxgt/material/draw';
345
+
346
+ const status = scene({ w: 200, h: 80 }, [
347
+ rect({ x: 0, y: 0, w: 200, h: 80, r: 16, fill: 'primary-container' }),
348
+ text('Shipped', { x: 100, y: 46, anchor: 'middle', fill: 'on-primary-container' }),
349
+ ]);
350
+
351
+ <Drawing scene={status} title="Release status" />;
352
+ ```
353
+
354
+ ### Accessibility
355
+
356
+ `Drawing` takes `title` **or** `decorative`, never neither: the type enforces it.
357
+ A named drawing is `role="img"` with `aria-label={title}`, never a `<title>`
358
+ element (React 19 would hoist it into the page's head); a `decorative` one is
359
+ `aria-hidden`. A drawing with an interactive node is `role="group"` (an image
360
+ cannot hold focusable children); set `interactive` on a JSX `Drawing` that is
361
+ server rendered so the first markup says so too. An interactive node needs a
362
+ `label`: it is a focusable `role="button"` (it has `onClick`) or `role="img"`,
363
+ Enter and Space click it, and a focus ring (a second, unfilled copy of its
364
+ outline, class `nxgt-draw-ring`) shows on `:focus-visible`; text, and a group with
365
+ no shape, show a CSS outline instead. A decorative
366
+ drawing cannot hold an interactive node: it throws.
367
+
368
+ ### Events
369
+
370
+ In scene mode, set events by node `id`, or listen to all of them:
371
+
372
+ ```tsx
373
+ <Drawing
374
+ scene={flow}
375
+ title="Release flow"
376
+ handlers={{ review: { onPointerEnter: preview, onFocus: preview } }}
377
+ onNodeClick={(id, event) => open(id)}
378
+ />
379
+ ```
380
+
381
+ A node is interactive when its scene node has `interactive: true`, an entry in
382
+ `handlers`, or (JSX) any of `onClick`, `onPointerEnter`, `onPointerLeave`,
383
+ `onPointerDown`, `onPointerUp`, `onFocus`, `onBlur` or `onKeyDown`. A JSX `Group`
384
+ with an event shows its focus as a CSS outline instead of an outline copy
385
+ (a scene `group` keeps the outline copy).
386
+
387
+ ### Text
388
+
389
+ Wrapped text (`maxWidth`) breaks with Inter's metrics, the same on the server
390
+ and in the first client render. Once mounted, and again when the fonts load,
391
+ the browser re-measures each wrapped text (`exactText`, on by default), so a
392
+ fallback font cannot overflow its box; the lines may move at that point. Set
393
+ `exactText={false}` to keep the metrics' breaks.
394
+
395
+ ### Shapes and layout
396
+
397
+ `@nxgt/material/draw` re-exports `shape`, `morph`, `SHAPE_NAMES`, `toCubics` and
398
+ `bbox`, `stack`, `grid`, `align`, `distribute` from `@nxgt/material-core`, by
399
+ name (a bundler keeps only the ones you import; `Drawing` alone carries no
400
+ shape library). `shape('cookie-9', { x, y, w, h, fill })` is a path node, so it
401
+ goes to a scene or to `<Path node={...} />`; `morph(a, b, t)` is the path at `t`
402
+ between two shapes or nodes; `stack` and `grid` place labelled boxes.
403
+
404
+ ```tsx
405
+ import { Drawing, Path, shape } from '@nxgt/material/draw';
406
+
407
+ <Drawing w={120} h={120} title="A cookie">
408
+ <Path node={shape('cookie-9', { x: 10, y: 10, w: 100, h: 100, fill: 'tertiary' })} />
409
+ </Drawing>;
410
+ ```
411
+
412
+ ### Sketch
413
+
414
+ `@nxgt/material/draw/sketch` draws a drawing by hand. `Sketch` wraps a `Drawing`
415
+ (scene or JSX), or primitives inside a JSX one; `sketch(sceneOrNode, options)`
416
+ does the same to plain data. Strokes are two wobbling passes with a bow,
417
+ ellipses are loose loops, filled shapes are hatched (`fill`: `hachure`,
418
+ `cross-hatch`, `solid`, `none`). Texts and images stay as they are. The wobble
419
+ is seeded (`seed`, else the scene's, else 0): the markup is the same on the
420
+ server and in the browser. Ids, labels, the focus ring and events keep working;
421
+ the hatch lines are fill, so they get no focus ring.
422
+
423
+ ```tsx
424
+ 'use client';
425
+
426
+ import { Drawing, Rect } from '@nxgt/material/draw';
427
+ import { Sketch } from '@nxgt/material/draw/sketch';
428
+
429
+ <Sketch seed={7} fill="cross-hatch">
430
+ <Drawing w={200} h={100} title="A sketchy button">
431
+ <Rect id="go" label="Go" x={10} y={10} w={180} h={80} r={12} fill="primary" stroke="primary" onClick={go} />
432
+ </Drawing>
433
+ </Sketch>;
434
+ ```
435
+
436
+ Options: `seed`, `roughness` (1; 0 is clean double strokes), `bowing` (1), `fill`
437
+ (`hachure`), `hachureAngle` (-41), `hachureGap` (three stroke widths, at least 4),
438
+ `strokeWidth` (1.5 for a shape that sets none). Types: `SketchProps`,
439
+ `SketchOptions`, `SketchFill`.
440
+
441
+ ### Props
442
+
443
+ | Prop | Type | Default | Effect |
444
+ | --- | --- | --- | --- |
445
+ | `title` / `decorative` | `string` / `true` | required, one of two | the accessible name, or hidden from assistive technology |
446
+ | `scene` | `Scene` | — | draw a scene of plain data (scene mode) |
447
+ | `w`, `h`, `viewBox`, `background`, `children` | `number`, `[x, y, w, h]`, `Paint`, `ReactNode` | — | the size, the view and the primitives (JSX mode) |
448
+ | `handlers`, `onNodeClick` | `Record<id, NodeHandlers>`, `(id, event) => void` | — | events by scene `id` (scene mode); `onNodeClick` in both modes |
449
+ | `interactive` | `boolean` | `false` | JSX mode: the root is a group in the server's markup |
450
+ | `exactText` | `boolean` | `true` | re-measure wrapped text in the browser |
451
+ | `className` | `string` | — | on the `<svg>`; it scales to its container (`max-width: 100%`) |
452
+
453
+ A `Path` takes `d` (SVG path data), `build` (`(p) => p.moveTo(0, 0).lineTo(10, 10)`)
454
+ or `node` (a ready node, such as a shape; the other props override its style).
455
+ `Text` takes strings and numbers as children (`\n` breaks a line). Every primitive takes the node's style (`fill`, `stroke`, `strokeWidth`, `opacity`,
456
+ `transform`, `clip`, `mask`, `className`, `id`, `label`, `interactive`).
457
+
458
+ ### Animation
459
+
460
+ `@nxgt/material/draw/animate` animates a drawing without inline style. Wrap a
461
+ scene with `drawOn` (strokes trace themselves, fills fade in) or `appear`
462
+ (nodes fade and grow in), one after the next; they only add class names that
463
+ `styles.css` animates, so a server renders them and a strict CSP is satisfied.
464
+ `useDrawingControls(ref)` replays, pauses, plays or finishes them through the
465
+ Web Animations API, and `MorphDrawing` (or `useSceneMorph` with a `Drawing`)
466
+ springs one scene into another when `active` changes. Under reduced motion
467
+ nothing moves and the last frame shows at once.
468
+
469
+ ```tsx
470
+ 'use client';
471
+
472
+ import { Drawing, scene, shape } from '@nxgt/material/draw';
473
+ import { drawOn, MorphDrawing, useDrawingControls } from '@nxgt/material/draw/animate';
474
+ import { useRef } from 'react';
475
+
476
+ const flow = drawOn(scene({ w: 240, h: 80 }, [/* ... */]), { dur: 'l' }); // keep scenes stable
477
+ const cookie = scene({ w: 120, h: 120 }, [shape('cookie-9', { id: 'blob', x: 10, y: 10, w: 100, h: 100, fill: 'primary-container' })]);
478
+ const heart = scene({ w: 120, h: 120 }, [shape('heart', { id: 'blob', x: 10, y: 10, w: 100, h: 100, fill: 'tertiary-container' })]);
479
+
480
+ export function Demo({ liked }: { liked: boolean }) {
481
+ const ref = useRef<SVGSVGElement>(null);
482
+ const { replay } = useDrawingControls(ref);
483
+ return (
484
+ <>
485
+ <Drawing ref={ref} scene={flow} title="Release flow" />
486
+ <button onClick={replay}>Replay</button>
487
+ <MorphDrawing from={cookie} to={heart} active={liked} title="Like" />
488
+ </>
489
+ );
490
+ }
491
+ ```
492
+
493
+ `MorphDrawing` animates the closed paths the two scenes share by `id` (`shape()`
494
+ gives them); any other node (text, a line, an arrowed, interactive or sketched
495
+ one) shows the scene being moved to at once, and `useSceneMorph` cross-fades
496
+ everything. The options of `drawOn` and `appear`, the delay per step
497
+ (`--nxgt-draw-stagger`, 60 ms) and `morphScenes` are in the
498
+ [core drawing reference](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/docs/draw.md#animation-nxgtmaterial-coredrawanimate).
499
+
500
+ How to use it in an app (server rendering, CSP, colours, events, PNG, PDF, e-mail) is in the
501
+ [Drawing guide](../guides/drawing.md). The scene model, colours, ids and the CSP rules are in the
502
+ [vector drawing reference of `@nxgt/material-core`](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/docs/draw.md).
503
+
504
+ **Storybook:** `Rich widgets/Drawing`, `Rich widgets/Drawing/Shapes and layout`, `Rich widgets/Drawing/Sketch`, `Rich widgets/Drawing/Animation`, `Rich widgets/Drawing/PNG export`, `Rich widgets/Drawing/Gallery` · **Vue:** React only for now; the engine is framework-free in core
505
+
506
+ ---
507
+
312
508
  ## EmojiPicker
313
509
 
314
510
  ![EmojiPicker](../previews/rich-widgets-emojipicker.webp)