@salesforce/ui-bundle-template-app-react-sample-b2e 11.7.0 → 11.8.1

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 (16) hide show
  1. package/dist/CHANGELOG.md +16 -0
  2. package/dist/force-app/main/default/uiBundles/propertymanagementapp/package.json +4 -4
  3. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/dashboard/IssuesDonutChart.tsx +50 -29
  4. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/properties/PropertyCard.tsx +10 -1
  5. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/ui/button.tsx +1 -1
  6. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/ui/datePicker.tsx +2 -2
  7. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/ui/table.tsx +9 -2
  8. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/DateFilter.tsx +1 -1
  9. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/FilterFieldWrapper.tsx +6 -1
  10. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/MultiSelectFilter.tsx +9 -1
  11. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/ApplicationSearch.tsx +11 -2
  12. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/MaintenanceRequestSearch.tsx +11 -2
  13. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/MaintenanceWorkerSearch.tsx +11 -2
  14. package/dist/package-lock.json +2 -2
  15. package/dist/package.json +1 -1
  16. package/package.json +2 -2
package/dist/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
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.8.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.8.0...v11.8.1) (2026-07-06)
7
+
8
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
9
+
10
+
11
+
12
+
13
+
14
+ ## [11.8.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.7.0...v11.8.0) (2026-07-06)
15
+
16
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
17
+
18
+
19
+
20
+
21
+
6
22
  ## [11.7.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.6.0...v11.7.0) (2026-07-06)
7
23
 
8
24
  **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.7.0",
22
- "@salesforce/ui-bundle": "^11.7.0",
21
+ "@salesforce/platform-sdk": "^11.8.1",
22
+ "@salesforce/ui-bundle": "^11.8.1",
23
23
  "@tailwindcss/vite": "^4.1.17",
24
24
  "class-variance-authority": "^0.7.1",
25
25
  "clsx": "^2.1.1",
@@ -46,8 +46,8 @@
46
46
  "@graphql-eslint/eslint-plugin": "^4.1.0",
47
47
  "@graphql-tools/utils": "^11.0.0",
48
48
  "@playwright/test": "^1.49.0",
49
- "@salesforce/graphiti": "^11.7.0",
50
- "@salesforce/vite-plugin-ui-bundle": "^11.7.0",
49
+ "@salesforce/graphiti": "^11.8.1",
50
+ "@salesforce/vite-plugin-ui-bundle": "^11.8.1",
51
51
  "@testing-library/jest-dom": "^6.6.3",
52
52
  "@testing-library/react": "^16.1.0",
53
53
  "@testing-library/user-event": "^14.5.2",
