@salesforce/ui-bundle-template-feature-react-customer-web-client-chat 11.52.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 (107) hide show
  1. package/LICENSE.txt +82 -0
  2. package/README.md +63 -0
  3. package/dist/.forceignore +15 -0
  4. package/dist/.husky/pre-commit +4 -0
  5. package/dist/.prettierignore +11 -0
  6. package/dist/.prettierrc +17 -0
  7. package/dist/CHANGELOG.md +4553 -0
  8. package/dist/README.md +77 -0
  9. package/dist/config/project-scratch-def.json +13 -0
  10. package/dist/eslint.config.js +7 -0
  11. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/.forceignore +15 -0
  12. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/.graphqlrc.yml +2 -0
  13. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/.prettierignore +9 -0
  14. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/.prettierrc +11 -0
  15. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/CHANGELOG.md +10 -0
  16. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/README.md +75 -0
  17. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/codegen.yml +95 -0
  18. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/components.json +18 -0
  19. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/e2e/app.spec.ts +17 -0
  20. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/eslint.config.js +169 -0
  21. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/feature-react-customer-web-client-chat.uibundle-meta.xml +7 -0
  22. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/index.html +12 -0
  23. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/package.json +76 -0
  24. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/playwright.config.ts +24 -0
  25. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/scripts/get-graphql-schema.mjs +71 -0
  26. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/scripts/rewrite-e2e-assets.mjs +23 -0
  27. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/api/graphqlClient.ts +44 -0
  28. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/app.tsx +17 -0
  29. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/appLayout.tsx +83 -0
  30. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/icons/book.svg +3 -0
  31. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/icons/copy.svg +4 -0
  32. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/icons/rocket.svg +3 -0
  33. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/icons/star.svg +3 -0
  34. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/images/codey-1.png +0 -0
  35. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/images/codey-2.png +0 -0
  36. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/images/codey-3.png +0 -0
  37. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/assets/images/vibe-codey.svg +194 -0
  38. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/CustomerWebClientChat.tsx +74 -0
  39. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/alerts/status-alert.tsx +52 -0
  40. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/layouts/card-layout.tsx +29 -0
  41. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/alert.tsx +76 -0
  42. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/avatar.tsx +109 -0
  43. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/badge.tsx +48 -0
  44. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/breadcrumb.tsx +109 -0
  45. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/button.tsx +67 -0
  46. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/calendar.tsx +232 -0
  47. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/card.tsx +103 -0
  48. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/checkbox.tsx +32 -0
  49. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/collapsible.tsx +33 -0
  50. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/datePicker.tsx +127 -0
  51. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/dialog.tsx +162 -0
  52. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/dropdown-menu.tsx +257 -0
  53. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/field.tsx +237 -0
  54. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/index.ts +109 -0
  55. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/input.tsx +19 -0
  56. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/label.tsx +22 -0
  57. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/pagination.tsx +132 -0
  58. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/popover.tsx +89 -0
  59. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/select.tsx +193 -0
  60. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/separator.tsx +26 -0
  61. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/skeleton.tsx +14 -0
  62. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/sonner.tsx +20 -0
  63. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/spinner.tsx +16 -0
  64. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/table.tsx +121 -0
  65. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/ui/tabs.tsx +88 -0
  66. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/hooks/useAsyncData.ts +67 -0
  67. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/index.ts +6 -0
  68. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/lib/utils.ts +6 -0
  69. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/navigationMenu.tsx +80 -0
  70. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/pages/Home.tsx +12 -0
  71. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/pages/NotFound.tsx +18 -0
  72. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/pages/TestChatPage.tsx +26 -0
  73. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/router-utils.tsx +35 -0
  74. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/routes.tsx +28 -0
  75. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/styles/global.css +135 -0
  76. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/types/chat.ts +36 -0
  77. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/tsconfig.json +45 -0
  78. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/tsconfig.node.json +13 -0
  79. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/tsconfig.tsbuildinfo +1 -0
  80. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/ui-bundle.json +7 -0
  81. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/vite-env.d.ts +4 -0
  82. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/vite.config.ts +106 -0
  83. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/vitest-env.d.ts +2 -0
  84. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/vitest.config.ts +11 -0
  85. package/dist/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/vitest.setup.ts +1 -0
  86. package/dist/jest.config.js +6 -0
  87. package/dist/package-lock.json +10066 -0
  88. package/dist/package.json +46 -0
  89. package/dist/scripts/apex/hello.apex +10 -0
  90. package/dist/scripts/gitignore-templates.json +4 -0
  91. package/dist/scripts/graphql-search.sh +191 -0
  92. package/dist/scripts/org-setup-config-schema.mjs +120 -0
  93. package/dist/scripts/org-setup-dev.mjs +87 -0
  94. package/dist/scripts/org-setup-utils.mjs +569 -0
  95. package/dist/scripts/org-setup-xml.mjs +182 -0
  96. package/dist/scripts/org-setup.config.json +5 -0
  97. package/dist/scripts/org-setup.mjs +2345 -0
  98. package/dist/scripts/sf-project-setup.mjs +103 -0
  99. package/dist/scripts/soql/account.soql +6 -0
  100. package/dist/scripts/validate-org-setup-config.mjs +38 -0
  101. package/dist/sfdx-project.json +12 -0
  102. package/package.json +51 -0
  103. package/src/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/components/CustomerWebClientChat.tsx +74 -0
  104. package/src/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/index.ts +6 -0
  105. package/src/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/pages/TestChatPage.tsx +26 -0
  106. package/src/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/routes.tsx +23 -0
  107. package/src/force-app/main/default/uiBundles/feature-react-customer-web-client-chat/src/types/chat.ts +36 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+
