@uipath/apollo-react 4.24.1 → 4.24.2-pr672.9dd3fa2

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.
@@ -192,7 +192,7 @@ const ButtonHandleBase = ({ id, nodeId, type, position, connectionPosition = pos
192
192
  const ButtonHandle = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(ButtonHandleBase);
193
193
  function InwardHandleContent({ handleType, isVertical, selected, hovered, showNotch, label, labelIcon, labelBackgroundColor, layout }) {
194
194
  const labelElement = label ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
195
- className: (0, CssUtil_cjs_namespaceObject.cx)('pointer-events-none flex items-center gap-1.5 whitespace-nowrap rounded-full border border-border-subtle bg-transparent px-2 py-0.5', 'text-xs font-medium leading-4 text-foreground-muted'),
195
+ className: (0, CssUtil_cjs_namespaceObject.cx)('pointer-events-none flex items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-surface px-2 py-0.5', 'text-xs font-medium leading-4 text-foreground-muted'),
196
196
  style: labelBackgroundColor ? {
197
197
  backgroundColor: labelBackgroundColor
198
198
  } : void 0,
@@ -163,7 +163,7 @@ const ButtonHandleBase = ({ id, nodeId, type, position, connectionPosition = pos
163
163
  const ButtonHandle = /*#__PURE__*/ memo(ButtonHandleBase);
164
164
  function InwardHandleContent({ handleType, isVertical, selected, hovered, showNotch, label, labelIcon, labelBackgroundColor, layout }) {
165
165
  const labelElement = label ? /*#__PURE__*/ jsxs("div", {
166
- className: cx('pointer-events-none flex items-center gap-1.5 whitespace-nowrap rounded-full border border-border-subtle bg-transparent px-2 py-0.5', 'text-xs font-medium leading-4 text-foreground-muted'),
166
+ className: cx('pointer-events-none flex items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-surface px-2 py-0.5', 'text-xs font-medium leading-4 text-foreground-muted'),
167
167
  style: labelBackgroundColor ? {
168
168
  backgroundColor: labelBackgroundColor
169
169
  } : void 0,
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ IterationNavigator: ()=>IterationNavigator
28
+ });
29
+ const jsx_runtime_namespaceObject = require("react/jsx-runtime");
30
+ const apollo_wind_namespaceObject = require("@uipath/apollo-wind");
31
+ const external_react_namespaceObject = require("react");
32
+ const index_cjs_namespaceObject = require("../../utils/index.cjs");
33
+ const icon_registry_cjs_namespaceObject = require("../../utils/icon-registry.cjs");
34
+ function resolveState(iterationState) {
35
+ if (!Number.isFinite(iterationState.total)) return;
36
+ const total = Math.trunc(iterationState.total);
37
+ if (total <= 0) return;
38
+ const rawActiveIndex = Number.isFinite(iterationState.activeIndex) ? Math.trunc(iterationState.activeIndex) : 0;
39
+ return {
40
+ ...iterationState,
41
+ total,
42
+ activeIndex: (0, index_cjs_namespaceObject.clamp)(rawActiveIndex, 0, total - 1)
43
+ };
44
+ }
45
+ function stopCanvasControlEvent(event) {
46
+ event.stopPropagation();
47
+ }
48
+ function IterationNavigator({ iterationState }) {
49
+ const resolvedState = resolveState(iterationState);
50
+ if (!resolvedState) return null;
51
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(NavigatorContent, {
52
+ iterationState: resolvedState
53
+ });
54
+ }
55
+ function NavigatorContent({ iterationState }) {
56
+ const { activeIndex, total, onActiveIndexChange, disabled, ariaLabel } = iterationState;
57
+ const canInteract = !disabled && 'function' == typeof onActiveIndexChange;
58
+ const canGoPrevious = canInteract && activeIndex > 0;
59
+ const canGoNext = canInteract && activeIndex < total - 1;
60
+ const label = ariaLabel ?? 'Loop iteration';
61
+ const visibleIndex = activeIndex + 1;
62
+ const handlePrevious = (0, external_react_namespaceObject.useCallback)((event)=>{
63
+ event.stopPropagation();
64
+ if (!canGoPrevious) return;
65
+ onActiveIndexChange?.(activeIndex - 1);
66
+ }, [
67
+ activeIndex,
68
+ canGoPrevious,
69
+ onActiveIndexChange
70
+ ]);
71
+ const handleNext = (0, external_react_namespaceObject.useCallback)((event)=>{
72
+ event.stopPropagation();
73
+ if (!canGoNext) return;
74
+ onActiveIndexChange?.(activeIndex + 1);
75
+ }, [
76
+ activeIndex,
77
+ canGoNext,
78
+ onActiveIndexChange
79
+ ]);
80
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("fieldset", {
81
+ className: (0, apollo_wind_namespaceObject.cn)('nodrag nopan pointer-events-auto m-0 flex h-6 min-w-0 shrink-0 items-center gap-1 rounded-full px-1 py-0', 'border border-border bg-surface text-foreground shadow-sm'),
82
+ "data-testid": "loop-iteration-navigator",
83
+ onPointerDown: stopCanvasControlEvent,
84
+ onMouseDown: stopCanvasControlEvent,
85
+ onDoubleClick: stopCanvasControlEvent,
86
+ children: [
87
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("legend", {
88
+ className: "sr-only",
89
+ children: [
90
+ label,
91
+ ": ",
92
+ visibleIndex,
93
+ " of ",
94
+ total
95
+ ]
96
+ }),
97
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("button", {
98
+ type: "button",
99
+ className: (0, apollo_wind_namespaceObject.cn)('nodrag nopan inline-flex h-4 w-4 items-center justify-center rounded-full', 'text-foreground transition-opacity', canGoPrevious ? 'cursor-pointer opacity-100' : 'cursor-not-allowed opacity-40'),
100
+ disabled: !canGoPrevious,
101
+ "aria-label": "Previous loop iteration",
102
+ onClick: handlePrevious,
103
+ onPointerDown: stopCanvasControlEvent,
104
+ onMouseDown: stopCanvasControlEvent,
105
+ "data-testid": "loop-iteration-previous",
106
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icon_registry_cjs_namespaceObject.CanvasIcon, {
107
+ icon: "chevron-left",
108
+ size: 12
109
+ })
110
+ }),
111
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
112
+ className: "min-w-8 select-none px-1 text-center text-[11px] font-semibold leading-4",
113
+ "data-testid": "loop-iteration-label",
114
+ children: [
115
+ visibleIndex,
116
+ " / ",
117
+ total
118
+ ]
119
+ }),
120
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("button", {
121
+ type: "button",
122
+ className: (0, apollo_wind_namespaceObject.cn)('nodrag nopan inline-flex h-4 w-4 items-center justify-center rounded-full', 'text-foreground transition-opacity', canGoNext ? 'cursor-pointer opacity-100' : 'cursor-not-allowed opacity-40'),
123
+ disabled: !canGoNext,
124
+ "aria-label": "Next loop iteration",
125
+ onClick: handleNext,
126
+ onPointerDown: stopCanvasControlEvent,
127
+ onMouseDown: stopCanvasControlEvent,
128
+ "data-testid": "loop-iteration-next",
129
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icon_registry_cjs_namespaceObject.CanvasIcon, {
130
+ icon: "chevron-right",
131
+ size: 12
132
+ })
133
+ })
134
+ ]
135
+ });
136
+ }
137
+ exports.IterationNavigator = __webpack_exports__.IterationNavigator;
138
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
139
+ "IterationNavigator"
140
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
141
+ Object.defineProperty(exports, '__esModule', {
142
+ value: true
143
+ });
@@ -0,0 +1,7 @@
1
+ import type { LoopIterationState } from './LoopNode.types';
2
+ interface IterationNavigatorProps {
3
+ iterationState: LoopIterationState;
4
+ }
5
+ export declare function IterationNavigator({ iterationState }: IterationNavigatorProps): import("react/jsx-runtime").JSX.Element | null;
6
+ export {};
7
+ //# sourceMappingURL=IterationNavigator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IterationNavigator.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/LoopNode/IterationNavigator.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,UAAU,uBAAuB;IAC/B,cAAc,EAAE,kBAAkB,CAAC;CACpC;AA4BD,wBAAgB,kBAAkB,CAAC,EAAE,cAAc,EAAE,EAAE,uBAAuB,kDAQ7E"}
@@ -0,0 +1,109 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "@uipath/apollo-wind";
3
+ import { useCallback } from "react";
4
+ import { clamp } from "../../utils/index.js";
5
+ import { CanvasIcon } from "../../utils/icon-registry.js";
6
+ function resolveState(iterationState) {
7
+ if (!Number.isFinite(iterationState.total)) return;
8
+ const total = Math.trunc(iterationState.total);
9
+ if (total <= 0) return;
10
+ const rawActiveIndex = Number.isFinite(iterationState.activeIndex) ? Math.trunc(iterationState.activeIndex) : 0;
11
+ return {
12
+ ...iterationState,
13
+ total,
14
+ activeIndex: clamp(rawActiveIndex, 0, total - 1)
15
+ };
16
+ }
17
+ function stopCanvasControlEvent(event) {
18
+ event.stopPropagation();
19
+ }
20
+ function IterationNavigator({ iterationState }) {
21
+ const resolvedState = resolveState(iterationState);
22
+ if (!resolvedState) return null;
23
+ return /*#__PURE__*/ jsx(NavigatorContent, {
24
+ iterationState: resolvedState
25
+ });
26
+ }
27
+ function NavigatorContent({ iterationState }) {
28
+ const { activeIndex, total, onActiveIndexChange, disabled, ariaLabel } = iterationState;
29
+ const canInteract = !disabled && 'function' == typeof onActiveIndexChange;
30
+ const canGoPrevious = canInteract && activeIndex > 0;
31
+ const canGoNext = canInteract && activeIndex < total - 1;
32
+ const label = ariaLabel ?? 'Loop iteration';
33
+ const visibleIndex = activeIndex + 1;
34
+ const handlePrevious = useCallback((event)=>{
35
+ event.stopPropagation();
36
+ if (!canGoPrevious) return;
37
+ onActiveIndexChange?.(activeIndex - 1);
38
+ }, [
39
+ activeIndex,
40
+ canGoPrevious,
41
+ onActiveIndexChange
42
+ ]);
43
+ const handleNext = useCallback((event)=>{
44
+ event.stopPropagation();
45
+ if (!canGoNext) return;
46
+ onActiveIndexChange?.(activeIndex + 1);
47
+ }, [
48
+ activeIndex,
49
+ canGoNext,
50
+ onActiveIndexChange
51
+ ]);
52
+ return /*#__PURE__*/ jsxs("fieldset", {
53
+ className: cn('nodrag nopan pointer-events-auto m-0 flex h-6 min-w-0 shrink-0 items-center gap-1 rounded-full px-1 py-0', 'border border-border bg-surface text-foreground shadow-sm'),
54
+ "data-testid": "loop-iteration-navigator",
55
+ onPointerDown: stopCanvasControlEvent,
56
+ onMouseDown: stopCanvasControlEvent,
57
+ onDoubleClick: stopCanvasControlEvent,
58
+ children: [
59
+ /*#__PURE__*/ jsxs("legend", {
60
+ className: "sr-only",
61
+ children: [
62
+ label,
63
+ ": ",
64
+ visibleIndex,
65
+ " of ",
66
+ total
67
+ ]
68
+ }),
69
+ /*#__PURE__*/ jsx("button", {
70
+ type: "button",
71
+ className: cn('nodrag nopan inline-flex h-4 w-4 items-center justify-center rounded-full', 'text-foreground transition-opacity', canGoPrevious ? 'cursor-pointer opacity-100' : 'cursor-not-allowed opacity-40'),
72
+ disabled: !canGoPrevious,
73
+ "aria-label": "Previous loop iteration",
74
+ onClick: handlePrevious,
75
+ onPointerDown: stopCanvasControlEvent,
76
+ onMouseDown: stopCanvasControlEvent,
77
+ "data-testid": "loop-iteration-previous",
78
+ children: /*#__PURE__*/ jsx(CanvasIcon, {
79
+ icon: "chevron-left",
80
+ size: 12
81
+ })
82
+ }),
83
+ /*#__PURE__*/ jsxs("span", {
84
+ className: "min-w-8 select-none px-1 text-center text-[11px] font-semibold leading-4",
85
+ "data-testid": "loop-iteration-label",
86
+ children: [
87
+ visibleIndex,
88
+ " / ",
89
+ total
90
+ ]
91
+ }),
92
+ /*#__PURE__*/ jsx("button", {
93
+ type: "button",
94
+ className: cn('nodrag nopan inline-flex h-4 w-4 items-center justify-center rounded-full', 'text-foreground transition-opacity', canGoNext ? 'cursor-pointer opacity-100' : 'cursor-not-allowed opacity-40'),
95
+ disabled: !canGoNext,
96
+ "aria-label": "Next loop iteration",
97
+ onClick: handleNext,
98
+ onPointerDown: stopCanvasControlEvent,
99
+ onMouseDown: stopCanvasControlEvent,
100
+ "data-testid": "loop-iteration-next",
101
+ children: /*#__PURE__*/ jsx(CanvasIcon, {
102
+ icon: "chevron-right",
103
+ size: 12
104
+ })
105
+ })
106
+ ]
107
+ });
108
+ }
109
+ export { IterationNavigator };
@@ -47,6 +47,7 @@ const BaseNodeContainer_cjs_namespaceObject = require("../BaseNode/BaseNodeConta
47
47
  const BaseNodeMissingManifest_cjs_namespaceObject = require("../BaseNode/BaseNodeMissingManifest.cjs");
48
48
  const external_ButtonHandle_index_cjs_namespaceObject = require("../ButtonHandle/index.cjs");
49
49
  const external_Toolbar_index_cjs_namespaceObject = require("../Toolbar/index.cjs");
50
+ const external_IterationNavigator_cjs_namespaceObject = require("./IterationNavigator.cjs");
50
51
  const external_LoopNode_helpers_cjs_namespaceObject = require("./LoopNode.helpers.cjs");
51
52
  const DEFAULT_LOOP_ICON = 'repeat';
52
53
  const DEFAULT_LOOP_TITLE = 'Loop';
@@ -153,7 +154,7 @@ function resolveLoopHandleConfigurations(manifestHandleConfigurations, data) {
153
154
  return manifestHandleConfigurations ?? [];
154
155
  }
155
156
  function LoopNodeComponent(props) {
156
- const { id, type, data, selected = false, dragging = false, width = 0, height = 0, onAddFirstChild, onResize, toolbarConfig: toolbarConfigProp, adornments: adornmentsProp, executionStatusOverride, suggestionType: suggestionTypeProp } = props;
157
+ const { id, type, data, selected = false, dragging = false, width = 0, height = 0, onAddFirstChild, onResize, toolbarConfig: toolbarConfigProp, adornments: adornmentsProp, executionStatusOverride, suggestionType: suggestionTypeProp, iterationState: iterationStateProp } = props;
157
158
  const nodeTypeRegistry = (0, index_cjs_namespaceObject.useOptionalNodeTypeRegistry)();
158
159
  const [isHovered, setIsHovered] = (0, external_react_namespaceObject.useState)(false);
159
160
  const resolvedData = data ?? EMPTY_DATA;
@@ -285,7 +286,7 @@ function LoopNodeComponent(props) {
285
286
  "data-suggestion-type": suggestionType,
286
287
  "data-validation-status": validationState?.validationStatus,
287
288
  "aria-busy": resolvedData.loading || void 0,
288
- className: (0, apollo_wind_namespaceObject.cn)('group/loop-shell relative box-border flex h-full w-full flex-col overflow-visible rounded-[20px] border bg-transparent', 'transition-[border-color,box-shadow,opacity] shadow-(--canvas-node-shadow-rest)', 'border-border-subtle', (0, BaseNodeContainer_cjs_namespaceObject.getStatusBorder)(suggestionType ?? validationState?.validationStatus ?? executionStatus), isHovered && 'shadow-(--canvas-node-shadow-hover) border-border-hover', selected && 'outline outline-2 outline-foreground-accent-muted', isDropTarget && 'bg-surface-hover outline outline-2 outline-brand', 'drag' === interactionState && 'cursor-grabbing shadow-(--canvas-node-shadow-lifted)'),
289
+ className: (0, apollo_wind_namespaceObject.cn)('group/loop-shell relative box-border flex h-full w-full flex-col overflow-visible rounded-[20px] border bg-transparent', 'transition-[border-color,box-shadow,opacity] shadow-(--canvas-node-shadow-rest)', 'border-border', (0, BaseNodeContainer_cjs_namespaceObject.getStatusBorder)(suggestionType ?? validationState?.validationStatus ?? executionStatus), isHovered && 'shadow-(--canvas-node-shadow-hover) border-border-hover', selected && 'outline outline-2 outline-foreground-accent-muted', isDropTarget && 'bg-surface-hover outline outline-2 outline-brand', 'drag' === interactionState && 'cursor-grabbing shadow-(--canvas-node-shadow-lifted)'),
289
290
  style: {
290
291
  ...nodeSizeStyle,
291
292
  ...display.background ? {
@@ -311,7 +312,8 @@ function LoopNodeComponent(props) {
311
312
  title: displayTitle,
312
313
  icon: displayIcon,
313
314
  loading: isLoading,
314
- isParallel: isParallel
315
+ isParallel: isParallel,
316
+ iterationState: iterationStateProp
315
317
  }),
316
318
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(BodyFrame, {
317
319
  isEmpty: showEmptyStateButton,
@@ -347,7 +349,7 @@ function LoopNodeComponent(props) {
347
349
  });
348
350
  }
349
351
  const LoopNode = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(LoopNodeComponent);
350
- function Header({ title, icon, loading, isParallel }) {
352
+ function Header({ title, icon, loading, isParallel, iterationState }) {
351
353
  const titleContent = loading ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
352
354
  className: "h-5 w-28 animate-pulse rounded bg-(--canvas-background-overlay)"
353
355
  }) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
@@ -365,7 +367,7 @@ function Header({ title, icon, loading, isParallel }) {
365
367
  })
366
368
  }) : null;
367
369
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
368
- className: "flex shrink-0 cursor-grab items-center justify-between gap-2.5 px-3.5 pt-2.5 text-foreground active:cursor-grabbing",
370
+ className: (0, apollo_wind_namespaceObject.cn)('flex shrink-0 cursor-grab items-center justify-between gap-2.5 rounded-t-[18px]', '-mb-2.5 bg-surface-overlay px-3.5 pb-2.5 pt-2.5 text-foreground', 'active:cursor-grabbing'),
369
371
  "data-testid": "loop-node-header",
370
372
  children: [
371
373
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
@@ -375,18 +377,26 @@ function Header({ title, icon, loading, isParallel }) {
375
377
  titleContent
376
378
  ]
377
379
  }),
378
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
379
- className: "flex shrink-0 items-center gap-1 rounded-full border border-border-subtle bg-transparent px-2.5 py-0.5 text-[11px] font-semibold leading-4 text-foreground",
380
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
381
+ className: "flex shrink-0 items-center gap-2",
380
382
  children: [
381
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
382
- className: (0, apollo_wind_namespaceObject.cn)('flex shrink-0', isParallel && 'rotate-90'),
383
- "aria-hidden": true,
384
- children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icon_registry_cjs_namespaceObject.CanvasIcon, {
385
- icon: "align-justify",
386
- size: 11
387
- })
388
- }),
389
- isParallel ? 'Parallel' : 'Sequential'
383
+ iterationState ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_IterationNavigator_cjs_namespaceObject.IterationNavigator, {
384
+ iterationState: iterationState
385
+ }) : null,
386
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
387
+ className: "flex h-6 shrink-0 items-center gap-1 rounded-full border border-border bg-surface px-2.5 text-[11px] font-semibold leading-4 text-foreground shadow-sm",
388
+ children: [
389
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
390
+ className: (0, apollo_wind_namespaceObject.cn)('flex shrink-0', isParallel && 'rotate-90'),
391
+ "aria-hidden": true,
392
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icon_registry_cjs_namespaceObject.CanvasIcon, {
393
+ icon: "align-justify",
394
+ size: 11
395
+ })
396
+ }),
397
+ isParallel ? 'Parallel' : 'Sequential'
398
+ ]
399
+ })
390
400
  ]
