@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.
- package/dist/.build-stamp.json +4 -4
- package/dist/_internal/client/features/sticker-trace/canvas-codec.d.ts +2 -0
- package/dist/_internal/client/features/sticker-trace/canvas-codec.js +148 -0
- package/dist/_internal/server/features/auctions/actions.js +1 -1
- package/dist/_internal/server/features/categories/data.js +23 -7
- package/dist/_internal/server/features/checkout/actions.js +10 -3
- package/dist/_internal/server/features/checkout/data.d.ts +15 -0
- package/dist/_internal/server/features/checkout/data.js +20 -3
- package/dist/_internal/server/features/lottery/actions.js +9 -1
- package/dist/_internal/server/features/lottery/og.d.ts +40 -0
- package/dist/_internal/server/features/lottery/og.js +79 -0
- package/dist/_internal/server/features/messages/actions.js +4 -0
- package/dist/_internal/server/features/offers/adapters.js +17 -3
- package/dist/_internal/server/features/orders/actions.js +7 -2
- package/dist/_internal/server/features/raffle/actions.d.ts +19 -0
- package/dist/_internal/server/features/raffle/actions.js +25 -0
- package/dist/_internal/server/features/reviews/actions.js +1 -1
- package/dist/_internal/server/features/reviews/data.d.ts +1 -1
- package/dist/_internal/server/features/search/index-build/artifact-store.d.ts +89 -0
- package/dist/_internal/server/features/search/index-build/artifact-store.js +208 -0
- package/dist/_internal/server/features/search/index-build/build.d.ts +57 -0
- package/dist/_internal/server/features/search/index-build/build.js +285 -0
- package/dist/_internal/server/features/search/index-build/sources.d.ts +53 -0
- package/dist/_internal/server/features/search/index-build/sources.js +385 -0
- package/dist/_internal/server/features/search/search-sources.d.ts +0 -15
- package/dist/_internal/server/features/search/search-sources.js +142 -7
- package/dist/_internal/server/features/seo/robots.js +21 -1
- package/dist/_internal/server/features/seo/sitemap.js +1 -1
- package/dist/_internal/server/features/shared/listing-data-factory.js +16 -4
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +26 -0
- package/dist/_internal/server/features/sticker-trace/actions.d.ts +109 -0
- package/dist/_internal/server/features/sticker-trace/actions.js +172 -0
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +80 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +174 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.js +127 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.d.ts +27 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.js +169 -0
- package/dist/_internal/server/features/sticker-trace/fanout.d.ts +43 -0
- package/dist/_internal/server/features/sticker-trace/fanout.js +180 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.d.ts +25 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.js +123 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.d.ts +30 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.js +112 -0
- package/dist/_internal/server/features/sticker-trace/progress.d.ts +81 -0
- package/dist/_internal/server/features/sticker-trace/progress.js +198 -0
- package/dist/_internal/server/features/sticker-trace/promote.d.ts +23 -0
- package/dist/_internal/server/features/sticker-trace/promote.js +193 -0
- package/dist/_internal/server/features/sticker-trace/shard.d.ts +50 -0
- package/dist/_internal/server/features/sticker-trace/shard.js +174 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +141 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +279 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +135 -0
- package/dist/_internal/server/features/sticker-trace/storage.js +282 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +25 -1
- package/dist/_internal/server/jobs/core/_event-ref.d.ts +51 -0
- package/dist/_internal/server/jobs/core/_event-ref.js +63 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.d.ts +18 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.js +77 -16
- package/dist/_internal/server/jobs/core/auctionSettlement.js +13 -4
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +44 -15
- package/dist/_internal/server/jobs/core/bundleStockSync.js +3 -4
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +44 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.d.ts +78 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.js +133 -0
- package/dist/_internal/server/jobs/core/listingProcessor.js +28 -8
- package/dist/_internal/server/jobs/core/onOrderCreate.js +12 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +13 -2
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +8 -2
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +8 -2
- package/dist/_internal/server/jobs/core/onStoreWrite.js +11 -4
- package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +5 -4
- package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -4
- package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -2
- package/dist/_internal/server/jobs/core/promotions.js +7 -4
- package/dist/_internal/server/jobs/core/searchIndexBuild.d.ts +7 -0
- package/dist/_internal/server/jobs/core/searchIndexBuild.js +211 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.d.ts +35 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.js +213 -31
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +20 -14
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +15 -15
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onCategoryWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onProductWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onReviewWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onScamReportUpdate.js +18 -0
- package/dist/_internal/server/jobs/handlers/onStoreWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.js +2 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -6
- package/dist/_internal/shared/actions/action-registry.js +29 -0
- package/dist/_internal/shared/cache/revalidate-targets.d.ts +0 -1
- package/dist/_internal/shared/cache/revalidate-targets.js +10 -8
- package/dist/_internal/shared/features/events/config.d.ts +14 -0
- package/dist/_internal/shared/features/events/config.js +14 -0
- package/dist/_internal/shared/features/notifications/action-url.js +8 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/codec.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/codec.js +30 -0
- package/dist/_internal/shared/features/sticker-trace/config.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/config.js +177 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.js +60 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.d.ts +65 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.js +176 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.d.ts +56 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.d.ts +92 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.js +110 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.d.ts +68 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.js +223 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.js +178 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.d.ts +26 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.js +134 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.d.ts +40 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.js +195 -0
- package/dist/_internal/shared/features/sticker-trace/index.d.ts +2 -0
- package/dist/_internal/shared/features/sticker-trace/index.js +59 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.js +66 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.js +165 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.js +156 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.d.ts +16 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.js +242 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.d.ts +46 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.js +168 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.js +286 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.js +74 -0
- package/dist/_internal/shared/features/sticker-trace/resume.d.ts +50 -0
- package/dist/_internal/shared/features/sticker-trace/resume.js +160 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.js +132 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.d.ts +28 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.d.ts +21 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.js +104 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.d.ts +3 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.js +140 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.js +138 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.js +187 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.d.ts +32 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.js +147 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.d.ts +30 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.js +125 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.js +344 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.js +251 -0
- package/dist/_internal/shared/features/sticker-trace/types.d.ts +197 -0
- package/dist/_internal/shared/features/sticker-trace/types.js +49 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +11 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +1 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +1 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +1 -0
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +7 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +9 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +1 -0
- package/dist/_internal/shared/media/limits.d.ts +12 -2
- package/dist/_internal/shared/media/limits.js +12 -2
- package/dist/_internal/shared/search/artifact-url.d.ts +35 -0
- package/dist/_internal/shared/search/artifact-url.js +119 -0
- package/dist/_internal/shared/search/index-record.d.ts +68 -0
- package/dist/_internal/shared/search/index-record.js +96 -0
- package/dist/_internal/shared/search/match.d.ts +65 -0
- package/dist/_internal/shared/search/match.js +263 -0
- package/dist/client.d.ts +8 -7
- package/dist/client.js +12 -5
- package/dist/configs/eslint.js +22 -2
- package/dist/constants/api-endpoints.d.ts +68 -0
- package/dist/constants/api-endpoints.js +32 -0
- package/dist/constants/field-names.d.ts +7 -1
- package/dist/constants/field-names.js +36 -1
- package/dist/contracts/repository.d.ts +8 -7
- package/dist/contracts/search.d.ts +2 -2
- package/dist/contracts/table.d.ts +3 -3
- package/dist/contracts/table.js +3 -3
- package/dist/core/contact-submissions.repository.js +2 -2
- package/dist/core/integration-keys.js +7 -1
- package/dist/core/newsletter.repository.js +2 -2
- package/dist/core/site-config.js +1 -1
- package/dist/errors/error-codes.d.ts +30 -0
- package/dist/errors/error-codes.js +30 -0
- package/dist/errors/error-display-map.js +40 -1
- package/dist/features/account/api/[userId]/addresses/route.js +1 -1
- package/dist/features/account/components/UserBidsView.js +1 -1
- package/dist/features/account/components/index.d.ts +0 -8
- package/dist/features/account/components/index.js +0 -4
- package/dist/features/addresses/repository/addresses.repository.d.ts +17 -6
- package/dist/features/addresses/repository/addresses.repository.js +65 -9
- package/dist/features/addresses/schemas/firestore.d.ts +17 -6
- package/dist/features/admin/actions/notification-actions.js +15 -6
- package/dist/features/admin/api/bids/route.js +1 -1
- package/dist/features/admin/api/coupons/route.js +1 -1
- package/dist/features/admin/api/products/route.js +1 -1
- package/dist/features/admin/api/reviews/route.js +1 -1
- package/dist/features/admin/components/AdminAdEditorView.js +19 -5
- package/dist/features/admin/components/AdminAuditLogView.js +1 -1
- package/dist/features/admin/components/AdminBlogEditorView.js +0 -1
- package/dist/features/admin/components/AdminBlogView.js +1 -1
- package/dist/features/admin/components/AdminBrandsView.js +17 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +0 -1
- package/dist/features/admin/components/AdminContactView.js +1 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -3
- package/dist/features/admin/components/AdminNewsletterView.js +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +9 -2
- package/dist/features/admin/components/AdminPayoutsView.js +1 -1
- package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -0
- package/dist/features/admin/components/AdminProductEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminProductEditorView.js +24 -37
- package/dist/features/admin/components/AdminProductsView.js +10 -3
- package/dist/features/admin/components/AdminScammersView.js +1 -1
- package/dist/features/admin/components/AdminSectionsView.js +21 -5
- package/dist/features/admin/components/AdminSessionsView.js +1 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +22 -1
- package/dist/features/admin/components/AdminTeamView.js +1 -1
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +0 -1
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/DataListingView.d.ts +2 -1
- package/dist/features/admin/components/DataListingView.js +9 -4
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +0 -2
- package/dist/features/admin/hooks/useAdminListing.d.ts +1 -1
- package/dist/features/admin/repository/site-settings.repository.js +8 -3
- package/dist/features/admin/schemas/firestore.d.ts +62 -1
- package/dist/features/admin/schemas/firestore.js +32 -0
- package/dist/features/admin/types/index.d.ts +1 -1
- package/dist/features/auctions/actions/bid-actions.d.ts +2 -2
- package/dist/features/auctions/actions/bid-actions.js +16 -4
- package/dist/features/auctions/api/route.js +1 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +4 -0
- package/dist/features/auctions/repository/bid.repository.d.ts +46 -4
- package/dist/features/auctions/repository/bid.repository.js +114 -13
- package/dist/features/auctions/schemas/firestore.d.ts +24 -4
- package/dist/features/auctions/schemas/firestore.js +1 -0
- package/dist/features/auth/actions/profile-actions.js +30 -4
- package/dist/features/auth/components/index.d.ts +0 -1
- package/dist/features/auth/components/index.js +0 -1
- package/dist/features/auth/repository/session.repository.d.ts +17 -3
- package/dist/features/auth/repository/session.repository.js +46 -5
- package/dist/features/auth/repository/token.repository.d.ts +27 -4
- package/dist/features/auth/repository/token.repository.js +65 -11
- package/dist/features/auth/repository/user.repository.d.ts +33 -7
- package/dist/features/auth/repository/user.repository.js +100 -15
- package/dist/features/auth/schemas/firestore.d.ts +63 -12
- package/dist/features/auth/schemas/firestore.js +11 -0
- package/dist/features/before-after/api/route.js +1 -1
- package/dist/features/blog/components/BlogListView.js +16 -3
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/blog/schemas/index.d.ts +2 -2
- package/dist/features/cart/api/route.js +1 -1
- package/dist/features/catalogue/repository/catalogue.repository.d.ts +7 -7
- package/dist/features/catalogue/repository/catalogue.repository.js +28 -10
- package/dist/features/catalogue/schemas/firestore.d.ts +11 -0
- package/dist/features/categories/api/route.js +10 -10
- package/dist/features/categories/components/CategoryDetailPageView.js +35 -5
- package/dist/features/categories/components/CategorySelectorCreate.js +0 -1
- package/dist/features/categories/components/index.d.ts +0 -2
- package/dist/features/categories/components/index.js +0 -1
- package/dist/features/categories/repository/categories.repository.d.ts +1 -0
- package/dist/features/categories/repository/categories.repository.js +31 -1
- package/dist/features/categories/schemas/index.d.ts +2 -2
- package/dist/features/categories/utils/taxonomy-visual.d.ts +21 -0
- package/dist/features/categories/utils/taxonomy-visual.js +58 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +8 -1
- package/dist/features/collections/api/[slug]/route.js +3 -3
- package/dist/features/collections/api/route.js +1 -1
- package/dist/features/consultation/api/route.js +1 -1
- package/dist/features/consultation/repository/consultations.repository.js +1 -1
- package/dist/features/consultation/types/index.d.ts +1 -1
- package/dist/features/contact/components/ContactForm.js +1 -3
- package/dist/features/corporate/api/route.js +1 -1
- package/dist/features/corporate/repository/corporate.repository.js +1 -1
- package/dist/features/corporate/types/index.d.ts +1 -1
- package/dist/features/cron/jobs/auction-expiry.job.js +1 -1
- package/dist/features/cron/jobs/preorder-reminder.job.js +1 -1
- package/dist/features/events/actions/event-actions.d.ts +14 -0
- package/dist/features/events/actions/event-actions.js +82 -3
- package/dist/features/events/api/[id]/route.js +2 -2
- package/dist/features/events/components/AdminEventEditorView.js +22 -3
- package/dist/features/events/components/AdminEventsView.js +32 -8
- package/dist/features/events/components/EventRafflesSection.d.ts +34 -1
- package/dist/features/events/components/EventRafflesSection.js +52 -3
- package/dist/features/events/components/SpinWheelView.d.ts +2 -2
- package/dist/features/events/components/SpinWheelView.js +41 -4
- package/dist/features/events/repository/event-entry.repository.d.ts +14 -2
- package/dist/features/events/repository/event-entry.repository.js +41 -7
- package/dist/features/events/schemas/firestore.d.ts +17 -4
- package/dist/features/events/types/index.d.ts +37 -0
- package/dist/features/faq/repository/faqs.repository.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +5 -2
- package/dist/features/faq/schemas/index.js +6 -0
- package/dist/features/faq/types/index.d.ts +0 -1
- package/dist/features/grouped/components/GroupedListingEditorView.js +17 -2
- package/dist/features/homepage/api/carousel/[id]/route.js +1 -1
- package/dist/features/homepage/api/carousel/route.js +4 -4
- package/dist/features/homepage/api/route.js +2 -2
- package/dist/features/homepage/api/sections/route.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +1 -9
- package/dist/features/homepage/components/AnnouncementBar.js +13 -19
- package/dist/features/homepage/components/MarketplaceHomepageView.js +6 -1
- package/dist/features/homepage/components/index.d.ts +0 -2
- package/dist/features/homepage/components/index.js +0 -1
- package/dist/features/homepage/repository/homepage.repository.js +1 -1
- package/dist/features/homepage/schemas/firestore.d.ts +6 -0
- package/dist/features/homepage/schemas/index.d.ts +10 -10
- package/dist/features/layout/AppLayoutShell.d.ts +11 -0
- package/dist/features/layout/AppLayoutShell.js +64 -12
- package/dist/features/layout/BottomActionsContext.d.ts +16 -0
- package/dist/features/layout/BottomActionsContext.js +5 -0
- package/dist/features/layout/BottomChrome.js +48 -9
- package/dist/features/layout/BottomNavbar.d.ts +14 -0
- package/dist/features/layout/BottomNavbar.js +43 -3
- package/dist/features/layout/MainNavbar.d.ts +11 -0
- package/dist/features/layout/NavbarLayout.d.ts +3 -0
- package/dist/features/layout/NavbarLayout.js +88 -11
- package/dist/features/layout/SideActionDock.d.ts +1 -0
- package/dist/features/layout/SideActionDock.js +219 -0
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/layout/cta-anchor.d.ts +31 -0
- package/dist/features/layout/cta-anchor.js +31 -0
- package/dist/features/layout/hooks/useBottomActions.d.ts +7 -0
- package/dist/features/layout/hooks/useBottomActions.js +6 -1
- package/dist/features/layout/index.d.ts +9 -1
- package/dist/features/layout/index.js +9 -1
- package/dist/features/layout/useCtaReveal.d.ts +24 -0
- package/dist/features/layout/useCtaReveal.js +82 -0
- package/dist/features/layout/useHoldToOpen.d.ts +41 -0
- package/dist/features/layout/useHoldToOpen.js +84 -0
- package/dist/features/lottery/repository/lottery-entry.repository.d.ts +18 -3
- package/dist/features/lottery/repository/lottery-entry.repository.js +48 -6
- package/dist/features/lottery/schemas/firestore.d.ts +33 -5
- package/dist/features/loyalty/api/balance/route.js +1 -1
- package/dist/features/loyalty/api/history/route.js +1 -1
- package/dist/features/media/MediaImage.js +0 -1
- package/dist/features/media/MediaPickerModal.js +7 -1
- package/dist/features/media/modals/ImageEditor.js +5 -1
- package/dist/features/media/modals/VideoThumbnailSelector.js +17 -1
- package/dist/features/media/repository/media-assets.repository.d.ts +19 -0
- package/dist/features/media/upload/CameraCapture.js +16 -1
- package/dist/features/media/upload/ImageUpload.js +42 -4
- package/dist/features/media/upload/MediaUploadField.js +69 -13
- package/dist/features/media/upload/downscale-image.d.ts +56 -0
- package/dist/features/media/upload/downscale-image.js +150 -0
- package/dist/features/messages/components/ConversationThreadView.js +45 -2
- package/dist/features/messages/components/MessageSellerButton.d.ts +15 -1
- package/dist/features/messages/components/MessageSellerButton.js +10 -2
- package/dist/features/messages/schemas/firestore.d.ts +15 -0
- package/dist/features/orders/hooks/useOrders.js +4 -2
- package/dist/features/orders/repository/orders.repository.d.ts +15 -4
- package/dist/features/orders/repository/orders.repository.js +52 -20
- package/dist/features/orders/schemas/firestore.d.ts +15 -4
- package/dist/features/orders/schemas/index.d.ts +8 -8
- package/dist/features/orders/types/index.d.ts +2 -2
- package/dist/features/payments/repository/payments.repository.js +2 -2
- package/dist/features/payments/repository/payout.repository.d.ts +23 -6
- package/dist/features/payments/repository/payout.repository.js +63 -23
- package/dist/features/payments/repository/saved-payment-methods.repository.d.ts +17 -6
- package/dist/features/payments/repository/saved-payment-methods.repository.js +59 -11
- package/dist/features/payments/schemas/firestore.d.ts +14 -3
- package/dist/features/payments/schemas/saved-methods-firestore.d.ts +12 -1
- package/dist/features/pre-orders/api/[slug]/route.js +1 -1
- package/dist/features/pre-orders/api/admin/route.js +1 -1
- package/dist/features/pre-orders/api/route.js +1 -1
- package/dist/features/pre-orders/repository/pre-orders.repository.d.ts +3 -3
- package/dist/features/pre-orders/repository/pre-orders.repository.js +6 -6
- package/dist/features/products/api/[id]/route.js +1 -1
- package/dist/features/products/components/ListingBottomActions.js +4 -0
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductGalleryClient.js +2 -2
- package/dist/features/products/components/ProductGrid.js +12 -1
- package/dist/features/products/components/index.d.ts +0 -2
- package/dist/features/products/components/index.js +0 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +0 -3
- package/dist/features/products/config/listing-type-listing-config.js +27 -2
- package/dist/features/products/constants/listing-tabs.d.ts +9 -0
- package/dist/features/products/constants/listing-tabs.js +3 -2
- package/dist/features/products/hooks/useProducts.js +2 -2
- package/dist/features/products/repository/products.repository.js +13 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/types/index.d.ts +1 -1
- package/dist/features/promotions/api/route.js +1 -1
- package/dist/features/reviews/actions/review-actions.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +22 -8
- package/dist/features/reviews/components/ReviewDetailPageView.js +13 -1
- package/dist/features/reviews/components/ReviewsIndexPageView.js +21 -4
- package/dist/features/reviews/repository/reviews.repository.d.ts +19 -7
- package/dist/features/reviews/repository/reviews.repository.js +63 -12
- package/dist/features/reviews/schemas/firestore.d.ts +13 -2
- package/dist/features/reviews/schemas/index.d.ts +2 -2
- package/dist/features/scams/actions/scam-actions.js +16 -4
- package/dist/features/search/components/SearchResultsPageView.js +2 -1
- package/dist/features/search/hooks/useSearchIndex.d.ts +34 -0
- package/dist/features/search/hooks/useSearchIndex.js +172 -0
- package/dist/features/search/repository/search.repository.js +2 -2
- package/dist/features/seller/actions/offer-actions.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +38 -8
- package/dist/features/seller/actions/seller-actions.js +34 -7
- package/dist/features/seller/api/coupons/route.js +1 -1
- package/dist/features/seller/api/products/route.js +1 -1
- package/dist/features/seller/api/store/route.js +1 -1
- package/dist/features/seller/components/SellerBidsView.js +1 -1
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +9 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +0 -1
- package/dist/features/seller/components/SellerPayoutsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +0 -1
- package/dist/features/seller/components/SellerProductsView.js +1 -1
- package/dist/features/seller/components/SellerShippingView.js +0 -1
- package/dist/features/seller/components/SellerStorefrontView.js +0 -1
- package/dist/features/seller/components/index.d.ts +0 -4
- package/dist/features/seller/components/index.js +0 -2
- package/dist/features/seller/repository/offer.repository.d.ts +15 -3
- package/dist/features/seller/repository/offer.repository.js +43 -7
- package/dist/features/seller/schemas/firestore.d.ts +14 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +39 -0
- package/dist/features/seller/schemas/order-forms.js +37 -0
- package/dist/features/shell/FormShell.js +6 -2
- package/dist/features/shell/QuickFormDrawer.js +15 -1
- package/dist/features/shipments/components/AdminShipmentEditorView.js +0 -1
- package/dist/features/shipments/components/AdminShipmentsView.js +1 -1
- package/dist/features/sticker-trace/components/StickerCommitPanel.d.ts +30 -0
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +93 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.d.ts +33 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.js +104 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.d.ts +20 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.js +128 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.d.ts +45 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.js +84 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.d.ts +27 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.js +171 -0
- package/dist/features/sticker-trace/constants/help-content.d.ts +23 -0
- package/dist/features/sticker-trace/constants/help-content.js +172 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.d.ts +27 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.js +160 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.d.ts +22 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.js +106 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.d.ts +113 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.js +146 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.d.ts +132 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.js +174 -0
- package/dist/features/sticker-trace/schemas/firestore.d.ts +248 -0
- package/dist/features/sticker-trace/schemas/firestore.js +79 -0
- package/dist/features/sticker-trace/server.d.ts +8 -0
- package/dist/features/sticker-trace/server.js +51 -0
- package/dist/features/stores/actions/store-query-actions.d.ts +2 -2
- package/dist/features/stores/actions/store-query-actions.js +7 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/reviews/route.js +1 -1
- package/dist/features/stores/api/[storeSlug]/route.js +1 -1
- package/dist/features/stores/components/StoreNavTabs.js +17 -2
- package/dist/features/stores/manifest.js +8 -4
- package/dist/features/support/repository/support.repository.d.ts +14 -3
- package/dist/features/support/repository/support.repository.js +93 -13
- package/dist/features/support/schemas/firestore.d.ts +16 -5
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +61 -19
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +19 -3
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +243 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +36 -10
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.js +209 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.js +90 -0
- package/dist/features/tester/seed-data/authored/index.js +8 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +19 -17
- package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +10 -5
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +283 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +192 -22
- package/dist/index.d.ts +10 -23
- package/dist/index.js +27 -19
- package/dist/next/api/routeHandler.js +9 -0
- package/dist/next/routing/require-record.d.ts +13 -0
- package/dist/next/routing/require-record.js +62 -0
- package/dist/next/routing/route-map.d.ts +4 -4
- package/dist/next/routing/route-map.js +25 -3
- package/dist/providers/db-firebase/base.d.ts +4 -2
- package/dist/providers/db-firebase/base.js +21 -5
- package/dist/providers/db-firebase/base.repository.d.ts +11 -9
- package/dist/providers/db-firebase/base.repository.js +19 -0
- package/dist/providers/db-firebase/rtdb-paths.d.ts +12 -0
- package/dist/providers/db-firebase/rtdb-paths.js +12 -0
- package/dist/react/ErrorBoundary.js +6 -1
- package/dist/react/hooks/realtime-event-constants.d.ts +1 -0
- package/dist/react/hooks/realtime-event-constants.js +8 -0
- package/dist/react/hooks/useEntityDelete.js +5 -1
- package/dist/react/hooks/useMessage.js +5 -1
- package/dist/repositories/index.d.ts +2 -2
- package/dist/repositories/index.js +6 -1
- package/dist/schemas/registry.d.ts +13 -20
- package/dist/schemas/registry.js +31 -14
- package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
- package/dist/security/encrypted.d.ts +117 -0
- package/dist/security/encrypted.js +100 -0
- package/dist/security/index.d.ts +5 -2
- package/dist/security/index.js +16 -2
- package/dist/security/pii-accessors.d.ts +71 -0
- package/dist/security/pii-accessors.js +150 -0
- package/dist/security/pii-encrypt.d.ts +0 -8
- package/dist/security/pii-encrypt.js +22 -15
- package/dist/security/pii-mask.d.ts +18 -0
- package/dist/security/pii-mask.js +27 -0
- package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -6
- package/dist/seed/_helpers/search-txt-wrappers.js +22 -0
- package/dist/seed/addresses-seed-data.d.ts +2 -2
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.js +1277 -0
- package/dist/seed/bids-seed-data.d.ts +2 -2
- package/dist/seed/bids-seed-data.js +23 -2
- package/dist/seed/events-seed-data.d.ts +2 -2
- package/dist/seed/events-seed-data.js +5 -0
- package/dist/seed/faq-seed-data.js +175 -5
- package/dist/seed/homepage-sections-seed-data.js +39 -23
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/lottery-entries-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.js +1 -1
- package/dist/seed/orders-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.js +1 -1
- package/dist/seed/reviews-seed-data.d.ts +1 -2
- package/dist/seed/seed-purpose.js +7 -0
- package/dist/seed/sessions-seed-data.d.ts +2 -2
- package/dist/seed/sessions-seed-data.js +5 -0
- package/dist/seed/site-settings-seed-data.js +1 -1
- package/dist/seed/support-tickets-seed-data.d.ts +2 -2
- package/dist/seed/support-tickets-seed-data.js +1 -1
- package/dist/seed/users-seed-data.d.ts +2 -2
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seo/json-ld.js +5 -1
- package/dist/server.d.ts +18 -3
- package/dist/server.js +59 -3
- package/dist/styles.css +237 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.js +7 -1
- package/dist/ui/components/FilterChipGroup.d.ts +11 -0
- package/dist/ui/components/FilterChipGroup.js +1 -1
- package/dist/ui/components/ImageGallery.js +6 -1
- package/dist/ui/components/ListingLayout.js +14 -8
- package/dist/ui/components/OverflowRow.d.ts +92 -0
- package/dist/ui/components/OverflowRow.js +203 -0
- package/dist/ui/components/OverflowRow.style.css +235 -0
- package/dist/ui/components/RecordDetailModal.js +14 -1
- package/dist/ui/components/RowActionMenu.js +5 -1
- package/dist/ui/components/SideDrawer.js +5 -1
- package/dist/ui/components/SideModal.js +9 -1
- package/dist/ui/components/TabBarShell.d.ts +12 -1
- package/dist/ui/components/TabBarShell.js +3 -2
- package/dist/ui/components/Tabs.js +36 -24
- package/dist/ui/components/Toast.d.ts +3 -24
- package/dist/ui/components/Toast.js +2 -19
- package/dist/ui/components/TopBannerPortal.d.ts +15 -0
- package/dist/ui/components/TopBannerPortal.js +19 -0
- package/dist/ui/components/UnsavedChangesModal.js +5 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/row-collapse.d.ts +15 -0
- package/dist/ui/components/row-collapse.js +127 -0
- package/dist/ui/components/toast-context.d.ts +63 -0
- package/dist/ui/components/toast-context.js +48 -0
- package/dist/ui/components/top-banner-slot.d.ts +37 -0
- package/dist/ui/components/top-banner-slot.js +45 -0
- package/dist/ui/icons/icon-registry.d.ts +6 -0
- package/dist/ui/icons/icon-registry.js +17 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/array.helper.d.ts +2 -2
- package/dist/utils/array.helper.js +5 -5
- package/dist/utils/id-generators.d.ts +6 -0
- package/dist/utils/id-generators.js +10 -0
- package/dist/utils/media-url.js +0 -2
- package/dist/utils/search-txt-builders.d.ts +28 -4
- package/dist/utils/search-txt-builders.js +41 -1
- package/dist/validation/schemas.d.ts +8 -8
- package/package.json +6 -2
- package/scripts/seed-cli.mjs +3 -0
- package/dist/features/account/components/UserAddressesView.d.ts +0 -13
- package/dist/features/account/components/UserAddressesView.js +0 -5
- package/dist/features/account/components/UserNotificationsView.d.ts +0 -15
- package/dist/features/account/components/UserNotificationsView.js +0 -12
- package/dist/features/account/components/UserSettingsView.d.ts +0 -16
- package/dist/features/account/components/UserSettingsView.js +0 -13
- package/dist/features/account/components/UserSupportView.d.ts +0 -3
- package/dist/features/account/components/UserSupportView.js +0 -166
- package/dist/features/admin/components/DemoSeedView.d.ts +0 -11
- package/dist/features/admin/components/DemoSeedView.js +0 -5
- package/dist/features/auth/components/AuthStatusPanel.d.ts +0 -10
- package/dist/features/auth/components/AuthStatusPanel.js +0 -22
- package/dist/features/categories/components/CategoryProductsView.d.ts +0 -45
- package/dist/features/categories/components/CategoryProductsView.js +0 -21
- package/dist/features/homepage/components/HowItWorksInfoView.d.ts +0 -36
- package/dist/features/homepage/components/HowItWorksInfoView.js +0 -10
- package/dist/features/layout/BottomActions.d.ts +0 -1
- package/dist/features/layout/BottomActions.js +0 -311
- package/dist/features/products/components/ProductsView.d.ts +0 -6
- package/dist/features/products/components/ProductsView.js +0 -5
- package/dist/features/seller/components/SellerStoreView.d.ts +0 -8
- 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, {
|
|
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
|
|
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
|
|
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
|
+
}
|