@you-agent-factory/components 0.0.2 → 0.0.7

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 (48) hide show
  1. package/dist/charts/chart-state-panel.d.ts +1 -1
  2. package/dist/charts/chart.d.ts +3 -3
  3. package/dist/charts/index.d.ts +1 -1
  4. package/dist/charts/index.js +6 -1
  5. package/dist/chunks/alert-panel.js +10 -12
  6. package/dist/chunks/button.js +3 -1
  7. package/dist/chunks/{package-form-field.js → package-textarea.js} +51 -54
  8. package/dist/chunks/table-layout.js +22 -25
  9. package/dist/chunks/typography-roles.js +2 -2
  10. package/dist/chunks/typography.js +1 -1
  11. package/dist/chunks/{widget-frame.js → widget-frame-states.js} +144 -140
  12. package/dist/data-display/data-table.d.ts +1 -1
  13. package/dist/data-display/index.d.ts +5 -5
  14. package/dist/factory-emulator/factory-emulator-controls.d.ts +1 -1
  15. package/dist/factory-emulator/index.d.ts +1 -1
  16. package/dist/feedback/index.d.ts +1 -1
  17. package/dist/feedback/skeleton.d.ts +1 -1
  18. package/dist/forms/index.d.ts +9 -9
  19. package/dist/forms/index.js +1 -1
  20. package/dist/forms/package-enum-select.d.ts +3 -3
  21. package/dist/forms/package-select.d.ts +5 -5
  22. package/dist/forms/select-icons.d.ts +2 -2
  23. package/dist/graphs/graph-edge.d.ts +1 -1
  24. package/dist/graphs/graph-node-handle-badge.d.ts +1 -1
  25. package/dist/graphs/graph-node-shell.d.ts +1 -1
  26. package/dist/graphs/graph-node-state-indicator.d.ts +1 -1
  27. package/dist/graphs/index.d.ts +5 -5
  28. package/dist/graphs/index.js +483 -483
  29. package/dist/index.d.ts +16 -16
  30. package/dist/index.js +87 -87
  31. package/dist/layout/action-row.d.ts +1 -1
  32. package/dist/layout/index.d.ts +2 -2
  33. package/dist/overlays/collapsible.d.ts +1 -1
  34. package/dist/overlays/dialog.d.ts +6 -6
  35. package/dist/overlays/index.d.ts +3 -3
  36. package/dist/overlays/popover.d.ts +1 -1
  37. package/dist/primitives/index.d.ts +5 -5
  38. package/dist/primitives/index.js +3 -3
  39. package/dist/primitives/package-text.d.ts +1 -1
  40. package/dist/recipes/index.d.ts +7 -7
  41. package/dist/recipes/index.js +1 -1
  42. package/dist/recipes/widget-frame-content.d.ts +5 -5
  43. package/dist/recipes/widget-frame-disclosure.d.ts +3 -3
  44. package/dist/recipes/widget-frame-skeleton.d.ts +1 -1
  45. package/dist/recipes/widget-frame-states.d.ts +3 -3
  46. package/dist/recipes/widget-frame.d.ts +1 -1
  47. package/dist/testing/render.d.ts +1 -1
  48. package/package.json +1 -2
@@ -1,7 +1,274 @@
1
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import { forwardRef, useRef, useState, useEffect } from "react";
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { getBezierPath, Position, BaseEdge, Handle } from "@xyflow/react";
3
+ import { useRef, useState, useEffect, forwardRef } from "react";
3
4
  import { c as cn } from "../chunks/cn.js";