391
401
  })
392
402
  ]
@@ -408,7 +418,7 @@ function BodyFrame({ isEmpty, isLoading }) {
408
418
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
409
419
  "data-testid": "loop-body-frame",
410
420
  "data-empty": isEmpty ? 'true' : 'false',
411
- className: (0, apollo_wind_namespaceObject.cn)('relative m-2.5 flex flex-1 rounded-xl border-[1.5px] border-dashed border-border-subtle bg-transparent', 'pointer-events-none'),
421
+ className: (0, apollo_wind_namespaceObject.cn)('relative m-2.5 flex flex-1 rounded-xl border-[1.5px] border-dashed border-border bg-transparent', 'shadow-[0_0_0_10px_var(--surface-overlay)]', 'pointer-events-none'),
412
422
  children: isLoading ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
413
423
  className: "m-6 h-14 w-full animate-pulse rounded-[18px] bg-(--canvas-background-overlay)"
414
424
  }) : null
@@ -1 +1 @@
1
- {"version":3,"file":"LoopNode.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/LoopNode/LoopNode.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAmItD,iBAAS,iBAAiB,CAAC,KAAK,EAAE,aAAa,2CA2O9C;AAED,eAAO,MAAM,QAAQ,+DAA0B,CAAC"}
1
+ {"version":3,"file":"LoopNode.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/LoopNode/LoopNode.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAmI1E,iBAAS,iBAAiB,CAAC,KAAK,EAAE,aAAa,2CAkP9C;AAED,eAAO,MAAM,QAAQ,+DAA0B,CAAC"}
@@ -19,6 +19,7 @@ import { getStatusBorder } from "../BaseNode/BaseNodeContainer.js";
19
19
  import { MissingManifestNode } from "../BaseNode/BaseNodeMissingManifest.js";
