@djangocfg/ui-tools 2.1.156 → 2.1.158

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 (43) hide show
  1. package/README.md +149 -2
  2. package/dist/{Mermaid.client-AF4WOQZR.cjs → Mermaid.client-2TAFAXPW.cjs} +106 -136
  3. package/dist/Mermaid.client-2TAFAXPW.cjs.map +1 -0
  4. package/dist/{Mermaid.client-W4QXJX7Q.mjs → Mermaid.client-HG24D5KB.mjs} +107 -137
  5. package/dist/Mermaid.client-HG24D5KB.mjs.map +1 -0
  6. package/dist/index.cjs +4 -9
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +14 -17
  9. package/dist/index.d.ts +14 -17
  10. package/dist/index.mjs +4 -9
  11. package/dist/index.mjs.map +1 -1
  12. package/package.json +6 -6
  13. package/src/tools/Mermaid/Mermaid.client.tsx +49 -45
  14. package/src/tools/Mermaid/Mermaid.story.tsx +195 -110
  15. package/src/tools/Mermaid/builders/FlowDiagram/FlowDiagram.ts +96 -0
  16. package/src/tools/Mermaid/builders/FlowDiagram/functions/getEdges.ts +50 -0
  17. package/src/tools/Mermaid/builders/FlowDiagram/functions/getNodes.ts +43 -0
  18. package/src/tools/Mermaid/builders/FlowDiagram/functions/getStyles.ts +90 -0
  19. package/src/tools/Mermaid/builders/FlowDiagram/functions/index.ts +8 -0
  20. package/src/tools/Mermaid/builders/FlowDiagram/index.ts +16 -0
  21. package/src/tools/Mermaid/builders/FlowDiagram/types.ts +130 -0
  22. package/src/tools/Mermaid/builders/JourneyDiagram/JourneyDiagram.ts +88 -0
  23. package/src/tools/Mermaid/builders/JourneyDiagram/index.ts +12 -0
  24. package/src/tools/Mermaid/builders/JourneyDiagram/types.ts +48 -0
  25. package/src/tools/Mermaid/builders/SequenceDiagram/SequenceDiagram.ts +123 -0
  26. package/src/tools/Mermaid/builders/SequenceDiagram/functions/getActivations.ts +30 -0
  27. package/src/tools/Mermaid/builders/SequenceDiagram/functions/getBlocks.ts +112 -0
  28. package/src/tools/Mermaid/builders/SequenceDiagram/functions/getMessages.ts +85 -0
  29. package/src/tools/Mermaid/builders/SequenceDiagram/functions/getNotes.ts +94 -0
  30. package/src/tools/Mermaid/builders/SequenceDiagram/functions/index.ts +16 -0
  31. package/src/tools/Mermaid/builders/SequenceDiagram/index.ts +17 -0
  32. package/src/tools/Mermaid/builders/SequenceDiagram/types.ts +147 -0
  33. package/src/tools/Mermaid/builders/core/DiagramStore.ts +138 -0
  34. package/src/tools/Mermaid/builders/core/index.ts +8 -0
  35. package/src/tools/Mermaid/builders/core/sanitize.ts +78 -0
  36. package/src/tools/Mermaid/builders/core/theme.ts +42 -0
  37. package/src/tools/Mermaid/builders/core/types.ts +183 -0
  38. package/src/tools/Mermaid/builders/index.ts +96 -0
  39. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +78 -54
  40. package/src/tools/Mermaid/index.tsx +51 -10
  41. package/src/tools/Mermaid/lazy.tsx +2 -5
  42. package/dist/Mermaid.client-AF4WOQZR.cjs.map +0 -1
  43. package/dist/Mermaid.client-W4QXJX7Q.mjs.map +0 -1
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Shared types for Mermaid diagram builders
3
+ * @module Mermaid/builders/core/types
4
+ */
5
+
6
+ // ============================================================================
7
+ // Node Types
8
+ // ============================================================================
9
+
10
+ export type NodeId = string;
11
+
12
+ /**
13
+ * Node shapes supported by Mermaid flowcharts
14
+ * @see https://mermaid.js.org/syntax/flowchart.html#node-shapes
15
+ */
16
+ export type NodeShape =
17
+ | 'rect' // [text]
18
+ | 'round' // (text)
19
+ | 'stadium' // ([text])
20
+ | 'subroutine' // [[text]]
21
+ | 'cylinder' // [(text)]
22
+ | 'circle' // ((text))
23
+ | 'asymmetric' // >text]
24
+ | 'rhombus' // {text}
25
+ | 'hexagon' // {{text}}
26
+ | 'parallelogram' // [/text/]
27
+ | 'parallelogramAlt' // [\text\]
28
+ | 'trapezoid' // [/text\]
29
+ | 'trapezoidAlt' // [\text/]
30
+ | 'doubleCircle'; // (((text)))
31
+
32
+ /**
33
+ * Shape syntax lookup for Mermaid
34
+ */
35
+ export const NODE_SHAPE_SYNTAX: Record<NodeShape, [string, string]> = {
36
+ rect: ['[', ']'],
37
+ round: ['(', ')'],
38
+ stadium: ['([', '])'],
39
+ subroutine: ['[[', ']]'],
40
+ cylinder: ['[(', ')]'],
41
+ circle: ['((', '))'],
42
+ asymmetric: ['>', ']'],
43
+ rhombus: ['{', '}'],
44
+ hexagon: ['{{', '}}'],
45
+ parallelogram: ['[/', '/]'],
46
+ parallelogramAlt: ['[\\', '\\]'],
47
+ trapezoid: ['[/', '\\]'],
48
+ trapezoidAlt: ['[\\', '/]'],
49
+ doubleCircle: ['(((', ')))'],
50
+ };
51
+
52
+ // ============================================================================
53
+ // Edge Types
54
+ // ============================================================================
55
+
56
+ /**
57
+ * Edge line styles
58
+ */
59
+ export type EdgeLineStyle = 'solid' | 'dotted' | 'thick';
60
+
61
+ /**
62
+ * Arrow head types
63
+ */
64
+ export type ArrowHead = 'arrow' | 'open' | 'circle' | 'cross' | 'none';
65
+
66
+ /**
67
+ * Edge syntax lookup
68
+ */
69
+ export const EDGE_SYNTAX: Record<EdgeLineStyle, Record<ArrowHead, string>> = {
70
+ solid: {
71
+ arrow: '-->',
72
+ open: '---',
73
+ circle: '--o',
74
+ cross: '--x',
75
+ none: '---',
76
+ },
77
+ dotted: {
78
+ arrow: '-..->',
79
+ open: '-.-',
80
+ circle: '-.-o',
81
+ cross: '-.-x',
82
+ none: '-.-',
83
+ },
84
+ thick: {
85
+ arrow: '==>',
86
+ open: '===',
87
+ circle: '==o',
88
+ cross: '==x',
89
+ none: '===',
90
+ },
91
+ };
92
+
93
+ /**
94
+ * Simplified edge syntax for common cases
95
+ */
96
+ export const SIMPLE_EDGE_SYNTAX = {
97
+ solid: '-->',
98
+ dotted: '-.->',
99
+ thick: '==>',
100
+ solidOpen: '---',
101
+ dottedOpen: '-.-',
102
+ } as const;
103
+
104
+ // ============================================================================
105
+ // Style Types
106
+ // ============================================================================
107
+
108
+ /**
109
+ * CSS-like style properties for nodes
110
+ */
111
+ export interface StyleProperties {
112
+ fill?: string;
113
+ stroke?: string;
114
+ 'stroke-width'?: string;
115
+ color?: string;
116
+ 'font-weight'?: 'bold' | 'normal';
117
+ 'stroke-dasharray'?: string;
118
+ }
119
+
120
+ /**
121
+ * Style class definition
122
+ */
123
+ export interface StyleClass {
124
+ name: string;
125
+ properties: StyleProperties;
126
+ }
127
+
128
+ // ============================================================================
129
+ // Flow Diagram Types
130
+ // ============================================================================
131
+
132
+ /**
133
+ * Flow diagram directions
134
+ */
135
+ export type FlowDirection = 'TB' | 'BT' | 'LR' | 'RL';
136
+
137
+ // ============================================================================
138
+ // Sequence Diagram Types
139
+ // ============================================================================
140
+
141
+ /**
142
+ * Participant types in sequence diagrams
143
+ */
144
+ export type ParticipantType = 'participant' | 'actor';
145
+
146
+ /**
147
+ * Message arrow types in sequence diagrams
148
+ */
149
+ export const MESSAGE_ARROWS = {
150
+ sync: '->>', // Synchronous call
151
+ syncReply: '-->>', // Synchronous reply
152
+ async: '-)', // Async call
153
+ asyncReply: '--)', // Async reply
154
+ solid: '->', // Solid line
155
+ dotted: '-->', // Dotted line
156
+ cross: '-x', // Cross (failure)
157
+ crossDotted: '--x', // Dotted cross
158
+ } as const;
159
+
160
+ export type MessageArrowType = keyof typeof MESSAGE_ARROWS;
161
+
162
+ // ============================================================================
163
+ // Journey Diagram Types
164
+ // ============================================================================
165
+
166
+ /**
167
+ * Task score (1-5, where 5 is best)
168
+ */
169
+ export type TaskScore = 1 | 2 | 3 | 4 | 5;
170
+
171
+ // ============================================================================
172
+ // Utility Types
173
+ // ============================================================================
174
+
175
+ /**
176
+ * Makes all properties in T writable (removes readonly)
177
+ */
178
+ export type Writable<T> = { -readonly [P in keyof T]: T[P] };
179
+
180
+ /**
181
+ * Extracts keys from a const object
182
+ */
183
+ export type KeysOf<T> = keyof T & string;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Mermaid Diagram Builders
3
+ *
4
+ * Declarative, type-safe builders for creating Mermaid diagrams.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import {
9
+ * FlowDiagram,
10
+ * SequenceDiagram,
11
+ * JourneyDiagram,
12
+ * useStylePresets,
13
+ * useBoxColors
14
+ * } from '@djangocfg/ui-tools/tools/Mermaid/builders';
15
+ *
16
+ * function MyDiagram() {
17
+ * const presets = useStylePresets();
18
+ * const boxes = useBoxColors();
19
+ *
20
+ * // Flow diagram
21
+ * const flow = FlowDiagram<'A' | 'B'>({ direction: 'LR' });
22
+ * flow.node('A').rect('Start');
23
+ * flow.edge('A').to('B').solid();
24
+ * flow.style.define('highlight', presets.success);
25
+ *
26
+ * // Sequence diagram
27
+ * const { d, rect } = SequenceDiagram({
28
+ * Alice: 'participant',
29
+ * Bob: 'actor',
30
+ * });
31
+ * rect(boxes.primary, () => {
32
+ * d.Alice.sync.Bob.msg('Hello!');
33
+ * });
34
+ *
35
+ * // Journey diagram
36
+ * const journey = JourneyDiagram({ title: 'User Flow' });
37
+ * journey.section('Start').task('Open app', 5, 'User');
38
+ * }
39
+ * ```
40
+ *
41
+ * @module Mermaid/builders
42
+ */
43
+
44
+ // Core
45
+ export { DiagramStore, type DiagramStoreOptions } from './core/DiagramStore';
46
+ export { sanitizeLabel, toNodeId, escapeQuoted, formatLabel } from './core/sanitize';
47
+ export * from './core/types';
48
+
49
+ // Theme hooks and utilities (re-exported from @djangocfg/ui-core/styles/palette)
50
+ export {
51
+ useThemePalette,
52
+ useStylePresets,
53
+ useBoxColors,
54
+ hslToHex,
55
+ hslToRgbString,
56
+ hslToRgba,
57
+ type ThemePalette,
58
+ type StyleColors,
59
+ type StylePresets,
60
+ type BoxColors,
61
+ } from './core/theme';
62
+
63
+ // FlowDiagram
64
+ export { FlowDiagram, STYLE_PRESETS } from './FlowDiagram';
65
+ export type {
66
+ FlowDiagramOptions,
67
+ FlowDiagramBuilder,
68
+ NodeBuilder,
69
+ EdgeBuilder,
70
+ EdgeEndBuilder,
71
+ StyleBuilder,
72
+ SubgraphBuilder,
73
+ } from './FlowDiagram';
74
+
75
+ // SequenceDiagram
76
+ export { SequenceDiagram } from './SequenceDiagram';
77
+ export type {
78
+ ParticipantsObject,
79
+ SequenceDiagramOptions,
80
+ SequenceDiagramBuilder,
81
+ MessageBuilder,
82
+ MessageArrows,
83
+ MessageTarget,
84
+ MessageAction,
85
+ NoteBuilder,
86
+ ActivationBuilder,
87
+ } from './SequenceDiagram';
88
+
89
+ // JourneyDiagram
90
+ export { JourneyDiagram } from './JourneyDiagram';
91
+ export type {
92
+ JourneyDiagramOptions,
93
+ JourneyDiagramBuilder,
94
+ SectionBuilder,
95
+ TaskDefinition,
96
+ } from './JourneyDiagram';
@@ -1,11 +1,12 @@
1
1
  'use client';
2
2
 
3
- import React, { useEffect, useMemo } from 'react';
3
+ import React, { useEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
+ import { X, ZoomIn, ZoomOut, RotateCcw } from 'lucide-react';
6
+ import { TransformWrapper, TransformComponent, useControls } from 'react-zoom-pan-pinch';
5
7
 
6
- import { useTypedT, type I18nTranslations } from '@djangocfg/i18n';
8
+ import { Button } from '@djangocfg/ui-core/components';
7
9
  import { applyMermaidTextColors } from '../utils/mermaid-helpers';
8
- import { MermaidCodeViewer } from './MermaidCodeViewer';
9
10
 
10
11
  interface MermaidFullscreenModalProps {
11
12
  isOpen: boolean;
@@ -13,25 +14,40 @@ interface MermaidFullscreenModalProps {
13
14
  isVertical: boolean;
14
15
  theme: string;
15
16
  chart: string;
16
- fullscreenRef: React.RefObject<HTMLDivElement>;
17
+ fullscreenRef: React.RefObject<HTMLDivElement | null>;
17
18
  onClose: () => void;
18
19
  onBackdropClick: (e: React.MouseEvent) => void;
19
20
  }
20
21
 
22
+ // Zoom controls component
23
+ function ZoomControls() {
24
+ const { zoomIn, zoomOut, resetTransform } = useControls();
25
+
26
+ return (
27
+ <div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2 z-10">
28
+ <Button variant="secondary" size="icon" onClick={() => zoomOut()}>
29
+ <ZoomOut className="h-4 w-4" />
30
+ </Button>
31
+ <Button variant="secondary" size="icon" onClick={() => resetTransform()}>
32
+ <RotateCcw className="h-4 w-4" />
33
+ </Button>
34
+ <Button variant="secondary" size="icon" onClick={() => zoomIn()}>
35
+ <ZoomIn className="h-4 w-4" />
36
+ </Button>
37
+ </div>
38
+ );
39
+ }
40
+
21
41
  export const MermaidFullscreenModal: React.FC<MermaidFullscreenModalProps> = ({
22
42
  isOpen,
23
43
  svgContent,
24
44
  isVertical,
25
45
  theme,
26
- chart,
27
46
  fullscreenRef,
28
47
  onClose,
29
48
  onBackdropClick,
30
49
  }) => {
31
- const t = useTypedT<I18nTranslations>();
32
- const diagramTitle = useMemo(() => t('tools.diagram.title'), [t]);
33
-
34
- // Apply text colors to fullscreen modal after render
50
+ // Apply text colors
35
51
  useEffect(() => {
36
52
  if (isOpen && fullscreenRef.current) {
37
53
  const getCSSVariable = (variable: string) => {
@@ -45,62 +61,70 @@ export const MermaidFullscreenModal: React.FC<MermaidFullscreenModalProps> = ({
45
61
  : getCSSVariable('--foreground') || 'hsl(222.2 84% 4.9%)';
46
62
 
47
63
  applyMermaidTextColors(fullscreenRef.current, textColor);
64
+ }
65
+ }, [isOpen, theme, isVertical, fullscreenRef, svgContent]);
66
+
67
+ // Handle escape key
68
+ useEffect(() => {
69
+ if (!isOpen) return;
48
70
 
49
- // Make SVG responsive
50
- const svgElement = fullscreenRef.current.querySelector('svg');
51
- if (svgElement) {
52
- svgElement.style.display = 'block';
53
- svgElement.style.height = 'auto';
54
- svgElement.style.maxWidth = '100%';
71
+ const handleKeyDown = (e: KeyboardEvent) => {
72
+ if (e.key === 'Escape') onClose();
73
+ };
55
74
 
56
- // For vertical diagrams, limit width
57
- if (isVertical) {
58
- svgElement.style.maxWidth = '600px';
59
- svgElement.style.margin = '0 auto';
60
- }
61
- }
62
- }
63
- }, [isOpen, theme, isVertical, fullscreenRef]);
75
+ document.addEventListener('keydown', handleKeyDown);
76
+ return () => document.removeEventListener('keydown', handleKeyDown);
77
+ }, [isOpen, onClose]);
64
78
 
65
79
  if (!isOpen || typeof document === 'undefined') return null;
66
80
 
67
81
  return createPortal(
68
82
  <div
69
- className="fixed inset-0 z-9999 flex items-center justify-center p-4"
70
- style={{ backgroundColor: 'rgb(0 0 0 / 0.75)' }}
83
+ className="fixed inset-0 z-9999 bg-background/95 backdrop-blur-sm"
71
84
  onClick={onBackdropClick}
72
85
  >
73
- <div className={`relative bg-card rounded-sm shadow-xl max-h-[95vh] flex flex-col border border-border ${
74
- isVertical
75
- ? 'w-auto min-w-[400px] max-w-[600px]'
76
- : 'min-w-[600px] max-w-[90vw] w-auto'
77
- }`}>
78
- {/* Header */}
79
- <div className="flex items-center justify-between py-4 px-6 border-b border-border">
80
- <h3 className="text-sm font-medium text-foreground py-0 my-0">{diagramTitle}</h3>
81
- <button
82
- onClick={onClose}
83
- className="text-muted-foreground hover:text-foreground transition-colors"
84
- >
85
- <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
86
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
87
- </svg>
88
- </button>
89
- </div>
86
+ {/* Close button */}
87
+ <Button
88
+ variant="ghost"
89
+ size="icon"
90
+ className="absolute top-4 right-4 z-10"
91
+ onClick={onClose}
92
+ >
93
+ <X className="h-5 w-5" />
94
+ </Button>
90
95
 
91
- {/* Content - Code Viewer with tabs */}
92
- <div className="flex-1 overflow-hidden">
93
- <MermaidCodeViewer
94
- chart={chart}
95
- renderPreview={() => (
96
- <div
97
- ref={fullscreenRef}
98
- dangerouslySetInnerHTML={{ __html: svgContent }}
99
- />
100
- )}
96
+ {/* Zoomable diagram */}
97
+ <TransformWrapper
98
+ initialScale={1}
99
+ minScale={0.1}
100
+ maxScale={10}
101
+ centerOnInit
102
+ wheel={{ step: 0.1 }}
103
+ pinch={{ step: 5 }}
104
+ doubleClick={{ mode: 'reset' }}
105
+ >
106
+ <ZoomControls />
107
+ <TransformComponent
108
+ wrapperStyle={{
109
+ width: '100%',
110
+ height: '100%',
111
+ }}
112
+ contentStyle={{
113
+ width: '100%',
114
+ height: '100%',
115
+ display: 'flex',
116
+ alignItems: 'center',
117
+ justifyContent: 'center',
118
+ }}
119
+ >
120
+ <div
121
+ ref={fullscreenRef}
122
+ className="p-8"
123
+ dangerouslySetInnerHTML={{ __html: svgContent }}
124
+ onClick={(e) => e.stopPropagation()}
101
125
  />
102
- </div>
103
- </div>
126
+ </TransformComponent>
127
+ </TransformWrapper>
104
128
  </div>,
105
129
  document.body
106
130
  );
@@ -14,16 +14,8 @@ const MermaidClient = lazy(() => import('./Mermaid.client'));
14
14
 
15
15
  // Loading fallback component
16
16
  const LoadingFallback = () => (
17
- <div className="relative bg-card rounded-sm border border-border overflow-hidden">
18
- <div className="p-4 border-b border-border bg-muted/50">
19
- <h6 className="text-sm font-semibold text-foreground">Diagram</h6>
20
- <p className="text-xs text-muted-foreground mt-1">Loading...</p>
21
- </div>
22
- <div className="p-4">
23
- <div className="flex justify-center items-center min-h-[200px]">
24
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
25
- </div>
26
- </div>
17
+ <div className="flex justify-center items-center min-h-[100px]">
18
+ <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary" />
27
19
  </div>
28
20
  );
29
21
 
@@ -31,6 +23,8 @@ export interface MermaidProps {
31
23
  chart: string;
32
24
  className?: string;
33
25
  isCompact?: boolean;
26
+ /** Enable click-to-fullscreen functionality (default: true) */
27
+ fullscreen?: boolean;
34
28
  }
35
29
 
36
30
  const Mermaid: React.FC<MermaidProps> = (props) => {
@@ -42,3 +36,50 @@ const Mermaid: React.FC<MermaidProps> = (props) => {
42
36
  };
43
37
 
44
38
  export default Mermaid;
39
+
40
+ // Re-export builders for declarative diagram construction
41
+ export {
42
+ // Core
43
+ DiagramStore,
44
+ sanitizeLabel,
45
+ toNodeId,
46
+ // Theme hooks
47
+ useThemePalette,
48
+ useStylePresets,
49
+ useBoxColors,
50
+ // FlowDiagram
51
+ FlowDiagram,
52
+ STYLE_PRESETS,
53
+ // SequenceDiagram
54
+ SequenceDiagram,
55
+ // JourneyDiagram
56
+ JourneyDiagram,
57
+ } from './builders';
58
+
59
+ export type {
60
+ // Core types
61
+ DiagramStoreOptions,
62
+ FlowDirection,
63
+ NodeShape,
64
+ ParticipantType,
65
+ TaskScore,
66
+ // Theme types
67
+ ThemePalette,
68
+ StyleColors,
69
+ StylePresets,
70
+ BoxColors,
71
+ // FlowDiagram types
72
+ FlowDiagramOptions,
73
+ FlowDiagramBuilder,
74
+ NodeBuilder,
75
+ EdgeBuilder,
76
+ StyleBuilder,
77
+ // SequenceDiagram types
78
+ ParticipantsObject,
79
+ SequenceDiagramOptions,
80
+ SequenceDiagramBuilder,
81
+ // JourneyDiagram types
82
+ JourneyDiagramOptions,
83
+ JourneyDiagramBuilder,
84
+ SectionBuilder,
85
+ } from './builders';
@@ -11,16 +11,13 @@
11
11
  */
12
12
 
13
13
  import { createLazyComponent, CardLoadingFallback } from '../../components';
14
+ import type { MermaidProps } from './index';
14
15
 
15
16
  // ============================================================================
16
17
  // Types
17
18
  // ============================================================================
18
19
 
19
- export interface MermaidProps {
20
- chart: string;
21
- className?: string;
22
- isCompact?: boolean;
23
- }
20
+ export type { MermaidProps };
24
21
 
25
22
  // ============================================================================
26
23
  // Lazy Component