@handled-ai/design-system 0.18.34 → 0.18.36

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.
@@ -21,8 +21,10 @@ import {
21
21
  Maximize2,
22
22
  Minimize2,
23
23
  CalendarDays,
24
+ ChevronRight,
24
25
  } from "lucide-react"
25
26
  import { TimelineActivity, type TimelineEvent } from "./timeline-activity"
27
+ import { BRAND_ICONS } from "../lib/icons"
26
28
 
27
29
  // ---------------------------------------------------------------------------
28
30
  // EntityPanel -- supports Sheet (side panel), wide, and fullscreen modes
@@ -778,6 +780,121 @@ export function EntityDetails({ onClose: _onClose }: { onClose?: () => void }) {
778
780
  // SourcesToggle – collapsible sources list
779
781
  // ---------------------------------------------------------------------------
780
782
 
783
+ // ---------------------------------------------------------------------------
784
+ // RelatedRecordActionCard – clickable card for related records (cases, accounts, etc.)
785
+ // ---------------------------------------------------------------------------
786
+
787
+ /** Icon can be a ReactNode (e.g. a Lucide icon) or the string "salesforce" for the brand logo. */
788
+ export type RelatedRecordActionIcon = React.ReactNode | "salesforce"
789
+
790
+ export interface RelatedRecordActionCardProps {
791
+ kind: string
792
+ label: string
793
+ subtitle?: string
794
+ href?: string
795
+ external?: boolean
796
+ icon?: RelatedRecordActionIcon
797
+ onClick?: () => void
798
+ disabledReason?: string
799
+ testId?: string
800
+ }
801
+
802
+ export function RelatedRecordActionCard({
803
+ kind: _kind,
804
+ label,
805
+ subtitle,
806
+ href,
807
+ external,
808
+ icon,
809
+ onClick,
810
+ disabledReason,
811
+ testId,
812
+ }: RelatedRecordActionCardProps) {
813
+ const disabled = !!disabledReason
814
+
815
+ const iconNode =
816
+ icon === "salesforce" ? (
817
+ <img
818
+ src={BRAND_ICONS.salesforce}
819
+ alt="Salesforce"
820
+ className="w-4 h-4 object-contain"
821
+ />
822
+ ) : (
823
+ icon ?? <FileText className="h-4 w-4" aria-hidden="true" />
824
+ )
825
+
826
+ const content = (
827
+ <>
828
+ <div className="flex items-center gap-2.5 min-w-0">
829
+ <div className="w-7 h-7 rounded-md border border-border/60 bg-muted/30 flex items-center justify-center shrink-0 text-muted-foreground">
830
+ {iconNode}
831
+ </div>
832
+ <div className="min-w-0">
833
+ <p className="text-sm font-medium text-foreground leading-snug truncate">
834
+ {label}
835
+ </p>
836
+ {subtitle && (
837
+ <p className="text-[11px] text-muted-foreground/70 truncate">
838
+ {subtitle}
839
+ </p>
840
+ )}
841
+ </div>
842
+ </div>
843
+ <div className="flex items-center gap-1 shrink-0 text-muted-foreground">
844
+ {external && <ExternalLink className="w-3 h-3" />}
845
+ <ChevronRight className="w-3.5 h-3.5" />
846
+ </div>
847
+ </>
848
+ )
849
+
850
+ const baseClassName =
851
+ "flex items-center justify-between gap-3 py-2 px-2 -mx-2 rounded-md transition-colors"
852
+ const interactiveClassName = disabled
853
+ ? `${baseClassName} opacity-50 cursor-not-allowed`
854
+ : `${baseClassName} hover:bg-muted/50 cursor-pointer`
855
+
856
+ if (disabled) {
857
+ return (
858
+ <div
859
+ className={interactiveClassName}
860
+ title={disabledReason}
861
+ data-testid={testId}
862
+ >
863
+ {content}
864
+ </div>
865
+ )
866
+ }
867
+
868
+ if (href) {
869
+ return (
870
+ <a
871
+ href={href}
872
+ target={external ? "_blank" : undefined}
873
+ rel={external ? "noopener noreferrer" : undefined}
874
+ className={interactiveClassName}
875
+ data-testid={testId}
876
+ >
877
+ {content}
878
+ </a>
879
+ )
880
+ }
881
+
882
+ return (
883
+ <button
884
+ type="button"
885
+ onClick={onClick}
886
+ className={`${interactiveClassName} w-full text-left`}
887
+ data-testid={testId}
888
+ >
889
+ {content}
890
+ </button>
891
+ )
892
+ }
893
+
894
+ // ---------------------------------------------------------------------------
895
+ // SourcesToggle – collapsible sources list
896
+ // ---------------------------------------------------------------------------
897
+
781
898
  function SourcesToggle() {
782
899
  const [expanded, setExpanded] = React.useState(false)
783
900
 
@@ -175,7 +175,7 @@ function Trigger({ className }: { className?: string }) {
175
175
  className={cn(
176
176
  "p-1.5 rounded transition-colors",
177
177
  thumbState === "down"
178
- ? "bg-red-50 text-red-600 dark:bg-red-950/30 dark:text-red-400"
178
+ ? "bg-muted text-foreground"
179
179
  : "hover:bg-muted text-muted-foreground hover:text-foreground"
180
180
  )}
181
181
  >
@@ -1037,7 +1037,7 @@ function SuggestedActionCard({
1037
1037
  onClick={() => handleThumbClick("down")}
1038
1038
  className={`p-1.5 rounded transition-colors ${
1039
1039
  feedbackOpen && feedbackDirection === "down"
1040
- ? "bg-red-50 text-red-600 dark:bg-red-950/30 dark:text-red-400"
1040
+ ? "bg-muted text-foreground"
1041
1041
  : "hover:bg-muted text-muted-foreground hover:text-foreground"
1042
1042
  }`}
1043
1043
  >