4
- import { Position, Handle, getBezierPath, BaseEdge } from "@xyflow/react";
5
+ const CATMULL_ROM_ALPHA = 0.5;
6
+ const MIN_PARAMETER_DISTANCE = 1e-4;
7
+ const VIRTUAL_ENDPOINT_DISTANCE = 96;
8
+ function positionVector(position) {
9
+ switch (position) {
10
+ case Position.Left:
11
+ return { x: -1, y: 0 };
12
+ case Position.Right:
13
+ return { x: 1, y: 0 };
14
+ case Position.Top:
15
+ return { x: 0, y: -1 };
16
+ case Position.Bottom:
17
+ return { x: 0, y: 1 };
18
+ }
19
+ }
20
+ function pointDistance(first, second) {
21
+ return Math.hypot(second.x - first.x, second.y - first.y);
22
+ }
23
+ function catmullRomParameterDistance(first, second) {
24
+ return Math.max(
25
+ MIN_PARAMETER_DISTANCE,
26
+ pointDistance(first, second) ** CATMULL_ROM_ALPHA
27
+ );
28
+ }
29
+ function formatPathNumber(value) {
30
+ if (Object.is(value, -0)) {
31
+ return "0";
32
+ }
33
+ return Number.isInteger(value) ? `${value}` : value.toFixed(3);
34
+ }
35
+ function compactConsecutiveRoutePoints(routePoints) {
36
+ const compacted = [];
37
+ for (const point of routePoints) {
38
+ const previous = compacted.at(-1);
39
+ if (previous && previous.x === point.x && previous.y === point.y) {
40
+ continue;
41
+ }
42
+ compacted.push(point);
43
+ }
44
+ return compacted;
45
+ }
46
+ function virtualEndpoint(input) {
47
+ const distance = Math.max(
48
+ VIRTUAL_ENDPOINT_DISTANCE,
49
+ pointDistance(input.from, input.neighbor)
50
+ );
51
+ const scalar = input.mode === "before" ? -distance : distance;
52
+ return {
53
+ x: input.from.x + input.direction.x * scalar,
54
+ y: input.from.y + input.direction.y * scalar
55
+ };
56
+ }
57
+ function catmullRomTangent(input) {
58
+ const previousSpan = input.tCurrent - input.tPrevious;
59
+ const nextSpan = input.tNext - input.tCurrent;
60
+ const totalSpan = input.tNext - input.tPrevious;
61
+ return {
62
+ x: nextSpan * ((input.current.x - input.previous.x) / previousSpan - (input.next.x - input.previous.x) / totalSpan + (input.next.x - input.current.x) / nextSpan),
63
+ y: nextSpan * ((input.current.y - input.previous.y) / previousSpan - (input.next.y - input.previous.y) / totalSpan + (input.next.y - input.current.y) / nextSpan)
64
+ };
65
+ }
66
+ function buildWaypointCatmullRomPath(input) {
67
+ const routePoints = compactConsecutiveRoutePoints(input.routePoints);
68
+ if (routePoints.length <= 1) {
69
+ const [point] = routePoints;
70
+ return point ? `M ${formatPathNumber(point.x)} ${formatPathNumber(point.y)}` : "";
71
+ }
72
+ const lastPointIndex = routePoints.length - 1;
73
+ const [source] = routePoints;
74
+ const points = [
75
+ virtualEndpoint({
76
+ direction: positionVector(input.sourcePosition),
77
+ from: source,
78
+ mode: "before",
79
+ neighbor: routePoints[1]
80
+ }),
81
+ ...routePoints,
82
+ virtualEndpoint({
83
+ direction: {
84
+ x: -positionVector(input.targetPosition).x,
85
+ y: -positionVector(input.targetPosition).y
86
+ },
87
+ from: routePoints[lastPointIndex],
88
+ mode: "after",
89
+ neighbor: routePoints[lastPointIndex - 1]
90
+ })
91
+ ];
92
+ const segments = [
93
+ `M ${formatPathNumber(source.x)} ${formatPathNumber(source.y)}`
94
+ ];
95
+ for (let index = 1; index <= lastPointIndex; index += 1) {
96
+ const previous = points[index - 1];
97
+ const start = points[index];
98
+ const end = points[index + 1];
99
+ const next = points[index + 2];
100
+ const tPrevious = 0;
101
+ const tStart = tPrevious + catmullRomParameterDistance(previous, start);
102
+ const tEnd = tStart + catmullRomParameterDistance(start, end);
103
+ const tNext = tEnd + catmullRomParameterDistance(end, next);
104
+ const startTangent = catmullRomTangent({
105
+ current: start,
106
+ next: end,
107
+ previous,
108
+ tCurrent: tStart,
109
+ tNext: tEnd,
110
+ tPrevious
111
+ });
112
+ const endTangent = catmullRomTangent({
113
+ current: end,
114
+ next,
115
+ previous: start,
116
+ tCurrent: tEnd,
117
+ tNext,
118
+ tPrevious: tStart
119
+ });
120
+ const firstControl = {
121
+ x: start.x + startTangent.x / 3,
122
+ y: start.y + startTangent.y / 3
123
+ };
124
+ const secondControl = {
125
+ x: end.x - endTangent.x / 3,
126
+ y: end.y - endTangent.y / 3
127
+ };
128
+ segments.push(
129
+ [
130
+ "C",
131
+ formatPathNumber(firstControl.x),
132
+ formatPathNumber(firstControl.y),
133
+ `${formatPathNumber(secondControl.x)},`,
134
+ formatPathNumber(secondControl.y),
135
+ `${formatPathNumber(end.x)},`,
136
+ formatPathNumber(end.y)
137
+ ].join(" ")
138
+ );
139
+ }
140
+ return segments.join(" ");
141
+ }
142
+ function buildGraphEdgePathThroughWaypoints(input) {
143
+ const routePoints = [
144
+ { x: input.sourceX, y: input.sourceY },
145
+ ...input.waypoints ?? [],
146
+ { x: input.targetX, y: input.targetY }
147
+ ];
148
+ if (routePoints.length <= 2) {
149
+ const [path2, labelX, labelY] = getBezierPath({
150
+ sourcePosition: input.sourcePosition,
151
+ sourceX: input.sourceX,
152
+ sourceY: input.sourceY,
153
+ targetPosition: input.targetPosition,
154
+ targetX: input.targetX,
155
+ targetY: input.targetY
156
+ });
157
+ return { labelX, labelY, path: path2 };
158
+ }
159
+ const path = buildWaypointCatmullRomPath({
160
+ routePoints,
161
+ sourcePosition: input.sourcePosition,
162
+ targetPosition: input.targetPosition
163
+ });
164
+ const midpointIndex = Math.floor((routePoints.length - 1) / 2);
165
+ const labelPoint = routePoints[midpointIndex];
166
+ return {
167
+ labelX: labelPoint.x,
168
+ labelY: labelPoint.y,
169
+ path
170
+ };
171
+ }
172
+ const GRAPH_EDGE_TYPES = {
173
+ graphEdge: GraphEdge
174
+ };
175
+ function GraphEdge({
176
+ data,
177
+ edgeClassName = "graph-edge",
178
+ id,
179
+ interactionWidth,
180
+ labelClassName = "graph-edge-label pointer-events-none fill-on-surface-subtle text-[11px] font-semibold",
181
+ markerEnd,
182
+ selected,
183
+ sourcePosition,
184
+ sourceX,
185
+ sourceY,
186
+ style,
187
+ targetPosition,
188
+ targetX,
189
+ targetY
190
+ }) {
191
+ const edgeRef = useRef(null);
192
+ const [inspected, setInspected] = useState(false);
193
+ const edgeData = data ?? {};
194
+ const routedPath = buildGraphEdgePathThroughWaypoints({
195
+ sourcePosition,
196
+ sourceX,
197
+ sourceY,
198
+ targetPosition,
199
+ targetX,
200
+ targetY,
201
+ waypoints: edgeData.waypoints
202
+ });
203
+ const [fallbackPath, fallbackLabelX, fallbackLabelY] = getBezierPath({
204
+ sourcePosition,
205
+ sourceX,
206
+ sourceY,
207
+ targetPosition,
208
+ targetX,
209
+ targetY
210
+ });
211
+ const edgePath = edgeData.waypoints && edgeData.waypoints.length > 0 ? routedPath.path : fallbackPath;
212
+ const labelX = edgeData.waypoints && edgeData.waypoints.length > 0 ? routedPath.labelX : fallbackLabelX;
213
+ const labelY = edgeData.waypoints && edgeData.waypoints.length > 0 ? routedPath.labelY : fallbackLabelY;
214
+ useEffect(() => {
215
+ const edgeElement = edgeRef.current?.parentElement;
216
+ if (!edgeElement) {
217
+ return;
218
+ }
219
+ const show = () => setInspected(true);
220
+ const hide = () => setInspected(false);
221
+ edgeElement.addEventListener("mouseenter", show);
222
+ edgeElement.addEventListener("mouseleave", hide);
223
+ edgeElement.addEventListener("focusin", show);
224
+ edgeElement.addEventListener("focusout", hide);
225
+ return () => {
226
+ edgeElement.removeEventListener("mouseenter", show);
227
+ edgeElement.removeEventListener("mouseleave", hide);
228
+ edgeElement.removeEventListener("focusin", show);
229
+ edgeElement.removeEventListener("focusout", hide);
230
+ };
231
+ }, []);
232
+ const revealLabel = Boolean(
233
+ edgeData.label && (edgeData.alwaysShowLabel || inspected || selected)
234
+ );
235
+ return /* @__PURE__ */ jsxs(
236
+ "g",
237
+ {
238
+ className: edgeClassName,
239
+ "data-edge-id": id,
240
+ "data-label-visible": revealLabel ? "true" : "false",
241
+ ref: edgeRef,
242
+ children: [
243
+ /* @__PURE__ */ jsx(
244
+ BaseEdge,
245
+ {
246
+ interactionWidth,
247
+ markerEnd,
248
+ path: edgePath,
249
+ style
250
+ }
251
+ ),
252
+ edgeData.label ? /* @__PURE__ */ jsx(
253
+ "text",
254
+ {
255
+ className: labelClassName,
256
+ style: {
257
+ paintOrder: "stroke",
258
+ stroke: "var(--color-surface)",
259
+ strokeLinejoin: "round",
260
+ strokeWidth: 8
261
+ },
262
+ textAnchor: "middle",
263
+ x: labelX,
264
+ y: labelY,
265
+ children: edgeData.label
266
+ }
267
+ ) : null
268
+ ]
269
+ }
270
+ );
271
+ }
5
272
  const GRAPH_NODE_CONTENT_MIN_HEIGHT_CLASS = "min-h-12";
