@backstage/ui 0.15.1-next.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/dist/components/Combobox/Combobox.esm.js +150 -52
  3. package/dist/components/Combobox/Combobox.esm.js.map +1 -1
  4. package/dist/components/Combobox/Combobox.module.css.esm.js +2 -2
  5. package/dist/components/Combobox/ComboboxItem.esm.js +76 -0
  6. package/dist/components/Combobox/ComboboxItem.esm.js.map +1 -0
  7. package/dist/components/Combobox/ComboboxListBox.esm.js +215 -17
  8. package/dist/components/Combobox/ComboboxListBox.esm.js.map +1 -1
  9. package/dist/components/Combobox/definition.esm.js +62 -3
  10. package/dist/components/Combobox/definition.esm.js.map +1 -1
  11. package/dist/components/Combobox/useAsyncComboboxState.esm.js +133 -0
  12. package/dist/components/Combobox/useAsyncComboboxState.esm.js.map +1 -0
  13. package/dist/components/Header/HeaderNav.esm.js +0 -1
  14. package/dist/components/Header/HeaderNav.esm.js.map +1 -1
  15. package/dist/components/Select/Select.esm.js +87 -19
  16. package/dist/components/Select/Select.esm.js.map +1 -1
  17. package/dist/components/Select/Select.module.css.esm.js +2 -2
  18. package/dist/components/Select/SelectContent.esm.js +70 -18
  19. package/dist/components/Select/SelectContent.esm.js.map +1 -1
  20. package/dist/components/Select/SelectItem.esm.js +76 -0
  21. package/dist/components/Select/SelectItem.esm.js.map +1 -0
  22. package/dist/components/Select/SelectListBox.esm.js +175 -19
  23. package/dist/components/Select/SelectListBox.esm.js.map +1 -1
  24. package/dist/components/Select/SelectTrigger.esm.js +1 -1
  25. package/dist/components/Select/SelectTrigger.esm.js.map +1 -1
  26. package/dist/components/Select/definition.esm.js +72 -9
  27. package/dist/components/Select/definition.esm.js.map +1 -1
  28. package/dist/components/Skeleton/Skeleton.module.css.esm.js +2 -2
  29. package/dist/components/Skeleton/definition.esm.js +1 -0
  30. package/dist/components/Skeleton/definition.esm.js.map +1 -1
  31. package/dist/components/Table/Table.module.css.esm.js +2 -2
  32. package/dist/components/Table/components/Table.esm.js +60 -57
  33. package/dist/components/Table/components/Table.esm.js.map +1 -1
  34. package/dist/components/Table/definition.esm.js +2 -1
  35. package/dist/components/Table/definition.esm.js.map +1 -1
  36. package/dist/components/TablePagination/TablePagination.esm.js +4 -1
  37. package/dist/components/TablePagination/TablePagination.esm.js.map +1 -1
  38. package/dist/components/Tabs/TabsIndicators.esm.js +155 -108
  39. package/dist/components/Tabs/TabsIndicators.esm.js.map +1 -1
  40. package/dist/css/styles.css +4 -4
  41. package/dist/hooks/useCollectionAdapter.esm.js +67 -0
  42. package/dist/hooks/useCollectionAdapter.esm.js.map +1 -0
  43. package/dist/hooks/useDelayedVisibility.esm.js +17 -0
  44. package/dist/hooks/useDelayedVisibility.esm.js.map +1 -0
  45. package/dist/hooks/useTrackedSelectionKeys.esm.js +23 -0
  46. package/dist/hooks/useTrackedSelectionKeys.esm.js.map +1 -0
  47. package/dist/index.d.ts +742 -77
  48. package/dist/index.esm.js +5 -2
  49. package/dist/index.esm.js.map +1 -1
  50. package/dist/utils/selectableCollection.esm.js +75 -0
  51. package/dist/utils/selectableCollection.esm.js.map +1 -0
  52. package/package.json +4 -4
@@ -1,45 +1,243 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { ListBox, ListBoxSection, Header, ListBoxItem, Text } from 'react-aria-components';
3
- import { RiCheckLine } from '@remixicon/react';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useContext, cloneElement } from 'react';
3
+ import { ComboBoxStateContext, ListBox, SelectableCollectionContext, Collection, ListBoxLoadMoreItem, ListBoxSection, Header, Text } from 'react-aria-components';
4
+ import { useFilter } from 'react-aria';
5
+ import clsx from 'clsx';
4
6
  import { useDefinition } from '../../hooks/useDefinition/useDefinition.esm.js';
5
- import { ComboboxListBoxDefinition, ComboboxSectionDefinition, ComboboxListBoxItemDefinition } from './definition.esm.js';
7
+ import { normalizeOptions } from '../../utils/selectableCollection.esm.js';
8
+ import { ComboboxItem } from './ComboboxItem.esm.js';
9
+ import { ComboboxListBoxDefinition, ComboboxSectionDefinition, ComboboxItemTextDefinition, ComboboxListBoxItemDefinition } from './definition.esm.js';
10
+ import { Skeleton } from '../Skeleton/Skeleton.esm.js';
11
+ import '../Skeleton/Skeleton.module.css.esm.js';
12
+ import { useDelayedVisibility } from '../../hooks/useDelayedVisibility.esm.js';
6
13
 
14
+ const loadingRowWidths = ["70%", "55%", "65%"];
15
+ const loadingIndicatorDelayMs = 300;
16
+ function LoadingRows({
17
+ count,
18
+ className,
19
+ rowClassName
20
+ }) {
21
+ return /* @__PURE__ */ jsx("div", { className, "aria-hidden": "true", children: loadingRowWidths.slice(0, count).map((width) => /* @__PURE__ */ jsx("div", { className: rowClassName, children: /* @__PURE__ */ jsx(Skeleton, { width, height: "0.75rem" }) }, width)) });
22
+ }
7
23
  const NoResults = () => {
8
24
  const { ownProps } = useDefinition(ComboboxListBoxDefinition, {});
9
25
  const { classes } = ownProps;
10
26
  return /* @__PURE__ */ jsx("div", { className: classes.noResults, children: "No results found." });
11
27
  };
