@shumoku/renderer 0.2.1 → 0.2.4

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 (46) hide show
  1. package/dist/html/index.d.ts +25 -0
  2. package/dist/html/index.d.ts.map +1 -1
  3. package/dist/html/index.js +742 -158
  4. package/dist/html/index.js.map +1 -1
  5. package/dist/html/navigation.d.ts +54 -0
  6. package/dist/html/navigation.d.ts.map +1 -0
  7. package/dist/html/navigation.js +210 -0
  8. package/dist/html/navigation.js.map +1 -0
  9. package/dist/html/runtime.d.ts +2 -1
  10. package/dist/html/runtime.d.ts.map +1 -1
  11. package/dist/html/runtime.js +245 -482
  12. package/dist/html/runtime.js.map +1 -1
  13. package/dist/html/spotlight.d.ts +9 -0
  14. package/dist/html/spotlight.d.ts.map +1 -0
  15. package/dist/html/spotlight.js +119 -0
  16. package/dist/html/spotlight.js.map +1 -0
  17. package/dist/html/tooltip.d.ts +14 -0
  18. package/dist/html/tooltip.d.ts.map +1 -0
  19. package/dist/html/tooltip.js +133 -0
  20. package/dist/html/tooltip.js.map +1 -0
  21. package/dist/html/viewbox.d.ts +14 -0
  22. package/dist/html/viewbox.d.ts.map +1 -0
  23. package/dist/html/viewbox.js +21 -0
  24. package/dist/html/viewbox.js.map +1 -0
  25. package/dist/iife-string.d.ts +2 -0
  26. package/dist/iife-string.js +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/shumoku-interactive.iife.js +25 -20
  30. package/dist/svg.d.ts +27 -0
  31. package/dist/svg.d.ts.map +1 -1
  32. package/dist/svg.js +202 -101
  33. package/dist/svg.js.map +1 -1
  34. package/dist/types.d.ts +2 -0
  35. package/dist/types.d.ts.map +1 -1
  36. package/package.json +5 -2
  37. package/src/build-iife-string.ts +26 -19
  38. package/src/html/index.ts +880 -226
  39. package/src/html/navigation.ts +256 -0
  40. package/src/html/runtime.ts +412 -654
  41. package/src/html/spotlight.ts +135 -0
  42. package/src/html/tooltip.ts +141 -0
  43. package/src/html/viewbox.ts +28 -0
  44. package/src/index.ts +25 -22
  45. package/src/svg.ts +1640 -1502
  46. package/src/types.ts +127 -125
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Navigation UI for hierarchical network diagrams
3
+ * Provides breadcrumb, tabs, and back button for sheet navigation
4
+ */
5
+
6
+ /**
7
+ * Navigation state for hierarchical diagrams
8
+ */
9
+ export interface NavigationState {
10
+ /**
11
+ * Current sheet ID (undefined = root)
12
+ */
13
+ currentSheet?: string
14
+
15
+ /**
16
+ * Breadcrumb path from root to current sheet
17
+ */
18
+ breadcrumb: string[]
19
+
20
+ /**
21
+ * Available sheets
22
+ */
23
+ sheets: Map<string, SheetInfo>
24
+ }
25
+
26
+ /**
27
+ * Information about a sheet
28
+ */
29
+ export interface SheetInfo {
30
+ id: string
31
+ label: string
32
+ parentId?: string
33
+ }
34
+
35
+ /**
36
+ * Generate breadcrumb HTML
37
+ */
38
+ export function generateBreadcrumb(state: NavigationState): string {
39
+ const items = state.breadcrumb.map((id, index) => {
40
+ const isLast = index === state.breadcrumb.length - 1
41
+ const label = id === 'root' ? 'Overview' : (state.sheets.get(id)?.label ?? id)
42
+
43
+ if (isLast) {
44
+ return `<span class="breadcrumb-current">${escapeHtml(label)}</span>`
45
+ }
46
+
47
+ return `<button class="breadcrumb-item" data-sheet="${escapeHtml(id)}">${escapeHtml(label)}</button>`
48
+ })
49
+
50
+ return `<nav class="breadcrumb">${items.join('<span class="breadcrumb-sep">/</span>')}</nav>`
51
+ }
52
+
53
+ /**
54
+ * Generate tab navigation HTML for sibling sheets
55
+ */
56
+ export function generateTabs(state: NavigationState, siblingIds: string[]): string {
57
+ if (siblingIds.length <= 1) return ''
58
+
59
+ const tabs = siblingIds.map((id) => {
60
+ const info = state.sheets.get(id)
61
+ const label = info?.label ?? id
62
+ const isActive = id === state.currentSheet
63
+
64
+ return `<button class="tab ${isActive ? 'active' : ''}" data-sheet="${escapeHtml(id)}">${escapeHtml(label)}</button>`
65
+ })
66
+
67
+ return `<div class="tabs">${tabs.join('')}</div>`
68
+ }
69
+
70
+ /**
71
+ * Generate back button HTML
72
+ */
73
+ export function generateBackButton(state: NavigationState): string {
74
+ if (state.breadcrumb.length <= 1) return ''
75
+
76
+ const parentId = state.breadcrumb[state.breadcrumb.length - 2]
77
+ const parentLabel =
78
+ parentId === 'root' ? 'Overview' : (state.sheets.get(parentId)?.label ?? parentId)
79
+
80
+ return `<button class="back-btn" data-sheet="${escapeHtml(parentId)}">
81
+ <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
82
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
83
+ </svg>
84
+ ${escapeHtml(parentLabel)}
85
+ </button>`
86
+ }
87
+
88
+ /**
89
+ * Generate complete navigation toolbar HTML
90
+ */
91
+ export function generateNavigationToolbar(
92
+ state: NavigationState,
93
+ siblingIds: string[] = [],
94
+ ): string {
95
+ const breadcrumb = generateBreadcrumb(state)
96
+ const backBtn = generateBackButton(state)
97
+ const tabs = generateTabs(state, siblingIds)
98
+
99
+ return `<div class="nav-toolbar">
100
+ <div class="nav-row">
101
+ ${backBtn}
102
+ ${breadcrumb}
103
+ </div>
104
+ ${tabs}
105
+ </div>`
106
+ }
107
+
108
+ /**
109
+ * Get CSS styles for navigation components
110
+ */
111
+ export function getNavigationStyles(): string {
112
+ return `
113
+ .nav-toolbar {
114
+ padding: 8px 16px;
115
+ background: white;
116
+ border-bottom: 1px solid #e5e5e5;
117
+ }
118
+ .nav-row {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: 12px;
122
+ }
123
+ .back-btn {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 4px;
127
+ padding: 6px 12px;
128
+ border: 1px solid #e5e5e5;
129
+ background: white;
130
+ border-radius: 6px;
131
+ cursor: pointer;
132
+ font-size: 13px;
133
+ color: #555;
134
+ transition: all 0.15s;
135
+ }
136
+ .back-btn:hover {
137
+ background: #f5f5f5;
138
+ border-color: #ccc;
139
+ }
140
+ .breadcrumb {
141
+ display: flex;
142
+ align-items: center;
143
+ gap: 4px;
144
+ font-size: 13px;
145
+ }
146
+ .breadcrumb-item {
147
+ background: none;
148
+ border: none;
149
+ color: #0066cc;
150
+ cursor: pointer;
151
+ padding: 4px 8px;
152
+ border-radius: 4px;
153
+ }
154
+ .breadcrumb-item:hover {
155
+ background: #f0f7ff;
156
+ }
157
+ .breadcrumb-current {
158
+ color: #333;
159
+ font-weight: 500;
160
+ }
161
+ .breadcrumb-sep {
162
+ color: #999;
163
+ }
164
+ .tabs {
165
+ display: flex;
166
+ gap: 4px;
167
+ margin-top: 8px;
168
+ border-bottom: 1px solid #e5e5e5;
169
+ padding-bottom: 0;
170
+ }
171
+ .tab {
172
+ padding: 8px 16px;
173
+ border: none;
174
+ background: none;
175
+ cursor: pointer;
176
+ font-size: 13px;
177
+ color: #666;
178
+ border-bottom: 2px solid transparent;
179
+ margin-bottom: -1px;
180
+ transition: all 0.15s;
181
+ }
182
+ .tab:hover {
183
+ color: #333;
184
+ background: #f5f5f5;
185
+ }
186
+ .tab.active {
187
+ color: #0066cc;
188
+ border-bottom-color: #0066cc;
189
+ font-weight: 500;
190
+ }
191
+ `
192
+ }
193
+
194
+ /**
195
+ * Get JavaScript code for navigation event handling
196
+ */
197
+ export function getNavigationScript(): string {
198
+ return `
199
+ (function() {
200
+ function navigateToSheet(sheetId) {
201
+ // Dispatch custom event for sheet navigation
202
+ var event = new CustomEvent('shumoku:navigate', {
203
+ detail: { sheetId: sheetId },
204
+ bubbles: true
205
+ });
206
+ document.dispatchEvent(event);
207
+
208
+ // For standalone HTML, show alert (sheets are not embedded yet)
209
+ console.log('[Shumoku] Navigate to sheet:', sheetId);
210
+ alert('Navigate to: ' + sheetId + '\\n\\nNote: Multi-sheet navigation requires embedded sheets.');
211
+ }
212
+
213
+ // Listen for navigation events from subgraph clicks
214
+ document.addEventListener('shumoku:navigate', function(e) {
215
+ var sheetId = e.detail && e.detail.sheetId;
216
+ if (sheetId) {
217
+ console.log('[Shumoku] Subgraph clicked, sheet:', sheetId);
218
+ alert('Navigate to: ' + sheetId + '\\n\\nNote: Multi-sheet navigation requires embedded sheets.');
219
+ }
220
+ });
221
+
222
+ // Handle breadcrumb clicks
223
+ document.querySelectorAll('.breadcrumb-item').forEach(function(btn) {
224
+ btn.addEventListener('click', function() {
225
+ var sheetId = this.getAttribute('data-sheet');
226
+ if (sheetId) navigateToSheet(sheetId);
227
+ });
228
+ });
229
+
230
+ // Handle back button clicks
231
+ document.querySelectorAll('.back-btn').forEach(function(btn) {
232
+ btn.addEventListener('click', function() {
233
+ var sheetId = this.getAttribute('data-sheet');
234
+ if (sheetId) navigateToSheet(sheetId);
235
+ });
236
+ });
237
+
238
+ // Handle tab clicks
239
+ document.querySelectorAll('.tab').forEach(function(btn) {
240
+ btn.addEventListener('click', function() {
241
+ var sheetId = this.getAttribute('data-sheet');
242
+ if (sheetId) navigateToSheet(sheetId);
243
+ });
244
+ });
245
+ })();
246
+ `
247
+ }
248
+
249
+ function escapeHtml(str: string): string {
250
+ return str
251
+ .replace(/&/g, '&amp;')
252
+ .replace(/</g, '&lt;')
253
+ .replace(/>/g, '&gt;')
254
+ .replace(/"/g, '&quot;')
255
+ .replace(/'/g, '&#39;')
256
+ }