@djangocfg/ui-tools 2.1.158 → 2.1.160

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.
package/README.md CHANGED
@@ -49,8 +49,21 @@ import { Gallery, GalleryLightbox } from '@djangocfg/ui-tools/gallery';
49
49
 
50
50
  // Only loads Map (~800KB)
51
51
  import { MapContainer, MapMarker } from '@djangocfg/ui-tools/map';
52
+
53
+ // Mermaid builders (no heavy Mermaid dependency until render)
54
+ import { FlowDiagram, SequenceDiagram, JourneyDiagram } from '@djangocfg/ui-tools/mermaid';
52
55
  ```
53
56
 
57
+ ## Exports
58
+
59
+ | Path | Content |
60
+ |------|---------|
61
+ | `@djangocfg/ui-tools` | All tools with lazy loading |
62
+ | `@djangocfg/ui-tools/gallery` | Gallery components & hooks |
63
+ | `@djangocfg/ui-tools/map` | Map components & utilities |
64
+ | `@djangocfg/ui-tools/mermaid` | Mermaid component & declarative builders |
65
+ | `@djangocfg/ui-tools/styles` | CSS styles |
66
+
54
67
  ## Gallery
55
68
 
56
69
  Full-featured image/video gallery with carousel, grid view, and fullscreen lightbox.
@@ -241,9 +254,9 @@ Render Mermaid diagrams with fullscreen zoom support and type-safe declarative b
241
254
  ### Basic Usage
242
255
 
243
256
  ```tsx
244
- import Mermaid from '@djangocfg/ui-tools/tools/Mermaid';
257
+ import { LazyMermaid } from '@djangocfg/ui-tools';
245
258
 
