@mohasinac/appkit 4.52.5 → 4.53.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 (630) hide show
  1. package/dist/.build-stamp.json +4 -4
  2. package/dist/_internal/client/features/sticker-trace/canvas-codec.d.ts +2 -0
  3. package/dist/_internal/client/features/sticker-trace/canvas-codec.js +148 -0
  4. package/dist/_internal/server/features/auctions/actions.js +1 -1
  5. package/dist/_internal/server/features/categories/data.js +23 -7
  6. package/dist/_internal/server/features/checkout/actions.js +10 -3
  7. package/dist/_internal/server/features/checkout/data.d.ts +15 -0
  8. package/dist/_internal/server/features/checkout/data.js +20 -3
  9. package/dist/_internal/server/features/lottery/actions.js +9 -1
  10. package/dist/_internal/server/features/lottery/og.d.ts +40 -0
  11. package/dist/_internal/server/features/lottery/og.js +79 -0
  12. package/dist/_internal/server/features/messages/actions.js +4 -0
  13. package/dist/_internal/server/features/offers/adapters.js +17 -3
  14. package/dist/_internal/server/features/orders/actions.js +7 -2
  15. package/dist/_internal/server/features/raffle/actions.d.ts +19 -0
  16. package/dist/_internal/server/features/raffle/actions.js +25 -0
  17. package/dist/_internal/server/features/reviews/actions.js +1 -1
  18. package/dist/_internal/server/features/reviews/data.d.ts +1 -1
  19. package/dist/_internal/server/features/search/index-build/artifact-store.d.ts +89 -0
  20. package/dist/_internal/server/features/search/index-build/artifact-store.js +208 -0
  21. package/dist/_internal/server/features/search/index-build/build.d.ts +57 -0
  22. package/dist/_internal/server/features/search/index-build/build.js +285 -0
  23. package/dist/_internal/server/features/search/index-build/sources.d.ts +53 -0
  24. package/dist/_internal/server/features/search/index-build/sources.js +385 -0
  25. package/dist/_internal/server/features/search/search-sources.d.ts +0 -15
  26. package/dist/_internal/server/features/search/search-sources.js +142 -7
  27. package/dist/_internal/server/features/seo/robots.js +21 -1
  28. package/dist/_internal/server/features/seo/sitemap.js +1 -1
  29. package/dist/_internal/server/features/shared/listing-data-factory.js +16 -4
  30. package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
  31. package/dist/_internal/server/features/site-settings/adapters.js +26 -0
  32. package/dist/_internal/server/features/sticker-trace/actions.d.ts +109 -0
  33. package/dist/_internal/server/features/sticker-trace/actions.js +172 -0
  34. package/dist/_internal/server/features/sticker-trace/adapters.d.ts +80 -0
  35. package/dist/_internal/server/features/sticker-trace/adapters.js +174 -0
  36. package/dist/_internal/server/features/sticker-trace/build-cut-file.d.ts +26 -0
  37. package/dist/_internal/server/features/sticker-trace/build-cut-file.js +127 -0
  38. package/dist/_internal/server/features/sticker-trace/coordinator.d.ts +27 -0
  39. package/dist/_internal/server/features/sticker-trace/coordinator.js +169 -0
  40. package/dist/_internal/server/features/sticker-trace/fanout.d.ts +43 -0
  41. package/dist/_internal/server/features/sticker-trace/fanout.js +180 -0
  42. package/dist/_internal/server/features/sticker-trace/finalizer.d.ts +25 -0
  43. package/dist/_internal/server/features/sticker-trace/finalizer.js +123 -0
  44. package/dist/_internal/server/features/sticker-trace/mosaic-inputs.d.ts +30 -0
  45. package/dist/_internal/server/features/sticker-trace/mosaic-inputs.js +112 -0
  46. package/dist/_internal/server/features/sticker-trace/progress.d.ts +81 -0
  47. package/dist/_internal/server/features/sticker-trace/progress.js +198 -0
  48. package/dist/_internal/server/features/sticker-trace/promote.d.ts +23 -0
  49. package/dist/_internal/server/features/sticker-trace/promote.js +193 -0
  50. package/dist/_internal/server/features/sticker-trace/shard.d.ts +50 -0
  51. package/dist/_internal/server/features/sticker-trace/shard.js +174 -0
  52. package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +141 -0
  53. package/dist/_internal/server/features/sticker-trace/sheet-actions.js +279 -0
  54. package/dist/_internal/server/features/sticker-trace/storage.d.ts +135 -0
  55. package/dist/_internal/server/features/sticker-trace/storage.js +282 -0
  56. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  57. package/dist/_internal/server/functions/scheduled.js +25 -1
  58. package/dist/_internal/server/jobs/core/_event-ref.d.ts +51 -0
  59. package/dist/_internal/server/jobs/core/_event-ref.js +63 -0
  60. package/dist/_internal/server/jobs/core/assignSpinPrize.d.ts +18 -0
  61. package/dist/_internal/server/jobs/core/assignSpinPrize.js +77 -16
  62. package/dist/_internal/server/jobs/core/auctionSettlement.js +13 -4
  63. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +44 -15
  64. package/dist/_internal/server/jobs/core/bundleStockSync.js +3 -4
  65. package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +44 -0
  66. package/dist/_internal/server/jobs/core/event-draw-reasons.d.ts +78 -0
  67. package/dist/_internal/server/jobs/core/event-draw-reasons.js +133 -0
  68. package/dist/_internal/server/jobs/core/listingProcessor.js +28 -8
  69. package/dist/_internal/server/jobs/core/onOrderCreate.js +12 -1
  70. package/dist/_internal/server/jobs/core/onScamReportCreate.js +13 -2
  71. package/dist/_internal/server/jobs/core/onScamReportRejected.js +8 -2
  72. package/dist/_internal/server/jobs/core/onScamReportVerified.js +8 -2
  73. package/dist/_internal/server/jobs/core/onStoreWrite.js +11 -4
  74. package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +5 -4
  75. package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -4
  76. package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -2
  77. package/dist/_internal/server/jobs/core/promotions.js +7 -4
  78. package/dist/_internal/server/jobs/core/searchIndexBuild.d.ts +7 -0
  79. package/dist/_internal/server/jobs/core/searchIndexBuild.js +211 -0
  80. package/dist/_internal/server/jobs/core/triggerEventRaffle.d.ts +35 -0
  81. package/dist/_internal/server/jobs/core/triggerEventRaffle.js +213 -31
  82. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +20 -14
  83. package/dist/_internal/server/jobs/handlers/assignSpinPrize.d.ts +8 -0
  84. package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +15 -15
  85. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  86. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  87. package/dist/_internal/server/jobs/handlers/onCategoryWrite.js +18 -0
  88. package/dist/_internal/server/jobs/handlers/onProductWrite.js +18 -0
  89. package/dist/_internal/server/jobs/handlers/onReviewWrite.js +18 -0
  90. package/dist/_internal/server/jobs/handlers/onScamReportUpdate.js +18 -0
  91. package/dist/_internal/server/jobs/handlers/onStoreWrite.js +18 -0
  92. package/dist/_internal/server/jobs/handlers/searchIndexBuild.d.ts +2 -0
  93. package/dist/_internal/server/jobs/handlers/searchIndexBuild.js +2 -0
  94. package/dist/_internal/server/jobs/handlers/triggerEventRaffle.d.ts +8 -0
  95. package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -6
  96. package/dist/_internal/shared/actions/action-registry.js +29 -0
  97. package/dist/_internal/shared/cache/revalidate-targets.d.ts +0 -1
  98. package/dist/_internal/shared/cache/revalidate-targets.js +10 -8
  99. package/dist/_internal/shared/features/events/config.d.ts +14 -0
  100. package/dist/_internal/shared/features/events/config.js +14 -0
  101. package/dist/_internal/shared/features/notifications/action-url.js +8 -0
  102. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  103. package/dist/_internal/shared/features/sticker-trace/codec.d.ts +81 -0
  104. package/dist/_internal/shared/features/sticker-trace/codec.js +30 -0
  105. package/dist/_internal/shared/features/sticker-trace/config.d.ts +81 -0
  106. package/dist/_internal/shared/features/sticker-trace/config.js +177 -0
  107. package/dist/_internal/shared/features/sticker-trace/cut-contour.d.ts +20 -0
  108. package/dist/_internal/shared/features/sticker-trace/cut-contour.js +60 -0
  109. package/dist/_internal/shared/features/sticker-trace/export/build-export-set.d.ts +65 -0
  110. package/dist/_internal/shared/features/sticker-trace/export/build-export-set.js +176 -0
  111. package/dist/_internal/shared/features/sticker-trace/export/cut-svg.d.ts +56 -0
  112. package/dist/_internal/shared/features/sticker-trace/export/cut-svg.js +120 -0
  113. package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.d.ts +92 -0
  114. package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.js +153 -0
  115. package/dist/_internal/shared/features/sticker-trace/export/nesting.d.ts +51 -0
  116. package/dist/_internal/shared/features/sticker-trace/export/nesting.js +110 -0
  117. package/dist/_internal/shared/features/sticker-trace/export/page-sizes.d.ts +68 -0
  118. package/dist/_internal/shared/features/sticker-trace/export/page-sizes.js +223 -0
  119. package/dist/_internal/shared/features/sticker-trace/export/part-tiling.d.ts +51 -0
  120. package/dist/_internal/shared/features/sticker-trace/export/part-tiling.js +178 -0
  121. package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.d.ts +26 -0
  122. package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.js +134 -0
  123. package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.d.ts +40 -0
  124. package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.js +195 -0
  125. package/dist/_internal/shared/features/sticker-trace/index.d.ts +2 -0
  126. package/dist/_internal/shared/features/sticker-trace/index.js +59 -0
  127. package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.d.ts +11 -0
  128. package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.js +66 -0
  129. package/dist/_internal/shared/features/sticker-trace/math/edt.d.ts +27 -0
  130. package/dist/_internal/shared/features/sticker-trace/math/edt.js +165 -0
  131. package/dist/_internal/shared/features/sticker-trace/math/label.d.ts +15 -0
  132. package/dist/_internal/shared/features/sticker-trace/math/label.js +156 -0
  133. package/dist/_internal/shared/features/sticker-trace/math/marching-squares.d.ts +16 -0
  134. package/dist/_internal/shared/features/sticker-trace/math/marching-squares.js +242 -0
  135. package/dist/_internal/shared/features/sticker-trace/math/morphology.d.ts +46 -0
  136. package/dist/_internal/shared/features/sticker-trace/math/morphology.js +168 -0
  137. package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.d.ts +88 -0
  138. package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.js +286 -0
  139. package/dist/_internal/shared/features/sticker-trace/math/rdp.d.ts +10 -0
  140. package/dist/_internal/shared/features/sticker-trace/math/rdp.js +74 -0
  141. package/dist/_internal/shared/features/sticker-trace/resume.d.ts +50 -0
  142. package/dist/_internal/shared/features/sticker-trace/resume.js +160 -0
  143. package/dist/_internal/shared/features/sticker-trace/trace/cluster.d.ts +20 -0
  144. package/dist/_internal/shared/features/sticker-trace/trace/cluster.js +132 -0
  145. package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.d.ts +28 -0
  146. package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.js +120 -0
  147. package/dist/_internal/shared/features/sticker-trace/trace/flood.d.ts +21 -0
  148. package/dist/_internal/shared/features/sticker-trace/trace/flood.js +104 -0
  149. package/dist/_internal/shared/features/sticker-trace/trace/geometry.d.ts +3 -0
  150. package/dist/_internal/shared/features/sticker-trace/trace/geometry.js +140 -0
  151. package/dist/_internal/shared/features/sticker-trace/trace/line-filter.d.ts +15 -0
  152. package/dist/_internal/shared/features/sticker-trace/trace/line-filter.js +138 -0
  153. package/dist/_internal/shared/features/sticker-trace/trace/merge.d.ts +27 -0
  154. package/dist/_internal/shared/features/sticker-trace/trace/merge.js +187 -0
  155. package/dist/_internal/shared/features/sticker-trace/trace/paper.d.ts +32 -0
  156. package/dist/_internal/shared/features/sticker-trace/trace/paper.js +147 -0
  157. package/dist/_internal/shared/features/sticker-trace/trace/prefilter.d.ts +30 -0
  158. package/dist/_internal/shared/features/sticker-trace/trace/prefilter.js +125 -0
  159. package/dist/_internal/shared/features/sticker-trace/trace/quantise.d.ts +10 -0
  160. package/dist/_internal/shared/features/sticker-trace/trace/quantise.js +153 -0
  161. package/dist/_internal/shared/features/sticker-trace/trace/ridge.d.ts +88 -0
  162. package/dist/_internal/shared/features/sticker-trace/trace/ridge.js +344 -0
  163. package/dist/_internal/shared/features/sticker-trace/trace/segment.d.ts +10 -0
  164. package/dist/_internal/shared/features/sticker-trace/trace/segment.js +251 -0
  165. package/dist/_internal/shared/features/sticker-trace/types.d.ts +197 -0
  166. package/dist/_internal/shared/features/sticker-trace/types.js +49 -0
  167. package/dist/_internal/shared/listing-types/_registry.d.ts +11 -0
  168. package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
  169. package/dist/_internal/shared/listing-types/art/config.js +1 -0
  170. package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
  171. package/dist/_internal/shared/listing-types/auction/config.js +1 -0
  172. package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
  173. package/dist/_internal/shared/listing-types/classified/config.js +1 -0
  174. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
  175. package/dist/_internal/shared/listing-types/digital-code/config.js +1 -0
  176. package/dist/_internal/shared/listing-types/feature-flags.d.ts +7 -0
  177. package/dist/_internal/shared/listing-types/feature-flags.js +9 -0
  178. package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
  179. package/dist/_internal/shared/listing-types/live/config.js +1 -0
  180. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
  181. package/dist/_internal/shared/listing-types/pre-order/config.js +1 -0
  182. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
  183. package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -0
  184. package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
  185. package/dist/_internal/shared/listing-types/standard/config.js +1 -0
  186. package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
  187. package/dist/_internal/shared/listing-types/stickers/config.js +1 -0
  188. package/dist/_internal/shared/media/limits.d.ts +12 -2
  189. package/dist/_internal/shared/media/limits.js +12 -2
  190. package/dist/_internal/shared/search/artifact-url.d.ts +35 -0
  191. package/dist/_internal/shared/search/artifact-url.js +119 -0
  192. package/dist/_internal/shared/search/index-record.d.ts +68 -0
  193. package/dist/_internal/shared/search/index-record.js +96 -0
  194. package/dist/_internal/shared/search/match.d.ts +65 -0
  195. package/dist/_internal/shared/search/match.js +263 -0
  196. package/dist/client.d.ts +8 -7
  197. package/dist/client.js +12 -5
  198. package/dist/configs/eslint.js +22 -2
  199. package/dist/constants/api-endpoints.d.ts +68 -0
  200. package/dist/constants/api-endpoints.js +32 -0
  201. package/dist/constants/field-names.d.ts +7 -1
  202. package/dist/constants/field-names.js +36 -1
  203. package/dist/contracts/repository.d.ts +8 -7
  204. package/dist/contracts/search.d.ts +2 -2
  205. package/dist/contracts/table.d.ts +3 -3
  206. package/dist/contracts/table.js +3 -3
  207. package/dist/core/contact-submissions.repository.js +2 -2
  208. package/dist/core/integration-keys.js +7 -1
  209. package/dist/core/newsletter.repository.js +2 -2
  210. package/dist/core/site-config.js +1 -1
  211. package/dist/errors/error-codes.d.ts +30 -0
  212. package/dist/errors/error-codes.js +30 -0
  213. package/dist/errors/error-display-map.js +40 -1
  214. package/dist/features/account/api/[userId]/addresses/route.js +1 -1
  215. package/dist/features/account/components/UserBidsView.js +1 -1
  216. package/dist/features/account/components/index.d.ts +0 -8
  217. package/dist/features/account/components/index.js +0 -4
  218. package/dist/features/addresses/repository/addresses.repository.d.ts +17 -6
  219. package/dist/features/addresses/repository/addresses.repository.js +65 -9
  220. package/dist/features/addresses/schemas/firestore.d.ts +17 -6
  221. package/dist/features/admin/actions/notification-actions.js +15 -6
  222. package/dist/features/admin/api/bids/route.js +1 -1
  223. package/dist/features/admin/api/coupons/route.js +1 -1
  224. package/dist/features/admin/api/products/route.js +1 -1
  225. package/dist/features/admin/api/reviews/route.js +1 -1
  226. package/dist/features/admin/components/AdminAdEditorView.js +19 -5
  227. package/dist/features/admin/components/AdminAuditLogView.js +1 -1
  228. package/dist/features/admin/components/AdminBlogEditorView.js +0 -1
  229. package/dist/features/admin/components/AdminBlogView.js +1 -1
  230. package/dist/features/admin/components/AdminBrandsView.js +17 -1
  231. package/dist/features/admin/components/AdminCategoryEditorView.js +0 -1
  232. package/dist/features/admin/components/AdminContactView.js +1 -1
  233. package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -3
  234. package/dist/features/admin/components/AdminNewsletterView.js +1 -1
  235. package/dist/features/admin/components/AdminOrdersView.js +9 -2
  236. package/dist/features/admin/components/AdminPayoutsView.js +1 -1
  237. package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -0
  238. package/dist/features/admin/components/AdminProductEditorView.d.ts +10 -1
  239. package/dist/features/admin/components/AdminProductEditorView.js +24 -37
  240. package/dist/features/admin/components/AdminProductsView.js +10 -3
  241. package/dist/features/admin/components/AdminScammersView.js +1 -1
  242. package/dist/features/admin/components/AdminSectionsView.js +21 -5
  243. package/dist/features/admin/components/AdminSessionsView.js +1 -1
  244. package/dist/features/admin/components/AdminSublistingCategoriesView.js +22 -1
  245. package/dist/features/admin/components/AdminTeamView.js +1 -1
  246. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +0 -1
  247. package/dist/features/admin/components/AdminUsersView.js +1 -1
  248. package/dist/features/admin/components/DataListingView.d.ts +2 -1
  249. package/dist/features/admin/components/DataListingView.js +9 -4
  250. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +0 -2
  251. package/dist/features/admin/hooks/useAdminListing.d.ts +1 -1
  252. package/dist/features/admin/repository/site-settings.repository.js +8 -3
  253. package/dist/features/admin/schemas/firestore.d.ts +62 -1
  254. package/dist/features/admin/schemas/firestore.js +32 -0
  255. package/dist/features/admin/types/index.d.ts +1 -1
  256. package/dist/features/auctions/actions/bid-actions.d.ts +2 -2
  257. package/dist/features/auctions/actions/bid-actions.js +16 -4
  258. package/dist/features/auctions/api/route.js +1 -1
  259. package/dist/features/auctions/components/AuctionBottomActions.js +4 -0
  260. package/dist/features/auctions/repository/bid.repository.d.ts +46 -4
  261. package/dist/features/auctions/repository/bid.repository.js +114 -13
  262. package/dist/features/auctions/schemas/firestore.d.ts +24 -4
  263. package/dist/features/auctions/schemas/firestore.js +1 -0
  264. package/dist/features/auth/actions/profile-actions.js +30 -4
  265. package/dist/features/auth/components/index.d.ts +0 -1
  266. package/dist/features/auth/components/index.js +0 -1
  267. package/dist/features/auth/repository/session.repository.d.ts +17 -3
  268. package/dist/features/auth/repository/session.repository.js +46 -5
  269. package/dist/features/auth/repository/token.repository.d.ts +27 -4
  270. package/dist/features/auth/repository/token.repository.js +65 -11
  271. package/dist/features/auth/repository/user.repository.d.ts +33 -7
  272. package/dist/features/auth/repository/user.repository.js +100 -15
  273. package/dist/features/auth/schemas/firestore.d.ts +63 -12
  274. package/dist/features/auth/schemas/firestore.js +11 -0
  275. package/dist/features/before-after/api/route.js +1 -1
  276. package/dist/features/blog/components/BlogListView.js +16 -3
  277. package/dist/features/blog/components/BlogPostView.js +1 -1
  278. package/dist/features/blog/schemas/index.d.ts +2 -2
  279. package/dist/features/cart/api/route.js +1 -1
  280. package/dist/features/catalogue/repository/catalogue.repository.d.ts +7 -7
  281. package/dist/features/catalogue/repository/catalogue.repository.js +28 -10
  282. package/dist/features/catalogue/schemas/firestore.d.ts +11 -0
  283. package/dist/features/categories/api/route.js +10 -10
  284. package/dist/features/categories/components/CategoryDetailPageView.js +35 -5
  285. package/dist/features/categories/components/CategorySelectorCreate.js +0 -1
  286. package/dist/features/categories/components/index.d.ts +0 -2
  287. package/dist/features/categories/components/index.js +0 -1
  288. package/dist/features/categories/repository/categories.repository.d.ts +1 -0
  289. package/dist/features/categories/repository/categories.repository.js +31 -1
  290. package/dist/features/categories/schemas/index.d.ts +2 -2
  291. package/dist/features/categories/utils/taxonomy-visual.d.ts +21 -0
  292. package/dist/features/categories/utils/taxonomy-visual.js +58 -0
  293. package/dist/features/checkout/actions/checkout-value-otp-actions.js +8 -1
  294. package/dist/features/collections/api/[slug]/route.js +3 -3
  295. package/dist/features/collections/api/route.js +1 -1
  296. package/dist/features/consultation/api/route.js +1 -1
  297. package/dist/features/consultation/repository/consultations.repository.js +1 -1
  298. package/dist/features/consultation/types/index.d.ts +1 -1
  299. package/dist/features/contact/components/ContactForm.js +1 -3
  300. package/dist/features/corporate/api/route.js +1 -1
  301. package/dist/features/corporate/repository/corporate.repository.js +1 -1
  302. package/dist/features/corporate/types/index.d.ts +1 -1
  303. package/dist/features/cron/jobs/auction-expiry.job.js +1 -1
  304. package/dist/features/cron/jobs/preorder-reminder.job.js +1 -1
  305. package/dist/features/events/actions/event-actions.d.ts +14 -0
  306. package/dist/features/events/actions/event-actions.js +82 -3
  307. package/dist/features/events/api/[id]/route.js +2 -2
  308. package/dist/features/events/components/AdminEventEditorView.js +22 -3
  309. package/dist/features/events/components/AdminEventsView.js +32 -8
  310. package/dist/features/events/components/EventRafflesSection.d.ts +34 -1
  311. package/dist/features/events/components/EventRafflesSection.js +52 -3
  312. package/dist/features/events/components/SpinWheelView.d.ts +2 -2
  313. package/dist/features/events/components/SpinWheelView.js +41 -4
  314. package/dist/features/events/repository/event-entry.repository.d.ts +14 -2
  315. package/dist/features/events/repository/event-entry.repository.js +41 -7
  316. package/dist/features/events/schemas/firestore.d.ts +17 -4
  317. package/dist/features/events/types/index.d.ts +37 -0
  318. package/dist/features/faq/repository/faqs.repository.js +1 -1
  319. package/dist/features/faq/schemas/index.d.ts +5 -2
  320. package/dist/features/faq/schemas/index.js +6 -0
  321. package/dist/features/faq/types/index.d.ts +0 -1
  322. package/dist/features/grouped/components/GroupedListingEditorView.js +17 -2
  323. package/dist/features/homepage/api/carousel/[id]/route.js +1 -1
  324. package/dist/features/homepage/api/carousel/route.js +4 -4
  325. package/dist/features/homepage/api/route.js +2 -2
  326. package/dist/features/homepage/api/sections/route.js +1 -1
  327. package/dist/features/homepage/components/AnnouncementBar.d.ts +1 -9
  328. package/dist/features/homepage/components/AnnouncementBar.js +13 -19
  329. package/dist/features/homepage/components/MarketplaceHomepageView.js +6 -1
  330. package/dist/features/homepage/components/index.d.ts +0 -2
  331. package/dist/features/homepage/components/index.js +0 -1
  332. package/dist/features/homepage/repository/homepage.repository.js +1 -1
  333. package/dist/features/homepage/schemas/firestore.d.ts +6 -0
  334. package/dist/features/homepage/schemas/index.d.ts +10 -10
  335. package/dist/features/layout/AppLayoutShell.d.ts +11 -0
  336. package/dist/features/layout/AppLayoutShell.js +64 -12
  337. package/dist/features/layout/BottomActionsContext.d.ts +16 -0
  338. package/dist/features/layout/BottomActionsContext.js +5 -0
  339. package/dist/features/layout/BottomChrome.js +48 -9
  340. package/dist/features/layout/BottomNavbar.d.ts +14 -0
  341. package/dist/features/layout/BottomNavbar.js +43 -3
  342. package/dist/features/layout/MainNavbar.d.ts +11 -0
  343. package/dist/features/layout/NavbarLayout.d.ts +3 -0
  344. package/dist/features/layout/NavbarLayout.js +88 -11
  345. package/dist/features/layout/SideActionDock.d.ts +1 -0
  346. package/dist/features/layout/SideActionDock.js +219 -0
  347. package/dist/features/layout/TitleBarLayout.js +1 -1
  348. package/dist/features/layout/cta-anchor.d.ts +31 -0
  349. package/dist/features/layout/cta-anchor.js +31 -0
  350. package/dist/features/layout/hooks/useBottomActions.d.ts +7 -0
  351. package/dist/features/layout/hooks/useBottomActions.js +6 -1
  352. package/dist/features/layout/index.d.ts +9 -1
  353. package/dist/features/layout/index.js +9 -1
  354. package/dist/features/layout/useCtaReveal.d.ts +24 -0
  355. package/dist/features/layout/useCtaReveal.js +82 -0
  356. package/dist/features/layout/useHoldToOpen.d.ts +41 -0
  357. package/dist/features/layout/useHoldToOpen.js +84 -0
  358. package/dist/features/lottery/repository/lottery-entry.repository.d.ts +18 -3
  359. package/dist/features/lottery/repository/lottery-entry.repository.js +48 -6
  360. package/dist/features/lottery/schemas/firestore.d.ts +33 -5
  361. package/dist/features/loyalty/api/balance/route.js +1 -1
  362. package/dist/features/loyalty/api/history/route.js +1 -1
  363. package/dist/features/media/MediaImage.js +0 -1
  364. package/dist/features/media/MediaPickerModal.js +7 -1
  365. package/dist/features/media/modals/ImageEditor.js +5 -1
  366. package/dist/features/media/modals/VideoThumbnailSelector.js +17 -1
  367. package/dist/features/media/repository/media-assets.repository.d.ts +19 -0
  368. package/dist/features/media/upload/CameraCapture.js +16 -1
  369. package/dist/features/media/upload/ImageUpload.js +42 -4
  370. package/dist/features/media/upload/MediaUploadField.js +69 -13
  371. package/dist/features/media/upload/downscale-image.d.ts +56 -0
  372. package/dist/features/media/upload/downscale-image.js +150 -0
  373. package/dist/features/messages/components/ConversationThreadView.js +45 -2
  374. package/dist/features/messages/components/MessageSellerButton.d.ts +15 -1
  375. package/dist/features/messages/components/MessageSellerButton.js +10 -2
  376. package/dist/features/messages/schemas/firestore.d.ts +15 -0
  377. package/dist/features/orders/hooks/useOrders.js +4 -2
  378. package/dist/features/orders/repository/orders.repository.d.ts +15 -4
  379. package/dist/features/orders/repository/orders.repository.js +52 -20
  380. package/dist/features/orders/schemas/firestore.d.ts +15 -4
  381. package/dist/features/orders/schemas/index.d.ts +8 -8
  382. package/dist/features/orders/types/index.d.ts +2 -2
  383. package/dist/features/payments/repository/payments.repository.js +2 -2
  384. package/dist/features/payments/repository/payout.repository.d.ts +23 -6
  385. package/dist/features/payments/repository/payout.repository.js +63 -23
  386. package/dist/features/payments/repository/saved-payment-methods.repository.d.ts +17 -6
  387. package/dist/features/payments/repository/saved-payment-methods.repository.js +59 -11
  388. package/dist/features/payments/schemas/firestore.d.ts +14 -3
  389. package/dist/features/payments/schemas/saved-methods-firestore.d.ts +12 -1
  390. package/dist/features/pre-orders/api/[slug]/route.js +1 -1
  391. package/dist/features/pre-orders/api/admin/route.js +1 -1
  392. package/dist/features/pre-orders/api/route.js +1 -1
  393. package/dist/features/pre-orders/repository/pre-orders.repository.d.ts +3 -3
  394. package/dist/features/pre-orders/repository/pre-orders.repository.js +6 -6
  395. package/dist/features/products/api/[id]/route.js +1 -1
  396. package/dist/features/products/components/ListingBottomActions.js +4 -0
  397. package/dist/features/products/components/ProductDetailPageView.js +2 -1
  398. package/dist/features/products/components/ProductGalleryClient.js +2 -2
  399. package/dist/features/products/components/ProductGrid.js +12 -1
  400. package/dist/features/products/components/index.d.ts +0 -2
  401. package/dist/features/products/components/index.js +0 -1
  402. package/dist/features/products/config/listing-type-listing-config.d.ts +0 -3
  403. package/dist/features/products/config/listing-type-listing-config.js +27 -2
  404. package/dist/features/products/constants/listing-tabs.d.ts +9 -0
  405. package/dist/features/products/constants/listing-tabs.js +3 -2
  406. package/dist/features/products/hooks/useProducts.js +2 -2
  407. package/dist/features/products/repository/products.repository.js +13 -1
  408. package/dist/features/products/schemas/index.d.ts +2 -2
  409. package/dist/features/products/types/index.d.ts +1 -1
  410. package/dist/features/promotions/api/route.js +1 -1
  411. package/dist/features/reviews/actions/review-actions.d.ts +6 -6
  412. package/dist/features/reviews/actions/review-actions.js +22 -8
  413. package/dist/features/reviews/components/ReviewDetailPageView.js +13 -1
  414. package/dist/features/reviews/components/ReviewsIndexPageView.js +21 -4
  415. package/dist/features/reviews/repository/reviews.repository.d.ts +19 -7
  416. package/dist/features/reviews/repository/reviews.repository.js +63 -12
  417. package/dist/features/reviews/schemas/firestore.d.ts +13 -2
  418. package/dist/features/reviews/schemas/index.d.ts +2 -2
  419. package/dist/features/scams/actions/scam-actions.js +16 -4
  420. package/dist/features/search/components/SearchResultsPageView.js +2 -1
  421. package/dist/features/search/hooks/useSearchIndex.d.ts +34 -0
  422. package/dist/features/search/hooks/useSearchIndex.js +172 -0
  423. package/dist/features/search/repository/search.repository.js +2 -2
  424. package/dist/features/seller/actions/offer-actions.d.ts +5 -5
  425. package/dist/features/seller/actions/offer-actions.js +38 -8
  426. package/dist/features/seller/actions/seller-actions.js +34 -7
  427. package/dist/features/seller/api/coupons/route.js +1 -1
  428. package/dist/features/seller/api/products/route.js +1 -1
  429. package/dist/features/seller/api/store/route.js +1 -1
  430. package/dist/features/seller/components/SellerBidsView.js +1 -1
  431. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  432. package/dist/features/seller/components/SellerListingTypeView.js +9 -1
  433. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  434. package/dist/features/seller/components/SellerPayoutSettingsView.js +0 -1
  435. package/dist/features/seller/components/SellerPayoutsView.js +1 -1
  436. package/dist/features/seller/components/SellerProductShell.js +0 -1
  437. package/dist/features/seller/components/SellerProductsView.js +1 -1
  438. package/dist/features/seller/components/SellerShippingView.js +0 -1
  439. package/dist/features/seller/components/SellerStorefrontView.js +0 -1
  440. package/dist/features/seller/components/index.d.ts +0 -4
  441. package/dist/features/seller/components/index.js +0 -2
  442. package/dist/features/seller/repository/offer.repository.d.ts +15 -3
  443. package/dist/features/seller/repository/offer.repository.js +43 -7
  444. package/dist/features/seller/schemas/firestore.d.ts +14 -3
  445. package/dist/features/seller/schemas/index.d.ts +4 -4
  446. package/dist/features/seller/schemas/order-forms.d.ts +39 -0
  447. package/dist/features/seller/schemas/order-forms.js +37 -0
  448. package/dist/features/shell/FormShell.js +6 -2
  449. package/dist/features/shell/QuickFormDrawer.js +15 -1
  450. package/dist/features/shipments/components/AdminShipmentEditorView.js +0 -1
  451. package/dist/features/shipments/components/AdminShipmentsView.js +1 -1
  452. package/dist/features/sticker-trace/components/StickerCommitPanel.d.ts +30 -0
  453. package/dist/features/sticker-trace/components/StickerCommitPanel.js +93 -0
  454. package/dist/features/sticker-trace/components/StickerPrintPanel.d.ts +33 -0
  455. package/dist/features/sticker-trace/components/StickerPrintPanel.js +104 -0
  456. package/dist/features/sticker-trace/components/StickerRetryPanel.d.ts +20 -0
  457. package/dist/features/sticker-trace/components/StickerRetryPanel.js +128 -0
  458. package/dist/features/sticker-trace/components/StickerRunHistoryPanel.d.ts +45 -0
  459. package/dist/features/sticker-trace/components/StickerRunHistoryPanel.js +84 -0
  460. package/dist/features/sticker-trace/components/StickerTraceStudio.d.ts +27 -0
  461. package/dist/features/sticker-trace/components/StickerTraceStudio.js +171 -0
  462. package/dist/features/sticker-trace/constants/help-content.d.ts +23 -0
  463. package/dist/features/sticker-trace/constants/help-content.js +172 -0
  464. package/dist/features/sticker-trace/hooks/useLiveTrace.d.ts +27 -0
  465. package/dist/features/sticker-trace/hooks/useLiveTrace.js +160 -0
  466. package/dist/features/sticker-trace/hooks/useStickerTraceProgress.d.ts +22 -0
  467. package/dist/features/sticker-trace/hooks/useStickerTraceProgress.js +106 -0
  468. package/dist/features/sticker-trace/repository/sticker-sheets.repository.d.ts +113 -0
  469. package/dist/features/sticker-trace/repository/sticker-sheets.repository.js +146 -0
  470. package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.d.ts +132 -0
  471. package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.js +174 -0
  472. package/dist/features/sticker-trace/schemas/firestore.d.ts +248 -0
  473. package/dist/features/sticker-trace/schemas/firestore.js +79 -0
  474. package/dist/features/sticker-trace/server.d.ts +8 -0
  475. package/dist/features/sticker-trace/server.js +51 -0
  476. package/dist/features/stores/actions/store-query-actions.d.ts +2 -2
  477. package/dist/features/stores/actions/store-query-actions.js +7 -2
  478. package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -3
  479. package/dist/features/stores/api/[storeSlug]/products/route.js +3 -3
  480. package/dist/features/stores/api/[storeSlug]/reviews/route.js +1 -1
  481. package/dist/features/stores/api/[storeSlug]/route.js +1 -1
  482. package/dist/features/stores/components/StoreNavTabs.js +17 -2
  483. package/dist/features/stores/manifest.js +8 -4
  484. package/dist/features/support/repository/support.repository.d.ts +14 -3
  485. package/dist/features/support/repository/support.repository.js +93 -13
  486. package/dist/features/support/schemas/firestore.d.ts +16 -5
  487. package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +61 -19
  488. package/dist/features/tester/seed-data/authored/buying__browsing-search.js +19 -3
  489. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
  490. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +243 -0
  491. package/dist/features/tester/seed-data/authored/content-discovery__events.js +36 -10
  492. package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.d.ts +2 -0
  493. package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.js +209 -0
  494. package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.d.ts +2 -0
  495. package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.js +90 -0
  496. package/dist/features/tester/seed-data/authored/index.js +8 -0
  497. package/dist/features/tester/seed-data/authored/selling__media-limits.js +19 -17
  498. package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +10 -5
  499. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.d.ts +2 -0
  500. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +283 -0
  501. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +192 -22
  502. package/dist/index.d.ts +10 -23
  503. package/dist/index.js +27 -19
  504. package/dist/next/api/routeHandler.js +9 -0
  505. package/dist/next/routing/require-record.d.ts +13 -0
  506. package/dist/next/routing/require-record.js +62 -0
  507. package/dist/next/routing/route-map.d.ts +4 -4
  508. package/dist/next/routing/route-map.js +25 -3
  509. package/dist/providers/db-firebase/base.d.ts +4 -2
  510. package/dist/providers/db-firebase/base.js +21 -5
  511. package/dist/providers/db-firebase/base.repository.d.ts +11 -9
  512. package/dist/providers/db-firebase/base.repository.js +19 -0
  513. package/dist/providers/db-firebase/rtdb-paths.d.ts +12 -0
  514. package/dist/providers/db-firebase/rtdb-paths.js +12 -0
  515. package/dist/react/ErrorBoundary.js +6 -1
  516. package/dist/react/hooks/realtime-event-constants.d.ts +1 -0
  517. package/dist/react/hooks/realtime-event-constants.js +8 -0
  518. package/dist/react/hooks/useEntityDelete.js +5 -1
  519. package/dist/react/hooks/useMessage.js +5 -1
  520. package/dist/repositories/index.d.ts +2 -2
  521. package/dist/repositories/index.js +6 -1
  522. package/dist/schemas/registry.d.ts +13 -20
  523. package/dist/schemas/registry.js +31 -14
  524. package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
  525. package/dist/security/encrypted.d.ts +117 -0
  526. package/dist/security/encrypted.js +100 -0
  527. package/dist/security/index.d.ts +5 -2
  528. package/dist/security/index.js +16 -2
  529. package/dist/security/pii-accessors.d.ts +71 -0
  530. package/dist/security/pii-accessors.js +150 -0
  531. package/dist/security/pii-encrypt.d.ts +0 -8
  532. package/dist/security/pii-encrypt.js +22 -15
  533. package/dist/security/pii-mask.d.ts +18 -0
  534. package/dist/security/pii-mask.js +27 -0
  535. package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -6
  536. package/dist/seed/_helpers/search-txt-wrappers.js +22 -0
  537. package/dist/seed/addresses-seed-data.d.ts +2 -2
  538. package/dist/seed/authenticity-knowledge-seed-data.d.ts +34 -0
  539. package/dist/seed/authenticity-knowledge-seed-data.js +1277 -0
  540. package/dist/seed/bids-seed-data.d.ts +2 -2
  541. package/dist/seed/bids-seed-data.js +23 -2
  542. package/dist/seed/events-seed-data.d.ts +2 -2
  543. package/dist/seed/events-seed-data.js +5 -0
  544. package/dist/seed/faq-seed-data.js +175 -5
  545. package/dist/seed/homepage-sections-seed-data.js +39 -23
  546. package/dist/seed/index.d.ts +1 -0
  547. package/dist/seed/index.js +1 -0
  548. package/dist/seed/lottery-entries-seed-data.d.ts +2 -2
  549. package/dist/seed/offers-seed-data.d.ts +2 -2
  550. package/dist/seed/offers-seed-data.js +1 -1
  551. package/dist/seed/orders-seed-data.d.ts +2 -2
  552. package/dist/seed/payouts-seed-data.d.ts +2 -2
  553. package/dist/seed/payouts-seed-data.js +1 -1
  554. package/dist/seed/reviews-seed-data.d.ts +1 -2
  555. package/dist/seed/seed-purpose.js +7 -0
  556. package/dist/seed/sessions-seed-data.d.ts +2 -2
  557. package/dist/seed/sessions-seed-data.js +5 -0
  558. package/dist/seed/site-settings-seed-data.js +1 -1
  559. package/dist/seed/support-tickets-seed-data.d.ts +2 -2
  560. package/dist/seed/support-tickets-seed-data.js +1 -1
  561. package/dist/seed/users-seed-data.d.ts +2 -2
  562. package/dist/seed/users-seed-data.js +1 -1
  563. package/dist/seo/json-ld.js +5 -1
  564. package/dist/server.d.ts +18 -3
  565. package/dist/server.js +59 -3
  566. package/dist/styles.css +237 -1
  567. package/dist/tailwind-utilities.css +1 -1
  568. package/dist/ui/components/Button.js +7 -1
  569. package/dist/ui/components/FilterChipGroup.d.ts +11 -0
  570. package/dist/ui/components/FilterChipGroup.js +1 -1
  571. package/dist/ui/components/ImageGallery.js +6 -1
  572. package/dist/ui/components/ListingLayout.js +14 -8
  573. package/dist/ui/components/OverflowRow.d.ts +92 -0
  574. package/dist/ui/components/OverflowRow.js +203 -0
  575. package/dist/ui/components/OverflowRow.style.css +235 -0
  576. package/dist/ui/components/RecordDetailModal.js +14 -1
  577. package/dist/ui/components/RowActionMenu.js +5 -1
  578. package/dist/ui/components/SideDrawer.js +5 -1
  579. package/dist/ui/components/SideModal.js +9 -1
  580. package/dist/ui/components/TabBarShell.d.ts +12 -1
  581. package/dist/ui/components/TabBarShell.js +3 -2
  582. package/dist/ui/components/Tabs.js +36 -24
  583. package/dist/ui/components/Toast.d.ts +3 -24
  584. package/dist/ui/components/Toast.js +2 -19
  585. package/dist/ui/components/TopBannerPortal.d.ts +15 -0
  586. package/dist/ui/components/TopBannerPortal.js +19 -0
  587. package/dist/ui/components/UnsavedChangesModal.js +5 -1
  588. package/dist/ui/components/index.style.css +1 -0
  589. package/dist/ui/components/row-collapse.d.ts +15 -0
  590. package/dist/ui/components/row-collapse.js +127 -0
  591. package/dist/ui/components/toast-context.d.ts +63 -0
  592. package/dist/ui/components/toast-context.js +48 -0
  593. package/dist/ui/components/top-banner-slot.d.ts +37 -0
  594. package/dist/ui/components/top-banner-slot.js +45 -0
  595. package/dist/ui/icons/icon-registry.d.ts +6 -0
  596. package/dist/ui/icons/icon-registry.js +17 -1
  597. package/dist/ui/index.d.ts +2 -0
  598. package/dist/ui/index.js +1 -0
  599. package/dist/utils/array.helper.d.ts +2 -2
  600. package/dist/utils/array.helper.js +5 -5
  601. package/dist/utils/id-generators.d.ts +6 -0
  602. package/dist/utils/id-generators.js +10 -0
  603. package/dist/utils/media-url.js +0 -2
  604. package/dist/utils/search-txt-builders.d.ts +28 -4
  605. package/dist/utils/search-txt-builders.js +41 -1
  606. package/dist/validation/schemas.d.ts +8 -8
  607. package/package.json +6 -2
  608. package/scripts/seed-cli.mjs +3 -0
  609. package/dist/features/account/components/UserAddressesView.d.ts +0 -13
  610. package/dist/features/account/components/UserAddressesView.js +0 -5
  611. package/dist/features/account/components/UserNotificationsView.d.ts +0 -15
  612. package/dist/features/account/components/UserNotificationsView.js +0 -12
  613. package/dist/features/account/components/UserSettingsView.d.ts +0 -16
  614. package/dist/features/account/components/UserSettingsView.js +0 -13
  615. package/dist/features/account/components/UserSupportView.d.ts +0 -3
  616. package/dist/features/account/components/UserSupportView.js +0 -166
  617. package/dist/features/admin/components/DemoSeedView.d.ts +0 -11
  618. package/dist/features/admin/components/DemoSeedView.js +0 -5
  619. package/dist/features/auth/components/AuthStatusPanel.d.ts +0 -10
  620. package/dist/features/auth/components/AuthStatusPanel.js +0 -22
  621. package/dist/features/categories/components/CategoryProductsView.d.ts +0 -45
  622. package/dist/features/categories/components/CategoryProductsView.js +0 -21
  623. package/dist/features/homepage/components/HowItWorksInfoView.d.ts +0 -36
  624. package/dist/features/homepage/components/HowItWorksInfoView.js +0 -10
  625. package/dist/features/layout/BottomActions.d.ts +0 -1
  626. package/dist/features/layout/BottomActions.js +0 -311
  627. package/dist/features/products/components/ProductsView.d.ts +0 -6
  628. package/dist/features/products/components/ProductsView.js +0 -5
  629. package/dist/features/seller/components/SellerStoreView.d.ts +0 -8
  630. package/dist/features/seller/components/SellerStoreView.js +0 -8
