@mohasinac/appkit 4.10.0 → 4.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +6 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
  3. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
  4. package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
  5. package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
  6. package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
  7. package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
  8. package/dist/_internal/server/features/audit-log/actions.js +38 -0
  9. package/dist/_internal/server/features/brands/actions.js +0 -2
  10. package/dist/_internal/server/features/brands/og.d.ts +4 -1
  11. package/dist/_internal/server/features/brands/og.js +1 -1
  12. package/dist/_internal/server/features/grouped/data.d.ts +4 -0
  13. package/dist/_internal/server/features/grouped/data.js +24 -0
  14. package/dist/_internal/server/features/grouped/index.d.ts +1 -1
  15. package/dist/_internal/server/features/grouped/index.js +1 -1
  16. package/dist/_internal/server/features/orders/actions.js +9 -0
  17. package/dist/_internal/server/features/orders/adapters.js +25 -0
  18. package/dist/_internal/server/features/products/data.d.ts +2 -2
  19. package/dist/_internal/server/features/products/data.js +5 -23
  20. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  21. package/dist/_internal/server/functions/scheduled.js +17 -1
  22. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
  23. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
  24. package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
  25. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
  26. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
  27. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
  28. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
  29. package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
  30. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
  31. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
  32. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  33. package/dist/_internal/server/jobs/handlers/index.js +3 -0
  34. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
  35. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
  36. package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
  37. package/dist/_internal/server/notifications/channel-health.js +101 -0
  38. package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
  39. package/dist/_internal/shared/features/brands/schema.js +0 -1
  40. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
  41. package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
  42. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  43. package/dist/_internal/shared/features/products/to-product-item.d.ts +25 -0
  44. package/dist/_internal/shared/features/products/to-product-item.js +45 -0
  45. package/dist/client.d.ts +21 -6
  46. package/dist/client.js +13 -3
  47. package/dist/constants/api-endpoints.d.ts +6 -9
  48. package/dist/constants/api-endpoints.js +2 -3
  49. package/dist/contracts/client-auth.d.ts +3 -7
  50. package/dist/contracts/email.d.ts +1 -0
  51. package/dist/features/account/components/AddressForm.js +24 -2
  52. package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
  53. package/dist/features/account/components/BecomeSellerView.js +1 -1
  54. package/dist/features/account/components/NotificationBell.js +1 -1
  55. package/dist/features/account/components/UserBidsView.d.ts +1 -0
  56. package/dist/features/account/components/UserBidsView.js +47 -0
  57. package/dist/features/account/components/UserOrdersView.d.ts +4 -11
  58. package/dist/features/account/components/UserOrdersView.js +54 -4
  59. package/dist/features/account/components/UserReturnsView.d.ts +4 -9
  60. package/dist/features/account/components/UserReturnsView.js +37 -3
  61. package/dist/features/account/components/index.d.ts +3 -2
  62. package/dist/features/account/components/index.js +1 -0
  63. package/dist/features/admin/actions/admin-actions.js +22 -0
  64. package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
  65. package/dist/features/admin/actions/notification-actions.js +4 -3
  66. package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
  67. package/dist/features/admin/components/AdminAdsView.js +86 -89
  68. package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
  69. package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
  70. package/dist/features/admin/components/AdminAuditLogView.js +95 -0
  71. package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
  72. package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
  73. package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
  74. package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
  75. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
  76. package/dist/features/admin/components/AdminCartsView.js +34 -4
  77. package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
  78. package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
  79. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  80. package/dist/features/admin/components/AdminHistoryView.js +11 -1
  81. package/dist/features/admin/components/AdminNotificationsView.js +27 -1
  82. package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
  83. package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
  84. package/dist/features/admin/components/AdminOrdersView.js +92 -24
  85. package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
  86. package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
  87. package/dist/features/admin/components/AdminPayoutsView.js +15 -31
  88. package/dist/features/admin/components/AdminProductEditorView.js +26 -3
  89. package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
  90. package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
  91. package/dist/features/admin/components/AdminStoresView.js +7 -0
  92. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
  93. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
  94. package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
  95. package/dist/features/admin/components/AdminUserEditorView.js +4 -2
  96. package/dist/features/admin/components/AdminUsersView.js +1 -1
  97. package/dist/features/admin/components/AdminWishlistsView.js +14 -1
  98. package/dist/features/admin/components/DataListingView.d.ts +2 -2
  99. package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
  100. package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
  101. package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
  102. package/dist/features/admin/components/ViewNotificationModal.js +15 -0
  103. package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
  104. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
  105. package/dist/features/admin/components/index.d.ts +8 -1
  106. package/dist/features/admin/components/index.js +4 -0
  107. package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
  108. package/dist/features/admin/constants/filter-tabs.js +27 -0
  109. package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
  110. package/dist/features/admin/hooks/useAdminListing.js +3 -1
  111. package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
  112. package/dist/features/admin/hooks/useAdminListingData.js +9 -2
  113. package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
  114. package/dist/features/admin/schemas/firestore.d.ts +12 -0
  115. package/dist/features/analytics/types.d.ts +1 -1
  116. package/dist/features/analytics/types.js +8 -0
  117. package/dist/features/auctions/schemas/index.d.ts +5 -0
  118. package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
  119. package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
  120. package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
  121. package/dist/features/audit-log/schemas/firestore.js +35 -0
  122. package/dist/features/auth/actions/index.d.ts +0 -1
  123. package/dist/features/auth/actions/index.js +0 -1
  124. package/dist/features/auth/hooks/useAuth.d.ts +8 -35
  125. package/dist/features/auth/hooks/useAuth.js +21 -37
  126. package/dist/features/auth/permissions/constants.d.ts +1 -1
  127. package/dist/features/auth/permissions/constants.js +2 -0
  128. package/dist/features/blog/schemas/index.d.ts +32 -0
  129. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
  130. package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
  131. package/dist/features/categories/components/BrandDetailPageView.js +14 -12
  132. package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
  133. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
  134. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
  135. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
  136. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  137. package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
  138. package/dist/features/categories/schemas/firestore.d.ts +19 -2
  139. package/dist/features/categories/schemas/index.d.ts +24 -3
  140. package/dist/features/categories/schemas/index.js +3 -1
  141. package/dist/features/categories/types/index.d.ts +7 -0
  142. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
  143. package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
  144. package/dist/features/contact/components/ContactForm.js +17 -4
  145. package/dist/features/contact/email.d.ts +1 -0
  146. package/dist/features/contact/email.js +3 -0
  147. package/dist/features/events/components/AdminEventEditorView.js +54 -2
  148. package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
  149. package/dist/features/events/components/AdminEventEntriesView.js +56 -89
  150. package/dist/features/events/components/EventFormDrawer.js +5 -1
  151. package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
  152. package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
  153. package/dist/features/events/schemas/index.d.ts +22 -0
  154. package/dist/features/grouped/components/GroupedListingsCarousel.js +4 -1
  155. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +4 -0
  156. package/dist/features/grouped/repository/grouped-listings.repository.js +18 -0
  157. package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
  158. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
  159. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  160. package/dist/features/layout/TitleBarLayout.d.ts +1 -1
  161. package/dist/features/layout/TitleBarLayout.js +3 -3
  162. package/dist/features/media/MediaImage.js +39 -3
  163. package/dist/features/media/types/index.d.ts +10 -0
  164. package/dist/features/media/types/index.js +1 -0
  165. package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
  166. package/dist/features/media/upload/MediaUploadField.js +11 -7
  167. package/dist/features/media/upload/video-poster.d.ts +2 -0
  168. package/dist/features/media/upload/video-poster.js +16 -1
  169. package/dist/features/media/upload/video-poster.test.js +1 -1
  170. package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
  171. package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
  172. package/dist/features/orders/components/index.d.ts +2 -0
  173. package/dist/features/orders/components/index.js +1 -0
  174. package/dist/features/orders/constants/payment-window.d.ts +25 -0
  175. package/dist/features/orders/constants/payment-window.js +25 -0
  176. package/dist/features/orders/repository/orders.repository.d.ts +32 -0
  177. package/dist/features/orders/repository/orders.repository.js +56 -0
  178. package/dist/features/orders/schemas/index.d.ts +24 -24
  179. package/dist/features/orders/types/index.d.ts +33 -0
  180. package/dist/features/pre-orders/schemas/index.d.ts +5 -0
  181. package/dist/features/products/components/BidHistory.js +9 -1
  182. package/dist/features/products/components/GroupSettingsPanel.js +25 -3
  183. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  184. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
  185. package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
  186. package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
  187. package/dist/features/products/components/ProductDetailActions.js +1 -1
  188. package/dist/features/products/components/ProductGrid.js +15 -1
  189. package/dist/features/products/constants/action-defs.d.ts +1 -0
  190. package/dist/features/products/constants/action-defs.js +1 -0
  191. package/dist/features/products/schemas/index.d.ts +5 -0
  192. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
  193. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  194. package/dist/features/search/components/SearchView.d.ts +1 -3
  195. package/dist/features/search/components/SearchView.js +1 -1
  196. package/dist/features/seller/components/QuickProductForm.js +2 -1
  197. package/dist/features/seller/components/SellerBidsView.js +66 -107
  198. package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
  199. package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
  200. package/dist/features/seller/components/SellerOrdersView.js +134 -163
  201. package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
  202. package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
  203. package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
  204. package/dist/features/seller/components/SellerPayoutsView.js +25 -5
  205. package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
  206. package/dist/features/seller/components/SellerProductShell.js +89 -36
  207. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
  208. package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
  209. package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
  210. package/dist/features/seller/components/SellerProductsView.js +131 -189
  211. package/dist/features/seller/components/SellerReviewsView.js +95 -133
  212. package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
  213. package/dist/features/seller/components/SellerShippingView.js +41 -4
  214. package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
  215. package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
  216. package/dist/features/seller/components/SellerStorefrontView.js +42 -5
  217. package/dist/features/seller/components/index.d.ts +2 -2
  218. package/dist/features/seller/components/index.js +2 -2
  219. package/dist/features/shell/FormShell.d.ts +24 -4
  220. package/dist/features/shell/FormShell.js +12 -6
  221. package/dist/features/shell/QuickFormDrawer.js +67 -12
  222. package/dist/features/shell/StepForm.d.ts +30 -1
  223. package/dist/features/shell/StepForm.js +47 -4
  224. package/dist/features/shell/index.d.ts +1 -1
  225. package/dist/features/shell/index.js +1 -1
  226. package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
  227. package/dist/features/shipments/schemas/validation.d.ts +14 -4
  228. package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
  229. package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
  230. package/dist/features/tester/components/TesterHubView.js +3 -2
  231. package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
  232. package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
  233. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +404 -15
  234. package/dist/index.d.ts +15 -3
  235. package/dist/index.js +22 -5
  236. package/dist/next/routing/route-map.d.ts +11 -0
  237. package/dist/next/routing/route-map.js +5 -0
  238. package/dist/providers/email-resend/provider.js +1 -0
  239. package/dist/providers/firebase-client/auth.d.ts +1 -0
  240. package/dist/providers/firebase-client/auth.js +7 -1
  241. package/dist/repositories/index.d.ts +1 -0
  242. package/dist/repositories/index.js +1 -0
  243. package/dist/schemas/registry.d.ts +61 -25
  244. package/dist/security/pii-mask.js +1 -1
  245. package/dist/seed/categories-seed-data.js +69 -0
  246. package/dist/seed/products-auctions-seed-data.js +11 -0
  247. package/dist/seed/products-standard-seed-data.js +93 -4
  248. package/dist/seed/site-settings-seed-data.js +13 -1
  249. package/dist/seed/store-extensions-seed-data.js +1 -1
  250. package/dist/server-entry.d.ts +2 -1
  251. package/dist/server-entry.js +20 -2
  252. package/dist/server.d.ts +7 -2
  253. package/dist/server.js +8 -3
  254. package/dist/styles.css +1 -1
  255. package/dist/tailwind-utilities.css +1 -1
  256. package/dist/ui/components/Form.d.ts +11 -2
  257. package/dist/ui/components/Form.js +4 -3
  258. package/dist/ui/components/FormField.d.ts +3 -1
  259. package/dist/ui/components/FormField.js +22 -4
  260. package/dist/ui/components/ListingLayout.d.ts +1 -2
  261. package/dist/ui/components/ListingLayout.js +1 -1
  262. package/dist/ui/components/RecordDetailModal.d.ts +68 -0
  263. package/dist/ui/components/RecordDetailModal.js +8 -0
  264. package/dist/ui/components/SlottedListingView.js +9 -1
  265. package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
  266. package/dist/ui/forms/FormErrorSummary.js +37 -0
  267. package/dist/ui/forms/FormShell.d.ts +37 -2
  268. package/dist/ui/forms/FormShell.js +37 -7
  269. package/dist/ui/forms/FormShell.style.css +17 -0
  270. package/dist/ui/forms/index.d.ts +2 -0
  271. package/dist/ui/forms/index.js +1 -0
  272. package/dist/ui/index.d.ts +4 -0
  273. package/dist/ui/index.js +5 -0
  274. package/dist/utils/media-url.d.ts +3 -1
  275. package/dist/utils/media-url.js +20 -1
  276. package/dist/validation/schemas.d.ts +4 -4
  277. package/package.json +1 -1
  278. package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
  279. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
  280. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
  281. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
  282. package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
  283. package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
  284. package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
  285. package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
  286. package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
  287. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
  288. package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
  289. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
  290. package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
  291. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
  292. package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
  293. package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
  294. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
  295. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
  296. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
  297. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
  298. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
  299. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
  300. package/dist/features/auth/consent-otp.d.ts +0 -57
  301. package/dist/features/auth/consent-otp.js +0 -127
  302. package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
  303. package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
  304. package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
  305. package/dist/features/checkout/actions/checkout-actions.js +0 -124
  306. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
  307. package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
  308. package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
  309. package/dist/features/classified/components/ClassifiedListView.js +0 -44
  310. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
  311. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
  312. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
  313. package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
  314. package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
  315. package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
  316. package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
  317. package/dist/features/live/components/LiveItemsListView.js +0 -44
  318. package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
  319. package/dist/features/seller/components/SellerTemplatesView.js +0 -276
  320. package/dist/react/hooks/useVisibleItems.d.ts +0 -37
  321. package/dist/react/hooks/useVisibleItems.js +0 -59
  322. package/dist/ui/components/TabStrip.d.ts +0 -34
  323. package/dist/ui/components/TabStrip.js +0 -56
  324. package/dist/ui/components/TabStrip.style.css +0 -97