6
273
  const GRAPH_NODE_STATE_INDICATOR_HEIGHT_CLASS = "min-h-5";
7
274
  function graphNodeShellStateClassName(state) {
@@ -79,518 +346,251 @@ const GraphNodeButton = forwardRef(function GraphNodeButton2({
79
346
  className,
80
347
  disabled,
81
348
  graphState = "default",
82
- onClick,
83
- stateLabel,
84
- type = "button",
85
- ...props
86
- }, ref) {
87
- const isDisabled = graphNodeButtonIsDisabled(graphState, disabled);
88
- return /* @__PURE__ */ jsx(
89
- "button",
90
- {
91
- className: cn(
92
- GRAPH_NODE_BUTTON_BASE_CLASS,
93
- graphNodeButtonStateClassName(graphState),
94
- className
95
- ),
96
- disabled: isDisabled,
97
- onClick: isDisabled ? void 0 : onClick,
98
- ref,
99
- type,
100
- ...graphNodeButtonStateAttributes(graphState, stateLabel),
101
- ...props
102
- }
103
- );
104
- });
105
- const GraphViewportSurface = forwardRef(function GraphViewportSurface2({ children, className, role, ...props }, ref) {
106
- return /* @__PURE__ */ jsx(
107
- "section",
108
- {
109
- className: cn(
110
- "relative min-h-0 overflow-hidden rounded-3xl border shadow-none transition-colors",
111
- className
112
- ),
113
- "data-graph-viewport-surface": "true",
114
- ref,
115
- role: role ?? "region",
116
- ...props,
117
- children
118
- }
119
- );
120
- });
121
- function GraphNodeHandleBadge({ handle }) {
122
- const position = handle.side === "left" ? Position.Left : Position.Right;
123
- const overlayHandleStyle = anchoredHandleStyle(handle.side);
124
- const isButton = handle.onButtonClick !== void 0;
125
- if (handle.hidden) {
126
- return /* @__PURE__ */ jsx(
127
- Handle,
128
- {
129
- className: "pointer-events-none !top-1/2 opacity-0",
130
- id: handle.id,
131
- isConnectable: handle.connectable ?? false,
132
- position,
133
- style: overlayHandleStyle,
134
- type: handle.type
135
- }
136
- );
137
- }
138
- const tone = handle.tone ?? "default";
139
- return /* @__PURE__ */ jsx(
140
- "div",
141
- {
142
- className: "pointer-events-none relative flex h-5 w-5 items-center justify-center",
143
- "data-node-handle-badge": handle.id,
144
- "data-node-handle-invalid": handle.validationError ? "true" : void 0,
145
- "data-node-handle-tone": tone,
146
- children: /* @__PURE__ */ jsx(
147
- Handle,
148
- {
149
- "aria-disabled": isButton && handle.buttonDisabled ? true : void 0,
150
- "aria-invalid": handle.validationError ? true : void 0,
151
- "aria-label": handle.buttonAriaLabel ?? handle.label,
152
- "aria-pressed": isButton ? handle.buttonPressed : void 0,
153
- className: cn(
154
- "pointer-events-auto absolute !top-1/2 !h-5 !w-5 !border-0 !bg-transparent",
155
- "before:pointer-events-none before:absolute before:top-1/2 before:h-2.5 before:w-2.5 before:-translate-x-1/2 before:-translate-y-1/2 before:rounded-full before:border before:border-surface before:bg-[var(--node-handle-background)] before:shadow-sm before:transition before:content-['']",
156
- handle.side === "left" ? "before:left-0" : "before:left-full",
157
- handle.buttonPressed && "before:scale-125 before:shadow-[0_0_0_3px_var(--color-primary-container)]",
158
- handle.variant === "valid-target" && "before:scale-125 before:shadow-[0_0_0_3px_var(--color-success-container)]",
159
- handle.variant === "error" && "before:border-af-danger-border before:shadow-[0_0_0_3px_var(--color-error-container)] motion-safe:before:animate-pulse",
160
- handle.validationError && "before:ring-2 before:ring-af-danger-border motion-safe:before:animate-pulse"
161
- ),
162
- id: handle.id,
163
- isConnectable: handle.connectable ?? true,
164
- onClick: handle.buttonDisabled ? void 0 : handle.onButtonClick,
165
- onKeyDown: isButton && !handle.buttonDisabled ? (event) => {
166
- if (event.key !== "Enter" && event.key !== " ") return;
167
- event.preventDefault();
168
- handle.onButtonClick?.();
169
- } : void 0,
170
- position,
171
- role: isButton ? "button" : "img",
172
- style: {
173
- ...overlayHandleStyle,
174
- "--node-handle-background": handleDotColor(tone),
175
- opacity: handle.buttonDisabled ? 0.45 : void 0
176
- },
177
- title: handle.buttonTitle ?? handle.validationMessage,
178
- tabIndex: isButton && !handle.buttonDisabled ? 0 : void 0,
179
- type: handle.type
180
- }
181
- )
182
- }
183
- );
184
- }
185
- function handleDotColor(tone) {
186
- switch (tone) {
187
- case "assignment":
188
- return "var(--color-success)";
189
- case "continue":
190
- return "var(--color-secondary)";
191
- case "failure":
192
- return "var(--color-error)";
193
- case "input":
194
- return "var(--color-success)";
195
- case "output":
196
- return "var(--color-success)";
197
- case "rejection":
198
- return "var(--color-warning)";
199
- case "resource":
200
- return "var(--color-black)";
201
- case "worker":
202
- return "var(--color-purple-500)";
203
- default:
204
- return "var(--color-success)";
205
- }
206
- }
207
- function anchoredHandleStyle(side) {
208
- return side === "left" ? {
209
- left: "50%",
210
- top: "50%",
211
- transform: "translateY(-50%)"
212
- } : {
213
- left: "50%",
214
- top: "50%",
215
- transform: "translate(-100%, -50%)"
216
- };
217
- }
218
- function GraphNodeStateIndicator({
219
- state,
220
- stateLabel
221
- }) {
222
- const label = stateLabel ?? defaultGraphNodeStateLabel(state);
223
- const showIndicator = state === "loading" || state === "error";
224
- return /* @__PURE__ */ jsx(
225
- "div",
226
- {
227
- "aria-hidden": showIndicator ? void 0 : true,
228
- className: cn(
229
- GRAPH_NODE_STATE_INDICATOR_HEIGHT_CLASS,
230
- "flex items-center gap-2 text-[0.65rem] font-semibold uppercase tracking-[0.08em]",
231
- state === "error" ? "text-on-error-container" : "text-on-surface-variant",
232
- !showIndicator && "invisible"
233
- ),
234
- "data-graph-node-state-indicator": showIndicator ? state : void 0,
235
- children: state === "loading" ? /* @__PURE__ */ jsxs(Fragment, { children: [
236
- /* @__PURE__ */ jsx(
237
- "span",
238
- {
239
- "aria-hidden": "true",
240
- className: "inline-block h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-outline border-t-primary",
241
- "data-graph-node-loading-spinner": "true"
242
- }
243
- ),
244
- /* @__PURE__ */ jsx("span", { children: label ?? "Loading" })
245
- ] }) : state === "error" ? /* @__PURE__ */ jsx("span", { role: "alert", children: label ?? "Error" }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " " })
246
- }
247
- );
248
- }
249
- function GraphNodeShell({
250
- children,
251
- className = "",
252
- handles,
253
- nodeKind,
254
- showStateIndicator = true,
255
- state = "default",
256
- stateLabel,
257
- ...articleProps
258
- }) {
259
- const leftHandles = handles.filter((handle) => handle.side === "left");
260
- const rightHandles = handles.filter((handle) => handle.side === "right");
261
- return /* @__PURE__ */ jsxs(
262
- "article",
349
+ onClick,
350
+ stateLabel,
351
+ type = "button",
352
+ ...props
353
+ }, ref) {
354
+ const isDisabled = graphNodeButtonIsDisabled(graphState, disabled);
355
+ return /* @__PURE__ */ jsx(
356
+ "button",
263
357
  {
264
358
  className: cn(
265
- "relative flex h-full min-w-0 w-full overflow-visible rounded-lg border border-outline bg-surface text-on-surface",
266
- graphNodeShellStateClassName(state),
359
+ GRAPH_NODE_BUTTON_BASE_CLASS,
360
+ graphNodeButtonStateClassName(graphState),
267
361
  className
268
362
  ),
269
- "data-graph-node-kind": nodeKind,
270
- ...graphNodeShellStateAttributes(state, stateLabel),
271
- ...articleProps,
272
- children: [
273
- /* @__PURE__ */ jsx(NodeHandleRail, { handles: leftHandles, side: "left" }),
274
- /* @__PURE__ */ jsx(NodeHandleRail, { handles: rightHandles, side: "right" }),
275
- /* @__PURE__ */ jsxs(
276
- "div",
277
- {
278
- className: cn(
279
- "flex h-full min-w-0 w-full flex-col gap-1 py-3",
280
- showStateIndicator && GRAPH_NODE_CONTENT_MIN_HEIGHT_CLASS,
281
- leftHandles.length > 0 ? "pl-6 pr-3" : "px-3",
282
- rightHandles.length > 0 && leftHandles.length > 0 ? "pr-6" : rightHandles.length > 0 ? "pl-3 pr-6" : null
283
- ),
284
- children: [
285
- showStateIndicator ? /* @__PURE__ */ jsx(GraphNodeStateIndicator, { state, stateLabel }) : null,
286
- children
287
- ]
288
- }
289
- )
290
- ]
363
+ disabled: isDisabled,
364
+ onClick: isDisabled ? void 0 : onClick,
365
+ ref,
366
+ type,
367
+ ...graphNodeButtonStateAttributes(graphState, stateLabel),
368
+ ...props
291
369
  }
292
370
  );
293
- }
294
- function NodeHandleRail({
295
- handles,
296
- side
297
- }) {
298
- if (handles.length === 0) {
299
- return null;
371
+ });
372
+ function GraphNodeHandleBadge({ handle }) {
373
+ const position = handle.side === "left" ? Position.Left : Position.Right;
374
+ const overlayHandleStyle = anchoredHandleStyle(handle.side);
375
+ const isButton = handle.onButtonClick !== void 0;
376
+ if (handle.hidden) {
377
+ return /* @__PURE__ */ jsx(
378
+ Handle,
379
+ {
380
+ className: "pointer-events-none !top-1/2 opacity-0",
381
+ id: handle.id,
382
+ isConnectable: handle.connectable ?? false,
383
+ position,
384
+ style: overlayHandleStyle,
385
+ type: handle.type
386
+ }
387
+ );
300
388
  }
389
+ const tone = handle.tone ?? "default";
301
390
  return /* @__PURE__ */ jsx(
302
391
  "div",
303
392
  {
304
- className: cn(
305
- "pointer-events-none absolute inset-y-0 z-20 w-6",
306
- side === "left" ? "left-0" : "right-0"
307
- ),
308
- "data-node-handle-rail": side,
309
- children: handles.map((handle, index) => /* @__PURE__ */ jsx(
310
- "div",
393
+ className: "pointer-events-none relative flex h-5 w-5 items-center justify-center",
394
+ "data-node-handle-badge": handle.id,
395
+ "data-node-handle-invalid": handle.validationError ? "true" : void 0,
396
+ "data-node-handle-tone": tone,
397
+ children: /* @__PURE__ */ jsx(
398
+ Handle,
311
399
  {
400
+ "aria-disabled": isButton && handle.buttonDisabled ? true : void 0,
401
+ "aria-invalid": handle.validationError ? true : void 0,
402
+ "aria-label": handle.buttonAriaLabel ?? handle.label,
403
+ "aria-pressed": isButton ? handle.buttonPressed : void 0,
312
404
  className: cn(
313
- "absolute top-0 flex -translate-y-1/2",
314
- side === "left" ? "left-0 -translate-x-1/2" : "right-0 translate-x-1/2"
405
+ "pointer-events-auto absolute !top-1/2 !h-5 !w-5 !border-0 !bg-transparent",
406
+ "before:pointer-events-none before:absolute before:top-1/2 before:h-2.5 before:w-2.5 before:-translate-x-1/2 before:-translate-y-1/2 before:rounded-full before:border before:border-surface before:bg-[var(--node-handle-background)] before:shadow-sm before:transition before:content-['']",
407
+ handle.side === "left" ? "before:left-0" : "before:left-full",
408
+ handle.buttonPressed && "before:scale-125 before:shadow-[0_0_0_3px_var(--color-primary-container)]",
409
+ handle.variant === "valid-target" && "before:scale-125 before:shadow-[0_0_0_3px_var(--color-success-container)]",
410
+ handle.variant === "error" && "before:border-af-danger-border before:shadow-[0_0_0_3px_var(--color-error-container)] motion-safe:before:animate-pulse",
411
+ handle.validationError && "before:ring-2 before:ring-af-danger-border motion-safe:before:animate-pulse"
315
412
  ),
316
- style: { top: handlePosition(index, handles.length) },
317
- children: /* @__PURE__ */ jsx(GraphNodeHandleBadge, { handle })
318
- },
319
- handle.id
320
- ))
321
- }
322
- );
323
- }
324
- function handlePosition(index, count) {
325
- return `${(index + 1) * 100 / (count + 1)}%`;
326
- }
327
- const CATMULL_ROM_ALPHA = 0.5;
328
- const MIN_PARAMETER_DISTANCE = 1e-4;
329
- const VIRTUAL_ENDPOINT_DISTANCE = 96;
330
- function positionVector(position) {
331
- switch (position) {
332
- case Position.Left:
333
- return { x: -1, y: 0 };
334
- case Position.Right:
335
- return { x: 1, y: 0 };
336
- case Position.Top:
337
- return { x: 0, y: -1 };
338
- case Position.Bottom:
339
- return { x: 0, y: 1 };
340
- }
341
- }
342
- function pointDistance(first, second) {
343
- return Math.hypot(second.x - first.x, second.y - first.y);
344
- }
345
- function catmullRomParameterDistance(first, second) {
346
- return Math.max(
347
- MIN_PARAMETER_DISTANCE,
348
- pointDistance(first, second) ** CATMULL_ROM_ALPHA
349
- );
350
- }
351
- function formatPathNumber(value) {
352
- if (Object.is(value, -0)) {
353
- return "0";
354
- }
355
- return Number.isInteger(value) ? `${value}` : value.toFixed(3);
356
- }
357
- function compactConsecutiveRoutePoints(routePoints) {
358
- const compacted = [];
359
- for (const point of routePoints) {
360
- const previous = compacted.at(-1);
361
- if (previous && previous.x === point.x && previous.y === point.y) {
362
- continue;
413
+ id: handle.id,
414
+ isConnectable: handle.connectable ?? true,
415
+ onClick: handle.buttonDisabled ? void 0 : handle.onButtonClick,
416
+ onKeyDown: isButton && !handle.buttonDisabled ? (event) => {
417
+ if (event.key !== "Enter" && event.key !== " ") return;
418
+ event.preventDefault();
419
+ handle.onButtonClick?.();
420
+ } : void 0,
421
+ position,
422
+ role: isButton ? "button" : "img",
423
+ style: {
424
+ ...overlayHandleStyle,
425
+ "--node-handle-background": handleDotColor(tone),
426
+ opacity: handle.buttonDisabled ? 0.45 : void 0
427
+ },
428
+ title: handle.buttonTitle ?? handle.validationMessage,
429
+ tabIndex: isButton && !handle.buttonDisabled ? 0 : void 0,
430
+ type: handle.type
431
+ }
432
+ )
363
433
  }
364
- compacted.push(point);
365
- }
366
- return compacted;
367
- }
368
- function virtualEndpoint(input) {
369
- const distance = Math.max(
370
- VIRTUAL_ENDPOINT_DISTANCE,
371
- pointDistance(input.from, input.neighbor)
372
434
  );
373
- const scalar = input.mode === "before" ? -distance : distance;
374
- return {
375
- x: input.from.x + input.direction.x * scalar,
376
- y: input.from.y + input.direction.y * scalar
377
- };
378
- }
379
- function catmullRomTangent(input) {
380
- const previousSpan = input.tCurrent - input.tPrevious;
381
- const nextSpan = input.tNext - input.tCurrent;
382
- const totalSpan = input.tNext - input.tPrevious;
383
- return {
384
- x: nextSpan * ((input.current.x - input.previous.x) / previousSpan - (input.next.x - input.previous.x) / totalSpan + (input.next.x - input.current.x) / nextSpan),
385
- y: nextSpan * ((input.current.y - input.previous.y) / previousSpan - (input.next.y - input.previous.y) / totalSpan + (input.next.y - input.current.y) / nextSpan)
386
- };
387
435
  }