@@ -0,0 +1,219 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * SideActionDock — the floating action dock that replaced the bottom bar.
5
+ *
6
+ * Reads the SAME `BottomActionsContext` the bar read, so all ~30 publishers
7
+ * (`useBottomActions`, `useFormBottomActions`, every `DataListingView` bulk
8
+ * bar) are untouched: only the presentation changed.
9
+ *
10
+ * ── Why a side dock and not a bar ──────────────────────────────────────────
11
+ *
12
+ * A full-width bar welded to an edge covers content the whole time it is up —
13
+ * the last row of a listing on mobile, and on desktop it either reads as a
14
+ * browser download bar at the bottom or steals the header's space at the top.
15
+ * A dock is a 56px button at rest and a panel only while it is being used.
16
+ *
17
+ * ── Three rules this encodes ───────────────────────────────────────────────
18
+ *
19
+ * 1. **It docks OPPOSITE the sidebar.** `SidebarLayout` docks to the hand-mode
20
+ * side (`hand === "left" ? left-0 : right-0`), so the dock takes the other
21
+ * edge and the two can never overlap — including while the sidebar is open,
22
+ * which is exactly when a CTA hidden underneath it would be unreachable.
23
+ *
24
+ * 2. **It reveals only after the inline CTA has been seen and passed** — see
25
+ * `useCtaReveal`. A page with no CTA anchor shows it at once, which is what
26
+ * every bulk-action screen needs.
27
+ *
28
+ * 3. **Bulk mode ignores the reveal gate.** A selection is a state the user
29
+ * just entered deliberately; making them scroll to act on it would be a
30
+ * puzzle, not an affordance.
31
+ *
32
+ * 🛑 It is NOT part of the `BottomChrome` tier any more and must not be put
33
+ * back into it. The tier exists so bars can stack without overlapping and
34
+ * publish one height; a dock that floats beside the content reserves no height
35
+ * and belongs to no tier. Rendering it inside `BottomChrome` would re-add its
36
+ * height to `--bottom-chrome-height` and push the footer down by a phantom bar.
37
+ */
38
+ import { useEffect, useId, useRef, useState } from "react";
39
+ import { ChevronDown, ChevronUp, Check, X } from "lucide-react";
40
+ import { useBottomActionsContext } from "./BottomActionsContext.js";
41
+ import { useClickOutside } from "../../react/index.js";
42
+ import { useHandMode } from "../../_internal/client/hand-mode/index.js";
43
+ import { useCtaReveal } from "./useCtaReveal.js";
44
+ import { ActionRow, Div, IconButton, Row, Span, Stack, Text, Button } from "../../ui/index.js";
45
+ const PANEL_SURFACE = "bg-[color-mix(in_srgb,var(--appkit-color-bg)_94%,transparent)] backdrop-blur-md border border-[var(--appkit-color-border)]";
46
+ const FLEX_CENTER = "flex items-center justify-center";
47
+ const CLS_COUNT_BADGE = "bg-error-solid text-error-on-solid";
48
+ /**
49
+ * How many actions fit on one line before the row splits in two.
50
+ *
51
+ * 🛑 ROW COUNT is a function of `pageActions.length` and NOTHING else — never
52
+ * of validation state, and never of measured width. In this app LABELS ARE
53
+ * STATE ("Add to Cart" → "Adding…", "Buy Now" → "Out of Stock"), so a layout
54
+ * that re-flowed on width would shift the controls under the user's thumb at
55
+ * the exact moment they committed to a tap.
56
+ */
57
+ const SINGLE_ROW_MAX_ACTIONS = 2;
58
+ function ActionButtons({ actions, dispatchAction, }) {
59
+ return (_jsx(_Fragment, { children: actions.map((action) => {
60
+ const isIconOnly = !action.label;
61
+ /*
62
+ * Width is ActionRow's job, not this component's — every action is
63
+ * sized from its own label by `.appkit-action-row__group > *`.
64
+ *
65
+ * 🛑 Never add `flex-1`, `flex-shrink-0`, `basis-*`, `w-*`, `h-*`,
66
+ * `truncate` or `leading-none` below. Both tailwind configs set
67
+ * `important: true`, so any of them beats ActionRow's CSS and silently
68
+ * reverts this to the squeezed behaviour with no visible error — a
69
+ * 44px stub reading "Ba" beside a full-width "Continue to payment".
70
+ */
71
+ return (_jsxs(Button, { type: "button", variant: action.variant ?? "primary", size: "sm", isLoading: action.loading, disabled: action.disabled, onClick: () => dispatchAction(action.id), className: [
72
+ "relative",
73
+ isIconOnly ? "appkit-action-row__icon-only justify-center" : "",
74
+ ]
75
+ .filter(Boolean)
76
+ .join(" "), children: [action.icon && (_jsx(Span, { className: ["flex-shrink-0", action.label ? "mr-1.5" : ""].join(" "), "aria-hidden": "true", children: action.icon })), action.label && _jsx(Span, { children: action.label }), action.badge !== undefined && (_jsx(Span, { className: `absolute -top-1.5 -right-1.5 min-w-[18px] h-[18px] ${CLS_COUNT_BADGE} text-[10px] ${FLEX_CENTER} px-[var(--appkit-space-1)] pointer-events-none select-none`, rounded: "full", weight: "bold", "aria-hidden": "true", children: action.badge }))] }, action.id));
77
+ }) }));
78
+ }
79
+ /**
80
+ * Lays a page's actions out across one or two lines. The LAST action is the
81
+ * primary — `useFormBottomActions` appends submit last and the checkout bars
82
+ * build `[back, primary]`, so this holds for every producer.
83
+ */
84
+ function PageActionsRow({ pageActions, dispatchAction, }) {
85
+ if (pageActions.length === 0)
86
+ return null;
87
+ if (pageActions.length <= SINGLE_ROW_MAX_ACTIONS) {
88
+ return (_jsx(ActionRow, { children: _jsx(ActionButtons, { actions: pageActions, dispatchAction: dispatchAction }) }));
89
+ }
90
+ const secondaries = pageActions.slice(0, -1);
91
+ const primary = pageActions[pageActions.length - 1];
92
+ return (_jsxs(Div, { className: "flex w-full flex-col gap-[var(--appkit-space-2)]", children: [_jsx(ActionRow, { children: _jsx(ActionButtons, { actions: secondaries, dispatchAction: dispatchAction }) }), _jsx(ActionRow, { children: _jsx(ActionButtons, { actions: [primary], dispatchAction: dispatchAction }) })] }));
93
+ }
94
+ /** The bulk-mode action list — one tap picks AND runs. */
95
+ function BulkActionList({ bulkActions, selectedActionId, onSelect, }) {
96
+ return (_jsx(Div, { role: "listbox", "aria-label": "Bulk actions", className: "w-full", children: bulkActions.map((action, i) => {
97
+ const isSelected = action.id === selectedActionId;
98
+ return (_jsxs(Button, { role: "option", "aria-selected": isSelected, type: "button", variant: "ghost", disabled: action.disabled || action.loading, onClick: () => onSelect(action.id), className: [
99
+ "w-full flex items-center gap-[var(--appkit-space-3)] px-[var(--appkit-space-3)] py-[var(--appkit-space-2-5)] text-left text-[length:var(--appkit-text-sm)] font-medium transition-colors rounded-md",
100
+ i > 0 ? "border-t border-[var(--appkit-color-border-subtle)]" : "",
101
+ isSelected ? "bg-[var(--appkit-color-surface-input)]" : "",
102
+ action.variant === "danger"
103
+ ? "text-error hover:bg-error-surface"
104
+ : "text-[var(--appkit-color-text)] hover:bg-surface-hover",
105
+ action.disabled || action.loading ? "opacity-50 cursor-not-allowed" : "",
106
+ ]
107
+ .filter(Boolean)
108
+ .join(" "), children: [action.icon && (_jsx(Span, { className: `flex-shrink-0 w-5 h-5 ${FLEX_CENTER}`, "aria-hidden": "true", children: action.icon })), _jsx(Span, { className: "flex-1 truncate", children: action.label }), isSelected && (_jsx(Check, { className: "w-4 h-4 flex-shrink-0 text-primary-600 dark:text-primary-400", "aria-hidden": "true" }))] }, action.id));
109
+ }) }));
110
+ }
111
+ export default function SideActionDock() {
112
+ const { state, actionCallbacksRef, bulkCallbacksRef, bulkClearRef } = useBottomActionsContext();
113
+ const { hand } = useHandMode();
114
+ const [expanded, setExpanded] = useState(false);
115
+ const [infoOpen, setInfoOpen] = useState(false);
116
+ const [selectedActionId, setSelectedActionId] = useState(null);
117
+ const containerRef = useRef(null);
118
+ const infoPanelId = useId();
119
+ useClickOutside(containerRef, () => {
120
+ setExpanded(false);
121
+ setInfoOpen(false);
122
+ });
123
+ const { actions, bulk, infoLabel, secondaryLabel, infoPanel, infoOpenSignal, ctaAnchorId } = state;
124
+ const isBulkMode = !!(bulk && bulk.selectedCount > 0);
125
+ const hasInfoPanel = infoPanel != null && !isBulkMode;
126
+ const bulkActions = bulk?.actions ?? [];
127
+ const pageActions = actions;
128
+ const hasContent = (isBulkMode ? bulkActions.length > 0 || !!bulk : pageActions.length > 0) ||
129
+ !!infoLabel ||
130
+ !!secondaryLabel;
131
+ // Rule 3 — a selection is its own reveal.
132
+ const revealed = useCtaReveal(hasContent && !isBulkMode, ctaAnchorId) || isBulkMode;
133
+ const isVisible = hasContent && revealed;
134
+ // Rule 1 — opposite the sidebar, which docks to the hand-mode side.
135
+ const dockSideClass = hand === "left" ? "right-0" : "left-0";
136
+ const panelAlignClass = hand === "left" ? "items-end" : "items-start";
137
+ // Collapse when the dock goes away, or the next page inherits an open panel.
138
+ useEffect(() => {
139
+ if (!isVisible) {
140
+ setExpanded(false);
141
+ setInfoOpen(false);
142
+ }
143
+ }, [isVisible]);
144
+ useEffect(() => {
145
+ if (!hasInfoPanel)
146
+ setInfoOpen(false);
147
+ }, [hasInfoPanel]);
148
+ /*
149
+ * Force-open on a bumped signal — a failed form submit, today. Depends on
150
+ * the counter alone, so a re-render with the same value never re-opens what
151
+ * the user has since collapsed. The dock must EXPAND as well: a failed save
152
+ * whose error sheet opens inside a collapsed dock is a message nobody sees.
153
+ */
154
+ const lastSignalRef = useRef(undefined);
155
+ useEffect(() => {
156
+ if (infoOpenSignal == null)
157
+ return;
158
+ if (lastSignalRef.current === infoOpenSignal)
159
+ return;
160
+ lastSignalRef.current = infoOpenSignal;
161
+ setExpanded(true);
162
+ setInfoOpen(true);
163
+ }, [infoOpenSignal]);
164
+ useEffect(() => {
165
+ if (!isBulkMode) {
166
+ setSelectedActionId(null);
167
+ return;
168
+ }
169
+ setSelectedActionId((prev) => {
170
+ const ids = bulkActions.map((a) => a.id);
171
+ if (prev && ids.includes(prev))
172
+ return prev;
173
+ return ids[0] ?? null;
174
+ });
175
+ // eslint-disable-next-line react-hooks/exhaustive-deps
176
+ }, [isBulkMode, bulkActions.map((a) => a.id).join(",")]);
177
+ const selectedAction = bulkActions.find((a) => a.id === selectedActionId);
178
+ const dispatchAction = (id) => {
179
+ actionCallbacksRef.current.get(id)?.();
180
+ setExpanded(false);
181
+ };
182
+ const dispatchBulkClear = () => {
183
+ bulkClearRef.current?.();
184
+ setExpanded(false);
185
+ };
186
+ const handleApply = () => {
187
+ if (!selectedActionId)
188
+ return;
189
+ bulkCallbacksRef.current.get(selectedActionId)?.();
190
+ setExpanded(false);
191
+ };
192
+ if (!isVisible)
193
+ return null;
194
+ /*
195
+ * The resting affordance. In bulk mode it counts the selection, which is the
196
+ * one number a user in that state is tracking; otherwise it carries the
197
+ * PRIMARY action's icon, so the dock looks like what it does rather than like
198
+ * a generic "more" button.
199
+ */
200
+ const primaryAction = pageActions[pageActions.length - 1];
201
+ const fabBadge = isBulkMode ? bulk?.selectedCount : undefined;
202
+ const fabLabel = isBulkMode
203
+ ? `${bulk?.selectedCount ?? 0} selected — bulk actions`
204
+ : (primaryAction?.label ?? infoLabel ?? "Page actions");
205
+ return (_jsxs(Div, { ref: containerRef, role: "toolbar", "aria-label": isBulkMode ? "Bulk actions" : "Page actions", className: [
206
+ "fixed z-[var(--appkit-z-overlay)] pointer-events-auto flex flex-col",
207
+ panelAlignClass,
208
+ dockSideClass,
209
+ // Clears the whole bottom tier, so it never lands on the mobile tab bar
210
+ // or on a pagination bar — the same sum every other floating control
211
+ // reads (see CSS Variable Reference → "The bottom edge is three tiers").
212
+ "bottom-[calc(var(--keyboard-inset-height,0px)+var(--bottom-nav-height,4rem)+var(--bottom-chrome-height,0px)+var(--appkit-space-4))]",
213
+ "px-[var(--appkit-space-3)] gap-[var(--appkit-space-2)]",
214
+ ].join(" "), "data-section": "side-action-dock", children: [expanded && (_jsx(Div, { surface: "elevated", rounded: "xl", shadow: "lg", padding: "sm", className: `${PANEL_SURFACE} w-[min(20rem,calc(100vw-2rem))] max-h-[70vh] overflow-y-auto`, children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { align: "center", justify: "between", gap: "sm", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", className: "truncate", children: isBulkMode
215
+ ? bulk?.noun
216
+ ? `${bulk.selectedCount} ${bulk.noun}`
217
+ : `${bulk?.selectedCount ?? 0} selected`
218
+ : (secondaryLabel ?? infoLabel ?? "Actions") }), _jsx(IconButton, { size: "sm", variant: "ghost", "aria-label": "Close actions", onClick: () => setExpanded(false), icon: _jsx(X, { className: "w-4 h-4", "aria-hidden": "true" }) })] }), !isBulkMode && secondaryLabel && infoLabel && (_jsx(Text, { size: "xs", color: "muted", className: "leading-5", children: infoLabel })), hasInfoPanel && (_jsxs(_Fragment, { children: [_jsxs(Button, { type: "button", variant: "ghost", onClick: () => setInfoOpen((o) => !o), "aria-expanded": infoOpen, "aria-controls": infoPanelId, className: "w-full flex items-center justify-between gap-[var(--appkit-space-2)] rounded-md px-[var(--appkit-space-2)] py-[var(--appkit-space-1)] min-h-0", children: [_jsx(Text, { as: "span", size: "xs", color: "muted", children: infoOpen ? "Hide details" : "Details" }), infoOpen ? (_jsx(ChevronDown, { className: "w-4 h-4 text-zinc-400", "aria-hidden": "true" })) : (_jsx(ChevronUp, { className: "w-4 h-4 text-zinc-400", "aria-hidden": "true" }))] }), infoOpen && (_jsx(Div, { id: infoPanelId, className: "max-h-[40vh]", overflow: "y-auto", children: infoPanel }))] })), isBulkMode && bulk ? (_jsxs(Stack, { gap: "sm", children: [_jsx(BulkActionList, { bulkActions: bulkActions, selectedActionId: selectedActionId, onSelect: setSelectedActionId }), _jsxs(ActionRow, { children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: dispatchBulkClear, children: [_jsx(X, { className: "w-3.5 h-3.5 mr-1.5 flex-shrink-0", "aria-hidden": "true" }), _jsx(Span, { children: "Clear" })] }), _jsx(Button, { type: "button", variant: selectedAction?.variant ?? "primary", size: "sm", isLoading: selectedAction?.loading, disabled: !selectedActionId || selectedAction?.disabled || selectedAction?.loading, onClick: handleApply, children: _jsx(Span, { children: "Apply" }) })] })] })) : (_jsx(PageActionsRow, { pageActions: pageActions, dispatchAction: dispatchAction }))] }) })), _jsxs(Button, { type: "button", variant: isBulkMode ? "primary" : (primaryAction?.variant ?? "primary"), rounded: "full", "aria-expanded": expanded, "aria-label": fabLabel, onClick: () => setExpanded((o) => !o), className: "relative shadow-lg h-14 min-h-0 px-[var(--appkit-space-5)]", children: [primaryAction?.icon && !isBulkMode && (_jsx(Span, { className: "flex-shrink-0 mr-1.5", "aria-hidden": "true", children: primaryAction.icon })), _jsx(Span, { className: "truncate max-w-[9rem]", children: isBulkMode ? "Bulk actions" : (primaryAction?.label ?? "Actions") }), fabBadge !== undefined && fabBadge > 0 && (_jsx(Span, { className: `absolute -top-1.5 -right-1.5 min-w-[20px] h-[20px] ${CLS_COUNT_BADGE} text-[10px] ${FLEX_CENTER} px-[var(--appkit-space-1)] pointer-events-none select-none`, rounded: "full", weight: "bold", "aria-hidden": "true", children: fabBadge }))] })] }));
219
+ }
@@ -64,7 +64,7 @@ export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, s
64
64
  _jsxs(Row, { gap: "xs", reverse: "hand", 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-surface", 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;
65
65
  const hasTb2 = !!(notificationsEl || messagesEl || wishlistEl || cartEl || profileEl);
66
66
  // ── Render ───────────────────────────────────────────────────────────────────
67
- 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", reverse: "hand", 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", reverse: "hand", children: [devSlot, navSlot, compareEl, notificationSlot, notificationsEl && _jsx(Div, { className: "hidden lg:flex", children: notificationsEl }), messagesEl && _jsx(Div, { className: "hidden lg:flex", children: messagesEl }), wishlistEl && _jsx(Div, { className: "hidden lg:flex", children: wishlistEl }), cartEl && _jsx(Div, { className: "hidden lg:flex", children: cartEl }), user
67
+ 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, { gap: "none", reverse: "hand", className: "relative h-14", children: [_jsx(Row, { gap: "3", reverse: "hand", className: "flex-1", 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 flex-none", 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", reverse: "hand", justify: "end", className: "flex-1", children: [devSlot, navSlot, compareEl, notificationSlot, notificationsEl && _jsx(Div, { className: "hidden lg:flex", children: notificationsEl }), messagesEl && _jsx(Div, { className: "hidden lg:flex", children: messagesEl }), wishlistEl && _jsx(Div, { className: "hidden lg:flex", children: wishlistEl }), cartEl && _jsx(Div, { className: "hidden lg:flex", children: cartEl }), user
68
68
  ? profileEl && _jsx(Div, { className: "hidden lg:flex", children: profileEl })
69
69
  : authButtonsEl ?? (profileEl && _jsx(Div, { className: "hidden lg:flex", children: profileEl })), searchBtn, _jsx(Div, { className: "hidden sm:flex", children: promotionsEl }), themeBtn, hamburgerBtn] })] }), hasTb2 && (
70
70
  // `justify="end"` is CORRECT alongside `reverse="hand"` — do not
@@ -0,0 +1,31 @@
1
+ /**
2
+ * CTA anchor — the inline Buy button a floating action dock hides behind.
3
+ *
4
+ * A page marks its own primary CTA with `ctaAnchorProps()`; `SideActionDock`
5
+ * finds it by attribute and reveals itself only once that element has been
6
+ * SEEN and then scrolled out of view.
7
+ *
8
+ * 🛑 An ATTRIBUTE, not a ref passed through the context, on purpose. The dock
9
+ * is mounted once by `AppLayoutShell`, several levels above every page that
10
+ * registers actions, and ~30 call sites publish into that context — threading a
11
+ * ref through all of them to reach a gate that only a handful of detail pages
12
+ * need would make the common case pay for the rare one. An attribute lets a
13
+ * page opt in with one prop spread and lets every other page say nothing.
14
+ *
15
+ * A page with NO anchor reveals the dock immediately. That is the honest
16
+ * default: an admin bulk bar has no Buy button to scroll past, and a dock that
17
+ * waited for an element that will never exist would never appear at all.
18
+ */
19
+ export declare const CTA_ANCHOR_ATTR = "data-cta-anchor";
20
+ /**
21
+ * Spread onto the element wrapping a page's inline primary CTA.
22
+ *
23
+ * @example
24
+ * <Stack gap="sm" {...ctaAnchorProps()}>
25
+ * <Button>Buy Now</Button>
26
+ * <Button>Add to Cart</Button>
27
+ * </Stack>
28
+ */
29
+ export declare function ctaAnchorProps(): {
30
+ [CTA_ANCHOR_ATTR]: "true";
31
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * CTA anchor — the inline Buy button a floating action dock hides behind.
3
+ *
4
+ * A page marks its own primary CTA with `ctaAnchorProps()`; `SideActionDock`
5
+ * finds it by attribute and reveals itself only once that element has been
6
+ * SEEN and then scrolled out of view.
7
+ *
8
+ * 🛑 An ATTRIBUTE, not a ref passed through the context, on purpose. The dock
9
+ * is mounted once by `AppLayoutShell`, several levels above every page that
10
+ * registers actions, and ~30 call sites publish into that context — threading a
11
+ * ref through all of them to reach a gate that only a handful of detail pages
12
+ * need would make the common case pay for the rare one. An attribute lets a
13
+ * page opt in with one prop spread and lets every other page say nothing.
14
+ *
15
+ * A page with NO anchor reveals the dock immediately. That is the honest
16
+ * default: an admin bulk bar has no Buy button to scroll past, and a dock that
17
+ * waited for an element that will never exist would never appear at all.
18
+ */
19
+ export const CTA_ANCHOR_ATTR = "data-cta-anchor";
20
+ /**
21
+ * Spread onto the element wrapping a page's inline primary CTA.
22
+ *
23
+ * @example
24
+ * <Stack gap="sm" {...ctaAnchorProps()}>
25
+ * <Button>Buy Now</Button>
26
+ * <Button>Add to Cart</Button>
27
+ * </Stack>
28
+ */
29
+ export function ctaAnchorProps() {
30
+ return { [CTA_ANCHOR_ATTR]: "true" };
31
+ }
@@ -18,6 +18,13 @@ export interface UseBottomActionsOptions {
18
18
  * so pages that don't opt in behave exactly as before.
19
19
  */
20
20
  desktop?: BottomActionsDesktopMode;
21
+ /**
22
+ * `id` of this page's inline primary CTA. The floating action dock stays
23
+ * hidden until that element has been seen and scrolled out of view. Omit it
24
+ * and the dock appears as soon as there is something to show — which is what
25
+ * every bulk-selection screen wants.
26
+ */
27
+ ctaAnchorId?: string;
21
28
  /**
22
29
  * Set false to opt out entirely — no claim is taken, so this consumer is
23
30
  * invisible to the stack and cannot displace whoever currently owns the
@@ -2,7 +2,7 @@
2
2
  import { useEffect, useId, useRef } from "react";
3
3
  import { useBottomActionsContext, } from "../BottomActionsContext.js";
4
4
  export function useBottomActions(options = {}) {
5
- const { setActions, setBulkConfig, setInfoLabel, setSecondaryLabel, setInfoPanel, setInfoOpenSignal, setDesktopMode, claim, release, topClaimId, } = useBottomActionsContext();
5
+ const { setActions, setBulkConfig, setInfoLabel, setSecondaryLabel, setInfoPanel, setInfoOpenSignal, setDesktopMode, setCtaAnchorId, claim, release, topClaimId, } = useBottomActionsContext();
6
6
  /*
7
7
  * One bar, many potential claimants. `DataListingView` already holds it on
8
8
  * ~70 admin screens, so a form opened in a drawer over a listing used to
@@ -75,6 +75,11 @@ export function useBottomActions(options = {}) {
75
75
  return;
76
76
  setDesktopMode(options.desktop);
77
77
  }, [setDesktopMode, options.desktop, isTop]);
78
+ useEffect(() => {
79
+ if (!isTop)
80
+ return;
81
+ setCtaAnchorId(options.ctaAnchorId);
82
+ }, [setCtaAnchorId, options.ctaAnchorId, isTop]);
78
83
  // NOTE: no clearAll() on unmount any more — `release()` above owns that, and
79
84
  // only blanks the bar when the stack empties. Clearing here would flash an
80
85
  // empty bar between a drawer closing and the listing behind it republishing.
@@ -32,7 +32,15 @@ export { useBottomActions } from "./hooks/useBottomActions";
32
32
  export type { UseBottomActionsOptions } from "./hooks/useBottomActions";
33
33
  export { useFormBottomActions } from "./hooks/useFormBottomActions";
34
34
  export type { UseFormBottomActionsOptions } from "./hooks/useFormBottomActions";
35
- export { default as BottomActions } from "./BottomActions";
35
+ export { default as SideActionDock } from "./SideActionDock";
36
+ /**
37
+ * @deprecated The bottom action bar is now a floating side dock. Kept as an
38
+ * alias so a consumer that mounts it by name keeps compiling and keeps
39
+ * rendering the same actions — the component it resolves to is
40
+ * `SideActionDock`.
41
+ */
42
+ export { default as BottomActions } from "./SideActionDock";
43
+ export { ctaAnchorProps, CTA_ANCHOR_ATTR } from "./cta-anchor";
36
44
  export { BottomChrome } from "./BottomChrome";
37
45
  export type { BottomChromeProps } from "./BottomChrome";
38
46
  export { BottomNavbar } from "./BottomNavbar";
@@ -17,7 +17,15 @@ export { AppLayoutShell } from "./AppLayoutShell.js";
17
17
  export { BottomActionsProvider, useBottomActionsContext, } from "./BottomActionsContext.js";
18
18
  export { useBottomActions } from "./hooks/useBottomActions.js";
19
19
  export { useFormBottomActions } from "./hooks/useFormBottomActions.js";
20
- export { default as BottomActions } from "./BottomActions.js";
20
+ export { default as SideActionDock } from "./SideActionDock.js";
21
+ /**
22
+ * @deprecated The bottom action bar is now a floating side dock. Kept as an
23
+ * alias so a consumer that mounts it by name keeps compiling and keeps
24
+ * rendering the same actions — the component it resolves to is
25
+ * `SideActionDock`.
26
+ */
27
+ export { default as BottomActions } from "./SideActionDock.js";
28
+ export { ctaAnchorProps, CTA_ANCHOR_ATTR } from "./cta-anchor.js";
21
29
  export { BottomChrome } from "./BottomChrome.js";
22
30
  export { BottomNavbar } from "./BottomNavbar.js";
23
31
  export { MainNavbar } from "./MainNavbar.js";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * useCtaReveal — "has the user met the Buy button and scrolled past it?"
3
+ *
4
+ * Returns true when the floating action dock should be on screen:
5
+ *
6
+ * - the page marks NO CTA anchor → true immediately (nothing to wait
7
+ * for; an admin bulk bar has no Buy button)
8
+ * - the page marks one, not yet seen → false (the inline CTA is doing the
9
+ * job; a second copy of it beside itself is noise)
10
+ * - seen, and now out of view → true
11
+ * - seen, and scrolled back into view → false again
12
+ *
13
+ * 🛑 `IntersectionObserver`, never a scroll-position threshold. The bar this
14
+ * replaces used `window.scrollY > 400`, which is a guess about where a CTA sits
15
+ * — wrong on a short page (the dock appears while the real button is still on
16
+ * screen) and wrong on a long gallery (it appears before the CTA is reached).
17
+ * Observing the element itself is the same rule stated exactly, and it costs no
18
+ * scroll handler.
19
+ *
20
+ * The anchor is looked up on an interval-free `MutationObserver` because the
21
+ * page that owns it mounts AFTER this dock — the dock lives in the app shell
22
+ * and the CTA arrives with the route.
23
+ */
24
+ export declare function useCtaReveal(enabled?: boolean, anchorId?: string): boolean;
@@ -0,0 +1,82 @@
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
+ import { CTA_ANCHOR_ATTR } from "./cta-anchor.js";
4
+ /**
5
+ * useCtaReveal — "has the user met the Buy button and scrolled past it?"
6
+ *
7
+ * Returns true when the floating action dock should be on screen:
8
+ *
9
+ * - the page marks NO CTA anchor → true immediately (nothing to wait
10
+ * for; an admin bulk bar has no Buy button)
11
+ * - the page marks one, not yet seen → false (the inline CTA is doing the
12
+ * job; a second copy of it beside itself is noise)
13
+ * - seen, and now out of view → true
14
+ * - seen, and scrolled back into view → false again
15
+ *
16
+ * 🛑 `IntersectionObserver`, never a scroll-position threshold. The bar this
17
+ * replaces used `window.scrollY > 400`, which is a guess about where a CTA sits
18
+ * — wrong on a short page (the dock appears while the real button is still on
19
+ * screen) and wrong on a long gallery (it appears before the CTA is reached).
20
+ * Observing the element itself is the same rule stated exactly, and it costs no
21
+ * scroll handler.
22
+ *
23
+ * The anchor is looked up on an interval-free `MutationObserver` because the
24
+ * page that owns it mounts AFTER this dock — the dock lives in the app shell
25
+ * and the CTA arrives with the route.
26
+ */
27
+ export function useCtaReveal(enabled = true, anchorId) {
28
+ const [anchor, setAnchor] = useState(null);
29
+ const [anchorExists, setAnchorExists] = useState(false);
30
+ const [seen, setSeen] = useState(false);
31
+ const [inView, setInView] = useState(false);
32
+ // Find the anchor, and keep looking — a client-side navigation swaps the
33
+ // page under a dock that never unmounts.
34
+ useEffect(() => {
35
+ if (!enabled || typeof document === "undefined")
36
+ return;
37
+ const read = () => {
38
+ // An id published through the context wins over the attribute: a page
39
+ // that names its anchor explicitly is making a more specific statement
40
+ // than "somewhere on this page there is a CTA".
41
+ const el = anchorId
42
+ ? document.getElementById(anchorId)
43
+ : document.querySelector(`[${CTA_ANCHOR_ATTR}]`);
44
+ setAnchor((prev) => (prev === el ? prev : el));
45
+ setAnchorExists(!!el);
46
+ // A new page means a fresh question. Without this reset, navigating from
47
+ // a product page (seen, scrolled past) to another one would reveal the
48
+ // dock at the top of the new page, over its own inline CTA.
49
+ if (!el) {
50
+ setSeen(false);
51
+ setInView(false);
52
+ }
53
+ };
54
+ read();
55
+ const mo = new MutationObserver(read);
56
+ mo.observe(document.body, { childList: true, subtree: true });
57
+ return () => mo.disconnect();
58
+ }, [enabled, anchorId]);
59
+ useEffect(() => {
60
+ if (!anchor || typeof IntersectionObserver === "undefined")
61
+ return;
62
+ setSeen(false);
63
+ const io = new IntersectionObserver(([entry]) => {
64
+ if (!entry)
65
+ return;
66
+ setInView(entry.isIntersecting);
67
+ if (entry.isIntersecting)
68
+ setSeen(true);
69
+ },
70
+ // Any sliver counts as "met it" — a CTA half-cut by the fold has been
71
+ // encountered, and requiring full visibility would leave the dock hidden
72
+ // on a short viewport where it is needed most.
73
+ { threshold: 0 });
74
+ io.observe(anchor);
75
+ return () => io.disconnect();
76
+ }, [anchor]);
77
+ if (!enabled)
78
+ return false;
79
+ if (!anchorExists)
80
+ return true;
81
+ return seen && !inView;
82
+ }
@@ -0,0 +1,41 @@
1
+ import React from "react";
2
+ /**
3
+ * How long a press has to last before it counts as "hold to open" rather than
4
+ * "tap to follow the link". 400ms is the usual long-press threshold — short
5
+ * enough not to feel like a stall, long enough that an ordinary tap never
6
+ * trips it.
7
+ */
8
+ export declare const HOLD_TO_OPEN_MS = 400;
9
+ /**
10
+ * useHoldToOpen — press-and-hold a navigation link to open its sub-menu
11
+ * instead of following it.
12
+ *
13
+ * The shared half of the same affordance on two surfaces: the desktop navbar's
14
+ * dropdown and the mobile bottom nav's sheet. Both wrap a REAL link whose tap
15
+ * must still navigate, and both need the `click` that a long press still fires
16
+ * to be swallowed — otherwise the menu opens and the browser immediately
17
+ * navigates away from it, which reads as the gesture doing nothing.
18
+ *
19
+ * 🛑 `held` is a ref, not state. The click handler reads it in the same tick
20
+ * the timer wrote it, and a state update would not have landed yet — the link
21
+ * would follow through on every hold.
22
+ *
23
+ * @param onHold called once the press passes the threshold (open the menu)
24
+ * @param enabled false for a link with no children — then every handler is a
25
+ * no-op and the link behaves exactly as it did before
26
+ */
27
+ export declare function useHoldToOpen(onHold: () => void, enabled?: boolean): {
28
+ onPointerDown: () => void;
29
+ onPointerUp: () => void;
30
+ onPointerLeave: () => void;
31
+ onPointerCancel: () => void;
32
+ onClickCapture: (e: React.MouseEvent) => void;
33
+ onContextMenu: (e: React.MouseEvent) => void;
34
+ } | {
35
+ onPointerDown?: undefined;
36
+ onPointerUp?: undefined;
37
+ onPointerLeave?: undefined;
38
+ onPointerCancel?: undefined;
39
+ onClickCapture?: undefined;
40
+ onContextMenu?: undefined;
41
+ };
@@ -0,0 +1,84 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef } from "react";
3
+ /**
4
+ * How long a press has to last before it counts as "hold to open" rather than
5
+ * "tap to follow the link". 400ms is the usual long-press threshold — short
6
+ * enough not to feel like a stall, long enough that an ordinary tap never
7
+ * trips it.
8
+ */
9
+ export const HOLD_TO_OPEN_MS = 400;
10
+ /**
11
+ * useHoldToOpen — press-and-hold a navigation link to open its sub-menu
12
+ * instead of following it.
13
+ *
14
+ * The shared half of the same affordance on two surfaces: the desktop navbar's
15
+ * dropdown and the mobile bottom nav's sheet. Both wrap a REAL link whose tap
16
+ * must still navigate, and both need the `click` that a long press still fires
17
+ * to be swallowed — otherwise the menu opens and the browser immediately
18
+ * navigates away from it, which reads as the gesture doing nothing.
19
+ *
20
+ * 🛑 `held` is a ref, not state. The click handler reads it in the same tick
21
+ * the timer wrote it, and a state update would not have landed yet — the link
22
+ * would follow through on every hold.
23
+ *
24
+ * @param onHold called once the press passes the threshold (open the menu)
25
+ * @param enabled false for a link with no children — then every handler is a
26
+ * no-op and the link behaves exactly as it did before
27
+ */
28
+ export function useHoldToOpen(onHold, enabled = true) {
29
+ const timerRef = useRef(null);
30
+ const heldRef = useRef(false);
31
+ const onHoldRef = useRef(onHold);
32
+ // Keep the callback current without re-creating the handlers (and therefore
33
+ // without restarting a press in progress on every parent re-render).
34
+ useEffect(() => {
35
+ onHoldRef.current = onHold;
36
+ }, [onHold]);
37
+ const cancel = useCallback(() => {
38
+ if (timerRef.current) {
39
+ clearTimeout(timerRef.current);
40
+ timerRef.current = null;
41
+ }
42
+ }, []);
43
+ // Clear a pending timer if the item unmounts mid-press — the nav re-renders
44
+ // its item list whenever the listing-type flags or the session resolve.
45
+ useEffect(() => cancel, [cancel]);
46
+ const start = useCallback(() => {
47
+ heldRef.current = false;
48
+ cancel();
49
+ timerRef.current = setTimeout(() => {
50
+ heldRef.current = true;
51
+ onHoldRef.current();
52
+ }, HOLD_TO_OPEN_MS);
53
+ }, [cancel]);
54
+ /**
55
+ * Spread onto the element that wraps (or is) the link. `onClickCapture` is
56
+ * deliberate rather than `onClick`: on the bottom nav the handlers sit on a
57
+ * wrapper around `<NavItem>`, and by the time a bubbled click arrives the
58
+ * anchor's own default is already queued — capture runs before the anchor
59
+ * sees it, so one set of handlers works whether it is spread onto the link
60
+ * itself or onto a container.
61
+ */
62
+ const handlers = enabled
63
+ ? {
64
+ onPointerDown: start,
65
+ onPointerUp: cancel,
66
+ onPointerLeave: cancel,
67
+ onPointerCancel: cancel,
68
+ onClickCapture: (e) => {
69
+ if (!heldRef.current)
70
+ return;
71
+ e.preventDefault();
72
+ e.stopPropagation();
73
+ heldRef.current = false;
74
+ },
75
+ // A long press on touch otherwise raises the OS link callout over the
76
+ // menu the same gesture just opened.
77
+ onContextMenu: (e) => {
78
+ if (heldRef.current)
79
+ e.preventDefault();
80
+ },
81
+ }
82
+ : {};
83
+ return handlers;
84
+ }