@lukeashford/aurelius 2.1.0 → 2.2.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/dist/index.mjs CHANGED
@@ -74,28 +74,40 @@ Input.displayName = "Input";
74
74
 
75
75
  // src/components/Card.tsx
76
76
  import React3 from "react";
77
+ import { Check } from "lucide-react";
78
+ var VARIANT_STYLES = {
79
+ default: "bg-charcoal shadow-sm border border-gold/30",
80
+ elevated: "bg-charcoal shadow-lg border-0",
81
+ outlined: "bg-charcoal shadow-none border border-ash",
82
+ ghost: "bg-transparent shadow-none border-0",
83
+ featured: "bg-charcoal border border-gold shadow-glow-sm"
84
+ };
77
85
  function cx3(...classes) {
78
86
  return classes.filter(Boolean).join(" ");
79
87
  }
80
88
  var Card = React3.forwardRef(
81
- ({ variant = "default", interactive = false, className, ...rest }, ref) => {
82
- const base = "rounded-none p-6";
83
- const variantClasses = {
84
- default: "bg-charcoal shadow-sm border border-gold/30",
85
- elevated: "bg-charcoal shadow-lg border-0",
86
- outlined: "bg-charcoal shadow-none border border-ash",
87
- ghost: "bg-transparent shadow-none border-0",
88
- featured: "bg-charcoal border border-gold shadow-[0_0_10px_rgba(201,162,39,0.2)]"
89
- };
90
- const interactiveClass = interactive ? "transition-all duration-200 hover:border-gold hover:shadow-glow cursor-pointer" : "";
91
- const variantClass = variantClasses[variant];
89
+ ({ variant = "default", interactive = false, selected = false, className, children, ...props }, ref) => {
92
90
  return /* @__PURE__ */ React3.createElement(
93
91
  "div",
94
92
  {
95
93
  ref,
96
- className: cx3(base, variantClass, interactiveClass, className),
97
- ...rest
98
- }
94
+ className: cx3(
95
+ "rounded-none p-6 relative",
96
+ VARIANT_STYLES[variant],
97
+ interactive && "transition-all duration-200 hover:border-gold hover:shadow-glow cursor-pointer",
98
+ selected && "border-gold shadow-glow-md",
99
+ className
100
+ ),
101
+ ...props
102
+ },
103
+ children,
104
+ selected && /* @__PURE__ */ React3.createElement(
105
+ "div",
106
+ {
107
+ className: "absolute top-3 right-3 flex items-center justify-center h-6 w-6 rounded-full bg-gold text-obsidian"
108
+ },
109
+ /* @__PURE__ */ React3.createElement(Check, { className: "h-4 w-4" })
110
+ )
99
111
  );
100
112
  }
101
113
  );
@@ -626,23 +638,456 @@ var Modal = ({ isOpen, onClose, title, children, className }) => {
626
638
  };
627
639
  Modal.displayName = "Modal";
628
640
 
