@opensite/ui 3.8.1 → 3.9.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.
@@ -764,6 +764,13 @@ function getNavbarLayoutClasses(layoutVariant = "fullScreenContainerizedLinks",
764
764
  };
765
765
  }
766
766
  var MOBILE_BREAKPOINT = 1024;
767
+ var DESKTOP_GROUP_COLUMN_WIDTH = 248;
768
+ var DESKTOP_GROUP_GAP = 8;
769
+ var DESKTOP_GROUP_PADDING_X = 16;
770
+ var getDesktopGroupsGridStyle = (groupCount) => ({
771
+ width: groupCount * DESKTOP_GROUP_COLUMN_WIDTH + Math.max(groupCount - 1, 0) * DESKTOP_GROUP_GAP + DESKTOP_GROUP_PADDING_X,
772
+ gridTemplateColumns: `repeat(${groupCount}, minmax(0, 1fr))`
773
+ });
767
774
  var NavbarMultiColumnGroups = ({
768
775
  className,
769
776
  containerClassName,
@@ -942,33 +949,47 @@ var NavbarMultiColumnGroups = ({
942
949
  ] });
943
950
  };
944
951
  var DesktopMenuItem = ({ item, index }) => {
945
- if (item.groups) {
952
+ if (item.groups && item.groups.length > 0) {
946
953
  return /* @__PURE__ */ jsxRuntime.jsxs(NavigationMenuItem, { value: `${index}`, children: [
947
954
  /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuTrigger, { className: "h-fit bg-transparent px-2.5 font-normal text-muted-foreground", children: item.title }),
948
- /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex p-2", style: { width: item.groups.length * 248 }, children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { children: [
949
- /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
950
- group.links.map((link, linkIndex) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
951
- NavigationMenuLink,
952
- {
953
- asChild: true,
954
- className: "group/link flex-row gap-2 px-3 py-2 transition-colors duration-200",
955
- children: /* @__PURE__ */ jsxRuntime.jsxs(pressable.Pressable, { href: link.url, children: [
956
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(
957
- DynamicIcon,
958
- {
959
- name: link.icon || link.iconName,
960
- size: 16,
961
- className: "m-auto group-hover/link:stroke-black"
962
- }
963
- ) }),
964
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
965
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium", children: link.label }),
966
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground group-hover/link:text-foreground", children: link.description })
967
- ] })
968
- ] })
969
- }
970
- ) }, `desktop-links-${groupIndex}-${linkIndex}`))
971
- ] }) }, `desktop-group-${groupIndex}`)) }) })
955
+ /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsxRuntime.jsx(
956
+ "ul",
957
+ {
958
+ className: "grid box-border max-w-[calc(100vw-2rem)] gap-2 overflow-x-auto p-2",
959
+ style: getDesktopGroupsGridStyle(item.groups.length),
960
+ children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "min-w-0", children: [
961
+ /* @__PURE__ */ jsxRuntime.jsx("li", { className: "line-clamp-2 break-words px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
962
+ group.links.map((link, linkIndex) => /* @__PURE__ */ jsxRuntime.jsx(
963
+ "li",
964
+ {
965
+ className: "min-w-0",
966
+ children: /* @__PURE__ */ jsxRuntime.jsx(
967
+ NavigationMenuLink,
968
+ {
969
+ asChild: true,
970
+ className: "group/link !flex !w-full max-w-full min-w-0 flex-row items-start gap-2 overflow-hidden px-3 py-2 text-left whitespace-normal transition-colors duration-200",
971
+ children: /* @__PURE__ */ jsxRuntime.jsxs(pressable.Pressable, { href: link.url, children: [
972
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(
973
+ DynamicIcon,
974
+ {
975
+ name: link.icon || link.iconName,
976
+ size: 16,
977
+ className: "m-auto group-hover/link:stroke-black"
978
+ }
979
+ ) }),
980
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
981
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 break-words text-sm leading-snug font-medium", children: link.label }),
982
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 break-words text-xs leading-snug text-muted-foreground group-hover/link:text-foreground", children: link.description })
983
+ ] })
984
+ ] })
985
+ }
986
+ )
987
+ },
988
+ `desktop-links-${groupIndex}-${linkIndex}`
989
+ ))
990
+ ] }) }, `desktop-group-${groupIndex}`))
991
+ }
992
+ ) })
972
993
  ] }, `desktop-menu-item-${index}`);
