@w6w/ui 0.0.0-stage → 0.1.0

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 (143) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/LICENSE +21 -0
  3. package/README.md +260 -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-DJPYXE9t.cjs +11 -0
  14. package/dist/ConfirmModal-DJPYXE9t.cjs.map +1 -0
  15. package/dist/ConfirmModal-sY1tzkBO.js +6335 -0
  16. package/dist/ConfirmModal-sY1tzkBO.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 +7 -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 +22 -0
  85. package/dist/flow.mjs +1977 -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 +1811 -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 +420 -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/ui.css +1 -0
  103. package/dist/use-app-action-defs.d.ts +7 -0
  104. package/dist/use-enter-submit.d.ts +23 -0
  105. package/dist/use-seed-sources.d.ts +16 -0
  106. package/package.json +111 -3
  107. package/src/code.css +542 -0
  108. package/src/styles/_buttons.scss +38 -0
  109. package/src/styles/_chips.scss +210 -0
  110. package/src/styles/_code.scss +139 -0
  111. package/src/styles/_copyable.scss +147 -0
  112. package/src/styles/_data-vars.scss +38 -0
  113. package/src/styles/_execution-history.scss +282 -0
  114. package/src/styles/_execution-log.scss +178 -0
  115. package/src/styles/_expression-field.scss +65 -0
  116. package/src/styles/_expression-inline.scss +63 -0
  117. package/src/styles/_expression-modal.scss +292 -0
  118. package/src/styles/_fields.scss +161 -0
  119. package/src/styles/_flow.scss +217 -0
  120. package/src/styles/_fx.scss +158 -0
  121. package/src/styles/_health.scss +46 -0
  122. package/src/styles/_history-timeline.scss +156 -0
  123. package/src/styles/_icon-button.scss +22 -0
  124. package/src/styles/_icon.scss +15 -0
  125. package/src/styles/_icons.scss +31 -0
  126. package/src/styles/_incoming-state.scss +46 -0
  127. package/src/styles/_info-tip.scss +9 -0
  128. package/src/styles/_layout.scss +6 -0
  129. package/src/styles/_lists.scss +64 -0
  130. package/src/styles/_modal.scss +125 -0
  131. package/src/styles/_multiselect.scss +69 -0
  132. package/src/styles/_repo-sync-indicator.scss +99 -0
  133. package/src/styles/_scale.scss +70 -0
  134. package/src/styles/_sections.scss +36 -0
  135. package/src/styles/_server-resources.scss +163 -0
  136. package/src/styles/_step-builder.scss +376 -0
  137. package/src/styles/_step-config.scss +195 -0
  138. package/src/styles/_tabs.scss +54 -0
  139. package/src/styles/_tester.scss +111 -0
  140. package/src/styles/_tokens.scss +141 -0
  141. package/src/styles/_uptime.scss +61 -0
  142. package/src/styles.css +4208 -0
  143. package/src/styles.scss +61 -0