388
- function buildWaypointCatmullRomPath(input) {
389
- const routePoints = compactConsecutiveRoutePoints(input.routePoints);
390
- if (routePoints.length <= 1) {
391
- const [point] = routePoints;
392
- return point ? `M ${formatPathNumber(point.x)} ${formatPathNumber(point.y)}` : "";
393
- }
394
- const lastPointIndex = routePoints.length - 1;
395
- const [source] = routePoints;
396
- const points = [
397
- virtualEndpoint({
398
- direction: positionVector(input.sourcePosition),
399
- from: source,
400
- mode: "before",
401
- neighbor: routePoints[1]
402
- }),
403
- ...routePoints,
404
- virtualEndpoint({
405
- direction: {
406
- x: -positionVector(input.targetPosition).x,
407
- y: -positionVector(input.targetPosition).y
408
- },
409
- from: routePoints[lastPointIndex],
410
- mode: "after",
411
- neighbor: routePoints[lastPointIndex - 1]
412
- })
413
- ];
414
- const segments = [
415
- `M ${formatPathNumber(source.x)} ${formatPathNumber(source.y)}`
416
- ];
417
- for (let index = 1; index <= lastPointIndex; index += 1) {
418
- const previous = points[index - 1];
419
- const start = points[index];
420
- const end = points[index + 1];
421
- const next = points[index + 2];
422
- const tPrevious = 0;
423
- const tStart = tPrevious + catmullRomParameterDistance(previous, start);
424
- const tEnd = tStart + catmullRomParameterDistance(start, end);
425
- const tNext = tEnd + catmullRomParameterDistance(end, next);
426
- const startTangent = catmullRomTangent({
427
- current: start,
428
- next: end,
429
- previous,
430
- tCurrent: tStart,
431
- tNext: tEnd,
432
- tPrevious
433
- });
434
- const endTangent = catmullRomTangent({
435
- current: end,
436
- next,
437
- previous: start,
438
- tCurrent: tEnd,
439
- tNext,
440
- tPrevious: tStart
441
- });
442
- const firstControl = {
443
- x: start.x + startTangent.x / 3,
444
- y: start.y + startTangent.y / 3
445
- };
446
- const secondControl = {
447
- x: end.x - endTangent.x / 3,
448
- y: end.y - endTangent.y / 3
449
- };
450
- segments.push(
451
- [
452
- "C",
453
- formatPathNumber(firstControl.x),
454
- formatPathNumber(firstControl.y),
455
- `${formatPathNumber(secondControl.x)},`,
456
- formatPathNumber(secondControl.y),
457
- `${formatPathNumber(end.x)},`,
458
- formatPathNumber(end.y)
459
- ].join(" ")
460
- );
436
+ function handleDotColor(tone) {
437
+ switch (tone) {
438
+ case "assignment":
439
+ return "var(--color-success)";
440
+ case "continue":
441
+ return "var(--color-secondary)";
442
+ case "failure":
443
+ return "var(--color-error)";
444
+ case "input":
445
+ return "var(--color-success)";
446
+ case "output":
447
+ return "var(--color-success)";
448
+ case "rejection":
449
+ return "var(--color-warning)";
450
+ case "resource":
451
+ return "var(--color-black)";
452
+ case "worker":
453
+ return "var(--color-purple-500)";
454
+ default:
455
+ return "var(--color-success)";
461
456
  }
462
- return segments.join(" ");
463
457
  }
464
- function buildGraphEdgePathThroughWaypoints(input) {
465
- const routePoints = [
466
- { x: input.sourceX, y: input.sourceY },
467
- ...input.waypoints ?? [],
468
- { x: input.targetX, y: input.targetY }
469
- ];
470
- if (routePoints.length <= 2) {
471
- const [path2, labelX, labelY] = getBezierPath({
472
- sourcePosition: input.sourcePosition,
473
- sourceX: input.sourceX,
474
- sourceY: input.sourceY,
475
- targetPosition: input.targetPosition,
476
- targetX: input.targetX,
477
- targetY: input.targetY
478
- });
479
- return { labelX, labelY, path: path2 };
480
- }
481
- const path = buildWaypointCatmullRomPath({
482
- routePoints,
483
- sourcePosition: input.sourcePosition,
484
- targetPosition: input.targetPosition
485
- });
486
- const midpointIndex = Math.floor((routePoints.length - 1) / 2);
487
- const labelPoint = routePoints[midpointIndex];
488
- return {
489
- labelX: labelPoint.x,
490
- labelY: labelPoint.y,
491
- path
458
+ function anchoredHandleStyle(side) {
459
+ return side === "left" ? {
460
+ left: "50%",
461
+ top: "50%",
462
+ transform: "translateY(-50%)"
463
+ } : {
464
+ left: "50%",
465
+ top: "50%",
466
+ transform: "translate(-100%, -50%)"
492
467
  };
493
468
  }
494
- const GRAPH_EDGE_TYPES = {
495
- graphEdge: GraphEdge
496
- };
497
- function GraphEdge({
498
- data,
499
- edgeClassName = "graph-edge",
500
- id,
501
- interactionWidth,
502
- labelClassName = "graph-edge-label pointer-events-none fill-on-surface-subtle text-[11px] font-semibold",
503
- markerEnd,
504
- selected,
505
- sourcePosition,
506
- sourceX,
507
- sourceY,
508
- style,
509
- targetPosition,
510
- targetX,
511
- targetY
469
+ function GraphNodeStateIndicator({
470
+ state,
471
+ stateLabel
512
472
  }) {
513
- const edgeRef = useRef(null);
514
- const [inspected, setInspected] = useState(false);
515
- const edgeData = data ?? {};
516
- const routedPath = buildGraphEdgePathThroughWaypoints({
517
- sourcePosition,
518
- sourceX,
519
- sourceY,
520
- targetPosition,
521
- targetX,
522
- targetY,
523
- waypoints: edgeData.waypoints
524
- });
525
- const [fallbackPath, fallbackLabelX, fallbackLabelY] = getBezierPath({
526
- sourcePosition,
527
- sourceX,
528
- sourceY,
529
- targetPosition,
530
- targetX,
531
- targetY
532
- });
533
- const edgePath = edgeData.waypoints && edgeData.waypoints.length > 0 ? routedPath.path : fallbackPath;
534
- const labelX = edgeData.waypoints && edgeData.waypoints.length > 0 ? routedPath.labelX : fallbackLabelX;
535
- const labelY = edgeData.waypoints && edgeData.waypoints.length > 0 ? routedPath.labelY : fallbackLabelY;
536
- useEffect(() => {
537
- const edgeElement = edgeRef.current?.parentElement;
538
- if (!edgeElement) {
539
- return;
540
- }
541
- const show = () => setInspected(true);
542
- const hide = () => setInspected(false);
543
- edgeElement.addEventListener("mouseenter", show);
544
- edgeElement.addEventListener("mouseleave", hide);
545
- edgeElement.addEventListener("focusin", show);
546
- edgeElement.addEventListener("focusout", hide);
547
- return () => {
548
- edgeElement.removeEventListener("mouseenter", show);
549
- edgeElement.removeEventListener("mouseleave", hide);
550
- edgeElement.removeEventListener("focusin", show);
551
- edgeElement.removeEventListener("focusout", hide);
552
- };
553
- }, []);
554
- const revealLabel = Boolean(
555
- edgeData.label && (edgeData.alwaysShowLabel || inspected || selected)
556
- );
557
- return /* @__PURE__ */ jsxs(
558
- "g",
473
+ const label = stateLabel ?? defaultGraphNodeStateLabel(state);
474
+ const showIndicator = state === "loading" || state === "error";
475
+ return /* @__PURE__ */ jsx(
476
+ "div",
559
477
  {
560
- className: edgeClassName,
561
- "data-edge-id": id,
562
- "data-label-visible": revealLabel ? "true" : "false",
563
- ref: edgeRef,
564
- children: [
478
+ "aria-hidden": showIndicator ? void 0 : true,
479
+ className: cn(
480
+ GRAPH_NODE_STATE_INDICATOR_HEIGHT_CLASS,
481
+ "flex items-center gap-2 text-[0.65rem] font-semibold uppercase tracking-[0.08em]",
482
+ state === "error" ? "text-on-error-container" : "text-on-surface-variant",
483
+ !showIndicator && "invisible"
484
+ ),
485
+ "data-graph-node-state-indicator": showIndicator ? state : void 0,
486
+ children: state === "loading" ? /* @__PURE__ */ jsxs(Fragment, { children: [
565
487
  /* @__PURE__ */ jsx(
566
- BaseEdge,
488
+ "span",
567
489
  {
568
- interactionWidth,
569
- markerEnd,
570
- path: edgePath,
571
- style
490
+ "aria-hidden": "true",
491
+ className: "inline-block h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-outline border-t-primary",
492
+ "data-graph-node-loading-spinner": "true"
572
493
  }
573
494
  ),
574
- edgeData.label ? /* @__PURE__ */ jsx(
575
- "text",
495
+ /* @__PURE__ */ jsx("span", { children: label ?? "Loading" })
496
+ ] }) : state === "error" ? /* @__PURE__ */ jsx("span", { role: "alert", children: label ?? "Error" }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " " })
497
+ }
498
+ );
499
+ }
500
+ function GraphNodeShell({
501
+ children,
502
+ className = "",
503
+ handles,
504
+ nodeKind,
505
+ showStateIndicator = true,
506
+ state = "default",
507
+ stateLabel,
508
+ ...articleProps
509
+ }) {
510
+ const leftHandles = handles.filter((handle) => handle.side === "left");
511
+ const rightHandles = handles.filter((handle) => handle.side === "right");
512
+ return /* @__PURE__ */ jsxs(
513
+ "article",
514
+ {
515
+ className: cn(
516
+ "relative flex h-full min-w-0 w-full overflow-visible rounded-lg border border-outline bg-surface text-on-surface",
517
+ graphNodeShellStateClassName(state),
518
+ className
519
+ ),
520
+ "data-graph-node-kind": nodeKind,
521
+ ...graphNodeShellStateAttributes(state, stateLabel),
522
+ ...articleProps,
523
+ children: [
524
+ /* @__PURE__ */ jsx(NodeHandleRail, { handles: leftHandles, side: "left" }),
525
+ /* @__PURE__ */ jsx(NodeHandleRail, { handles: rightHandles, side: "right" }),
526
+ /* @__PURE__ */ jsxs(
527
+ "div",
576
528
  {
577
- className: labelClassName,
578
- style: {
579
- paintOrder: "stroke",
580
- stroke: "var(--color-surface)",
581
- strokeLinejoin: "round",
582
- strokeWidth: 8
583
- },
584
- textAnchor: "middle",
585
- x: labelX,
586
- y: labelY,
587
- children: edgeData.label
529
+ className: cn(
530
+ "flex h-full min-w-0 w-full flex-col gap-1 py-3",
531
+ showStateIndicator && GRAPH_NODE_CONTENT_MIN_HEIGHT_CLASS,
532
+ leftHandles.length > 0 ? "pl-6 pr-3" : "px-3",
533
+ rightHandles.length > 0 && leftHandles.length > 0 ? "pr-6" : rightHandles.length > 0 ? "pl-3 pr-6" : null
534
+ ),
535
+ children: [
536
+ showStateIndicator ? /* @__PURE__ */ jsx(GraphNodeStateIndicator, { state, stateLabel }) : null,
537
+ children
538
+ ]
588
539
  }
589
- ) : null
540
+ )
590
541
  ]
591
542
  }
592
543
  );
593
544
  }
545
+ function NodeHandleRail({
546
+ handles,
547
+ side
548
+ }) {
549
+ if (handles.length === 0) {
550
+ return null;
551
+ }
552
+ return /* @__PURE__ */ jsx(
553
+ "div",
554
+ {
555
+ className: cn(
556
+ "pointer-events-none absolute inset-y-0 z-20 w-6",
557
+ side === "left" ? "left-0" : "right-0"
558
+ ),
559
+ "data-node-handle-rail": side,
560
+ children: handles.map((handle, index) => /* @__PURE__ */ jsx(
561
+ "div",
562
+ {
563
+ className: cn(
564
+ "absolute top-0 flex -translate-y-1/2",
565
+ side === "left" ? "left-0 -translate-x-1/2" : "right-0 translate-x-1/2"
566
+ ),
567
+ style: { top: handlePosition(index, handles.length) },
568
+ children: /* @__PURE__ */ jsx(GraphNodeHandleBadge, { handle })
569
+ },
570
+ handle.id
571
+ ))
572
+ }
573
+ );
574
+ }
575
+ function handlePosition(index, count) {
576
+ return `${(index + 1) * 100 / (count + 1)}%`;
577
+ }
578
+ const GraphViewportSurface = forwardRef(function GraphViewportSurface2({ children, className, role, ...props }, ref) {
579
+ return /* @__PURE__ */ jsx(
580
+ "section",
581
+ {
582
+ className: cn(
583
+ "relative min-h-0 overflow-hidden rounded-3xl border shadow-none transition-colors",
584
+ className
585
+ ),
586
+ "data-graph-viewport-surface": "true",
587
+ ref,
588
+ role: role ?? "region",
589
+ ...props,
590
+ children
591
+ }
592
+ );
593
+ });
594
594
  const COMPONENTS_CATEGORY = "graphs";
595
595
  export {
596
596
  COMPONENTS_CATEGORY,