@w6w/ui 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 (142) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE +21 -0
  3. package/README.md +275 -2
  4. package/dist/ActionTestForm.d.ts +76 -0
  5. package/dist/AddConnectionModal.d.ts +24 -0
  6. package/dist/AppPicker.d.ts +83 -0
  7. package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
  8. package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
  9. package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
  10. package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
  11. package/dist/CodeBlock.d.ts +65 -0
  12. package/dist/CodeEditor.d.ts +42 -0
  13. package/dist/ConfirmModal-8avl9Nv8.cjs +11 -0
  14. package/dist/ConfirmModal-8avl9Nv8.cjs.map +1 -0
  15. package/dist/ConfirmModal-CD-P8mhN.js +6335 -0
  16. package/dist/ConfirmModal-CD-P8mhN.js.map +1 -0
  17. package/dist/Copyable-1niV9gUa.js +771 -0
  18. package/dist/Copyable-1niV9gUa.js.map +1 -0
  19. package/dist/Copyable-CYZU1o4X.cjs +2 -0
  20. package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
  21. package/dist/JsonEditor.d.ts +60 -0
  22. package/dist/NodeConfigForm.d.ts +70 -0
  23. package/dist/ParamsForm.d.ts +56 -0
  24. package/dist/PropertyEntryForm.d.ts +56 -0
  25. package/dist/RetryPolicyFields.d.ts +18 -0
  26. package/dist/StepBuilderModal.d.ts +375 -0
  27. package/dist/TriggerFillForm.d.ts +52 -0
  28. package/dist/WaitEditor.d.ts +6 -0
  29. package/dist/WorkflowFlowEditor.d.ts +119 -0
  30. package/dist/YamlEditor.d.ts +46 -0
  31. package/dist/app-categories.d.ts +38 -0
  32. package/dist/app-pages.d.ts +111 -0
  33. package/dist/code.cjs +2 -0
  34. package/dist/code.cjs.map +1 -0
  35. package/dist/code.d.ts +29 -0
  36. package/dist/code.mjs +8 -0
  37. package/dist/code.mjs.map +1 -0
  38. package/dist/components/ApiCallsPanel.d.ts +41 -0
  39. package/dist/components/AppIcon.d.ts +25 -0
  40. package/dist/components/AuthFieldsForm.d.ts +22 -0
  41. package/dist/components/Combobox.d.ts +24 -0
  42. package/dist/components/ConfirmModal.d.ts +33 -0
  43. package/dist/components/Copyable.d.ts +51 -0
  44. package/dist/components/CopyableText.d.ts +40 -0
  45. package/dist/components/DeleteButton.d.ts +16 -0
  46. package/dist/components/EditButton.d.ts +10 -0
  47. package/dist/components/ExecutionDetail.d.ts +70 -0
  48. package/dist/components/ExecutionFilters.d.ts +59 -0
  49. package/dist/components/ExecutionList.d.ts +60 -0
  50. package/dist/components/ExecutionLogPanel.d.ts +98 -0
  51. package/dist/components/ExecutionStats.d.ts +47 -0
  52. package/dist/components/ExpressionEditorModal.d.ts +42 -0
  53. package/dist/components/ExpressionInput.d.ts +36 -0
  54. package/dist/components/ExpressionOptions.d.ts +185 -0
  55. package/dist/components/HealthStatusPill.d.ts +25 -0
  56. package/dist/components/HistoryTimeline.d.ts +56 -0
  57. package/dist/components/Icon.d.ts +34 -0
  58. package/dist/components/IconButton.d.ts +60 -0
  59. package/dist/components/InfoTip.d.ts +15 -0
  60. package/dist/components/InternalIcon.d.ts +19 -0
  61. package/dist/components/ListItem.d.ts +25 -0
  62. package/dist/components/Modal.d.ts +29 -0
  63. package/dist/components/RepoSyncIndicator.d.ts +29 -0
  64. package/dist/components/ResolvedParams.d.ts +31 -0
  65. package/dist/components/ServerResources.d.ts +47 -0
  66. package/dist/components/StepStatusPill.d.ts +51 -0
  67. package/dist/components/UptimeStrip.d.ts +56 -0
  68. package/dist/components/execution-format.d.ts +24 -0
  69. package/dist/components/expression-dom.d.ts +154 -0
  70. package/dist/components/expression-template.d.ts +86 -0
  71. package/dist/components/history-scale.d.ts +33 -0
  72. package/dist/components/icons.d.ts +41 -0
  73. package/dist/components/resolved-clip.d.ts +42 -0
  74. package/dist/components/server-resources-format.d.ts +68 -0
  75. package/dist/components/server-resources.fixture.d.ts +9 -0
  76. package/dist/components/use-copy.d.ts +14 -0
  77. package/dist/createW6WApi.d.ts +31 -0
  78. package/dist/flow-connect.d.ts +138 -0
  79. package/dist/flow-fanout.d.ts +15 -0
  80. package/dist/flow-types.d.ts +356 -0
  81. package/dist/flow-utils.d.ts +284 -0
  82. package/dist/flow.cjs +3 -0
  83. package/dist/flow.cjs.map +1 -0
  84. package/dist/flow.d.ts +24 -0
  85. package/dist/flow.mjs +1978 -0
  86. package/dist/flow.mjs.map +1 -0
  87. package/dist/index.cjs +2 -0
  88. package/dist/index.cjs.map +1 -0
  89. package/dist/index.d.ts +94 -0
  90. package/dist/index.mjs +1812 -0
  91. package/dist/index.mjs.map +1 -0
  92. package/dist/oauth-popup.d.ts +17 -0
  93. package/dist/output-shape.d.ts +58 -0
  94. package/dist/provider.d.ts +421 -0
  95. package/dist/resolve-params.d.ts +112 -0
  96. package/dist/resolved-json.d.ts +21 -0
  97. package/dist/run-visuals.d.ts +90 -0
  98. package/dist/step-preview-state.d.ts +143 -0
  99. package/dist/theme.d.ts +32 -0
  100. package/dist/trigger-fields.d.ts +56 -0
  101. package/dist/types.d.ts +413 -0
  102. package/dist/use-app-action-defs.d.ts +7 -0
  103. package/dist/use-enter-submit.d.ts +23 -0
  104. package/dist/use-seed-sources.d.ts +16 -0
  105. package/package.json +112 -3
  106. package/src/code.css +561 -0
  107. package/src/styles/_buttons.scss +38 -0
  108. package/src/styles/_chips.scss +210 -0
  109. package/src/styles/_code.scss +139 -0
  110. package/src/styles/_copyable.scss +147 -0
  111. package/src/styles/_data-vars.scss +38 -0
  112. package/src/styles/_execution-history.scss +282 -0
  113. package/src/styles/_execution-log.scss +178 -0
  114. package/src/styles/_expression-field.scss +65 -0
  115. package/src/styles/_expression-inline.scss +63 -0
  116. package/src/styles/_expression-modal.scss +292 -0
  117. package/src/styles/_fields.scss +161 -0
  118. package/src/styles/_flow.scss +217 -0
  119. package/src/styles/_fx.scss +158 -0
  120. package/src/styles/_health.scss +46 -0
  121. package/src/styles/_history-timeline.scss +156 -0
  122. package/src/styles/_icon-button.scss +22 -0
  123. package/src/styles/_icon.scss +15 -0
  124. package/src/styles/_icons.scss +31 -0
  125. package/src/styles/_incoming-state.scss +46 -0
  126. package/src/styles/_info-tip.scss +9 -0
  127. package/src/styles/_layout.scss +6 -0
  128. package/src/styles/_lists.scss +64 -0
  129. package/src/styles/_modal.scss +125 -0
  130. package/src/styles/_multiselect.scss +69 -0
  131. package/src/styles/_repo-sync-indicator.scss +99 -0
  132. package/src/styles/_scale.scss +70 -0
  133. package/src/styles/_sections.scss +36 -0
  134. package/src/styles/_server-resources.scss +163 -0
  135. package/src/styles/_step-builder.scss +376 -0
  136. package/src/styles/_step-config.scss +195 -0
  137. package/src/styles/_tabs.scss +54 -0
  138. package/src/styles/_tester.scss +111 -0
  139. package/src/styles/_tokens.scss +160 -0
  140. package/src/styles/_uptime.scss +61 -0
  141. package/src/styles.css +4894 -0
  142. package/src/styles.scss +61 -0