641
+ // src/components/Stepper.tsx
642
+ import React18 from "react";
643
+ import { Check as Check2 } from "lucide-react";
644
+ function cx18(...classes) {
645
+ return classes.filter(Boolean).join(" ");
646
+ }
647
+ var Stepper = React18.forwardRef(
648
+ ({ steps, currentStep, status, className, ...rest }, ref) => {
649
+ const currentIndex = steps.findIndex((step) => step.id === currentStep);
650
+ const getStepState = (index) => {
651
+ if (index < currentIndex) {
652
+ return "complete";
653
+ }
654
+ if (index === currentIndex) {
655
+ return status || "current";
656
+ }
657
+ return "future";
658
+ };
659
+ return /* @__PURE__ */ React18.createElement(
660
+ "div",
661
+ {
662
+ ref,
663
+ className: cx18("flex items-center w-full", className),
664
+ ...rest
665
+ },
666
+ steps.map((step, index) => {
667
+ const state = getStepState(index);
668
+ const isLast = index === steps.length - 1;
669
+ return /* @__PURE__ */ React18.createElement(React18.Fragment, { key: step.id }, /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React18.createElement(
670
+ "div",
671
+ {
672
+ className: cx18(
673
+ "flex items-center justify-center w-10 h-10 rounded-full border-2 font-semibold text-sm transition-all duration-200",
674
+ state === "complete" && "bg-gold border-gold text-obsidian",
675
+ state === "current" && "bg-charcoal border-gold text-gold",
676
+ state === "error" && "bg-error border-error text-white",
677
+ state === "future" && "bg-charcoal border-ash text-silver"
678
+ )
679
+ },
680
+ state === "complete" ? /* @__PURE__ */ React18.createElement(Check2, { className: "h-5 w-5" }) : /* @__PURE__ */ React18.createElement("span", null, index + 1)
681
+ ), /* @__PURE__ */ React18.createElement(
682
+ "span",
683
+ {
684
+ className: cx18(
685
+ "mt-2 text-xs font-medium",
686
+ state === "complete" && "text-gold",
687
+ state === "current" && "text-white",
688
+ state === "error" && "text-error",
689
+ state === "future" && "text-silver"
690
+ )
691
+ },
692
+ step.label
693
+ )), !isLast && /* @__PURE__ */ React18.createElement(
694
+ "div",
695
+ {
696
+ className: cx18(
697
+ "flex-1 h-0.5 mx-4 transition-all duration-200",
698
+ index < currentIndex ? "bg-gold" : "bg-ash"
699
+ )
700
+ }
701
+ ));
702
+ })
703
+ );
704
+ }
705
+ );
706
+ Stepper.displayName = "Stepper";
707
+
708
+ // src/components/Message.tsx
709
+ import React21 from "react";
710
+
711
+ // src/components/MarkdownContent.tsx
712
+ import React19, { useMemo } from "react";
713
+ import DOMPurify from "dompurify";
714
+ function cx19(...classes) {
715
+ return classes.filter(Boolean).join(" ");
716
+ }
717
+ var DEFAULT_SANITIZE_CONFIG = {
718
+ ALLOWED_TAGS: [
719
+ "h1",
720
+ "h2",
721
+ "h3",
722
+ "h4",
723
+ "h5",
724
+ "h6",
725
+ "p",
726
+ "br",
727
+ "hr",
728
+ "strong",
729
+ "b",
730
+ "em",
731
+ "i",
732
+ "u",
733
+ "s",
734
+ "strike",
735
+ "del",
736
+ "ins",
737
+ "sup",
738
+ "sub",
739
+ "mark",
740
+ "small",
741
+ "ul",
742
+ "ol",
743
+ "li",
744
+ "a",
745
+ "code",
746
+ "pre",
747
+ "kbd",
748
+ "samp",
749
+ "var",
750
+ "blockquote",
751
+ "q",
752
+ "cite",
753
+ "abbr",
754
+ "table",
755
+ "thead",
756
+ "tbody",
757
+ "tfoot",
758
+ "tr",
759
+ "th",
760
+ "td",
761
+ "caption",
762
+ "colgroup",
763
+ "col",
764
+ "div",
765
+ "span",
766
+ "details",
767
+ "summary"
768
+ ],
769
+ ALLOWED_ATTR: [
770
+ "href",
771
+ "title",
772
+ "target",
773
+ "rel",
774
+ "class",
775
+ "id",
776
+ "colspan",
777
+ "rowspan",
778
+ "scope",
779
+ "open"
780
+ ],
781
+ ADD_ATTR: ["target", "rel"],
782
+ ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i
783
+ };
784
+ function useDOMPurifySetup() {
785
+ useMemo(() => {
786
+ DOMPurify.addHook("afterSanitizeAttributes", (node) => {
787
+ if (node.tagName === "A") {
788
+ node.setAttribute("target", "_blank");
789
+ node.setAttribute("rel", "noopener noreferrer");
790
+ }
791
+ });
792
+ }, []);
793
+ }
794
+ var MarkdownContent = React19.forwardRef(
795
+ ({ className, content, sanitizeConfig, ...rest }, ref) => {
796
+ useDOMPurifySetup();
797
+ const sanitizedHtml = useMemo(() => {
798
+ if (!content) {
799
+ return "";
800
+ }
801
+ const config = sanitizeConfig ?? DEFAULT_SANITIZE_CONFIG;
802
+ return DOMPurify.sanitize(content, config);
803
+ }, [content, sanitizeConfig]);
804
+ return /* @__PURE__ */ React19.createElement(
805
+ "div",
806
+ {
807
+ ref,
808
+ className: cx19("prose", className),
809
+ dangerouslySetInnerHTML: { __html: sanitizedHtml },
810
+ ...rest
811
+ }
812
+ );
813
+ }
814
+ );
815
+ MarkdownContent.displayName = "MarkdownContent";
816
+
817
+ // src/components/StreamingCursor.tsx
818
+ import React20 from "react";
819
+ function cx20(...classes) {
820
+ return classes.filter(Boolean).join(" ");
821
+ }
822
+ var StreamingCursor = React20.forwardRef(
823
+ ({ className, variant = "line", ...rest }, ref) => {
824
+ const variantStyles3 = {
825
+ block: "w-2.5 h-cursor translate-y-cursor-offset",
826
+ line: "w-0.5 h-cursor translate-y-cursor-offset",
827
+ underscore: "w-2.5 h-0.5 self-end mb-0.5"
828
+ };
829
+ return /* @__PURE__ */ React20.createElement(
830
+ "span",
831
+ {
832
+ ref,
833
+ className: cx20(
834
+ "inline-block bg-current animate-cursor-blink",
835
+ variantStyles3[variant],
836
+ className
837
+ ),
838
+ "aria-hidden": "true",
839
+ ...rest
840
+ }
841
+ );
842
+ }
843
+ );
844
+ StreamingCursor.displayName = "StreamingCursor";
845
+
846
+ // src/components/Message.tsx
847
+ function cx21(...classes) {
848
+ return classes.filter(Boolean).join(" ");
849
+ }
850
+ var variantStyles2 = {
851
+ user: "bg-gold text-obsidian ml-auto",
852
+ assistant: "bg-charcoal border border-ash text-white mr-auto"
853
+ };
854
+ var Message = React21.forwardRef(
855
+ ({ variant = "assistant", className, content, isStreaming, ...rest }, ref) => {
856
+ const isUser = variant === "user";
857
+ return /* @__PURE__ */ React21.createElement(
858
+ "div",
859
+ {
860
+ ref,
861
+ className: cx21(
862
+ "px-3 py-2 w-fit",
863
+ variantStyles2[variant],
864
+ className
865
+ ),
866
+ ...rest
867
+ },
868
+ /* @__PURE__ */ React21.createElement(
869
+ MarkdownContent,
870
+ {
871
+ content,
872
+ className: cx21("prose-sm", isUser ? "prose-inherit" : "prose-invert")
873
+ }
874
+ ),
875
+ isStreaming && /* @__PURE__ */ React21.createElement(StreamingCursor, { className: "ml-0.5" })
876
+ );
877
+ }
878
+ );
879
+ Message.displayName = "Message";
880
+
881
+ // src/components/ChatHistory.tsx
882
+ import React22 from "react";
883
+ function cx22(...classes) {
884
+ return classes.filter(Boolean).join(" ");
885
+ }
886
+ var ChatHistory = React22.forwardRef(
887
+ ({ messages, className, ...rest }, ref) => {
888
+ return /* @__PURE__ */ React22.createElement(
889
+ "div",
890
+ {
891
+ ref,
892
+ className: cx22("flex flex-col gap-3 w-full", className),
893
+ ...rest
894
+ },
895
+ messages.map(({ id, variant, className: messageClassName, ...messageProps }, index) => /* @__PURE__ */ React22.createElement(
896
+ Message,
897
+ {
898
+ key: id ?? index,
899
+ variant,
900
+ className: messageClassName,
901
+ ...messageProps
902
+ }
903
+ ))
904
+ );
905
+ }
906
+ );
907
+ ChatHistory.displayName = "ChatHistory";
908
+
909
+ // src/components/BrandIcon.tsx
910
+ import React23 from "react";
911
+ function cx23(...classes) {
912
+ return classes.filter(Boolean).join(" ");
913
+ }
914
+ var sizeMap2 = {
915
+ sm: "h-8 w-8 text-sm",
916
+ md: "h-12 w-12 text-base",
917
+ lg: "h-16 w-16 text-lg"
918
+ };
919
+ var BrandIcon = React23.forwardRef(
920
+ ({ size = "md", variant = "solid", children, className, ...rest }, ref) => {
921
+ const variantClasses = variant === "solid" ? "bg-gold text-obsidian border-2 border-gold" : "bg-transparent text-gold border-2 border-gold";
922
+ return /* @__PURE__ */ React23.createElement(
923
+ "div",
924
+ {
925
+ ref,
926
+ className: cx23(
927
+ "inline-flex items-center justify-center rounded-none font-bold select-none overflow-hidden",
928
+ sizeMap2[size],
929
+ variantClasses,
930
+ className
931
+ ),
932
+ ...rest
933
+ },
934
+ children
935
+ );
936
+ }
937
+ );
938
+ BrandIcon.displayName = "BrandIcon";
939
+
940
+ // src/components/ColorSwatch.tsx
941
+ import React24 from "react";
942
+ function cx24(...classes) {
943
+ return classes.filter(Boolean).join(" ");
944
+ }
945
+ var ColorSwatch = React24.forwardRef(
946
+ ({ color, label, className, ...rest }, ref) => {
947
+ return /* @__PURE__ */ React24.createElement(
948
+ "div",
949
+ {
950
+ ref,
951
+ className: cx24("flex flex-col items-center gap-2", className),
952
+ ...rest
953
+ },
954
+ /* @__PURE__ */ React24.createElement(
955
+ "div",
956
+ {
957
+ className: "h-16 w-16 border-2 border-ash rounded-none shadow-sm",
958
+ style: { backgroundColor: color },
959
+ "aria-label": label || color
960
+ }
961
+ ),
962
+ label && /* @__PURE__ */ React24.createElement("span", { className: "text-xs text-silver font-medium" }, label)
963
+ );
964
+ }
965
+ );
966
+ ColorSwatch.displayName = "ColorSwatch";
967
+
968
+ // src/components/ImageCard.tsx
969
+ import React25 from "react";
970
+ var ASPECT_RATIO_PRESETS = {
971
+ landscape: "3 / 2",
972
+ portrait: "2 / 3",
973
+ square: "1 / 1"
974
+ };
975
+ function resolveAspectRatio(ratio) {
976
+ if (ratio in ASPECT_RATIO_PRESETS) {
977
+ return ASPECT_RATIO_PRESETS[ratio];
978
+ }
979
+ return ratio.replace("/", " / ");
980
+ }
981
+ function cx25(...classes) {
982
+ return classes.filter(Boolean).join(" ");
983
+ }
984
+ var ImageCard = React25.forwardRef(
985
+ ({
986
+ src,
987
+ alt,
988
+ title,
989
+ subtitle,
990
+ aspectRatio,
991
+ objectFit = "cover",
992
+ overlay,
993
+ mediaClassName,
994
+ contentClassName,
995
+ className,
996
+ children,
997
+ ...props
998
+ }, ref) => {
999
+ const hasAspectRatio = aspectRatio !== void 0;
1000
+ const isContain = objectFit === "contain";
1001
+ return /* @__PURE__ */ React25.createElement(Card, { ref, className: cx25("p-0 overflow-hidden group w-fit", className), ...props }, /* @__PURE__ */ React25.createElement(
1002
+ "div",
1003
+ {
1004
+ className: cx25(
1005
+ "relative",
1006
+ hasAspectRatio && "overflow-hidden",
1007
+ mediaClassName
1008
+ ),
1009
+ style: hasAspectRatio ? { aspectRatio: resolveAspectRatio(aspectRatio) } : void 0
1010
+ },
1011
+ /* @__PURE__ */ React25.createElement(
1012
+ "img",
1013
+ {
1014
+ src,
1015
+ alt,
1016
+ className: cx25(
1017
+ "block max-w-full",
1018
+ hasAspectRatio && "w-full h-full",
1019
+ hasAspectRatio && (isContain ? "object-contain" : "object-cover"),
1020
+ !hasAspectRatio && "h-auto"
1021
+ )
1022
+ }
1023
+ ),
1024
+ overlay && /* @__PURE__ */ React25.createElement(
1025
+ "div",
1026
+ {
1027
+ className: "absolute inset-0 bg-obsidian/80 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex items-center justify-center"
1028
+ },
1029
+ overlay
1030
+ )
1031
+ ), (title || subtitle || children) && /* @__PURE__ */ React25.createElement("div", { className: cx25("px-4 pt-4", contentClassName) }, title && /* @__PURE__ */ React25.createElement("h4", { className: "text-lg font-semibold leading-tight" }, title), subtitle && /* @__PURE__ */ React25.createElement("p", { className: "text-sm text-silver leading-normal" }, subtitle), children));
1032
+ }
1033
+ );
1034
+ ImageCard.displayName = "ImageCard";
1035
+
1036
+ // src/components/SectionHeading.tsx
1037
+ import React26 from "react";
1038
+ function cx26(...classes) {
1039
+ return classes.filter(Boolean).join(" ");
1040
+ }
1041
+ var levelStyles = {
1042
+ h2: "text-2xl mb-4",
1043
+ h3: "text-xl mb-3"
1044
+ };
1045
+ var SectionHeading = React26.forwardRef(
1046
+ ({ level = "h2", children, className, ...rest }, ref) => {
1047
+ const Component = level;
1048
+ return /* @__PURE__ */ React26.createElement(
1049
+ Component,
1050
+ {
1051
+ ref,
1052
+ className: cx26(
1053
+ "text-gold font-semibold tracking-tight",
1054
+ levelStyles[level],
1055
+ className
1056
+ ),
1057
+ ...rest
1058
+ },
1059
+ children
1060
+ );
1061
+ }
1062
+ );
1063
+ SectionHeading.displayName = "SectionHeading";
1064
+
629
1065
  // src/index.ts
630
1066
  var version = "2.0.0";
631
1067
  export {
632
1068
  Alert,
633
1069
  Avatar,
634
1070
  Badge,
1071
+ BrandIcon,
635
1072
  Button,
636
1073
  Card,
1074
+ ChatHistory,
637
1075
  Checkbox,
1076
+ ColorSwatch,
638
1077
  HelperText,
1078
+ ImageCard,
639
1079
  Input,
640
1080
  Label,
1081
+ MarkdownContent,
1082
+ Message,
641
1083
  Modal,
642
1084
  Radio,
1085
+ SectionHeading,
643
1086
  Select,
644
1087
  Skeleton,
645
1088
  Spinner,
1089
+ Stepper,
1090
+ StreamingCursor,
646
1091
  Switch,
647
1092
  Textarea,
648
1093
  Tooltip,