246
- <Mermaid chart={`
259
+ <LazyMermaid chart={`
247
260
  graph TD
248
261
  A[Start] --> B{Decision}
249
262
  B -->|Yes| C[Action]
@@ -265,13 +278,14 @@ import Mermaid from '@djangocfg/ui-tools/tools/Mermaid';
265
278
  Type-safe builders for creating Mermaid diagrams programmatically:
266
279
 
267
280
  ```tsx
268
- import Mermaid, {
281
+ import { LazyMermaid } from '@djangocfg/ui-tools';
282
+ import {
269
283
  FlowDiagram,
270
284
  SequenceDiagram,
271
285
  JourneyDiagram,
272
286
  useStylePresets,
273
287
  useBoxColors,
274
- } from '@djangocfg/ui-tools/tools/Mermaid';
288
+ } from '@djangocfg/ui-tools/mermaid';
275
289
 
276
290
  function MyDiagram() {
277
291
  const presets = useStylePresets();
@@ -295,7 +309,7 @@ function MyDiagram() {
295
309
  flow.style.define('success', presets.success);
296
310
  flow.style.apply('success', 'success', 'finish');
297
311
 
298
- return <Mermaid chart={flow.toString()} />;
312
+ return <LazyMermaid chart={flow.toString()} />;
299
313
  }
300
314
  ```
301
315
 
@@ -347,6 +361,8 @@ flow.style.apply('myStyle', 'A', 'B');
347
361
 
348
362
  ### SequenceDiagram API
349
363
 
364
+ **Static API** (type-safe, for known participants):
365
+
350
366
  ```tsx
351
367
  const { d, rect, alt, loop, toString } = SequenceDiagram({
352
368
  User: 'actor',
@@ -354,7 +370,7 @@ const { d, rect, alt, loop, toString } = SequenceDiagram({
354
370
  API: 'participant',
355
371
  }, { autoNumber: true });
356
372
 
357
- // Messages
373
+ // Messages (type-safe chain)
358
374
  d.User.sync.App.msg('Click button');
359
375
  d.App.async.API.msg('Fetch data');
360
376
  d.API.asyncReply.App.msg('Response');
@@ -377,6 +393,43 @@ loop('Every 5s', () => {
377
393
  return toString();
378
394
  ```
379
395
 
396
+ **Dynamic API** (for runtime participant names):
397
+
398
+ ```tsx
399
+ // Participants from API/database
400
+ const characters = ['Alice', 'Bob', 'Charlie'];
401
+ const participants: Record<string, 'participant'> = {};
402
+ characters.forEach(c => { participants[c] = 'participant'; });
403
+
404
+ const seq = SequenceDiagram(participants, { autoNumber: true });
405
+
406
+ // Dynamic methods - no type assertions needed
407
+ seq.message('Alice', 'Bob', 'Hello!');
408
+ seq.message('Bob', 'Alice', 'Hi!', 'syncReply');
409
+ seq.message('Alice', 'Charlie', 'Ping', 'async');
410
+
411
+ // Notes
412
+ seq.noteOver('Alice', 'Thinking...');
413
+ seq.noteOverSpan('Alice', 'Bob', 'Discussion');
414
+ seq.noteLeft('Charlie', 'Waiting');
415
+ seq.noteRight('Charlie', 'Done');
416
+
417
+ // Blocks work the same
418
+ seq.rect('rgba(100,200,255,0.2)', () => {
419
+ seq.message('Alice', 'Bob', 'Secret message');
420
+ });
421
+
422
+ return seq.toString();
423
+ ```
424
+
425
+ | Dynamic Method | Description |
426
+ |----------------|-------------|
427
+ | `message(from, to, text, arrow?)` | Send message (arrow: sync, syncReply, async, asyncReply, solid, dotted, cross) |
428
+ | `noteOver(participant, text)` | Note over one participant |
429
+ | `noteOverSpan(p1, p2, text)` | Note spanning two participants |
430
+ | `noteLeft(participant, text)` | Note left of participant |
431
+ | `noteRight(participant, text)` | Note right of participant |
432
+
380
433
  ### JourneyDiagram API
381
434
 
382
435
  ```tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-tools",
3
- "version": "2.1.158",
3
+ "version": "2.1.160",
4
4
  "description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
5
5
  "keywords": [
6
6
  "ui-tools",
@@ -47,6 +47,11 @@
47
47
  "import": "./src/tools/Map/index.ts",
48
48
  "require": "./src/tools/Map/index.ts"
49
49
  },
50
+ "./mermaid": {
51
+ "types": "./src/tools/Mermaid/index.tsx",
52
+ "import": "./src/tools/Mermaid/index.tsx",
53
+ "require": "./src/tools/Mermaid/index.tsx"
54
+ },
50
55
  "./styles": "./src/styles/index.css"
51
56
  },
52
57
  "files": [
@@ -63,8 +68,8 @@
63
68
  "check": "tsc --noEmit"
64
69
  },
65
70
  "peerDependencies": {
66
- "@djangocfg/i18n": "^2.1.158",
67
- "@djangocfg/ui-core": "^2.1.158",
71
+ "@djangocfg/i18n": "^2.1.160",
72
+ "@djangocfg/ui-core": "^2.1.160",
68
73
  "lucide-react": "^0.545.0",
69
74
  "react": "^19.0.0",
70
75
  "react-dom": "^19.0.0",
@@ -96,10 +101,10 @@
96
101
  "@maplibre/maplibre-gl-geocoder": "^1.7.0"
97
102
  },
98
103
  "devDependencies": {
99
- "@djangocfg/i18n": "^2.1.158",
104
+ "@djangocfg/i18n": "^2.1.160",
100
105
  "@djangocfg/playground": "workspace:*",
101
- "@djangocfg/typescript-config": "^2.1.158",
102
- "@djangocfg/ui-core": "^2.1.158",
106
+ "@djangocfg/typescript-config": "^2.1.160",
107
+ "@djangocfg/ui-core": "^2.1.160",
103
108
  "@types/mapbox__mapbox-gl-draw": "^1.4.8",
104
109
  "@types/node": "^24.7.2",
105
110
  "@types/react": "^19.1.0",
@@ -96,6 +96,39 @@ function useJourneyDiagram() {
96
96
  return journey.toString();
97
97
  }
98
98
 
99
+ /**
100
+ * Example using dynamic methods for runtime participant names
101
+ * Useful when participants are not known at compile time
102
+ */
103
+ function useDynamicSequenceDiagram() {
104
+ const boxes = useBoxColors();
105
+
106
+ // Participants from dynamic data (e.g., from API)
107
+ const participants = ['Alice', 'Bob', 'Charlie'];
108
+ const participantsObj: Record<string, 'participant'> = {};
109
+ participants.forEach(p => { participantsObj[p] = 'participant'; });
110
+
111
+ const seq = SequenceDiagram(participantsObj, { autoNumber: true });
112
+
113
+ // Using dynamic methods - no type assertions needed
114
+ seq.rect(boxes.primary, () => {
115
+ seq.noteOver('Alice', 'Starting conversation');
116
+ seq.message('Alice', 'Bob', 'Hello Bob!');
117
+ seq.message('Bob', 'Alice', 'Hi Alice!', 'syncReply');
118
+ });
119
+
120
+ seq.blank();
121
+
122
+ seq.rect(boxes.success, () => {
123
+ seq.noteOverSpan('Alice', 'Charlie', 'Group discussion');
124
+ seq.message('Alice', 'Charlie', 'Hey Charlie!');
125
+ seq.message('Charlie', 'Bob', 'Bob, join us!');
126
+ seq.message('Bob', 'Charlie', 'On my way!', 'async');
127
+ });
128
+
129
+ return seq.toString();
130
+ }
131
+
99
132
  function useArchitectureDiagram() {
100
133
  type Nodes = 'client' | 'nginx' | 'api1' | 'api2' | 'db' | 'cache' | 'queue';
101
134
  const flow = FlowDiagram<Nodes>({ direction: 'TB' });
@@ -148,7 +181,7 @@ function useArchitectureDiagram() {
148
181
 
149
182
  export const Interactive = () => {
150
183
  const [diagramType] = useSelect('diagramType', {
151
- options: ['flow', 'sequence', 'journey', 'architecture'] as const,
184
+ options: ['flow', 'sequence', 'sequenceDynamic', 'journey', 'architecture'] as const,
152
185
  defaultValue: 'flow',
153
186
  label: 'Diagram Type',
154
187
  });
@@ -160,12 +193,14 @@ export const Interactive = () => {
160
193
 
161
194
  const flowChart = useFlowDiagram();
162
195
  const sequenceChart = useSequenceDiagram();
196
+ const sequenceDynamicChart = useDynamicSequenceDiagram();
163
197
  const journeyChart = useJourneyDiagram();
164
198
  const architectureChart = useArchitectureDiagram();
165
199
 
166
200
  const charts = {
167
201
  flow: flowChart,
168
202
  sequence: sequenceChart,
203
+ sequenceDynamic: sequenceDynamicChart,
169
204
  journey: journeyChart,
170
205
  architecture: architectureChart,
171
206
  };
@@ -18,7 +18,7 @@ import {
18
18
  createCriticalBuilder,
19
19
  createBreakBuilder,
20
20
  } from './functions/getBlocks';
21
- import type { ParticipantsObject, SequenceDiagramOptions, SequenceDiagramBuilder } from './types';
21
+ import type { ParticipantsObject, SequenceDiagramOptions, SequenceDiagramBuilder, DynamicArrowType } from './types';
22
22
 
23
23
  const DEFAULT_OPTIONS: Required<SequenceDiagramOptions> = {
24
24
  autoNumber: false,
@@ -97,10 +97,45 @@ export function SequenceDiagram<P extends string>(
97
97
  const noteBuilder = createNoteBuilder<P>(store, participantKeys);
98
98
  const activationBuilder = createActivationBuilder<P>(store, participantKeys);
99
99
 
100
+ // Arrow type to Mermaid syntax mapping
101
+ const arrowMap: Record<DynamicArrowType, string> = {
102
+ sync: '->>',
103
+ syncReply: '-->>',
104
+ async: '-)',
105
+ asyncReply: '--)',
106
+ solid: '->',
107
+ dotted: '-->',
108
+ cross: '-x',
109
+ crossDotted: '--x',
110
+ };
111
+
100
112
  return {
101
113
  d: messageBuilder,
102
114
  note: noteBuilder,
103
115
  activate: activationBuilder,
116
+
117
+ // Dynamic access methods
118
+ message(from: string, to: string, text: string, arrow: DynamicArrowType = 'sync') {
119
+ const arrowSyntax = arrowMap[arrow] || '->>';
120
+ store.add(`${from}${arrowSyntax}${to}: ${sanitizeLabel(text)}`);
121
+ },
122
+
123
+ noteOver(participant: string, text: string) {
124
+ store.add(`Note over ${participant}: ${sanitizeLabel(text)}`);
125
+ },
126
+
127
+ noteOverSpan(participant1: string, participant2: string, text: string) {
128
+ store.add(`Note over ${participant1},${participant2}: ${sanitizeLabel(text)}`);
129
+ },
130
+
131
+ noteLeft(participant: string, text: string) {
132
+ store.add(`Note left of ${participant}: ${sanitizeLabel(text)}`);
133
+ },
134
+
135
+ noteRight(participant: string, text: string) {
136
+ store.add(`Note right of ${participant}: ${sanitizeLabel(text)}`);
137
+ },
138
+
104
139
  loop: createLoopBuilder(store),
105
140
  alt: createAltBuilder(store),
106
141
  par: createParBuilder(store),
@@ -14,4 +14,5 @@ export type {
14
14
  MessageAction,
15
15
  NoteBuilder,
16
16
  ActivationBuilder,
17
+ DynamicArrowType,
17
18
  } from './types';
@@ -116,6 +116,11 @@ export type ActivationBuilder<P extends string> = {
116
116
  };
117
117
  };
118
118
 
119
+ /**
120
+ * Arrow type for dynamic message method
121
+ */
122
+ export type DynamicArrowType = 'sync' | 'syncReply' | 'async' | 'asyncReply' | 'solid' | 'dotted' | 'cross' | 'crossDotted';
123
+
119
124
  /**
120
125
  * Main SequenceDiagram builder result
121
126
  */
@@ -126,6 +131,46 @@ export interface SequenceDiagramBuilder<P extends string> {
126
131
  note: NoteBuilder<P>;
127
132
  /** Activation builder (activate.Alice.activate()) */
128
133
  activate: ActivationBuilder<P>;
134
+
135
+ // ============================================================================
136
+ // Dynamic access methods (for runtime participant names)
137
+ // ============================================================================
138
+
139
+ /**
140
+ * Send a message dynamically (for runtime participant names)
141
+ * @example message('Alice', 'Bob', 'Hello!') // sync arrow
142
+ * @example message('Alice', 'Bob', 'Hello!', 'async')
143
+ */
144
+ message(from: string, to: string, text: string, arrow?: DynamicArrowType): void;
145
+
146
+ /**
147
+ * Add a note over one participant dynamically
148
+ * @example noteOver('Alice', 'Thinking...')
149
+ */
150
+ noteOver(participant: string, text: string): void;
151
+
152
+ /**
153
+ * Add a note spanning two participants dynamically
154
+ * @example noteOverSpan('Alice', 'Bob', 'Handshake')
155
+ */
156
+ noteOverSpan(participant1: string, participant2: string, text: string): void;
157
+
158
+ /**
159
+ * Add a note to the left of a participant
160
+ * @example noteLeft('Alice', 'Waiting')
161
+ */
162
+ noteLeft(participant: string, text: string): void;
163
+
164
+ /**
165
+ * Add a note to the right of a participant
166
+ * @example noteRight('Alice', 'Done')
167
+ */
168
+ noteRight(participant: string, text: string): void;
169
+
170
+ // ============================================================================
171
+ // Block methods
172
+ // ============================================================================
173
+
129
174
  /** Loop block */
130
175
  loop(label: string, fn: () => void): void;
131
176
  /** Optional/alternative block */