@salesforce/ui-bundle-template-feature-react-search 11.24.4 → 11.24.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [11.24.7](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.24.6...v11.24.7) (2026-07-14)
7
+
8
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
9
+
10
+
11
+
12
+
13
+
14
+ ## [11.24.6](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.24.5...v11.24.6) (2026-07-14)
15
+
16
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
17
+
18
+
19
+
20
+
21
+
22
+ ## [11.24.5](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.24.4...v11.24.5) (2026-07-14)
23
+
24
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
25
+
26
+
27
+
28
+
29
+
6
30
  ## [11.24.4](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.24.3...v11.24.4) (2026-07-14)
7
31
 
8
32
  **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
@@ -18,8 +18,8 @@
18
18
  "graphql:schema": "node scripts/get-graphql-schema.mjs"
19
19
  },
20
20
  "dependencies": {
21
- "@salesforce/platform-sdk": "^11.24.4",
22
- "@salesforce/ui-bundle": "^11.24.4",
21
+ "@salesforce/platform-sdk": "^11.24.7",
22
+ "@salesforce/ui-bundle": "^11.24.7",
23
23
  "@tailwindcss/vite": "^4.1.17",
24
24
  "class-variance-authority": "^0.7.1",
25
25
  "clsx": "^2.1.1",
@@ -44,8 +44,8 @@
44
44
  "@graphql-eslint/eslint-plugin": "^4.1.0",
45
45
  "@graphql-tools/utils": "^11.0.0",
46
46
  "@playwright/test": "^1.49.0",
47
- "@salesforce/graphiti": "^11.24.4",
48
- "@salesforce/vite-plugin-ui-bundle": "^11.24.4",
47
+ "@salesforce/graphiti": "^11.24.7",
48
+ "@salesforce/vite-plugin-ui-bundle": "^11.24.7",
49
49
  "@testing-library/jest-dom": "^6.6.3",
50
50
  "@testing-library/react": "^16.1.0",
51
51
  "@testing-library/user-event": "^14.5.2",
@@ -108,8 +108,22 @@ export function MergedSearchResults({
108
108
 
109
109
  const skeletons = skeletonCount ?? page.pageSize;
110
110
 
111
+ // Persistent, always-mounted live region: screen readers announce result
112
+ // updates (searching → count → empty → error) without an Enter keypress.
113
+ const liveMessage = loading
114
+ ? "Searching…"
115
+ : error
116
+ ? "Search failed."
117
+ : mergedResults.length === 0
118
+ ? (emptyMessage ?? "No results found.")
119
+ : `${page.totalCount} result${page.totalCount === 1 ? "" : "s"}`;
120
+
111
121
  return (
112
122
  <div className={`space-y-6 ${className ?? ""}`}>
123
+ <p className="sr-only" role="status" aria-live="polite">
124
+ {liveMessage}
125
+ </p>
126
+
113
127
  {soleController && <SingleSourceChrome controller={soleController} />}
114
128
 
115
129
  {error && (
@@ -123,7 +137,7 @@ export function MergedSearchResults({
123
137
  {/* Results count — its own row, directly above the grid, in every scope.
124
138
  Hidden when there are none (the empty state covers that case). */}
125
139
  {!loading && !error && page.totalCount > 0 && (
126
- <p className="text-sm text-muted-foreground" role="status">
140
+ <p className="text-sm text-muted-foreground">
127
141
  {page.totalCount} result{page.totalCount === 1 ? "" : "s"}
128
142
  </p>
129
143
  )}
@@ -139,7 +153,7 @@ export function MergedSearchResults({
139
153
  {emptyMessage ?? "No results found."}
140
154
  </p>
141
155
  ) : (
142
- <div className={gridClassName}>
156
+ <ul className={gridClassName}>
143
157
  {mergedResults.map(({ sourceKey, node }, i) => {
144
158
  const override = renderResult?.[sourceKey];
145
159
  if (override === false) return null;
@@ -157,16 +171,16 @@ export function MergedSearchResults({
157
171
  />
158
172
  ) : null;
159
173
  return (
160
- <div
174
+ <li
161
175
  key={getItemKey(sourceKey, node, i)}
162
176
  className="flex flex-col gap-1.5 [&>:last-child]:min-h-0 [&>:last-child]:flex-1"
163
177
  >
164
178
  {badge}
165
179
  {rendered}
166
- </div>
180
+ </li>
167
181
  );
168
182
  })}
169
- </div>
183
+ </ul>
170
184
  )}
171
185
 
172
186
  {page.totalCount > 0 && (
@@ -58,8 +58,24 @@ export function SourceSection({
58
58
  const showActiveChips = !hideFilterChrome && filters.active.length > 0;
59
59
  const showSortControl = !hideFilterChrome && (config.sortBy?.length ?? 0) > 0;
60
60
 
61
+ // Persistent, always-mounted live region: screen readers announce result
62
+ // updates (searching → count → empty → error) without an Enter keypress.
63
+ const liveMessage = loading
64
+ ? "Searching…"
65
+ : error
66
+ ? `Failed to load ${config.label}.`
67
+ : showEmpty
68
+ ? (emptyMessage ?? `No ${config.label.toLowerCase()} found.`)
69
+ : totalCount != null
70
+ ? `${config.label}: ${totalCount} ${totalCount === 1 ? "result" : "results"}`
71
+ : "";
72
+
61
73
  return (
62
74
  <section className={`flex flex-col gap-6 ${className ?? ""}`}>
75
+ <p className="sr-only" role="status" aria-live="polite">
76
+ {liveMessage}
77
+ </p>
78
+
63
79
  {showFilterPanel && (
64
80
  <FilterProvider
65
81
  filters={filters.active}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
3
- "version": "11.24.4",
3
+ "version": "11.24.7",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
9
- "version": "11.24.4",
9
+ "version": "11.24.7",
10
10
  "license": "SEE LICENSE IN LICENSE.txt",
11
11
  "dependencies": {
12
12
  "fast-xml-parser": "^5.9.3",
@@ -9964,9 +9964,9 @@
9964
9964
  "license": "ISC"
9965
9965
  },
9966
9966
  "node_modules/yaml": {
9967
- "version": "2.8.2",
9968
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
9969
- "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
9967
+ "version": "2.9.0",
9968
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
9969
+ "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
9970
9970
  "dev": true,
9971
9971
  "license": "ISC",
9972
9972
  "bin": {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
3
- "version": "11.24.4",
3
+ "version": "11.24.7",
4
4
  "description": "Base SFDX project template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "publishConfig": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-feature-react-search",
3
- "version": "11.24.4",
3
+ "version": "11.24.7",
4
4
  "description": "[Beta] Configuration-driven multi-source search for UI Bundles",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "",
@@ -108,8 +108,22 @@ export function MergedSearchResults({
108
108
 
109
109
  const skeletons = skeletonCount ?? page.pageSize;
110
110
 
111
+ // Persistent, always-mounted live region: screen readers announce result
112
+ // updates (searching → count → empty → error) without an Enter keypress.
113
+ const liveMessage = loading
114
+ ? "Searching…"
115
+ : error
116
+ ? "Search failed."
117
+ : mergedResults.length === 0
118
+ ? (emptyMessage ?? "No results found.")
119
+ : `${page.totalCount} result${page.totalCount === 1 ? "" : "s"}`;
120
+
111
121
  return (
112
122
  <div className={`space-y-6 ${className ?? ""}`}>
123
+ <p className="sr-only" role="status" aria-live="polite">
124
+ {liveMessage}
125
+ </p>
126
+
113
127
  {soleController && <SingleSourceChrome controller={soleController} />}
114
128
 
115
129
  {error && (
@@ -123,7 +137,7 @@ export function MergedSearchResults({
123
137
  {/* Results count — its own row, directly above the grid, in every scope.
124
138
  Hidden when there are none (the empty state covers that case). */}
125
139
  {!loading && !error && page.totalCount > 0 && (
126
- <p className="text-sm text-muted-foreground" role="status">
140
+ <p className="text-sm text-muted-foreground">
127
141
  {page.totalCount} result{page.totalCount === 1 ? "" : "s"}
128
142
  </p>
129
143
  )}
@@ -139,7 +153,7 @@ export function MergedSearchResults({
139
153
  {emptyMessage ?? "No results found."}
140
154
  </p>
141
155
  ) : (
142
- <div className={gridClassName}>
156
+ <ul className={gridClassName}>
143
157
  {mergedResults.map(({ sourceKey, node }, i) => {
144
158
  const override = renderResult?.[sourceKey];
145
159
  if (override === false) return null;
@@ -157,16 +171,16 @@ export function MergedSearchResults({
157
171
  />
158
172
  ) : null;
159
173
  return (
160
- <div
174
+ <li
161
175
  key={getItemKey(sourceKey, node, i)}
162
176
  className="flex flex-col gap-1.5 [&>:last-child]:min-h-0 [&>:last-child]:flex-1"
163
177
  >
164
178
  {badge}
165
179
  {rendered}
166
- </div>
180
+ </li>
167
181
  );
168
182
  })}
169
- </div>
183
+ </ul>
170
184
  )}
171
185
 
172
186
  {page.totalCount > 0 && (
@@ -58,8 +58,24 @@ export function SourceSection({
58
58
  const showActiveChips = !hideFilterChrome && filters.active.length > 0;
59
59
  const showSortControl = !hideFilterChrome && (config.sortBy?.length ?? 0) > 0;
60
60
 
61
+ // Persistent, always-mounted live region: screen readers announce result
62
+ // updates (searching → count → empty → error) without an Enter keypress.
63
+ const liveMessage = loading
64
+ ? "Searching…"
65
+ : error
66
+ ? `Failed to load ${config.label}.`
67
+ : showEmpty
68
+ ? (emptyMessage ?? `No ${config.label.toLowerCase()} found.`)
69
+ : totalCount != null
70
+ ? `${config.label}: ${totalCount} ${totalCount === 1 ? "result" : "results"}`
71
+ : "";
72
+
61
73
  return (
62
74
  <section className={`flex flex-col gap-6 ${className ?? ""}`}>
75
+ <p className="sr-only" role="status" aria-live="polite">
76
+ {liveMessage}
77
+ </p>
78
+
63
79
  {showFilterPanel && (
64
80
  <FilterProvider
65
81
  filters={filters.active}