@@ -1,11 +1,21 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { normalizeError } from "../../../errors/normalize";
4
- import { useState, useRef } from "react";
4
+ import { useEffect, useState, useRef } from "react";
5
+ import { z } from "zod";
5
6
  import Image from "next/image";
6
7
  import { Button, Details, Div, Heading, Input, Label, Li, Row, Span, Stack, Summary, Text, Textarea, Ul } from "../../../ui";
8
+ import { useFormShellState, FormShellContext, FormErrorSummary } from "../../../ui/forms";
7
9
  import { resolveMediaUrl } from "../../../utils/media-url";
8
10
  import { DEFAULT_ACCENT_HEX } from "../lib/franchise-colors";
11
+ // Validates the "Pin Details" step's draft fields — mirrors the existing
12
+ // `disabled={!draftName || !draftHref}` gates on that step's Save buttons.
13
+ const pinDetailsSchema = z.object({
14
+ draftName: z.string().min(1, "Name is required"),
15
+ draftUniverse: z.string().min(1, "Universe/Category is required"),
16
+ draftDescription: z.string().min(1, "Description is required"),
17
+ draftHref: z.string().min(1, "Link (href) is required"),
18
+ });
9
19
  function randomId() {
10
20
  return Math.random().toString(36).slice(2, 9);
11
21
  }