20
20
  import { ButtonHandles } from "../ButtonHandle/index.js";
21
21
  import { NodeToolbar } from "../Toolbar/index.js";
22
+ import { IterationNavigator } from "./IterationNavigator.js";
22
23
  import { resolveContainerHandleGroups } from "./LoopNode.helpers.js";
23
24
  const DEFAULT_LOOP_ICON = 'repeat';
24
25
  const DEFAULT_LOOP_TITLE = 'Loop';
@@ -125,7 +126,7 @@ function resolveLoopHandleConfigurations(manifestHandleConfigurations, data) {
125
126
  return manifestHandleConfigurations ?? [];
126
127
  }
127
128
  function LoopNodeComponent(props) {
128
- const { id, type, data, selected = false, dragging = false, width = 0, height = 0, onAddFirstChild, onResize, toolbarConfig: toolbarConfigProp, adornments: adornmentsProp, executionStatusOverride, suggestionType: suggestionTypeProp } = props;
129
+ const { id, type, data, selected = false, dragging = false, width = 0, height = 0, onAddFirstChild, onResize, toolbarConfig: toolbarConfigProp, adornments: adornmentsProp, executionStatusOverride, suggestionType: suggestionTypeProp, iterationState: iterationStateProp } = props;
129
130
  const nodeTypeRegistry = useOptionalNodeTypeRegistry();
130
131
  const [isHovered, setIsHovered] = useState(false);
131
132
  const resolvedData = data ?? EMPTY_DATA;
@@ -257,7 +258,7 @@ function LoopNodeComponent(props) {
257
258
  "data-suggestion-type": suggestionType,
258
259
  "data-validation-status": validationState?.validationStatus,
259
260
  "aria-busy": resolvedData.loading || void 0,
260
- className: cn('group/loop-shell relative box-border flex h-full w-full flex-col overflow-visible rounded-[20px] border bg-transparent', 'transition-[border-color,box-shadow,opacity] shadow-(--canvas-node-shadow-rest)', 'border-border-subtle', getStatusBorder(suggestionType ?? validationState?.validationStatus ?? executionStatus), isHovered && 'shadow-(--canvas-node-shadow-hover) border-border-hover', selected && 'outline outline-2 outline-foreground-accent-muted', isDropTarget && 'bg-surface-hover outline outline-2 outline-brand', 'drag' === interactionState && 'cursor-grabbing shadow-(--canvas-node-shadow-lifted)'),
261
+ className: cn('group/loop-shell relative box-border flex h-full w-full flex-col overflow-visible rounded-[20px] border bg-transparent', 'transition-[border-color,box-shadow,opacity] shadow-(--canvas-node-shadow-rest)', 'border-border', getStatusBorder(suggestionType ?? validationState?.validationStatus ?? executionStatus), isHovered && 'shadow-(--canvas-node-shadow-hover) border-border-hover', selected && 'outline outline-2 outline-foreground-accent-muted', isDropTarget && 'bg-surface-hover outline outline-2 outline-brand', 'drag' === interactionState && 'cursor-grabbing shadow-(--canvas-node-shadow-lifted)'),
261
262
  style: {
262
263
  ...nodeSizeStyle,
263
264
  ...display.background ? {
@@ -283,7 +284,8 @@ function LoopNodeComponent(props) {
283
284
  title: displayTitle,
284
285
  icon: displayIcon,
285
286
  loading: isLoading,
286
- isParallel: isParallel
287
+ isParallel: isParallel,
288
+ iterationState: iterationStateProp
287
289
  }),
288
290
  /*#__PURE__*/ jsx(BodyFrame, {
289
291
  isEmpty: showEmptyStateButton,
@@ -319,7 +321,7 @@ function LoopNodeComponent(props) {
319
321
  });
320
322
  }
321
323
  const LoopNode = /*#__PURE__*/ memo(LoopNodeComponent);
322
- function Header({ title, icon, loading, isParallel }) {
324
+ function Header({ title, icon, loading, isParallel, iterationState }) {
323
325
  const titleContent = loading ? /*#__PURE__*/ jsx("div", {
324
326
  className: "h-5 w-28 animate-pulse rounded bg-(--canvas-background-overlay)"
325
327
  }) : /*#__PURE__*/ jsx("span", {
@@ -337,7 +339,7 @@ function Header({ title, icon, loading, isParallel }) {
337
339
  })
338
340
  }) : null;
339
341
  return /*#__PURE__*/ jsxs("div", {
340
- className: "flex shrink-0 cursor-grab items-center justify-between gap-2.5 px-3.5 pt-2.5 text-foreground active:cursor-grabbing",
342
+ className: cn('flex shrink-0 cursor-grab items-center justify-between gap-2.5 rounded-t-[18px]', '-mb-2.5 bg-surface-overlay px-3.5 pb-2.5 pt-2.5 text-foreground', 'active:cursor-grabbing'),
341
343
  "data-testid": "loop-node-header",
342
344
  children: [
343
345
  /*#__PURE__*/ jsxs("div", {
@@ -347,18 +349,26 @@ function Header({ title, icon, loading, isParallel }) {
347
349
  titleContent
348
350
  ]
349
351
  }),
350
- /*#__PURE__*/ jsxs("span", {
351
- className: "flex shrink-0 items-center gap-1 rounded-full border border-border-subtle bg-transparent px-2.5 py-0.5 text-[11px] font-semibold leading-4 text-foreground",
352
+ /*#__PURE__*/ jsxs("div", {
353
+ className: "flex shrink-0 items-center gap-2",
352
354
  children: [
353
- /*#__PURE__*/ jsx("span", {
354
- className: cn('flex shrink-0', isParallel && 'rotate-90'),
355
- "aria-hidden": true,
356
- children: /*#__PURE__*/ jsx(CanvasIcon, {
357
- icon: "align-justify",
358
- size: 11
359
- })
360
- }),
361
- isParallel ? 'Parallel' : 'Sequential'
355
+ iterationState ? /*#__PURE__*/ jsx(IterationNavigator, {
356
+ iterationState: iterationState
357
+ }) : null,
358
+ /*#__PURE__*/ jsxs("span", {
359
+ className: "flex h-6 shrink-0 items-center gap-1 rounded-full border border-border bg-surface px-2.5 text-[11px] font-semibold leading-4 text-foreground shadow-sm",
360
+ children: [
361
+ /*#__PURE__*/ jsx("span", {
362
+ className: cn('flex shrink-0', isParallel && 'rotate-90'),
363
+ "aria-hidden": true,
364
+ children: /*#__PURE__*/ jsx(CanvasIcon, {
365
+ icon: "align-justify",
366
+ size: 11
367
+ })
368
+ }),
369
+ isParallel ? 'Parallel' : 'Sequential'
370
+ ]
371
+ })
362
372
  ]
363
373
  })
364
374
  ]
@@ -380,7 +390,7 @@ function BodyFrame({ isEmpty, isLoading }) {
380
390
  return /*#__PURE__*/ jsx("div", {
381
391
  "data-testid": "loop-body-frame",
382
392
  "data-empty": isEmpty ? 'true' : 'false',
383
- className: cn('relative m-2.5 flex flex-1 rounded-xl border-[1.5px] border-dashed border-border-subtle bg-transparent', 'pointer-events-none'),
393
+ className: cn('relative m-2.5 flex flex-1 rounded-xl border-[1.5px] border-dashed border-border bg-transparent', 'shadow-[0_0_0_10px_var(--surface-overlay)]', 'pointer-events-none'),
384
394
  children: isLoading ? /*#__PURE__*/ jsx("div", {
385
395
  className: "m-6 h-14 w-full animate-pulse rounded-[18px] bg-(--canvas-background-overlay)"
386
396
  }) : null
@@ -9,11 +9,19 @@ export interface LoopNodeResizeSize {
9
9
  width: number;
10
10
  height: number;
11
11
  }
12
+ export interface LoopIterationState {
13
+ activeIndex: number;
14
+ total: number;
15
+ onActiveIndexChange?: (nextIndex: number) => void;
16
+ disabled?: boolean;
17
+ ariaLabel?: string;
18
+ }
12
19
  export interface LoopNodeConfig {
13
20
  toolbarConfig?: NodeToolbarConfig | null;
14
21
  adornments?: NodeAdornments;
15
22
  executionStatusOverride?: ElementStatusValues;
16
23
  suggestionType?: SuggestionType;
24
+ iterationState?: LoopIterationState;
17
25
  }
18
26
  export interface LoopNodeProps extends NodeProps<Node<LoopNodeData>>, LoopNodeConfig {
19
27
  onAddFirstChild?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"LoopNode.types.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/LoopNode/LoopNode.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC;AAExC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,uBAAuB,CAAC,EAAE,mBAAmB,CAAC;IAC9C,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc;IAClF,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C"}
1
+ {"version":3,"file":"LoopNode.types.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/LoopNode/LoopNode.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC;AAExC,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,uBAAuB,CAAC,EAAE,mBAAmB,CAAC;IAC9C,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc;IAClF,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C"}