@opensite/ui 2.3.9 → 2.4.1

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.
@@ -894,6 +894,43 @@ function Badge({
894
894
  }
895
895
  );
896
896
  }
897
+ function TextInner({ as, className, children, ...props }, ref) {
898
+ const Component = as || "span";
899
+ return /* @__PURE__ */ jsxRuntime.jsx(Component, { ref, className: cn(className), ...props, children });
900
+ }
901
+ var Text = React__namespace.forwardRef(TextInner);
902
+ Text.displayName = "Text";
903
+ function isContentTextItem(item) {
904
+ return item !== null && typeof item === "object" && !React__namespace.isValidElement(item) && "_type" in item && item._type === "text";
905
+ }
906
+ var ContentGroup = React__namespace.forwardRef(
907
+ ({ items, className, children, ...props }, ref) => {
908
+ const hasContent = items && items.length > 0;
909
+ if (!hasContent) {
910
+ return null;
911
+ }
912
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn(className), ...props, children: [
913
+ items.map((item, idx) => {
914
+ if (isContentTextItem(item)) {
915
+ const { _type, ...textProps } = item;
916
+ return /* @__PURE__ */ jsxRuntime.jsx(Text, { ...textProps }, idx);
917
+ }
918
+ const reactNode = item;
919
+ if (React__namespace.isValidElement(reactNode)) {
920
+ return React__namespace.cloneElement(reactNode, { key: reactNode.key ?? idx });
921
+ }
922
+ return /* @__PURE__ */ jsxRuntime.jsx(React__namespace.Fragment, { children: reactNode }, idx);
923
+ }),
924
+ children
925
+ ] });
926
+ }
927
+ );
928
+ ContentGroup.displayName = "ContentGroup";
929
+ var ASPECT_RATIO_CLASSES = {
930
+ square: "aspect-square",
931
+ horizontal: "aspect-video",
932
+ vertical: "aspect-[3/4]"
933
+ };
897
934
  function FeatureImageCardsThreeColumn({
898
935
  title,
899
936
  description,
@@ -911,7 +948,8 @@ function FeatureImageCardsThreeColumn({
911
948
  background,
912
949
  pattern,
913
950
  patternOpacity,
914
- patternClassName
951
+ patternClassName,
952
+ cardAspectRatios = { desktop: "vertical", mobile: "square" }
915
953
  }) {
916
954
  const renderImage = React.useCallback(
917
955
  (card, imageAlt) => {
@@ -922,7 +960,7 @@ function FeatureImageCardsThreeColumn({
922
960
  {
923
961
  src: card.imageSrc,
924
962
  alt: imageAlt,
925
- className: "h-full max-h-[450px] min-h-80 w-full rounded-xl object-cover object-center",
963
+ className: "absolute inset-0 h-full w-full rounded-xl object-cover object-center",
926
964
  loading: "lazy",
927
965
  optixFlowConfig
928
966
  }
@@ -941,77 +979,149 @@ function FeatureImageCardsThreeColumn({
941
979
  },
942
980
  []
943
981
  );
982
+ const renderCardBadge = React.useCallback(
983
+ (card) => {
984
+ return card.badgeText || card.avatarSrc || card.icon || card.iconName ? /* @__PURE__ */ jsxRuntime.jsxs(
985
+ Badge,
986
+ {
987
+ variant: "default",
988
+ className: cn("py-1 px-3 gap-2", card.badgeClassName),
989
+ children: [
990
+ renderBadgeIcon(card),
991
+ card.badgeText
992
+ ]
993
+ }
994
+ ) : null;
995
+ },
996
+ [renderBadgeIcon]
997
+ );
998
+ const cardHasTextContent = React.useCallback(
999
+ (card) => {
1000
+ const hasBadge = !!(card.badgeText || card.avatarSrc || card.icon || card.iconName);
1001
+ return hasBadge || !!card.title || !!card.subtitle || !!card.linkText;
1002
+ },
1003
+ []
1004
+ );
1005
+ const renderCardText = React.useCallback(
1006
+ (card) => {
1007
+ if (!cardHasTextContent(card)) {
1008
+ return null;
1009
+ }
1010
+ const cardBadge = renderCardBadge(card);
1011
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-0 flex h-full w-full flex-col justify-between p-4 md:p-6", children: [
1012
+ cardBadge || /* @__PURE__ */ jsxRuntime.jsx("div", {}),
1013
+ card.title || card.subtitle || card.linkText ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4 md:gap-6 text-white", children: [
1014
+ card.title || card.subtitle ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-2 md:gap-4", children: [
1015
+ card.title && (typeof card.title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1016
+ "h3",
1017
+ {
1018
+ className: cn(
1019
+ "text-lg md:text-xl font-semibold",
1020
+ card.titleClassName
1021
+ ),
1022
+ children: card.title
1023
+ }
1024
+ ) : card.title),
1025
+ card.subtitle && (typeof card.subtitle === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1026
+ "p",
1027
+ {
1028
+ className: cn(
1029
+ "text-base font-normal",
1030
+ card.subtitleClassName
1031
+ ),
1032
+ children: card.subtitle
1033
+ }
1034
+ ) : card.subtitle)
1035
+ ] }) : null,
1036
+ card.linkText && /* @__PURE__ */ jsxRuntime.jsxs(
1037
+ "div",
1038
+ {
1039
+ className: cn(
1040
+ "font-bold text-xs uppercase flex items-center gap-2",
1041
+ card.linkClassName
1042
+ ),
1043
+ children: [
1044
+ card.linkText,
1045
+ /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-up-right", size: 18 })
1046
+ ]
1047
+ }
1048
+ )
1049
+ ] }) : null
1050
+ ] });
1051
+ },
1052
+ [cardHasTextContent, renderCardBadge]
1053
+ );
944
1054
  const cardsContent = React.useMemo(() => {
945
1055
  if (cardsSlot) return cardsSlot;
946
1056
  if (!cards || cards.length === 0) return null;
947
1057
  return cards.map((card, index) => {
948
1058
  const imageAlt = card.imageAlt || (typeof card.title === "string" ? card.title : "Card image");
1059
+ const mobileAspectClass = ASPECT_RATIO_CLASSES[cardAspectRatios.mobile];
1060
+ const desktopAspectClass = `md:${ASPECT_RATIO_CLASSES[cardAspectRatios.desktop]}`;
949
1061
  return /* @__PURE__ */ jsxRuntime.jsxs(
950
1062
  Pressable,
951
1063
  {
952
1064
  href: card.link,
953
1065
  onClick: card.onClick,
954
1066
  className: cn(
955
- "group relative overflow-hidden rounded-xl",
1067
+ "group relative overflow-hidden rounded-2xl shadow-xl",
1068
+ mobileAspectClass,
1069
+ desktopAspectClass,
956
1070
  cardClassName,
957
1071
  card.className
958
1072
  ),
959
1073
  children: [
960
1074
  renderImage(card, imageAlt),
961
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 right-0 bottom-0 left-0 translate-y-10 md:translate-y-20 rounded-xl bg-linear-to-t from-black to-transparent transition-transform duration-300 group-hover:translate-y-0" }),
962
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-0 flex h-full w-full flex-col justify-between p-4 md:p-6", children: [
963
- (card.badgeText || card.avatarSrc || card.icon || card.iconName) && /* @__PURE__ */ jsxRuntime.jsxs(
964
- Badge,
965
- {
966
- variant: "default",
967
- className: cn("py-1 px-4", card.badgeClassName),
968
- children: [
969
- renderBadgeIcon(card),
970
- card.badgeText
971
- ]
972
- }
973
- ),
974
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 md:gap-4", children: [
975
- card.title && (typeof card.title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
976
- "h3",
977
- {
978
- className: cn(
979
- "text-lg md:text-xl font-semibold",
980
- card.titleClassName
981
- ),
982
- children: card.title
983
- }
984
- ) : /* @__PURE__ */ jsxRuntime.jsx(
985
- "div",
986
- {
987
- className: cn(
988
- "text-lg md:text-xl font-semibold",
989
- card.titleClassName
990
- ),
991
- children: card.title
992
- }
993
- )),
994
- card.linkText && card.link && /* @__PURE__ */ jsxRuntime.jsxs(
995
- "div",
996
- {
997
- className: cn(
998
- "font-bold text-xs uppercase flex items-center gap-2",
999
- card.linkClassName
1000
- ),
1001
- children: [
1002
- card.linkText,
1003
- /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-up-right", size: 18 })
1004
- ]
1005
- }
1006
- )
1007
- ] })
1008
- ] })
1075
+ cardHasTextContent(card) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 right-0 bottom-0 left-0 translate-y-10 md:translate-y-20 rounded-xl bg-linear-to-t from-black to-transparent transition-transform duration-300 group-hover:translate-y-0" }),
1076
+ renderCardText(card)
1009
1077
  ]