@@ -36,6 +46,11 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
36
46
  const [saving, setSaving] = useState(false);
37
47
  const [error, setError] = useState(null);
38
48
  const [success, setSuccess] = useState(false);
49
+ const { shellCtx, validate: validatePinDetails } = useFormShellState(pinDetailsSchema);
50
+ useEffect(() => {
51
+ validatePinDetails({ draftName, draftUniverse, draftDescription, draftHref });
52
+ // eslint-disable-next-line react-hooks/exhaustive-deps
53
+ }, [draftName, draftUniverse, draftDescription, draftHref]);
39
54
  const containerRef = useRef(null);
40
55
  async function handleImageUpload(e) {
41
56
  const file = e.target.files?.[0];
@@ -119,204 +134,204 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
119
134
  { key: "review", label: "Review & Save" },
120
135
  ];
121
136
  const stepIndex = STEPS.findIndex((s) => s.key === step);
122
- return (_jsxs(Stack, { className: "mx-auto max-w-3xl", gap: "lg", children: [error && (_jsx(Text, { className: CLS_ERROR_BANNER, children: error })), success && (_jsx(Text, { className: CLS_SUCCESS_BANNER, children: "Saved to database successfully!" })), _jsx(Row, { align: "start", children: STEPS.map((s, i) => (_jsxs(Stack, { className: "flex-1", align: "center", children: [_jsxs(Row, { className: "w-full", align: "center", children: [i > 0 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
123
- background: i <= stepIndex
124
- ? "var(--color-black)"
125
- : "var(--border-ink)",
126
- } })), _jsx(Row, { textWeight: "bold", textSize: "sm", className: "h-8 w-8 shrink-0", align: "center", justify: "center", rounded: "full", style: {
127
- background: i < stepIndex
128
- ? "var(--color-black)"
129
- : i === stepIndex
137
+ return (_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(Stack, { className: "mx-auto max-w-3xl", gap: "lg", children: [error && (_jsx(Text, { className: CLS_ERROR_BANNER, children: error })), success && (_jsx(Text, { className: CLS_SUCCESS_BANNER, children: "Saved to database successfully!" })), _jsx(Row, { align: "start", children: STEPS.map((s, i) => (_jsxs(Stack, { className: "flex-1", align: "center", children: [_jsxs(Row, { className: "w-full", align: "center", children: [i > 0 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
138
+ background: i <= stepIndex
139
+ ? "var(--color-black)"
140
+ : "var(--border-ink)",
141
+ } })), _jsx(Row, { textWeight: "bold", textSize: "sm", className: "h-8 w-8 shrink-0", align: "center", justify: "center", rounded: "full", style: {
142
+ background: i < stepIndex
143
+ ? "var(--color-black)"
144
+ : i === stepIndex
145
+ ? "var(--color-yellow)"
146
+ : "var(--surface-elevated)",
147
+ color: i < stepIndex
130
148
  ? "var(--color-yellow)"
131
- : "var(--surface-elevated)",
132
- color: i < stepIndex
133
- ? "var(--color-yellow)"
134
- : "var(--color-black)",
135
- border: i <= stepIndex
136
- ? "2px solid var(--color-black)"
137
- : STY_BORDER_INK,
138
- }, children: i < stepIndex ? "✓" : i + 1 }), i < STEPS.length - 1 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
139
- background: i < stepIndex
140
- ? "var(--color-black)"
141
- : "var(--border-ink)",
142
- } }))] }), _jsx(Span, { weight: "medium",
143
- // audit-content-alignment-ok: label under a small draggable marker dot, admin editor UI not marketing content
144
- className: "mt-1 text-center text-[10px]", style: { color: "var(--color-muted)" }, children: s.label })] }, s.key))) }), step === "image" && (_jsxs(Div, { className: CLS_STEP, style: {
145
- borderColor: "var(--border-ink)",
146
- background: "var(--surface-elevated)",
147
- }, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Upload Background Image" }), _jsx(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: "Choose a wide panoramic image that shows all the characters. You will place pins on it in the next step." }), _jsxs(Label, { layout: "flex-col-center", gap: "md", rounded: "lg", padding: "xl", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Span, { size: "3xl", children: "\uD83D\uDDBC" }), _jsx(Span, { weight: "medium", children: uploading ? "Uploading…" : "Click to choose image" }), _jsx(Span, { size: "xs", style: { color: "var(--color-muted)" }, children: "JPG, PNG, WebP \u2014 wide landscape images work best" }), _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), imageUrl && (_jsxs(Stack, { gap: "xs", children: [_jsx(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "37.5%" }, children: _jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "680px" }) }), _jsx(Text, { className: CLS_SUCCESS_TEXT, children: "\u2713 Image uploaded" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), placeholder: "DC, Marvel and Anime characters", className: CLS_INPUT, style: {
148
- borderColor: "var(--border-ink)",
149
- background: "var(--surface-elevated)",
150
- color: "var(--color-black)",
151
- } })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] }), _jsxs(Row, { justify: "end", gap: "sm", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [(initial?.pins?.length ?? 0) > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: {
152
- background: "transparent",
153
- color: "var(--color-black)",
154
- }, children: "Skip to Review" })), _jsx(Button, { type: "button", onClick: () => setStep("place"), disabled: !imageUrl || uploading, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
155
- background: "var(--color-black)",
156
- color: "var(--color-yellow)",
157
- }, children: "Next: Place Pins \u2192" })] })] })), step === "place" && (_jsxs(Div, { className: CLS_STEP, style: {
158
- borderColor: "var(--border-ink)",
159
- background: "var(--surface-elevated)",
160
- }, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Place a Pin" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: [_jsx(Span, { weight: "bold", children: "Click anywhere on the image" }), " to drop a pin, or enter exact coordinates below."] }), _jsxs(Div, { ref: containerRef, className: CLS_IMG_WRAP, style: {
161
- paddingTop: "56.25%",
162
- cursor: "crosshair",
163
- background: "black",
164
- }, onClick: handleImageClick, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
165
- left: `${pin.xPct}%`,
166
- top: `${pin.yPct}%`,
167
- transform: STY_CENTERED,
168
- zIndex: 10,
169
- }, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
170
- width: 24,
171
- height: 24,
172
- background: pin.accent || DEFAULT_ACCENT_HEX,
173
- border: "2px solid white",
174
- boxShadow: "0 1px 4px rgba(0,0,0,0.5)",
175
- }, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-7 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id))), draftPos && (_jsxs(Div, { className: "absolute", style: {
176
- left: `${draftPos.xPct}%`,
177
- top: `${draftPos.yPct}%`,
178
- transform: STY_CENTERED,
179
- zIndex: 20,
180
- }, children: [_jsx(Span, { className: "absolute animate-ping", rounded: "full", style: {
181
- inset: -6,
182
- background: "rgba(255,228,0,0.4)",
183
- pointerEvents: "none",
184
- } }), _jsx(Row, { textWeight: "bold", className: "relative", align: "center", justify: "center", rounded: "full", style: {
185
- width: 32,
186
- height: 32,
187
- background: "var(--color-yellow)",
188
- border: "3px solid var(--color-black)",
189
- boxShadow: "0 2px 8px rgba(0,0,0,0.55)",
190
- color: "var(--color-black)",
191
- fontSize: 18,
192
- }, children: "\u2605" }), _jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-9 top-1/2 -translate-y-1/2 whitespace-nowrap text-[10px]", padding: "x-xs", rounded: "default", style: { paddingBlock: "0.125rem", background: "var(--color-black)", color: "var(--color-yellow)" }, children: "NEW PIN" })] }))] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
193
- {
194
- label: "X Position (%)",
195
- field: "xPct",
196
- value: draftPos?.xPct ?? "",
197
- onChange: (v) => setDraftPos((prev) => ({
198
- id: prev?.id ?? randomId(),
199
- xPct: Math.max(1, Math.min(99, v)),
200
- yPct: prev?.yPct ?? 50,
201
- })),
202
- },
203
- {
204
- label: "Y Position (%)",
205
- field: "yPct",
206
- value: draftPos?.yPct ?? "",
207
- onChange: (v) => setDraftPos((prev) => ({
208
- id: prev?.id ?? randomId(),
209
- xPct: prev?.xPct ?? 50,
210
- yPct: Math.max(1, Math.min(99, v)),
211
- })),
212
- },
213
- ].map(({ label, field, value, onChange }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "number", min: 1, max: 99, step: 0.1, value: value, placeholder: "e.g. 42.5", onChange: (e) => {
214
- const v = parseFloat(e.target.value);
215
- if (!isNaN(v))
216
- onChange(v);
217
- }, className: CLS_INPUT, style: {
149
+ : "var(--color-black)",
150
+ border: i <= stepIndex
151
+ ? "2px solid var(--color-black)"
152
+ : STY_BORDER_INK,
153
+ }, children: i < stepIndex ? "✓" : i + 1 }), i < STEPS.length - 1 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
154
+ background: i < stepIndex
155
+ ? "var(--color-black)"
156
+ : "var(--border-ink)",
157
+ } }))] }), _jsx(Span, { weight: "medium",
158
+ // audit-content-alignment-ok: label under a small draggable marker dot, admin editor UI not marketing content
159
+ className: "mt-1 text-center text-[10px]", style: { color: "var(--color-muted)" }, children: s.label })] }, s.key))) }), step === "image" && (_jsxs(Div, { className: CLS_STEP, style: {
160
+ borderColor: "var(--border-ink)",
161
+ background: "var(--surface-elevated)",
162
+ }, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Upload Background Image" }), _jsx(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: "Choose a wide panoramic image that shows all the characters. You will place pins on it in the next step." }), _jsxs(Label, { layout: "flex-col-center", gap: "md", rounded: "lg", padding: "xl", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Span, { size: "3xl", children: "\uD83D\uDDBC" }), _jsx(Span, { weight: "medium", children: uploading ? "Uploading…" : "Click to choose image" }), _jsx(Span, { size: "xs", style: { color: "var(--color-muted)" }, children: "JPG, PNG, WebP \u2014 wide landscape images work best" }), _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), imageUrl && (_jsxs(Stack, { gap: "xs", children: [_jsx(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "37.5%" }, children: _jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "680px" }) }), _jsx(Text, { className: CLS_SUCCESS_TEXT, children: "\u2713 Image uploaded" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), placeholder: "DC, Marvel and Anime characters", className: CLS_INPUT, style: {
218
163
  borderColor: "var(--border-ink)",
219
164
  background: "var(--surface-elevated)",
220
165
  color: "var(--color-black)",
221
- } })] }, field))) }), pins.length > 0 && (_jsxs(Text, { style: { color: "var(--color-muted)" }, size: "xs", children: [pins.length, " pin", pins.length !== 1 ? "s" : "", " already placed on this image."] })), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("image"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: { background: "transparent", color: "var(--color-black)" }, children: "\u2190 Back" }), _jsxs(Row, { gap: "sm", children: [pins.length > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "outline", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-bold rounded transition-opacity", style: {
222
- background: "var(--surface-warm)",
166
+ } })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] }), _jsxs(Row, { justify: "end", gap: "sm", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [(initial?.pins?.length ?? 0) > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: {
167
+ background: "transparent",
168
+ color: "var(--color-black)",
169
+ }, children: "Skip to Review" })), _jsx(Button, { type: "button", onClick: () => setStep("place"), disabled: !imageUrl || uploading, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
170
+ background: "var(--color-black)",
171
+ color: "var(--color-yellow)",
172
+ }, children: "Next: Place Pins \u2192" })] })] })), step === "place" && (_jsxs(Div, { className: CLS_STEP, style: {
173
+ borderColor: "var(--border-ink)",
174
+ background: "var(--surface-elevated)",
175
+ }, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Place a Pin" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: [_jsx(Span, { weight: "bold", children: "Click anywhere on the image" }), " to drop a pin, or enter exact coordinates below."] }), _jsxs(Div, { ref: containerRef, className: CLS_IMG_WRAP, style: {
176
+ paddingTop: "56.25%",
177
+ cursor: "crosshair",
178
+ background: "black",
179
+ }, onClick: handleImageClick, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
180
+ left: `${pin.xPct}%`,
181
+ top: `${pin.yPct}%`,
182
+ transform: STY_CENTERED,
183
+ zIndex: 10,
184
+ }, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
185
+ width: 24,
186
+ height: 24,
187
+ background: pin.accent || DEFAULT_ACCENT_HEX,
188
+ border: "2px solid white",
189
+ boxShadow: "0 1px 4px rgba(0,0,0,0.5)",
190
+ }, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-7 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id))), draftPos && (_jsxs(Div, { className: "absolute", style: {
191
+ left: `${draftPos.xPct}%`,
192
+ top: `${draftPos.yPct}%`,
193
+ transform: STY_CENTERED,
194
+ zIndex: 20,
195
+ }, children: [_jsx(Span, { className: "absolute animate-ping", rounded: "full", style: {
196
+ inset: -6,
197
+ background: "rgba(255,228,0,0.4)",
198
+ pointerEvents: "none",
199
+ } }), _jsx(Row, { textWeight: "bold", className: "relative", align: "center", justify: "center", rounded: "full", style: {
200
+ width: 32,
201
+ height: 32,
202
+ background: "var(--color-yellow)",
203
+ border: "3px solid var(--color-black)",
204
+ boxShadow: "0 2px 8px rgba(0,0,0,0.55)",
205
+ color: "var(--color-black)",
206
+ fontSize: 18,
207
+ }, children: "\u2605" }), _jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-9 top-1/2 -translate-y-1/2 whitespace-nowrap text-[10px]", padding: "x-xs", rounded: "default", style: { paddingBlock: "0.125rem", background: "var(--color-black)", color: "var(--color-yellow)" }, children: "NEW PIN" })] }))] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
208
+ {
209
+ label: "X Position (%)",
210
+ field: "xPct",
211
+ value: draftPos?.xPct ?? "",
212
+ onChange: (v) => setDraftPos((prev) => ({
213
+ id: prev?.id ?? randomId(),
214
+ xPct: Math.max(1, Math.min(99, v)),
215
+ yPct: prev?.yPct ?? 50,
216
+ })),
217
+ },
218
+ {
219
+ label: "Y Position (%)",
220
+ field: "yPct",
221
+ value: draftPos?.yPct ?? "",
222
+ onChange: (v) => setDraftPos((prev) => ({
223
+ id: prev?.id ?? randomId(),
224
+ xPct: prev?.xPct ?? 50,
225
+ yPct: Math.max(1, Math.min(99, v)),
226
+ })),
227
+ },
228
+ ].map(({ label, field, value, onChange }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "number", min: 1, max: 99, step: 0.1, value: value, placeholder: "e.g. 42.5", onChange: (e) => {
229
+ const v = parseFloat(e.target.value);
230
+ if (!isNaN(v))
231
+ onChange(v);
232
+ }, className: CLS_INPUT, style: {
233
+ borderColor: "var(--border-ink)",
234
+ background: "var(--surface-elevated)",
223
235
  color: "var(--color-black)",
224
- border: STY_BORDER_INK,
225
- }, children: "Done Adding Pins" })), _jsx(Button, { type: "button", onClick: () => setStep("details"), disabled: !draftPos, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
226
- background: "var(--color-black)",
227
- color: "var(--color-yellow)",
228
- }, children: "Continue: Add Details \u2192" })] })] })] })), step === "details" && (_jsxs(Div, { className: CLS_STEP, style: {
229
- borderColor: "var(--border-ink)",
230
- background: "var(--surface-elevated)",
231
- }, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Pin Details" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: ["Fill in the details for the pin at", " ", _jsxs(Span, { weight: "bold", children: [draftPos?.xPct, "%, ", draftPos?.yPct, "%"] }), "."] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
232
- {
233
- label: "Name *",
234
- value: draftName,
235
- onChange: setDraftName,
236
- placeholder: "SPIDER-MAN",
237
- },
238
- {
239
- label: "Universe / Category *",
240
- value: draftUniverse,
241
- onChange: setDraftUniverse,
242
- placeholder: "Marvel",
243
- },
244
- ].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
236
+ } })] }, field))) }), pins.length > 0 && (_jsxs(Text, { style: { color: "var(--color-muted)" }, size: "xs", children: [pins.length, " pin", pins.length !== 1 ? "s" : "", " already placed on this image."] })), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("image"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: { background: "transparent", color: "var(--color-black)" }, children: "\u2190 Back" }), _jsxs(Row, { gap: "sm", children: [pins.length > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "outline", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-bold rounded transition-opacity", style: {
237
+ background: "var(--surface-warm)",
238
+ color: "var(--color-black)",
239
+ border: STY_BORDER_INK,
240
+ }, children: "Done Adding Pins" })), _jsx(Button, { type: "button", onClick: () => setStep("details"), disabled: !draftPos, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
241
+ background: "var(--color-black)",
242
+ color: "var(--color-yellow)",
243
+ }, children: "Continue: Add Details \u2192" })] })] })] })), step === "details" && (_jsxs(Div, { className: CLS_STEP, style: {
244
+ borderColor: "var(--border-ink)",
245
+ background: "var(--surface-elevated)",
246
+ }, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Pin Details" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: ["Fill in the details for the pin at", " ", _jsxs(Span, { weight: "bold", children: [draftPos?.xPct, "%, ", draftPos?.yPct, "%"] }), "."] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
247
+ {
248
+ label: "Name *",
249
+ value: draftName,
250
+ onChange: setDraftName,
251
+ placeholder: "SPIDER-MAN",
252
+ },
253
+ {
254
+ label: "Universe / Category *",
255
+ value: draftUniverse,
256
+ onChange: setDraftUniverse,
257
+ placeholder: "Marvel",
258
+ },
259
+ ].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
260
+ borderColor: "var(--border-ink)",
261
+ background: "var(--surface-elevated)",
262
+ color: "var(--color-black)",
263
+ } })] }, label))) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Description *" }), _jsx(Textarea, { rows: 3, value: draftDescription, onChange: (e) => setDraftDescription(e.target.value), className: "resize-none rounded border-2 px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] outline-none", style: {
245
264
  borderColor: "var(--border-ink)",