@@ -45,10 +45,24 @@ export const IssuesDonutChart: React.FC<IssuesDonutChartProps> = ({ data, loadin
45
45
  const maxValue = data.length > 0 ? Math.max(...data.map((item) => item.value)) : 0;
46
46
  const mainPercentage = total > 0 ? Math.round((maxValue / total) * 100) : 0;
47
47
 
48
+ // Recharts renders each sector as an <svg><path role="img">, but arbitrary ARIA
49
+ // props on <Cell> are not reliably forwarded to that path. Instead of labelling
50
+ // each slice, expose the whole chart as a single labelled image summarizing the
51
+ // data, and hide the decorative SVG internals from assistive technology.
52
+ const chartSummary =
53
+ total > 0
54
+ ? `Top maintenance issues: ${data
55
+ .map((item) => `${item.name} ${Math.round((item.value / total) * 100)}%`)
56
+ .join(", ")}.`
57
+ : "Top maintenance issues: no data available.";
58
+
48
59
  return (
49
60
  <Card className="p-4 border-gray-200 shadow-sm flex flex-col relative">
50
61
  {/* Three-dot menu */}
51
- <button className="absolute top-4 right-4 p-1 hover:bg-gray-100 rounded-md transition-colors z-10">
62
+ <button
63
+ className="absolute top-4 right-4 p-1 hover:bg-gray-100 rounded-md transition-colors z-10"
64
+ aria-label="More options"
65
+ >
52
66
  <MoreVertical className="w-4 h-4 text-gray-400" />
53
67
  </button>
54
68
 
@@ -71,34 +85,41 @@ export const IssuesDonutChart: React.FC<IssuesDonutChartProps> = ({ data, loadin
71
85
  </>
72
86
  ) : (
73
87
  <>
74
- <div className="relative flex items-center justify-center">
75
- <ResponsiveContainer width="100%" height={300}>
76
- <PieChart>
77
- <Pie
78
- data={data}
79
- cx="50%"
80
- cy="50%"
81
- innerRadius={70}
82
- outerRadius={110}
83
- paddingAngle={2}
84
- dataKey="value"
85
- >
86
- {data.map((entry, index) => (
87
- <Cell key={`cell-${index}`} fill={entry.color} />
88
- ))}
89
- </Pie>
90
- <Tooltip
91
- content={(props) => (
92
- <CustomTooltip
93
- active={props.active}
94
- payload={props.payload as CustomTooltipProps["payload"]}
95
- total={total}
96
- />
97
- )}
98
- wrapperStyle={{ zIndex: 1000 }}
99
- />
100
- </PieChart>
101
- </ResponsiveContainer>
88
+ <div
89
+ className="relative flex items-center justify-center"
90
+ role="img"
91
+ aria-label={chartSummary}
92
+ >
93
+ <div aria-hidden="true" className="w-full">
94
+ <ResponsiveContainer width="100%" height={300}>
95
+ <PieChart>
96
+ <Pie
97
+ data={data}
98
+ cx="50%"
99
+ cy="50%"
100
+ innerRadius={70}
101
+ outerRadius={110}
102
+ paddingAngle={2}
103
+ dataKey="value"
104
+ rootTabIndex={-1}
105
+ >
106
+ {data.map((entry, index) => (
107
+ <Cell key={`cell-${index}`} fill={entry.color} />
108
+ ))}
109
+ </Pie>
110
+ <Tooltip
111
+ content={(props) => (
112
+ <CustomTooltip
113
+ active={props.active}
114
+ payload={props.payload as CustomTooltipProps["payload"]}
115
+ total={total}
116
+ />
117
+ )}
118
+ wrapperStyle={{ zIndex: 1000 }}
119
+ />
120
+ </PieChart>
121
+ </ResponsiveContainer>
122
+ </div>
102
123
  {/* Center text */}
103
124
  <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
104
125
  <div className="text-center">
@@ -32,8 +32,17 @@ export const PropertyCard: React.FC<PropertyCardProps> = ({ property, onClick })
32
32
 
33
33
  return (
34
34
  <div
35
- className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow cursor-pointer"
35
+ role="button"
36
+ tabIndex={0}
37
+ aria-label={name}
38
+ className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple focus-visible:ring-offset-2"
36
39
  onClick={handleClick}
40
+ onKeyDown={(e) => {
41
+ if (e.key === "Enter" || e.key === " ") {
42
+ e.preventDefault();
43
+ handleClick();
44
+ }
45
+ }}
37
46
  >
38
47
  <div className="relative h-48 bg-gray-200">
39
48
  {heroImage && !imageError ? (
@@ -17,7 +17,7 @@ const buttonVariants = cva(
17
17
  ghost:
18
18
  'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
19
19
  destructive:
20
- 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
20
+ 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-red-700 dark:text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
21
21
  link: 'text-primary underline-offset-4 hover:underline',
22
22
  },
23
23
  size: {
@@ -38,7 +38,7 @@ function DatePickerTrigger({
38
38
  data-slot="date-picker-trigger"
39
39
  data-empty={!date}
40
40
  className={cn(
41
- 'w-[280px] justify-start text-left font-normal data-[empty=true]:text-muted-foreground',
41
+ 'w-[280px] justify-start text-left font-normal data-[empty=true]:text-gray-600',
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -87,7 +87,7 @@ function DatePickerRangeTrigger({
87
87
  data-slot="date-picker-range-trigger"
88
88
  data-empty={!hasDate}
89
89
  className={cn(
90
- 'justify-start text-left font-normal data-[empty=true]:text-muted-foreground',
90
+ 'justify-start text-left font-normal data-[empty=true]:text-gray-600',
91
91
  className
92
92
  )}
93
93
  {...props}
@@ -2,11 +2,18 @@ import * as React from 'react';
2
2
 
3
3
  import { cn } from '../../lib/utils';
4
4
 
5
- function Table({ className, ...props }: React.ComponentProps<'table'>) {
5
+ function Table({
6
+ className,
7
+ 'aria-label': ariaLabel = 'Table',
8
+ ...props
9
+ }: React.ComponentProps<'table'>) {
6
10
  return (
7
11
  <div
8
12
  data-slot="table-container"
9
- className="relative w-full overflow-x-auto"
13
+ role="region"
14
+ aria-label={ariaLabel}
15
+ tabIndex={0}
16
+ className="relative w-full overflow-x-auto focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple"
10
17
  >
11
18
  <table
12
19
  data-slot="table"
@@ -83,7 +83,7 @@ export function DateFilter({
83
83
  <FilterFieldWrapper label={label} helpText={helpText} className={className} {...props}>
84
84
  <div className="flex gap-2">
85
85
  <Select value={operator} onValueChange={(v) => handleOperatorChange(v as DateOperator)}>
86
- <SelectTrigger className="w-full flex-1">
86
+ <SelectTrigger className="w-full flex-1" aria-label={label}>
87
87
  <SelectValue />
88
88
  </SelectTrigger>
89
89
  <SelectContent>
@@ -4,6 +4,8 @@ import { cn } from "../../../../lib/utils";
4
4
  interface FilterFieldWrapperProps extends React.ComponentProps<"div"> {
5
5
  label: string;
6
6
  htmlFor?: string;
7
+ /** id applied to the visible label so a non-native control can reference it via aria-labelledby */
8
+ labelId?: string;
7
9
  helpText?: string;
8
10
  error?: string;
9
11
  }
@@ -11,6 +13,7 @@ interface FilterFieldWrapperProps extends React.ComponentProps<"div"> {
11
13
  export function FilterFieldWrapper({
12
14
  label,
13
15
  htmlFor,
16
+ labelId,
14
17
  helpText,
15
18
  error,
16
19
  className,
@@ -19,7 +22,9 @@ export function FilterFieldWrapper({
19
22
  }: FilterFieldWrapperProps) {
20
23
  return (
21
24
  <div className={cn("space-y-1", className)} {...props}>
22
- <Label htmlFor={htmlFor}>{label}</Label>
25
+ <Label id={labelId} htmlFor={htmlFor}>
26
+ {label}
27
+ </Label>
23
28
  {children}
24
29
  <div className="min-h-4">
25
30
  {error ? (
@@ -28,6 +28,7 @@ export function MultiSelectFilter({
28
28
  }: MultiSelectFilterProps) {
29
29
  const { value, onChange } = useFilterField(field);
30
30
  const selected = value?.value ? value.value.split(",") : [];
31
+ const labelId = `filter-${field}-label`;
31
32
 
32
33
  const triggerLabel =
33
34
  selected.length === 0
@@ -54,12 +55,19 @@ export function MultiSelectFilter({
54
55
  }
55
56
 
56
57
  return (
57
- <FilterFieldWrapper label={label} helpText={helpText} className={className} {...props}>
58
+ <FilterFieldWrapper
59
+ label={label}
60
+ labelId={labelId}
61
+ helpText={helpText}
62
+ className={className}
63
+ {...props}
64
+ >
58
65
  <Popover>
59
66
  <PopoverTrigger asChild>
60
67
  <Button
61
68
  variant="outline"
62
69
  role="combobox"
70
+ aria-labelledby={labelId}
63
71
  className={cn(
64
72
  "w-full justify-between font-normal",
65
73
  selected.length === 0 && "text-muted-foreground",
@@ -142,7 +142,7 @@ export default function ApplicationSearch() {
142
142
  resetAll={resetAll}
143
143
  />
144
144
  <div className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
145
- <Table>
145
+ <Table aria-label="Applications">
146
146
  <ApplicationSearchTableHeader />
147
147
  <TableBody>
148
148
  {loading && <ApplicationSearchSkeleton pageSize={pagination.pageSize} />}
@@ -282,8 +282,17 @@ function ApplicationSearchTable({
282
282
  return (
283
283
  <TableRow
284
284
  key={application.Id}
285
+ role="button"
286
+ tabIndex={0}
287
+ aria-label={applicationName}
285
288
  onClick={() => setSelectedApplication(application)}
286
- className="hover:bg-gray-50 transition-colors cursor-pointer"
289
+ onKeyDown={(e) => {
290
+ if (e.key === "Enter" || e.key === " ") {
291
+ e.preventDefault();
292
+ setSelectedApplication(application);
293
+ }
294
+ }}
295
+ className="hover:bg-gray-50 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple focus-visible:ring-inset"
287
296
  >
288
297
  <TableCell className="px-6 py-4">
289
298
  <div className="text-sm font-medium text-gray-900">{applicationName}</div>
@@ -162,7 +162,7 @@ export default function MaintenanceRequestSearch() {
162
162
  />
163
163
 
164
164
  <div className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
165
- <Table>
165
+ <Table aria-label="Maintenance requests">
166
166
  <MaintenanceRequestSearchTableHeader />
167
167
  <TableBody>
168
168
  {loading && <MaintenanceRequestSearchSkeleton pageSize={pagination.pageSize} />}
@@ -328,8 +328,17 @@ function MaintenanceRequestSearchTable({
328
328
  return (
329
329
  <TableRow
330
330
  key={request.Id}
331
+ role="button"
332
+ tabIndex={0}
333
+ aria-label={requestName}
331
334
  onClick={() => setSelectedRequest(request)}
332
- className="hover:bg-gray-50 transition-colors cursor-pointer"
335
+ onKeyDown={(e) => {
336
+ if (e.key === "Enter" || e.key === " ") {
337
+ e.preventDefault();
338
+ setSelectedRequest(request);
339
+ }
340
+ }}
341
+ className="hover:bg-gray-50 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple focus-visible:ring-inset"
333
342
  >
334
343
  <TableCell className="max-w-xs px-6 py-5">
335
344
  <div className="flex items-center gap-4">
@@ -109,7 +109,7 @@ export default function MaintenanceWorkerSearch() {
109
109
  />
110
110
 
111
111
  <div className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
112
- <Table>
112
+ <Table aria-label="Maintenance workers">
113
113
  <MaintenanceWorkerSearchTableHeader />
114
114
  <TableBody>
115
115
  {loading && <MaintenanceWorkerSearchSkeleton pageSize={pagination.pageSize} />}
@@ -265,8 +265,17 @@ function MaintenanceWorkerSearchTable({
265
265
  return (
266
266
  <TableRow
267
267
  key={worker.Id}
268
+ role="button"
269
+ tabIndex={0}
270
+ aria-label={name}
268
271
  onClick={() => setSelectedWorker(worker)}
269
- className="hover:bg-gray-50 transition-colors cursor-pointer"
272
+ onKeyDown={(e) => {
273
+ if (e.key === "Enter" || e.key === " ") {
274
+ e.preventDefault();
275
+ setSelectedWorker(worker);
276
+ }
277
+ }}
278
+ className="hover:bg-gray-50 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple focus-visible:ring-inset"
270
279
  >
271
280
  <TableCell className="px-6 py-4 font-medium text-gray-900">{name}</TableCell>
272
281
  <TableCell className="px-6 py-4 text-gray-600">
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "11.7.0",
3
+ "version": "11.8.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
9
- "version": "11.7.0",
9
+ "version": "11.8.1",
10
10
  "license": "SEE LICENSE IN LICENSE.txt",
11
11
  "devDependencies": {
12
12
  "@lwc/eslint-plugin-lwc": "^3.3.0",
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
3
- "version": "11.7.0",
3
+ "version": "11.8.1",
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-app-react-sample-b2e",
3
- "version": "11.7.0",
3
+ "version": "11.8.1",
4
4
  "description": "Salesforce sample property rental React app",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "",
@@ -16,7 +16,7 @@
16
16
  "clean": "rm -rf dist"
17
17
  },
18
18
  "dependencies": {
19
- "@salesforce/ui-bundle": "^11.7.0",
19
+ "@salesforce/ui-bundle": "^11.8.1",
20
20
  "sonner": "^1.7.0"
21
21
  },
22
22
  "devDependencies": {