7
+ import { useEffect } from "react";
8
+ import type { CustomerWebClientChatProps, WindowWithCwcProperties } from "../types/chat";
9
+
10
+ /**
11
+ * React wrapper that embeds the Customer Web Client (Embedded Messaging) chat
12
+ * widget into an external site. It dynamically loads the site's
13
+ * `embeddedservice_bootstrap` script and calls `init` with the org, deployment,
14
+ * site, and SCRT2 configuration. Renders nothing itself — the chat UI is a
15
+ * floating widget injected by the bootstrap script.
16
+ */
17
+ export function CustomerWebClientChat({
18
+ orgId,
19
+ deploymentName,
20
+ siteURL,
21
+ scrt2URL,
22
+ language = "en",
23
+ devMode = false,
24
+ }: CustomerWebClientChatProps) {
25
+ useEffect(() => {
26
+ if (typeof window === "undefined") return;
27
+ if (
28
+ !orgId ||
29
+ !deploymentName ||
30
+ !siteURL ||
31
+ !scrt2URL ||
32
+ !(orgId.length === 15 || orgId.length === 18)
33
+ ) {
34
+ console.warn("[CustomerWebClientChat] missing required config; skipping init");
35
+ return;
36
+ }
37
+
38
+ const win = window as WindowWithCwcProperties;
39
+ const bootstrapSrc = `${siteURL}/assets/js/bootstrap.js`;
40
+ const existing = document.querySelector<HTMLScriptElement>(`script[src="${bootstrapSrc}"]`);
41
+ const script: HTMLScriptElement = existing ?? document.createElement("script");
42
+
43
+ const init = () => {
44
+ try {
45
+ if (!win.embeddedservice_bootstrap) return;
46
+ win.embeddedservice_bootstrap.settings.language = language;
47
+ if (devMode) win.embeddedservice_bootstrap.settings.devMode = true;
48
+ win.embeddedservice_bootstrap.init(orgId, deploymentName, siteURL, {
49
+ scrt2URL,
50
+ });
51
+ } catch (err) {
52
+ console.error("Error loading Embedded Messaging: ", err);
53
+ }
54
+ };
55
+
56
+ if (existing) {
57
+ if (win.embeddedservice_bootstrap) init();
58
+ else existing.addEventListener("load", init, { once: true });
59
+ } else {
60
+ script.type = "text/javascript";
61
+ script.src = bootstrapSrc;
62
+ script.addEventListener("load", init, { once: true });
63
+ document.body.appendChild(script);
64
+ }
65
+
66
+ return () => {
67
+ script.removeEventListener("load", init);
68
+ };
69
+ }, [orgId, deploymentName, siteURL, scrt2URL, language, devMode]);
70
+
71
+ return null;
72
+ }
73
+
74
+ export default CustomerWebClientChat;
@@ -0,0 +1,52 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+ import { AlertCircleIcon, CheckCircle2Icon, InfoIcon } from 'lucide-react';
3
+ import { Alert, AlertDescription } from '../../components/ui/alert';
4
+ import { useId } from 'react';
5
+
6
+ const statusAlertVariants = cva('', {
7
+ variants: {
8
+ variant: {
9
+ error: '',
10
+ success: '',
11
+ info: 'text-blue-600 *:[svg]:text-current *:data-[slot=alert-description]:text-blue-600/90',
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ variant: 'error',
16
+ },
17
+ });
18
+
19
+ interface StatusAlertProps extends VariantProps<typeof statusAlertVariants> {
20
+ children?: React.ReactNode;
21
+ /** Alert variant type. @default "error" */
22
+ variant?: 'error' | 'success' | 'info';
23
+ }
24
+
25
+ /**
26
+ * Status alert component for displaying error, success, or info messages.
27
+ * Returns null if no children are provided.
28
+ */
29
+ export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
30
+ const descriptionId = useId();
31
+ if (!children) return null;
32
+
33
+ const isError = variant === 'error';
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
+
41
+ return (
42
+ <Alert
43
+ variant={isError ? 'destructive' : 'default'}
44
+ className={statusAlertVariants({ variant })}
45
+ aria-describedby={descriptionId}
46
+ role={isError ? 'alert' : 'status'}
47
+ >
48
+ {icon}
49
+ <AlertDescription id={descriptionId}>{children}</AlertDescription>
50
+ </Alert>
51
+ );
52
+ }
@@ -0,0 +1,29 @@
1
+ import {
2
+ Card,
3
+ CardContent,
4
+ CardDescription,
5
+ CardHeader,
6
+ CardTitle,
7
+ } from '../../components/ui/card';
8
+
9
+ interface CardLayoutProps {
10
+ title: string;
11
+ description?: string;
12
+ children: React.ReactNode;
13
+ }
14
+
15
+ /**
16
+ * Card layout component for authentication pages.
17
+ * Provides CardHeader with title and optional description, and CardContent.
18
+ */
19
+ export function CardLayout({ title, description, children }: CardLayoutProps) {
20
+ return (
21
+ <Card>
22
+ <CardHeader>
23
+ <CardTitle className="text-2xl">{title}</CardTitle>
24
+ {description && <CardDescription>{description}</CardDescription>}
25
+ </CardHeader>
26
+ <CardContent>{children}</CardContent>
27
+ </Card>
28
+ );
29
+ }
@@ -0,0 +1,76 @@
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const alertVariants = cva(
7
+ "grid gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 w-full relative group/alert",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'bg-card text-card-foreground',
12
+ destructive:
13
+ 'text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current',
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: 'default',
18
+ },
19
+ }
20
+ );
21
+
22
+ function Alert({
23
+ className,
24
+ variant,
25
+ ...props
26
+ }: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
27
+ return (
28
+ <div
29
+ data-slot="alert"
30
+ role="alert"
31
+ className={cn(alertVariants({ variant }), className)}
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
38
+ return (
39
+ <div
40
+ data-slot="alert-title"
41
+ className={cn(
42
+ 'font-medium group-has-[>svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3',
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ );
48
+ }
49
+
50
+ function AlertDescription({
51
+ className,
52
+ ...props
53
+ }: React.ComponentProps<'div'>) {
54
+ return (
55
+ <div
56
+ data-slot="alert-description"
57
+ className={cn(
58
+ 'text-muted-foreground text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3',
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ );
64
+ }
65
+
66
+ function AlertAction({ className, ...props }: React.ComponentProps<'div'>) {
67
+ return (
68
+ <div
69
+ data-slot="alert-action"
70
+ className={cn('absolute top-2 right-2', className)}
71
+ {...props}
72
+ />
73
+ );
74
+ }
75
+
76
+ export { Alert, AlertTitle, AlertDescription, AlertAction };
@@ -0,0 +1,109 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { Avatar as AvatarPrimitive } from 'radix-ui';
5
+
6
+ import { cn } from '@/lib/utils';
7
+
8
+ function Avatar({
9
+ className,
10
+ size = 'default',
11
+ ...props
12
+ }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
13
+ size?: 'default' | 'sm' | 'lg';
14
+ }) {
15
+ return (
16
+ <AvatarPrimitive.Root
17
+ data-slot="avatar"
18
+ data-size={size}
19
+ className={cn(
20
+ 'group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6',
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ );
26
+ }
27
+
28
+ function AvatarImage({
29
+ className,
30
+ ...props
31
+ }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
32
+ return (
33
+ <AvatarPrimitive.Image
34
+ data-slot="avatar-image"
35
+ className={cn('aspect-square size-full', className)}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ function AvatarFallback({
42
+ className,
43
+ ...props
44
+ }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
45
+ return (
46
+ <AvatarPrimitive.Fallback
47
+ data-slot="avatar-fallback"
48
+ className={cn(
49
+ 'flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs',
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ );
55
+ }
56
+
57
+ function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
58
+ return (
59
+ <span
60
+ data-slot="avatar-badge"
61
+ className={cn(
62
+ 'absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none',
63
+ 'group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden',
64
+ 'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2',
65
+ 'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2',
66
+ className
67
+ )}
68
+ {...props}
69
+ />
70
+ );
71
+ }
72
+
73
+ function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
74
+ return (
75
+ <div
76
+ data-slot="avatar-group"
77
+ className={cn(
78
+ 'group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background',
79
+ className
80
+ )}
81
+ {...props}
82
+ />
83
+ );
84
+ }
85
+
86
+ function AvatarGroupCount({
87
+ className,
88
+ ...props
89
+ }: React.ComponentProps<'div'>) {
90
+ return (
91
+ <div
92
+ data-slot="avatar-group-count"
93
+ className={cn(
94
+ 'relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3',
95
+ className
96
+ )}
97
+ {...props}
98
+ />
99
+ );
100
+ }
101
+
102
+ export {
103
+ Avatar,
104
+ AvatarImage,
105
+ AvatarFallback,
106
+ AvatarBadge,
107
+ AvatarGroup,
108
+ AvatarGroupCount,
109
+ };
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+ import { Slot } from 'radix-ui';
4
+
5
+ import { cn } from '@/lib/utils';
6
+
7
+ const badgeVariants = cva(
8
+ 'inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
13
+ secondary:
14
+ 'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
15
+ destructive:
16
+ 'bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90',
17
+ outline:
18
+ 'border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
19
+ ghost: '[a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
20
+ link: 'text-primary underline-offset-4 [a&]:hover:underline',
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: 'default',
25
+ },
26
+ }
27
+ );
28
+
29
+ function Badge({
30
+ className,
31
+ variant = 'default',
32
+ asChild = false,
33
+ ...props
34
+ }: React.ComponentProps<'span'> &
35
+ VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
36
+ const Comp = asChild ? Slot.Root : 'span';
37
+
38
+ return (
39
+ <Comp
40
+ data-slot="badge"
41
+ data-variant={variant}
42
+ className={cn(badgeVariants({ variant }), className)}
43
+ {...props}
44
+ />
45
+ );
46
+ }
47
+
48
+ export { Badge, badgeVariants };
@@ -0,0 +1,109 @@
1
+ import * as React from 'react';
2
+ import { ChevronRight, MoreHorizontal } from 'lucide-react';
3
+ import { Slot } from 'radix-ui';
4
+
5
+ import { cn } from '@/lib/utils';
6
+
7
+ function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
8
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
9
+ }
10
+
11
+ function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
12
+ return (
13
+ <ol
14
+ data-slot="breadcrumb-list"
15
+ className={cn(
16
+ 'flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2.5',
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ );
22
+ }
23
+
24
+ function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
25
+ return (
26
+ <li
27
+ data-slot="breadcrumb-item"
28
+ className={cn('inline-flex items-center gap-1.5', className)}
29
+ {...props}
30
+ />
31
+ );
32
+ }
33
+
34
+ function BreadcrumbLink({
35
+ asChild,
36
+ className,
37
+ ...props
38
+ }: React.ComponentProps<'a'> & {
39
+ asChild?: boolean;
40
+ }) {
41
+ const Comp = asChild ? Slot.Root : 'a';
42
+
43
+ return (
44
+ <Comp
45
+ data-slot="breadcrumb-link"
46
+ className={cn('transition-colors hover:text-foreground', className)}
47
+ {...props}
48
+ />
49
+ );
50
+ }
51
+
52
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
53
+ return (
54
+ <span
55
+ data-slot="breadcrumb-page"
56
+ role="link"
57
+ aria-disabled="true"
58
+ aria-current="page"
59
+ className={cn('font-normal text-foreground', className)}
60
+ {...props}
61
+ />
62
+ );
63
+ }
64
+
65
+ function BreadcrumbSeparator({
66
+ children,
67
+ className,
68
+ ...props
69
+ }: React.ComponentProps<'li'>) {
70
+ return (
71
+ <li
72
+ data-slot="breadcrumb-separator"
73
+ role="presentation"
74
+ aria-hidden="true"
75
+ className={cn('[&>svg]:size-3.5', className)}
76
+ {...props}
77
+ >
78
+ {children ?? <ChevronRight />}
79
+ </li>
80
+ );
81
+ }
82
+
83
+ function BreadcrumbEllipsis({
84
+ className,
85
+ ...props
86
+ }: React.ComponentProps<'span'>) {
87
+ return (
88
+ <span
89
+ data-slot="breadcrumb-ellipsis"
90
+ role="presentation"
91
+ aria-hidden="true"
92
+ className={cn('flex size-9 items-center justify-center', className)}
93
+ {...props}
94
+ >
95
+ <MoreHorizontal className="size-4" />
96
+ <span className="sr-only">More</span>
97
+ </span>
98
+ );
99
+ }
100
+
101
+ export {
102
+ Breadcrumb,
103
+ BreadcrumbList,
104
+ BreadcrumbItem,
105
+ BreadcrumbLink,
106
+ BreadcrumbPage,
107
+ BreadcrumbSeparator,
108
+ BreadcrumbEllipsis,
109
+ };
@@ -0,0 +1,67 @@
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+ import { Slot } from 'radix-ui';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ const buttonVariants = cva(
8
+ "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 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
13
+ outline:
14
+ 'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground',
15
+ secondary:
16
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
17
+ ghost:
18
+ 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
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-red-700 dark:text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
21
+ link: 'text-primary underline-offset-4 hover:underline',
22
+ },
23
+ size: {
24
+ default:
25
+ 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
26
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
27
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
28
+ lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3',
29
+ icon: 'size-8',
30
+ 'icon-xs':
31
+ "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
32
+ 'icon-sm':
33
+ 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
34
+ 'icon-lg': 'size-9',
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ variant: 'default',
39
+ size: 'default',
40
+ },
41
+ }
42
+ );
43
+
44
+ function Button({
45
+ className,
46
+ variant = 'default',
47
+ size = 'default',
48
+ asChild = false,
49
+ ...props
50
+ }: React.ComponentProps<'button'> &
51
+ VariantProps<typeof buttonVariants> & {
52
+ asChild?: boolean;
53
+ }) {
54
+ const Comp = asChild ? Slot.Root : 'button';
55
+
56
+ return (
57
+ <Comp
58
+ data-slot="button"
59
+ data-variant={variant}
60
+ data-size={size}
61
+ className={cn(buttonVariants({ variant, size, className }))}
62
+ {...(props as any)}
63
+ />
64
+ );
65
+ }
66
+
67
+ export { Button, buttonVariants };