246
265
  background: "var(--surface-elevated)",
247
266
  color: "var(--color-black)",
248
- } })] }, label))) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Description *" }), _jsx(Textarea, { rows: 3, value: draftDescription, onChange: (e) => setDraftDescription(e.target.value), className: "resize-none rounded border-2 px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] outline-none", style: {
249
- borderColor: "var(--border-ink)",
250
- background: "var(--surface-elevated)",
251
- color: "var(--color-black)",
252
- }, placeholder: "Short description shown in the popup\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Link (href) *" }), _jsx(Input, { type: "text", value: draftHref, onChange: (e) => setDraftHref(e.target.value), placeholder: "/franchise/marvel", className: CLS_INPUT, style: {
253
- borderColor: "var(--border-ink)",
254
- background: "var(--surface-elevated)",
255
- color: "var(--color-black)",
256
- } })] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
257
- {
258
- label: "Button Text *",
259
- value: draftBuyText,
260
- onChange: setDraftBuyText,
261
- placeholder: "Get Spider-Man Figures",
262
- },
263
- {
264
- label: "Badge Label",
265
- value: draftBadge,
266
- onChange: setDraftBadge,
267
- placeholder: "MARVEL",
268
- },
269
- ].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
267
+ }, placeholder: "Short description shown in the popup\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Link (href) *" }), _jsx(Input, { type: "text", value: draftHref, onChange: (e) => setDraftHref(e.target.value), placeholder: "/franchise/marvel", className: CLS_INPUT, style: {
270
268
  borderColor: "var(--border-ink)",
271
269
  background: "var(--surface-elevated)",
272
270
  color: "var(--color-black)",
273
- } })] }, label))) }), _jsxs(Row, { align: "end", gap: "sm", children: [_jsxs(Stack, { className: "flex-1", gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Accent Colour (hex)" }), _jsx(Input, { type: "text", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), placeholder: DEFAULT_ACCENT_HEX, className: CLS_INPUT, style: {
271
+ } })] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
272
+ {
273
+ label: "Button Text *",
274
+ value: draftBuyText,
275
+ onChange: setDraftBuyText,
276
+ placeholder: "Get Spider-Man Figures",
277
+ },
278
+ {
279
+ label: "Badge Label",
280
+ value: draftBadge,
281
+ onChange: setDraftBadge,
282
+ placeholder: "MARVEL",
283
+ },
284
+ ].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
274
285
  borderColor: "var(--border-ink)",