@@ -0,0 +1,292 @@
1
+ .w6w-exprmodal {
2
+ flex: 1;
3
+ min-height: 0;
4
+ display: grid;
5
+ grid-template-columns: 260px 1fr;
6
+ gap: 14px;
7
+ }
8
+ .w6w-exprmodal-sources {
9
+ overflow: auto;
10
+ border: 1px solid var(--w6w-border);
11
+ border-radius: 8px;
12
+ background: var(--w6w-panel-2);
13
+ padding: var(--w6w-sp-2-5);
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: 14px;
17
+ }
18
+ .w6w-exprmodal-group {
19
+ display: flex;
20
+ flex-direction: column;
21
+ gap: 3px;
22
+ }
23
+ .w6w-exprmodal-group-label {
24
+ font-size: 0.72em;
25
+ font-weight: var(--w6w-fw-semibold);
26
+ letter-spacing: 0.04em;
27
+ text-transform: uppercase;
28
+ color: var(--w6w-muted);
29
+ margin-bottom: var(--w6w-sp-0-5);
30
+ }
31
+ .w6w-exprmodal-source {
32
+ display: flex;
33
+ align-items: center;
34
+ gap: var(--w6w-sp-1-5);
35
+ text-align: left;
36
+ background: transparent;
37
+ border: 1px solid transparent;
38
+ border-radius: 6px;
39
+ padding: 5px var(--w6w-sp-2);
40
+ color: var(--w6w-text);
41
+ font-size: 13px;
42
+ font-family: inherit;
43
+ cursor: pointer;
44
+ }
45
+ .w6w-exprmodal-source:hover {
46
+ background: var(--w6w-panel);
47
+ border-color: var(--w6w-border);
48
+ }
49
+ .w6w-exprmodal-source.w6w-expr-chip-var {
50
+ color: var(--w6w-accent);
51
+ }
52
+ .w6w-exprmodal-source.w6w-expr-chip-secret {
53
+ color: var(--w6w-danger);
54
+ }
55
+ .w6w-exprmodal-source-label {
56
+ overflow: hidden;
57
+ text-overflow: ellipsis;
58
+ white-space: nowrap;
59
+ }
60
+ /* A step's per-field sources, nested under its whole-output source, so three
61
+ upstream steps x four fields reads as a tree rather than a flat wall. */
62
+ .w6w-exprmodal-subsources {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 3px;
66
+ margin-left: 9px;
67
+ padding-left: var(--w6w-sp-2);
68
+ border-left: 1px solid var(--w6w-border);
69
+ }
70
+ /* One document-field row: the primary insert source (flex: 1, so it still
71
+ truncates a long key the same way a bare `.w6w-exprmodal-source` does) plus
72
+ the second, visible action (D-P1) that inserts the SAME ref as a `render`
73
+ part — so the two read as one entry, not two unrelated controls. */
74
+ .w6w-exprmodal-subsource-row {
75
+ display: flex;
76
+ align-items: center;
77
+ gap: var(--w6w-sp-1);
78
+ }
79
+ .w6w-exprmodal-subsource-row .w6w-exprmodal-source {
80
+ flex: 1;
81
+ min-width: 0;
82
+ }
83
+ .w6w-exprmodal-render-btn {
84
+ display: inline-flex;
85
+ flex: none;
86
+ align-items: center;
87
+ justify-content: center;
88
+ width: 20px;
89
+ height: 20px;
90
+ border: 1px solid var(--w6w-border);
91
+ border-radius: 6px;
92
+ background: transparent;
93
+ color: var(--w6w-success);
94
+ opacity: 0.75;
95
+ font-size: var(--w6w-fs-xs);
96
+ cursor: pointer;
97
+ }
98
+ .w6w-exprmodal-render-btn:hover {
99
+ opacity: 1;
100
+ background: var(--w6w-panel);
101
+ border-color: var(--w6w-success);
102
+ }
103
+ /* A rail source with surviving child rows (a multi-field document, a step
104
+ with declared outputs) — the "whole source" button plus the expand/collapse
105
+ toggle, as siblings on one row. Mirrors `.w6w-exprmodal-subsource-row`'s
106
+ flex row + child-fills-width shape (`:74-82` above), kept as its own class
107
+ because the two are counted independently by the test suite. */
108
+ .w6w-exprmodal-source-row {
109
+ display: flex;
110
+ align-items: center;
111
+ gap: var(--w6w-sp-1);
112
+ }
113
+ .w6w-exprmodal-source-row .w6w-exprmodal-source {
114
+ flex: 1;
115
+ min-width: 0;
116
+ }
117
+ /* A step row's disclosure caret, sitting where the chip's `▸` sigil was —
118
+ that arrow reads as "expand", so on a row with fields it does exactly that
119
+ (the chip beside it still inserts the whole output). */
120
+ .w6w-exprmodal-caret-btn {
121
+ display: inline-flex;
122
+ flex: none;
123
+ align-items: center;
124
+ justify-content: center;
125
+ width: 20px;
126
+ height: 20px;
127
+ padding: 0;
128
+ border: 0;
129
+ border-radius: 6px;
130
+ background: transparent;
131
+ color: var(--w6w-accent);
132
+ font-size: var(--w6w-fs-xs);
133
+ cursor: pointer;
134
+ }
135
+ .w6w-exprmodal-caret-btn:hover {
136
+ background: var(--w6w-panel);
137
+ }
138
+ /* The "N fields" toggle with the Metadata toggle stacked under it, so both
139
+ disclosures share one left edge on a step row. */
140
+ .w6w-exprmodal-toggle-stack {
141
+ display: flex;
142
+ flex: none;
143
+ flex-direction: column;
144
+ align-items: flex-start;
145
+ gap: 3px; /* lint-tokens-allow: 3px sits between no two steps of the spacing scale; tight stack of the fields and Metadata toggles */
146
+ }
147
+ /* A step with no fields: its Metadata toggle sits at the leaf indentation of
148
+ `.w6w-exprmodal-subsources` (margin 9px + 1px border + sp-2 padding). */
149
+ .w6w-exprmodal-meta-row {
150
+ margin-left: calc(10px + var(--w6w-sp-2)); /* lint-tokens-allow: 9px margin + 1px border of .w6w-exprmodal-subsources */
151
+ }
152
+ /* Same 20px-high chrome as `.w6w-exprmodal-render-btn` above — the sizing
153
+ precedent for a dense rail control — but a separate class: this toggles
154
+ the `.w6w-exprmodal-subsources` block below it, the render-btn inserts a
155
+ `render` part. It carries a "N fields" label, not a bare chevron, so it is
156
+ auto-width (a lone 20px chevron went unnoticed beside the chip). */
157
+ .w6w-exprmodal-toggle-btn {
158
+ display: inline-flex;
159
+ flex: none;
160
+ align-items: center;
161
+ justify-content: center;
162
+ gap: var(--w6w-sp-1);
163
+ height: 20px;
164
+ padding: 0 6px; /* lint-tokens-allow: no 6px step on the spacing scale; between sp-1 and sp-2 keeps the 20px pill's label centred */
165
+ white-space: nowrap;
166
+ border: 1px solid var(--w6w-border);
167
+ border-radius: 6px;
168
+ background: transparent;
169
+ color: var(--w6w-muted);
170
+ font-size: var(--w6w-fs-xs);
171
+ cursor: pointer;
172
+ }
173
+ .w6w-exprmodal-toggle-btn:hover {
174
+ background: var(--w6w-panel);
175
+ border-color: var(--w6w-accent);
176
+ color: var(--w6w-text);
177
+ }
178
+ .w6w-exprmodal-main {
179
+ min-width: 0;
180
+ min-height: 0;
181
+ display: flex;
182
+ flex-direction: column;
183
+ gap: var(--w6w-sp-3);
184
+ }
185
+ .w6w-exprmodal-editor {
186
+ display: flex;
187
+ flex-direction: column;
188
+ gap: var(--w6w-sp-1-5);
189
+ min-height: 0;
190
+ flex: 1 1 auto;
191
+ }
192
+ .w6w-exprmodal-pane-label {
193
+ font-size: 13px;
194
+ font-weight: var(--w6w-fw-semibold);
195
+ color: var(--w6w-text);
196
+ }
197
+ /* The WYSIWYG chip editor: tags flow inline with text (colored + spaced). */
198
+ .w6w-exprmodal-chips {
199
+ flex: 1;
200
+ min-height: 180px;
201
+ overflow: auto;
202
+ background: var(--w6w-panel-2);
203
+ border: 1px solid var(--w6w-border);
204
+ border-radius: 8px;
205
+ padding: var(--w6w-sp-2-5) var(--w6w-sp-3);
206
+ color: var(--w6w-text);
207
+ font-size: var(--w6w-fs-sm);
208
+ line-height: 2.1;
209
+ outline: none;
210
+ white-space: pre-wrap;
211
+ word-break: break-word;
212
+ }
213
+ .w6w-exprmodal-chips:focus {
214
+ border-color: var(--w6w-accent);
215
+ }
216
+ .w6w-exprmodal-chips.is-empty::before {
217
+ content: attr(data-placeholder);
218
+ color: var(--w6w-muted);
219
+ pointer-events: none;
220
+ }
221
+ .w6w-exprmodal-chips.is-masked {
222
+ -webkit-text-security: disc;
223
+ text-security: disc;
224
+ }
225
+ .w6w-exprmodal-chips.is-masked .w6w-expr-chip {
226
+ -webkit-text-security: none;
227
+ text-security: none;
228
+ }
229
+ .w6w-exprmodal-preview {
230
+ display: flex;
231
+ flex-direction: column;
232
+ gap: var(--w6w-sp-1-5);
233
+ }
234
+ /* The Result pane's own share of `.w6w-exprmodal-main`'s flex column — the
235
+ SHARE lives on this wrapper, not on the `<pre>` below: the `<pre>`'s parent
236
+ is this wrapper (`.w6w-exprmodal-preview`, a flex column), not `-main`
237
+ itself, so a `flex-basis` on the `<pre>` would be a share of a
238
+ content-sized box and do nothing. 42% keeps the pane in the 30-50% band and
239
+ the chips editor above the 25% floor at 1440x900, 1280x720 and 1440x1200 —
240
+ measured in real Chromium, `test/expr-template/expr-template-guards.test.cjs`
241
+ T-height; see the project's result for the numbers. */
242
+ .w6w-exprmodal-result-pane {
243
+ flex: 0 0 42%;
244
+ min-height: 0;
245
+ }
246
+ /* The pane's 42% share above is a flex-basis on `.w6w-exprmodal-result-pane`
247
+ itself (a column flex container) — it must still reach the `<pre>` now that
248
+ `Copyable` wraps it in a `.w6w-copyable` div. That wrapper is the actual
249
+ column child now, so it needs the grow/shrink share instead. */
250
+ .w6w-exprmodal-result-pane > .w6w-copyable {
251
+ flex: 1 1 auto;
252
+ min-height: 0;
253
+ }
254
+ .w6w-exprmodal-result {
255
+ flex: 1 1 auto;
256
+ /* `.w6w-copyable` is a ROW flex container (`_copyable.scss:5`), and its
257
+ `:has(> pre)` arm (`_copyable.scss:19-21`) sets `align-items: flex-start`
258
+ for CodeBlock's snippet case, where the box is sized TO the pre's
259
+ content. Here it's the other way around — the wrapper is grown to the
260
+ pane's share by the rule above, and the `<pre>` must fill IT. `flex: 1 1
261
+ auto`'s grow/shrink applies to the row's main axis (width) and does
262
+ nothing for height there, so the cross-axis stretch has to be pinned
263
+ directly on this item, overriding the container's `flex-start`. */
264
+ align-self: stretch;
265
+ min-height: 0;
266
+ max-height: none;
267
+ overflow: auto;
268
+ margin: 0;
269
+ background: var(--w6w-panel-2);
270
+ border: 1px solid var(--w6w-border);
271
+ border-radius: 8px;
272
+ padding: var(--w6w-sp-2-5) var(--w6w-sp-3);
273
+ /* `_copyable.scss:105-107`'s corner-button clearance is scoped to
274
+ `.w6w-code-block` and does not apply here — same 40px value (icon box +
275
+ inset + gap) so the overlaid copy button never sits on the first line. */
276
+ padding-right: var(--w6w-sp-10);
277
+ color: var(--w6w-muted);
278
+ font-family: var(--w6w-font-mono);
279
+ font-size: 12.5px;
280
+ line-height: 1.6;
281
+ white-space: pre-wrap;
282
+ word-break: break-word;
283
+ }
284
+ .w6w-exprmodal-actions {
285
+ display: flex;
286
+ gap: var(--w6w-sp-2);
287
+ }
288
+ .w6w-expr-toolbar {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: var(--w6w-sp-2);
292
+ }
@@ -0,0 +1,161 @@
1
+ /* Form fields */
2
+ .w6w-field {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: var(--w6w-sp-1);
6
+ color: var(--w6w-muted);
7
+ font-size: 0.9em;
8
+ }
9
+ .w6w-field > span {
10
+ color: var(--w6w-muted);
11
+ }
12
+ .w6w-field input[type="text"],
13
+ .w6w-field input[type="password"],
14
+ .w6w-field input[type="number"],
15
+ .w6w-field select,
16
+ .w6w-field textarea {
17
+ background: var(--w6w-panel-2);
18
+ border: 1px solid var(--w6w-border);
19
+ border-radius: 8px;
20
+ padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
21
+ color: var(--w6w-text);
22
+ font-size: var(--w6w-fs-sm);
23
+ font-family: inherit;
24
+ }
25
+ /* Native popups: the list background follows `color-scheme` (declared with the
26
+ tokens), so give the options token colours too — never one theme's text on
27
+ the other theme's background. */
28
+ .w6w-field option,
29
+ .w6w-field optgroup,
30
+ select option,
31
+ select optgroup {
32
+ color: var(--w6w-text);
33
+ background-color: var(--w6w-panel);
34
+ }
35
+ .w6w-field input:focus,
36
+ .w6w-field select:focus,
37
+ .w6w-field textarea:focus {
38
+ outline: none;
39
+ border-color: var(--w6w-accent);
40
+ }
41
+ /* Credential inputs are plain text fields (never type="password", which would
42
+ trigger the browser's save-password prompt + suggestions). Mask them visually
43
+ so a secret still reads as dots. WebKit/Blink support text-security; other
44
+ engines fall back to plain text, which is acceptable for a credential. */
45
+ .w6w-secret-input {
46
+ -webkit-text-security: disc;
47
+ text-security: disc;
48
+ }
49
+ .w6w-hint {
50
+ color: var(--w6w-muted);
51
+ font-size: 0.8em;
52
+ }
53
+ /* Side-by-side fields: params sharing a `row` id lay out horizontally. */
54
+ .w6w-field-row {
55
+ display: flex;
56
+ flex-wrap: wrap;
57
+ gap: var(--w6w-sp-2-5);
58
+ }
59
+ .w6w-field-row > .w6w-field {
60
+ flex: 1 1 140px;
61
+ min-width: 0;
62
+ }
63
+
64
+ /* Array control: a row per item + an add button. */
65
+ .w6w-array {
66
+ display: flex;
67
+ flex-direction: column;
68
+ gap: var(--w6w-sp-1-5);
69
+ align-items: flex-start;
70
+ }
71
+ .w6w-array-row {
72
+ display: flex;
73
+ align-items: center;
74
+ gap: var(--w6w-sp-1-5);
75
+ width: 100%;
76
+ }
77
+ .w6w-array-cells {
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ gap: var(--w6w-sp-1-5);
81
+ flex: 1;
82
+ min-width: 0;
83
+ }
84
+ .w6w-array-cells > .w6w-array-input {
85
+ flex: 1 1 120px;
86
+ }
87
+ /* An object-item array row's boolean cell: `<label><checkbox><span>`. It is a
88
+ `<label>`, so `margin: 0` is load-bearing for the same reason it is on
89
+ `.w6w-fx-inline-label` further down — a host page layers an unscoped
90
+ `label { margin-bottom: 10px }` after this file (studio's does, at
91
+ `studio/src/styles.css:499`) and owns any property this block leaves
92
+ undeclared. `.w6w-array-cells` is a flex row at the default `align-items:
93
+ stretch`, so a bottom margin does not translate this cell, it SHORTENS its
94
+ stretched box — and because this block centres its own contents, the checkbox
95
+ and its caption then ride upward off the row's centre line. Measured before
96
+ this declaration existed, in [ui+studio]: checkbox cy 792 against the sibling
97
+ text cell's 799 — 7.0px out, while a ui-only render showed 0.0px. */
98
+ .w6w-array-check {
99
+ display: inline-flex;
100
+ align-items: center;
101
+ gap: var(--w6w-sp-1-5);
102
+ flex: 0 0 auto;
103
+ margin: 0;
104
+ font-size: 13px;
105
+ color: var(--w6w-text);
106
+ white-space: nowrap;
107
+ cursor: pointer;
108
+ }
109
+ /* `> input[type="checkbox"]`, not `input`: a bare `.w6w-array-check input` is
110
+ (0,1,1), which TIES with a host `input[type="checkbox"] { margin-right: 6px }`
111
+ (studio/src/styles.css:785) and then loses on source order — measured
112
+ `margin-right: 6px` reaching this checkbox with the `margin: 0` below already
113
+ present. The compound form is (0,2,1) and wins outright. Same shape as
114
+ `.w6w-fx-inline > input[type="checkbox"]`, which is why that one was never
115
+ affected. */
116
+ .w6w-array-check > input[type="checkbox"] {
117
+ margin: 0;
118
+ }
119
+ .w6w-field .w6w-array-input {
120
+ flex: 1;
121
+ min-width: 0;
122
+ /* Load-bearing, same class as `.w6w-array-check` above: a host
123
+ `input[type="text"] { margin-top: 4px }` otherwise lands here and drops this
124
+ cell 2px below its own row's checkbox cell. Measured in [ui+studio]:
125
+ checkbox cy 797 against this input's 799. This selector is (0,2,0) and beats
126
+ the host's (0,1,1). */
127
+ margin: 0;
128
+ background: var(--w6w-panel-2);
129
+ border: 1px solid var(--w6w-border);
130
+ border-radius: 8px;
131
+ padding: var(--w6w-sp-1-5) var(--w6w-sp-2);
132
+ color: var(--w6w-text);
133
+ font-size: var(--w6w-fs-sm);
134
+ font-family: inherit;
135
+ }
136
+ .w6w-field .w6w-array-input:focus {
137
+ outline: none;
138
+ border-color: var(--w6w-accent);
139
+ }
140
+ .w6w-array-x {
141
+ display: inline-flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ width: 26px;
145
+ height: 26px;
146
+ flex-shrink: 0;
147
+ border: 1px solid var(--w6w-border);
148
+ border-radius: 8px;
149
+ background: transparent;
150
+ color: var(--w6w-muted);
151
+ font-size: var(--w6w-fs-base);
152
+ line-height: 1;
153
+ cursor: pointer;
154
+ }
155
+ .w6w-array-x:hover {
156
+ background: var(--w6w-panel-2);
157
+ color: var(--w6w-text);
158
+ }
159
+ .w6w-array-add {
160
+ margin-top: var(--w6w-sp-0-5);
161
+ }
@@ -0,0 +1,217 @@
1
+ /* React Flow chrome, driven from the app's own tokens.
2
+
3
+ React Flow themes every surface through a three-link chain,
4
+ `var(--xy-X-props, var(--xy-X, var(--xy-X-default)))`. The library defines
5
+ only the `-default` link (light/dark, its own palette); the MIDDLE name is
6
+ never declared by the library and exists purely as a host hook. Setting those
7
+ middle names here re-points the zoom/fit control stack at `--w6w-*`, so it
8
+ matches whatever surface the host theme actually uses — and any ControlButton
9
+ added to that stack later inherits it with no styling of its own.
10
+
11
+ Custom properties, deliberately, rather than a `.react-flow__controls-button`
12
+ override: React Flow's own stylesheet is compiled into the same
13
+ styles.css (`@use` in the build-only styles.build.scss), but cascade
14
+ order is not something to lean on: a bare class override (0,1,0) would tie
15
+ with the library's own rule and lose if the order ever changed. Custom properties inherit and are
16
+ order-independent, and scoping them on `.w6w-flow` keeps them off the rest of
17
+ the page.
18
+
19
+ Pairs with `colorMode={…}` on <ReactFlow>, which fixes the `-default` link for
20
+ the chrome this block doesn't name (minimap mask, handles, background dots). */
21
+ .w6w-flow {
22
+ --xy-controls-button-background-color: var(--w6w-panel);
23
+ --xy-controls-button-background-color-hover: var(--w6w-panel-2);
24
+ --xy-controls-button-color: var(--w6w-text);
25
+ --xy-controls-button-color-hover: var(--w6w-accent);
26
+ --xy-controls-button-border-color: var(--w6w-border);
27
+ }
28
+
29
+ /* An error edge — `Edge.when: "error"` (core rfcs/workflow.md · "Amendment —
30
+ 2026-07-29: failure-conditioned edges"). Dashed and drawn in the shared
31
+ --w6w-danger token (never a hard-coded hex) so the failure lane reads
32
+ differently from the success lane, and correctly, in BOTH themes.
33
+
34
+ ORDER MATTERS — this must stay ABOVE the selected/focused block below.
35
+ Both selectors are (0,4,0), i.e. exactly equal specificity, so source order
36
+ decides the winner. Selection has to be able to repaint the edge in the
37
+ accent colour; put this block after that one and a selected error edge stops
38
+ highlighting, which reads as a bug. */
39
+ .w6w-flow .react-flow__edge.w6w-edge-error .react-flow__edge-path {
40
+ stroke: var(--w6w-danger);
41
+ stroke-dasharray: 6 4;
42
+ }
43
+ .w6w-flow .react-flow__edge.w6w-edge-error .react-flow__edge-text {
44
+ fill: var(--w6w-danger);
45
+ }
46
+ .w6w-flow .react-flow__edge.w6w-edge-error .react-flow__edge-textbg {
47
+ fill: var(--w6w-panel);
48
+ }
49
+
50
+ /* Run-state edge painting (T1.1.1) — whether a main-graph edge was TAKEN or
51
+ SKIPPED by the run currently showing on the canvas (see `run-visuals.ts`'s
52
+ `edgeRunState`). Both classes are ADDITIVE to `.w6w-edge-error` above (an
53
+ edge can be `w6w-edge-error w6w-edge-taken` at once), so ORDER decides how
54
+ they compose — same equal-(0,4,0)-specificity discipline `.w6w-edge-error`
55
+ already documents, kept below it in source:
56
+
57
+ - `.w6w-edge-taken`'s STROKE COLOUR is guarded to the non-error case via
58
+ `:where(:not(.w6w-edge-error))` — `:where()` contributes ZERO
59
+ specificity, so this stays at the SAME (0,4,0) weight as every other
60
+ block here instead of out-ranking `.selected` below. A taken ERROR edge
61
+ (the failure path a run actually followed) keeps the danger colour — the
62
+ fact of having failed does not stop being true — and only gets the
63
+ thicker stroke-width (the second, unconditional rule).
64
+ - `.w6w-edge-skipped` is intentionally UNGUARDED: a skipped error edge
65
+ (the step succeeded, so its error lane never fired) dims to muted same
66
+ as a skipped success edge does — the failure never happened, so danger
67
+ is the wrong colour regardless of which lane it is. */
68
+ .w6w-flow .react-flow__edge.w6w-edge-taken:where(:not(.w6w-edge-error)) .react-flow__edge-path {
69
+ stroke: var(--w6w-success);
70
+ }
71
+ .w6w-flow .react-flow__edge.w6w-edge-taken .react-flow__edge-path {
72
+ stroke-width: 2.5;
73
+ }
74
+ .w6w-flow .react-flow__edge.w6w-edge-skipped .react-flow__edge-path {
75
+ stroke: var(--w6w-muted);
76
+ stroke-dasharray: 2 3;
77
+ opacity: 0.55;
78
+ }
79
+
80
+ /* A step's own Notes, shown under its canvas card — human override,
81
+ 2026-08-30, so a description written once (settings → gear icon) is
82
+ visible without opening the step. One line, clipped with an ellipsis (the
83
+ full text is still on the node's `title=` for a hover); `max-width`
84
+ matches the card's own `minWidth` so a short note never forces the row
85
+ wider than the card sitting above it. Font size matches the sibling
86
+ meta-line's own inline fontSize:10 (not scanned by this ratchet) directly
87
+ above it — the smallest declared token, --w6w-fs-xs, is 12px and would
88
+ visibly mismatch the two lines. */
89
+ .w6w-flow .w6w-node-notes {
90
+ margin-top: var(--w6w-sp-0-5);
91
+ padding-left: var(--w6w-sp-0-5);
92
+ /* lint-tokens-allow: matches the sibling meta-line's inline fontSize:10 above it */
93
+ font-size: 10px;
94
+ font-style: italic;
95
+ opacity: 0.75;
96
+ max-width: 180px;
97
+ overflow: hidden;
98
+ text-overflow: ellipsis;
99
+ white-space: nowrap;
100
+ }
101
+
102
+ /* The ordinary (success) ports — bumped from the library's own 6px default
103
+ (2026-08-30: "ports must have consistent size") to match the error port
104
+ below exactly. `:not(.w6w-handle-multi)`: the multi-input handle is its
105
+ own taller pill shape (`PortHandle`'s inline style), not a dot — this
106
+ rule must not touch it. */
107
+ .w6w-flow .react-flow__handle:not(.w6w-handle-multi) {
108
+ width: 8px;
109
+ height: 8px;
110
+ }
111
+
112
+ /* The error exit port — a step/control node's second SOURCE handle (T1.1.1),
113
+ rendered below the ordinary exit via the shared PortHandle component
114
+ (`id={ERROR_SOURCE_HANDLE}`, `variant="error"`). Danger-tinted, same
115
+ --w6w-danger token as .w6w-edge-error above (never a hard-coded hex).
116
+ DELIBERATELY 1px SMALLER, in actual box size, than the ordinary ports
117
+ above (2026-08-30, second pass on "consistent size"): setting both to the
118
+ literal same 8px×8px box (the first pass) still read as bigger — measured
119
+ directly, computed styles for both were byte-identical (same width,
120
+ height, border-width, box-sizing, no box-shadow/outline difference) — a
121
+ saturated warm fill on a light canvas background perceptually "expands"
122
+ past a same-sized dark/cool one (the classic irradiation illusion), so
123
+ matching PIXELS does not produce matching APPEARANCE. Compensating with a
124
+ smaller literal box is what actually reads as equal. */
125
+ .w6w-flow .react-flow__handle.w6w-handle-error {
126
+ width: 7px;
127
+ height: 7px;
128
+ background: var(--w6w-danger);
129
+ border-color: var(--w6w-danger);
130
+ opacity: 0.85;
131
+ }
132
+ .w6w-flow .react-flow__handle.w6w-handle-error:hover {
133
+ opacity: 1;
134
+ }
135
+
136
+ /* Workflow edges: highlight the selected/focused edge in the accent colour and
137
+ thicken it, so it's obvious which one Backspace/Delete will remove. The wide,
138
+ invisible interaction path keeps the click target generous. */
139
+ .w6w-flow .react-flow__edge.selected .react-flow__edge-path,
140
+ .w6w-flow .react-flow__edge:focus .react-flow__edge-path,
141
+ .w6w-flow .react-flow__edge:focus-visible .react-flow__edge-path {
142
+ stroke: var(--w6w-accent);
143
+ stroke-width: 2.5;
144
+ }
145
+
146
+ /* The edge-lane control — `Run on: Success / Error`, revealed in a React Flow
147
+ <Panel position="top-right"> when exactly one edge is selected. Unlike the
148
+ `+ Step` button (a self-contained .w6w-btn), this row mixes a label, two ghost
149
+ buttons and an inline refusal, so it needs its own surface to stay legible over
150
+ the canvas background. Same shape as .w6w-node-toolbar below; tokens only. */
151
+ .w6w-edge-lane {
152
+ display: flex;
153
+ align-items: center;
154
+ flex-wrap: wrap;
155
+ gap: var(--w6w-sp-1-5);
156
+ max-width: 280px;
157
+ padding: var(--w6w-sp-1) var(--w6w-sp-2);
158
+ background: var(--w6w-panel);
159
+ border: 1px solid var(--w6w-border);
160
+ border-radius: 8px;
161
+ }
162
+ /* An inline refusal (re-laning would mint an id another edge already holds).
163
+ Rendered here rather than through a browser dialog — see .ai/conventions.md ·
164
+ "No browser dialogs" — and on its own row so the buttons don't reflow. */
165
+ .w6w-edge-lane-err {
166
+ flex: 1 1 100%;
167
+ color: var(--w6w-danger);
168
+ }
169
+
170
+ /* Per-node control toolbar (React Flow NodeToolbar) */
171
+ .w6w-node-toolbar {
172
+ display: flex;
173
+ gap: var(--w6w-sp-1);
174
+ background: var(--w6w-panel);
175
+ border: 1px solid var(--w6w-border);
176
+ border-radius: 8px;
177
+ padding: var(--w6w-sp-1);
178
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
179
+ }
180
+ .w6w-node-toolbar-btn {
181
+ display: inline-flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ background: transparent;
185
+ border: none;
186
+ border-radius: 6px;
187
+ padding: 5px;
188
+ color: var(--w6w-text);
189
+ font-size: var(--w6w-fs-xs);
190
+ cursor: pointer;
191
+ }
192
+ .w6w-node-toolbar-btn:hover {
193
+ background: var(--w6w-panel-2);
194
+ }
195
+ .w6w-node-toolbar-btn.danger:hover {
196
+ background: var(--w6w-danger);
197
+ color: white;
198
+ }
199
+
200
+ .w6w-params-optional > summary {
201
+ cursor: pointer;
202
+ }
203
+
204
+ /* `section` param — a layout-only container. `section: "collapsible"` renders as
205
+ a titled, bordered disclosure; `section: "group"` reuses `.w6w-field-row` /
206
+ `.w6w-stack` for its layout (no rules of its own needed). */
207
+
208
+ /* Fan-out badge under a card: the glyph (⇉ parallel / → sequence), not colour, carries the mode. */
209
+ .w6w-flow .w6w-fanout-badge {
210
+ display: inline-block;
211
+ margin-top: var(--w6w-sp-0-5);
212
+ padding: 0 var(--w6w-sp-1);
213
+ border: 1px solid var(--w6w-border);
214
+ border-radius: var(--w6w-radius-sm, 3px);
215
+ font-size: var(--w6w-fs-xs);
216
+ color: var(--w6w-muted, inherit);
217
+ }