973
994
  }
974
995
  return /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuItem, { value: `${index}`, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -1032,13 +1053,13 @@ var MobileNavigationMenu = ({
1032
1053
  value: `nav-${index}`,
1033
1054
  className: "border-b-0",
1034
1055
  children: [
1035
- /* @__PURE__ */ jsxRuntime.jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: item.title }),
1056
+ /* @__PURE__ */ jsxRuntime.jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words text-left", children: item.title }) }),
1036
1057
  /* @__PURE__ */ jsxRuntime.jsx(AccordionContent, { className: "overflow-x-none", children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
1037
1058
  "div",
1038
1059
  {
1039
1060
  className: "mb-4",
1040
1061
  children: [
1041
- group.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
1062
+ group.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 line-clamp-2 break-words px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
1042
1063
  group.links.map((link, linkIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
1043
1064
  pressable.Pressable,
1044
1065
  {
@@ -1051,10 +1072,10 @@ var MobileNavigationMenu = ({
1051
1072
  {
1052
1073
  name: link.icon || link.iconName,
1053
1074
  size: 16,
1054
- className: "stroke-muted-foreground"
1075
+ className: "shrink-0 stroke-muted-foreground"
1055
1076
  }
1056
1077
  ),
1057
- link.label
1078
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: link.label })
1058
1079
  ]
1059
1080
  },
1060
1081
  `mobile-link-${groupIndex}-${linkIndex}`
@@ -1074,7 +1095,7 @@ var MobileNavigationMenu = ({
1074
1095
  href: item.url,
1075
1096
  className: "flex h-15 items-center rounded-md p-0 px-4 text-left text-base leading-[3.75] font-normal text-muted-foreground ring-ring/10 outline-ring/50 transition-all hover:bg-muted focus-visible:ring-4 focus-visible:outline-1",
1076
1097
  onClick: handleClose,
1077
- children: item.title
1098
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: item.title })
1078
1099
  },
1079
1100
  `nav-link-${index}`
1080
1101
  );
@@ -741,6 +741,13 @@ function getNavbarLayoutClasses(layoutVariant = "fullScreenContainerizedLinks",
741
741
  };
742
742
  }
743
743
  var MOBILE_BREAKPOINT = 1024;
744
+ var DESKTOP_GROUP_COLUMN_WIDTH = 248;
745
+ var DESKTOP_GROUP_GAP = 8;
746
+ var DESKTOP_GROUP_PADDING_X = 16;
747
+ var getDesktopGroupsGridStyle = (groupCount) => ({
748
+ width: groupCount * DESKTOP_GROUP_COLUMN_WIDTH + Math.max(groupCount - 1, 0) * DESKTOP_GROUP_GAP + DESKTOP_GROUP_PADDING_X,
749
+ gridTemplateColumns: `repeat(${groupCount}, minmax(0, 1fr))`
750
+ });
744
751
  var NavbarMultiColumnGroups = ({
745
752
  className,
746
753
  containerClassName,
@@ -919,33 +926,47 @@ var NavbarMultiColumnGroups = ({
919
926
  ] });
920
927
  };
921
928
  var DesktopMenuItem = ({ item, index }) => {
922
- if (item.groups) {
929
+ if (item.groups && item.groups.length > 0) {
923
930
  return /* @__PURE__ */ jsxs(NavigationMenuItem, { value: `${index}`, children: [
924
931
  /* @__PURE__ */ jsx(NavigationMenuTrigger, { className: "h-fit bg-transparent px-2.5 font-normal text-muted-foreground", children: item.title }),
925
- /* @__PURE__ */ jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsx("ul", { className: "flex p-2", style: { width: item.groups.length * 248 }, children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsx("li", { className: "flex-1", children: /* @__PURE__ */ jsxs("ul", { children: [
926
- /* @__PURE__ */ jsx("li", { className: "px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
927
- group.links.map((link, linkIndex) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
928
- NavigationMenuLink,
929
- {
930
- asChild: true,
931
- className: "group/link flex-row gap-2 px-3 py-2 transition-colors duration-200",
932
- children: /* @__PURE__ */ jsxs(Pressable, { href: link.url, children: [
933
- /* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsx(
934
- DynamicIcon,
935
- {
936
- name: link.icon || link.iconName,
937
- size: 16,
938
- className: "m-auto group-hover/link:stroke-black"
939
- }
940
- ) }),
941
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
942
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: link.label }),
943
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground group-hover/link:text-foreground", children: link.description })
944
- ] })
945
- ] })
946
- }
947
- ) }, `desktop-links-${groupIndex}-${linkIndex}`))
948
- ] }) }, `desktop-group-${groupIndex}`)) }) })
932
+ /* @__PURE__ */ jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsx(
933
+ "ul",
934
+ {
935
+ className: "grid box-border max-w-[calc(100vw-2rem)] gap-2 overflow-x-auto p-2",
936
+ style: getDesktopGroupsGridStyle(item.groups.length),
937
+ children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsx("li", { className: "min-w-0", children: /* @__PURE__ */ jsxs("ul", { className: "min-w-0", children: [
938
+ /* @__PURE__ */ jsx("li", { className: "line-clamp-2 break-words px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
939
+ group.links.map((link, linkIndex) => /* @__PURE__ */ jsx(
940
+ "li",
941
+ {
942
+ className: "min-w-0",
943
+ children: /* @__PURE__ */ jsx(
944
+ NavigationMenuLink,
945
+ {
946
+ asChild: true,
947
+ className: "group/link !flex !w-full max-w-full min-w-0 flex-row items-start gap-2 overflow-hidden px-3 py-2 text-left whitespace-normal transition-colors duration-200",
948
+ children: /* @__PURE__ */ jsxs(Pressable, { href: link.url, children: [
949
+ /* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsx(
950
+ DynamicIcon,
951
+ {
952
+ name: link.icon || link.iconName,
953
+ size: 16,
954
+ className: "m-auto group-hover/link:stroke-black"
955
+ }
956
+ ) }),
957
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
958
+ /* @__PURE__ */ jsx("div", { className: "line-clamp-2 break-words text-sm leading-snug font-medium", children: link.label }),
959
+ /* @__PURE__ */ jsx("div", { className: "line-clamp-2 break-words text-xs leading-snug text-muted-foreground group-hover/link:text-foreground", children: link.description })
960
+ ] })
961
+ ] })
962
+ }
963
+ )
964
+ },
965
+ `desktop-links-${groupIndex}-${linkIndex}`
966
+ ))
967
+ ] }) }, `desktop-group-${groupIndex}`))
968
+ }
969
+ ) })
949
970
  ] }, `desktop-menu-item-${index}`);
950
971
  }
951
972
  return /* @__PURE__ */ jsx(NavigationMenuItem, { value: `${index}`, children: /* @__PURE__ */ jsx(
@@ -1009,13 +1030,13 @@ var MobileNavigationMenu = ({
1009
1030
  value: `nav-${index}`,
1010
1031
  className: "border-b-0",
1011
1032
  children: [
1012
- /* @__PURE__ */ jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: item.title }),
1033
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words text-left", children: item.title }) }),
1013
1034
  /* @__PURE__ */ jsx(AccordionContent, { className: "overflow-x-none", children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxs(
1014
1035
  "div",
1015
1036
  {
1016
1037
  className: "mb-4",
1017
1038
  children: [
1018
- group.title && /* @__PURE__ */ jsx("p", { className: "mt-4 px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
1039
+ group.title && /* @__PURE__ */ jsx("p", { className: "mt-4 line-clamp-2 break-words px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
1019
1040
  group.links.map((link, linkIndex) => /* @__PURE__ */ jsxs(
1020
1041
  Pressable,
1021
1042
  {
@@ -1028,10 +1049,10 @@ var MobileNavigationMenu = ({
1028
1049
  {
1029
1050
  name: link.icon || link.iconName,
1030
1051
  size: 16,
1031
- className: "stroke-muted-foreground"
1052
+ className: "shrink-0 stroke-muted-foreground"
1032
1053
  }
1033
1054
  ),
1034
- link.label
1055
+ /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: link.label })
1035
1056
  ]
1036
1057
  },
1037
1058
  `mobile-link-${groupIndex}-${linkIndex}`
@@ -1051,7 +1072,7 @@ var MobileNavigationMenu = ({
1051
1072
  href: item.url,
1052
1073
  className: "flex h-15 items-center rounded-md p-0 px-4 text-left text-base leading-[3.75] font-normal text-muted-foreground ring-ring/10 outline-ring/50 transition-all hover:bg-muted focus-visible:ring-4 focus-visible:outline-1",
1053
1074
  onClick: handleClose,
1054
- children: item.title
1075
+ children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: item.title })
1055
1076
  },
1056
1077
  `nav-link-${index}`
1057
1078
  );
package/dist/registry.cjs CHANGED
@@ -67914,6 +67914,13 @@ var renderMobileMenuItem4 = (item, index) => {
67914
67914
  );
67915
67915
  };
67916
67916
  var MOBILE_BREAKPOINT5 = 1024;
67917
+ var DESKTOP_GROUP_COLUMN_WIDTH = 248;
67918
+ var DESKTOP_GROUP_GAP = 8;
67919
+ var DESKTOP_GROUP_PADDING_X = 16;
67920
+ var getDesktopGroupsGridStyle = (groupCount) => ({
67921
+ width: groupCount * DESKTOP_GROUP_COLUMN_WIDTH + Math.max(groupCount - 1, 0) * DESKTOP_GROUP_GAP + DESKTOP_GROUP_PADDING_X,
67922
+ gridTemplateColumns: `repeat(${groupCount}, minmax(0, 1fr))`
67923
+ });
67917
67924
  var NavbarMultiColumnGroups = ({
67918
67925
  className,
67919
67926
  containerClassName,
@@ -68092,33 +68099,47 @@ var NavbarMultiColumnGroups = ({
68092
68099
  ] });
68093
68100
  };
68094
68101
  var DesktopMenuItem6 = ({ item, index }) => {
68095
- if (item.groups) {
68102
+ if (item.groups && item.groups.length > 0) {
68096
68103
  return /* @__PURE__ */ jsxRuntime.jsxs(NavigationMenuItem, { value: `${index}`, children: [
68097
68104
  /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuTrigger, { className: "h-fit bg-transparent px-2.5 font-normal text-muted-foreground", children: item.title }),
68098
- /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex p-2", style: { width: item.groups.length * 248 }, children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { children: [
68099
- /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
68100
- group.links.map((link, linkIndex) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
68101
- NavigationMenuLink,
68102
- {
68103
- asChild: true,
68104
- className: "group/link flex-row gap-2 px-3 py-2 transition-colors duration-200",
68105
- children: /* @__PURE__ */ jsxRuntime.jsxs(pressable.Pressable, { href: link.url, children: [
68106
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(
68107
- DynamicIcon,
68108
- {
68109
- name: link.icon || link.iconName,
68110
- size: 16,
68111
- className: "m-auto group-hover/link:stroke-black"
68112
- }
68113
- ) }),
68114
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
68115
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium", children: link.label }),
68116
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground group-hover/link:text-foreground", children: link.description })
68117
- ] })
68118
- ] })
68119
- }
68120
- ) }, `desktop-links-${groupIndex}-${linkIndex}`))
68121
- ] }) }, `desktop-group-${groupIndex}`)) }) })
68105
+ /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsxRuntime.jsx(
68106
+ "ul",
68107
+ {
68108
+ className: "grid box-border max-w-[calc(100vw-2rem)] gap-2 overflow-x-auto p-2",
68109
+ style: getDesktopGroupsGridStyle(item.groups.length),
68110
+ children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "min-w-0", children: [
68111
+ /* @__PURE__ */ jsxRuntime.jsx("li", { className: "line-clamp-2 break-words px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
68112
+ group.links.map((link, linkIndex) => /* @__PURE__ */ jsxRuntime.jsx(
68113
+ "li",
68114
+ {
68115
+ className: "min-w-0",
68116
+ children: /* @__PURE__ */ jsxRuntime.jsx(
68117
+ NavigationMenuLink,
68118
+ {
68119
+ asChild: true,
68120
+ className: "group/link !flex !w-full max-w-full min-w-0 flex-row items-start gap-2 overflow-hidden px-3 py-2 text-left whitespace-normal transition-colors duration-200",
68121
+ children: /* @__PURE__ */ jsxRuntime.jsxs(pressable.Pressable, { href: link.url, children: [
68122
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(
68123
+ DynamicIcon,
68124
+ {
68125
+ name: link.icon || link.iconName,
68126
+ size: 16,
68127
+ className: "m-auto group-hover/link:stroke-black"
68128
+ }
68129
+ ) }),
68130
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
68131
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 break-words text-sm leading-snug font-medium", children: link.label }),
68132
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 break-words text-xs leading-snug text-muted-foreground group-hover/link:text-foreground", children: link.description })
68133
+ ] })
68134
+ ] })
68135
+ }
68136
+ )
68137
+ },
68138
+ `desktop-links-${groupIndex}-${linkIndex}`
68139
+ ))
68140
+ ] }) }, `desktop-group-${groupIndex}`))
68141
+ }
68142
+ ) })
68122
68143
  ] }, `desktop-menu-item-${index}`);
