@pauloricca/spagbol 0.0.0-stage → 0.1.1

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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +338 -2
  3. package/dist/controls.css +122 -0
  4. package/dist/core/controller.d.ts +89 -0
  5. package/dist/core/controller.d.ts.map +1 -0
  6. package/dist/core/controller.js +732 -0
  7. package/dist/core/controller.js.map +1 -0
  8. package/dist/core/graph.d.ts +30 -0
  9. package/dist/core/graph.d.ts.map +1 -0
  10. package/dist/core/graph.js +318 -0
  11. package/dist/core/graph.js.map +1 -0
  12. package/dist/core/grouping.d.ts +10 -0
  13. package/dist/core/grouping.d.ts.map +1 -0
  14. package/dist/core/grouping.js +130 -0
  15. package/dist/core/grouping.js.map +1 -0
  16. package/dist/core/groups.d.ts +40 -0
  17. package/dist/core/groups.d.ts.map +1 -0
  18. package/dist/core/groups.js +164 -0
  19. package/dist/core/groups.js.map +1 -0
  20. package/dist/core/index.d.ts +8 -0
  21. package/dist/core/index.d.ts.map +1 -0
  22. package/dist/core/index.js +8 -0
  23. package/dist/core/index.js.map +1 -0
  24. package/dist/core/model.d.ts +182 -0
  25. package/dist/core/model.d.ts.map +1 -0
  26. package/dist/core/model.js +149 -0
  27. package/dist/core/model.js.map +1 -0
  28. package/dist/core/observations.d.ts +10 -0
  29. package/dist/core/observations.d.ts.map +1 -0
  30. package/dist/core/observations.js +36 -0
  31. package/dist/core/observations.js.map +1 -0
  32. package/dist/core/serialization.d.ts +9 -0
  33. package/dist/core/serialization.d.ts.map +1 -0
  34. package/dist/core/serialization.js +148 -0
  35. package/dist/core/serialization.js.map +1 -0
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +4 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/link-controls.css +123 -0
  41. package/dist/react/Controls.d.ts +18 -0
  42. package/dist/react/Controls.d.ts.map +1 -0
  43. package/dist/react/Controls.js +301 -0
  44. package/dist/react/Controls.js.map +1 -0
  45. package/dist/react/SpagbolCanvas.d.ts +38 -0
  46. package/dist/react/SpagbolCanvas.d.ts.map +1 -0
  47. package/dist/react/SpagbolCanvas.js +1248 -0
  48. package/dist/react/SpagbolCanvas.js.map +1 -0
  49. package/dist/react/SpagbolCanvasControls.d.ts +36 -0
  50. package/dist/react/SpagbolCanvasControls.d.ts.map +1 -0
  51. package/dist/react/SpagbolCanvasControls.js +113 -0
  52. package/dist/react/SpagbolCanvasControls.js.map +1 -0
  53. package/dist/react/SpagbolCanvasFlow.d.ts +14 -0
  54. package/dist/react/SpagbolCanvasFlow.d.ts.map +1 -0
  55. package/dist/react/SpagbolCanvasFlow.js +6 -0
  56. package/dist/react/SpagbolCanvasFlow.js.map +1 -0
  57. package/dist/react/SpagbolCanvasLinkControls.d.ts +16 -0
  58. package/dist/react/SpagbolCanvasLinkControls.d.ts.map +1 -0
  59. package/dist/react/SpagbolCanvasLinkControls.js +7 -0
  60. package/dist/react/SpagbolCanvasLinkControls.js.map +1 -0
  61. package/dist/react/SpagbolCanvasMenu.d.ts +12 -0
  62. package/dist/react/SpagbolCanvasMenu.d.ts.map +1 -0
  63. package/dist/react/SpagbolCanvasMenu.js +65 -0
  64. package/dist/react/SpagbolCanvasMenu.js.map +1 -0
  65. package/dist/react/SpagbolControlNumber.d.ts +25 -0
  66. package/dist/react/SpagbolControlNumber.d.ts.map +1 -0
  67. package/dist/react/SpagbolControlNumber.js +209 -0
  68. package/dist/react/SpagbolControlNumber.js.map +1 -0
  69. package/dist/react/SpagbolControlNumberLink.d.ts +6 -0
  70. package/dist/react/SpagbolControlNumberLink.d.ts.map +1 -0
  71. package/dist/react/SpagbolControlNumberLink.js +159 -0
  72. package/dist/react/SpagbolControlNumberLink.js.map +1 -0
  73. package/dist/react/SpagbolControlZoom.d.ts +11 -0
  74. package/dist/react/SpagbolControlZoom.d.ts.map +1 -0
  75. package/dist/react/SpagbolControlZoom.js +24 -0
  76. package/dist/react/SpagbolControlZoom.js.map +1 -0
  77. package/dist/react/SpagbolNodeFrame.d.ts +35 -0
  78. package/dist/react/SpagbolNodeFrame.d.ts.map +1 -0
  79. package/dist/react/SpagbolNodeFrame.js +171 -0
  80. package/dist/react/SpagbolNodeFrame.js.map +1 -0
  81. package/dist/react/SpagbolNodeFrameTypePicker.d.ts +9 -0
  82. package/dist/react/SpagbolNodeFrameTypePicker.d.ts.map +1 -0
  83. package/dist/react/SpagbolNodeFrameTypePicker.js +68 -0
  84. package/dist/react/SpagbolNodeFrameTypePicker.js.map +1 -0
  85. package/dist/react/SpagbolNodeGroupPort.d.ts +15 -0
  86. package/dist/react/SpagbolNodeGroupPort.d.ts.map +1 -0
  87. package/dist/react/SpagbolNodeGroupPort.js +62 -0
  88. package/dist/react/SpagbolNodeGroupPort.js.map +1 -0
  89. package/dist/react/SpagbolNodeGroupPortAdd.d.ts +5 -0
  90. package/dist/react/SpagbolNodeGroupPortAdd.d.ts.map +1 -0
  91. package/dist/react/SpagbolNodeGroupPortAdd.js +27 -0
  92. package/dist/react/SpagbolNodeGroupPortAdd.js.map +1 -0
  93. package/dist/react/context.d.ts +84 -0
  94. package/dist/react/context.d.ts.map +1 -0
  95. package/dist/react/context.js +43 -0
  96. package/dist/react/context.js.map +1 -0
  97. package/dist/react/duplicateDrag.d.ts +19 -0
  98. package/dist/react/duplicateDrag.d.ts.map +1 -0
  99. package/dist/react/duplicateDrag.js +71 -0
  100. package/dist/react/duplicateDrag.js.map +1 -0
  101. package/dist/react/flowPresentation.d.ts +11 -0
  102. package/dist/react/flowPresentation.d.ts.map +1 -0
  103. package/dist/react/flowPresentation.js +50 -0
  104. package/dist/react/flowPresentation.js.map +1 -0
  105. package/dist/react/geometry.d.ts +13 -0
  106. package/dist/react/geometry.d.ts.map +1 -0
  107. package/dist/react/geometry.js +43 -0
  108. package/dist/react/geometry.js.map +1 -0
  109. package/dist/react/index.d.ts +11 -0
  110. package/dist/react/index.d.ts.map +1 -0
  111. package/dist/react/index.js +11 -0
  112. package/dist/react/index.js.map +1 -0
  113. package/dist/react/nodeDrag.d.ts +7 -0
  114. package/dist/react/nodeDrag.d.ts.map +1 -0
  115. package/dist/react/nodeDrag.js +27 -0
  116. package/dist/react/nodeDrag.js.map +1 -0
  117. package/dist/react/portState.d.ts +10 -0
  118. package/dist/react/portState.d.ts.map +1 -0
  119. package/dist/react/portState.js +35 -0
  120. package/dist/react/portState.js.map +1 -0
  121. package/dist/react/viewport.d.ts +24 -0
  122. package/dist/react/viewport.d.ts.map +1 -0
  123. package/dist/react/viewport.js +55 -0
  124. package/dist/react/viewport.js.map +1 -0
  125. package/dist/styles.css +748 -0
  126. package/package.json +58 -4
  127. package/src/core/controller.ts +844 -0
  128. package/src/core/graph.ts +451 -0
  129. package/src/core/grouping.ts +159 -0
  130. package/src/core/groups.ts +125 -0
  131. package/src/core/index.ts +7 -0
  132. package/src/core/model.ts +304 -0
  133. package/src/core/observations.ts +31 -0
  134. package/src/core/serialization.ts +184 -0
  135. package/src/index.ts +9 -0
  136. package/src/react/Controls.tsx +355 -0
  137. package/src/react/SpagbolCanvas.tsx +1893 -0
  138. package/src/react/SpagbolCanvasControls.tsx +255 -0
  139. package/src/react/SpagbolCanvasFlow.tsx +38 -0
  140. package/src/react/SpagbolCanvasLinkControls.tsx +21 -0
  141. package/src/react/SpagbolCanvasMenu.tsx +121 -0
  142. package/src/react/SpagbolControlNumber.tsx +297 -0
  143. package/src/react/SpagbolControlNumberLink.tsx +209 -0
  144. package/src/react/SpagbolControlZoom.tsx +102 -0
  145. package/src/react/SpagbolNodeFrame.tsx +330 -0
  146. package/src/react/SpagbolNodeFrameTypePicker.tsx +51 -0
  147. package/src/react/SpagbolNodeGroupPort.tsx +111 -0
  148. package/src/react/SpagbolNodeGroupPortAdd.tsx +48 -0
  149. package/src/react/context.tsx +146 -0
  150. package/src/react/controls.css +122 -0
  151. package/src/react/duplicateDrag.ts +97 -0
  152. package/src/react/flowPresentation.ts +56 -0
  153. package/src/react/geometry.ts +53 -0
  154. package/src/react/index.ts +61 -0
  155. package/src/react/link-controls.css +123 -0
  156. package/src/react/nodeDrag.ts +33 -0
  157. package/src/react/portState.ts +24 -0
  158. package/src/react/styles.css +748 -0
  159. package/src/react/viewport.ts +90 -0