275
286
  background: "var(--surface-elevated)",
276
287
  color: "var(--color-black)",
277
- } })] }), _jsx(Input, { type: "color", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), className: "mb-0.5 h-10 w-10 cursor-pointer rounded border-2", style: { borderColor: "var(--border-ink)" }, title: "Pick colour" })] }), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("place"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: { background: "transparent", color: "var(--color-black)" }, children: "\u2190 Back" }), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
278
- commitDraftPin();
279
- setStep("review");
280
- }, variant: "outline", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
281
- background: "var(--surface-warm)",
282
- color: "var(--color-black)",
283
- border: STY_BORDER_INK,
284
- }, children: "Save Pin & Finish" }), _jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
285
- commitDraftPin();
286
- setStep("place");
287
- }, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
288
- background: "var(--color-black)",
289
- color: "var(--color-yellow)",
290
- }, children: "Save Pin & Add Another \u2192" })] })] })] })), step === "review" && (_jsxs(Div, { className: CLS_STEP, style: {
291
- borderColor: "var(--border-ink)",
292
- background: "var(--surface-elevated)",
293
- }, children: [_jsxs(Row, { justify: "between", children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Review & Save" }), _jsxs(Span, { rounded: "full", padding: "pill-md", size: "sm", weight: "bold", style: { background: "var(--surface-warm)" }, children: [pins.length, " pin", pins.length !== 1 ? "s" : ""] })] }), _jsxs(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "56.25%", background: "black" }, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
294
- left: `${pin.xPct}%`,
295
- top: `${pin.yPct}%`,
296
- transform: STY_CENTERED,
297
- zIndex: 10,
298
- }, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
299
- width: 28,
300
- height: 28,
301
- background: pin.accent || DEFAULT_ACCENT_HEX,
302
- border: "2px solid white",
303
- boxShadow: "0 2px 6px rgba(0,0,0,0.55)",
304
- }, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-8 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id)))] }), pins.length > 0 ? (_jsx(Ul, { rounded: "lg", className: "divide-y border", style: { borderColor: "var(--border-ink)" }, children: pins.map((pin, i) => (_jsx(Li, { padding: "inline", children: _jsxs(Row, { gap: "sm", children: [_jsx(Span, { layout: "flex-center", color: "inverse", className: "h-6 w-6 shrink-0", rounded: "full", size: "xs", weight: "bold", style: { background: pin.accent || DEFAULT_ACCENT_HEX }, children: i + 1 }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { className: "truncate", size: "sm", weight: "bold", children: pin.name || (_jsx(Span, { className: "italic", style: { color: "var(--color-muted)" }, children: "Unnamed" })) }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "xs", children: [pin.universe, " \u00B7 ", pin.xPct.toFixed(0), "%,", " ", pin.yPct.toFixed(0), "%"] })] }), _jsx(Button, { type: "button", onClick: () => deletePin(pin.id), variant: "ghost", className: CLS_DELETE_PIN, title: "Remove pin", children: "\u2715" })] }) }, pin.id))) })) : (_jsx(Div, { textSize: "sm", className: "border-2 border-dashed text-left", rounded: "lg", padding: "xl", style: {
305
- borderColor: "var(--border-ink)",
306
- color: "var(--color-muted)",
307
- }, children: "No pins yet \u2014 add some using the button below." })), _jsxs(Details, { rounded: "lg", padding: "md", className: "border", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Summary, { size: "sm", weight: "medium", children: "Image Settings" }), _jsxs(Stack, { className: "mt-3", gap: "3", children: [_jsxs(Label, { layout: "inline-flex", gap: "md", rounded: "default", padding: "toolbar", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", size: "sm", weight: "medium", style: { borderColor: "var(--border-ink)" }, children: [uploading ? "Uploading…" : "Replace Image", _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), className: CLS_INPUT, style: {
308
- borderColor: "var(--border-ink)",
309
- background: "var(--surface-elevated)",
310
- color: "var(--color-black)",
311
- } })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] })] })] }), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => {
312
- setDraftPos(null);
313
- setStep("place");
314
- }, variant: "outline", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-bold rounded transition-opacity", style: {
315
- background: "var(--surface-warm)",
316
- color: "var(--color-black)",
317
- border: STY_BORDER_INK,
318
- }, children: "+ Add Another Pin" }), _jsx(Button, { type: "button", onClick: handleSave, disabled: !imageUrl || saving || pins.length === 0, rounded: "default", variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] transition-opacity disabled:opacity-50", style: {
319
- background: "var(--color-black)",
320
- color: "var(--color-yellow)",
321
- }, children: saving ? "Saving…" : "Save to Database" })] })] }))] }));
288
+ } })] }, label))) }), _jsxs(Row, { align: "end", gap: "sm", children: [_jsxs(Stack, { className: "flex-1", gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Accent Colour (hex)" }), _jsx(Input, { type: "text", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), placeholder: DEFAULT_ACCENT_HEX, className: CLS_INPUT, style: {
289
+ borderColor: "var(--border-ink)",
290
+ background: "var(--surface-elevated)",
291
+ color: "var(--color-black)",
292
+ } })] }), _jsx(Input, { type: "color", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), className: "mb-0.5 h-10 w-10 cursor-pointer rounded border-2", style: { borderColor: "var(--border-ink)" }, title: "Pick colour" })] }), _jsx(FormErrorSummary, {}), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("place"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: { background: "transparent", color: "var(--color-black)" }, children: "\u2190 Back" }), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
293
+ commitDraftPin();
294
+ setStep("review");
295
+ }, variant: "outline", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
296
+ background: "var(--surface-warm)",
297
+ color: "var(--color-black)",
298
+ border: STY_BORDER_INK,
299
+ }, children: "Save Pin & Finish" }), _jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
300
+ commitDraftPin();
301
+ setStep("place");
302
+ }, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
303
+ background: "var(--color-black)",
304
+ color: "var(--color-yellow)",
305
+ }, children: "Save Pin & Add Another \u2192" })] })] })] })), step === "review" && (_jsxs(Div, { className: CLS_STEP, style: {
306
+ borderColor: "var(--border-ink)",
307
+ background: "var(--surface-elevated)",
308
+ }, children: [_jsxs(Row, { justify: "between", children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Review & Save" }), _jsxs(Span, { rounded: "full", padding: "pill-md", size: "sm", weight: "bold", style: { background: "var(--surface-warm)" }, children: [pins.length, " pin", pins.length !== 1 ? "s" : ""] })] }), _jsxs(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "56.25%", background: "black" }, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
309
+ left: `${pin.xPct}%`,
310
+ top: `${pin.yPct}%`,
311
+ transform: STY_CENTERED,
312
+ zIndex: 10,
313
+ }, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
314
+ width: 28,
315
+ height: 28,
316
+ background: pin.accent || DEFAULT_ACCENT_HEX,
317
+ border: "2px solid white",
318
+ boxShadow: "0 2px 6px rgba(0,0,0,0.55)",
319
+ }, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-8 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id)))] }), pins.length > 0 ? (_jsx(Ul, { rounded: "lg", className: "divide-y border", style: { borderColor: "var(--border-ink)" }, children: pins.map((pin, i) => (_jsx(Li, { padding: "inline", children: _jsxs(Row, { gap: "sm", children: [_jsx(Span, { layout: "flex-center", color: "inverse", className: "h-6 w-6 shrink-0", rounded: "full", size: "xs", weight: "bold", style: { background: pin.accent || DEFAULT_ACCENT_HEX }, children: i + 1 }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { className: "truncate", size: "sm", weight: "bold", children: pin.name || (_jsx(Span, { className: "italic", style: { color: "var(--color-muted)" }, children: "Unnamed" })) }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "xs", children: [pin.universe, " \u00B7 ", pin.xPct.toFixed(0), "%,", " ", pin.yPct.toFixed(0), "%"] })] }), _jsx(Button, { type: "button", onClick: () => deletePin(pin.id), variant: "ghost", className: CLS_DELETE_PIN, title: "Remove pin", children: "\u2715" })] }) }, pin.id))) })) : (_jsx(Div, { textSize: "sm", className: "border-2 border-dashed text-left", rounded: "lg", padding: "xl", style: {
320
+ borderColor: "var(--border-ink)",
321
+ color: "var(--color-muted)",
322
+ }, children: "No pins yet \u2014 add some using the button below." })), _jsxs(Details, { rounded: "lg", padding: "md", className: "border", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Summary, { size: "sm", weight: "medium", children: "Image Settings" }), _jsxs(Stack, { className: "mt-3", gap: "3", children: [_jsxs(Label, { layout: "inline-flex", gap: "md", rounded: "default", padding: "toolbar", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", size: "sm", weight: "medium", style: { borderColor: "var(--border-ink)" }, children: [uploading ? "Uploading…" : "Replace Image", _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), className: CLS_INPUT, style: {
323
+ borderColor: "var(--border-ink)",
324
+ background: "var(--surface-elevated)",
325
+ color: "var(--color-black)",
326
+ } })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] })] })] }), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => {
327
+ setDraftPos(null);
328
+ setStep("place");
329
+ }, variant: "outline", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-bold rounded transition-opacity", style: {
330
+ background: "var(--surface-warm)",
331
+ color: "var(--color-black)",
332
+ border: STY_BORDER_INK,
333
+ }, children: "+ Add Another Pin" }), _jsx(Button, { type: "button", onClick: handleSave, disabled: !imageUrl || saving || pins.length === 0, rounded: "default", variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] transition-opacity disabled:opacity-50", style: {
334
+ background: "var(--color-black)",
335
+ color: "var(--color-yellow)",
336
+ }, children: saving ? "Saving…" : "Save to Database" })] })] }))] }) }));
322
337
  }
