@diagrammo/dgmo 0.8.20 → 0.8.21
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/dist/cli.cjs +92 -90
- package/dist/editor.cjs +13 -1
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +13 -1
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +13 -1
- package/dist/highlight.cjs.map +1 -1
- package/dist/highlight.js +13 -1
- package/dist/highlight.js.map +1 -1
- package/dist/index.cjs +4144 -940
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +318 -84
- package/dist/index.d.ts +318 -84
- package/dist/index.js +4132 -938
- package/dist/index.js.map +1 -1
- package/docs/guide/chart-mindmap.md +198 -0
- package/docs/guide/chart-sequence.md +23 -1
- package/docs/guide/chart-wireframe.md +100 -0
- package/docs/guide/index.md +8 -0
- package/docs/language-reference.md +137 -2
- package/package.json +1 -1
- package/src/boxes-and-lines/collapse.ts +21 -3
- package/src/boxes-and-lines/layout.ts +51 -9
- package/src/boxes-and-lines/parser.ts +8 -1
- package/src/boxes-and-lines/renderer.ts +121 -23
- package/src/boxes-and-lines/types.ts +1 -0
- package/src/completion.ts +26 -0
- package/src/d3.ts +153 -32
- package/src/dgmo-router.ts +6 -0
- package/src/editor/keywords.ts +12 -0
- package/src/graph/layout.ts +73 -9
- package/src/graph/state-collapse.ts +78 -0
- package/src/graph/state-renderer.ts +139 -34
- package/src/index.ts +28 -0
- package/src/kanban/renderer.ts +303 -57
- package/src/mindmap/collapse.ts +88 -0
- package/src/mindmap/layout.ts +605 -0
- package/src/mindmap/parser.ts +379 -0
- package/src/mindmap/renderer.ts +543 -0
- package/src/mindmap/text-wrap.ts +207 -0
- package/src/mindmap/types.ts +55 -0
- package/src/render.ts +18 -21
- package/src/sequence/renderer.ts +129 -18
- package/src/sharing.ts +2 -0
- package/src/sitemap/layout.ts +35 -12
- package/src/utils/export-container.ts +3 -2
- package/src/utils/legend-d3.ts +1 -0
- package/src/utils/legend-layout.ts +2 -2
- package/src/utils/parsing.ts +2 -0
- package/src/wireframe/layout.ts +460 -0
- package/src/wireframe/parser.ts +956 -0
- package/src/wireframe/renderer.ts +1293 -0
- package/src/wireframe/types.ts +110 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Mind Map
|
|
2
|
+
|
|
3
|
+
```dgmo
|
|
4
|
+
mindmap Product Strategy
|
|
5
|
+
|
|
6
|
+
Research
|
|
7
|
+
User Interviews
|
|
8
|
+
Surveys | description: Quarterly NPS survey
|
|
9
|
+
Focus Groups
|
|
10
|
+
Competitor Analysis
|
|
11
|
+
Feature Matrix
|
|
12
|
+
Pricing Review
|
|
13
|
+
Development
|
|
14
|
+
MVP Features
|
|
15
|
+
Auth System
|
|
16
|
+
description: Handle login, signup, OAuth flows
|
|
17
|
+
Dashboard
|
|
18
|
+
Nice-to-haves | collapsed: true
|
|
19
|
+
Dark Mode
|
|
20
|
+
Export PDF
|
|
21
|
+
Go-to-Market
|
|
22
|
+
Launch Plan
|
|
23
|
+
Blog Post
|
|
24
|
+
Demo Video | description: 2-min product walkthrough
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
Mind maps visualize hierarchical information radiating from a central concept. Each branch represents a subtopic, with deeper nesting for finer detail. Mind maps are useful for brainstorming, project planning, knowledge organization, and breaking down complex topics.
|
|
30
|
+
|
|
31
|
+
**Interactive features:** Click nodes to navigate to their source line. Collapse and expand subtrees by clicking nodes with children. Toggle tag group coloring and depth-based coloring via the legend controls.
|
|
32
|
+
|
|
33
|
+
## Syntax
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
mindmap Title
|
|
37
|
+
|
|
38
|
+
Node
|
|
39
|
+
Child Node
|
|
40
|
+
Grandchild
|
|
41
|
+
Another Child
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The first line declares the chart type. The title becomes the root node. Indentation establishes the parent-child hierarchy.
|
|
45
|
+
|
|
46
|
+
## Nodes
|
|
47
|
+
|
|
48
|
+
Every non-blank, non-directive line is a node. Nesting is set by indentation:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
mindmap Root
|
|
52
|
+
Level 1a
|
|
53
|
+
Level 2a
|
|
54
|
+
Level 2b
|
|
55
|
+
Level 1b
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Node Colors
|
|
59
|
+
|
|
60
|
+
Add a color suffix in parentheses:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Important Topic(red)
|
|
64
|
+
Sub-topic(blue)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Descriptions
|
|
68
|
+
|
|
69
|
+
Nodes can have descriptions shown as secondary text. Two forms:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
// Pipe form (single line)
|
|
73
|
+
Surveys | description: Quarterly NPS survey
|
|
74
|
+
|
|
75
|
+
// Indented form (before children)
|
|
76
|
+
Auth System
|
|
77
|
+
description: Handle login, signup, and OAuth flows
|
|
78
|
+
Login Page
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Collapse Default
|
|
82
|
+
|
|
83
|
+
Set a node's default collapsed state with pipe metadata:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Nice-to-haves | collapsed: true
|
|
87
|
+
Dark Mode
|
|
88
|
+
Export PDF
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Collapsed nodes show a drill-bar indicating hidden children. Click to expand.
|
|
92
|
+
|
|
93
|
+
## Multi-Root
|
|
94
|
+
|
|
95
|
+
Omit the title to create multiple independent root trees:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
mindmap
|
|
99
|
+
|
|
100
|
+
Q1 Goals
|
|
101
|
+
Ship MVP
|
|
102
|
+
Hire designers
|
|
103
|
+
Q2 Goals
|
|
104
|
+
Launch marketing
|
|
105
|
+
Expand team
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The diagram title is inferred from the first root's label.
|
|
109
|
+
|
|
110
|
+
## Pipe Metadata
|
|
111
|
+
|
|
112
|
+
Attach metadata after `|` with comma-separated `key: value` pairs:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Node | priority: High, status: Done
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Tag values, descriptions, and `collapsed` are all set via pipe metadata.
|
|
119
|
+
|
|
120
|
+
## Tag Groups
|
|
121
|
+
|
|
122
|
+
Tag groups define color-coded categories. They appear before content and follow the standard tag syntax:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
mindmap Root
|
|
126
|
+
|
|
127
|
+
tag Priority p
|
|
128
|
+
High(red)
|
|
129
|
+
Medium(yellow)
|
|
130
|
+
Low(green)
|
|
131
|
+
|
|
132
|
+
Task A | p: High
|
|
133
|
+
Task B | p: Low
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- The alias (`p`) provides a shorthand for metadata keys
|
|
137
|
+
- The active tag group colors nodes by their tag value
|
|
138
|
+
- Click a tag group name in the legend to activate or deactivate it
|
|
139
|
+
|
|
140
|
+
## Options
|
|
141
|
+
|
|
142
|
+
| Option | Effect |
|
|
143
|
+
|--------|--------|
|
|
144
|
+
| `active-tag GroupName` | Set the default active tag group |
|
|
145
|
+
| `hide-descriptions` | Hide description text on all nodes |
|
|
146
|
+
|
|
147
|
+
Options are placed on their own line before content:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
mindmap Root
|
|
151
|
+
|
|
152
|
+
tag Priority p
|
|
153
|
+
High(red)
|
|
154
|
+
Low(green)
|
|
155
|
+
|
|
156
|
+
active-tag Priority
|
|
157
|
+
hide-descriptions
|
|
158
|
+
|
|
159
|
+
Task A | p: High
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Complete Example
|
|
163
|
+
|
|
164
|
+
```dgmo
|
|
165
|
+
mindmap Product Strategy(blue)
|
|
166
|
+
|
|
167
|
+
tag Priority p
|
|
168
|
+
High(red)
|
|
169
|
+
Medium(yellow)
|
|
170
|
+
Low(green)
|
|
171
|
+
|
|
172
|
+
tag Department d
|
|
173
|
+
Engineering(blue)
|
|
174
|
+
Design(purple)
|
|
175
|
+
Marketing(orange)
|
|
176
|
+
|
|
177
|
+
active-tag Priority
|
|
178
|
+
|
|
179
|
+
Research | d: Marketing
|
|
180
|
+
User Interviews | p: High
|
|
181
|
+
Surveys | description: Quarterly NPS survey
|
|
182
|
+
Focus Groups
|
|
183
|
+
Competitor Analysis | d: Engineering
|
|
184
|
+
Feature Matrix
|
|
185
|
+
Pricing Review
|
|
186
|
+
Development | p: High, d: Engineering
|
|
187
|
+
MVP Features
|
|
188
|
+
Auth System
|
|
189
|
+
description: Handle login, signup, OAuth flows
|
|
190
|
+
Dashboard
|
|
191
|
+
Nice-to-haves | p: Low, collapsed: true
|
|
192
|
+
Dark Mode
|
|
193
|
+
Export PDF
|
|
194
|
+
Go-to-Market | d: Marketing
|
|
195
|
+
Launch Plan
|
|
196
|
+
Blog Post
|
|
197
|
+
Demo Video | description: 2-min product walkthrough
|
|
198
|
+
```
|
|
@@ -103,7 +103,29 @@ PaymentGW is a networking aka "Payment Gateway"
|
|
|
103
103
|
OrderDB position -1
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
## Participant Ordering
|
|
107
|
+
|
|
108
|
+
Participants are laid out left-to-right based on **first appearance in messages** — the first participant mentioned gets the leftmost column.
|
|
109
|
+
|
|
110
|
+
**Position values:**
|
|
111
|
+
- `0` = leftmost, `1` = second from left, etc.
|
|
112
|
+
- `-1` = rightmost, `-2` = second from right
|
|
113
|
+
- If two participants target the same slot, the later one shifts to the nearest free position
|
|
114
|
+
|
|
115
|
+
**Groups affect ordering:** members of the same group always stay adjacent (see [Groups](#groups) below). The group is placed where its first member would naturally appear.
|
|
116
|
+
|
|
117
|
+
**Priority (highest wins):**
|
|
118
|
+
1. Explicit `position N`
|
|
119
|
+
2. Group adjacency
|
|
120
|
+
3. First appearance in messages
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
// Example: force the database to the far right
|
|
124
|
+
sequence
|
|
125
|
+
User -placeOrder-> OrderService
|
|
126
|
+
OrderService -save-> OrderDB
|
|
127
|
+
OrderDB position -1
|
|
128
|
+
```
|
|
107
129
|
|
|
108
130
|
## Messages
|
|
109
131
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Wireframe
|
|
2
|
+
|
|
3
|
+
```dgmo
|
|
4
|
+
wireframe Login Page
|
|
5
|
+
|
|
6
|
+
[Header]
|
|
7
|
+
Acme App
|
|
8
|
+
nav
|
|
9
|
+
Home | active
|
|
10
|
+
About
|
|
11
|
+
Pricing
|
|
12
|
+
|
|
13
|
+
[Main]
|
|
14
|
+
# Sign In
|
|
15
|
+
|
|
16
|
+
Email [user@example.com]
|
|
17
|
+
Password [****] | password
|
|
18
|
+
|
|
19
|
+
<x> Remember me
|
|
20
|
+
|
|
21
|
+
(Sign In)
|
|
22
|
+
(Forgot Password?) | ghost
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
New here? (Create Account) | ghost
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Overview
|
|
30
|
+
|
|
31
|
+
Wireframe diagrams use **visual-mnemonic syntax** where bracket characters communicate the element type. The source text reads as a wireframe even before rendering.
|
|
32
|
+
|
|
33
|
+
## Elements
|
|
34
|
+
|
|
35
|
+
| Syntax | Element |
|
|
36
|
+
|--------|---------|
|
|
37
|
+
| `[text]` (no children) | Text input |
|
|
38
|
+
| `[Name]` (with children) | Group / region |
|
|
39
|
+
| `(Label)` | Button |
|
|
40
|
+
| `{A \| B \| C}` | Dropdown |
|
|
41
|
+
| `<x>` / `< >` | Checkbox |
|
|
42
|
+
| `(*) Label` / `( ) Label` | Radio button |
|
|
43
|
+
| `# Text` | Heading |
|
|
44
|
+
| `## Text` | Subheading |
|
|
45
|
+
| `---` | Divider |
|
|
46
|
+
| `- text` | List item |
|
|
47
|
+
|
|
48
|
+
## Keywords
|
|
49
|
+
|
|
50
|
+
`nav`, `tabs`, `table`, `image`, `modal`, `skeleton`, `alert`, `progress`, `chart`
|
|
51
|
+
|
|
52
|
+
- `image round` / `image wide` — shape hints
|
|
53
|
+
- `chart line` / `chart bar` / `chart pie` — chart silhouettes
|
|
54
|
+
- `progress 60` — percentage bar
|
|
55
|
+
- `table 5x4` — skeleton table with dimensions
|
|
56
|
+
|
|
57
|
+
## States
|
|
58
|
+
|
|
59
|
+
Pipe metadata flags on elements:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
(Submit) | disabled
|
|
63
|
+
(Delete) | destructive
|
|
64
|
+
(Cancel) | ghost
|
|
65
|
+
[Email] | password
|
|
66
|
+
[Notes] | textarea
|
|
67
|
+
<x> Dark mode | toggle
|
|
68
|
+
[Cards] | horizontal
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Layout
|
|
72
|
+
|
|
73
|
+
- **Desktop** (default): 1200px, top-level regions side-by-side
|
|
74
|
+
- **Mobile**: `mobile` keyword, 375px vertical stacking
|
|
75
|
+
- **Smart sizing**: `sidebar` gets ~25%, `main` fills remaining
|
|
76
|
+
- `| horizontal` on any group arranges children in a row
|
|
77
|
+
|
|
78
|
+
## Multi-Element Lines
|
|
79
|
+
|
|
80
|
+
Two or more spaces between elements on one line:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Email [user@example.com] // label + field
|
|
84
|
+
(-) 1 (+) // inline stepper
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Tables
|
|
88
|
+
|
|
89
|
+
```dgmo
|
|
90
|
+
wireframe Data
|
|
91
|
+
|
|
92
|
+
table
|
|
93
|
+
Name, Email, Role
|
|
94
|
+
John, john@, Admin
|
|
95
|
+
Sally, sally@, Editor
|
|
96
|
+
|
|
97
|
+
// Skeleton shorthand:
|
|
98
|
+
table 5x4
|
|
99
|
+
Name, Email, Role, Status
|
|
100
|
+
```
|
package/docs/guide/index.md
CHANGED
|
@@ -4,6 +4,14 @@ Diagrammo is a diagram editor for creating charts and diagrams with a simple pla
|
|
|
4
4
|
|
|
5
5
|
Learn more at **[diagrammo.app](https://diagrammo.app)**.
|
|
6
6
|
|
|
7
|
+
## DGMO and Diagrammo
|
|
8
|
+
|
|
9
|
+
**DGMO** is the plain-text markup language you write. **Diagrammo** is the app you write it in.
|
|
10
|
+
|
|
11
|
+
Think of it like Markdown and your editor — Markdown is the syntax, and you can write it anywhere. DGMO works the same way: it's a `.dgmo` text file that describes a diagram. You can create and edit `.dgmo` files in the Diagrammo desktop app, the online editor, Obsidian (via plugin), or any text editor. The `dgmo` CLI renders them from the terminal, and the `@diagrammo/dgmo` npm package lets you render them programmatically.
|
|
12
|
+
|
|
13
|
+
The name "DGMO" is shorthand for "Diagrammo" — shorter to type, easier to use as a file extension and command name.
|
|
14
|
+
|
|
7
15
|
## Getting Started
|
|
8
16
|
|
|
9
17
|
- **Create a new file** using the file tree on the left, or press **Cmd + N**
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
14. [Timeline Diagrams](#14-timeline-diagrams)
|
|
21
21
|
15. [Data Charts](#15-data-charts)
|
|
22
22
|
16. [Visualizations](#16-visualizations)
|
|
23
|
-
17. [
|
|
23
|
+
17. [Wireframe Diagrams](#17-wireframe-diagrams)
|
|
24
|
+
18. [Colon Usage Summary](#18-colon-usage-summary)
|
|
24
25
|
|
|
25
26
|
---
|
|
26
27
|
|
|
@@ -1326,7 +1327,141 @@ Navigator 0.85 0.8
|
|
|
1326
1327
|
|
|
1327
1328
|
---
|
|
1328
1329
|
|
|
1329
|
-
## 17.
|
|
1330
|
+
## 17. Wireframe Diagrams
|
|
1331
|
+
|
|
1332
|
+
Wireframe diagrams use **visual-mnemonic syntax** where bracket characters communicate element type.
|
|
1333
|
+
|
|
1334
|
+
### Declaration
|
|
1335
|
+
|
|
1336
|
+
```
|
|
1337
|
+
wireframe Page Title
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
### Form Factor
|
|
1341
|
+
|
|
1342
|
+
```
|
|
1343
|
+
mobile
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
Switches to narrow vertical layout (375px). Desktop (1200px, horizontal regions) is the default.
|
|
1347
|
+
|
|
1348
|
+
### Visual-Mnemonic Elements
|
|
1349
|
+
|
|
1350
|
+
| Syntax | Element | Example |
|
|
1351
|
+
|--------|---------|---------|
|
|
1352
|
+
| `[text]` (leaf) | Text input | `[Email address]` |
|
|
1353
|
+
| `[Name]` (with children) | Group/region | `[Sidebar]` + indented children |
|
|
1354
|
+
| `(Label)` | Button | `(Submit)` |
|
|
1355
|
+
| `{A \| B \| C}` | Dropdown/select | `{Small \| Medium \| Large}` |
|
|
1356
|
+
| `<x>` / `< >` | Checkbox | `<x> Remember me` |
|
|
1357
|
+
| `(*) Label` / `( ) Label` | Radio button | `(*) Option A` |
|
|
1358
|
+
| `# Text` / `## Text` | Heading | `# Sign In` |
|
|
1359
|
+
| `---` | Divider | `---` |
|
|
1360
|
+
| `- text` | List item | `- Electronics` |
|
|
1361
|
+
| Bare text | Text/paragraph | `Welcome to our app` |
|
|
1362
|
+
|
|
1363
|
+
### Keyword Elements
|
|
1364
|
+
|
|
1365
|
+
| Keyword | Type | Parameters |
|
|
1366
|
+
|---------|------|------------|
|
|
1367
|
+
| `nav` | Block | Children are nav items |
|
|
1368
|
+
| `tabs` | Block | Children are tab labels |
|
|
1369
|
+
| `table` | Block | Comma-separated rows; first = header |
|
|
1370
|
+
| `table RxC` | Skeleton table | `table 5x4` + optional header row |
|
|
1371
|
+
| `image` | Leaf | `round`, `wide` hints |
|
|
1372
|
+
| `modal Title` | Block | Rendered as separate panel below |
|
|
1373
|
+
| `skeleton` | Block | Children render as grey placeholders |
|
|
1374
|
+
| `alert` | Block | Optional semantic state |
|
|
1375
|
+
| `progress N` | Leaf | Value 0-100: `progress 60` |
|
|
1376
|
+
| `chart type` | Leaf | `chart line`, `chart bar`, `chart pie` |
|
|
1377
|
+
|
|
1378
|
+
### Pipe Metadata (States)
|
|
1379
|
+
|
|
1380
|
+
Wireframe uses flag keywords (not `key: value`):
|
|
1381
|
+
|
|
1382
|
+
```
|
|
1383
|
+
(Submit) | disabled
|
|
1384
|
+
(Delete) | destructive
|
|
1385
|
+
(Cancel) | ghost
|
|
1386
|
+
[Email] | password
|
|
1387
|
+
[Notes] | textarea
|
|
1388
|
+
[Cards] | horizontal
|
|
1389
|
+
[Advanced] | collapsed
|
|
1390
|
+
[Messages] | scrollable
|
|
1391
|
+
<x> Dark mode | toggle
|
|
1392
|
+
```
|
|
1393
|
+
|
|
1394
|
+
Available states: `disabled`, `active`, `selected`, `empty`, `ghost`, `destructive`, `success`, `warning`, `info`, `scrollable`, `collapsed`, `toggle`, `password`, `textarea`, `horizontal`, `primary`.
|
|
1395
|
+
|
|
1396
|
+
Free-text annotations after states: `[Email] | required, validates email format`.
|
|
1397
|
+
|
|
1398
|
+
### Multi-Element Lines
|
|
1399
|
+
|
|
1400
|
+
Two or more spaces between segments create separate elements:
|
|
1401
|
+
|
|
1402
|
+
```
|
|
1403
|
+
Email [user@example.com] // label + field (2 segments)
|
|
1404
|
+
(-) 1 (+) // 3 inline items
|
|
1405
|
+
$299.99 ~~$349.99~~ // 2 inline texts
|
|
1406
|
+
```
|
|
1407
|
+
|
|
1408
|
+
- **2 segments** (bare text + element): label-for-element pairing
|
|
1409
|
+
- **3+ segments**: inline items, no label pairing
|
|
1410
|
+
- **Single space = same element**: `Cart (3)` is one text element
|
|
1411
|
+
|
|
1412
|
+
### Group Disambiguation
|
|
1413
|
+
|
|
1414
|
+
- `[Name]` with indented children = group/container
|
|
1415
|
+
- `[Name]` with no children = text input
|
|
1416
|
+
- `[Name] | horizontal/scrollable/collapsed` = group (even without children)
|
|
1417
|
+
|
|
1418
|
+
### Table Syntax
|
|
1419
|
+
|
|
1420
|
+
Explicit rows (comma-separated, first row = header):
|
|
1421
|
+
|
|
1422
|
+
```
|
|
1423
|
+
table
|
|
1424
|
+
Name, Email, Role
|
|
1425
|
+
John, john@, Admin
|
|
1426
|
+
Sally, sally@, Editor
|
|
1427
|
+
```
|
|
1428
|
+
|
|
1429
|
+
Skeleton shorthand:
|
|
1430
|
+
|
|
1431
|
+
```
|
|
1432
|
+
table 5x4
|
|
1433
|
+
Name, Email, Role, Status
|
|
1434
|
+
```
|
|
1435
|
+
|
|
1436
|
+
### Layout Model
|
|
1437
|
+
|
|
1438
|
+
- Desktop: 1200px wide, top-level regions arrange horizontally
|
|
1439
|
+
- Mobile: 375px wide, all regions stack vertically
|
|
1440
|
+
- Smart sizing: `sidebar` → ~25%, `main`/`content` → fill, `header`/`footer` → full width
|
|
1441
|
+
- `| horizontal` on groups arranges children in a row
|
|
1442
|
+
|
|
1443
|
+
### Example
|
|
1444
|
+
|
|
1445
|
+
```
|
|
1446
|
+
wireframe Login Page
|
|
1447
|
+
|
|
1448
|
+
[Header]
|
|
1449
|
+
nav
|
|
1450
|
+
Home | active
|
|
1451
|
+
Settings
|
|
1452
|
+
|
|
1453
|
+
[Main]
|
|
1454
|
+
# Sign In
|
|
1455
|
+
Email [user@example.com]
|
|
1456
|
+
Password [****] | password
|
|
1457
|
+
<x> Remember me
|
|
1458
|
+
(Sign In)
|
|
1459
|
+
(Forgot Password?) | ghost
|
|
1460
|
+
```
|
|
1461
|
+
|
|
1462
|
+
---
|
|
1463
|
+
|
|
1464
|
+
## 18. Colon Usage Summary
|
|
1330
1465
|
|
|
1331
1466
|
### Constructs Where Colons Are REQUIRED
|
|
1332
1467
|
|
package/package.json
CHANGED
|
@@ -40,12 +40,28 @@ export function collapseBoxesAndLines(
|
|
|
40
40
|
const nodeToGroup = new Map<string, string>();
|
|
41
41
|
const collapsedChildCounts = new Map<string, number>();
|
|
42
42
|
|
|
43
|
+
// Recursively collect all descendants of a group (including sub-group children)
|
|
44
|
+
function collectDescendants(groupLabel: string): string[] {
|
|
45
|
+
const group = groupByLabel.get(groupLabel);
|
|
46
|
+
if (!group) return [];
|
|
47
|
+
const descendants: string[] = [];
|
|
48
|
+
for (const child of group.children) {
|
|
49
|
+
descendants.push(child);
|
|
50
|
+
// If child is itself a group, collect its descendants too
|
|
51
|
+
if (groupByLabel.has(child)) {
|
|
52
|
+
descendants.push(...collectDescendants(child));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return descendants;
|
|
56
|
+
}
|
|
57
|
+
|
|
43
58
|
for (const groupLabel of collapsedGroups) {
|
|
44
59
|
const group = groupByLabel.get(groupLabel);
|
|
45
60
|
if (!group) continue;
|
|
46
61
|
const groupId = `__group_${groupLabel}`;
|
|
47
62
|
|
|
48
|
-
|
|
63
|
+
const allDescendants = collectDescendants(groupLabel);
|
|
64
|
+
for (const child of allDescendants) {
|
|
49
65
|
nodeToGroup.set(child, groupId);
|
|
50
66
|
}
|
|
51
67
|
collapsedChildCounts.set(groupLabel, group.children.length);
|
|
@@ -67,8 +83,10 @@ export function collapseBoxesAndLines(
|
|
|
67
83
|
edges.push({ ...edge, source: src, target: tgt });
|
|
68
84
|
}
|
|
69
85
|
|
|
70
|
-
// Keep only groups that are not collapsed
|
|
71
|
-
const groups = parsed.groups.filter(
|
|
86
|
+
// Keep only groups that are not collapsed and not inside a collapsed group
|
|
87
|
+
const groups = parsed.groups.filter(
|
|
88
|
+
(g) => !collapsedGroups.has(g.label) && !nodeToGroup.has(g.label)
|
|
89
|
+
);
|
|
72
90
|
|
|
73
91
|
return {
|
|
74
92
|
parsed: { ...parsed, nodes, edges, groups },
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ============================================================
|
|
4
4
|
|
|
5
5
|
import dagre from '@dagrejs/dagre';
|
|
6
|
-
import type { ParsedBoxesAndLines, BLNode } from './types';
|
|
6
|
+
import type { ParsedBoxesAndLines, BLNode, BLGroup } from './types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Clip a point at (cx, cy) to the border of a rectangle centered at (cx, cy)
|
|
@@ -38,8 +38,7 @@ const CONTAINER_PAD_X = 30;
|
|
|
38
38
|
const CONTAINER_PAD_TOP = 40;
|
|
39
39
|
const CONTAINER_PAD_BOTTOM = 24;
|
|
40
40
|
const MAX_PARALLEL_EDGES = 5;
|
|
41
|
-
const PARALLEL_SPACING =
|
|
42
|
-
const PARALLEL_EDGE_MARGIN = 10;
|
|
41
|
+
const PARALLEL_SPACING = 22;
|
|
43
42
|
|
|
44
43
|
// ── Result types ───────────────────────────────────────────
|
|
45
44
|
|
|
@@ -116,12 +115,23 @@ export function layoutBoxesAndLines(
|
|
|
116
115
|
});
|
|
117
116
|
g.setDefaultEdgeLabel(() => ({}));
|
|
118
117
|
|
|
119
|
-
// Determine which groups are collapsed
|
|
118
|
+
// Determine which groups are collapsed (but not hidden inside a collapsed parent)
|
|
120
119
|
const collapsedGroupLabels = new Set<string>();
|
|
121
120
|
if (collapseInfo) {
|
|
121
|
+
// Build set of all groups that are missing from parsed (collapsed or hidden)
|
|
122
|
+
const missingGroups = new Set<string>();
|
|
122
123
|
for (const og of collapseInfo.originalGroups) {
|
|
123
124
|
if (!parsed.groups.some((g) => g.label === og.label)) {
|
|
124
|
-
|
|
125
|
+
missingGroups.add(og.label);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Only show a collapsed group as a node if its parent is NOT also missing
|
|
129
|
+
// (i.e., it's a directly collapsed group, not one hidden inside a collapsed parent)
|
|
130
|
+
for (const label of missingGroups) {
|
|
131
|
+
const og = collapseInfo.originalGroups.find((g) => g.label === label);
|
|
132
|
+
const parentLabel = og?.parentGroup;
|
|
133
|
+
if (!parentLabel || !missingGroups.has(parentLabel)) {
|
|
134
|
+
collapsedGroupLabels.add(label);
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
137
|
}
|
|
@@ -147,6 +157,25 @@ export function layoutBoxesAndLines(
|
|
|
147
157
|
});
|
|
148
158
|
}
|
|
149
159
|
|
|
160
|
+
// Re-establish parent relationships for collapsed groups
|
|
161
|
+
// (must run AFTER expanded groups are added to the graph)
|
|
162
|
+
const originalGroupByLabel = new Map<string, BLGroup>();
|
|
163
|
+
if (collapseInfo) {
|
|
164
|
+
for (const og of collapseInfo.originalGroups) {
|
|
165
|
+
originalGroupByLabel.set(og.label, og);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const label of collapsedGroupLabels) {
|
|
169
|
+
const og = originalGroupByLabel.get(label);
|
|
170
|
+
if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup)) {
|
|
171
|
+
const gid = `__group_${label}`;
|
|
172
|
+
const parentGid = `__group_${og.parentGroup}`;
|
|
173
|
+
if (g.hasNode(parentGid)) {
|
|
174
|
+
g.setParent(gid, parentGid);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
150
179
|
// Add nodes
|
|
151
180
|
for (const node of parsed.nodes) {
|
|
152
181
|
const size = computeNodeSize(node);
|
|
@@ -157,10 +186,26 @@ export function layoutBoxesAndLines(
|
|
|
157
186
|
});
|
|
158
187
|
}
|
|
159
188
|
|
|
189
|
+
// Set parent relationships for nested groups
|
|
190
|
+
for (const group of parsed.groups) {
|
|
191
|
+
if (group.parentGroup) {
|
|
192
|
+
const childGid = `__group_${group.label}`;
|
|
193
|
+
const parentGid = `__group_${group.parentGroup}`;
|
|
194
|
+
if (g.hasNode(childGid) && g.hasNode(parentGid)) {
|
|
195
|
+
g.setParent(childGid, parentGid);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Build set of group labels for skip-check below
|
|
201
|
+
const groupLabelSet = new Set(parsed.groups.map((gr) => gr.label));
|
|
202
|
+
|
|
160
203
|
// Set parent relationships for nodes in groups
|
|
161
204
|
for (const group of parsed.groups) {
|
|
162
205
|
const gid = `__group_${group.label}`;
|
|
163
206
|
for (const child of group.children) {
|
|
207
|
+
// Skip children that are sub-groups — their parent is set above
|
|
208
|
+
if (groupLabelSet.has(child)) continue;
|
|
164
209
|
if (g.hasNode(child)) {
|
|
165
210
|
g.setParent(child, gid);
|
|
166
211
|
}
|
|
@@ -263,10 +308,7 @@ export function layoutBoxesAndLines(
|
|
|
263
308
|
edgeParallelCounts[idx] = 0;
|
|
264
309
|
}
|
|
265
310
|
if (capped.length < 2) continue;
|
|
266
|
-
const effectiveSpacing =
|
|
267
|
-
PARALLEL_SPACING,
|
|
268
|
-
(60 - PARALLEL_EDGE_MARGIN) / (capped.length - 1)
|
|
269
|
-
);
|
|
311
|
+
const effectiveSpacing = PARALLEL_SPACING;
|
|
270
312
|
for (let j = 0; j < capped.length; j++) {
|
|
271
313
|
edgeYOffsets[capped[j]] =
|
|
272
314
|
(j - (capped.length - 1) / 2) * effectiveSpacing;
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
OPTION_NOCOLON_RE,
|
|
21
21
|
} from '../utils/parsing';
|
|
22
22
|
|
|
23
|
-
const MAX_GROUP_DEPTH =
|
|
23
|
+
const MAX_GROUP_DEPTH = 2;
|
|
24
24
|
|
|
25
25
|
/** Boxes-and-lines requires explicit first line — no heuristic detection. */
|
|
26
26
|
export function looksLikeBoxesAndLines(_content: string): boolean {
|
|
@@ -387,13 +387,20 @@ export function parseBoxesAndLines(content: string): ParsedBoxesAndLines {
|
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
+
const parentGs = currentGroupState();
|
|
390
391
|
const group: BLGroup = {
|
|
391
392
|
label,
|
|
392
393
|
children: [],
|
|
393
394
|
lineNumber: lineNum,
|
|
394
395
|
metadata: groupMeta,
|
|
396
|
+
...(parentGs ? { parentGroup: parentGs.group.label } : {}),
|
|
395
397
|
};
|
|
396
398
|
|
|
399
|
+
// Add nested group as child of parent group
|
|
400
|
+
if (parentGs && indent > parentGs.indent) {
|
|
401
|
+
parentGs.group.children.push(label);
|
|
402
|
+
}
|
|
403
|
+
|
|
397
404
|
groupLabels.add(label);
|
|
398
405
|
groupStack.push({ group, indent, depth: currentDepth });
|
|
399
406
|
lastNodeLabel = label;
|