@@ -0,0 +1,413 @@
1
+ /**
2
+ * Wire types the components consume. These mirror the shapes the w6w server
3
+ * returns over HTTP. They are intentionally a local copy so consumers who
4
+ * don't use `@w6w/types` (partners, non-TypeScript backends) don't need it.
5
+ */
6
+ /** Summary of a registered app as returned by GET /apps. */
7
+ export interface AppSummary {
8
+ id: string;
9
+ displayName: string;
10
+ version?: string;
11
+ description?: string;
12
+ categories?: string[];
13
+ sourceRef?: string;
14
+ importedAt?: string;
15
+ /** Inlined data: URI (or absolute URL) for the app's icon. */
16
+ iconSvg?: string;
17
+ /** Optional dark-mode variant. */
18
+ iconSvgDark?: string;
19
+ brandColor?: string;
20
+ brandColorDark?: string;
21
+ versionCount?: number;
22
+ maturity?: string;
23
+ visibility?: string;
24
+ successor?: string;
25
+ /**
26
+ * True when the calling tenant has zero-credential access flagged for this
27
+ * app — usable with no connection step at all (server-computed per caller;
28
+ * `packages/server/packages/api/wire-summary.ts`'s `zeroCredential`).
29
+ */
30
+ zeroCredential?: boolean;
31
+ }
32
+ /** One trigger an app declares, as returned by GET /apps/:id/triggers. */
33
+ export interface TriggerSummary {
34
+ key: string;
35
+ /** The trigger's human label. REQUIRED — the wire type calls it `title`, not
36
+ * `displayName`; do not rename it. */
37
+ title: string;
38
+ description?: string;
39
+ requiresAuth?: boolean;
40
+ /** `"poll"` triggers are fetched on an interval; absent or `"webhook"` receive pushes. */
41
+ type?: "webhook" | "poll";
42
+ /** Host floor for a poll trigger's interval, in milliseconds. */
43
+ minIntervalMs?: number;
44
+ }
45
+ /** A Subscription (rfcs/trigger.md) as returned by the console subscription routes. */
46
+ export interface SubscriptionSummary {
47
+ id: string;
48
+ appId: string;
49
+ triggerKey: string;
50
+ workflowId: string;
51
+ connectionId: string | null;
52
+ /** Present only for `appId === "@w6w/webhook"` — the server's own computed receive URL. */
53
+ webhookUrl?: string;
54
+ type?: "webhook" | "poll";
55
+ status?: string;
56
+ /** Poll interval in milliseconds; null for webhook subscriptions. */
57
+ intervalMs?: number | null;
58
+ lastError?: {
59
+ code: string;
60
+ message: string;
61
+ } | null;
62
+ }
63
+ /** One field on an Auth method's connection form. Drives the input widgets. */
64
+ export interface AuthField {
65
+ key: string;
66
+ label: string;
67
+ type: "string" | "number" | "boolean" | "secret" | string;
68
+ required?: boolean;
69
+ default?: unknown;
70
+ hint?: string;
71
+ }
72
+ /**
73
+ * One declared parameter of an action, as returned by GET /apps/:id (the
74
+ * `actions[].params` array). Drives the guided step-builder form. Same shape as
75
+ * an app manifest's action param — a superset of `AuthField` (adds `text`/`json`
76
+ * widget types).
77
+ */
78
+ export interface ActionParam {
79
+ key: string;
80
+ label?: string;
81
+ /**
82
+ * Widget to render for this param. Beyond the scalar types, `text` is a
83
+ * textarea, `json`/`group` an inline JSON editor, `code` a code editor, and
84
+ * `vars` a dynamic typed key/value table.
85
+ */
86
+ type: "string" | "text" | "number" | "boolean" | "select" | "multiselect" | "array" | "json" | "group" | "secret" | "code" | "vars" | "section" | string;
87
+ required?: boolean;
88
+ default?: unknown;
89
+ hint?: string;
90
+ /** Placeholder text for the input (e.g. the trailing prompt on a multiselect). */
91
+ placeholder?: string;
92
+ /**
93
+ * Move this (optional) param under the collapsed "Additional parameters"
94
+ * section. Required + non-advanced params show up front. Ignored for required
95
+ * params (they always show).
96
+ */
97
+ advanced?: boolean;
98
+ /**
99
+ * Lay this param out on a shared row with adjacent params carrying the same
100
+ * `row` id — e.g. a username/password pair side by side.
101
+ */
102
+ row?: string;
103
+ /**
104
+ * Allow multiple values (array of `type`). Renders as an add/remove list via
105
+ * the same `ArrayField` a `type: "array"` param uses, with a synthesized
106
+ * `item` — sugar for `type: "array"`; see rfcs/param.md's `repeat` amendment.
107
+ * Mirrors `@w6w/types`' `Param.repeat`.
108
+ */
109
+ repeat?: boolean;
110
+ /** Element schema when `type: "array"` (a scalar list or a list of objects). */
111
+ item?: ParamArrayItem;
112
+ /**
113
+ * Conditional visibility — the param renders only when this predicate holds
114
+ * against a sibling field's value. Lets a schema declare conditional sections
115
+ * (e.g. Basic-auth fields shown only when `auth` is `"basic"`).
116
+ */
117
+ showIf?: ParamCondition;
118
+ /**
119
+ * Constrained choices. Renders as a single-select dropdown for `select` (or any
120
+ * param with options), and as a multi-select pill picker for `multiselect`.
121
+ */
122
+ options?: ParamOption[];
123
+ /** Type-specific render/behavior options. */
124
+ config?: ParamConfig;
125
+ /**
126
+ * Nested params, walked by the renderer for `type: "group"` (nested object)
127
+ * and `type: "section"` (layout-only container whose children write to the
128
+ * ENCLOSING form values, not under this param's key).
129
+ */
130
+ children?: ActionParam[];
131
+ /**
132
+ * `type: "section"` only — the container behavior. `"collapsible"` renders a
133
+ * titled, collapsed-by-default disclosure; `"group"` a `layout` row/stack.
134
+ */
135
+ section?: "collapsible" | "group";
136
+ /** `section: "collapsible"` only — the `<summary>` heading. */
137
+ title?: string;
138
+ /** `section: "collapsible"` only — an optional secondary summary line. */
139
+ subtitle?: string;
140
+ /** `section: "group"` only — `"row"` side by side, `"stack"` vertical (default). */
141
+ layout?: "row" | "stack";
142
+ /** `section: "collapsible"` only — start collapsed (default `true`). */
143
+ collapsed?: boolean;
144
+ }
145
+ /** A single choice for a param rendered as a dropdown. */
146
+ export interface ParamOption {
147
+ value: string | number;
148
+ label: string;
149
+ }
150
+ /**
151
+ * The element schema for a `type: "array"` param. Either a scalar list
152
+ * (`type: "string" | "number"`, each item a single value) or a list of objects
153
+ * (`type: "object"` with `fields`, each item a `{ [key]: value }` record whose
154
+ * fields render side by side).
155
+ */
156
+ export interface ParamArrayItem {
157
+ type: "string" | "number" | "object" | string;
158
+ /** For object items — the fields of each element (rendered inline in a row). */
159
+ fields?: ActionParam[];
160
+ /** Placeholder for a scalar item's input. */
161
+ placeholder?: string;
162
+ /** For a scalar item — constrained choices, carried over from a `repeat: true`
163
+ * param's own `options` (a `repeat` scalar with `options` still needs them). */
164
+ options?: ParamOption[];
165
+ }
166
+ /**
167
+ * A conditional-visibility predicate tested against a sibling param's value.
168
+ * Exactly one of `equals` / `in` / `notIn` / `truthy` is used (checked in that
169
+ * order). The compared value falls back to the sibling's `default` when unset.
170
+ */
171
+ export interface ParamCondition {
172
+ /** Sibling param key whose value is tested. */
173
+ field: string;
174
+ /** Visible when the field's value strictly equals this. */
175
+ equals?: string | number | boolean;
176
+ /** Visible when the field's value is one of these. */
177
+ in?: Array<string | number | boolean>;
178
+ /** Visible when the field's value is NOT one of these. */
179
+ notIn?: Array<string | number | boolean>;
180
+ /** Visible when the field's value is truthy (`true`) or falsy (`false`). */
181
+ truthy?: boolean;
182
+ }
183
+ /** Type-specific render/behavior options for a param. */
184
+ export interface ParamConfig {
185
+ /** Render as a multi-line textarea. Implied by `type: "text"`. */
186
+ multiline?: boolean;
187
+ }
188
+ /** Summary of an action an app exposes, as returned by GET /apps/:id. */
189
+ export interface ActionDef {
190
+ key: string;
191
+ type?: string;
192
+ title?: string;
193
+ description?: string;
194
+ params?: ActionParam[];
195
+ /**
196
+ * The declared output shape — `OutputField[]` (`{ key, type, label }`, a dot
197
+ * key for a nested path) or a `DynamicOutput` (`{ source }`) the editor does
198
+ * not resolve. Read by `output-shape.ts`, so a later step can pick fields.
199
+ */
200
+ output?: unknown;
201
+ /** An example output value; used for the field shape when `output` is absent. */
202
+ sample?: unknown;
203
+ /** Declared connection ports; `"many"` is unbounded. Absent fields fall through to defaults. */
204
+ ports?: {
205
+ in?: number | "many";
206
+ out?: number | "many";
207
+ };
208
+ }
209
+ /**
210
+ * Summary of a registered Function, as returned by GET /functions (core
211
+ * rfcs/function.md). `valid` mirrors the server's `isFunctionValid` — false for
212
+ * a draft Function (no `impl`, or an incomplete one) — the picker's list stage
213
+ * doesn't gate on it (an invalid Function still shows up; the server's own
214
+ * invoke route is what refuses it).
215
+ */
216
+ export interface FunctionSummary {
217
+ id: string;
218
+ key: string;
219
+ displayName?: string;
220
+ description?: string;
221
+ updatedAt?: string;
222
+ valid: boolean;
223
+ }
224
+ /**
225
+ * A Function's canonical interface, as returned by GET /functions/:id — enough
226
+ * to render its `inputs` form (core rfcs/function.md). `inputs` reuses the
227
+ * wire-mirror `ActionParam[]` shape verbatim, exactly as an app action's own
228
+ * declared `params` do.
229
+ */
230
+ export interface FunctionDetail {
231
+ id: string;
232
+ key: string;
233
+ displayName?: string;
234
+ description?: string;
235
+ inputs: ActionParam[];
236
+ valid: boolean;
237
+ }
238
+ /** Summary of a registered Workflow, as returned by GET /workflows. */
239
+ export interface WorkflowSummary {
240
+ id: string;
241
+ name: string;
242
+ displayName?: string;
243
+ description?: string;
244
+ status?: string;
245
+ updatedAt?: string;
246
+ }
247
+ /** One step of a Workflow, as returned by GET /workflows/:id — the minimal
248
+ * shape the picker's Configure stage needs to find the entry/trigger step's
249
+ * own declared `with.fields` (core rfcs/node-types.md's trigger node). */
250
+ export interface WorkflowStepSummary {
251
+ id: string;
252
+ uses: {
253
+ app: string;
254
+ action: string;
255
+ };
256
+ with?: Record<string, unknown>;
257
+ }
258
+ /**
259
+ * Full Workflow definition, as returned by GET /workflows/:id — enough to
260
+ * derive the trigger's declared input fields for the Functions/Workflows
261
+ * picker's Configure stage. A deliberately smaller mirror than `FlowWorkflow`
262
+ * (`flow-types.ts`) — these wire types stay independent of the flow-editor's
263
+ * own type, matching this file's own "local copy" convention.
264
+ */
265
+ export interface WorkflowDetail {
266
+ id: string;
267
+ name: string;
268
+ displayName?: string;
269
+ description?: string;
270
+ steps: WorkflowStepSummary[];
271
+ }
272
+ /** Auth method declaration as exposed by an app's manifest. */
273
+ export interface AuthDef {
274
+ key: string;
275
+ type: "oauth2" | "apiKey" | "basic" | "bearer" | "custom" | "tenantAuth" | "jit" | string;
276
+ displayName?: string;
277
+ description?: string;
278
+ connectionLabel?: string;
279
+ fields?: AuthField[];
280
+ /** OAuth2 endpoints (only present when type === "oauth2"). */
281
+ oauth2?: Record<string, unknown>;
282
+ /**
283
+ * False when the method requires per-host configuration that hasn't been
284
+ * provided yet (e.g. an oauth2 method with no client credentials set up).
285
+ * The picker hides entries with `available === false`.
286
+ */
287
+ available?: boolean;
288
+ /** Names of host-side config keys this method needs, when applicable. */
289
+ requiresHostConfig?: string[];
290
+ /**
291
+ * Present only on a `tenantAuth`/`jit` entry: `true` when the operator has
292
+ * flagged this method as zero-credential for the calling scope's tenant, so
293
+ * the server resolves a connection automatically at invoke time. This is
294
+ * NOT `available` — `available` means "this method can be picked at all";
295
+ * `autoSatisfied` means "the user does not have to pick anything for it".
296
+ */
297
+ autoSatisfied?: boolean;
298
+ /**
299
+ * `true` on the one method the server marks as the tenant's default for this
300
+ * app. The connect modal preselects it (among the available methods).
301
+ */
302
+ default?: boolean;
303
+ }
304
+ /** Public summary of a stored connection — never carries the credential. */
305
+ /** The display meta the server inlines on each {@link ConnectionSummary} (`app`). */
306
+ export interface ConnectionAppMeta {
307
+ displayName: string;
308
+ iconSvg?: string;
309
+ iconSvgDark?: string;
310
+ brandColor?: string;
311
+ brandColorDark?: string;
312
+ }
313
+ export interface ConnectionSummary {
314
+ id: string;
315
+ appId: string;
316
+ authKey: string;
317
+ /** The owning tenant. The server sends `tenant`/`subject`, never `owner`. */
318
+ tenant?: string;
319
+ /** The owning subject (the partner's user id). */
320
+ subject?: string;
321
+ /**
322
+ * The connection's app, inline: just enough to draw its card. `null` when the
323
+ * app is no longer in the catalog; absent from servers that don't send it.
324
+ */
325
+ app?: ConnectionAppMeta | null;
326
+ displayName?: string;
327
+ state?: "pending" | "connected" | "needs_refresh" | "broken" | "revoked" | string;
328
+ profile?: Record<string, unknown>;
329
+ createdAt?: string;
330
+ updatedAt?: string;
331
+ }
332
+ /** A saved set of action-test input values, scoped to a connection + action. */
333
+ export interface SavedTest {
334
+ id: string;
335
+ connectionId: string;
336
+ appId: string;
337
+ actionKey: string;
338
+ name: string;
339
+ values: Record<string, unknown>;
340
+ createdAt: string;
341
+ updatedAt: string;
342
+ /** When this saved test was last run (ISO), or null/undefined if never run. */
343
+ lastRunAt?: string | null;
344
+ /** Whether the most recent run succeeded, or null/undefined if never run. */
345
+ lastRunOk?: boolean | null;
346
+ /** Short headline for the most recent run's outcome, or null/undefined if never run. */
347
+ lastRunSummary?: string | null;
348
+ }
349
+ /**
350
+ * One outbound HTTP call an action made while running — the exact (redacted)
351
+ * request that went to the third-party API and the response that came back.
352
+ * Returned alongside an invoke's value/error and persisted server-side, so a
353
+ * run can be debugged and evaluated against the vendor's documented API.
354
+ */
355
+ export interface ApiCallRecord {
356
+ host: string;
357
+ method: string;
358
+ /** 0 when the request never produced a response (`error` says why). */
359
+ status: number;
360
+ url?: string;
361
+ requestHeaders?: Record<string, string>;
362
+ /** `null` on a persisted row that captured no body. */
363
+ requestBody?: string | null;
364
+ responseHeaders?: Record<string, string>;
365
+ responseBody?: string | null;
366
+ responseBytes?: number;
367
+ durationMs?: number;
368
+ /** A captured body hit the size cap and was cut. */
369
+ truncated?: boolean;
370
+ error?: string | null;
371
+ }
372
+ /** Effective theme hint passed to icon components to pick a light/dark variant. */
373
+ export type ThemeMode = "light" | "dark";
374
+ /** The segment kinds an {@link ExprValue} part can take. */
375
+ export type ExprPartKind = "text" | "var" | "secret" | "expr" | "render";
376
+ /**
377
+ * One segment of an {@link ExprValue}. The populated field depends on `kind`:
378
+ * - `text` → `value` holds a literal string chunk.
379
+ * - `var` → `ref` names a project variable.
380
+ * - `secret` → `ref` names a vault secret (surfaced via the secret picker).
381
+ * - `expr` → `expr` holds inline JSONLogic evaluated against the run scope.
382
+ */
383
+ export interface ExprPart {
384
+ kind: ExprPartKind;
385
+ /** Literal chunk, for `kind: "text"`. */
386
+ value?: string;
387
+ /** Name of the referenced variable/secret, for `kind: "var" | "secret"`. */
388
+ ref?: string;
389
+ /** Inline JSONLogic, for `kind: "expr"`. */
390
+ expr?: unknown;
391
+ }
392
+ /**
393
+ * A multipart value: an ordered list of {@link ExprPart} segments that
394
+ * concatenate to a string at resolve time.
395
+ */
396
+ export interface ExprValue {
397
+ type: "expr";
398
+ parts: ExprPart[];
399
+ }
400
+ /**
401
+ * The at-rest form of a secret-typed scalar field: AES-GCM ciphertext + IV
402
+ * (both base64). Decrypted server-side; never decrypted in the client — the UI
403
+ * renders it as `***`.
404
+ */
405
+ export interface SecretValue {
406
+ type: "secret";
407
+ ciphertext: string;
408
+ iv: string;
409
+ }
410
+ /** `true` if `v` is an {@link ExprValue} envelope. Safe on `unknown`. */
411
+ export declare function isExprValue(v: unknown): v is ExprValue;
412
+ /** `true` if `v` is a {@link SecretValue} envelope. Safe on `unknown`. */
413
+ export declare function isSecretValue(v: unknown): v is SecretValue;
package/dist/ui.css ADDED
@@ -0,0 +1 @@
1
+ .react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}
@@ -0,0 +1,7 @@
1
+ import { PortsLookup } from './flow-types.ts';
2
+ import { StepNode } from './flow-utils.ts';
3
+ import { W6WApi } from './provider.tsx';
4
+ import { ActionDef } from './types.ts';
5
+ export declare function useAppActionDefs(api: W6WApi, nodes: StepNode[]): Record<string, ActionDef[]>;
6
+ /** Build a `PortsLookup` over the fetched catalog defs (`useAppActionDefs`' result). */
7
+ export declare function portsLookupFromDefs(defs: Record<string, ActionDef[]>): PortsLookup;
@@ -0,0 +1,23 @@
1
+ import { KeyboardEventHandler } from 'react';
2
+ /**
3
+ * Enter-to-submit for a single-line text input, one implementation mounted by
4
+ * every form instead of each surface hand-rolling its own `onKeyDown` — see
5
+ * `studio/src/components/ApiServerSetting.tsx:75-80` for the ad-hoc version
6
+ * this replaces (a bare `if (e.key === "Enter")` with no modifier guard and no
7
+ * check that the target is actually a single-line text field). Spread the
8
+ * returned object onto the input: `<input {...useEnterSubmit(save)} … />`.
9
+ *
10
+ * Deliberately narrow: fires only for a bare `Enter` (no Shift/Alt/Ctrl/Meta,
11
+ * and not mid-IME-composition) on an `<input>` whose `type` is a plain
12
+ * single-line text control — never a `<textarea>`, a `contenteditable` node,
13
+ * or a non-text `<input>` (checkbox, date picker, …), each of which has its
14
+ * own meaning for Enter (a newline, a native widget's own key handling) that
15
+ * this hook must not steal. `opts.enabled` is a hard off switch: pass the same
16
+ * boolean guarding the caller's own submit button so Enter can never do
17
+ * something the button itself refuses to do.
18
+ */
19
+ export declare function useEnterSubmit(onSubmit: () => void, opts?: {
20
+ enabled?: boolean;
21
+ }): {
22
+ onKeyDown: KeyboardEventHandler<HTMLElement>;
23
+ };
@@ -0,0 +1,16 @@
1
+ import { ExpressionStepSource } from './components/ExpressionOptions.tsx';
2
+ import { SeedSource } from './step-preview-state.ts';
3
+ /**
4
+ * Gather each graph ancestor's latest saved step-test so the incoming-state
5
+ * control can offer it as a seed. **One implementation**, mounted by every
6
+ * surface — the step editor's Test tab, the canvas ▶ Run collect form, and the
7
+ * add-step builder's Test tab — so the `gate_1 · succeeded` chip behaves
8
+ * identically on each.
9
+ *
10
+ * Driven by `upstreamSteps` (from `upstreamStateSources` /
11
+ * `stepBuilderUpstreamSteps`), not a re-walked graph. Keyed on the *set* of
12
+ * upstream ids rather than the array's identity: that array is rebuilt on
13
+ * every node drag and every field edit, so keying on it would refetch on each
14
+ * keystroke.
15
+ */
16
+ export declare function useSeedSources(workflowId: string, upstreamSteps: ExpressionStepSource[], enabled: boolean): SeedSource[];
package/package.json CHANGED
@@ -1,6 +1,114 @@
1
1
  {
2
2
  "name": "@w6w/ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "React components for w6w — central API management. Build plugins, apps and integrations on them.",
5
+ "license": "MIT",
6
+ "homepage": "https://w6w.io",
7
+ "author": "W6W (https://w6w.io)",
8
+ "bugs": "https://github.com/w6w-io/w6w-ui/issues",
9
+ "keywords": [
10
+ "w6w",
11
+ "react",
12
+ "components",
13
+ "ui"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/w6w-io/w6w-ui.git"
18
+ },
19
+ "type": "module",
20
+ "main": "./dist/index.cjs",
21
+ "module": "./dist/index.mjs",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.mjs",
27
+ "require": "./dist/index.cjs"
28
+ },
29
+ "./flow": {
30
+ "types": "./dist/flow.d.ts",
31
+ "import": "./dist/flow.mjs",
32
+ "require": "./dist/flow.cjs"
33
+ },
34
+ "./code": {
35
+ "types": "./dist/code.d.ts",
36
+ "import": "./dist/code.mjs",
37
+ "require": "./dist/code.cjs"
38
+ },
39
+ "./styles.css": "./src/styles.css",
40
+ "./code.css": "./src/code.css",
41
+ "./styles.scss": "./src/styles.scss",
42
+ "./styles/*": "./src/styles/_*.scss"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "src/styles.css",
47
+ "src/code.css",
48
+ "src/styles.scss",
49
+ "src/styles/_*.scss",
50
+ "LICENSE",
51
+ "README.md",
52
+ "CHANGELOG.md"
53
+ ],
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
57
+ "sideEffects": [
58
+ "*.css",
59
+ "*.scss"
60
+ ],
61
+ "peerDependencies": {
62
+ "react": ">=18",
63
+ "react-dom": ">=18"
64
+ },
65
+ "dependencies": {
66
+ "@codemirror/lang-javascript": "^6.2.2",
67
+ "@codemirror/lang-json": "^6.0.1",
68
+ "@codemirror/lang-python": "^6.1.6",
69
+ "@codemirror/lang-yaml": "^6.1.2",
70
+ "@codemirror/lint": "^6.8.4",
71
+ "@codemirror/state": "^6.5.0",
72
+ "@codemirror/view": "^6.35.0",
73
+ "@uiw/react-codemirror": "^4.23.7",
74
+ "@w6w/expr": "^0.1.0",
75
+ "@xyflow/react": "^12.3.6",
76
+ "prism-react-renderer": "^2.4.1"
77
+ },
78
+ "devDependencies": {
79
+ "@biomejs/biome": "^1.9.4",
80
+ "@storybook/react-vite": "^10.5.8",
81
+ "@types/jsdom": "^28.0.3",
82
+ "@types/node": "^25.9.1",
83
+ "@types/react": "^18.3.17",
84
+ "@types/react-dom": "^18.3.5",
85
+ "@vitejs/plugin-react": "^4.3.4",
86
+ "jsdom": "^30.0.1",
87
+ "playwright-core": "1.60.0",
88
+ "react": "^18.3.1",
89
+ "react-dom": "^18.3.1",
90
+ "sass": "^1.102.0",
91
+ "storybook": "^10.5.8",
92
+ "typescript": "^5.7.2",
93
+ "vite": "^6.0.5",
94
+ "vite-plugin-dts": "^4.3.0"
95
+ },
96
+ "scripts": {
97
+ "build": "pnpm build:css && tsc -b && vite build",
98
+ "build:css": "node scripts/build-css.mjs",
99
+ "check:css": "node scripts/build-css.mjs --check",
100
+ "typecheck": "tsc -b --noEmit",
101
+ "test": "node --conditions=w6w-source --import ./src/test-jsx-loader.mjs --test src/__tests__/*.test.ts src/components/__tests__/*.test.ts",
102
+ "test:picker-layout": "bash test/picker-layout/run.sh",
103
+ "test:expr-template": "bash test/expr-template/run.sh",
104
+ "test:action-test-form": "bash test/action-test-form/run.sh",
105
+ "test:copyable": "bash test/copyable/run.sh",
106
+ "test:pack-smoke": "bash test/pack-smoke/run.sh",
107
+ "storybook": "storybook dev -p 6006 --no-open",
108
+ "build-storybook": "storybook build",
109
+ "lint": "biome check .",
110
+ "lint:tokens": "node scripts/lint-tokens.mjs",
111
+ "coverage:stories": "node scripts/coverage-stories.mjs",
112
+ "format": "biome format --write ."
113
+ }
6
114
  }