@@ -62,16 +62,10 @@ export interface SectionCarouselProps<T = unknown> {
62
62
  * Defaults to `true` when `backgroundImage` is provided, `false` otherwise.
63
63
  */
64
64
  lightText?: boolean;
65
- /**
66
- * When `true`, adds a negative right margin to the scroller wrapper so the
67
- * last visible item peeks at the edge.
68
- * Default: false
69
- */
70
- showPeek?: boolean;
71
65
  /**
72
66
  * Minimum item width in px.
73
67
  * Default: 220
74
68
  */
75
69
  minItemWidth?: number;
76
70
  }
77
- export declare function SectionCarousel<T = unknown>({ title, description, headingVariant, pillLabel, backgroundImage, viewMoreHref, viewMoreLabel, items, renderItem, perView, gap, autoScroll, autoScrollInterval, loop, keyExtractor, rows, className, isLoading, skeletonCount, lightText, showPeek: _showPeek, minItemWidth, }: SectionCarouselProps<T>): React.JSX.Element | null;
71
+ export declare function SectionCarousel<T = unknown>({ title, description, headingVariant, pillLabel, backgroundImage, viewMoreHref, viewMoreLabel, items, renderItem, perView, gap, autoScroll, autoScrollInterval, loop, keyExtractor, rows, className, isLoading, skeletonCount, lightText, minItemWidth, }: SectionCarouselProps<T>): React.JSX.Element | null;
@@ -14,7 +14,7 @@ function CarouselSkeleton({ count }) {
14
14
  return (_jsx(Div, { layout: "flex", gap: "4", className: `${__O.hidden}`, padding: "x-md", children: Array.from({ length: count }).map((_, i) => (_jsxs(Stack, { className: "flex-none min-w-[clamp(150px,18vw,260px)] max-w-[clamp(240px,36vw,380px)] h-[clamp(180px,26vh,260px)]", gap: "sm", children: [_jsx(Div, { className: `aspect-square ${skeleton.image}`, rounded: "xl" }), _jsx(Div, { className: `${skeleton.text} w-3/4` }), _jsx(Div, { className: `${skeleton.text} w-1/2` })] }, i))) }));
15
15
  }