@@ -0,0 +1,748 @@
1
+ @import "./link-controls.css";
2
+ @import "./controls.css";
3
+ @import "@xyflow/react/dist/style.css";
4
+
5
+ .spagbol-canvas {
6
+ --spagbol-bg: #000;
7
+ --spagbol-surface: rgba(0, 0, 0, 0.72);
8
+ --spagbol-surface-raised: rgba(0, 0, 0, 0.9);
9
+ --spagbol-foreground: #fff;
10
+ --spagbol-muted: #777;
11
+ --spagbol-border: #fff;
12
+ --spagbol-header: #fff;
13
+ --spagbol-header-text: #000;
14
+ --spagbol-accent: #2fd061;
15
+ --spagbol-selection: #ffff8a;
16
+ --spagbol-selection-outline: #fff;
17
+ --spagbol-error: #ff7474;
18
+ --spagbol-grid: rgba(255, 255, 255, 0.08);
19
+ --spagbol-control: rgba(0, 0, 0, 0.62);
20
+ --spagbol-link-underlay: #0b0b0b;
21
+ --spagbol-control-size: 28px;
22
+ --spagbol-font:
23
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
24
+ monospace;
25
+ position: relative;
26
+ width: 100%;
27
+ height: 100%;
28
+ min-width: 0;
29
+ min-height: 0;
30
+ overflow: hidden;
31
+ isolation: isolate;
32
+ color: var(--spagbol-foreground);
33
+ background: var(--spagbol-bg);
34
+ font: 13px / normal var(--spagbol-font);
35
+ outline: none;
36
+ }
37
+ .spagbol-canvas *,
38
+ .spagbol-canvas *::before,
39
+ .spagbol-canvas *::after {
40
+ box-sizing: border-box;
41
+ }
42
+ .spagbol-canvas button,
43
+ .spagbol-canvas input,
44
+ .spagbol-canvas select {
45
+ font: inherit;
46
+ color: inherit;
47
+ }
48
+ .spagbol-canvas button {
49
+ cursor: pointer;
50
+ }
51
+ .spagbol-canvas button:disabled {
52
+ opacity: 0.35;
53
+ cursor: default;
54
+ }
55
+ .spagbol-canvas button:focus-visible,
56
+ .spagbol-canvas input:focus-visible,
57
+ .spagbol-canvas select:focus-visible,
58
+ .spagbol-canvas [tabindex]:focus-visible {
59
+ outline: none;
60
+ }
61
+ .spagbol-canvas .react-flow {
62
+ --xy-edge-stroke: var(--spagbol-foreground);
63
+ --xy-selection-background-color: #b9df6820;
64
+ --xy-selection-border: 1px solid var(--spagbol-accent);
65
+ --xy-connectionline-stroke: var(--spagbol-accent);
66
+ }
67
+ /* Preserve Teia's individual selection styling without a group rectangle. */
68
+ .spagbol-canvas .react-flow__nodesselection-rect {
69
+ border: 0 !important;
70
+ background: transparent !important;
71
+ box-shadow: none !important;
72
+ outline: 0;
73
+ pointer-events: none;
74
+ }
75
+ .spagbol-canvas .react-flow__pane {
76
+ cursor: crosshair;
77
+ }
78
+ .spagbol-canvas .react-flow__node {
79
+ border-radius: 0;
80
+ }
81
+ .spagbol-canvas .react-flow__edgeupdater { fill: transparent; stroke: transparent; stroke-width: 0; cursor: grab; pointer-events: all; }
82
+ .spagbol-canvas .react-flow__edgeupdater-source { transform: translateX(-12px); }
83
+ .spagbol-canvas .react-flow__edgeupdater-target { transform: translateX(12px); }
84
+ .spagbol-canvas .spagbol-node-port.spagbol-node-port-selected-link { background: var(--spagbol-accent); border-color: var(--spagbol-accent); box-shadow: 0 0 0 2px var(--spagbol-link-underlay); pointer-events: none; }
85
+ .spagbol-canvas-link-overlay { position: absolute; inset: 0; z-index: 25; pointer-events: none; }
86
+
87
+ .spagbol-canvas .react-flow__attribution {
88
+ background: transparent;
89
+ color: var(--spagbol-muted);
90
+ }
91
+ .spagbol-canvas .react-flow__attribution a {
92
+ color: inherit;
93
+ }
94
+ .spagbol-node-frame {
95
+ width: 100%;
96
+ min-width: 150px;
97
+ height: 100%;
98
+ background: var(--spagbol-surface);
99
+ border: 1px solid var(--spagbol-border);
100
+ box-shadow: none;
101
+ }
102
+ .spagbol-node-frame-selected {
103
+ outline: 2px solid var(--spagbol-selection-outline);
104
+ outline-offset: 4px;
105
+ box-shadow:
106
+ 0 0 0 1px var(--spagbol-bg),
107
+ 0 0 0 6px #ffffff47;
108
+ }
109
+ .spagbol-node-frame-selected > .spagbol-node-frame-header {
110
+ background: var(--spagbol-selection);
111
+ color: var(--spagbol-header-text);
112
+ }
113
+ .spagbol-canvas .spagbol-canvas-duplicate-preview {
114
+ opacity: 0.7;
115
+ }
116
+ .spagbol-canvas-duplicate-origin {
117
+ height: 100%;
118
+ pointer-events: none;
119
+ }
120
+ .spagbol-canvas-link-preview {
121
+ opacity: 0.7;
122
+ }
123
+ .spagbol-node-frame-disabled {
124
+ opacity: 0.48;
125
+ border-style: dashed;
126
+ }
127
+ .spagbol-node-frame-header {
128
+ min-height: 31px;
129
+ padding: 4px 8px;
130
+ border-bottom: 1px solid var(--spagbol-border);
131
+ display: flex;
132
+ align-items: center;
133
+ gap: 6px;
134
+ background: var(--spagbol-header);
135
+ color: var(--spagbol-header-text);
136
+ cursor: grab;
137
+ user-select: none;
138
+ }
139
+ .spagbol-node-frame-title {
140
+ flex: 1;
141
+ min-width: 0;
142
+ overflow: visible;
143
+ text-overflow: ellipsis;
144
+ white-space: nowrap;
145
+ font-size: calc(13px * var(--spagbol-title-scale, 1));
146
+ font-weight: 700;
147
+ }
148
+ .spagbol-canvas .spagbol-node-frame-header-button {
149
+ border: 0;
150
+ background: transparent;
151
+ color: inherit;
152
+ font-size: 14px;
153
+ padding: 0 2px;
154
+ line-height: 1;
155
+ }
156
+ .spagbol-node-frame-body {
157
+ padding: 0;
158
+ }
159
+ .spagbol-node-frame-ports {
160
+ display: grid;
161
+ grid-template-columns: minmax(0, 1fr) minmax(64px, max-content);
162
+ gap: 10px;
163
+ padding: 8px 0;
164
+ }
165
+ .spagbol-node-port-row {
166
+ position: relative;
167
+ display: flex;
168
+ align-items: center;
169
+ gap: 6px;
170
+ padding: 0 8px;
171
+ min-height: 26px;
172
+ min-width: 0;
173
+ width: 100%;
174
+ }
175
+ .spagbol-node-port-row-input {
176
+ grid-column: 1;
177
+ }
178
+ .spagbol-node-port-row-output {
179
+ grid-column: 2;
180
+ }
181
+ .spagbol-canvas-link {
182
+ stroke-width: 2px;
183
+ fill: none;
184
+ transition: opacity 100ms;
185
+ }
186
+ .spagbol-canvas-link-emphasized {
187
+ stroke-width: 3px;
188
+ }
189
+ .spagbol-canvas-link-underlay {
190
+ stroke: var(--spagbol-link-underlay);
191
+ pointer-events: none;
192
+ }
193
+ .spagbol-canvas-link-dimmed {
194
+ opacity: 0.2;
195
+ }
196
+ .spagbol-canvas-link-disabled {
197
+ stroke-dasharray: 5 5;
198
+ opacity: 0.4;
199
+ }
200
+ .spagbol-canvas-link-control,
201
+ .spagbol-canvas-link-virtual {
202
+ stroke-dasharray: 2 5;
203
+ }
204
+ .spagbol-canvas-link-error {
205
+ stroke: var(--spagbol-error) !important;
206
+ }
207
+ .spagbol-canvas-link-hit {
208
+ stroke: transparent;
209
+ stroke-width: 1px;
210
+ }
211
+ .spagbol-canvas-link-diagnostic {
212
+ position: absolute;
213
+ background: var(--spagbol-error);
214
+ color: var(--spagbol-bg);
215
+ border-radius: 50%;
216
+ padding: 0 6px;
217
+ }
218
+ .spagbol-canvas-link-anchor {
219
+ width: 1px;
220
+ height: 1px;
221
+ pointer-events: none;
222
+ }
223
+ .spagbol-canvas .spagbol-property-port {
224
+ top: 0;
225
+ left: 0;
226
+ width: 9px;
227
+ height: 9px;
228
+ border: 1px solid var(--spagbol-accent);
229
+ background: var(--spagbol-bg);
230
+ pointer-events: auto;
231
+ }
232
+ .spagbol-canvas-area {
233
+ position: relative;
234
+ border: 1px solid var(--spagbol-border);
235
+ background: #ffffff03;
236
+ pointer-events: none;
237
+ }
238
+ .spagbol-canvas-area-selected {
239
+ border-color: var(--spagbol-accent);
240
+ }
241
+ .spagbol-canvas-area-header {
242
+ position: absolute;
243
+ top: 0;
244
+ left: 0;
245
+ right: 0;
246
+ height: 32px;
247
+ padding: 5px 10px;
248
+ background: var(--spagbol-surface-raised);
249
+ color: var(--spagbol-muted);
250
+ display: flex;
251
+ justify-content: space-between;
252
+ cursor: move;
253
+ pointer-events: auto;
254
+ user-select: none;
255
+ touch-action: none;
256
+ }
257
+ .spagbol-canvas-area-header > span {
258
+ flex: 1;
259
+ font-size: calc(11px * var(--spagbol-title-scale, 1));
260
+ }
261
+ .spagbol-canvas-area-actions {
262
+ display: flex;
263
+ gap: 8px;
264
+ }
265
+ .spagbol-canvas-area-actions button {
266
+ border: none;
267
+ background: transparent;
268
+ padding: 0 2px;
269
+ }
270
+ .spagbol-canvas-area-resize {
271
+ position: absolute;
272
+ bottom: 0;
273
+ right: 0;
274
+ width: 15px;
275
+ height: 15px;
276
+ background: linear-gradient(
277
+ 135deg,
278
+ transparent 65%,
279
+ var(--spagbol-border) 65%,
280
+ var(--spagbol-border) 75%,
281
+ transparent 75%
282
+ );
283
+ border: 0;
284
+ pointer-events: auto;
285
+ cursor: nwse-resize;
286
+ touch-action: none;
287
+ }
288
+ .spagbol-canvas-area-divider {
289
+ position: absolute;
290
+ left: 0;
291
+ right: 0;
292
+ border-top: 1px dashed var(--spagbol-border);
293
+ }
294
+ .spagbol-canvas .spagbol-canvas-area-pin {
295
+ opacity: 0;
296
+ pointer-events: none;
297
+ }
298
+ .spagbol-canvas-area-draft {
299
+ position: absolute;
300
+ border: 1px dashed var(--spagbol-accent);
301
+ background: #b9df680b;
302
+ pointer-events: none;
303
+ }
304
+ .spagbol-canvas-controls {
305
+ position: absolute;
306
+ bottom: var(--spagbol-canvas-controls-inset, 14px);
307
+ left: var(--spagbol-canvas-controls-inset, 14px);
308
+ right: var(--spagbol-canvas-controls-inset, 14px);
309
+ z-index: 12;
310
+ display: grid;
311
+ grid-template-columns: auto minmax(0, 1fr);
312
+ gap: 12px;
313
+ align-items: end;
314
+ pointer-events: none;
315
+ }
316
+ .spagbol-control-zoom,
317
+ .spagbol-canvas-actions,
318
+ .spagbol-canvas-breadcrumbs {
319
+ pointer-events: auto;
320
+ }
321
+ .spagbol-canvas-controls button,
322
+ .spagbol-canvas-breadcrumbs button {
323
+ border: 1px solid var(--spagbol-border);
324
+ background: var(--spagbol-surface);
325
+ padding: 0 8px;
326
+ height: var(--spagbol-control-size, 30px);
327
+ border-radius: 0;
328
+ white-space: nowrap;
329
+ }
330
+ .spagbol-canvas-controls button:hover:not(:disabled),
331
+ .spagbol-canvas-controls button:focus-visible,
332
+ .spagbol-canvas-breadcrumbs button:hover {
333
+ background: var(--spagbol-header);
334
+ color: var(--spagbol-header-text);
335
+ }
336
+ .spagbol-control-zoom-corner {
337
+ display: flex;
338
+ align-items: end;
339
+ justify-self: start;
340
+ }
341
+ .spagbol-canvas-controls-no-zoom {
342
+ grid-template-columns: minmax(0, 1fr);
343
+ }
344
+ .spagbol-control-zoom-stack {
345
+ display: flex;
346
+ flex-direction: column;
347
+ }
348
+ .spagbol-control-zoom-stack button {
349
+ width: var(--spagbol-control-size, 30px);
350
+ padding: 0;
351
+ font-size: 18px;
352
+ }
353
+ .spagbol-control-zoom-stack button + button {
354
+ margin-top: -1px;
355
+ }
356
+ .spagbol-control-zoom-stack svg {
357
+ width: 14px;
358
+ height: 14px;
359
+ fill: none;
360
+ stroke: currentColor;
361
+ stroke-width: 1.5;
362
+ vertical-align: middle;
363
+ }
364
+ .spagbol-control-zoom-extras {
365
+ display: flex;
366
+ flex-direction: column;
367
+ align-items: start;
368
+ margin-left: -1px;
369
+ }
370
+ .spagbol-control-zoom-percentage {
371
+ min-width: 48px;
372
+ font-variant-numeric: tabular-nums;
373
+ }
374
+ .spagbol-canvas-actions {
375
+ display: flex;
376
+ flex-wrap: wrap;
377
+ gap: 6px;
378
+ align-items: center;
379
+ justify-content: flex-end;
380
+ justify-self: end;
381
+ min-width: 0;
382
+ max-width: 100%;
383
+ position: relative;
384
+ }
385
+ .spagbol-canvas-actions-leading {
386
+ gap: 6px;
387
+ display: flex;
388
+ align-items: center;
389
+ min-width: 0;
390
+ }
391
+ .spagbol-canvas-actions-leading input {
392
+ min-width: 0;
393
+ width: min(160px, 25vw);
394
+ height: var(--spagbol-control-size, 30px);
395
+ border: 1px solid var(--spagbol-border);
396
+ background: var(--spagbol-surface);
397
+ padding: 0 8px;
398
+ }
399
+ .spagbol-canvas-menu {
400
+ position: relative;
401
+ display: flex;
402
+ }
403
+ .spagbol-canvas-menu-items {
404
+ position: absolute;
405
+ right: 0;
406
+ bottom: 100%;
407
+ display: flex;
408
+ flex-direction: column;
409
+ gap: 6px;
410
+ min-width: 202px;
411
+ width: max-content;
412
+ max-width: min(320px, calc(100vw - 40px));
413
+ max-height: min(350px, calc(var(--spagbol-canvas-height, 100vh) - 80px));
414
+ overflow-y: auto;
415
+ padding-bottom: 6px;
416
+ }
417
+ .spagbol-canvas-menu-items[hidden] {
418
+ display: none;
419
+ }
420
+ .spagbol-canvas-menu-items > button {
421
+ width: 100%;
422
+ flex-shrink: 0;
423
+ display: flex;
424
+ align-items: center;
425
+ justify-content: flex-start;
426
+ gap: 8px;
427
+ text-align: left;
428
+ }
429
+ .spagbol-canvas-menu-check {
430
+ display: inline-block;
431
+ width: 12px;
432
+ flex-shrink: 0;
433
+ }
434
+ .spagbol-canvas-menu-separator {
435
+ height: 1px;
436
+ background: var(--spagbol-border);
437
+ margin: 2px 0;
438
+ }
439
+ .spagbol-canvas-breadcrumbs {
440
+ position: absolute;
441
+ top: 14px;
442
+ left: 14px;
443
+ right: 14px;
444
+ display: flex;
445
+ flex-wrap: wrap;
446
+ gap: 5px;
447
+ z-index: 12;
448
+ width: fit-content;
449
+ max-width: calc(100% - 28px);
450
+ }
451
+ .spagbol-canvas-actions-error {
452
+ position: absolute;
453
+ right: 0;
454
+ bottom: calc(100% + 8px);
455
+ min-width: 200px;
456
+ max-width: min(400px, 80vw);
457
+ background: var(--spagbol-surface);
458
+ color: var(--spagbol-error);
459
+ border: 1px solid var(--spagbol-error);
460
+ padding: 8px;
461
+ }
462
+ .spagbol-canvas-actions-error button {
463
+ height: 20px;
464
+ margin-left: 8px;
465
+ }
466
+ .spagbol-canvas-picker {
467
+ position: absolute;
468
+ width: 248px;
469
+ border: 1px solid var(--spagbol-border);
470
+ background: var(--spagbol-surface);
471
+ z-index: 30;
472
+ box-shadow: 0 10px 40px #0007;
473
+ }
474
+ .spagbol-canvas-picker-heading {
475
+ padding: 9px 10px;
476
+ display: flex;
477
+ align-items: center;
478
+ justify-content: space-between;
479
+ background: var(--spagbol-header);
480
+ color: var(--spagbol-header-text);
481
+ }
482
+ .spagbol-canvas-picker-heading button {
483
+ border: 0;
484
+ background: none;
485
+ color: inherit;
486
+ font-size: 18px;
487
+ line-height: 16px;
488
+ }
489
+ .spagbol-canvas-picker input {
490
+ margin: 8px;
491
+ width: calc(100% - 16px);
492
+ padding: 8px;
493
+ border: 1px solid var(--spagbol-border);
494
+ border-radius: 0;
495
+ background: var(--spagbol-bg);
496
+ }
497
+ .spagbol-canvas-picker-list {
498
+ max-height: 230px;
499
+ overflow: auto;
500
+ padding: 0 5px 6px;
501
+ }
502
+ .spagbol-canvas-picker-list button {
503
+ display: flex;
504
+ justify-content: space-between;
505
+ gap: 8px;
506
+ width: 100%;
507
+ text-align: left;
508
+ padding: 7px;
509
+ border: 0;
510
+ background: transparent;
511
+ }
512
+ .spagbol-canvas-picker-list button:hover {
513
+ background: var(--spagbol-surface-raised);
514
+ color: var(--spagbol-accent);
515
+ }
516
+ .spagbol-canvas-picker-list small {
517
+ color: var(--spagbol-muted);
518
+ }
519
+ .spagbol-canvas-picker-list p {
520
+ padding: 5px;
521
+ color: var(--spagbol-muted);
522
+ }
523
+ .spagbol-node-frame-diagnostics {
524
+ padding: 6px 10px;
525
+ color: var(--spagbol-error);
526
+ border-top: 1px solid var(--spagbol-border);
527
+ font-size: 10px;
528
+ }
529
+ .spagbol-canvas-error {
530
+ position: absolute;
531
+ left: 18px;
532
+ bottom: 62px;
533
+ max-width: min(500px, 90%);
534
+ padding: 10px;
535
+ border: 1px solid var(--spagbol-error);
536
+ background: var(--spagbol-surface);
537
+ color: var(--spagbol-error);
538
+ z-index: 30;
539
+ }
540
+ .spagbol-canvas-error button {
541
+ border: 0;
542
+ background: transparent;
543
+ color: inherit;
544
+ margin-left: 12px;
545
+ }
546
+ .spagbol-canvas-background {
547
+ position: absolute;
548
+ inset: 0;
549
+ pointer-events: none;
550
+ }
551
+ .spagbol-canvas-overlay {
552
+ position: absolute;
553
+ inset: 0;
554
+ pointer-events: none;
555
+ z-index: 15;
556
+ }
557
+ .spagbol-canvas-overlay > * {
558
+ pointer-events: auto;
559
+ }
560
+ .spagbol-node-panel { position: relative; padding: 0; overflow: hidden; }
561
+ .spagbol-node-panel-item { padding: 0; border: 0; background: transparent; }
562
+
563
+ .spagbol-node-frame-projected {
564
+ min-width: 0;
565
+ border: 0;
566
+ box-shadow: none;
567
+ }
568
+ .spagbol-canvas .react-flow__resize-control.handle {
569
+ border: 1px solid var(--spagbol-bg);
570
+ border-radius: 0;
571
+ background: var(--spagbol-accent);
572
+ }
573
+ @media (max-width: 640px) {
574
+ .spagbol-canvas-controls {
575
+ left: 10px;
576
+ right: 10px;
577
+ gap: 3px;
578
+ }
579
+ .spagbol-canvas-controls button {
580
+ padding: 5px;
581
+ font-size: 10px;
582
+ }
583
+ }
584
+
585
+ .spagbol-node-frame-enabled { display: inline-flex; width: 20px; height: 20px; flex: 0 0 auto; align-items: center; justify-content: center; margin-left: auto; padding: 0; border: 0; background: transparent; color: currentColor; cursor: pointer; }
586
+ .spagbol-node-frame-enabled-icon { display: block; width: 12px; height: 12px; box-sizing: border-box; border: 1px solid currentColor; border-radius: 50%; }
587
+ .spagbol-node-frame-disabled .spagbol-node-frame-enabled-icon { background: currentColor; }
588
+ .spagbol-node-frame-enabled:hover, .spagbol-node-frame-enabled:focus-visible { background: var(--spagbol-bg); color: var(--spagbol-foreground); outline: 0; }
589
+ .spagbol-node-frame-type-picker-button { display: inline; border: 0; background: transparent; color: inherit; padding: 0; font: inherit; cursor: inherit; }
590
+ .spagbol-node-frame-type-picker-editor {
591
+ position: absolute;
592
+ z-index: 30;
593
+ top: 0;
594
+ left: 0;
595
+ width: 100%;
596
+ }
597
+
598
+ .spagbol-node-frame-type-picker {
599
+ position: relative;
600
+ display: inline-block;
601
+ max-width: 100%;
602
+ min-width: 0;
603
+ height: 22px;
604
+ white-space: nowrap;
605
+ }
606
+
607
+ .spagbol-node-frame-type-picker-placeholder {
608
+ display: inline-block;
609
+ visibility: hidden;
610
+ height: 22px;
611
+ font-weight: 700;
612
+ line-height: 22px;
613
+ }
614
+
615
+ .spagbol-node-frame-type-picker-input {
616
+ display: block;
617
+ width: 100%;
618
+ height: 22px;
619
+ padding: 0 4px;
620
+ border: 1px solid var(--spagbol-bg, #000);
621
+ background: var(--spagbol-foreground, #fff);
622
+ color: var(--spagbol-bg, #000);
623
+ font: inherit;
624
+ font-weight: 700;
625
+ }
626
+
627
+ .spagbol-node-frame-type-picker-input::selection {
628
+ background: #000b;
629
+ color: var(--spagbol-foreground, #fff);
630
+ }
631
+
632
+ .spagbol-node-frame-type-picker-menu {
633
+ position: absolute;
634
+ top: calc(100% + 5px);
635
+ left: 0;
636
+ width: max-content;
637
+ min-width: 12ch;
638
+ max-width: 18ch;
639
+ max-height: 220px;
640
+ overflow: auto;
641
+ overscroll-behavior: contain;
642
+ border: 1px solid var(--spagbol-foreground, #fff);
643
+ background: #000e;
644
+ color: var(--spagbol-foreground, #fff);
645
+ box-shadow: 0 0 0 1px var(--spagbol-bg, #000);
646
+ }
647
+
648
+ .spagbol-node-frame-type-picker-menu button,
649
+ .spagbol-node-frame-type-picker-empty {
650
+ display: block;
651
+ width: 100%;
652
+ height: 24px;
653
+ padding: 0 6px;
654
+ border: 0;
655
+ border-bottom: 1px solid #333;
656
+ background: transparent;
657
+ color: var(--spagbol-foreground, #fff);
658
+ font: inherit;
659
+ text-align: left;
660
+ white-space: nowrap;
661
+ }
662
+
663
+ .spagbol-node-frame-type-picker-menu button.active,
664
+ .spagbol-node-frame-type-picker-menu button:hover {
665
+ background: var(--spagbol-foreground, #fff);
666
+ color: var(--spagbol-bg, #000);
667
+ }
668
+
669
+ .spagbol-node-frame-type-picker-empty {
670
+ color: var(--spagbol-muted, #777);
671
+ }
672
+
673
+
674
+ .spagbol-node-frame-ports-boundary { grid-template-columns: minmax(0, 1fr); }
675
+ .spagbol-node-group-port-add { min-height: 26px; padding: 0 8px; }
676
+ .spagbol-node-group-port-add-editor { width: 100%; background: var(--spagbol-bg); color: var(--spagbol-foreground); border: 1px solid var(--spagbol-border); }
677
+ .spagbol-node-group-port {
678
+ user-select: none;
679
+ -webkit-user-select: none;
680
+ }
681
+
682
+ .spagbol-node-group-port-editable {
683
+ cursor: grab;
684
+ }
685
+
686
+ .spagbol-node-group-port-editable:focus {
687
+ outline: 1px solid var(--spagbol-foreground);
688
+ outline-offset: 2px;
689
+ }
690
+
691
+ .spagbol-node-group-port-draggable:active {
692
+ cursor: grabbing;
693
+ }
694
+
695
+ .spagbol-node-group-port-drag-target {
696
+ outline: 1px dashed var(--spagbol-foreground);
697
+ outline-offset: 2px;
698
+ }
699
+
700
+ .spagbol-node-group-port-drag-source {
701
+ opacity: 0.58;
702
+ }
703
+
704
+ .spagbol-node-group-port-selected {
705
+ outline: 1px solid var(--spagbol-foreground);
706
+ outline-offset: 2px;
707
+ }
708
+
709
+ .spagbol-node-group-port-preview {
710
+ font-style: italic;
711
+ }
712
+
713
+ .spagbol-node-group-port-add-placeholder {
714
+ padding: 0;
715
+ border: 0;
716
+ background: none;
717
+ color: var(--spagbol-foreground);
718
+ opacity: 0.5;
719
+ cursor: text;
720
+ font: inherit;
721
+ text-align: left;
722
+ }
723
+
724
+ .spagbol-node-group-port-add-placeholder:hover,
725
+ .spagbol-node-group-port-add-placeholder:focus-visible {
726
+ opacity: 0.8;
727
+ }
728
+
729
+ .spagbol-node-group-port-editor {
730
+ width: max(7ch, 100%);
731
+ min-width: max-content;
732
+ height: 22px;
733
+ padding: 0 4px;
734
+ border: 1px solid var(--spagbol-foreground);
735
+ background: var(--spagbol-bg);
736
+ color: var(--spagbol-foreground);
737
+ font: inherit;
738
+ line-height: 20px;
739
+ }
740
+
741
+
742
+ .spagbol-canvas-area-title, .spagbol-canvas-area-title-input { flex: 1; min-width: 0; }
743
+ .spagbol-canvas-area-title-input { border: 0; padding: 0; color: inherit; background: transparent; font: inherit; outline: none; }
744
+
745
+ .spagbol-node-frame-projected > .spagbol-node-frame-header { background: var(--spagbol-bg); color: var(--spagbol-foreground); cursor: pointer; }
746
+ .spagbol-node-panel { border-bottom: 1px dashed var(--spagbol-foreground); background: var(--spagbol-bg); }
747
+
748
+ .spagbol-node-frame-auto-compact { min-width: 0; }