1010
1078
  },
1011
1079
  index
1012
1080
  );
1013
1081
  });
1014
- }, [cardsSlot, cards, cardClassName, renderImage, renderBadgeIcon]);
1082
+ }, [
1083
+ cardsSlot,
1084
+ cards,
1085
+ cardClassName,
1086
+ cardAspectRatios,
1087
+ renderImage,
1088
+ cardHasTextContent,
1089
+ renderCardText
1090
+ ]);
1091
+ const contentItems = React.useMemo(() => {
1092
+ const items = [];
1093
+ if (title) {
1094
+ if (typeof title === "string") {
1095
+ items.push({
1096
+ _type: "text",
1097
+ as: "h2",
1098
+ className: cn(
1099
+ "text-3xl font-semibold text-balance md:text-4xl lg:text-5xl max-w-full md:max-w-md",
1100
+ title
1101
+ ),
1102
+ children: title
1103
+ });
1104
+ } else {
1105
+ items.push(title);
1106
+ }
1107
+ }
1108
+ if (description) {
1109
+ if (typeof description === "string") {
1110
+ items.push({
1111
+ _type: "text",
1112
+ as: "p",
1113
+ className: cn(
1114
+ "text-xl max-w-full md:max-w-md text-balance",
1115
+ descriptionClassName
1116
+ ),
1117
+ children: description
1118
+ });
1119
+ } else {
1120
+ items.push(description);
1121
+ }
1122
+ }
1123
+ return items;
1124
+ }, [title, titleClassName, description, descriptionClassName]);
1015
1125
  return /* @__PURE__ */ jsxRuntime.jsx(
1016
1126
  Section,
1017
1127
  {
@@ -1023,34 +1133,16 @@ function FeatureImageCardsThreeColumn({
1023
1133
  className,
1024
1134
  containerClassName,
1025
1135
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-6 md:space-y-16", children: [
1026
- title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-6 text-left", headerClassName), children: [
1027
- title && (typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1028
- "h2",
1029
- {
1030
- className: cn(
1031
- "text-2xl font-semibold text-balance md:text-3xl lg:text-4xl max-w-lg md:max-w-md",
1032
- titleClassName
1033
- ),
1034
- children: title
1035
- }
1036
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1037
- "div",
1038
- {
1039
- className: cn(
1040
- "text-2xl font-semibold text-balance md:text-3xl lg:text-4xl max-w-lg md:max-w-md",
1041
- titleClassName
1042
- ),
1043
- children: title
1044
- }
1045
- )),
1046
- description && (typeof description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("max-w-lg md:max-w-md", descriptionClassName), children: description }) : /* @__PURE__ */ jsxRuntime.jsx(
1047
- "div",
1048
- {
1049
- className: cn("max-w-lg md:max-w-md", descriptionClassName),
1050
- children: description
1051
- }
1052
- ))
1053
- ] }) : null,
1136
+ /* @__PURE__ */ jsxRuntime.jsx(
1137
+ ContentGroup,
1138
+ {
1139
+ items: contentItems,
1140
+ className: cn(
1141
+ "flex flex-col gap-2 text-left items-start",
1142
+ headerClassName
1143
+ )
1144
+ }
1145
+ ),
1054
1146
  /* @__PURE__ */ jsxRuntime.jsx(
1055
1147
  "div",
1056
1148
  {
@@ -27,6 +27,10 @@ interface FeatureImageCardsThreeColumnItem {
27
27
  * Card title content
28
28
  */
29
29
  title?: React.ReactNode;
30
+ /**
31
+ * Card subtitle content
32
+ */
33
+ subtitle?: React.ReactNode;
30
34
  /**
31
35
  * Link text content
32
36
  */
@@ -63,6 +67,10 @@ interface FeatureImageCardsThreeColumnItem {
63
67
  * Additional CSS classes for the title
64
68
  */
65
69
  titleClassName?: string;
70
+ /**
71
+ * Additional CSS classes for the subtitle
72
+ */
73
+ subtitleClassName?: string;
66
74
  /**
67
75
  * Additional CSS classes for the link text
68
76
  */
@@ -137,34 +145,15 @@ interface FeatureImageCardsThreeColumnProps {
137
145
  * Additional CSS classes for the pattern overlay
138
146
  */
139
147
  patternClassName?: string;
148
+ /**
149
+ * Media card aspect ratios
150
+ * @default { desktop: "vertical", mobile: "square" }
151
+ */
152
+ cardAspectRatios?: {
153
+ desktop: "square" | "horizontal" | "vertical";
154
+ mobile: "square" | "horizontal" | "vertical";
155
+ };
140
156
  }
141
- /**
142
- * Feature Image Cards Three Column - Three-column grid of image cards with
143
- * gradient overlays, badges, and CTAs.
144
- *
145
- * Layout: Three equal-width cards with full-height images and overlays.
146
- * Key features: Gradient overlays, icon/avatar badges, hover animations, CTAs.
147
- * Best for: Portfolio showcases, product categories, feature highlights.
148
- *
149
- * @example
150
- * ```tsx
151
- * <FeatureImageCardsThreeColumn
152
- * title="Versatile Designs"
153
- * description="Personalize the box to fit your requirements"
154
- * cards={[
155
- * {
156
- * iconName: "lucide/zap",
157
- * badgeText: "Advanced tools",
158
- * title: "Transform your website",
159
- * linkText: "Explore all features",
160
- * link: "/features",
161
- * imageSrc: "/feature.jpg",
162
- * imageAlt: "Feature"
163
- * },
164
- * ]}
165
- * />
166
- * ```
167
- */
168
- declare function FeatureImageCardsThreeColumn({ title, description, headerClassName, cards, cardsSlot, className, containerClassName, spacing, titleClassName, descriptionClassName, gridClassName, cardClassName, optixFlowConfig, background, pattern, patternOpacity, patternClassName, }: FeatureImageCardsThreeColumnProps): React.JSX.Element;
157
+ declare function FeatureImageCardsThreeColumn({ title, description, headerClassName, cards, cardsSlot, className, containerClassName, spacing, titleClassName, descriptionClassName, gridClassName, cardClassName, optixFlowConfig, background, pattern, patternOpacity, patternClassName, cardAspectRatios, }: FeatureImageCardsThreeColumnProps): React.JSX.Element;
169
158
 
170
159
  export { FeatureImageCardsThreeColumn, type FeatureImageCardsThreeColumnProps };
@@ -27,6 +27,10 @@ interface FeatureImageCardsThreeColumnItem {
27
27
  * Card title content
28
28
  */
29
29
  title?: React.ReactNode;
30
+ /**
31
+ * Card subtitle content
32
+ */
33
+ subtitle?: React.ReactNode;
30
34
  /**
31
35
  * Link text content
32
36
  */
@@ -63,6 +67,10 @@ interface FeatureImageCardsThreeColumnItem {
63
67
  * Additional CSS classes for the title
64
68
  */
65
69
  titleClassName?: string;
70
+ /**
71
+ * Additional CSS classes for the subtitle
72
+ */
73
+ subtitleClassName?: string;
66
74
  /**
67
75
  * Additional CSS classes for the link text
68
76
  */
@@ -137,34 +145,15 @@ interface FeatureImageCardsThreeColumnProps {
137
145
  * Additional CSS classes for the pattern overlay
138
146
  */
139
147
  patternClassName?: string;
148
+ /**
149
+ * Media card aspect ratios
150
+ * @default { desktop: "vertical", mobile: "square" }
151
+ */
152
+ cardAspectRatios?: {
153
+ desktop: "square" | "horizontal" | "vertical";
154
+ mobile: "square" | "horizontal" | "vertical";
155
+ };
140
156
  }
141
- /**
142
- * Feature Image Cards Three Column - Three-column grid of image cards with
143
- * gradient overlays, badges, and CTAs.
144
- *
145
- * Layout: Three equal-width cards with full-height images and overlays.
146
- * Key features: Gradient overlays, icon/avatar badges, hover animations, CTAs.
147
- * Best for: Portfolio showcases, product categories, feature highlights.
148
- *
149
- * @example
150
- * ```tsx
151
- * <FeatureImageCardsThreeColumn
152
- * title="Versatile Designs"
153
- * description="Personalize the box to fit your requirements"
154
- * cards={[
155
- * {
156
- * iconName: "lucide/zap",
157
- * badgeText: "Advanced tools",
158
- * title: "Transform your website",
159
- * linkText: "Explore all features",
160
- * link: "/features",
161
- * imageSrc: "/feature.jpg",
162
- * imageAlt: "Feature"
163
- * },
164
- * ]}
165
- * />
166
- * ```
167
- */
168
- declare function FeatureImageCardsThreeColumn({ title, description, headerClassName, cards, cardsSlot, className, containerClassName, spacing, titleClassName, descriptionClassName, gridClassName, cardClassName, optixFlowConfig, background, pattern, patternOpacity, patternClassName, }: FeatureImageCardsThreeColumnProps): React.JSX.Element;
157
+ declare function FeatureImageCardsThreeColumn({ title, description, headerClassName, cards, cardsSlot, className, containerClassName, spacing, titleClassName, descriptionClassName, gridClassName, cardClassName, optixFlowConfig, background, pattern, patternOpacity, patternClassName, cardAspectRatios, }: FeatureImageCardsThreeColumnProps): React.JSX.Element;
169
158
 
170
159
  export { FeatureImageCardsThreeColumn, type FeatureImageCardsThreeColumnProps };