@salesforce/ui-bundle-template-app-react-template-b2e 12.3.8 → 12.3.9
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 +8 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/package.json +4 -4
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/appLayout.tsx +41 -7
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/AccountObjectDetailPage.tsx +36 -17
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/Home.tsx +7 -2
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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
|
+
## [12.3.9](https://github.com/salesforce-experience-platform-emu/webapps/compare/v12.3.8...v12.3.9) (2026-09-02)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
## [12.3.8](https://github.com/salesforce-experience-platform-emu/webapps/compare/v12.3.7...v12.3.8) (2026-09-01)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@salesforce/platform-sdk": "^12.3.
|
|
23
|
-
"@salesforce/ui-bundle": "^12.3.
|
|
22
|
+
"@salesforce/platform-sdk": "^12.3.9",
|
|
23
|
+
"@salesforce/ui-bundle": "^12.3.9",
|
|
24
24
|
"@tailwindcss/vite": "^4.1.17",
|
|
25
25
|
"class-variance-authority": "^0.7.1",
|
|
26
26
|
"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": "^12.3.
|
|
50
|
-
"@salesforce/vite-plugin-ui-bundle": "^12.3.
|
|
49
|
+
"@salesforce/graphiti": "^12.3.9",
|
|
50
|
+
"@salesforce/vite-plugin-ui-bundle": "^12.3.9",
|
|
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",
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { AgentforceConversationClient } from "./components/AgentforceConversationClient";
|
|
2
2
|
import { Outlet, Link, useLocation } from "react-router";
|
|
3
3
|
import { getAllRoutes } from "./router-utils";
|
|
4
|
-
import { useState } from "react";
|
|
4
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
5
5
|
|
|
6
6
|
export default function AppLayout() {
|
|
7
7
|
const [isOpen, setIsOpen] = useState(false);
|
|
8
8
|
const location = useLocation();
|
|
9
|
+
const navId = useId();
|
|
10
|
+
const outletWrapperRef = useRef<HTMLDivElement>(null);
|
|
11
|
+
const previousPathname = useRef<string | null>(null);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (previousPathname.current !== null && previousPathname.current !== location.pathname) {
|
|
15
|
+
const wrapper = outletWrapperRef.current;
|
|
16
|
+
const target = wrapper?.querySelector<HTMLElement>("h1, main, [role='main']") ?? wrapper;
|
|
17
|
+
if (target) {
|
|
18
|
+
if (!target.hasAttribute("tabindex")) target.setAttribute("tabindex", "-1");
|
|
19
|
+
target.focus();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
previousPathname.current = location.pathname;
|
|
23
|
+
}, [location.pathname]);
|
|
9
24
|
|
|
10
25
|
const isActive = (path: string) => location.pathname === path;
|
|
11
26
|
|
|
@@ -28,6 +43,20 @@ export default function AppLayout() {
|
|
|
28
43
|
|
|
29
44
|
return (
|
|
30
45
|
<>
|
|
46
|
+
<a
|
|
47
|
+
href="#main-content"
|
|
48
|
+
onClick={(e) => {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
const content = outletWrapperRef.current;
|
|
51
|
+
if (content) {
|
|
52
|
+
if (!content.hasAttribute("tabindex")) content.setAttribute("tabindex", "-1");
|
|
53
|
+
content.focus();
|
|
54
|
+
}
|
|
55
|
+
}}
|
|
56
|
+
className="sr-only focus:not-sr-only focus:absolute focus:z-50 focus:top-2 focus:left-2 focus:rounded-md focus:bg-white focus:px-4 focus:py-2 focus:text-gray-900 focus:shadow focus:ring-2 focus:ring-gray-900"
|
|
57
|
+
>
|
|
58
|
+
Skip to main content
|
|
59
|
+
</a>
|
|
31
60
|
<nav className="bg-white border-b border-gray-200">
|
|
32
61
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
33
62
|
<div className="flex justify-between items-center h-16">
|
|
@@ -38,8 +67,10 @@ export default function AppLayout() {
|
|
|
38
67
|
onClick={toggleMenu}
|
|
39
68
|
className="p-2 rounded-md text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
40
69
|
aria-label="Toggle menu"
|
|
70
|
+
aria-expanded={isOpen}
|
|
71
|
+
aria-controls={navId}
|
|
41
72
|
>
|
|
42
|
-
<div className="w-6 h-6 flex flex-col justify-center space-y-1.5">
|
|
73
|
+
<div aria-hidden="true" className="w-6 h-6 flex flex-col justify-center space-y-1.5">
|
|
43
74
|
<span
|
|
44
75
|
className={`block h-0.5 w-6 bg-current transition-all ${
|
|
45
76
|
isOpen ? "rotate-45 translate-y-2" : ""
|
|
@@ -56,14 +87,15 @@ export default function AppLayout() {
|
|
|
56
87
|
</div>
|
|
57
88
|
</button>
|
|
58
89
|
</div>
|
|
59
|
-
{
|
|
60
|
-
|
|
90
|
+
<div id={navId} className="pb-4" hidden={!isOpen}>
|
|
91
|
+
{isOpen && (
|
|
61
92
|
<div className="flex flex-col space-y-2">
|
|
62
93
|
{navigationRoutes.map((item) => (
|
|
63
94
|
<Link
|
|
64
95
|
key={item.path}
|
|
65
96
|
to={item.path}
|
|
66
97
|
onClick={() => setIsOpen(false)}
|
|
98
|
+
aria-current={isActive(item.path) ? "page" : undefined}
|
|
67
99
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
68
100
|
isActive(item.path)
|
|
69
101
|
? "bg-blue-100 text-blue-700"
|
|
@@ -74,11 +106,13 @@ export default function AppLayout() {
|
|
|
74
106
|
</Link>
|
|
75
107
|
))}
|
|
76
108
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
109
|
+
)}
|
|
110
|
+
</div>
|
|
79
111
|
</div>
|
|
80
112
|
</nav>
|
|
81
|
-
<
|
|
113
|
+
<div id="main-content" ref={outletWrapperRef}>
|
|
114
|
+
<Outlet />
|
|
115
|
+
</div>
|
|
82
116
|
<AgentforceConversationClient agentId="<USER_AGENT_ID_18_CHAR_0Xx...>" />
|
|
83
117
|
</>
|
|
84
118
|
);
|
package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/AccountObjectDetailPage.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
import { useParams, useNavigate } from "react-router";
|
|
3
3
|
import { createDataSDK } from "@salesforce/platform-sdk";
|
|
4
4
|
import { AlertCircle, ChevronDown, ChevronRight, FileQuestion } from "lucide-react";
|
|
@@ -83,8 +83,20 @@ export default function AccountObjectDetail() {
|
|
|
83
83
|
error,
|
|
84
84
|
} = useAsyncData(() => fetchAccountDetail(recordId!), [recordId]);
|
|
85
85
|
|
|
86
|
+
const pageTitle = loading
|
|
87
|
+
? "Loading Account | MyApp"
|
|
88
|
+
: error
|
|
89
|
+
? "Error | MyApp"
|
|
90
|
+
: account
|
|
91
|
+
? `${fieldValue(account.Name) ?? "Account"} | MyApp`
|
|
92
|
+
: "Account Not Found | MyApp";
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
document.title = pageTitle;
|
|
96
|
+
}, [pageTitle]);
|
|
97
|
+
|
|
86
98
|
return (
|
|
87
|
-
<
|
|
99
|
+
<main className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
|
88
100
|
{/* Loading state */}
|
|
89
101
|
{loading && <AccountDetailSkeleton />}
|
|
90
102
|
|
|
@@ -95,8 +107,8 @@ export default function AccountObjectDetail() {
|
|
|
95
107
|
{!loading && !error && !account && <AccountDetailNotFound onBack={() => navigate(-1)} />}
|
|
96
108
|
|
|
97
109
|
{/* Content */}
|
|
98
|
-
{account && <AccountDetailContent account={account} />}
|
|
99
|
-
</
|
|
110
|
+
{!loading && !error && account && <AccountDetailContent account={account} />}
|
|
111
|
+
</main>
|
|
100
112
|
);
|
|
101
113
|
}
|
|
102
114
|
|
|
@@ -229,10 +241,16 @@ function Section({ title, children }: { title: string; children: React.ReactNode
|
|
|
229
241
|
const [open, setOpen] = useState(true);
|
|
230
242
|
return (
|
|
231
243
|
<Collapsible open={open} onOpenChange={setOpen}>
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
244
|
+
<h2>
|
|
245
|
+
<CollapsibleTrigger className="flex items-center gap-2 cursor-pointer text-lg font-semibold py-2">
|
|
246
|
+
{open ? (
|
|
247
|
+
<ChevronDown aria-hidden="true" className="size-5" />
|
|
248
|
+
) : (
|
|
249
|
+
<ChevronRight aria-hidden="true" className="size-5" />
|
|
250
|
+
)}
|
|
251
|
+
{title}
|
|
252
|
+
</CollapsibleTrigger>
|
|
253
|
+
</h2>
|
|
236
254
|
<CollapsibleContent>
|
|
237
255
|
<div className="mt-2 space-y-4">{children}</div>
|
|
238
256
|
</CollapsibleContent>
|
|
@@ -244,9 +262,9 @@ function AccountDetailError({ onBack }: { onBack: () => void }) {
|
|
|
244
262
|
return (
|
|
245
263
|
<>
|
|
246
264
|
<Alert variant="destructive" role="alert">
|
|
247
|
-
<AlertCircle />
|
|
265
|
+
<AlertCircle aria-hidden="true" />
|
|
248
266
|
<AlertTitle>
|
|
249
|
-
<
|
|
267
|
+
<h1>Failed to load account</h1>
|
|
250
268
|
</AlertTitle>
|
|
251
269
|
<AlertDescription>
|
|
252
270
|
Something went wrong while loading this account. Please try again later.
|
|
@@ -254,7 +272,7 @@ function AccountDetailError({ onBack }: { onBack: () => void }) {
|
|
|
254
272
|
</Alert>
|
|
255
273
|
<div className="mt-4 flex gap-3">
|
|
256
274
|
<Button variant="outline" onClick={onBack}>
|
|
257
|
-
|
|
275
|
+
<span aria-hidden="true">←</span> Back
|
|
258
276
|
</Button>
|
|
259
277
|
<Button variant="outline" onClick={() => window.location.reload()}>
|
|
260
278
|
Retry
|
|
@@ -266,15 +284,15 @@ function AccountDetailError({ onBack }: { onBack: () => void }) {
|
|
|
266
284
|
|
|
267
285
|
function AccountDetailNotFound({ onBack }: { onBack: () => void }) {
|
|
268
286
|
return (
|
|
269
|
-
<Card>
|
|
287
|
+
<Card role="status">
|
|
270
288
|
<CardContent className="flex flex-col items-center justify-center py-16 text-center">
|
|
271
|
-
<FileQuestion className="size-12 text-muted-foreground mb-4" />
|
|
272
|
-
<
|
|
289
|
+
<FileQuestion aria-hidden="true" className="size-12 text-muted-foreground mb-4" />
|
|
290
|
+
<h1 className="text-lg font-semibold mb-1">Account not found</h1>
|
|
273
291
|
<p className="text-sm text-muted-foreground mb-6">
|
|
274
292
|
The account you're looking for doesn't exist or may have been deleted.
|
|
275
293
|
</p>
|
|
276
294
|
<Button variant="outline" onClick={onBack}>
|
|
277
|
-
|
|
295
|
+
<span aria-hidden="true">←</span> Go back
|
|
278
296
|
</Button>
|
|
279
297
|
</CardContent>
|
|
280
298
|
</Card>
|
|
@@ -283,7 +301,8 @@ function AccountDetailNotFound({ onBack }: { onBack: () => void }) {
|
|
|
283
301
|
|
|
284
302
|
function AccountDetailSkeleton() {
|
|
285
303
|
return (
|
|
286
|
-
|
|
304
|
+
<div role="status" aria-live="polite">
|
|
305
|
+
<span className="sr-only">Loading account…</span>
|
|
287
306
|
<Skeleton className="h-8 w-56 mb-4" />
|
|
288
307
|
|
|
289
308
|
<Card>
|
|
@@ -332,7 +351,7 @@ function AccountDetailSkeleton() {
|
|
|
332
351
|
</div>
|
|
333
352
|
</CardContent>
|
|
334
353
|
</Card>
|
|
335
|
-
|
|
354
|
+
</div>
|
|
336
355
|
);
|
|
337
356
|
}
|
|
338
357
|
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
1
2
|
import { GlobalSearchBox } from "../features/search";
|
|
2
3
|
|
|
3
4
|
export default function HomePage() {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
document.title = "Home | MyApp";
|
|
7
|
+
}, []);
|
|
8
|
+
|
|
4
9
|
return (
|
|
5
|
-
<
|
|
10
|
+
<main className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
6
11
|
<h1 className="text-2xl font-bold mb-6">Home</h1>
|
|
7
12
|
<GlobalSearchBox placeholder="Search accounts, contacts, opportunities..." />
|
|
8
|
-
</
|
|
13
|
+
</main>
|
|
9
14
|
);
|
|
10
15
|
}
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/ui-bundle-template-base-sfdx-project",
|
|
3
|
-
"version": "12.3.
|
|
3
|
+
"version": "12.3.9",
|
|
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": "12.3.
|
|
9
|
+
"version": "12.3.9",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"fast-xml-parser": "^5.9.3",
|
package/dist/package.json
CHANGED