@djangocfg/ui-tools 2.1.159 → 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 +40 -1
- package/package.json +6 -6
- package/src/tools/Mermaid/Mermaid.story.tsx +36 -1
- package/src/tools/Mermaid/builders/SequenceDiagram/SequenceDiagram.ts +36 -1
- package/src/tools/Mermaid/builders/SequenceDiagram/index.ts +1 -0
- package/src/tools/Mermaid/builders/SequenceDiagram/types.ts +45 -0
package/README.md
CHANGED
|
@@ -361,6 +361,8 @@ flow.style.apply('myStyle', 'A', 'B');
|
|
|
361
361
|
|
|
362
362
|
### SequenceDiagram API
|
|
363
363
|
|
|
364
|
+
**Static API** (type-safe, for known participants):
|
|
365
|
+
|
|
364
366
|
```tsx
|
|
365
367
|
const { d, rect, alt, loop, toString } = SequenceDiagram({
|
|
366
368
|
User: 'actor',
|
|
@@ -368,7 +370,7 @@ const { d, rect, alt, loop, toString } = SequenceDiagram({
|
|
|
368
370
|
API: 'participant',
|
|
369
371
|
}, { autoNumber: true });
|
|
370
372
|
|
|
371
|
-
// Messages
|
|
373
|
+
// Messages (type-safe chain)
|
|
372
374
|
d.User.sync.App.msg('Click button');
|
|
373
375
|
d.App.async.API.msg('Fetch data');
|
|
374
376
|
d.API.asyncReply.App.msg('Response');
|
|
@@ -391,6 +393,43 @@ loop('Every 5s', () => {
|
|
|
391
393
|
return toString();
|
|
392
394
|
```
|
|
393
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
|
+
|
|
394
433
|
### JourneyDiagram API
|
|
395
434
|
|
|
396
435
|
```tsx
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-tools",
|
|
3
|
-
"version": "2.1.
|
|
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",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"check": "tsc --noEmit"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"@djangocfg/i18n": "^2.1.
|
|
72
|
-
"@djangocfg/ui-core": "^2.1.
|
|
71
|
+
"@djangocfg/i18n": "^2.1.160",
|
|
72
|
+
"@djangocfg/ui-core": "^2.1.160",
|
|
73
73
|
"lucide-react": "^0.545.0",
|
|
74
74
|
"react": "^19.0.0",
|
|
75
75
|
"react-dom": "^19.0.0",
|
|
@@ -101,10 +101,10 @@
|
|
|
101
101
|
"@maplibre/maplibre-gl-geocoder": "^1.7.0"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
|
-
"@djangocfg/i18n": "^2.1.
|
|
104
|
+
"@djangocfg/i18n": "^2.1.160",
|
|
105
105
|
"@djangocfg/playground": "workspace:*",
|
|
106
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
107
|
-
"@djangocfg/ui-core": "^2.1.
|
|
106
|
+
"@djangocfg/typescript-config": "^2.1.160",
|
|
107
|
+
"@djangocfg/ui-core": "^2.1.160",
|
|
108
108
|
"@types/mapbox__mapbox-gl-draw": "^1.4.8",
|
|
109
109
|
"@types/node": "^24.7.2",
|
|
110
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),
|
|
@@ -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 */
|