@uipath/apollo-react 3.55.1 → 3.56.0-pr364.24cd059

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.
@@ -69,7 +69,7 @@ const AddNodePanel_AddNodePanel = /*#__PURE__*/ (0, external_react_namespaceObje
69
69
  onNodeSelect
70
70
  ]);
71
71
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_Toolbox_index_cjs_namespaceObject.Toolbox, {
72
- title: title ?? 'Add Node',
72
+ title: title ?? 'Add node',
73
73
  initialItems: nodeListOptions,
74
74
  loading: loading,
75
75
  onItemSelect: handleNodeListItemSelect,
@@ -41,7 +41,7 @@ const AddNodePanel_AddNodePanel = /*#__PURE__*/ memo(function({ onNodeSelect, on
41
41
  onNodeSelect
42
42
  ]);
43
43
  return /*#__PURE__*/ jsx(Toolbox, {
44
- title: title ?? 'Add Node',
44
+ title: title ?? 'Add node',
45
45
  initialItems: nodeListOptions,
46
46
  loading: loading,
47
47
  onItemSelect: handleNodeListItemSelect,
@@ -193,6 +193,7 @@ const StageNodeComponent = (props)=>{
193
193
  setIsStageTitleEditing(false);
194
194
  if (onStageTitleChange) onStageTitleChange(label);
195
195
  }
196
+ if ('Escape' !== e.key) e.stopPropagation();
196
197
  }, [
197
198
  onStageTitleChange,
198
199
  label
@@ -1 +1 @@
1
- {"version":3,"file":"StageNode.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/StageNode/StageNode.tsx"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA8oBxD,eAAO,MAAM,SAAS,8CApoBa,cAAc,6CAooBA,CAAC"}
1
+ {"version":3,"file":"StageNode.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/StageNode/StageNode.tsx"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAmpBxD,eAAO,MAAM,SAAS,8CAzoBa,cAAc,6CAyoBA,CAAC"}
@@ -165,6 +165,7 @@ const StageNodeComponent = (props)=>{
165
165
  setIsStageTitleEditing(false);
166
166
  if (onStageTitleChange) onStageTitleChange(label);
167
167
  }
168
+ if ('Escape' !== e.key) e.stopPropagation();
168
169
  }, [
169
170
  onStageTitleChange,
170
171
  label
@@ -24,7 +24,8 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
- ListView: ()=>ListView_ListView
27
+ ListView: ()=>ListView_ListView,
28
+ buildRenderedItems: ()=>buildRenderedItems
28
29
  });
29
30
  const jsx_runtime_namespaceObject = require("react/jsx-runtime");
30
31
  const apollo_core_namespaceObject = require("@uipath/apollo-core");
@@ -35,8 +36,37 @@ const components_index_cjs_namespaceObject = require("../../../material/componen
35
36
  const external_react_namespaceObject = require("react");
36
37
  const CanvasThemeContext_cjs_namespaceObject = require("../BaseCanvas/CanvasThemeContext.cjs");
37
38
  const external_ListView_styles_cjs_namespaceObject = require("./ListView.styles.cjs");
39
+ function buildRenderedItems(items, enableSections) {
40
+ const result = [];
41
+ if (0 === items.length) return result;
42
+ if (!enableSections) {
43
+ for (const item of items)result.push({
44
+ type: 'item',
45
+ item
46
+ });
47
+ return result;
48
+ }
49
+ const [itemsWithSection, itemsWithoutSection] = (0, external_utils_index_cjs_namespaceObject.partition)(items, (item)=>!!item.section);
50
+ for (const item of itemsWithoutSection)result.push({
51
+ type: 'item',
52
+ item
53
+ });
54
+ if (0 === itemsWithSection.length) return result;
55
+ const sections = Array.from(new Set(itemsWithSection.map((item)=>item.section)));
56
+ for (const section of sections){
57
+ result.push({
58
+ type: 'section',
59
+ sectionName: section
60
+ });
61
+ for (const item of itemsWithSection.filter((item)=>item.section === section))result.push({
62
+ type: 'item',
63
+ item
64
+ });
65
+ }
66
+ return result;
67
+ }
38
68
  const IconContainerMemoized = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(external_ListView_styles_cjs_namespaceObject.IconContainer);
39
- const ListViewRow = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(({ index, style, ariaAttributes, renderedItems, isLoading, isDarkMode, onItemClick, onItemHover })=>{
69
+ const ListViewRow = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(({ index, style, ariaAttributes, renderedItems, activeIndex, isLoading, isDarkMode, onItemClick, onItemHover })=>{
40
70
  const renderItem = renderedItems[index];
41
71
  const buttonStyle = (0, external_react_namespaceObject.useMemo)(()=>({
42
72
  ...style,
@@ -74,12 +104,17 @@ const ListViewRow = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(({ in
74
104
  });
75
105
  const item = renderItem.item;
76
106
  const bgColor = isDarkMode ? item.colorDark ?? item.color : item.color;
107
+ const isActive = index === activeIndex;
77
108
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_ListView_styles_cjs_namespaceObject.ListItemButton, {
78
109
  ...ariaAttributes,
110
+ tabIndex: -1,
111
+ id: `toolbox-item-${item.id}`,
112
+ role: "option",
113
+ "aria-selected": isActive,
79
114
  style: buttonStyle,
80
115
  onClick: handleButtonClick,
81
116
  onHoverStart: handleButtonHover,
82
- className: isLoading ? 'loading' : '',
117
+ className: `${isLoading ? 'loading' : ''} ${isActive ? 'active' : ''}`,
83
118
  disabled: isLoading,
84
119
  children: [
85
120
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(IconContainerMemoized, {
@@ -134,48 +169,27 @@ const ListViewRow = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(({ in
134
169
  ]
135
170
  });
136
171
  });
137
- const ListView_ListView = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(function({ items, onItemClick, onItemHover, emptyStateMessage = 'No items found', emptyStateIcon = 'search_off', isLoading = false, enableSections = true }) {
172
+ const ListViewInner = /*#__PURE__*/ (0, external_react_namespaceObject.forwardRef)(function({ items, activeIndex = -1, listRef, onItemClick, onItemHover, emptyStateMessage = 'No items found', emptyStateIcon = 'search_off', isLoading = false, enableSections = true }, ref) {
138
173
  const { isDarkMode } = (0, CanvasThemeContext_cjs_namespaceObject.useCanvasTheme)();
139
- const renderedItems = (0, external_react_namespaceObject.useMemo)(()=>{
140
- const result = [];
141
- if (0 === items.length) return result;
142
- if (!enableSections) {
143
- for (const item of items)result.push({
144
- type: 'item',
145
- item
146
- });
147
- return result;
148
- }
149
- const [itemsWithSection, itemsWithoutSection] = (0, external_utils_index_cjs_namespaceObject.partition)(items, (item)=>!!item.section);
150
- for (const item of itemsWithoutSection)result.push({
151
- type: 'item',
152
- item
153
- });
154
- if (0 === itemsWithSection.length) return result;
155
- const sections = Array.from(new Set(itemsWithSection.map((item)=>item.section)));
156
- for (const section of sections){
157
- result.push({
158
- type: 'section',
159
- sectionName: section
160
- });
161
- for (const item of itemsWithSection.filter((item)=>item.section === section))result.push({
162
- type: 'item',
163
- item
164
- });
165
- }
166
- return result;
167
- }, [
174
+ const renderedItems = (0, external_react_namespaceObject.useMemo)(()=>buildRenderedItems(items, enableSections), [
168
175
  items,
169
176
  enableSections
170
177
  ]);
178
+ (0, external_react_namespaceObject.useImperativeHandle)(ref, ()=>({
179
+ renderedItems
180
+ }), [
181
+ renderedItems
182
+ ]);
171
183
  const rowProps = (0, external_react_namespaceObject.useMemo)(()=>({
172
184
  renderedItems,
185
+ activeIndex,
173
186
  isLoading,
174
187
  isDarkMode,
175
188
  onItemClick,
176
189
  onItemHover
177
190
  }), [
178
191
  renderedItems,
192
+ activeIndex,
179
193
  isLoading,
180
194
  isDarkMode,
181
195
  onItemClick,
@@ -215,6 +229,9 @@ const ListView_ListView = /*#__PURE__*/ (0, external_react_namespaceObject.memo)
215
229
  ]
216
230
  });
217
231
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_ListView_styles_cjs_namespaceObject.StyledList, {
232
+ id: "toolbox-listbox",
233
+ role: "listbox",
234
+ listRef: listRef,
218
235
  rowProps: rowProps,
219
236
  rowComponent: ListViewRow,
220
237
  rowCount: renderedItems.length,
@@ -222,9 +239,12 @@ const ListView_ListView = /*#__PURE__*/ (0, external_react_namespaceObject.memo)
222
239
  overscanCount: 20
223
240
  });
224
241
  });
242
+ const ListView_ListView = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(ListViewInner);
225
243
  exports.ListView = __webpack_exports__.ListView;
244
+ exports.buildRenderedItems = __webpack_exports__.buildRenderedItems;
226
245
  for(var __rspack_i in __webpack_exports__)if (-1 === [
227
- "ListView"
246
+ "ListView",
247
+ "buildRenderedItems"
228
248
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
229
249
  Object.defineProperty(exports, '__esModule', {
230
250
  value: true
@@ -1,3 +1,4 @@
1
+ import type { ListImperativeAPI } from 'react-window';
1
2
  export interface ListItemIcon {
2
3
  name?: string;
3
4
  url?: string;
@@ -14,22 +15,29 @@ export type ListItem<T = any> = {
14
15
  colorDark?: string;
15
16
  children?: ListItem<T>[] | ((id: string, name: string) => Promise<ListItem<T>[]>);
16
17
  };
17
- type RenderItem<T extends ListItem> = {
18
+ export type RenderItem<T extends ListItem> = {
18
19
  type: 'section';
19
20
  sectionName: string;
20
21
  } | {
21
22
  type: 'item';
22
23
  item: T;
23
24
  };
25
+ export declare function buildRenderedItems<T extends ListItem>(items: T[], enableSections: boolean): RenderItem<T>[];
24
26
  export interface ListViewRowProps<T extends ListItem> {
25
27
  renderedItems: RenderItem<T>[];
28
+ activeIndex: number;
26
29
  isLoading?: boolean;
27
30
  isDarkMode?: boolean;
28
31
  onItemClick: (item: T) => void;
29
32
  onItemHover?: (item: T) => void;
30
33
  }
34
+ export interface ListViewHandle<T extends ListItem = ListItem> {
35
+ renderedItems: RenderItem<T>[];
36
+ }
31
37
  interface ListViewProps<T extends ListItem> {
32
38
  items: T[];
39
+ activeIndex?: number;
40
+ listRef?: React.RefObject<ListImperativeAPI | null>;
33
41
  onItemClick: (item: T) => void;
34
42
  onItemHover?: (item: T) => void;
35
43
  emptyStateMessage?: string;
@@ -37,6 +45,8 @@ interface ListViewProps<T extends ListItem> {
37
45
  isLoading?: boolean;
38
46
  enableSections?: boolean;
39
47
  }
40
- export declare const ListView: import("react").MemoExoticComponent<(<T extends ListItem>({ items, onItemClick, onItemHover, emptyStateMessage, emptyStateIcon, isLoading, enableSections, }: ListViewProps<T>) => import("react/jsx-runtime").JSX.Element)>;
48
+ export declare const ListView: <T extends ListItem>(props: ListViewProps<T> & {
49
+ ref?: React.Ref<ListViewHandle<T>>;
50
+ }) => React.ReactElement | null;
41
51
  export {};
42
52
  //# sourceMappingURL=ListView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/ListView.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,YAAY;IAI3B,IAAI,CAAC,EAAE,MAAM,CAAC;IAId,GAAG,CAAC,EAAE,MAAM,CAAC;IAIb,SAAS,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CACjC;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACnF,CAAC;AAEF,KAAK,UAAU,CAAC,CAAC,SAAS,QAAQ,IAC9B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,QAAQ;IAClD,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;CACjC;AAyGD,UAAU,aAAa,CAAC,CAAC,SAAS,QAAQ;IACxC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,QAAQ,wCAA0B,CAAC,SAAS,QAAQ,sGAQ9D,aAAa,CAAC,CAAC,CAAC,8CAkFjB,CAAC"}
1
+ {"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/ListView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAqB,MAAM,cAAc,CAAC;AAIzE,MAAM,WAAW,YAAY;IAI3B,IAAI,CAAC,EAAE,MAAM,CAAC;IAId,GAAG,CAAC,EAAE,MAAM,CAAC;IAIb,SAAS,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CACjC;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACnF,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,QAAQ,IACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAE9B,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,QAAQ,EACnD,KAAK,EAAE,CAAC,EAAE,EACV,cAAc,EAAE,OAAO,GACtB,UAAU,CAAC,CAAC,CAAC,EAAE,CAqCjB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,QAAQ;IAClD,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;CACjC;AAgHD,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ;IAC3D,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;CAChC;AAED,UAAU,aAAa,CAAC,CAAC,SAAS,QAAQ;IACxC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACpD,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAsED,eAAO,MAAM,QAAQ,EAA0B,CAAC,CAAC,SAAS,QAAQ,EAChE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;CAAE,KAC7D,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC"}
@@ -4,11 +4,40 @@ import { Column } from "../../layouts/index.js";
4
4
  import { NodeIcon, partition } from "../../utils/index.js";
5
5
  import { ApSkeleton, ApTypography } from "../../../material/index.js";
6
6
  import { ApIcon, ApTooltip } from "../../../material/components/index.js";
7
- import { memo, useCallback, useMemo } from "react";
7
+ import { forwardRef, memo, useCallback, useImperativeHandle, useMemo } from "react";
8
8
  import { useCanvasTheme } from "../BaseCanvas/CanvasThemeContext.js";
9
9
  import { IconContainer, ListItemButton, SectionHeader, StyledList } from "./ListView.styles.js";
10
+ function buildRenderedItems(items, enableSections) {
11
+ const result = [];
12
+ if (0 === items.length) return result;
13
+ if (!enableSections) {
14
+ for (const item of items)result.push({
15
+ type: 'item',
16
+ item
17
+ });
18
+ return result;
19
+ }
20
+ const [itemsWithSection, itemsWithoutSection] = partition(items, (item)=>!!item.section);
21
+ for (const item of itemsWithoutSection)result.push({
22
+ type: 'item',
23
+ item
24
+ });
25
+ if (0 === itemsWithSection.length) return result;
26
+ const sections = Array.from(new Set(itemsWithSection.map((item)=>item.section)));
27
+ for (const section of sections){
28
+ result.push({
29
+ type: 'section',
30
+ sectionName: section
31
+ });
32
+ for (const item of itemsWithSection.filter((item)=>item.section === section))result.push({
33
+ type: 'item',
34
+ item
35
+ });
36
+ }
37
+ return result;
38
+ }
10
39
  const IconContainerMemoized = /*#__PURE__*/ memo(IconContainer);
11
- const ListViewRow = /*#__PURE__*/ memo(({ index, style, ariaAttributes, renderedItems, isLoading, isDarkMode, onItemClick, onItemHover })=>{
40
+ const ListViewRow = /*#__PURE__*/ memo(({ index, style, ariaAttributes, renderedItems, activeIndex, isLoading, isDarkMode, onItemClick, onItemHover })=>{
12
41
  const renderItem = renderedItems[index];
13
42
  const buttonStyle = useMemo(()=>({
14
43
  ...style,
@@ -46,12 +75,17 @@ const ListViewRow = /*#__PURE__*/ memo(({ index, style, ariaAttributes, rendered
46
75
  });
47
76
  const item = renderItem.item;
48
77
  const bgColor = isDarkMode ? item.colorDark ?? item.color : item.color;
78
+ const isActive = index === activeIndex;
49
79
  return /*#__PURE__*/ jsxs(ListItemButton, {
50
80
  ...ariaAttributes,
81
+ tabIndex: -1,
82
+ id: `toolbox-item-${item.id}`,
83
+ role: "option",
84
+ "aria-selected": isActive,
51
85
  style: buttonStyle,
52
86
  onClick: handleButtonClick,
53
87
  onHoverStart: handleButtonHover,
54
- className: isLoading ? 'loading' : '',
88
+ className: `${isLoading ? 'loading' : ''} ${isActive ? 'active' : ''}`,
55
89
  disabled: isLoading,
56
90
  children: [
57
91
  /*#__PURE__*/ jsxs(IconContainerMemoized, {
@@ -106,48 +140,27 @@ const ListViewRow = /*#__PURE__*/ memo(({ index, style, ariaAttributes, rendered
106
140
  ]
107
141
  });
108
142
  });
109
- const ListView_ListView = /*#__PURE__*/ memo(function({ items, onItemClick, onItemHover, emptyStateMessage = 'No items found', emptyStateIcon = 'search_off', isLoading = false, enableSections = true }) {
143
+ const ListViewInner = /*#__PURE__*/ forwardRef(function({ items, activeIndex = -1, listRef, onItemClick, onItemHover, emptyStateMessage = 'No items found', emptyStateIcon = 'search_off', isLoading = false, enableSections = true }, ref) {
110
144
  const { isDarkMode } = useCanvasTheme();
111
- const renderedItems = useMemo(()=>{
112
- const result = [];
113
- if (0 === items.length) return result;
114
- if (!enableSections) {
115
- for (const item of items)result.push({
116
- type: 'item',
117
- item
118
- });
119
- return result;
120
- }
121
- const [itemsWithSection, itemsWithoutSection] = partition(items, (item)=>!!item.section);
122
- for (const item of itemsWithoutSection)result.push({
123
- type: 'item',
124
- item
125
- });
126
- if (0 === itemsWithSection.length) return result;
127
- const sections = Array.from(new Set(itemsWithSection.map((item)=>item.section)));
128
- for (const section of sections){
129
- result.push({
130
- type: 'section',
131
- sectionName: section
132
- });
133
- for (const item of itemsWithSection.filter((item)=>item.section === section))result.push({
134
- type: 'item',
135
- item
136
- });
137
- }
138
- return result;
139
- }, [
145
+ const renderedItems = useMemo(()=>buildRenderedItems(items, enableSections), [
140
146
  items,
141
147
  enableSections
142
148
  ]);
149
+ useImperativeHandle(ref, ()=>({
150
+ renderedItems
151
+ }), [
152
+ renderedItems
153
+ ]);
143
154
  const rowProps = useMemo(()=>({
144
155
  renderedItems,
156
+ activeIndex,
145
157
  isLoading,
146
158
  isDarkMode,
147
159
  onItemClick,
148
160
  onItemHover
149
161
  }), [
150
162
  renderedItems,
163
+ activeIndex,
151
164
  isLoading,
152
165
  isDarkMode,
153
166
  onItemClick,
@@ -187,6 +200,9 @@ const ListView_ListView = /*#__PURE__*/ memo(function({ items, onItemClick, onIt
187
200
  ]
188
201
  });
189
202
  return /*#__PURE__*/ jsx(StyledList, {
203
+ id: "toolbox-listbox",
204
+ role: "listbox",
205
+ listRef: listRef,
190
206
  rowProps: rowProps,
191
207
  rowComponent: ListViewRow,
192
208
  rowCount: renderedItems.length,
@@ -194,4 +210,5 @@ const ListView_ListView = /*#__PURE__*/ memo(function({ items, onItemClick, onIt
194
210
  overscanCount: 20
195
211
  });
196
212
  });
197
- export { ListView_ListView as ListView };
213
+ const ListView_ListView = /*#__PURE__*/ memo(ListViewInner);
214
+ export { ListView_ListView as ListView, buildRenderedItems };
@@ -68,9 +68,15 @@ const ListItemButton = styled_default()(react_namespaceObject.motion.button)`
68
68
  width: 100%;
69
69
  transition: all 0.15s ease;
70
70
 
71
- &:hover {
71
+ &:hover,
72
+ &.active {
72
73
  background: var(--uix-canvas-background-hover);
73
74
  }
75
+
76
+ &.active {
77
+ outline: 1px solid var(--uix-canvas-primary);
78
+ outline-offset: -1px;
79
+ }
74
80
  `;
75
81
  const IconContainer = styled_default().div`
76
82
  width: 32px;
@@ -1 +1 @@
1
- {"version":3,"file":"ListView.styles.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/ListView.styles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,eAAO,MAAM,aAAa;;;yGAazB,CAAC;AAEF,eAAO,MAAM,cAAc;;UAe1B,CAAC;AAEF,eAAO,MAAM,aAAa;;;;cAA0B,MAAM;yGAazD,CAAC;AAEF,eAAO,MAAM,UAAU,EAkClB,OAAO,IAAI,CAAC"}
1
+ {"version":3,"file":"ListView.styles.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/ListView.styles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,eAAO,MAAM,aAAa;;;yGAazB,CAAC;AAEF,eAAO,MAAM,cAAc;;UAqB1B,CAAC;AAEF,eAAO,MAAM,aAAa;;;;cAA0B,MAAM;yGAazD,CAAC;AAEF,eAAO,MAAM,UAAU,EAkClB,OAAO,IAAI,CAAC"}
@@ -27,9 +27,15 @@ const ListItemButton = styled(motion.button)`
27
27
  width: 100%;
28
28
  transition: all 0.15s ease;
29
29
 
30
- &:hover {
30
+ &:hover,
31
+ &.active {
31
32
  background: var(--uix-canvas-background-hover);
32
33
  }
34
+
35
+ &.active {
36
+ outline: 1px solid var(--uix-canvas-primary);
37
+ outline-offset: -1px;
38
+ }
33
39
  `;
34
40
  const IconContainer = styled.div`
35
41
  width: 32px;
@@ -31,11 +31,14 @@ const index_cjs_namespaceObject = require("../../utils/index.cjs");
31
31
  const components_index_cjs_namespaceObject = require("../../../material/components/index.cjs");
32
32
  const external_react_namespaceObject = require("react");
33
33
  const external_SearchBox_styles_cjs_namespaceObject = require("./SearchBox.styles.cjs");
34
- const SearchBox_SearchBox = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(function({ value, onChange, clear, placeholder = 'Search...' }) {
35
- const inputRef = (0, external_react_namespaceObject.useRef)(null);
34
+ const SearchBox_SearchBox = /*#__PURE__*/ (0, external_react_namespaceObject.memo)(function({ value, onChange, clear, placeholder = 'Search...', inputRef: externalInputRef, onNavigationKeyDown, activeDescendantId }) {
35
+ const internalRef = (0, external_react_namespaceObject.useRef)(null);
36
+ const inputRef = externalInputRef ?? internalRef;
36
37
  (0, external_react_namespaceObject.useEffect)(()=>{
37
38
  inputRef.current?.focus();
38
- }, []);
39
+ }, [
40
+ inputRef
41
+ ]);
39
42
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_SearchBox_styles_cjs_namespaceObject.StyledSearchForm, {
40
43
  autoComplete: "off",
41
44
  className: "searchbox-form",
@@ -56,10 +59,15 @@ const SearchBox_SearchBox = /*#__PURE__*/ (0, external_react_namespaceObject.mem
56
59
  ref: inputRef,
57
60
  autoComplete: "off",
58
61
  type: "text",
62
+ role: "combobox",
63
+ "aria-controls": "toolbox-listbox",
64
+ "aria-expanded": true,
59
65
  className: "searchbox-input",
60
66
  placeholder: placeholder,
61
67
  value: value,
62
- onChange: (e)=>onChange(e.target.value)
68
+ onChange: (e)=>onChange(e.target.value),
69
+ onKeyDown: onNavigationKeyDown,
70
+ "aria-activedescendant": activeDescendantId
63
71
  }),
64
72
  value && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("button", {
65
73
  type: "button",
@@ -3,6 +3,9 @@ interface SearchBoxProps {
3
3
  onChange: (value: string) => void;
4
4
  clear: () => void;
5
5
  placeholder?: string;
6
+ inputRef?: React.RefObject<HTMLInputElement | null>;
7
+ onNavigationKeyDown?: (e: React.KeyboardEvent) => void;
8
+ activeDescendantId?: string;
6
9
  }
7
10
  export declare const SearchBox: import("react").NamedExoticComponent<SearchBoxProps>;
8
11
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"SearchBox.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/SearchBox.tsx"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,sDAuCpB,CAAC"}
1
+ {"version":3,"file":"SearchBox.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/SearchBox.tsx"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IACvD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,SAAS,sDAgDpB,CAAC"}
@@ -3,11 +3,14 @@ import { cx } from "../../utils/index.js";
3
3
  import { ApIcon } from "../../../material/components/index.js";
4
4
  import { memo, useEffect, useRef } from "react";
5
5
  import { StyledSearchForm } from "./SearchBox.styles.js";
6
- const SearchBox_SearchBox = /*#__PURE__*/ memo(function({ value, onChange, clear, placeholder = 'Search...' }) {
7
- const inputRef = useRef(null);
6
+ const SearchBox_SearchBox = /*#__PURE__*/ memo(function({ value, onChange, clear, placeholder = 'Search...', inputRef: externalInputRef, onNavigationKeyDown, activeDescendantId }) {
7
+ const internalRef = useRef(null);
8
+ const inputRef = externalInputRef ?? internalRef;
8
9
  useEffect(()=>{
9
10
  inputRef.current?.focus();
10
- }, []);
11
+ }, [
12
+ inputRef
13
+ ]);
11
14
  return /*#__PURE__*/ jsx(StyledSearchForm, {
12
15
  autoComplete: "off",
13
16
  className: "searchbox-form",
@@ -28,10 +31,15 @@ const SearchBox_SearchBox = /*#__PURE__*/ memo(function({ value, onChange, clear
28
31
  ref: inputRef,
29
32
  autoComplete: "off",
30
33
  type: "text",
34
+ role: "combobox",
35
+ "aria-controls": "toolbox-listbox",
36
+ "aria-expanded": true,
31
37
  className: "searchbox-input",
32
38
  placeholder: placeholder,
33
39
  value: value,
34
- onChange: (e)=>onChange(e.target.value)
40
+ onChange: (e)=>onChange(e.target.value),
41
+ onKeyDown: onNavigationKeyDown,
42
+ "aria-activedescendant": activeDescendantId
35
43
  }),
36
44
  value && /*#__PURE__*/ jsx("button", {
37
45
  type: "button",
@@ -30,11 +30,13 @@ const jsx_runtime_namespaceObject = require("react/jsx-runtime");
30
30
  const index_cjs_namespaceObject = require("../../hooks/index.cjs");
31
31
  const external_layouts_index_cjs_namespaceObject = require("../../layouts/index.cjs");
32
32
  const external_react_namespaceObject = require("react");
33
+ const external_react_window_namespaceObject = require("react-window");
33
34
  const external_Header_cjs_namespaceObject = require("./Header.cjs");
34
35
  const external_ListView_cjs_namespaceObject = require("./ListView.cjs");
35
36
  const external_SearchBox_cjs_namespaceObject = require("./SearchBox.cjs");
36
37
  const external_Toolbox_styles_cjs_namespaceObject = require("./Toolbox.styles.cjs");
37
38
  const TRANSITION_DURATION = 150;
39
+ const SEARCH_BAR_INDEX = -1;
38
40
  function findItemById(items, id) {
39
41
  const queue = [
40
42
  ...items
@@ -52,6 +54,23 @@ function findItemById(items, id) {
52
54
  }
53
55
  return null;
54
56
  }
57
+ function getNextSelectableIndex(renderedItems, currentIndex, direction) {
58
+ const numericDirection = 'up' === direction ? -1 : 1;
59
+ let next = currentIndex + numericDirection;
60
+ while(next >= 0 && next < renderedItems.length){
61
+ if (renderedItems[next]?.type === 'item') return next;
62
+ next += numericDirection;
63
+ }
64
+ return SEARCH_BAR_INDEX;
65
+ }
66
+ function getFirstSelectableIndex(renderedItems) {
67
+ for(let i = 0; i < renderedItems.length; i++)if (renderedItems[i]?.type === 'item') return i;
68
+ return SEARCH_BAR_INDEX;
69
+ }
70
+ function getLastSelectableIndex(renderedItems) {
71
+ for(let i = renderedItems.length - 1; i >= 0; i--)if (renderedItems[i]?.type === 'item') return i;
72
+ return SEARCH_BAR_INDEX;
73
+ }
55
74
  function searchLeafItems(items, query) {
56
75
  const results = [];
57
76
  for (const item of items)if ('function' != typeof item.children) {
@@ -71,13 +90,23 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
71
90
  const [isTransitioning, setIsTransitioning] = (0, external_react_namespaceObject.useState)(false);
72
91
  const [animationDirection, setAnimationDirection] = (0, external_react_namespaceObject.useState)('forward');
73
92
  const navigationStack = (0, index_cjs_namespaceObject.useNavigationStack)();
93
+ const [activeIndex, setActiveIndex] = (0, external_react_namespaceObject.useState)(SEARCH_BAR_INDEX);
74
94
  const containerRef = (0, external_react_namespaceObject.useRef)(null);
75
95
  const transitionTimeoutRef = (0, external_react_namespaceObject.useRef)(void 0);
76
96
  const searchIdRef = (0, external_react_namespaceObject.useRef)(0);
77
97
  const initialItemsRef = (0, external_react_namespaceObject.useRef)(initialItems);
98
+ const listRef = (0, external_react_window_namespaceObject.useListRef)(null);
99
+ const listViewRef = (0, external_react_namespaceObject.useRef)(null);
100
+ const searchInputRef = (0, external_react_namespaceObject.useRef)(null);
78
101
  const isSearching = (0, external_react_namespaceObject.useMemo)(()=>search.length > 0, [
79
102
  search
80
103
  ]);
104
+ const displayedItems = (0, external_react_namespaceObject.useMemo)(()=>isSearching && !isSearchingInitialItems ? searchedItems : items, [
105
+ isSearching,
106
+ isSearchingInitialItems,
107
+ searchedItems,
108
+ items
109
+ ]);
81
110
  const startTransition = (0, external_react_namespaceObject.useCallback)((direction)=>{
82
111
  if (transitionTimeoutRef.current) clearTimeout(transitionTimeoutRef.current);
83
112
  setIsTransitioning(true);
@@ -86,11 +115,22 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
86
115
  setIsTransitioning(false);
87
116
  }, TRANSITION_DURATION);
88
117
  }, []);
118
+ const navigateToIndex = (0, external_react_namespaceObject.useCallback)((index)=>{
119
+ setActiveIndex(index);
120
+ if (index === SEARCH_BAR_INDEX) return void searchInputRef.current?.focus();
121
+ listRef.current?.scrollToRow({
122
+ index,
123
+ align: 'auto'
124
+ });
125
+ }, [
126
+ listRef
127
+ ]);
89
128
  const clearSearch = (0, external_react_namespaceObject.useCallback)(()=>{
90
129
  setSearch('');
91
130
  setSearchedItems([]);
92
131
  setSearchLoading(false);
93
132
  setIsSearchingInitialItems(true);
133
+ setActiveIndex(SEARCH_BAR_INDEX);
94
134
  }, []);
95
135
  const handleSearch = (0, external_react_namespaceObject.useCallback)(async (query)=>{
96
136
  if (!query.trim()) {
@@ -101,6 +141,7 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
101
141
  return;
102
142
  }
103
143
  setSearch(query);
144
+ setActiveIndex(SEARCH_BAR_INDEX);
104
145
  searchIdRef.current += 1;
105
146
  const currentRequestId = searchIdRef.current;
106
147
  setSearchLoading(true);
@@ -121,6 +162,7 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
121
162
  ]);
122
163
  const handleBackTransition = (0, external_react_namespaceObject.useCallback)(()=>{
123
164
  startTransition('back');
165
+ setActiveIndex(SEARCH_BAR_INDEX);
124
166
  const previousState = navigationStack.pop();
125
167
  if (previousState) {
126
168
  setItems(previousState.data.items);
@@ -149,6 +191,7 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
149
191
  setItems(nestedItems);
150
192
  setCurrentParentItem(item);
151
193
  clearSearch();
194
+ setActiveIndex(SEARCH_BAR_INDEX);
152
195
  startTransition('forward');
153
196
  setChildrenLoading(false);
154
197
  }, [
@@ -206,6 +249,96 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
206
249
  }, [
207
250
  items
208
251
  ]);
252
+ const activeDescendantId = (0, external_react_namespaceObject.useMemo)(()=>{
253
+ if (activeIndex < 0) return;
254
+ const renderItem = listViewRef.current?.renderedItems[activeIndex];
255
+ if (renderItem?.type === 'item') return `toolbox-item-${renderItem.item.id}`;
256
+ }, [
257
+ activeIndex
258
+ ]);
259
+ const handleNavigationKeyDown = (0, external_react_namespaceObject.useCallback)((e)=>{
260
+ if (isTransitioning) return;
261
+ const renderedItems = listViewRef.current?.renderedItems ?? [];
262
+ const navigateDown = ()=>{
263
+ if (activeIndex === SEARCH_BAR_INDEX) {
264
+ const firstIndex = getFirstSelectableIndex(renderedItems);
265
+ if (firstIndex !== SEARCH_BAR_INDEX) navigateToIndex(firstIndex);
266
+ } else {
267
+ const nextIndex = getNextSelectableIndex(renderedItems, activeIndex, 'down');
268
+ if (nextIndex !== SEARCH_BAR_INDEX) navigateToIndex(nextIndex);
269
+ else {
270
+ const firstIndex = getFirstSelectableIndex(renderedItems);
271
+ if (firstIndex !== SEARCH_BAR_INDEX) navigateToIndex(firstIndex);
272
+ }
273
+ }
274
+ };
275
+ const navigateUp = ()=>{
276
+ navigateToIndex(getNextSelectableIndex(renderedItems, activeIndex, 'up'));
277
+ };
278
+ switch(e.key){
279
+ case 'ArrowDown':
280
+ e.preventDefault();
281
+ navigateDown();
282
+ break;
283
+ case 'ArrowUp':
284
+ e.preventDefault();
285
+ navigateUp();
286
+ break;
287
+ case 'Enter':
288
+ {
289
+ if (activeIndex === SEARCH_BAR_INDEX) break;
290
+ const renderItem = renderedItems[activeIndex];
291
+ if (renderItem?.type === 'item') {
292
+ e.preventDefault();
293
+ handleItemSelect(renderItem.item);
294
+ }
295
+ break;
296
+ }
297
+ case 'ArrowRight':
298
+ {
299
+ const renderItem = renderedItems[activeIndex];
300
+ if (renderItem?.type === 'item' && renderItem.item.children) {
301
+ e.preventDefault();
302
+ handleItemSelect(renderItem.item);
303
+ }
304
+ break;
305
+ }
306
+ case 'ArrowLeft':
307
+ if (!navigationStack.canGoBack || activeIndex === SEARCH_BAR_INDEX && search.length > 0) return;
308
+ e.preventDefault();
309
+ handleBackTransition();
310
+ break;
311
+ case 'Tab':
312
+ e.preventDefault();
313
+ if (e.shiftKey) navigateUp();
314
+ else navigateDown();
315
+ break;
316
+ case 'Home':
317
+ {
318
+ if (activeIndex === SEARCH_BAR_INDEX) break;
319
+ e.preventDefault();
320
+ const firstIndex = getFirstSelectableIndex(renderedItems);
321
+ if (firstIndex !== SEARCH_BAR_INDEX) navigateToIndex(firstIndex);
322
+ break;
323
+ }
324
+ case 'End':
325
+ {
326
+ if (activeIndex === SEARCH_BAR_INDEX) break;
327
+ e.preventDefault();
328
+ const lastIndex = getLastSelectableIndex(renderedItems);
329
+ if (lastIndex !== SEARCH_BAR_INDEX) navigateToIndex(lastIndex);
330
+ break;
331
+ }
332
+ }
333
+ }, [
334
+ search,
335
+ isTransitioning,
336
+ activeIndex,
337
+ navigationStack.canGoBack,
338
+ navigateToIndex,
339
+ handleItemSelect,
340
+ handleBackTransition
341
+ ]);
209
342
  (0, external_react_namespaceObject.useEffect)(()=>{
210
343
  const handleKeyDown = (e)=>{
211
344
  if ('Escape' === e.key) if (isSearching) {
@@ -251,19 +384,25 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
251
384
  value: search,
252
385
  onChange: handleSearch,
253
386
  clear: clearSearch,
254
- placeholder: "Search"
387
+ placeholder: "Search",
388
+ inputRef: searchInputRef,
389
+ onNavigationKeyDown: handleNavigationKeyDown,
390
+ activeDescendantId: activeDescendantId
255
391
  }),
256
392
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_Toolbox_styles_cjs_namespaceObject.AnimatedContainer, {
257
393
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_Toolbox_styles_cjs_namespaceObject.AnimatedContent, {
258
394
  entering: isTransitioning,
259
395
  direction: animationDirection,
260
396
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_ListView_cjs_namespaceObject.ListView, {
397
+ ref: listViewRef,
261
398
  isLoading: childrenLoading || searchLoading || loading,
262
- items: isSearching && !isSearchingInitialItems ? searchedItems : items,
399
+ items: displayedItems,
400
+ activeIndex: activeIndex,
401
+ listRef: listRef,
263
402
  emptyStateMessage: isSearching ? 'No matching nodes found' : 'No nodes found',
264
- enableSections: !isSearching,
265
403
  onItemClick: handleItemSelect,
266
- onItemHover: onItemHover
404
+ onItemHover: onItemHover,
405
+ enableSections: !isSearching
267
406
  })
268
407
  })
269
408
  })
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbox.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/Toolbox.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,QAAQ,EAAY,MAAM,YAAY,CAAC;AAuCrD,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,GAAG,IAAI,CAC1C,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,OAAO,EACzB,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAC5E,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE5B,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;CACpC;AAoBD,wBAAgB,OAAO,CAAC,CAAC,EAAE,EACzB,OAAO,EACP,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,KAAK,EACL,YAAY,EACZ,OAAO,GACR,EAAE,YAAY,CAAC,CAAC,CAAC,2CAyQjB"}
1
+ {"version":3,"file":"Toolbox.d.ts","sourceRoot":"","sources":["../../../../src/canvas/components/Toolbox/Toolbox.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,QAAQ,EAAkD,MAAM,YAAY,CAAC;AAwC3F,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,GAAG,IAAI,CAC1C,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,OAAO,EACzB,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAC5E,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE5B,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;CACpC;AAgDD,wBAAgB,OAAO,CAAC,CAAC,EAAE,EACzB,OAAO,EACP,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,KAAK,EACL,YAAY,EACZ,OAAO,GACR,EAAE,YAAY,CAAC,CAAC,CAAC,2CAsZjB"}
@@ -2,11 +2,13 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useNavigationStack } from "../../hooks/index.js";
3
3
  import { Column } from "../../layouts/index.js";
4
4
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
+ import { useListRef } from "react-window";
5
6
  import { Header } from "./Header.js";
6
7
  import { ListView } from "./ListView.js";
7
8
  import { SearchBox } from "./SearchBox.js";
8
9
  import { AnimatedContainer, AnimatedContent } from "./Toolbox.styles.js";
9
10
  const TRANSITION_DURATION = 150;
11
+ const SEARCH_BAR_INDEX = -1;
10
12
  function findItemById(items, id) {
11
13
  const queue = [
12
14
  ...items
@@ -24,6 +26,23 @@ function findItemById(items, id) {
24
26
  }
25
27
  return null;
26
28
  }
29
+ function getNextSelectableIndex(renderedItems, currentIndex, direction) {
30
+ const numericDirection = 'up' === direction ? -1 : 1;
31
+ let next = currentIndex + numericDirection;
32
+ while(next >= 0 && next < renderedItems.length){
33
+ if (renderedItems[next]?.type === 'item') return next;
34
+ next += numericDirection;
35
+ }
36
+ return SEARCH_BAR_INDEX;
37
+ }
38
+ function getFirstSelectableIndex(renderedItems) {
39
+ for(let i = 0; i < renderedItems.length; i++)if (renderedItems[i]?.type === 'item') return i;
40
+ return SEARCH_BAR_INDEX;
41
+ }
42
+ function getLastSelectableIndex(renderedItems) {
43
+ for(let i = renderedItems.length - 1; i >= 0; i--)if (renderedItems[i]?.type === 'item') return i;
44
+ return SEARCH_BAR_INDEX;
45
+ }
27
46
  function searchLeafItems(items, query) {
28
47
  const results = [];
29
48
  for (const item of items)if ('function' != typeof item.children) {
@@ -43,13 +62,23 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
43
62
  const [isTransitioning, setIsTransitioning] = useState(false);
44
63
  const [animationDirection, setAnimationDirection] = useState('forward');
45
64
  const navigationStack = useNavigationStack();
65
+ const [activeIndex, setActiveIndex] = useState(SEARCH_BAR_INDEX);
46
66
  const containerRef = useRef(null);
47
67
  const transitionTimeoutRef = useRef(void 0);
48
68
  const searchIdRef = useRef(0);
49
69
  const initialItemsRef = useRef(initialItems);
70
+ const listRef = useListRef(null);
71
+ const listViewRef = useRef(null);
72
+ const searchInputRef = useRef(null);
50
73
  const isSearching = useMemo(()=>search.length > 0, [
51
74
  search
52
75
  ]);
76
+ const displayedItems = useMemo(()=>isSearching && !isSearchingInitialItems ? searchedItems : items, [
77
+ isSearching,
78
+ isSearchingInitialItems,
79
+ searchedItems,
80
+ items
81
+ ]);
53
82
  const startTransition = useCallback((direction)=>{
54
83
  if (transitionTimeoutRef.current) clearTimeout(transitionTimeoutRef.current);
55
84
  setIsTransitioning(true);
@@ -58,11 +87,22 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
58
87
  setIsTransitioning(false);
59
88
  }, TRANSITION_DURATION);
60
89
  }, []);
90
+ const navigateToIndex = useCallback((index)=>{
91
+ setActiveIndex(index);
92
+ if (index === SEARCH_BAR_INDEX) return void searchInputRef.current?.focus();
93
+ listRef.current?.scrollToRow({
94
+ index,
95
+ align: 'auto'
96
+ });
97
+ }, [
98
+ listRef
99
+ ]);
61
100
  const clearSearch = useCallback(()=>{
62
101
  setSearch('');
63
102
  setSearchedItems([]);
64
103
  setSearchLoading(false);
65
104
  setIsSearchingInitialItems(true);
105
+ setActiveIndex(SEARCH_BAR_INDEX);
66
106
  }, []);
67
107
  const handleSearch = useCallback(async (query)=>{
68
108
  if (!query.trim()) {
@@ -73,6 +113,7 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
73
113
  return;
74
114
  }
75
115
  setSearch(query);
116
+ setActiveIndex(SEARCH_BAR_INDEX);
76
117
  searchIdRef.current += 1;
77
118
  const currentRequestId = searchIdRef.current;
78
119
  setSearchLoading(true);
@@ -93,6 +134,7 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
93
134
  ]);
94
135
  const handleBackTransition = useCallback(()=>{
95
136
  startTransition('back');
137
+ setActiveIndex(SEARCH_BAR_INDEX);
96
138
  const previousState = navigationStack.pop();
97
139
  if (previousState) {
98
140
  setItems(previousState.data.items);
@@ -121,6 +163,7 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
121
163
  setItems(nestedItems);
122
164
  setCurrentParentItem(item);
123
165
  clearSearch();
166
+ setActiveIndex(SEARCH_BAR_INDEX);
124
167
  startTransition('forward');
125
168
  setChildrenLoading(false);
126
169
  }, [
@@ -178,6 +221,96 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
178
221
  }, [
179
222
  items
180
223
  ]);
224
+ const activeDescendantId = useMemo(()=>{
225
+ if (activeIndex < 0) return;
226
+ const renderItem = listViewRef.current?.renderedItems[activeIndex];
227
+ if (renderItem?.type === 'item') return `toolbox-item-${renderItem.item.id}`;
228
+ }, [
229
+ activeIndex
230
+ ]);
231
+ const handleNavigationKeyDown = useCallback((e)=>{
232
+ if (isTransitioning) return;
233
+ const renderedItems = listViewRef.current?.renderedItems ?? [];
234
+ const navigateDown = ()=>{
235
+ if (activeIndex === SEARCH_BAR_INDEX) {
236
+ const firstIndex = getFirstSelectableIndex(renderedItems);
237
+ if (firstIndex !== SEARCH_BAR_INDEX) navigateToIndex(firstIndex);
238
+ } else {
239
+ const nextIndex = getNextSelectableIndex(renderedItems, activeIndex, 'down');
240
+ if (nextIndex !== SEARCH_BAR_INDEX) navigateToIndex(nextIndex);
241
+ else {
242
+ const firstIndex = getFirstSelectableIndex(renderedItems);
243
+ if (firstIndex !== SEARCH_BAR_INDEX) navigateToIndex(firstIndex);
244
+ }
245
+ }
246
+ };
247
+ const navigateUp = ()=>{
248
+ navigateToIndex(getNextSelectableIndex(renderedItems, activeIndex, 'up'));
249
+ };
250
+ switch(e.key){
251
+ case 'ArrowDown':
252
+ e.preventDefault();
253
+ navigateDown();
254
+ break;
255
+ case 'ArrowUp':
256
+ e.preventDefault();
257
+ navigateUp();
258
+ break;
259
+ case 'Enter':
260
+ {
261
+ if (activeIndex === SEARCH_BAR_INDEX) break;
262
+ const renderItem = renderedItems[activeIndex];
263
+ if (renderItem?.type === 'item') {
264
+ e.preventDefault();
265
+ handleItemSelect(renderItem.item);
266
+ }
267
+ break;
268
+ }
269
+ case 'ArrowRight':
270
+ {
271
+ const renderItem = renderedItems[activeIndex];
272
+ if (renderItem?.type === 'item' && renderItem.item.children) {
273
+ e.preventDefault();
274
+ handleItemSelect(renderItem.item);
275
+ }
276
+ break;
277
+ }
278
+ case 'ArrowLeft':
279
+ if (!navigationStack.canGoBack || activeIndex === SEARCH_BAR_INDEX && search.length > 0) return;
280
+ e.preventDefault();
281
+ handleBackTransition();
282
+ break;
283
+ case 'Tab':
284
+ e.preventDefault();
285
+ if (e.shiftKey) navigateUp();
286
+ else navigateDown();
287
+ break;
288
+ case 'Home':
289
+ {
290
+ if (activeIndex === SEARCH_BAR_INDEX) break;
291
+ e.preventDefault();
292
+ const firstIndex = getFirstSelectableIndex(renderedItems);
293
+ if (firstIndex !== SEARCH_BAR_INDEX) navigateToIndex(firstIndex);
294
+ break;
295
+ }
296
+ case 'End':
297
+ {
298
+ if (activeIndex === SEARCH_BAR_INDEX) break;
299
+ e.preventDefault();
300
+ const lastIndex = getLastSelectableIndex(renderedItems);
301
+ if (lastIndex !== SEARCH_BAR_INDEX) navigateToIndex(lastIndex);
302
+ break;
303
+ }
304
+ }
305
+ }, [
306
+ search,
307
+ isTransitioning,
308
+ activeIndex,
309
+ navigationStack.canGoBack,
310
+ navigateToIndex,
311
+ handleItemSelect,
312
+ handleBackTransition
313
+ ]);
181
314
  useEffect(()=>{
182
315
  const handleKeyDown = (e)=>{
183
316
  if ('Escape' === e.key) if (isSearching) {
@@ -223,19 +356,25 @@ function Toolbox({ onClose, onBack, onItemSelect, onSearch, onItemHover, title,
223
356
  value: search,
224
357
  onChange: handleSearch,
225
358
  clear: clearSearch,
226
- placeholder: "Search"
359
+ placeholder: "Search",
360
+ inputRef: searchInputRef,
361
+ onNavigationKeyDown: handleNavigationKeyDown,
362
+ activeDescendantId: activeDescendantId
227
363
  }),
228
364
  /*#__PURE__*/ jsx(AnimatedContainer, {
229
365
  children: /*#__PURE__*/ jsx(AnimatedContent, {
230
366
  entering: isTransitioning,
231
367
  direction: animationDirection,
232
368
  children: /*#__PURE__*/ jsx(ListView, {
369
+ ref: listViewRef,
233
370
  isLoading: childrenLoading || searchLoading || loading,
234
- items: isSearching && !isSearchingInitialItems ? searchedItems : items,
371
+ items: displayedItems,
372
+ activeIndex: activeIndex,
373
+ listRef: listRef,
235
374
  emptyStateMessage: isSearching ? 'No matching nodes found' : 'No nodes found',
236
- enableSections: !isSearching,
237
375
  onItemClick: handleItemSelect,
238
- onItemHover: onItemHover
376
+ onItemHover: onItemHover,
377
+ enableSections: !isSearching
239
378
  })
240
379
  })
241
380
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/apollo-react",
3
- "version": "3.55.1",
3
+ "version": "3.56.0-pr364.24cd059",
4
4
  "description": "Apollo Design System - React component library with Material UI theming",
5
5
  "repository": {
6
6
  "type": "git",