16
16
  // --- Component ---------------------------------------------------------------
17
- export function SectionCarousel({ title, description, headingVariant = "editorial", pillLabel, backgroundImage, viewMoreHref, viewMoreLabel = "View all →", items, renderItem, perView = CAROUSEL_PER_VIEW.standard, gap = 16, autoScroll = false, autoScrollInterval = 3500, loop = true, keyExtractor, rows = 1, className = "", isLoading = false, skeletonCount = 4, lightText, showPeek: _showPeek = false, minItemWidth = 220, }) {
17
+ export function SectionCarousel({ title, description, headingVariant = "editorial", pillLabel, backgroundImage, viewMoreHref, viewMoreLabel = "View all →", items, renderItem, perView = CAROUSEL_PER_VIEW.standard, gap = 16, autoScroll = false, autoScrollInterval = 3500, loop = true, keyExtractor, rows = 1, className = "", isLoading = false, skeletonCount = 4, lightText, minItemWidth = 220, }) {
18
18
  const { hand } = useHandMode();
19
19
  if (!isLoading && items.length === 0)
20
20
  return null;
@@ -66,4 +66,4 @@ export interface TitleBarLayoutProps {
66
66
  *
67
67
  * Receives all domain data as props — zero domain imports.
68
68
  */
69
- export declare function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen: _searchOpen, brandName, brandShortName: _brandShortName, siteLogoUrl, logoHref, promotionsHref, compareHref, wishlistHref, wishlistCount, cartHref, cartCount, profileHref, unreadNotificationCount, notificationsHref, loginHref, registerHref, user, notificationSlot, devSlot, navSlot: _navSlot, promoStripText, isDark, onToggleTheme, onTourStart, hasDashboardNav, onToggleDashboardNav, hideSidebarToggle, id, className, }: TitleBarLayoutProps): React.JSX.Element;
69
+ export declare function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen, brandName, brandShortName, siteLogoUrl, logoHref, promotionsHref, compareHref, wishlistHref, wishlistCount, cartHref, cartCount, profileHref, unreadNotificationCount, notificationsHref, loginHref, registerHref, user, notificationSlot, devSlot, navSlot, promoStripText, isDark, onToggleTheme, onTourStart, hasDashboardNav, onToggleDashboardNav, hideSidebarToggle, id, className, }: TitleBarLayoutProps): React.JSX.Element;
@@ -14,7 +14,7 @@ const countBadge = "absolute -top-0.5 -right-0.5 flex items-center justify-cente
14
14
  *
15
15
  * Receives all domain data as props — zero domain imports.
16
16
  */