12
- function ComboboxItem({ option }) {
13
- const { ownProps } = useDefinition(ComboboxListBoxItemDefinition, {});
28
+ function ComboboxOptionItem({ option }) {
29
+ const { ownProps } = useDefinition(ComboboxItemTextDefinition, {
30
+ title: option.label,
31
+ description: option.description,
32
+ leadingIcon: option.leadingIcon
33
+ });
14
34
  const { classes } = ownProps;
35
+ const {
36
+ ownProps: { classes: legacyOptionClasses }
37
+ } = useDefinition(ComboboxListBoxItemDefinition, {});
15
38
  return /* @__PURE__ */ jsxs(
16
- ListBoxItem,
39
+ ComboboxItem,
17
40
  {
18
- id: option.value,
19
- textValue: option.label,
41
+ id: option.id,
42
+ value: option,
20
43
  className: classes.root,
44
+ textValue: option.label,
21
45
  isDisabled: option.disabled,
46
+ showSelectionIndicator: true,
22
47
  children: [
23
- /* @__PURE__ */ jsx("div", { className: classes.indicator, children: /* @__PURE__ */ jsx(RiCheckLine, { "aria-hidden": "true" }) }),
24
- /* @__PURE__ */ jsx(Text, { slot: "label", className: classes.label, children: option.label })
48
+ option.leadingIcon && /* @__PURE__ */ jsx("div", { className: classes.leadingIcon, children: option.leadingIcon }),
49
+ /* @__PURE__ */ jsxs("div", { className: classes.text, children: [
50
+ /* @__PURE__ */ jsx(
51
+ Text,
52
+ {
53
+ slot: "label",
54
+ className: clsx(classes.title, legacyOptionClasses.label),
55
+ children: option.label
56
+ }
57
+ ),
58
+ option.description && /* @__PURE__ */ jsx(Text, { slot: "description", className: classes.description, children: option.description })
59
+ ] })
25
60
  ]
26
61
  }
27
62
  );
28
63
  }
29
- function ComboboxSectionItems({ section }) {
64
+ function ComboboxSectionItems({
65
+ section
66
+ }) {
30
67
  const { ownProps } = useDefinition(ComboboxSectionDefinition, {});
31
68
  const { classes } = ownProps;
32
69
  return /* @__PURE__ */ jsxs(ListBoxSection, { className: classes.root, children: [
33
70
  /* @__PURE__ */ jsx(Header, { className: classes.header, children: section.title }),
34
- section.options.map((option) => /* @__PURE__ */ jsx(ComboboxItem, { option }, option.value))
71
+ section.options.map((option) => /* @__PURE__ */ jsx(ComboboxOptionItem, { option }, option.id))
35
72
  ] });
36
73
  }
74
+ function renderComboboxOption(item) {
75
+ if ("options" in item) {
76
+ return /* @__PURE__ */ jsx(ComboboxSectionItems, { section: item }, item.title);
77
+ }
78
+ return /* @__PURE__ */ jsx(ComboboxOptionItem, { option: item }, item.id);
79
+ }
80
+ function getCollectionFilter({
81
+ search,
82
+ hasItems,
83
+ inputValue,
84
+ contains
85
+ }) {
86
+ const searchProps = typeof search === "object" ? search : void 0;
87
+ if (searchProps?.mode === "server") {
88
+ return void 0;
89
+ }
90
+ const customFilter = searchProps?.filter;
91
+ if (customFilter) {
92
+ return (_textValue, node) => customFilter(node.value, inputValue);
93
+ }
94
+ if (search || hasItems) {
95
+ return (textValue) => contains(textValue, inputValue);
96
+ }
97
+ return void 0;
98
+ }
99
+ function ComboboxCollection({
100
+ normalizedOptions,
101
+ items,
102
+ children,
103
+ dependencies,
104
+ getItemTextValue
105
+ }) {
106
+ if (normalizedOptions) {
107
+ return /* @__PURE__ */ jsx(Fragment, { children: normalizedOptions.map(renderComboboxOption) });
108
+ }
109
+ if (items) {
110
+ const renderItemWithTextValue = (item) => {
111
+ let renderedItem;
112
+ if (typeof children === "function") {
113
+ renderedItem = children(item);
114
+ } else {
115
+ renderedItem = /* @__PURE__ */ jsx(ComboboxOptionItem, { option: item });
116
+ }
117
+ if (!getItemTextValue) {
118
+ return renderedItem;
119
+ }
120
+ return cloneElement(renderedItem, {
121
+ textValue: getItemTextValue(item)
122
+ });
123
+ };
124
+ return /* @__PURE__ */ jsx(Collection, { items, dependencies, children: renderItemWithTextValue });
125
+ }
126
+ return children;
127
+ }
128
+ function ComboboxEmptyState({
129
+ isLoading,
130
+ className,
131
+ rowClassName
132
+ }) {
133
+ if (!isLoading) {
134
+ return /* @__PURE__ */ jsx(NoResults, {});
135
+ }
136
+ return /* @__PURE__ */ jsx(LoadingRows, { count: 3, className, rowClassName });
137
+ }
138
+ function ComboboxLoadMoreIndicator({
139
+ loading,
140
+ isCollectionLoading,
141
+ isIndicatorVisible,
142
+ className,
143
+ rowClassName
144
+ }) {
145
+ if (!loading?.onLoadMore || isCollectionLoading) {
146
+ return null;
147
+ }
148
+ const onLoadMore = loading.state === "loadingMore" ? void 0 : loading.onLoadMore;
149
+ return /* @__PURE__ */ jsx(
150
+ ListBoxLoadMoreItem,
151
+ {
152
+ isLoading: isIndicatorVisible,
153
+ onLoadMore,
154
+ scrollOffset: 0,
155
+ children: /* @__PURE__ */ jsx(
156
+ LoadingRows,
157
+ {
158
+ count: 1,
159
+ className,
160
+ rowClassName
161
+ }
162
+ )
163
+ }
164
+ );
165
+ }
37
166
  function ComboboxListBox(props) {
38
167
  const { ownProps } = useDefinition(ComboboxListBoxDefinition, props);
39
- const { classes, options } = ownProps;
40
- return /* @__PURE__ */ jsx(ListBox, { className: classes.root, renderEmptyState: () => /* @__PURE__ */ jsx(NoResults, {}), children: options?.map(
41
- (item) => "options" in item ? /* @__PURE__ */ jsx(ComboboxSectionItems, { section: item }, item.title) : /* @__PURE__ */ jsx(ComboboxItem, { option: item }, item.value)
42
- ) });
168
+ const {
169
+ classes,
170
+ options,
171
+ items,
172
+ children,
173
+ dependencies,
174
+ search,
175
+ loading,
176
+ isStale,
177
+ getItemTextValue
178
+ } = ownProps;
179
+ const normalizedOptions = options && normalizeOptions(options);
180
+ const state = useContext(ComboBoxStateContext);
181
+ const { contains } = useFilter({ sensitivity: "base" });
182
+ const inputValue = state?.inputValue ?? "";
183
+ const filter = getCollectionFilter({
184
+ search,
185
+ hasItems: items !== void 0,
186
+ inputValue,
187
+ contains
188
+ });
189
+ const isCollectionLoading = loading?.state === "loading" || loading?.state === "filtering" || loading?.state === "sorting";
190
+ const isBusy = isCollectionLoading || loading?.state === "loadingMore";
191
+ const showStale = useDelayedVisibility(
192
+ isStale ?? false,
193
+ loadingIndicatorDelayMs
194
+ );
195
+ const showLoadMoreIndicator = useDelayedVisibility(
196
+ loading?.state === "loadingMore",
197
+ loadingIndicatorDelayMs
198
+ );
199
+ const listBox = /* @__PURE__ */ jsxs(
200
+ ListBox,
201
+ {
202
+ className: classes.root,
203
+ "data-stale": showStale || void 0,
204
+ renderEmptyState: () => /* @__PURE__ */ jsx(
205
+ ComboboxEmptyState,
206
+ {
207
+ isLoading: isCollectionLoading,
208
+ className: classes.loading,
209
+ rowClassName: classes.loadingRow
210
+ }
211
+ ),
212
+ children: [
213
+ /* @__PURE__ */ jsx(
214
+ ComboboxCollection,
215
+ {
216
+ normalizedOptions,
217
+ items,
218
+ dependencies,
219
+ getItemTextValue,
220
+ children
221
+ }
222
+ ),
223
+ /* @__PURE__ */ jsx(
224
+ ComboboxLoadMoreIndicator,
225
+ {
226
+ loading,
227
+ isCollectionLoading,
228
+ isIndicatorVisible: showLoadMoreIndicator,
229
+ className: classes.loading,
230
+ rowClassName: classes.loadingRow
231
+ }
232
+ )
233
+ ]
234
+ }
235
+ );
236
+ const busyListBox = /* @__PURE__ */ jsx("div", { "aria-busy": isBusy || void 0, children: listBox });
237
+ if (!filter) {
238
+ return busyListBox;
239
+ }
240
+ return /* @__PURE__ */ jsx(SelectableCollectionContext.Provider, { value: { filter }, children: busyListBox });
43
241
  }
44
242
 
45
243
  export { ComboboxListBox };
@@ -1 +1 @@
1
- {"version":3,"file":"ComboboxListBox.esm.js","sources":["../../../src/components/Combobox/ComboboxListBox.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ListBox,\n ListBoxItem,\n ListBoxSection,\n Header,\n Text,\n} from 'react-aria-components';\nimport { RiCheckLine } from '@remixicon/react';\nimport { useDefinition } from '../../hooks/useDefinition';\nimport {\n ComboboxListBoxDefinition,\n ComboboxListBoxItemDefinition,\n ComboboxSectionDefinition,\n} from './definition';\nimport type { Option, OptionSection, ComboboxListBoxOwnProps } from './types';\n\nconst NoResults = () => {\n const { ownProps } = useDefinition(ComboboxListBoxDefinition, {});\n const { classes } = ownProps;\n\n return <div className={classes.noResults}>No results found.</div>;\n};\n\nfunction ComboboxItem({ option }: { option: Option }) {\n const { ownProps } = useDefinition(ComboboxListBoxItemDefinition, {});\n const { classes } = ownProps;\n\n return (\n <ListBoxItem\n id={option.value}\n textValue={option.label}\n className={classes.root}\n isDisabled={option.disabled}\n >\n <div className={classes.indicator}>\n <RiCheckLine aria-hidden=\"true\" />\n </div>\n <Text slot=\"label\" className={classes.label}>\n {option.label}\n </Text>\n </ListBoxItem>\n );\n}\n\nfunction ComboboxSectionItems({ section }: { section: OptionSection }) {\n const { ownProps } = useDefinition(ComboboxSectionDefinition, {});\n const { classes } = ownProps;\n\n return (\n <ListBoxSection className={classes.root}>\n <Header className={classes.header}>{section.title}</Header>\n {section.options.map(option => (\n <ComboboxItem key={option.value} option={option} />\n ))}\n </ListBoxSection>\n );\n}\n\nexport function ComboboxListBox(props: ComboboxListBoxOwnProps) {\n const { ownProps } = useDefinition(ComboboxListBoxDefinition, props);\n const { classes, options } = ownProps;\n\n return (\n <ListBox className={classes.root} renderEmptyState={() => <NoResults />}>\n {options?.map(item =>\n 'options' in item ? (\n <ComboboxSectionItems key={item.title} section={item} />\n ) : (\n <ComboboxItem key={item.value} option={item} />\n ),\n )}\n </ListBox>\n );\n}\n"],"names":[],"mappings":";;;;;;AAgCA,MAAM,YAAY,MAAM;AACtB,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,aAAA,CAAc,yBAAA,EAA2B,EAAE,CAAA;AAChE,EAAA,MAAM,EAAE,SAAQ,GAAI,QAAA;AAEpB,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,OAAA,CAAQ,WAAW,QAAA,EAAA,mBAAA,EAAiB,CAAA;AAC7D,CAAA;AAEA,SAAS,YAAA,CAAa,EAAE,MAAA,EAAO,EAAuB;AACpD,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,aAAA,CAAc,6BAAA,EAA+B,EAAE,CAAA;AACpE,EAAA,MAAM,EAAE,SAAQ,GAAI,QAAA;AAEpB,EAAA,uBACE,IAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,IAAI,MAAA,CAAO,KAAA;AAAA,MACX,WAAW,MAAA,CAAO,KAAA;AAAA,MAClB,WAAW,OAAA,CAAQ,IAAA;AAAA,MACnB,YAAY,MAAA,CAAO,QAAA;AAAA,MAEnB,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,WAAW,OAAA,CAAQ,SAAA,EACtB,8BAAC,WAAA,EAAA,EAAY,aAAA,EAAY,QAAO,CAAA,EAClC,CAAA;AAAA,wBACA,GAAA,CAAC,QAAK,IAAA,EAAK,OAAA,EAAQ,WAAW,OAAA,CAAQ,KAAA,EACnC,iBAAO,KAAA,EACV;AAAA;AAAA;AAAA,GACF;AAEJ;AAEA,SAAS,oBAAA,CAAqB,EAAE,OAAA,EAAQ,EAA+B;AACrE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,aAAA,CAAc,yBAAA,EAA2B,EAAE,CAAA;AAChE,EAAA,MAAM,EAAE,SAAQ,GAAI,QAAA;AAEpB,EAAA,uBACE,IAAA,CAAC,cAAA,EAAA,EAAe,SAAA,EAAW,OAAA,CAAQ,IAAA,EACjC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAW,OAAA,CAAQ,MAAA,EAAS,kBAAQ,KAAA,EAAM,CAAA;AAAA,IACjD,OAAA,CAAQ,QAAQ,GAAA,CAAI,CAAA,MAAA,yBAClB,YAAA,EAAA,EAAgC,MAAA,EAAA,EAAd,MAAA,CAAO,KAAuB,CAClD;AAAA,GAAA,EACH,CAAA;AAEJ;AAEO,SAAS,gBAAgB,KAAA,EAAgC;AAC9D,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,aAAA,CAAc,2BAA2B,KAAK,CAAA;AACnE,EAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,QAAA;AAE7B,EAAA,uBACE,GAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAW,OAAA,CAAQ,IAAA,EAAM,kBAAkB,sBAAM,GAAA,CAAC,SAAA,EAAA,EAAU,CAAA,EAClE,QAAA,EAAA,OAAA,EAAS,GAAA;AAAA,IAAI,CAAA,IAAA,KACZ,SAAA,IAAa,IAAA,mBACX,GAAA,CAAC,wBAAsC,OAAA,EAAS,IAAA,EAAA,EAArB,IAAA,CAAK,KAAsB,oBAEtD,GAAA,CAAC,YAAA,EAAA,EAA8B,MAAA,EAAQ,IAAA,EAAA,EAApB,KAAK,KAAqB;AAAA,GAEjD,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"ComboboxListBox.esm.js","sources":["../../../src/components/Combobox/ComboboxListBox.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cloneElement, useContext } from 'react';\nimport {\n Collection,\n ComboBoxStateContext,\n Header,\n ListBox,\n ListBoxLoadMoreItem,\n ListBoxSection,\n SelectableCollectionContext,\n Text,\n} from 'react-aria-components';\nimport { useFilter } from 'react-aria';\nimport clsx from 'clsx';\nimport { useDefinition } from '../../hooks/useDefinition';\nimport { normalizeOptions } from '../../utils/selectableCollection';\nimport { ComboboxItem } from './ComboboxItem';\nimport {\n ComboboxItemTextDefinition,\n ComboboxListBoxDefinition,\n ComboboxListBoxItemDefinition,\n ComboboxSectionDefinition,\n} from './definition';\nimport type {\n CollectionItem,\n LoadingConfig,\n NormalizedOption,\n NormalizedOptionSection,\n} from '../../types/selectableCollection';\nimport type { ComboboxListBoxOwnProps } from './types';\nimport type { Node } from '@react-types/shared';\nimport { Skeleton } from '../Skeleton';\nimport { useDelayedVisibility } from '../../hooks/useDelayedVisibility';\n\nconst loadingRowWidths = ['70%', '55%', '65%'];\nconst loadingIndicatorDelayMs = 300;\n\nfunction LoadingRows({\n count,\n className,\n rowClassName,\n}: {\n count: number;\n className: string;\n rowClassName: string;\n}) {\n return (\n <div className={className} aria-hidden=\"true\">\n {loadingRowWidths.slice(0, count).map(width => (\n <div key={width} className={rowClassName}>\n <Skeleton width={width} height=\"0.75rem\" />\n </div>\n ))}\n </div>\n );\n}\n\nconst NoResults = () => {\n const { ownProps } = useDefinition(ComboboxListBoxDefinition, {});\n const { classes } = ownProps;\n\n return <div className={classes.noResults}>No results found.</div>;\n};\n\nfunction ComboboxOptionItem({ option }: { option: NormalizedOption }) {\n const { ownProps } = useDefinition(ComboboxItemTextDefinition, {\n title: option.label,\n description: option.description,\n leadingIcon: option.leadingIcon,\n });\n const { classes } = ownProps;\n const {\n ownProps: { classes: legacyOptionClasses },\n } = useDefinition(ComboboxListBoxItemDefinition, {});\n\n return (\n <ComboboxItem\n id={option.id}\n value={option}\n className={classes.root}\n textValue={option.label}\n isDisabled={option.disabled}\n showSelectionIndicator\n >\n {option.leadingIcon && (\n <div className={classes.leadingIcon}>{option.leadingIcon}</div>\n )}\n <div className={classes.text}>\n <Text\n slot=\"label\"\n className={clsx(classes.title, legacyOptionClasses.label)}\n >\n {option.label}\n </Text>\n {option.description && (\n <Text slot=\"description\" className={classes.description}>\n {option.description}\n </Text>\n )}\n </div>\n </ComboboxItem>\n );\n}\n\nfunction ComboboxSectionItems({\n section,\n}: {\n section: NormalizedOptionSection;\n}) {\n const { ownProps } = useDefinition(ComboboxSectionDefinition, {});\n const { classes } = ownProps;\n\n return (\n <ListBoxSection className={classes.root}>\n <Header className={classes.header}>{section.title}</Header>\n {section.options.map(option => (\n <ComboboxOptionItem key={option.id} option={option} />\n ))}\n </ListBoxSection>\n );\n}\n\nfunction renderComboboxOption(\n item: NormalizedOption | NormalizedOptionSection,\n) {\n if ('options' in item) {\n return <ComboboxSectionItems key={item.title} section={item} />;\n }\n\n return <ComboboxOptionItem key={item.id} option={item} />;\n}\n\nfunction getCollectionFilter<T extends CollectionItem>({\n search,\n hasItems,\n inputValue,\n contains,\n}: {\n search?: ComboboxListBoxOwnProps<T>['search'];\n hasItems: boolean;\n inputValue: string;\n contains: (textValue: string, inputValue: string) => boolean;\n}) {\n const searchProps = typeof search === 'object' ? search : undefined;\n if (searchProps?.mode === 'server') {\n return undefined;\n }\n\n const customFilter = searchProps?.filter;\n if (customFilter) {\n return (_textValue: string, node: Node<T>) =>\n customFilter(node.value as T, inputValue);\n }\n\n if (search || hasItems) {\n return (textValue: string) => contains(textValue, inputValue);\n }\n\n return undefined;\n}\n\nfunction ComboboxCollection<T extends CollectionItem>({\n normalizedOptions,\n items,\n children,\n dependencies,\n getItemTextValue,\n}: {\n normalizedOptions?: Array<NormalizedOption | NormalizedOptionSection>;\n items?: Iterable<T>;\n children?: React.ReactNode | ((item: T) => React.ReactElement);\n dependencies?: ReadonlyArray<unknown>;\n getItemTextValue?: (item: T) => string;\n}) {\n if (normalizedOptions) {\n return <>{normalizedOptions.map(renderComboboxOption)}</>;\n }\n\n if (items) {\n const renderItemWithTextValue = (item: T) => {\n let renderedItem: React.ReactElement;\n if (typeof children === 'function') {\n renderedItem = children(item);\n } else {\n renderedItem = (\n <ComboboxOptionItem option={item as unknown as NormalizedOption} />\n );\n }\n\n if (!getItemTextValue) {\n return renderedItem;\n }\n\n return cloneElement(renderedItem, {\n textValue: getItemTextValue(item),\n });\n };\n\n return (\n <Collection items={items} dependencies={dependencies}>\n {renderItemWithTextValue}\n </Collection>\n );\n }\n\n return children as React.ReactNode;\n}\n\nfunction ComboboxEmptyState({\n isLoading,\n className,\n rowClassName,\n}: {\n isLoading: boolean;\n className: string;\n rowClassName: string;\n}) {\n if (!isLoading) {\n return <NoResults />;\n }\n\n return (\n <LoadingRows count={3} className={className} rowClassName={rowClassName} />\n );\n}\n\nfunction ComboboxLoadMoreIndicator({\n loading,\n isCollectionLoading,\n isIndicatorVisible,\n className,\n rowClassName,\n}: {\n loading?: LoadingConfig;\n isCollectionLoading: boolean;\n isIndicatorVisible: boolean;\n className: string;\n rowClassName: string;\n}) {\n if (!loading?.onLoadMore || isCollectionLoading) {\n return null;\n }\n\n const onLoadMore =\n loading.state === 'loadingMore' ? undefined : loading.onLoadMore;\n\n return (\n <ListBoxLoadMoreItem\n isLoading={isIndicatorVisible}\n onLoadMore={onLoadMore}\n scrollOffset={0}\n >\n <LoadingRows\n count={1}\n className={className}\n rowClassName={rowClassName}\n />\n </ListBoxLoadMoreItem>\n );\n}\n\nexport function ComboboxListBox<T extends CollectionItem>(\n props: ComboboxListBoxOwnProps<T>,\n) {\n const { ownProps } = useDefinition(ComboboxListBoxDefinition, props);\n const {\n classes,\n options,\n items,\n children,\n dependencies,\n search,\n loading,\n isStale,\n getItemTextValue,\n } = ownProps;\n const normalizedOptions = options && normalizeOptions(options);\n const state = useContext(ComboBoxStateContext);\n const { contains } = useFilter({ sensitivity: 'base' });\n const inputValue = state?.inputValue ?? '';\n const filter = getCollectionFilter({\n search,\n hasItems: items !== undefined,\n inputValue,\n contains,\n });\n const isCollectionLoading =\n loading?.state === 'loading' ||\n loading?.state === 'filtering' ||\n loading?.state === 'sorting';\n const isBusy = isCollectionLoading || loading?.state === 'loadingMore';\n const showStale = useDelayedVisibility(\n isStale ?? false,\n loadingIndicatorDelayMs,\n );\n const showLoadMoreIndicator = useDelayedVisibility(\n loading?.state === 'loadingMore',\n loadingIndicatorDelayMs,\n );\n\n const listBox = (\n <ListBox\n className={classes.root}\n data-stale={showStale || undefined}\n renderEmptyState={() => (\n <ComboboxEmptyState\n isLoading={isCollectionLoading}\n className={classes.loading}\n rowClassName={classes.loadingRow}\n />\n )}\n >\n <ComboboxCollection\n normalizedOptions={normalizedOptions}\n items={items}\n dependencies={dependencies}\n getItemTextValue={getItemTextValue}\n >\n {children}\n </ComboboxCollection>\n <ComboboxLoadMoreIndicator\n loading={loading}\n isCollectionLoading={isCollectionLoading}\n isIndicatorVisible={showLoadMoreIndicator}\n className={classes.loading}\n rowClassName={classes.loadingRow}\n />\n </ListBox>\n );\n\n const busyListBox = <div aria-busy={isBusy || undefined}>{listBox}</div>;\n\n if (!filter) {\n return busyListBox;\n }\n\n return (\n <SelectableCollectionContext.Provider value={{ filter }}>\n {busyListBox}\n </SelectableCollectionContext.Provider>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -18,6 +18,11 @@ const ComboboxDefinition = defineComponent()({
18
18
  icon: {},
19
19
  size: { dataAttribute: true, default: "small" },
20
20
  options: {},
21
+ items: {},
22
+ children: {},
23
+ dependencies: {},
24
+ search: {},
25
+ loading: {},
21
26
  placeholder: {},
22
27
  label: {},
23
28
  secondaryLabel: {},
@@ -46,10 +51,19 @@ const ComboboxListBoxDefinition = defineComponent()({
46
51
  styles,
47
52
  classNames: {
48
53
  root: "bui-ComboboxList",
49
- noResults: "bui-ComboboxNoResults"
54
+ noResults: "bui-ComboboxNoResults",
55
+ loading: "bui-ComboboxLoading",
56
+ loadingRow: "bui-ComboboxLoadingRow"
50
57
  },
51
58
  propDefs: {
52
- options: {}
59
+ options: {},
60
+ items: {},
61
+ children: {},
62
+ dependencies: {},
63
+ search: {},
64
+ loading: {},
65
+ isStale: {},
66
+ getItemTextValue: {}
53
67
  }
54
68
  });
55
69
  const ComboboxListBoxItemDefinition = defineComponent()({
@@ -61,6 +75,51 @@ const ComboboxListBoxItemDefinition = defineComponent()({
61
75
  },
62
76
  propDefs: {}
63
77
  });
78
+ const ComboboxItemDefinition = defineComponent()({
79
+ styles,
80
+ classNames: {
81
+ root: "bui-ComboboxItem",
82
+ indicator: "bui-ComboboxItemIndicator",
83
+ content: "bui-ComboboxItemContent"
84
+ },
85
+ propDefs: {
86
+ children: {},
87
+ textValue: {},
88
+ showSelectionIndicator: {},
89
+ className: {}
90
+ }
91
+ });
92
+ const ComboboxItemTextDefinition = defineComponent()({
93
+ styles,
94
+ classNames: {
95
+ root: "bui-ComboboxItemText",
96
+ leadingIcon: "bui-ComboboxItemTextLeadingIcon",
97
+ text: "bui-ComboboxItemTextContent",
98
+ title: "bui-ComboboxItemTitle",
99
+ description: "bui-ComboboxItemDescription"
100
+ },
101
+ propDefs: {
102
+ title: {},
103
+ description: {},
104
+ leadingIcon: {},
105
+ textValue: {},
106
+ className: {}
107
+ }
108
+ });
109
+ const ComboboxItemProfileDefinition = defineComponent()({
110
+ styles,
111
+ classNames: {
112
+ root: "bui-ComboboxItemProfile",
113
+ avatar: "bui-ComboboxItemAvatar",
114
+ name: "bui-ComboboxItemTitle"
115
+ },
116
+ propDefs: {
117
+ name: {},
118
+ src: {},
119
+ textValue: {},
120
+ className: {}
121
+ }
122
+ });
64
123
  const ComboboxSectionDefinition = defineComponent()({
65
124
  styles,
66
125
  classNames: {
@@ -70,5 +129,5 @@ const ComboboxSectionDefinition = defineComponent()({
70
129
  propDefs: {}
71
130
  });
72
131
 
73
- export { ComboboxDefinition, ComboboxInputDefinition, ComboboxListBoxDefinition, ComboboxListBoxItemDefinition, ComboboxSectionDefinition };
132
+ export { ComboboxDefinition, ComboboxInputDefinition, ComboboxItemDefinition, ComboboxItemProfileDefinition, ComboboxItemTextDefinition, ComboboxListBoxDefinition, ComboboxListBoxItemDefinition, ComboboxSectionDefinition };
74
133
  //# sourceMappingURL=definition.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"definition.esm.js","sources":["../../../src/components/Combobox/definition.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { defineComponent } from '../../hooks/useDefinition';\nimport type {\n ComboboxOwnProps,\n ComboboxInputOwnProps,\n ComboboxListBoxOwnProps,\n ComboboxListBoxItemOwnProps,\n ComboboxSectionOwnProps,\n} from './types';\nimport styles from './Combobox.module.css';\n\n/**\n * Component definition for Combobox\n * @public\n */\nexport const ComboboxDefinition = defineComponent<ComboboxOwnProps>()({\n styles,\n classNames: {\n root: 'bui-Combobox',\n popover: 'bui-ComboboxPopover',\n },\n propDefs: {\n icon: {},\n size: { dataAttribute: true, default: 'small' },\n options: {},\n placeholder: {},\n label: {},\n secondaryLabel: {},\n description: {},\n isRequired: {},\n className: {},\n },\n});\n\n/**\n * Component definition for ComboboxInput\n * @public\n */\nexport const ComboboxInputDefinition = defineComponent<ComboboxInputOwnProps>()(\n {\n styles,\n classNames: {\n root: 'bui-ComboboxInput',\n icon: 'bui-ComboboxInputIcon',\n input: 'bui-ComboboxInputField',\n chevron: 'bui-ComboboxInputChevron',\n },\n bg: 'consumer',\n propDefs: {\n icon: {},\n placeholder: {},\n },\n },\n);\n\n/**\n * Component definition for ComboboxListBox\n * @public\n */\nexport const ComboboxListBoxDefinition =\n defineComponent<ComboboxListBoxOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxList',\n noResults: 'bui-ComboboxNoResults',\n },\n propDefs: {\n options: {},\n },\n });\n\n/**\n * Component definition for ComboboxListBoxItem\n * @public\n */\nexport const ComboboxListBoxItemDefinition =\n defineComponent<ComboboxListBoxItemOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxItem',\n indicator: 'bui-ComboboxItemIndicator',\n label: 'bui-ComboboxItemLabel',\n },\n propDefs: {},\n });\n\n/**\n * Component definition for ComboboxSection\n * @public\n */\nexport const ComboboxSectionDefinition =\n defineComponent<ComboboxSectionOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxSection',\n header: 'bui-ComboboxSectionHeader',\n },\n propDefs: {},\n });\n"],"names":[],"mappings":";;;;;;;;;;AA8BO,MAAM,kBAAA,GAAqB,iBAAkC,CAAE;AAAA,EACpE,MAAA;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM,cAAA;AAAA,IACN,OAAA,EAAS;AAAA,GACX;AAAA,EACA,QAAA,EAAU;AAAA,IACR,MAAM,EAAC;AAAA,IACP,IAAA,EAAM,EAAE,aAAA,EAAe,IAAA,EAAM,SAAS,OAAA,EAAQ;AAAA,IAC9C,SAAS,EAAC;AAAA,IACV,aAAa,EAAC;AAAA,IACd,OAAO,EAAC;AAAA,IACR,gBAAgB,EAAC;AAAA,IACjB,aAAa,EAAC;AAAA,IACd,YAAY,EAAC;AAAA,IACb,WAAW;AAAC;AAEhB,CAAC;AAMM,MAAM,0BAA0B,eAAA,EAAuC;AAAA,EAC5E;AAAA,IACE,MAAA;AAAA,IACA,UAAA,EAAY;AAAA,MACV,IAAA,EAAM,mBAAA;AAAA,MACN,IAAA,EAAM,uBAAA;AAAA,MACN,KAAA,EAAO,wBAAA;AAAA,MACP,OAAA,EAAS;AAAA,KACX;AAAA,IACA,EAAA,EAAI,UAAA;AAAA,IACJ,QAAA,EAAU;AAAA,MACR,MAAM,EAAC;AAAA,MACP,aAAa;AAAC;AAChB;AAEJ;AAMO,MAAM,yBAAA,GACX,iBAAyC,CAAE;AAAA,EACzC,MAAA;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM,kBAAA;AAAA,IACN,SAAA,EAAW;AAAA,GACb;AAAA,EACA,QAAA,EAAU;AAAA,IACR,SAAS;AAAC;AAEd,CAAC;AAMI,MAAM,6BAAA,GACX,iBAA6C,CAAE;AAAA,EAC7C,MAAA;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM,kBAAA;AAAA,IACN,SAAA,EAAW,2BAAA;AAAA,IACX,KAAA,EAAO;AAAA,GACT;AAAA,EACA,UAAU;AACZ,CAAC;AAMI,MAAM,yBAAA,GACX,iBAAyC,CAAE;AAAA,EACzC,MAAA;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM,qBAAA;AAAA,IACN,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,UAAU;AACZ,CAAC;;;;"}
1
+ {"version":3,"file":"definition.esm.js","sources":["../../../src/components/Combobox/definition.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { defineComponent } from '../../hooks/useDefinition';\nimport type {\n ComboboxOwnProps,\n ComboboxInputOwnProps,\n ComboboxItemOwnProps,\n ComboboxItemProfileOwnProps,\n ComboboxItemTextOwnProps,\n ComboboxListBoxOwnProps,\n ComboboxListBoxItemOwnProps,\n ComboboxSectionOwnProps,\n} from './types';\nimport styles from './Combobox.module.css';\n\n/** @public */\nexport const ComboboxDefinition = defineComponent<ComboboxOwnProps>()({\n styles,\n classNames: {\n root: 'bui-Combobox',\n popover: 'bui-ComboboxPopover',\n },\n propDefs: {\n icon: {},\n size: { dataAttribute: true, default: 'small' },\n options: {},\n items: {},\n children: {},\n dependencies: {},\n search: {},\n loading: {},\n placeholder: {},\n label: {},\n secondaryLabel: {},\n description: {},\n isRequired: {},\n className: {},\n },\n});\n\n/** @public */\nexport const ComboboxInputDefinition = defineComponent<ComboboxInputOwnProps>()(\n {\n styles,\n classNames: {\n root: 'bui-ComboboxInput',\n icon: 'bui-ComboboxInputIcon',\n input: 'bui-ComboboxInputField',\n chevron: 'bui-ComboboxInputChevron',\n },\n bg: 'consumer',\n propDefs: {\n icon: {},\n placeholder: {},\n },\n },\n);\n\n/** @public */\nexport const ComboboxListBoxDefinition = defineComponent<\n ComboboxListBoxOwnProps<any>\n>()({\n styles,\n classNames: {\n root: 'bui-ComboboxList',\n noResults: 'bui-ComboboxNoResults',\n loading: 'bui-ComboboxLoading',\n loadingRow: 'bui-ComboboxLoadingRow',\n },\n propDefs: {\n options: {},\n items: {},\n children: {},\n dependencies: {},\n search: {},\n loading: {},\n isStale: {},\n getItemTextValue: {},\n },\n});\n\n/** @public */\nexport const ComboboxListBoxItemDefinition =\n defineComponent<ComboboxListBoxItemOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxItem',\n indicator: 'bui-ComboboxItemIndicator',\n label: 'bui-ComboboxItemLabel',\n },\n propDefs: {},\n });\n\n/** @public */\nexport const ComboboxItemDefinition = defineComponent<ComboboxItemOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxItem',\n indicator: 'bui-ComboboxItemIndicator',\n content: 'bui-ComboboxItemContent',\n },\n propDefs: {\n children: {},\n textValue: {},\n showSelectionIndicator: {},\n className: {},\n },\n});\n\n/** @public */\nexport const ComboboxItemTextDefinition =\n defineComponent<ComboboxItemTextOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxItemText',\n leadingIcon: 'bui-ComboboxItemTextLeadingIcon',\n text: 'bui-ComboboxItemTextContent',\n title: 'bui-ComboboxItemTitle',\n description: 'bui-ComboboxItemDescription',\n },\n propDefs: {\n title: {},\n description: {},\n leadingIcon: {},\n textValue: {},\n className: {},\n },\n });\n\n/** @public */\nexport const ComboboxItemProfileDefinition =\n defineComponent<ComboboxItemProfileOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxItemProfile',\n avatar: 'bui-ComboboxItemAvatar',\n name: 'bui-ComboboxItemTitle',\n },\n propDefs: {\n name: {},\n src: {},\n textValue: {},\n className: {},\n },\n });\n\n/** @public */\nexport const ComboboxSectionDefinition =\n defineComponent<ComboboxSectionOwnProps>()({\n styles,\n classNames: {\n root: 'bui-ComboboxSection',\n header: 'bui-ComboboxSectionHeader',\n },\n propDefs: {},\n });\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import { useState, useRef, useCallback, useEffect } from 'react';
2
+
3
+ function getItemTextValue(item) {
4
+ return "textValue" in item ? item.textValue : item.label;
5
+ }
6
+ function resolveNextSelectedItem({
7
+ key,
8
+ currentItem,
9
+ sourceItems,
10
+ isControlled
11
+ }) {
12
+ if (key === null) {
13
+ return null;
14
+ }
15
+ if (isControlled && currentItem?.id === key) {
16
+ return currentItem;
17
+ }
18
+ return sourceItems.find((item) => item.id === key) ?? currentItem;
19
+ }
20
+ function useAsyncComboboxState(props) {
21
+ const isEnabled = props !== void 0;
22
+ const { source, value, defaultValue, onChange, allowsCustomValue } = props ?? {};
23
+ const isControlled = value !== void 0;
24
+ const [uncontrolledValue, setUncontrolledValue] = useState(
25
+ defaultValue ?? null
26
+ );
27
+ const selectedItem = isControlled ? value ?? null : uncontrolledValue;
28
+ const selectedItemRef = useRef(selectedItem);
29
+ const sourceItemsRef = useRef([]);
30
+ const inputValueRef = useRef("");
31
+ const sourceFilterText = source?.filterText ?? "";
32
+ const setSourceFilterText = source?.setFilterText;
33
+ const sourceFilterTextRef = useRef(sourceFilterText);
34
+ const preserveInputOnClearRef = useRef(false);
35
+ const [inputValue, setInputValue] = useState(
36
+ () => selectedItem ? getAsyncComboboxItemTextValue(selectedItem) : sourceFilterText
37
+ );
38
+ selectedItemRef.current = selectedItem;
39
+ sourceItemsRef.current = source ? [...source.items] : [];
40
+ inputValueRef.current = inputValue;
41
+ sourceFilterTextRef.current = sourceFilterText;
42
+ const updateInputValue = useCallback(
43
+ (nextInputValue) => {
44
+ setInputValue(nextInputValue);
45
+ if (isEnabled && setSourceFilterText && sourceFilterTextRef.current !== nextInputValue) {
46
+ sourceFilterTextRef.current = nextInputValue;
47
+ setSourceFilterText(nextInputValue);
48
+ }
49
+ },
50
+ [isEnabled, setSourceFilterText]
51
+ );
52
+ useEffect(() => {
53
+ if (isEnabled) {
54
+ setInputValue(sourceFilterText);
55
+ }
56
+ }, [isEnabled, sourceFilterText]);
57
+ const selectedId = selectedItem?.id ?? null;
58
+ const selectedTextValue = selectedItem ? getAsyncComboboxItemTextValue(selectedItem) : void 0;
59
+ const previousSelectedId = useRef(null);
60
+ const previousSelectedTextValue = useRef();
61
+ useEffect(() => {
62
+ if (!isEnabled) {
63
+ return;
64
+ }
65
+ const selectionChanged = previousSelectedId.current !== selectedId || previousSelectedTextValue.current !== selectedTextValue;
66
+ previousSelectedId.current = selectedId;
67
+ previousSelectedTextValue.current = selectedTextValue;
68
+ if (selectionChanged) {
69
+ if (selectedTextValue !== void 0) {
70
+ updateInputValue(selectedTextValue);
71
+ } else if (preserveInputOnClearRef.current) {
72
+ preserveInputOnClearRef.current = false;
73
+ } else {
74
+ updateInputValue("");
75
+ }
76
+ }
77
+ }, [isEnabled, selectedId, selectedTextValue, updateInputValue]);
78
+ const freshSelectedItem = selectedItem ? sourceItemsRef.current.find((item) => item.id === selectedItem.id) : void 0;
79
+ const isEditing = selectedTextValue !== void 0 && inputValueRef.current !== selectedTextValue;
80
+ useEffect(() => {
81
+ if (isEnabled && !isControlled && !isEditing && freshSelectedItem && freshSelectedItem !== selectedItemRef.current) {
82
+ setUncontrolledValue(freshSelectedItem);
83
+ }
84
+ }, [freshSelectedItem, isControlled, isEditing, isEnabled]);
85
+ const handleChange = useCallback(
86
+ (key) => {
87
+ const currentItem = selectedItemRef.current;
88
+ const currentTextValue = currentItem ? getAsyncComboboxItemTextValue(currentItem) : void 0;
89
+ if (key === null && allowsCustomValue && currentTextValue === inputValueRef.current) {
90
+ updateInputValue(currentTextValue);
91
+ return;
92
+ }
93
+ if (key === null && allowsCustomValue && currentItem) {
94
+ preserveInputOnClearRef.current = true;
95
+ }
96
+ if (key === null && !currentItem && !allowsCustomValue) {
97
+ updateInputValue("");
98
+ return;
99
+ }
100
+ const nextItem = resolveNextSelectedItem({
101
+ key,
102
+ currentItem,
103
+ sourceItems: sourceItemsRef.current,
104
+ isControlled
105
+ });
106
+ if (nextItem) {
107
+ updateInputValue(getAsyncComboboxItemTextValue(nextItem));
108
+ }
109
+ if (!isControlled) {
110
+ setUncontrolledValue(nextItem);
111
+ }
112
+ if (nextItem?.id !== currentItem?.id) {
113
+ onChange?.(nextItem);
114
+ }
115
+ },
116
+ [allowsCustomValue, isControlled, onChange, updateInputValue]
117
+ );
118
+ if (!isEnabled) {
119
+ return void 0;
120
+ }
121
+ return {
122
+ value: selectedItem?.id ?? null,
123
+ inputValue,
124
+ onChange: handleChange,
125
+ onInputChange: updateInputValue
126
+ };
127
+ }
128
+ function getAsyncComboboxItemTextValue(item) {
129
+ return getItemTextValue(item);
130
+ }
131
+
132
+ export { getAsyncComboboxItemTextValue, useAsyncComboboxState };
133
+ //# sourceMappingURL=useAsyncComboboxState.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAsyncComboboxState.esm.js","sources":["../../../src/components/Combobox/useAsyncComboboxState.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { Key } from 'react-aria-components';\nimport type {\n AsyncListSource,\n CollectionItem,\n} from '../../types/selectableCollection';\n\ntype AsyncComboboxItem = CollectionItem &\n ({ textValue: string } | { label: string });\n\nfunction getItemTextValue(item: AsyncComboboxItem) {\n return 'textValue' in item ? item.textValue : item.label;\n}\n\nfunction resolveNextSelectedItem<T extends CollectionItem>({\n key,\n currentItem,\n sourceItems,\n isControlled,\n}: {\n key: Key | null;\n currentItem: T | null;\n sourceItems: T[];\n isControlled: boolean;\n}) {\n if (key === null) {\n return null;\n }\n\n if (isControlled && currentItem?.id === key) {\n return currentItem;\n }\n\n return sourceItems.find(item => item.id === key) ?? currentItem;\n}\n\ntype UseAsyncComboboxStateProps<T extends CollectionItem> = {\n source: AsyncListSource<T>;\n value?: T | null;\n defaultValue?: T | null;\n onChange?: (value: T | null) => void;\n allowsCustomValue?: boolean;\n};\n\n/** @internal */\nexport function useAsyncComboboxState<T extends CollectionItem>(\n props?: UseAsyncComboboxStateProps<T>,\n) {\n const isEnabled = props !== undefined;\n const { source, value, defaultValue, onChange, allowsCustomValue } =\n props ?? {};\n const isControlled = value !== undefined;\n const [uncontrolledValue, setUncontrolledValue] = useState<T | null>(\n defaultValue ?? null,\n );\n const selectedItem = isControlled ? value ?? null : uncontrolledValue;\n const selectedItemRef = useRef(selectedItem);\n const sourceItemsRef = useRef<T[]>([]);\n const inputValueRef = useRef('');\n const sourceFilterText = source?.filterText ?? '';\n const setSourceFilterText = source?.setFilterText;\n const sourceFilterTextRef = useRef(sourceFilterText);\n const preserveInputOnClearRef = useRef(false);\n const [inputValue, setInputValue] = useState(() =>\n selectedItem\n ? getAsyncComboboxItemTextValue(selectedItem)\n : sourceFilterText,\n );\n\n selectedItemRef.current = selectedItem;\n sourceItemsRef.current = source ? [...source.items] : [];\n inputValueRef.current = inputValue;\n sourceFilterTextRef.current = sourceFilterText;\n\n const updateInputValue = useCallback(\n (nextInputValue: string) => {\n setInputValue(nextInputValue);\n if (\n isEnabled &&\n setSourceFilterText &&\n sourceFilterTextRef.current !== nextInputValue\n ) {\n sourceFilterTextRef.current = nextInputValue;\n setSourceFilterText(nextInputValue);\n }\n },\n [isEnabled, setSourceFilterText],\n );\n\n useEffect(() => {\n if (isEnabled) {\n setInputValue(sourceFilterText);\n }\n }, [isEnabled, sourceFilterText]);\n\n const selectedId = selectedItem?.id ?? null;\n const selectedTextValue = selectedItem\n ? getAsyncComboboxItemTextValue(selectedItem)\n : undefined;\n const previousSelectedId = useRef<Key | null>(null);\n const previousSelectedTextValue = useRef<string>();\n\n useEffect(() => {\n if (!isEnabled) {\n return;\n }\n\n const selectionChanged =\n previousSelectedId.current !== selectedId ||\n previousSelectedTextValue.current !== selectedTextValue;\n\n previousSelectedId.current = selectedId;\n previousSelectedTextValue.current = selectedTextValue;\n\n if (selectionChanged) {\n if (selectedTextValue !== undefined) {\n updateInputValue(selectedTextValue);\n } else if (preserveInputOnClearRef.current) {\n preserveInputOnClearRef.current = false;\n } else {\n updateInputValue('');\n }\n }\n }, [isEnabled, selectedId, selectedTextValue, updateInputValue]);\n\n const freshSelectedItem = selectedItem\n ? sourceItemsRef.current.find(item => item.id === selectedItem.id)\n : undefined;\n const isEditing =\n selectedTextValue !== undefined &&\n inputValueRef.current !== selectedTextValue;\n\n useEffect(() => {\n if (\n isEnabled &&\n !isControlled &&\n !isEditing &&\n freshSelectedItem &&\n freshSelectedItem !== selectedItemRef.current\n ) {\n setUncontrolledValue(freshSelectedItem);\n }\n }, [freshSelectedItem, isControlled, isEditing, isEnabled]);\n\n const handleChange = useCallback(\n (key: Key | null) => {\n const currentItem = selectedItemRef.current;\n const currentTextValue = currentItem\n ? getAsyncComboboxItemTextValue(currentItem)\n : undefined;\n\n if (\n key === null &&\n allowsCustomValue &&\n currentTextValue === inputValueRef.current\n ) {\n updateInputValue(currentTextValue);\n return;\n }\n\n if (key === null && allowsCustomValue && currentItem) {\n preserveInputOnClearRef.current = true;\n }\n\n if (key === null && !currentItem && !allowsCustomValue) {\n updateInputValue('');\n return;\n }\n\n const nextItem = resolveNextSelectedItem({\n key,\n currentItem,\n sourceItems: sourceItemsRef.current,\n isControlled,\n });\n\n if (nextItem) {\n updateInputValue(getAsyncComboboxItemTextValue(nextItem));\n }\n\n if (!isControlled) {\n setUncontrolledValue(nextItem);\n }\n\n if (nextItem?.id !== currentItem?.id) {\n onChange?.(nextItem);\n }\n },\n [allowsCustomValue, isControlled, onChange, updateInputValue],\n );\n\n if (!isEnabled) {\n return undefined;\n }\n\n return {\n value: selectedItem?.id ?? null,\n inputValue,\n onChange: handleChange,\n onInputChange: updateInputValue,\n };\n}\n\n/** @internal */\nexport function getAsyncComboboxItemTextValue(item: CollectionItem) {\n return getItemTextValue(item as AsyncComboboxItem);\n}\n"],"names":[],"mappings":"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"}
@@ -37,7 +37,6 @@ function HeaderNavLink(props) {
37
37
  linkRef.current = el;
38
38
  registerRef(id, el);
39
39
  },
40
- href,
41
40
  className: ownProps.classes.root,
42
41
  "aria-current": active ? "page" : void 0,
43
42
  onClick: handleClick,