@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,532 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { cn } from '@timmbr/utils';
5
+ import { resolveMotion } from '../../types/motion.js';
6
+ import { navHeaderContainerVariants, navHeaderVariants } from './NavHeader.styles.js';
7
+ import { Search } from '@timmbr/icons';
8
+ import { NavHeaderContext } from './NavHeader.context.js';
9
+ import { OfferBanner } from './subcomponents/OfferBanner.js';
10
+ import { NavBrand } from './subcomponents/NavBrand.js';
11
+ import { NavItems } from './subcomponents/NavItems.js';
12
+ import { NavMegaMenu } from './subcomponents/NavMegaMenu.js';
13
+ import { NavSearch } from './subcomponents/NavSearch.js';
14
+ import { NavActions } from './subcomponents/NavActions.js';
15
+ import { NavMobileTabSlider } from './subcomponents/NavMobileTabSlider.js';
16
+ import { NavMobileTabContent } from './subcomponents/NavMobileTabContent.js';
17
+ import { NavMobileSearchDrawer } from './subcomponents/NavMobileSearchDrawer.js';
18
+ import { useGlobalAnimation } from '../../providers/AnimationProvider.js';
19
+
20
+ const NavHeader = React.forwardRef(
21
+ ({
22
+ // 1. Branding & Global Layout
23
+ branding,
24
+ containerMaxWidth = "2xl",
25
+ sticky = false,
26
+ linkComponent,
27
+ rightContent,
28
+ // 2. Modular Configuration Objects
29
+ offerBanner = {
30
+ content: "Extra 15% Off on All Home and Kitchen Orders*"
31
+ },
32
+ navigation,
33
+ search = true,
34
+ actions,
35
+ mobile,
36
+ // 3. Shorthand & Convenience Props (Backwards Compatible)
37
+ showOfferBanner: shorthandShowOfferBanner,
38
+ items: shorthandItems,
39
+ showNavItems: shorthandShowNavItems,
40
+ maxVisibleNavItems: shorthandMaxVisibleNavItems,
41
+ activeItemId: shorthandActiveItemId,
42
+ defaultActiveItemId: shorthandDefaultActiveItemId,
43
+ onActiveItemChange: shorthandOnActiveItemChange,
44
+ showSearch: shorthandShowSearch,
45
+ showActions: shorthandShowActions,
46
+ maxVisibleActions: shorthandMaxVisibleActions,
47
+ overflowActionLabel: shorthandOverflowActionLabel,
48
+ overflowActionIcon: shorthandOverflowActionIcon,
49
+ profileAction: shorthandProfileAction,
50
+ wishlistAction: shorthandWishlistAction,
51
+ cartAction: shorthandCartAction,
52
+ mobileTabSlider: shorthandMobileTabSlider,
53
+ mobileSearchMode: shorthandMobileSearchMode,
54
+ mobileActiveItemId: shorthandMobileActiveItemId,
55
+ defaultMobileActiveItemId: shorthandDefaultMobileActiveItemId,
56
+ onMobileActiveItemChange: shorthandOnMobileActiveItemChange,
57
+ mobileSearchOpen: shorthandMobileSearchOpen,
58
+ defaultMobileSearchOpen: shorthandDefaultMobileSearchOpen,
59
+ onMobileSearchOpenChange: shorthandOnMobileSearchOpenChange,
60
+ // 4. Motion & Styling Overrides
61
+ motion: motionProp,
62
+ className,
63
+ ...props
64
+ }, ref) => {
65
+ const globalMotion = useGlobalAnimation();
66
+ const { shouldAnimate, motionClass } = resolveMotion(motionProp, globalMotion);
67
+ const isOfferBannerVisible = shorthandShowOfferBanner !== void 0 ? shorthandShowOfferBanner : typeof offerBanner === "object" && offerBanner !== null && "show" in offerBanner ? offerBanner.show ?? true : Boolean(offerBanner);
68
+ const navigationConfig = Array.isArray(navigation) ? { items: navigation } : navigation ?? {};
69
+ const navItems = shorthandItems ?? navigationConfig.items ?? [];
70
+ const isNavItemsVisible = shorthandShowNavItems !== void 0 ? shorthandShowNavItems : navigationConfig.show ?? true;
71
+ const maxVisibleNavItems = shorthandMaxVisibleNavItems !== void 0 ? shorthandMaxVisibleNavItems : navigationConfig.maxVisibleItems;
72
+ const controlledActiveId = shorthandActiveItemId !== void 0 ? shorthandActiveItemId : navigationConfig.activeItemId;
73
+ const defaultActiveItemId = shorthandDefaultActiveItemId !== void 0 ? shorthandDefaultActiveItemId : navigationConfig.defaultActiveItemId ?? null;
74
+ const onActiveItemChange = shorthandOnActiveItemChange ?? navigationConfig.onActiveItemChange;
75
+ const searchConfig = typeof search === "object" && search !== null ? search : {};
76
+ const isSearchVisible = shorthandShowSearch !== void 0 ? shorthandShowSearch : searchConfig.show ?? Boolean(search);
77
+ const actionsConfig = Array.isArray(actions) ? { items: actions } : actions ?? {};
78
+ const actionItems = actionsConfig.items;
79
+ const isActionsVisible = shorthandShowActions !== void 0 ? shorthandShowActions : actionsConfig.show ?? true;
80
+ const maxVisibleActions = shorthandMaxVisibleActions !== void 0 ? shorthandMaxVisibleActions : actionsConfig.maxVisible;
81
+ const overflowActionLabel = shorthandOverflowActionLabel ?? actionsConfig.overflow?.label;
82
+ const overflowActionIcon = shorthandOverflowActionIcon ?? actionsConfig.overflow?.icon;
83
+ const profileAction = shorthandProfileAction ?? actionsConfig.profile;
84
+ const wishlistAction = shorthandWishlistAction ?? actionsConfig.wishlist;
85
+ const cartAction = shorthandCartAction ?? actionsConfig.cart;
86
+ const mobileConfig = mobile ?? {};
87
+ const tabSliderOption = mobileConfig.tabSlider;
88
+ const tabSliderConfig = typeof tabSliderOption === "object" && tabSliderOption !== null ? tabSliderOption : {};
89
+ const isMobileTabSliderEnabled = shorthandMobileTabSlider !== void 0 ? shorthandMobileTabSlider : typeof tabSliderOption === "boolean" ? tabSliderOption : tabSliderConfig.show ?? true;
90
+ const controlledMobileActiveId = shorthandMobileActiveItemId !== void 0 ? shorthandMobileActiveItemId : tabSliderConfig.activeItemId;
91
+ const defaultMobileActiveItemId = shorthandDefaultMobileActiveItemId !== void 0 ? shorthandDefaultMobileActiveItemId : tabSliderConfig.defaultActiveItemId ?? null;
92
+ const onMobileActiveItemChange = shorthandOnMobileActiveItemChange ?? tabSliderConfig.onActiveItemChange;
93
+ const mobileSearchConfig = mobileConfig.search ?? {};
94
+ const resolvedMobileSearchMode = shorthandMobileSearchMode ?? mobileSearchConfig.mode ?? searchConfig.mobileMode ?? "bar";
95
+ const controlledMobileSearchOpen = shorthandMobileSearchOpen !== void 0 ? shorthandMobileSearchOpen : mobileSearchConfig.open;
96
+ const defaultMobileSearchOpen = shorthandDefaultMobileSearchOpen !== void 0 ? shorthandDefaultMobileSearchOpen : mobileSearchConfig.defaultOpen ?? false;
97
+ const onMobileSearchOpenChange = shorthandOnMobileSearchOpenChange ?? mobileSearchConfig.onOpenChange;
98
+ const [uncontrolledActiveId, setUncontrolledActiveId] = React.useState(
99
+ defaultActiveItemId
100
+ );
101
+ const activeItemId = controlledActiveId !== void 0 ? controlledActiveId : uncontrolledActiveId;
102
+ const setActiveItemId = React.useCallback(
103
+ (id) => {
104
+ if (controlledActiveId === void 0) {
105
+ setUncontrolledActiveId(id);
106
+ }
107
+ onActiveItemChange?.(id);
108
+ },
109
+ [controlledActiveId, onActiveItemChange]
110
+ );
111
+ const [uncontrolledSearchOpen, setUncontrolledSearchOpen] = React.useState(
112
+ searchConfig.defaultOpen ?? false
113
+ );
114
+ const isSearchOpen = searchConfig.isOpen !== void 0 ? searchConfig.isOpen : uncontrolledSearchOpen;
115
+ const setIsSearchOpen = React.useCallback(
116
+ (open) => {
117
+ if (searchConfig.isOpen === void 0) {
118
+ setUncontrolledSearchOpen(open);
119
+ }
120
+ searchConfig.onOpenChange?.(open);
121
+ },
122
+ [searchConfig]
123
+ );
124
+ const [uncontrolledSearchValue, setUncontrolledSearchValue] = React.useState(
125
+ searchConfig.defaultValue ?? ""
126
+ );
127
+ const searchValue = searchConfig.value !== void 0 ? searchConfig.value : uncontrolledSearchValue;
128
+ const setSearchValue = React.useCallback(
129
+ (val) => {
130
+ if (searchConfig.value === void 0) {
131
+ setUncontrolledSearchValue(val);
132
+ }
133
+ searchConfig.onChange?.(val);
134
+ },
135
+ [searchConfig]
136
+ );
137
+ const leaveTimeoutRef = React.useRef(null);
138
+ const cancelLeaveTimeout = React.useCallback(() => {
139
+ if (leaveTimeoutRef.current) {
140
+ clearTimeout(leaveTimeoutRef.current);
141
+ leaveTimeoutRef.current = null;
142
+ }
143
+ }, []);
144
+ const handleItemMouseEnter = React.useCallback(
145
+ (id) => {
146
+ cancelLeaveTimeout();
147
+ setActiveItemId(id);
148
+ },
149
+ [cancelLeaveTimeout, setActiveItemId]
150
+ );
151
+ const handleItemMouseLeave = React.useCallback(() => {
152
+ cancelLeaveTimeout();
153
+ leaveTimeoutRef.current = setTimeout(() => {
154
+ setActiveItemId(null);
155
+ }, 180);
156
+ }, [cancelLeaveTimeout, setActiveItemId]);
157
+ const handleMegaMenuMouseEnter = React.useCallback(() => {
158
+ cancelLeaveTimeout();
159
+ }, [cancelLeaveTimeout]);
160
+ const handleMegaMenuMouseLeave = React.useCallback(() => {
161
+ cancelLeaveTimeout();
162
+ leaveTimeoutRef.current = setTimeout(() => {
163
+ setActiveItemId(null);
164
+ }, 180);
165
+ }, [cancelLeaveTimeout, setActiveItemId]);
166
+ const handleMegaMenuClose = React.useCallback(() => {
167
+ cancelLeaveTimeout();
168
+ setActiveItemId(null);
169
+ }, [cancelLeaveTimeout, setActiveItemId]);
170
+ const handleItemClick = React.useCallback(
171
+ (id, item) => {
172
+ if (item.content) {
173
+ setActiveItemId(activeItemId === id ? null : id);
174
+ }
175
+ },
176
+ [activeItemId, setActiveItemId]
177
+ );
178
+ const handleSearchSubmit = React.useCallback(
179
+ (query) => {
180
+ searchConfig.onSubmit?.(query);
181
+ },
182
+ [searchConfig]
183
+ );
184
+ React.useEffect(() => {
185
+ return () => {
186
+ if (leaveTimeoutRef.current) {
187
+ clearTimeout(leaveTimeoutRef.current);
188
+ }
189
+ };
190
+ }, []);
191
+ const innerRef = React.useRef(null);
192
+ const leftRef = React.useRef(null);
193
+ const centerRef = React.useRef(null);
194
+ const searchContainerRef = React.useRef(null);
195
+ const [autoMaxVisible, setAutoMaxVisible] = React.useState(void 0);
196
+ React.useEffect(() => {
197
+ if (maxVisibleActions !== void 0 && typeof maxVisibleActions === "number") {
198
+ setAutoMaxVisible(maxVisibleActions);
199
+ return;
200
+ }
201
+ const updateFit = () => {
202
+ if (!innerRef.current) return;
203
+ const innerWidth = innerRef.current.clientWidth;
204
+ if (innerWidth <= 0) return;
205
+ const leftWidth = leftRef.current?.offsetWidth || 0;
206
+ const centerWidth = centerRef.current?.offsetWidth || 0;
207
+ const searchBaseWidth = isSearchVisible ? 52 : 0;
208
+ const columnGap = innerWidth >= 1024 ? 32 : 16;
209
+ const columnGapsTotal = columnGap * 2;
210
+ const rightSectionGap = innerWidth >= 1024 ? 20 : 12;
211
+ const availableWidthForActions = Math.max(
212
+ 0,
213
+ innerWidth - leftWidth - centerWidth - searchBaseWidth - columnGapsTotal - rightSectionGap
214
+ );
215
+ const itemFootprint = innerWidth >= 640 ? 74 : 64;
216
+ const moreButtonFootprint = itemFootprint;
217
+ if (availableWidthForActions <= moreButtonFootprint) {
218
+ setAutoMaxVisible(1);
219
+ return;
220
+ }
221
+ const calculatedSlots = Math.floor(availableWidthForActions / itemFootprint);
222
+ setAutoMaxVisible(Math.max(1, calculatedSlots));
223
+ };
224
+ updateFit();
225
+ const handleResize = () => {
226
+ requestAnimationFrame(updateFit);
227
+ };
228
+ window.addEventListener("resize", handleResize);
229
+ let resizeObserver = null;
230
+ if (typeof ResizeObserver !== "undefined" && innerRef.current) {
231
+ resizeObserver = new ResizeObserver(handleResize);
232
+ resizeObserver.observe(innerRef.current);
233
+ if (leftRef.current) resizeObserver.observe(leftRef.current);
234
+ if (centerRef.current) resizeObserver.observe(centerRef.current);
235
+ }
236
+ return () => {
237
+ window.removeEventListener("resize", handleResize);
238
+ resizeObserver?.disconnect();
239
+ };
240
+ }, [maxVisibleActions, navItems.length, search]);
241
+ const [uncontrolledMobileActiveId, setUncontrolledMobileActiveId] = React.useState(
242
+ defaultMobileActiveItemId
243
+ );
244
+ const mobileActiveItemId = controlledMobileActiveId !== void 0 ? controlledMobileActiveId : uncontrolledMobileActiveId;
245
+ const handleMobileItemClick = React.useCallback(
246
+ (id, item) => {
247
+ if (item.content) {
248
+ const nextId = mobileActiveItemId === id ? null : id;
249
+ if (controlledMobileActiveId === void 0) {
250
+ setUncontrolledMobileActiveId(nextId);
251
+ }
252
+ onMobileActiveItemChange?.(nextId);
253
+ }
254
+ },
255
+ [mobileActiveItemId, controlledMobileActiveId, onMobileActiveItemChange]
256
+ );
257
+ const activeMobileItem = React.useMemo(() => {
258
+ return navItems.find((item) => item.id === mobileActiveItemId) ?? null;
259
+ }, [navItems, mobileActiveItemId]);
260
+ const [uncontrolledMobileSearchOpen, setUncontrolledMobileSearchOpen] = React.useState(
261
+ defaultMobileSearchOpen
262
+ );
263
+ const isMobileSearchOpen = controlledMobileSearchOpen !== void 0 ? controlledMobileSearchOpen : uncontrolledMobileSearchOpen;
264
+ const setIsMobileSearchOpen = React.useCallback(
265
+ (open) => {
266
+ if (controlledMobileSearchOpen === void 0) {
267
+ setUncontrolledMobileSearchOpen(open);
268
+ }
269
+ onMobileSearchOpenChange?.(open);
270
+ },
271
+ [controlledMobileSearchOpen, onMobileSearchOpenChange]
272
+ );
273
+ const activeItem = React.useMemo(() => {
274
+ return navItems.find((item) => item.id === activeItemId) ?? null;
275
+ }, [navItems, activeItemId]);
276
+ const contextValue = React.useMemo(
277
+ () => ({
278
+ activeItemId,
279
+ setActiveItemId,
280
+ isSearchOpen,
281
+ setIsSearchOpen,
282
+ searchValue,
283
+ setSearchValue,
284
+ shouldAnimate,
285
+ motionClass,
286
+ linkComponent,
287
+ handleItemMouseEnter,
288
+ handleItemMouseLeave,
289
+ handleItemClick,
290
+ handleSearchSubmit,
291
+ autoMaxVisibleActions: autoMaxVisible
292
+ }),
293
+ [
294
+ activeItemId,
295
+ setActiveItemId,
296
+ isSearchOpen,
297
+ setIsSearchOpen,
298
+ searchValue,
299
+ setSearchValue,
300
+ shouldAnimate,
301
+ motionClass,
302
+ linkComponent,
303
+ handleItemMouseEnter,
304
+ handleItemMouseLeave,
305
+ handleItemClick,
306
+ handleSearchSubmit,
307
+ autoMaxVisible
308
+ ]
309
+ );
310
+ return /* @__PURE__ */ jsx(NavHeaderContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
311
+ "header",
312
+ {
313
+ ref,
314
+ role: "banner",
315
+ "data-slot": "nav-header",
316
+ className: cn(navHeaderVariants({ sticky }), className),
317
+ ...props,
318
+ children: [
319
+ /* @__PURE__ */ jsx(
320
+ OfferBanner,
321
+ {
322
+ banner: offerBanner,
323
+ show: isOfferBannerVisible,
324
+ shouldAnimate,
325
+ motionClass,
326
+ linkComponent
327
+ }
328
+ ),
329
+ /* @__PURE__ */ jsxs("div", { className: "hidden lg:block", children: [
330
+ /* @__PURE__ */ jsxs(
331
+ "div",
332
+ {
333
+ ref: innerRef,
334
+ className: cn(
335
+ navHeaderContainerVariants({ maxWidth: containerMaxWidth }),
336
+ "relative"
337
+ ),
338
+ "data-slot": "nav-header-inner",
339
+ children: [
340
+ /* @__PURE__ */ jsx("div", { ref: leftRef, className: "flex-1 flex items-center justify-start h-full min-w-0 pr-8 xl:pr-14", children: isNavItemsVisible && navItems.length > 0 && /* @__PURE__ */ jsx(
341
+ NavItems,
342
+ {
343
+ items: navItems,
344
+ activeItemId,
345
+ maxVisibleItems: maxVisibleNavItems,
346
+ onItemMouseEnter: handleItemMouseEnter,
347
+ onItemMouseLeave: handleItemMouseLeave,
348
+ onItemClick: handleItemClick,
349
+ shouldAnimate,
350
+ motionClass,
351
+ linkComponent
352
+ }
353
+ ) }),
354
+ /* @__PURE__ */ jsx(
355
+ "div",
356
+ {
357
+ ref: centerRef,
358
+ className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 flex items-center justify-center shrink-0 z-10 pointer-events-auto",
359
+ children: /* @__PURE__ */ jsx(
360
+ NavBrand,
361
+ {
362
+ branding,
363
+ isSearchOpen,
364
+ shouldAnimate,
365
+ motionClass,
366
+ linkComponent
367
+ }
368
+ )
369
+ }
370
+ ),
371
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-2.5 lg:gap-4 justify-end min-w-0 pl-8 xl:pl-14", children: [
372
+ isSearchVisible && /* @__PURE__ */ jsx("div", { ref: searchContainerRef, className: "flex items-center", children: /* @__PURE__ */ jsx(
373
+ NavSearch,
374
+ {
375
+ config: search,
376
+ isOpen: isSearchOpen,
377
+ onOpenChange: setIsSearchOpen,
378
+ value: searchValue,
379
+ onChange: setSearchValue,
380
+ onSubmit: handleSearchSubmit,
381
+ shouldAnimate,
382
+ motionClass,
383
+ linkComponent
384
+ }
385
+ ) }),
386
+ isActionsVisible && /* @__PURE__ */ jsx(
387
+ NavActions,
388
+ {
389
+ actions: actionItems,
390
+ maxVisibleActions: maxVisibleActions === "auto" ? autoMaxVisible : maxVisibleActions ?? autoMaxVisible,
391
+ overflowActionLabel,
392
+ overflowActionIcon,
393
+ profileAction,
394
+ wishlistAction,
395
+ cartAction,
396
+ rightContent,
397
+ shouldAnimate,
398
+ motionClass,
399
+ linkComponent
400
+ }
401
+ )
402
+ ] })
403
+ ]
404
+ }
405
+ ),
406
+ isNavItemsVisible && /* @__PURE__ */ jsx(
407
+ NavMegaMenu,
408
+ {
409
+ activeItem,
410
+ onMouseEnter: handleMegaMenuMouseEnter,
411
+ onMouseLeave: handleMegaMenuMouseLeave,
412
+ onClose: handleMegaMenuClose,
413
+ shouldAnimate,
414
+ motionClass
415
+ }
416
+ )
417
+ ] }),
418
+ /* @__PURE__ */ jsxs("div", { className: "lg:hidden", "data-slot": "nav-mobile-container", children: [
419
+ /* @__PURE__ */ jsxs(
420
+ "div",
421
+ {
422
+ className: cn(
423
+ navHeaderContainerVariants({ maxWidth: containerMaxWidth }),
424
+ "h-[62px] sm:h-[70px] px-3 sm:px-6"
425
+ ),
426
+ "data-slot": "nav-mobile-top-bar",
427
+ children: [
428
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-start shrink-0", children: /* @__PURE__ */ jsx(
429
+ NavBrand,
430
+ {
431
+ branding,
432
+ isSearchOpen: false,
433
+ shouldAnimate,
434
+ motionClass,
435
+ linkComponent
436
+ }
437
+ ) }),
438
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 sm:gap-2.5 lg:gap-4 justify-end", children: [
439
+ isSearchVisible && resolvedMobileSearchMode === "icon" && /* @__PURE__ */ jsxs(
440
+ "button",
441
+ {
442
+ type: "button",
443
+ onClick: () => setIsMobileSearchOpen(true),
444
+ "aria-label": "Open search drawer",
445
+ className: "group flex flex-col items-center justify-center min-w-[36px] sm:min-w-[40px] lg:min-w-[52px] text-[#3C3C3C] hover:text-[#C0643A] transition-colors py-1 px-1 lg:px-1.5 cursor-pointer",
446
+ "data-slot": "nav-mobile-search-icon-trigger",
447
+ children: [
448
+ /* @__PURE__ */ jsx(Search, { size: 22, className: "shrink-0 stroke-[1.8]" }),
449
+ /* @__PURE__ */ jsx("span", { className: "hidden lg:inline font-sans font-bold text-[10px] tracking-[0.0926em] uppercase", children: "SEARCH" })
450
+ ]
451
+ }
452
+ ),
453
+ isActionsVisible && /* @__PURE__ */ jsx(
454
+ NavActions,
455
+ {
456
+ actions: actionItems,
457
+ maxVisibleActions: isSearchVisible && resolvedMobileSearchMode === "icon" ? 2 : 3,
458
+ overflowActionLabel,
459
+ overflowActionIcon,
460
+ profileAction,
461
+ wishlistAction,
462
+ cartAction,
463
+ rightContent,
464
+ shouldAnimate,
465
+ motionClass,
466
+ linkComponent
467
+ }
468
+ )
469
+ ] })
470
+ ]
471
+ }
472
+ ),
473
+ isSearchVisible && resolvedMobileSearchMode !== "icon" && /* @__PURE__ */ jsx("div", { className: "px-3 sm:px-6 pb-2.5 pt-0.5 bg-[var(--color-bg-2,#F7F1E6)]", children: /* @__PURE__ */ jsxs(
474
+ "button",
475
+ {
476
+ type: "button",
477
+ onClick: () => setIsMobileSearchOpen(true),
478
+ "aria-label": "Open search drawer",
479
+ className: "w-full h-10 px-4 flex items-center gap-2.5 rounded-full bg-white border border-[#E7DFD3] text-left text-sm text-grey-400 hover:border-grey-400 shadow-xs transition-all cursor-pointer select-none",
480
+ "data-slot": "nav-mobile-search-pill",
481
+ children: [
482
+ /* @__PURE__ */ jsx(Search, { size: 18, className: "text-grey-500 shrink-0" }),
483
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: typeof search === "object" && search.placeholder ? search.placeholder : "Search for furniture, decor, and more..." })
484
+ ]
485
+ }
486
+ ) }),
487
+ isNavItemsVisible && isMobileTabSliderEnabled && navItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
488
+ /* @__PURE__ */ jsx(
489
+ NavMobileTabSlider,
490
+ {
491
+ items: navItems,
492
+ activeItemId: mobileActiveItemId,
493
+ onItemClick: handleMobileItemClick,
494
+ shouldAnimate,
495
+ motionClass,
496
+ linkComponent
497
+ }
498
+ ),
499
+ /* @__PURE__ */ jsx(
500
+ NavMobileTabContent,
501
+ {
502
+ activeItem: activeMobileItem,
503
+ onClose: () => handleMobileItemClick(mobileActiveItemId ?? "", activeMobileItem),
504
+ shouldAnimate,
505
+ motionClass
506
+ }
507
+ )
508
+ ] })
509
+ ] }),
510
+ isSearchVisible && /* @__PURE__ */ jsx(
511
+ NavMobileSearchDrawer,
512
+ {
513
+ isOpen: isMobileSearchOpen,
514
+ onClose: () => setIsMobileSearchOpen(false),
515
+ value: searchValue,
516
+ onChange: setSearchValue,
517
+ onSubmit: handleSearchSubmit,
518
+ config: search,
519
+ shouldAnimate,
520
+ motionClass,
521
+ linkComponent
522
+ }
523
+ )
524
+ ]
525
+ }
526
+ ) });
527
+ }
528
+ );
529
+ NavHeader.displayName = "NavHeader";
530
+ const Header = NavHeader;
531
+
532
+ export { Header, NavHeader };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Offer banner bar styles.
3
+ */
4
+ export declare const offerBannerVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
5
+ /**
6
+ * Main header wrapper styles.
7
+ */
8
+ export declare const navHeaderVariants: (props?: ({
9
+ sticky?: boolean | null | undefined;
10
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
11
+ /**
12
+ * Header inner container styles.
13
+ */
14
+ export declare const navHeaderContainerVariants: (props?: ({
15
+ maxWidth?: "sm" | "lg" | "md" | "xl" | "2xl" | "full" | null | undefined;
16
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
17
+ /**
18
+ * Navigation item link / trigger styles.
19
+ */
20
+ export declare const navHeaderItemVariants: (props?: ({
21
+ active?: boolean | null | undefined;
22
+ disabled?: boolean | null | undefined;
23
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
24
+ /**
25
+ * Action button (Search, Profile, Wishlist, Cart) styles.
26
+ */
27
+ export declare const navActionVariants: (props?: ({
28
+ active?: boolean | null | undefined;
29
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
30
+ /**
31
+ * Mega menu dropdown container styles.
32
+ */
33
+ export declare const megaMenuCardVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
34
+ /**
35
+ * Search popover suggestions card styles.
36
+ */
37
+ export declare const searchPopoverCardVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
38
+ /**
39
+ * Overflow action menu dropdown popover container.
40
+ */
41
+ export declare const actionOverflowPopoverVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
42
+ /**
43
+ * Overflow action item row.
44
+ */
45
+ export declare const actionOverflowItemVariants: (props?: ({
46
+ disabled?: boolean | null | undefined;
47
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
48
+ /**
49
+ * Mobile tab slider scroll container with cross-browser hidden scrollbars.
50
+ */
51
+ export declare const mobileTabSliderVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
52
+ /**
53
+ * Mobile tab slider individual item trigger.
54
+ */
55
+ export declare const mobileTabItemVariants: (props?: ({
56
+ active?: boolean | null | undefined;
57
+ disabled?: boolean | null | undefined;
58
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
59
+ /**
60
+ * Mobile expandable tab content panel.
61
+ */
62
+ export declare const mobileTabContentPanelVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
63
+ /**
64
+ * Mobile full-screen search drawer container.
65
+ */
66
+ export declare const mobileSearchDrawerVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
67
+ //# sourceMappingURL=NavHeader.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavHeader.styles.d.ts","sourceRoot":"","sources":["../../../src/components/NavHeader/NavHeader.styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,mBAAmB,oFAE/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;8EAa7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAiBtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;8EAkBjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;8EAa7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,oFAEhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAErC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAatC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,oFAEnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;8EAkBjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,oFAEtC,CAAC"}