17
- export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen: _searchOpen, brandName, brandShortName: _brandShortName, siteLogoUrl, logoHref, promotionsHref, compareHref, wishlistHref, wishlistCount = 0, cartHref, cartCount = 0, profileHref, unreadNotificationCount = 0, notificationsHref, loginHref, registerHref, user, notificationSlot, devSlot, navSlot: _navSlot, promoStripText, isDark = false, onToggleTheme, onTourStart, hasDashboardNav, onToggleDashboardNav, hideSidebarToggle = false, id = "titlebar", className = "", }) {
17
+ export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen, brandName, brandShortName, siteLogoUrl, logoHref, promotionsHref, compareHref, wishlistHref, wishlistCount = 0, cartHref, cartCount = 0, profileHref, unreadNotificationCount = 0, notificationsHref, loginHref, registerHref, user, notificationSlot, devSlot, navSlot, promoStripText, isDark = false, onToggleTheme, onTourStart, hasDashboardNav, onToggleDashboardNav, hideSidebarToggle = false, id = "titlebar", className = "", }) {
18
18
  // ── Element builders ────────────────────────────────────────────────────────
19
19
  const promotionsEl = promotionsHref ? (_jsxs(Link, { href: promotionsHref, "aria-label": "Today's deals", className: "flex items-center gap-[var(--appkit-space-1)] px-[var(--appkit-space-3)] py-[var(--appkit-space-1)] rounded-full text-[length:var(--appkit-text-xs)] font-bold bg-primary-100 text-primary-700 dark:bg-secondary-900/40 dark:text-secondary-400 hover:bg-primary-200 dark:hover:bg-secondary-900/60 transition-colors border border-primary-200/60 dark:border-secondary-700/40", children: [_jsx("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { d: "M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.37.86.58 1.41.58.55 0 1.05-.21 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z" }) }), _jsx(Span, { className: "hidden sm:inline", children: "Today's Deals" })] })) : null;
20
20
  const themeBtn = onToggleTheme ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode", onClick: onToggleTheme, className: iconBtn, children: isDark ? (_jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m8.66-9h-1M4.34 12h-1m15.07-6.07-.71.71M6.34 17.66l-.71.71m12.73 0-.71-.71M6.34 6.34l-.71-.71M12 5a7 7 0 1 0 0 14A7 7 0 0 0 12 5z" }) })) : (_jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 12.79A9 9 0 1 1 11.21 3a7 7 0 1 0 9.79 9.79z" }) })) })) : null;
@@ -22,7 +22,7 @@ export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, s
22
22
  const hamburgerBtn = !hideSidebarToggle ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": sidebarOpen ? "Close menu" : hasDashboardNav ? "Open dashboard navigation" : "Open menu", "aria-expanded": sidebarOpen, "aria-controls": "secondary-sidebar", onClick: hasDashboardNav && onToggleDashboardNav ? onToggleDashboardNav : onToggleSidebar, className: iconBtn, children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: sidebarOpen ? (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })) : (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" })) }) })) : null;
23
23
  // Compare is always lg+ (desktop-only feature, less critical on mobile)
24
24
  const compareEl = compareHref ? (_jsx(Link, { href: compareHref, "aria-label": "Compare items", className: `${iconBtn} hidden lg:flex`, children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" }) }) })) : null;
25
- const searchBtn = (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": "Search", onClick: onSearchToggle, className: iconBtn, "data-tour": "nav-search", children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z" }) }) }));
25
+ const searchBtn = (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": "Search", "aria-pressed": searchOpen, onClick: onSearchToggle, className: iconBtn, "data-tour": "nav-search", children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z" }) }) }));
26
26
  // Dedicated notification bell — rendered immediately before the wishlist
27
27
  // icon (per layout request). Falls back to invisible when no href is set;
28
28
  // the count badge mirrors the wishlist/cart pattern.
@@ -33,7 +33,7 @@ export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, s
33
33
  const authButtonsEl = !user && (loginHref || registerHref) ? (_jsxs(Row, { gap: "xs", className: "hidden lg:flex", children: [loginHref && (_jsx(Link, { href: loginHref, className: "px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-sm)] font-medium text-[var(--appkit-color-text-muted)] hover:text-primary-700 dark:hover:text-secondary-400 transition-colors rounded-lg hover:bg-primary-50 dark:hover:bg-[var(--appkit-color-surface-elevated)]", children: "Sign in" })), registerHref && (_jsx(Link, { href: registerHref, className: "px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-sm)] font-semibold rounded-lg bg-primary text-white hover:bg-primary/90 transition-colors btn-glow shadow-sm", children: "Register" }))] })) : null;
34
34
  const hasTb2 = !!(notificationsEl || wishlistEl || cartEl || profileEl);
35
35
  // ── Render ───────────────────────────────────────────────────────────────────
36
- return (_jsxs(BlockHeader, { id: id, className: `sticky top-0 z-50 bg-[var(--appkit-color-bg)]/95 backdrop-blur-md border-b border-[var(--appkit-color-border-subtle)] shadow-sm ${className}`, children: [promoStripText && (_jsx(Section, { color: "inverse", tone: "accent-banner", className: "text-[length:var(--appkit-text-xs)] text-center font-medium", padding: "y-2xs", children: promoStripText })), _jsxs(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: [_jsxs(Row, { justify: "between", gap: "none", className: "relative h-14", children: [_jsx(Row, { gap: "3", children: _jsxs(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center gap-[var(--appkit-space-2)] transition-opacity hover:opacity-80", children: [_jsx(Div, { className: "flex md:hidden", children: _jsx(SiteMark, { title: brandName, size: "sm" }) }), _jsx(SiteLogo, { title: brandName, size: "md" })] }) }), _jsx(Row, { className: "hidden md:flex absolute inset-y-0 left-1/2 -translate-x-1/2", align: "center", children: _jsx(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center transition-opacity hover:opacity-80", children: _jsx(SiteMark, { src: siteLogoUrl, title: brandName, size: "lg" }) }) }), _jsxs(Row, { gap: "xs", children: [devSlot, compareEl, notificationSlot, notificationsEl && _jsx(Div, { className: "hidden lg:flex", children: notificationsEl }), wishlistEl && _jsx(Div, { className: "hidden lg:flex", children: wishlistEl }), cartEl && _jsx(Div, { className: "hidden lg:flex", children: cartEl }), user
36
+ return (_jsxs(BlockHeader, { id: id, className: `sticky top-0 z-50 bg-[var(--appkit-color-bg)]/95 backdrop-blur-md border-b border-[var(--appkit-color-border-subtle)] shadow-sm ${className}`, children: [promoStripText && (_jsx(Section, { color: "inverse", tone: "accent-banner", className: "text-[length:var(--appkit-text-xs)] text-center font-medium", padding: "y-2xs", children: promoStripText })), _jsxs(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: [_jsxs(Row, { justify: "between", gap: "none", className: "relative h-14", children: [_jsx(Row, { gap: "3", children: _jsxs(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center gap-[var(--appkit-space-2)] transition-opacity hover:opacity-80", children: [_jsx(Div, { className: "flex md:hidden", children: _jsx(SiteMark, { title: brandShortName ?? brandName, size: "sm" }) }), _jsx(SiteLogo, { title: brandName, size: "md" })] }) }), _jsx(Row, { className: "hidden md:flex absolute inset-y-0 left-1/2 -translate-x-1/2", align: "center", children: _jsx(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center transition-opacity hover:opacity-80", children: _jsx(SiteMark, { src: siteLogoUrl, title: brandName, size: "lg" }) }) }), _jsxs(Row, { gap: "xs", children: [devSlot, navSlot, compareEl, notificationSlot, notificationsEl && _jsx(Div, { className: "hidden lg:flex", children: notificationsEl }), wishlistEl && _jsx(Div, { className: "hidden lg:flex", children: wishlistEl }), cartEl && _jsx(Div, { className: "hidden lg:flex", children: cartEl }), user
37
37
  ? profileEl && _jsx(Div, { className: "hidden lg:flex", children: profileEl })
38
38
  : authButtonsEl ?? (profileEl && _jsx(Div, { className: "hidden lg:flex", children: profileEl })), searchBtn, promotionsEl, tourBtn, themeBtn, hamburgerBtn] })] }), hasTb2 && (_jsxs(Row, { border: "subtle", as: "nav", "aria-label": "Account actions", justify: "end", gap: "xs", className: "flex lg:hidden h-10 border-t px-[var(--appkit-space-1)]", children: [notificationsEl, wishlistEl, cartEl, profileEl] }))] })] }));
39
39
  }