68123
68144
  }
68124
68145
  return /* @__PURE__ */ jsxRuntime.jsx(NavigationMenuItem, { value: `${index}`, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -68182,13 +68203,13 @@ var MobileNavigationMenu5 = ({
68182
68203
  value: `nav-${index}`,
68183
68204
  className: "border-b-0",
68184
68205
  children: [
68185
- /* @__PURE__ */ jsxRuntime.jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: item.title }),
68206
+ /* @__PURE__ */ jsxRuntime.jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words text-left", children: item.title }) }),
68186
68207
  /* @__PURE__ */ jsxRuntime.jsx(AccordionContent, { className: "overflow-x-none", children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
68187
68208
  "div",
68188
68209
  {
68189
68210
  className: "mb-4",
68190
68211
  children: [
68191
- group.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
68212
+ group.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 line-clamp-2 break-words px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
68192
68213
  group.links.map((link, linkIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
68193
68214
  pressable.Pressable,
68194
68215
  {
@@ -68201,10 +68222,10 @@ var MobileNavigationMenu5 = ({
68201
68222
  {
68202
68223
  name: link.icon || link.iconName,
68203
68224
  size: 16,
68204
- className: "stroke-muted-foreground"
68225
+ className: "shrink-0 stroke-muted-foreground"
68205
68226
  }
68206
68227
  ),
68207
- link.label
68228
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: link.label })
68208
68229
  ]
68209
68230
  },
68210
68231
  `mobile-link-${groupIndex}-${linkIndex}`
@@ -68224,7 +68245,7 @@ var MobileNavigationMenu5 = ({
68224
68245
  href: item.url,
68225
68246
  className: "flex h-15 items-center rounded-md p-0 px-4 text-left text-base leading-[3.75] font-normal text-muted-foreground ring-ring/10 outline-ring/50 transition-all hover:bg-muted focus-visible:ring-4 focus-visible:outline-1",
68226
68247
  onClick: handleClose,
68227
- children: item.title
68248
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: item.title })
68228
68249
  },
68229
68250
  `nav-link-${index}`
68230
68251
  );
@@ -135193,7 +135214,51 @@ function createBuilderContractBundle({
135193
135214
  hydrationPhase: "routing-build",
135194
135215
  canonicalPayloadExpectation: "Keep blog feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135195
135216
  requiredFields: ["type"],
135196
- optionalFields: ["limit", "offset", "category", "tag", "featuredOnly"]
135217
+ optionalFields: [
135218
+ "limit",
135219
+ "offset",
135220
+ "category",
135221
+ "tag",
135222
+ "featuredOnly",
135223
+ "bindTo"
135224
+ ]
135225
+ },
135226
+ blog_post: {
135227
+ sourceType: "blog_post",
135228
+ symbolic: true,
135229
+ hydrationOwner: "dashtrack-ai",
135230
+ hydrationPhase: "routing-build",
135231
+ canonicalPayloadExpectation: "Keep blog post requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135232
+ requiredFields: ["type"],
135233
+ optionalFields: ["slug", "current", "bindTo"]
135234
+ },
135235
+ testimonials_feed: {
135236
+ sourceType: "testimonials_feed",
135237
+ symbolic: true,
135238
+ hydrationOwner: "dashtrack-ai",
135239
+ hydrationPhase: "routing-build",
135240
+ canonicalPayloadExpectation: "Keep testimonials feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135241
+ requiredFields: ["type"],
135242
+ optionalFields: ["limit", "minRating", "platforms", "locationId", "bindTo"]
135243
+ },
135244
+ instagram_feed: {
135245
+ sourceType: "instagram_feed",
135246
+ symbolic: true,
135247
+ hydrationOwner: "dashtrack-ai",
135248
+ hydrationPhase: "routing-build",
135249
+ canonicalPayloadExpectation: "Keep Instagram feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135250
+ requiredFields: ["type"],
135251
+ optionalFields: ["limit", "profile", "hashtag", "bindTo"]
135252
+ },
135253
+ events_feed: {
135254
+ sourceType: "events_feed",
135255
+ symbolic: true,
135256
+ hydrationOwner: "dashtrack-ai",
135257
+ hydrationPhase: "routing-build",
135258
+ canonicalPayloadExpectation: "Keep events feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135259
+ requiredFields: ["type"],
135260
+ optionalFields: ["limit", "upcomingOnly", "locationIds", "bindTo"],
135261
+ expands: true
135197
135262
  }
135198
135263
  },
135199
135264
  designTokens: {
@@ -234,9 +234,19 @@ interface BuilderContractDynamicSourceDefinition {
234
234
  canonicalPayloadExpectation: string;
235
235
  requiredFields: string[];
236
236
  optionalFields: string[];
237
+ /**
238
+ * When true, hydration may fan a single symbolic block out into N concrete
239
+ * block instances (one-to-many expansion, contract D6). Absent for the
240
+ * one-to-one sources.
241
+ */
242
+ expands?: boolean;
237
243
  }
238
244
  interface BuilderContractDynamicSources {
239
245
  blog_feed: BuilderContractDynamicSourceDefinition;
246
+ blog_post: BuilderContractDynamicSourceDefinition;
247
+ testimonials_feed: BuilderContractDynamicSourceDefinition;
248
+ instagram_feed: BuilderContractDynamicSourceDefinition;
249
+ events_feed: BuilderContractDynamicSourceDefinition;
240
250
  }
241
251
  interface BuilderContractDesignTokens {
242
252
  canonicalSource: "theme_config";
@@ -234,9 +234,19 @@ interface BuilderContractDynamicSourceDefinition {
234
234
  canonicalPayloadExpectation: string;
235
235
  requiredFields: string[];
236
236
  optionalFields: string[];
237
+ /**
238
+ * When true, hydration may fan a single symbolic block out into N concrete
239
+ * block instances (one-to-many expansion, contract D6). Absent for the
240
+ * one-to-one sources.
241
+ */
242
+ expands?: boolean;
237
243
  }
238
244
  interface BuilderContractDynamicSources {
239
245
  blog_feed: BuilderContractDynamicSourceDefinition;
246
+ blog_post: BuilderContractDynamicSourceDefinition;
247
+ testimonials_feed: BuilderContractDynamicSourceDefinition;
248
+ instagram_feed: BuilderContractDynamicSourceDefinition;
249
+ events_feed: BuilderContractDynamicSourceDefinition;
240
250
  }
241
251
  interface BuilderContractDesignTokens {
242
252
  canonicalSource: "theme_config";
package/dist/registry.js CHANGED
@@ -67874,6 +67874,13 @@ var renderMobileMenuItem4 = (item, index) => {
67874
67874
  );
67875
67875
  };
67876
67876
  var MOBILE_BREAKPOINT5 = 1024;
67877
+ var DESKTOP_GROUP_COLUMN_WIDTH = 248;
67878
+ var DESKTOP_GROUP_GAP = 8;
67879
+ var DESKTOP_GROUP_PADDING_X = 16;
67880
+ var getDesktopGroupsGridStyle = (groupCount) => ({
67881
+ width: groupCount * DESKTOP_GROUP_COLUMN_WIDTH + Math.max(groupCount - 1, 0) * DESKTOP_GROUP_GAP + DESKTOP_GROUP_PADDING_X,
67882
+ gridTemplateColumns: `repeat(${groupCount}, minmax(0, 1fr))`
67883
+ });
67877
67884
  var NavbarMultiColumnGroups = ({
67878
67885
  className,
67879
67886
  containerClassName,
@@ -68052,33 +68059,47 @@ var NavbarMultiColumnGroups = ({
68052
68059
  ] });
68053
68060
  };
68054
68061
  var DesktopMenuItem6 = ({ item, index }) => {
68055
- if (item.groups) {
68062
+ if (item.groups && item.groups.length > 0) {
68056
68063
  return /* @__PURE__ */ jsxs(NavigationMenuItem, { value: `${index}`, children: [
68057
68064
  /* @__PURE__ */ jsx(NavigationMenuTrigger, { className: "h-fit bg-transparent px-2.5 font-normal text-muted-foreground", children: item.title }),
68058
- /* @__PURE__ */ jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsx("ul", { className: "flex p-2", style: { width: item.groups.length * 248 }, children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsx("li", { className: "flex-1", children: /* @__PURE__ */ jsxs("ul", { children: [
68059
- /* @__PURE__ */ jsx("li", { className: "px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
68060
- group.links.map((link, linkIndex) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
68061
- NavigationMenuLink,
68062
- {
68063
- asChild: true,
68064
- className: "group/link flex-row gap-2 px-3 py-2 transition-colors duration-200",
68065
- children: /* @__PURE__ */ jsxs(Pressable, { href: link.url, children: [
68066
- /* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsx(
68067
- DynamicIcon,
68068
- {
68069
- name: link.icon || link.iconName,
68070
- size: 16,
68071
- className: "m-auto group-hover/link:stroke-black"
68072
- }
68073
- ) }),
68074
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
68075
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: link.label }),
68076
- /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground group-hover/link:text-foreground", children: link.description })
68077
- ] })
68078
- ] })
68079
- }
68080
- ) }, `desktop-links-${groupIndex}-${linkIndex}`))
68081
- ] }) }, `desktop-group-${groupIndex}`)) }) })
68065
+ /* @__PURE__ */ jsx(NavigationMenuContent, { className: "rounded-xl! border! p-0!", children: /* @__PURE__ */ jsx(
68066
+ "ul",
68067
+ {
68068
+ className: "grid box-border max-w-[calc(100vw-2rem)] gap-2 overflow-x-auto p-2",
68069
+ style: getDesktopGroupsGridStyle(item.groups.length),
68070
+ children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsx("li", { className: "min-w-0", children: /* @__PURE__ */ jsxs("ul", { className: "min-w-0", children: [
68071
+ /* @__PURE__ */ jsx("li", { className: "line-clamp-2 break-words px-3 py-2 text-sm leading-normal text-muted-foreground", children: group.title }),
68072
+ group.links.map((link, linkIndex) => /* @__PURE__ */ jsx(
68073
+ "li",
68074
+ {
68075
+ className: "min-w-0",
68076
+ children: /* @__PURE__ */ jsx(
68077
+ NavigationMenuLink,
68078
+ {
68079
+ asChild: true,
68080
+ className: "group/link !flex !w-full max-w-full min-w-0 flex-row items-start gap-2 overflow-hidden px-3 py-2 text-left whitespace-normal transition-colors duration-200",
68081
+ children: /* @__PURE__ */ jsxs(Pressable, { href: link.url, children: [
68082
+ /* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 rounded-lg border duration-400 fade-in group-hover/link:bg-background", children: /* @__PURE__ */ jsx(
68083
+ DynamicIcon,
68084
+ {
68085
+ name: link.icon || link.iconName,
68086
+ size: 16,
68087
+ className: "m-auto group-hover/link:stroke-black"
68088
+ }
68089
+ ) }),
68090
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
68091
+ /* @__PURE__ */ jsx("div", { className: "line-clamp-2 break-words text-sm leading-snug font-medium", children: link.label }),
68092
+ /* @__PURE__ */ jsx("div", { className: "line-clamp-2 break-words text-xs leading-snug text-muted-foreground group-hover/link:text-foreground", children: link.description })
68093
+ ] })
68094
+ ] })
68095
+ }
68096
+ )
68097
+ },
68098
+ `desktop-links-${groupIndex}-${linkIndex}`
68099
+ ))
68100
+ ] }) }, `desktop-group-${groupIndex}`))
68101
+ }
68102
+ ) })
68082
68103
  ] }, `desktop-menu-item-${index}`);
68083
68104
  }
68084
68105
  return /* @__PURE__ */ jsx(NavigationMenuItem, { value: `${index}`, children: /* @__PURE__ */ jsx(
@@ -68142,13 +68163,13 @@ var MobileNavigationMenu5 = ({
68142
68163
  value: `nav-${index}`,
68143
68164
  className: "border-b-0",
68144
68165
  children: [
68145
- /* @__PURE__ */ jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: item.title }),
68166
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "h-15 items-center p-0 px-4! text-base leading-[3.75] font-normal text-muted-foreground hover:bg-muted hover:no-underline", children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words text-left", children: item.title }) }),
68146
68167
  /* @__PURE__ */ jsx(AccordionContent, { className: "overflow-x-none", children: item.groups.map((group, groupIndex) => /* @__PURE__ */ jsxs(
68147
68168
  "div",
68148
68169
  {
68149
68170
  className: "mb-4",
68150
68171
  children: [
68151
- group.title && /* @__PURE__ */ jsx("p", { className: "mt-4 px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
68172
+ group.title && /* @__PURE__ */ jsx("p", { className: "mt-4 line-clamp-2 break-words px-4 text-xs font-semibold text-muted-foreground uppercase", children: group.title }),
68152
68173
  group.links.map((link, linkIndex) => /* @__PURE__ */ jsxs(
68153
68174
  Pressable,
68154
68175
  {
@@ -68161,10 +68182,10 @@ var MobileNavigationMenu5 = ({
68161
68182
  {
68162
68183
  name: link.icon || link.iconName,
68163
68184
  size: 16,
68164
- className: "stroke-muted-foreground"
68185
+ className: "shrink-0 stroke-muted-foreground"
68165
68186
  }
68166
68187
  ),
68167
- link.label
68188
+ /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: link.label })
68168
68189
  ]
68169
68190
  },
68170
68191
  `mobile-link-${groupIndex}-${linkIndex}`
@@ -68184,7 +68205,7 @@ var MobileNavigationMenu5 = ({
68184
68205
  href: item.url,
68185
68206
  className: "flex h-15 items-center rounded-md p-0 px-4 text-left text-base leading-[3.75] font-normal text-muted-foreground ring-ring/10 outline-ring/50 transition-all hover:bg-muted focus-visible:ring-4 focus-visible:outline-1",
68186
68207
  onClick: handleClose,
68187
- children: item.title
68208
+ children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 break-words", children: item.title })
68188
68209
  },
68189
68210
  `nav-link-${index}`
68190
68211
  );
@@ -135153,7 +135174,51 @@ function createBuilderContractBundle({
135153
135174
  hydrationPhase: "routing-build",
135154
135175
  canonicalPayloadExpectation: "Keep blog feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135155
135176
  requiredFields: ["type"],
135156
- optionalFields: ["limit", "offset", "category", "tag", "featuredOnly"]
135177
+ optionalFields: [
135178
+ "limit",
135179
+ "offset",
135180
+ "category",
135181
+ "tag",
135182
+ "featuredOnly",
135183
+ "bindTo"
135184
+ ]
135185
+ },
135186
+ blog_post: {
135187
+ sourceType: "blog_post",
135188
+ symbolic: true,
135189
+ hydrationOwner: "dashtrack-ai",
135190
+ hydrationPhase: "routing-build",
135191
+ canonicalPayloadExpectation: "Keep blog post requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135192
+ requiredFields: ["type"],
135193
+ optionalFields: ["slug", "current", "bindTo"]
135194
+ },
135195
+ testimonials_feed: {
135196
+ sourceType: "testimonials_feed",
135197
+ symbolic: true,
135198
+ hydrationOwner: "dashtrack-ai",
135199
+ hydrationPhase: "routing-build",
135200
+ canonicalPayloadExpectation: "Keep testimonials feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135201
+ requiredFields: ["type"],
135202
+ optionalFields: ["limit", "minRating", "platforms", "locationId", "bindTo"]
135203
+ },
135204
+ instagram_feed: {
135205
+ sourceType: "instagram_feed",
135206
+ symbolic: true,
135207
+ hydrationOwner: "dashtrack-ai",
135208
+ hydrationPhase: "routing-build",
135209
+ canonicalPayloadExpectation: "Keep Instagram feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135210
+ requiredFields: ["type"],
135211
+ optionalFields: ["limit", "profile", "hashtag", "bindTo"]
135212
+ },
135213
+ events_feed: {
135214
+ sourceType: "events_feed",
135215
+ symbolic: true,
135216
+ hydrationOwner: "dashtrack-ai",
135217
+ hydrationPhase: "routing-build",
135218
+ canonicalPayloadExpectation: "Keep events feed requests symbolic in canonical page JSON until routing-build hydration resolves them.",
135219
+ requiredFields: ["type"],
135220
+ optionalFields: ["limit", "upcomingOnly", "locationIds", "bindTo"],
135221
+ expands: true
135157
135222
  }
135158
135223
  },
135159
135224
  designTokens: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensite/ui",
3
- "version": "3.8.1",
3
+ "version": "3.9.0",
4
4
  "description": "Foundational UI component library for OpenSite Semantic Site Builder with tree-shakable exports and abstract styling",
5
5
  "keywords": [
6
6
  "react",