@timmbr/ui 1.1.0 → 1.3.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 (125) hide show
  1. package/dist/components/Accordion/Accordion.d.ts.map +1 -1
  2. package/dist/components/Alert/Alert.types.d.ts +2 -4
  3. package/dist/components/Alert/Alert.types.d.ts.map +1 -1
  4. package/dist/components/AlertDialog/AlertDialog.d.ts +16 -0
  5. package/dist/components/AlertDialog/AlertDialog.d.ts.map +1 -0
  6. package/dist/components/AlertDialog/AlertDialog.js +94 -0
  7. package/dist/components/AlertDialog/AlertDialog.styles.d.ts +8 -0
  8. package/dist/components/AlertDialog/AlertDialog.styles.d.ts.map +1 -0
  9. package/dist/components/AlertDialog/AlertDialog.styles.js +25 -0
  10. package/dist/components/AlertDialog/AlertDialog.types.d.ts +16 -0
  11. package/dist/components/AlertDialog/AlertDialog.types.d.ts.map +1 -0
  12. package/dist/components/AlertDialog/index.d.ts +4 -0
  13. package/dist/components/AlertDialog/index.d.ts.map +1 -0
  14. package/dist/components/Avatar/Avatar.styles.d.ts +1 -1
  15. package/dist/components/Dialog/Dialog.d.ts +2 -1
  16. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  17. package/dist/components/Dialog/Dialog.js +8 -6
  18. package/dist/components/Dialog/Dialog.styles.d.ts +1 -0
  19. package/dist/components/Dialog/Dialog.styles.d.ts.map +1 -1
  20. package/dist/components/Dialog/Dialog.styles.js +7 -4
  21. package/dist/components/Dialog/Dialog.types.d.ts +4 -6
  22. package/dist/components/Dialog/Dialog.types.d.ts.map +1 -1
  23. package/dist/components/Drawer/Drawer.types.d.ts +3 -6
  24. package/dist/components/Drawer/Drawer.types.d.ts.map +1 -1
  25. package/dist/components/Dropdown/Dropdown.types.d.ts +1 -2
  26. package/dist/components/Dropdown/Dropdown.types.d.ts.map +1 -1
  27. package/dist/components/FormField/FormField.js +3 -3
  28. package/dist/components/ImageUpload/ImageUpload.d.ts +4 -0
  29. package/dist/components/ImageUpload/ImageUpload.d.ts.map +1 -0
  30. package/dist/components/ImageUpload/ImageUpload.helpers.d.ts +30 -0
  31. package/dist/components/ImageUpload/ImageUpload.helpers.d.ts.map +1 -0
  32. package/dist/components/ImageUpload/ImageUpload.helpers.js +95 -0
  33. package/dist/components/ImageUpload/ImageUpload.js +365 -0
  34. package/dist/components/ImageUpload/ImageUpload.styles.d.ts +17 -0
  35. package/dist/components/ImageUpload/ImageUpload.styles.d.ts.map +1 -0
  36. package/dist/components/ImageUpload/ImageUpload.styles.js +72 -0
  37. package/dist/components/ImageUpload/ImageUpload.types.d.ts +112 -0
  38. package/dist/components/ImageUpload/ImageUpload.types.d.ts.map +1 -0
  39. package/dist/components/ImageUpload/index.d.ts +6 -0
  40. package/dist/components/ImageUpload/index.d.ts.map +1 -0
  41. package/dist/components/ImageUpload/subcomponents/ImageUploadDropzone.d.ts +25 -0
  42. package/dist/components/ImageUpload/subcomponents/ImageUploadDropzone.d.ts.map +1 -0
  43. package/dist/components/ImageUpload/subcomponents/ImageUploadDropzone.js +106 -0
  44. package/dist/components/ImageUpload/subcomponents/ImageUploadIcons.d.ts +6 -0
  45. package/dist/components/ImageUpload/subcomponents/ImageUploadIcons.d.ts.map +1 -0
  46. package/dist/components/ImageUpload/subcomponents/ImageUploadIcons.js +61 -0
  47. package/dist/components/ImageUpload/subcomponents/ImageUploadModal.d.ts +12 -0
  48. package/dist/components/ImageUpload/subcomponents/ImageUploadModal.d.ts.map +1 -0
  49. package/dist/components/ImageUpload/subcomponents/ImageUploadModal.js +137 -0
  50. package/dist/components/ImageUpload/subcomponents/ImageUploadSinglePreview.d.ts +14 -0
  51. package/dist/components/ImageUpload/subcomponents/ImageUploadSinglePreview.d.ts.map +1 -0
  52. package/dist/components/ImageUpload/subcomponents/ImageUploadSinglePreview.js +142 -0
  53. package/dist/components/ImageUpload/subcomponents/ImageUploadThumbnailCard.d.ts +23 -0
  54. package/dist/components/ImageUpload/subcomponents/ImageUploadThumbnailCard.d.ts.map +1 -0
  55. package/dist/components/ImageUpload/subcomponents/ImageUploadThumbnailCard.js +139 -0
  56. package/dist/components/ImageUpload/subcomponents/index.d.ts +6 -0
  57. package/dist/components/ImageUpload/subcomponents/index.d.ts.map +1 -0
  58. package/dist/components/Input/Input.js +3 -3
  59. package/dist/components/List/List.types.d.ts +2 -4
  60. package/dist/components/List/List.types.d.ts.map +1 -1
  61. package/dist/components/NavHeader/NavHeader.context.d.ts +20 -0
  62. package/dist/components/NavHeader/NavHeader.context.d.ts.map +1 -0
  63. package/dist/components/NavHeader/NavHeader.context.js +13 -0
  64. package/dist/components/NavHeader/NavHeader.d.ts +8 -0
  65. package/dist/components/NavHeader/NavHeader.d.ts.map +1 -0
  66. package/dist/components/NavHeader/NavHeader.helpers.d.ts +13 -0
  67. package/dist/components/NavHeader/NavHeader.helpers.d.ts.map +1 -0
  68. package/dist/components/NavHeader/NavHeader.helpers.js +14 -0
  69. package/dist/components/NavHeader/NavHeader.js +532 -0
  70. package/dist/components/NavHeader/NavHeader.styles.d.ts +67 -0
  71. package/dist/components/NavHeader/NavHeader.styles.d.ts.map +1 -0
  72. package/dist/components/NavHeader/NavHeader.styles.js +123 -0
  73. package/dist/components/NavHeader/NavHeader.types.d.ts +321 -0
  74. package/dist/components/NavHeader/NavHeader.types.d.ts.map +1 -0
  75. package/dist/components/NavHeader/index.d.ts +11 -0
  76. package/dist/components/NavHeader/index.d.ts.map +1 -0
  77. package/dist/components/NavHeader/subcomponents/NavActionOverflow.d.ts +13 -0
  78. package/dist/components/NavHeader/subcomponents/NavActionOverflow.d.ts.map +1 -0
  79. package/dist/components/NavHeader/subcomponents/NavActionOverflow.js +169 -0
  80. package/dist/components/NavHeader/subcomponents/NavActions.d.ts +22 -0
  81. package/dist/components/NavHeader/subcomponents/NavActions.d.ts.map +1 -0
  82. package/dist/components/NavHeader/subcomponents/NavActions.js +228 -0
  83. package/dist/components/NavHeader/subcomponents/NavBrand.d.ts +12 -0
  84. package/dist/components/NavHeader/subcomponents/NavBrand.d.ts.map +1 -0
  85. package/dist/components/NavHeader/subcomponents/NavBrand.js +96 -0
  86. package/dist/components/NavHeader/subcomponents/NavItems.d.ts +15 -0
  87. package/dist/components/NavHeader/subcomponents/NavItems.d.ts.map +1 -0
  88. package/dist/components/NavHeader/subcomponents/NavItems.js +141 -0
  89. package/dist/components/NavHeader/subcomponents/NavItemsOverflow.d.ts +13 -0
  90. package/dist/components/NavHeader/subcomponents/NavItemsOverflow.d.ts.map +1 -0
  91. package/dist/components/NavHeader/subcomponents/NavItemsOverflow.js +165 -0
  92. package/dist/components/NavHeader/subcomponents/NavMegaMenu.d.ts +12 -0
  93. package/dist/components/NavHeader/subcomponents/NavMegaMenu.d.ts.map +1 -0
  94. package/dist/components/NavHeader/subcomponents/NavMegaMenu.js +73 -0
  95. package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.d.ts +16 -0
  96. package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.d.ts.map +1 -0
  97. package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.js +149 -0
  98. package/dist/components/NavHeader/subcomponents/NavMobileTabContent.d.ts +11 -0
  99. package/dist/components/NavHeader/subcomponents/NavMobileTabContent.d.ts.map +1 -0
  100. package/dist/components/NavHeader/subcomponents/NavMobileTabContent.js +40 -0
  101. package/dist/components/NavHeader/subcomponents/NavMobileTabSlider.d.ts +13 -0
  102. package/dist/components/NavHeader/subcomponents/NavMobileTabSlider.d.ts.map +1 -0
  103. package/dist/components/NavHeader/subcomponents/NavMobileTabSlider.js +111 -0
  104. package/dist/components/NavHeader/subcomponents/NavSearch.d.ts +15 -0
  105. package/dist/components/NavHeader/subcomponents/NavSearch.d.ts.map +1 -0
  106. package/dist/components/NavHeader/subcomponents/NavSearch.js +222 -0
  107. package/dist/components/NavHeader/subcomponents/OfferBanner.d.ts +11 -0
  108. package/dist/components/NavHeader/subcomponents/OfferBanner.d.ts.map +1 -0
  109. package/dist/components/NavHeader/subcomponents/OfferBanner.js +92 -0
  110. package/dist/components/Popover/Popover.types.d.ts +1 -2
  111. package/dist/components/Popover/Popover.types.d.ts.map +1 -1
  112. package/dist/components/Radio/Radio.js +3 -3
  113. package/dist/components/Select/Select.js +3 -3
  114. package/dist/components/Stat/Stat.types.d.ts +3 -6
  115. package/dist/components/Stat/Stat.types.d.ts.map +1 -1
  116. package/dist/components/Table/Table.types.d.ts +7 -14
  117. package/dist/components/Table/Table.types.d.ts.map +1 -1
  118. package/dist/components/Textarea/Textarea.js +3 -3
  119. package/dist/components/Toast/Toast.js +1 -1
  120. package/dist/components/Toast/Toast.types.d.ts +1 -2
  121. package/dist/components/Toast/Toast.types.d.ts.map +1 -1
  122. package/dist/index.d.ts +3 -0
  123. package/dist/index.d.ts.map +1 -1
  124. package/dist/index.js +21 -2
  125. package/package.json +5 -4
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+ import type { NavActionItem } from '../NavHeader.types';
3
+ export interface NavActionsProps {
4
+ actions?: NavActionItem[];
5
+ profileAction?: Partial<NavActionItem>;
6
+ wishlistAction?: Partial<NavActionItem> & {
7
+ count?: number;
8
+ };
9
+ cartAction?: Partial<NavActionItem> & {
10
+ count?: number;
11
+ };
12
+ maxVisibleActions?: number | 'auto';
13
+ overflowActionLabel?: React.ReactNode;
14
+ overflowActionIcon?: React.ReactNode;
15
+ rightContent?: React.ReactNode;
16
+ shouldAnimate?: boolean;
17
+ motionClass?: string;
18
+ linkComponent?: React.ComponentType<any>;
19
+ }
20
+ export declare const NavActions: React.FC<NavActionsProps>;
21
+ export default NavActions;
22
+ //# sourceMappingURL=NavActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavActions.d.ts","sourceRoot":"","sources":["../../../../src/components/NavHeader/subcomponents/NavActions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACvC,cAAc,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtC,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACrC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsRhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -0,0 +1,228 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { User, Heart, ShoppingCart } from '@timmbr/icons';
5
+ import { cn } from '@timmbr/utils';
6
+ import { navActionVariants } from '../NavHeader.styles.js';
7
+ import { resolveNavDestination, isCrossZoneNavigation } from '../NavHeader.helpers.js';
8
+ import { NavActionOverflow } from './NavActionOverflow.js';
9
+ import { useTimmbrConfig } from '../../../providers/TimmbrConfigProvider.js';
10
+
11
+ const NavActions = ({
12
+ actions,
13
+ profileAction,
14
+ wishlistAction,
15
+ cartAction,
16
+ maxVisibleActions = "auto",
17
+ overflowActionLabel,
18
+ overflowActionIcon,
19
+ rightContent,
20
+ shouldAnimate = true,
21
+ motionClass,
22
+ linkComponent: CustomLink
23
+ }) => {
24
+ const config = useTimmbrConfig();
25
+ const containerRef = React.useRef(null);
26
+ const [measuredMaxVisible, setMeasuredMaxVisible] = React.useState(null);
27
+ const items = React.useMemo(() => {
28
+ if (actions && actions.length > 0 && !profileAction && !wishlistAction && !cartAction) {
29
+ return actions;
30
+ }
31
+ const defaultItems = [];
32
+ const customItems = actions ?? [];
33
+ defaultItems.push({
34
+ id: "profile",
35
+ label: profileAction?.label ?? "PROFILE",
36
+ icon: profileAction?.icon ?? /* @__PURE__ */ jsx(User, { size: 22, className: "stroke-[1.8]" }),
37
+ href: profileAction?.href ?? "/account",
38
+ zone: profileAction?.zone,
39
+ crossZone: profileAction?.crossZone,
40
+ onClick: profileAction?.onClick,
41
+ ariaLabel: profileAction?.ariaLabel ?? "User Account"
42
+ });
43
+ const wishCount = wishlistAction?.count;
44
+ defaultItems.push({
45
+ id: "wishlist",
46
+ label: wishlistAction?.label ?? "WISH LIST",
47
+ icon: wishlistAction?.icon ?? /* @__PURE__ */ jsx(Heart, { size: 22, className: "stroke-[1.8]" }),
48
+ href: wishlistAction?.href ?? "/wishlist",
49
+ zone: wishlistAction?.zone,
50
+ crossZone: wishlistAction?.crossZone,
51
+ badge: wishlistAction?.badge ?? (wishCount && wishCount > 0 ? wishCount : void 0),
52
+ onClick: wishlistAction?.onClick,
53
+ ariaLabel: wishlistAction?.ariaLabel ?? (wishCount ? `Wishlist with ${wishCount} items` : "Wishlist")
54
+ });
55
+ const cartCount = cartAction?.count;
56
+ defaultItems.push({
57
+ id: "cart",
58
+ label: cartAction?.label ?? "CART",
59
+ icon: cartAction?.icon ?? /* @__PURE__ */ jsx(ShoppingCart, { size: 22, className: "stroke-[1.8]" }),
60
+ href: cartAction?.href ?? "/cart",
61
+ zone: cartAction?.zone,
62
+ crossZone: cartAction?.crossZone,
63
+ badge: cartAction?.badge ?? (cartCount && cartCount > 0 ? cartCount : void 0),
64
+ onClick: cartAction?.onClick,
65
+ ariaLabel: cartAction?.ariaLabel ?? (cartCount ? `Shopping cart with ${cartCount} items` : "Shopping cart"),
66
+ priority: "high"
67
+ });
68
+ return [...customItems, ...defaultItems];
69
+ }, [actions, profileAction, wishlistAction, cartAction]);
70
+ React.useEffect(() => {
71
+ if (maxVisibleActions !== "auto") {
72
+ setMeasuredMaxVisible(null);
73
+ return;
74
+ }
75
+ const container = containerRef.current;
76
+ if (!container || typeof ResizeObserver === "undefined") return;
77
+ const calculateFit = () => {
78
+ const parent = container.parentElement;
79
+ if (!parent) return;
80
+ const parentWidth = parent.clientWidth;
81
+ if (parentWidth <= 0) return;
82
+ let siblingsWidth = 0;
83
+ Array.from(parent.children).forEach((child) => {
84
+ if (child !== container) {
85
+ siblingsWidth += child.offsetWidth || 0;
86
+ }
87
+ });
88
+ const availableWidth = Math.max(0, parentWidth - siblingsWidth);
89
+ const itemWidth = 68;
90
+ const moreWidth = 68;
91
+ if (availableWidth <= moreWidth) {
92
+ setMeasuredMaxVisible(1);
93
+ return;
94
+ }
95
+ const maxSlots = Math.floor(availableWidth / itemWidth);
96
+ setMeasuredMaxVisible(Math.max(1, maxSlots));
97
+ };
98
+ calculateFit();
99
+ const observer = new ResizeObserver(() => {
100
+ calculateFit();
101
+ });
102
+ if (container.parentElement) {
103
+ observer.observe(container.parentElement);
104
+ }
105
+ return () => {
106
+ observer.disconnect();
107
+ };
108
+ }, [maxVisibleActions, items.length]);
109
+ const { visibleActions, overflowActions } = React.useMemo(() => {
110
+ const limit = typeof maxVisibleActions === "number" ? maxVisibleActions : measuredMaxVisible ?? items.length;
111
+ if (items.length <= limit) {
112
+ return { visibleActions: items, overflowActions: [] };
113
+ }
114
+ const countToKeep = typeof maxVisibleActions === "number" ? maxVisibleActions : Math.max(1, limit - 1);
115
+ const hasPriorities = items.some((i) => i.priority);
116
+ if (!hasPriorities) {
117
+ return {
118
+ visibleActions: items.slice(0, countToKeep),
119
+ overflowActions: items.slice(countToKeep)
120
+ };
121
+ }
122
+ const priorityScore = (item) => {
123
+ if (item.priority === "high") return 3;
124
+ if (item.priority === "low") return 1;
125
+ return 2;
126
+ };
127
+ const indexed = items.map((item, index) => ({ item, index, score: priorityScore(item) }));
128
+ const sorted = [...indexed].sort((a, b) => b.score - a.score || a.index - b.index);
129
+ const visibleIndices = new Set(sorted.slice(0, countToKeep).map((x) => x.index));
130
+ const visible = [];
131
+ const overflow = [];
132
+ items.forEach((item, index) => {
133
+ if (visibleIndices.has(index)) {
134
+ visible.push(item);
135
+ } else {
136
+ overflow.push(item);
137
+ }
138
+ });
139
+ return { visibleActions: visible, overflowActions: overflow };
140
+ }, [items, maxVisibleActions, measuredMaxVisible]);
141
+ return /* @__PURE__ */ jsxs(
142
+ "div",
143
+ {
144
+ ref: containerRef,
145
+ className: "flex items-center gap-1.5 sm:gap-2.5 lg:gap-[18px]",
146
+ "data-slot": "nav-actions-container",
147
+ children: [
148
+ visibleActions.map((item) => {
149
+ if (item.render) {
150
+ return /* @__PURE__ */ jsx("div", { className: "relative inline-flex items-center", children: item.render({ item, isOverflow: false }) }, item.id);
151
+ }
152
+ const resolvedHref = resolveNavDestination(item.href, item.zone, config.zones?.zones);
153
+ const requiresCrossZone = isCrossZoneNavigation(item.zone, config.zones?.currentZone, item.crossZone);
154
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
155
+ /* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
156
+ item.icon,
157
+ typeof item.badge !== "undefined" && item.badge !== null && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-2 min-w-[16px] h-4 px-1 rounded-full bg-[#C0643A] text-white text-[10px] font-bold flex items-center justify-center", children: item.badge })
158
+ ] }),
159
+ /* @__PURE__ */ jsx("span", { className: "hidden lg:inline font-sans font-bold text-[10px] tracking-[0.0926em] uppercase whitespace-nowrap", children: item.label })
160
+ ] });
161
+ const actionClass = cn(
162
+ navActionVariants(),
163
+ item.disabled && "opacity-40 cursor-not-allowed pointer-events-none",
164
+ !shouldAnimate && "transition-none",
165
+ motionClass,
166
+ item.className
167
+ );
168
+ if (resolvedHref && !item.disabled) {
169
+ if (CustomLink && !requiresCrossZone) {
170
+ return /* @__PURE__ */ jsx(
171
+ CustomLink,
172
+ {
173
+ href: resolvedHref,
174
+ "aria-label": item.ariaLabel,
175
+ className: actionClass,
176
+ onClick: item.onClick,
177
+ "data-slot": "nav-action-link",
178
+ children: content
179
+ },
180
+ item.id
181
+ );
182
+ }
183
+ return /* @__PURE__ */ jsx(
184
+ "a",
185
+ {
186
+ href: resolvedHref,
187
+ "aria-label": item.ariaLabel,
188
+ "data-cross-zone": requiresCrossZone ? "true" : void 0,
189
+ className: actionClass,
190
+ onClick: item.onClick,
191
+ "data-slot": "nav-action-link",
192
+ children: content
193
+ },
194
+ item.id
195
+ );
196
+ }
197
+ return /* @__PURE__ */ jsx(
198
+ "button",
199
+ {
200
+ type: "button",
201
+ disabled: item.disabled,
202
+ "aria-label": item.ariaLabel,
203
+ onClick: item.onClick,
204
+ className: actionClass,
205
+ "data-slot": "nav-action-button",
206
+ children: content
207
+ },
208
+ item.id
209
+ );
210
+ }),
211
+ overflowActions.length > 0 && /* @__PURE__ */ jsx(
212
+ NavActionOverflow,
213
+ {
214
+ items: overflowActions,
215
+ label: overflowActionLabel,
216
+ icon: overflowActionIcon,
217
+ shouldAnimate,
218
+ motionClass,
219
+ linkComponent: CustomLink
220
+ }
221
+ ),
222
+ rightContent && /* @__PURE__ */ jsx("div", { className: "ml-2 flex items-center", children: rightContent })
223
+ ]
224
+ }
225
+ );
226
+ };
227
+
228
+ export { NavActions };
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import type { NavHeaderBranding } from '../NavHeader.types';
3
+ export interface NavBrandProps {
4
+ branding: NavHeaderBranding;
5
+ isSearchOpen?: boolean;
6
+ shouldAnimate?: boolean;
7
+ motionClass?: string;
8
+ linkComponent?: React.ComponentType<any>;
9
+ }
10
+ export declare const NavBrand: React.FC<NavBrandProps>;
11
+ export default NavBrand;
12
+ //# sourceMappingURL=NavBrand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavBrand.d.ts","sourceRoot":"","sources":["../../../../src/components/NavHeader/subcomponents/NavBrand.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAmG5C,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { motion } from '@timmbr/motion';
4
+ import { cn } from '@timmbr/utils';
5
+ import { resolveNavDestination, isCrossZoneNavigation } from '../NavHeader.helpers.js';
6
+ import { useTimmbrConfig } from '../../../providers/TimmbrConfigProvider.js';
7
+
8
+ const NavBrand = ({
9
+ branding,
10
+ isSearchOpen = false,
11
+ shouldAnimate = true,
12
+ motionClass,
13
+ linkComponent: CustomLink
14
+ }) => {
15
+ const config = useTimmbrConfig();
16
+ const { logo, miniLogo, href = "/", zone, alt = "Brand Home", className, onClick } = branding;
17
+ const resolvedHref = resolveNavDestination(href, zone, config.zones?.zones) ?? "/";
18
+ const requiresCrossZone = isCrossZoneNavigation(zone, config.zones?.currentZone);
19
+ const showMini = Boolean(isSearchOpen && miniLogo);
20
+ const logoNode = /* @__PURE__ */ jsxs(
21
+ "div",
22
+ {
23
+ className: "relative flex items-center justify-center shrink-0 min-w-[32px] h-8",
24
+ "data-slot": "nav-brand-logo",
25
+ children: [
26
+ /* @__PURE__ */ jsx(
27
+ motion.div,
28
+ {
29
+ initial: false,
30
+ animate: shouldAnimate ? {
31
+ opacity: showMini ? 0 : 1,
32
+ scale: showMini ? 0.92 : 1
33
+ } : void 0,
34
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
35
+ className: cn(
36
+ "flex items-center justify-center shrink-0 transition-opacity",
37
+ showMini ? "pointer-events-none" : "pointer-events-auto",
38
+ !shouldAnimate && (showMini ? "opacity-0" : "opacity-100"),
39
+ motionClass
40
+ ),
41
+ children: logo
42
+ }
43
+ ),
44
+ miniLogo && /* @__PURE__ */ jsx(
45
+ motion.div,
46
+ {
47
+ initial: false,
48
+ animate: shouldAnimate ? {
49
+ opacity: showMini ? 1 : 0,
50
+ scale: showMini ? 1 : 0.92
51
+ } : void 0,
52
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
53
+ className: cn(
54
+ "absolute inset-0 flex items-center justify-center shrink-0",
55
+ showMini ? "pointer-events-auto" : "pointer-events-none",
56
+ !shouldAnimate && (showMini ? "opacity-100" : "opacity-0"),
57
+ motionClass
58
+ ),
59
+ children: miniLogo
60
+ }
61
+ )
62
+ ]
63
+ }
64
+ );
65
+ const wrapperClass = cn(
66
+ "inline-flex items-center justify-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 rounded-md transition-transform",
67
+ className
68
+ );
69
+ if (CustomLink && !requiresCrossZone) {
70
+ return /* @__PURE__ */ jsx(
71
+ CustomLink,
72
+ {
73
+ href: resolvedHref,
74
+ "aria-label": alt,
75
+ className: wrapperClass,
76
+ onClick,
77
+ "data-slot": "nav-brand-link",
78
+ children: logoNode
79
+ }
80
+ );
81
+ }
82
+ return /* @__PURE__ */ jsx(
83
+ "a",
84
+ {
85
+ href: resolvedHref,
86
+ "aria-label": alt,
87
+ "data-cross-zone": requiresCrossZone ? "true" : void 0,
88
+ "data-slot": "nav-brand-link",
89
+ className: wrapperClass,
90
+ onClick,
91
+ children: logoNode
92
+ }
93
+ );
94
+ };
95
+
96
+ export { NavBrand };
@@ -0,0 +1,15 @@
1
+ import * as React from 'react';
2
+ import type { NavHeaderItem } from '../NavHeader.types';
3
+ export interface NavItemsProps {
4
+ items: NavHeaderItem[];
5
+ activeItemId: string | null;
6
+ onItemMouseEnter: (id: string) => void;
7
+ onItemMouseLeave: () => void;
8
+ onItemClick: (id: string, item: NavHeaderItem) => void;
9
+ maxVisibleItems?: number;
10
+ shouldAnimate?: boolean;
11
+ motionClass?: string;
12
+ linkComponent?: React.ComponentType<any>;
13
+ }
14
+ export declare const NavItems: React.FC<NavItemsProps>;
15
+ //# sourceMappingURL=NavItems.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavItems.d.ts","sourceRoot":"","sources":["../../../../src/components/NavHeader/subcomponents/NavItems.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAiJ5C,CAAC"}
@@ -0,0 +1,141 @@
1
+ "use client";
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { motion } from '@timmbr/motion';
5
+ import { cn } from '@timmbr/utils';
6
+ import { navHeaderItemVariants } from '../NavHeader.styles.js';
7
+ import { resolveNavDestination, isCrossZoneNavigation } from '../NavHeader.helpers.js';
8
+ import { NavItemsOverflow } from './NavItemsOverflow.js';
9
+ import { useTimmbrConfig } from '../../../providers/TimmbrConfigProvider.js';
10
+
11
+ const NavItems = ({
12
+ items,
13
+ activeItemId,
14
+ onItemMouseEnter,
15
+ onItemMouseLeave,
16
+ onItemClick,
17
+ maxVisibleItems,
18
+ shouldAnimate = true,
19
+ motionClass,
20
+ linkComponent: CustomLink
21
+ }) => {
22
+ const config = useTimmbrConfig();
23
+ const { visibleItems, overflowItems } = React.useMemo(() => {
24
+ if (typeof maxVisibleItems !== "number" || items.length <= maxVisibleItems) {
25
+ return { visibleItems: items, overflowItems: [] };
26
+ }
27
+ const visibleCount = Math.max(1, maxVisibleItems);
28
+ return {
29
+ visibleItems: items.slice(0, visibleCount),
30
+ overflowItems: items.slice(visibleCount)
31
+ };
32
+ }, [items, maxVisibleItems]);
33
+ return /* @__PURE__ */ jsxs(
34
+ "nav",
35
+ {
36
+ "aria-label": "Main Navigation",
37
+ className: "flex items-center gap-2.5 xl:gap-4 2xl:gap-6 h-full",
38
+ "data-slot": "nav-items-container",
39
+ onMouseLeave: onItemMouseLeave,
40
+ children: [
41
+ visibleItems.map((item) => {
42
+ const isActive = activeItemId === item.id;
43
+ const hasContent = Boolean(item.content);
44
+ const resolvedHref = resolveNavDestination(item.href, item.zone, config.zones?.zones);
45
+ const requiresCrossZone = isCrossZoneNavigation(item.zone, config.zones?.currentZone, item.crossZone);
46
+ const handleClick = (e) => {
47
+ if (item.disabled) {
48
+ e.preventDefault();
49
+ return;
50
+ }
51
+ onItemClick(item.id, item);
52
+ };
53
+ const handleKeyDown = (e) => {
54
+ if (e.key === "Enter" || e.key === " ") {
55
+ if (hasContent && !item.href) {
56
+ e.preventDefault();
57
+ onItemClick(item.id, item);
58
+ }
59
+ }
60
+ };
61
+ const itemContent = /* @__PURE__ */ jsxs(Fragment, { children: [
62
+ /* @__PURE__ */ jsx("span", { children: item.label }),
63
+ item.badge && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center text-xs font-semibold px-1.5 py-0.5 rounded-full bg-primary-100 text-primary-800", children: item.badge }),
64
+ isActive && shouldAnimate && /* @__PURE__ */ jsx(
65
+ motion.div,
66
+ {
67
+ layoutId: "nav-header-active-indicator",
68
+ className: "absolute bottom-0 left-0 right-0 h-[2.5px] bg-[#C0643A] rounded-full",
69
+ transition: { type: "spring", stiffness: 500, damping: 35 }
70
+ }
71
+ ),
72
+ isActive && !shouldAnimate && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-[2.5px] bg-[#C0643A] rounded-full" })
73
+ ] });
74
+ const className = cn(
75
+ navHeaderItemVariants({ active: isActive, disabled: item.disabled }),
76
+ !shouldAnimate && "transition-none",
77
+ motionClass,
78
+ item.className
79
+ );
80
+ if (!hasContent && resolvedHref) {
81
+ if (CustomLink && !requiresCrossZone) {
82
+ return /* @__PURE__ */ jsx(
83
+ CustomLink,
84
+ {
85
+ href: resolvedHref,
86
+ className,
87
+ onClick: handleClick,
88
+ "data-slot": "nav-item-link",
89
+ children: itemContent
90
+ },
91
+ item.id
92
+ );
93
+ }
94
+ return /* @__PURE__ */ jsx(
95
+ "a",
96
+ {
97
+ href: resolvedHref,
98
+ "data-cross-zone": requiresCrossZone ? "true" : void 0,
99
+ className,
100
+ onClick: handleClick,
101
+ "data-slot": "nav-item-link",
102
+ children: itemContent
103
+ },
104
+ item.id
105
+ );
106
+ }
107
+ return /* @__PURE__ */ jsx(
108
+ "button",
109
+ {
110
+ type: "button",
111
+ className,
112
+ "aria-haspopup": "dialog",
113
+ "aria-expanded": isActive,
114
+ disabled: item.disabled,
115
+ onClick: handleClick,
116
+ onKeyDown: handleKeyDown,
117
+ onMouseEnter: () => onItemMouseEnter(item.id),
118
+ "data-slot": "nav-item-trigger",
119
+ "data-active": isActive ? "true" : void 0,
120
+ children: itemContent
121
+ },
122
+ item.id
123
+ );
124
+ }),
125
+ overflowItems.length > 0 && /* @__PURE__ */ jsx(
126
+ NavItemsOverflow,
127
+ {
128
+ items: overflowItems,
129
+ activeItemId,
130
+ onItemClick,
131
+ shouldAnimate,
132
+ motionClass,
133
+ linkComponent: CustomLink
134
+ }
135
+ )
136
+ ]
137
+ }
138
+ );
139
+ };
140
+
141
+ export { NavItems };
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import type { NavHeaderItem } from '../NavHeader.types';
3
+ export interface NavItemsOverflowProps {
4
+ items: NavHeaderItem[];
5
+ activeItemId: string | null;
6
+ onItemClick: (id: string, item: NavHeaderItem) => void;
7
+ shouldAnimate?: boolean;
8
+ motionClass?: string;
9
+ linkComponent?: React.ComponentType<any>;
10
+ }
11
+ export declare const NavItemsOverflow: React.FC<NavItemsOverflowProps>;
12
+ export default NavItemsOverflow;
13
+ //# sourceMappingURL=NavItemsOverflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavItemsOverflow.d.ts","sourceRoot":"","sources":["../../../../src/components/NavHeader/subcomponents/NavItemsOverflow.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACvD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAkL5D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}