@salesforce/ui-bundle-template-base-react-app 2.2.1 → 3.1.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.
- package/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/src/force-app/main/default/uiBundles/base-react-app/package.json +3 -3
- package/src/force-app/main/default/uiBundles/base-react-app/src/components/alerts/status-alert.tsx +11 -8
- package/src/force-app/main/default/uiBundles/base-react-app/src/components/ui/input.tsx +1 -1
- package/src/force-app/main/default/uiBundles/base-react-app/src/hooks/useAsyncData.ts +67 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
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
|
+
## [3.1.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v3.0.0...v3.1.0) (2026-05-12)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- post tdx changes @W-22390798 ([#500](https://github.com/salesforce-experience-platform-emu/webapps/issues/500)) ([b611d9e](https://github.com/salesforce-experience-platform-emu/webapps/commit/b611d9ecbadd07d052bd7d9a4f5659dec422bf22))
|
|
11
|
+
|
|
12
|
+
## [3.0.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v2.2.1...v3.0.0) (2026-05-11)
|
|
13
|
+
|
|
14
|
+
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-react-app
|
|
15
|
+
|
|
6
16
|
## [2.2.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v2.2.0...v2.2.1) (2026-05-11)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-react-app
|
package/package.json
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@salesforce/platform-sdk-data": "^
|
|
22
|
-
"@salesforce/ui-bundle": "^
|
|
21
|
+
"@salesforce/platform-sdk-data": "^3.1.0",
|
|
22
|
+
"@salesforce/ui-bundle": "^3.1.0",
|
|
23
23
|
"@tailwindcss/vite": "^4.1.17",
|
|
24
24
|
"class-variance-authority": "^0.7.1",
|
|
25
25
|
"clsx": "^2.1.1",
|
|
@@ -44,7 +44,7 @@
|
|
|
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/vite-plugin-ui-bundle": "^
|
|
47
|
+
"@salesforce/vite-plugin-ui-bundle": "^3.1.0",
|
|
48
48
|
"@testing-library/jest-dom": "^6.6.3",
|
|
49
49
|
"@testing-library/react": "^16.1.0",
|
|
50
50
|
"@testing-library/user-event": "^14.5.2",
|
package/src/force-app/main/default/uiBundles/base-react-app/src/components/alerts/status-alert.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
-
import { AlertCircleIcon, CheckCircle2Icon } from 'lucide-react';
|
|
2
|
+
import { AlertCircleIcon, CheckCircle2Icon, InfoIcon } from 'lucide-react';
|
|
3
3
|
import { Alert, AlertDescription } from '../../components/ui/alert';
|
|
4
4
|
import { useId } from 'react';
|
|
5
5
|
|
|
@@ -8,6 +8,7 @@ const statusAlertVariants = cva('', {
|
|
|
8
8
|
variant: {
|
|
9
9
|
error: '',
|
|
10
10
|
success: '',
|
|
11
|
+
info: 'text-blue-600 *:[svg]:text-current *:data-[slot=alert-description]:text-blue-600/90',
|
|
11
12
|
},
|
|
12
13
|
},
|
|
13
14
|
defaultVariants: {
|
|
@@ -18,11 +19,11 @@ const statusAlertVariants = cva('', {
|
|
|
18
19
|
interface StatusAlertProps extends VariantProps<typeof statusAlertVariants> {
|
|
19
20
|
children?: React.ReactNode;
|
|
20
21
|
/** Alert variant type. @default "error" */
|
|
21
|
-
variant?: 'error' | 'success';
|
|
22
|
+
variant?: 'error' | 'success' | 'info';
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
* Status alert component for displaying error or
|
|
26
|
+
* Status alert component for displaying error, success, or info messages.
|
|
26
27
|
* Returns null if no children are provided.
|
|
27
28
|
*/
|
|
28
29
|
export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
|
|
@@ -31,6 +32,12 @@ export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
|
|
|
31
32
|
|
|
32
33
|
const isError = variant === 'error';
|
|
33
34
|
|
|
35
|
+
const icon = {
|
|
36
|
+
error: <AlertCircleIcon aria-hidden="true" />,
|
|
37
|
+
success: <CheckCircle2Icon aria-hidden="true" />,
|
|
38
|
+
info: <InfoIcon aria-hidden="true" />,
|
|
39
|
+
}[variant];
|
|
40
|
+
|
|
34
41
|
return (
|
|
35
42
|
<Alert
|
|
36
43
|
variant={isError ? 'destructive' : 'default'}
|
|
@@ -38,11 +45,7 @@ export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
|
|
|
38
45
|
aria-describedby={descriptionId}
|
|
39
46
|
role={isError ? 'alert' : 'status'}
|
|
40
47
|
>
|
|
41
|
-
{
|
|
42
|
-
<AlertCircleIcon aria-hidden="true" />
|
|
43
|
-
) : (
|
|
44
|
-
<CheckCircle2Icon aria-hidden="true" />
|
|
45
|
-
)}
|
|
48
|
+
{icon}
|
|
46
49
|
<AlertDescription id={descriptionId}>{children}</AlertDescription>
|
|
47
50
|
</Alert>
|
|
48
51
|
);
|
|
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
|
|
8
8
|
type={type}
|
|
9
9
|
data-slot="input"
|
|
10
10
|
className={cn(
|
|
11
|
-
'dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
11
|
+
'dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground/70 placeholder:italic w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
12
12
|
className
|
|
13
13
|
)}
|
|
14
14
|
{...props}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
interface UseAsyncDataResult<T> {
|
|
4
|
+
data: T | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Runs an async fetcher on mount and whenever `deps` change.
|
|
11
|
+
* Returns the loading/error/data state. Does not cache — every call
|
|
12
|
+
* to the fetcher hits the source directly.
|
|
13
|
+
*
|
|
14
|
+
* A cleanup flag prevents state updates if the component unmounts
|
|
15
|
+
* or deps change before the fetch completes (avoids React warnings
|
|
16
|
+
* and stale updates from out-of-order responses).
|
|
17
|
+
*/
|
|
18
|
+
export function useAsyncData<T>(
|
|
19
|
+
fetcher: () => Promise<T>,
|
|
20
|
+
deps: React.DependencyList
|
|
21
|
+
): UseAsyncDataResult<T> {
|
|
22
|
+
const [data, setData] = useState<T | null>(null);
|
|
23
|
+
const [loading, setLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState<string | null>(null);
|
|
25
|
+
const [generation, setGeneration] = useState(0);
|
|
26
|
+
|
|
27
|
+
const fetcherRef = useRef(fetcher);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
fetcherRef.current = fetcher;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Detect dep changes during render to reset loading state and bump generation
|
|
33
|
+
const [prevDeps, setPrevDeps] = useState(deps);
|
|
34
|
+
if (
|
|
35
|
+
deps.length !== prevDeps.length ||
|
|
36
|
+
deps.some((d, i) => d !== prevDeps[i])
|
|
37
|
+
) {
|
|
38
|
+
setPrevDeps(deps);
|
|
39
|
+
setGeneration(g => g + 1);
|
|
40
|
+
if (!loading) setLoading(true);
|
|
41
|
+
if (error !== null) setError(null);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
let cancelled = false;
|
|
46
|
+
|
|
47
|
+
fetcherRef
|
|
48
|
+
.current()
|
|
49
|
+
.then(result => {
|
|
50
|
+
if (!cancelled) setData(result);
|
|
51
|
+
})
|
|
52
|
+
.catch(err => {
|
|
53
|
+
console.error(err);
|
|
54
|
+
if (!cancelled)
|
|
55
|
+
setError(err instanceof Error ? err.message : 'An error occurred');
|
|
56
|
+
})
|
|
57
|
+
.finally(() => {
|
|
58
|
+
if (!cancelled) setLoading(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return () => {
|
|
62
|
+
cancelled = true;
|
|
63
|
+
};
|
|
64
|
+
}, [generation]);
|
|
65
|
+
|
|
66
|
+
return { data, loading, error };
|
|
67
|
+
}
|