@mohasinac/appkit 4.13.1 → 4.14.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/_internal/client/features/layout/DashboardLayoutClient.js +14 -5
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +3 -0
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +6 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +8 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.js +4 -1
- package/dist/_internal/client/features/lottery/LotteryListView.d.ts +7 -0
- package/dist/_internal/client/features/lottery/LotteryListView.js +1 -1
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +4 -1
- package/dist/_internal/client/features/lottery/slot-collage-items.d.ts +15 -0
- package/dist/_internal/client/features/lottery/slot-collage-items.js +13 -0
- package/dist/_internal/server/features/auctions/actions.js +6 -0
- package/dist/_internal/server/features/bundles/data.d.ts +16 -0
- package/dist/_internal/server/features/bundles/data.js +26 -0
- package/dist/_internal/server/features/bundles/index.d.ts +1 -1
- package/dist/_internal/server/features/bundles/index.js +1 -1
- package/dist/_internal/server/features/checkout/actions.js +6 -0
- package/dist/_internal/server/features/checkout/locked-lines.d.ts +38 -0
- package/dist/_internal/server/features/checkout/locked-lines.js +171 -0
- package/dist/_internal/server/features/homepage/index.d.ts +0 -1
- package/dist/_internal/server/features/homepage/index.js +7 -1
- package/dist/_internal/server/features/lottery/adapters.js +4 -0
- package/dist/_internal/server/features/products/data.js +15 -37
- package/dist/_internal/server/features/products/index.d.ts +1 -1
- package/dist/_internal/server/features/products/index.js +1 -1
- package/dist/_internal/server/features/products/list-public.d.ts +46 -20
- package/dist/_internal/server/features/products/list-public.js +266 -90
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +44 -0
- package/dist/_internal/server/features/products/listing-tab-counts.js +97 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +51 -0
- package/dist/_internal/server/features/site-settings/adapters.js +75 -0
- package/dist/_internal/server/features/site-settings/index.d.ts +1 -0
- package/dist/_internal/server/features/site-settings/index.js +1 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +56 -0
- package/dist/_internal/server/features/stores/adapters.js +91 -0
- package/dist/_internal/server/features/stores/index.d.ts +1 -0
- package/dist/_internal/server/features/stores/index.js +1 -0
- package/dist/_internal/server/jobs/core/auctionSettlement.js +56 -2
- package/dist/_internal/server/jobs/core/offerExpiry.js +45 -9
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.d.ts +5 -0
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.js +33 -1
- package/dist/_internal/server/jobs/handlers/messages.d.ts +7 -0
- package/dist/_internal/server/jobs/handlers/messages.js +10 -0
- package/dist/_internal/shared/actions/action-registry.js +15 -1
- package/dist/_internal/shared/checkout/lanes.d.ts +25 -0
- package/dist/_internal/shared/checkout/lanes.js +26 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +27 -0
- package/dist/_internal/shared/features/auctions/config.js +27 -0
- package/dist/_internal/shared/features/blog/schema.d.ts +2 -2
- package/dist/_internal/shared/features/cart/schema.d.ts +12 -12
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +32 -32
- package/dist/_internal/shared/features/emi/schedule.d.ts +24 -3
- package/dist/_internal/shared/features/emi/schedule.js +20 -5
- package/dist/_internal/shared/features/events/schema.d.ts +2 -2
- package/dist/_internal/shared/features/homepage/section-gate.d.ts +14 -0
- package/dist/_internal/shared/features/homepage/section-gate.js +51 -0
- package/dist/_internal/shared/features/offers/config.d.ts +30 -0
- package/dist/_internal/shared/features/offers/config.js +59 -0
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +32 -32
- package/dist/_internal/shared/features/products/to-product-item.js +6 -0
- package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
- package/dist/_internal/shared/features/site-settings/fees.d.ts +60 -0
- package/dist/_internal/shared/features/site-settings/fees.js +39 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +40 -0
- package/dist/_internal/shared/features/site-settings/types.js +1 -0
- package/dist/_internal/shared/history/history.d.ts +66 -0
- package/dist/_internal/shared/history/history.js +158 -0
- package/dist/_internal/shared/history/index.d.ts +4 -0
- package/dist/_internal/shared/history/index.js +2 -0
- package/dist/_internal/shared/history/types.d.ts +61 -0
- package/dist/_internal/shared/history/types.js +6 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +54 -1
- package/dist/_internal/shared/listing-types/_registry.js +67 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/art/config.js +5 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +13 -0
- package/dist/_internal/shared/listing-types/auction/config.js +21 -0
- package/dist/_internal/shared/listing-types/availability.d.ts +79 -0
- package/dist/_internal/shared/listing-types/availability.js +104 -0
- package/dist/_internal/shared/listing-types/capabilities.d.ts +15 -0
- package/dist/_internal/shared/listing-types/capabilities.js +12 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/classified/config.js +5 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +11 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +22 -2
- package/dist/_internal/shared/listing-types/live/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/live/config.js +5 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +19 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +11 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +15 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/standard/config.js +5 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +5 -0
- package/dist/client.d.ts +7 -5
- package/dist/client.js +2 -2
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/constants/field-names.d.ts +49 -2
- package/dist/constants/field-names.js +53 -2
- package/dist/constants/table-keys.d.ts +17 -0
- package/dist/constants/table-keys.js +17 -0
- package/dist/errors/error-codes.d.ts +13 -1
- package/dist/errors/error-codes.js +13 -1
- package/dist/errors/error-display-map.js +12 -3
- package/dist/errors/messages.d.ts +10 -2
- package/dist/errors/messages.js +10 -2
- package/dist/features/about/components/AboutView.d.ts +3 -0
- package/dist/features/about/components/AboutView.js +3 -2
- package/dist/features/about/components/PolicyPageView.d.ts +2 -1
- package/dist/features/about/components/PolicyPageView.js +61 -23
- package/dist/features/about/components/PublicProfileView.js +5 -0
- package/dist/features/about/schemas/firestore.d.ts +3 -0
- package/dist/features/account/components/UserOrdersView.js +7 -0
- package/dist/features/account/components/index.d.ts +0 -2
- package/dist/features/account/components/index.js +0 -1
- package/dist/features/account/schemas/index.d.ts +2 -2
- package/dist/features/account/types/index.d.ts +21 -2
- package/dist/features/addresses/schemas/index.d.ts +4 -4
- package/dist/features/admin/components/AdminArtView.js +8 -3
- package/dist/features/admin/components/AdminClassifiedView.js +8 -3
- package/dist/features/admin/components/AdminDigitalCodesView.js +8 -3
- package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -0
- package/dist/features/admin/components/AdminLiveView.js +8 -3
- package/dist/features/admin/components/AdminOffersView.d.ts +4 -0
- package/dist/features/admin/components/AdminOffersView.js +186 -0
- package/dist/features/admin/components/AdminOrdersView.js +10 -1
- package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -0
- package/dist/features/admin/components/AdminProductsView.js +16 -29
- package/dist/features/admin/components/AdminSiteSettingsView.js +31 -13
- package/dist/features/admin/components/AdminSiteView.js +6 -2
- package/dist/features/admin/components/AdminStickersView.js +8 -3
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +86 -0
- package/dist/features/admin/constants/filter-tabs.js +55 -0
- package/dist/features/admin/schemas/firestore.d.ts +122 -3
- package/dist/features/admin/schemas/firestore.js +1 -0
- package/dist/features/auctions/actions/bid-actions.d.ts +20 -5
- package/dist/features/auctions/actions/bid-actions.js +93 -20
- package/dist/features/auctions/components/AuctionDetailPageView.js +11 -6
- package/dist/features/auctions/components/AuctionsListView.js +5 -6
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +7 -0
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +19 -2
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +8 -4
- package/dist/features/auctions/repository/bid.repository.d.ts +13 -0
- package/dist/features/auctions/repository/bid.repository.js +23 -0
- package/dist/features/auctions/schemas/firestore.d.ts +17 -0
- package/dist/features/auctions/schemas/index.d.ts +12 -12
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +10 -1
- package/dist/features/blog/actions/blog-actions.d.ts +7 -7
- package/dist/features/blog/schemas/index.d.ts +6 -6
- package/dist/features/cart/repository/cart.repository.js +1 -0
- package/dist/features/cart/schemas/firestore.d.ts +15 -0
- package/dist/features/catalogue/schemas/validation.d.ts +4 -4
- package/dist/features/categories/components/BrandDetailPageView.js +23 -40
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -7
- package/dist/features/categories/components/BrandDetailTabs.js +8 -12
- package/dist/features/categories/components/BundleCollage.js +1 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +53 -57
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +10 -8
- package/dist/features/categories/components/CategoryDetailTabs.js +11 -16
- package/dist/features/categories/components/CategoryProductsListing.js +11 -1
- package/dist/features/categories/components/ConcernCard.js +7 -1
- package/dist/features/categories/schemas/firestore.d.ts +13 -0
- package/dist/features/categories/schemas/index.d.ts +26 -26
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +16 -1
- package/dist/features/classified/components/ClassifiedDetailPageView.js +23 -3
- package/dist/features/events/components/AdminEventsView.js +15 -11
- package/dist/features/events/components/EventFilters.d.ts +9 -1
- package/dist/features/events/components/EventFilters.js +45 -21
- package/dist/features/events/components/EventsIndexListing.d.ts +6 -1
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/components/EventsListPageView.js +13 -4
- package/dist/features/events/repository/events.repository.d.ts +17 -0
- package/dist/features/events/repository/events.repository.js +27 -0
- package/dist/features/events/schemas/firestore.d.ts +12 -0
- package/dist/features/events/schemas/firestore.js +12 -0
- package/dist/features/events/schemas/index.d.ts +50 -50
- package/dist/features/events/types/index.d.ts +11 -0
- package/dist/features/events/types/index.js +57 -1
- package/dist/features/faq/actions/faq-actions.d.ts +12 -12
- package/dist/features/faq/schemas/index.d.ts +8 -8
- package/dist/features/filters/FilterFacetSection.d.ts +7 -1
- package/dist/features/filters/FilterFacetSection.js +11 -3
- package/dist/features/grouped/schemas/index.d.ts +4 -4
- package/dist/features/homepage/components/AnnouncementBar.d.ts +7 -1
- package/dist/features/homepage/components/AnnouncementBar.js +3 -3
- package/dist/features/homepage/components/MarketplaceHomepageView.js +20 -6
- package/dist/features/homepage/hooks/homepage-query.d.ts +16 -0
- package/dist/features/homepage/hooks/homepage-query.js +45 -0
- package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +10 -0
- package/dist/features/homepage/hooks/useFeaturedAuctions.js +28 -8
- package/dist/features/homepage/hooks/useFeaturedPreOrders.js +17 -8
- package/dist/features/homepage/hooks/useFeaturedProducts.js +15 -8
- package/dist/features/homepage/schemas/index.d.ts +2 -2
- package/dist/features/layout/AppLayoutShell.d.ts +11 -1
- package/dist/features/layout/AppLayoutShell.js +15 -14
- package/dist/features/layout/BackToTop.d.ts +9 -0
- package/dist/features/layout/BackToTop.js +10 -1
- package/dist/features/layout/BottomActions.js +28 -25
- package/dist/features/layout/BottomChrome.d.ts +34 -0
- package/dist/features/layout/BottomChrome.js +55 -0
- package/dist/features/layout/BottomNavLayout.d.ts +6 -0
- package/dist/features/layout/BottomNavLayout.js +7 -1
- package/dist/features/layout/BottomNavbar.js +15 -2
- package/dist/features/layout/FooterLayout.js +11 -1
- package/dist/features/layout/NavbarLayout.js +1 -1
- package/dist/features/layout/TitleBarLayout.d.ts +7 -0
- package/dist/features/layout/TitleBarLayout.js +28 -5
- package/dist/features/layout/index.d.ts +2 -0
- package/dist/features/layout/index.js +1 -0
- package/dist/features/lottery/types/index.d.ts +3 -0
- package/dist/features/media/MediaPickerModal.js +5 -1
- package/dist/features/messages/schemas/index.d.ts +2 -2
- package/dist/features/orders/components/OrderScopeTabs.d.ts +20 -0
- package/dist/features/orders/components/OrderScopeTabs.js +31 -0
- package/dist/features/orders/constants/order-scope.d.ts +48 -0
- package/dist/features/orders/constants/order-scope.js +111 -0
- package/dist/features/orders/repository/orders.repository.d.ts +54 -7
- package/dist/features/orders/repository/orders.repository.js +116 -22
- package/dist/features/orders/schemas/firestore.d.ts +117 -0
- package/dist/features/orders/schemas/firestore.js +30 -0
- package/dist/features/orders/schemas/index.d.ts +18 -18
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +14 -9
- package/dist/features/pre-orders/components/PreOrdersListView.js +6 -5
- package/dist/features/pre-orders/schemas/index.d.ts +1 -1
- package/dist/features/products/actions/product-actions.d.ts +14 -0
- package/dist/features/products/actions/product-actions.js +49 -11
- package/dist/features/products/api/route.d.ts +12 -0
- package/dist/features/products/api/route.js +42 -100
- package/dist/features/products/components/ArtStickersListView.js +2 -2
- package/dist/features/products/components/AuctionsIndexListing.js +13 -11
- package/dist/features/products/components/AvailabilityTabs.d.ts +11 -0
- package/dist/features/products/components/AvailabilityTabs.js +47 -0
- package/dist/features/products/components/MakeOfferButton.js +48 -49
- package/dist/features/products/components/PrizeDrawCollage.d.ts +20 -4
- package/dist/features/products/components/PrizeDrawCollage.js +9 -1
- package/dist/features/products/components/PrizeDrawsIndexListing.js +14 -12
- package/dist/features/products/components/PrizeDrawsListingView.js +2 -2
- package/dist/features/products/components/PrizeDrawsSection.d.ts +7 -1
- package/dist/features/products/components/PrizeDrawsSection.js +23 -18
- package/dist/features/products/components/ProductDetailPageView.d.ts +4 -1
- package/dist/features/products/components/ProductDetailPageView.js +18 -4
- package/dist/features/products/components/ProductForm.js +5 -2
- package/dist/features/products/components/ProductGrid.js +6 -1
- package/dist/features/products/components/ProductsIndexListing.js +22 -32
- package/dist/features/products/components/ProductsIndexPageView.js +6 -9
- package/dist/features/products/components/index.d.ts +2 -2
- package/dist/features/products/components/index.js +1 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +20 -0
- package/dist/features/products/config/listing-type-listing-config.js +22 -10
- package/dist/features/products/constants/action-defs.d.ts +2 -0
- package/dist/features/products/constants/action-defs.js +6 -0
- package/dist/features/products/hooks/useAvailabilityScope.d.ts +13 -0
- package/dist/features/products/hooks/useAvailabilityScope.js +19 -0
- package/dist/features/products/hooks/useProducts.d.ts +5 -0
- package/dist/features/products/hooks/useProducts.js +13 -2
- package/dist/features/products/repository/products.repository.d.ts +31 -2
- package/dist/features/products/repository/products.repository.js +53 -21
- package/dist/features/products/schemas/firestore.d.ts +17 -3
- package/dist/features/products/schemas/firestore.js +7 -2
- package/dist/features/products/schemas/index.d.ts +66 -66
- package/dist/features/products/schemas/product-features.validators.d.ts +6 -6
- package/dist/features/products/types/index.d.ts +16 -1
- package/dist/features/promotions/schemas/index.d.ts +2 -2
- package/dist/features/reviews/schemas/index.d.ts +16 -16
- package/dist/features/search/schemas/index.d.ts +4 -4
- package/dist/features/seller/actions/offer-actions.js +25 -2
- package/dist/features/seller/components/SellerArtView.js +5 -0
- package/dist/features/seller/components/SellerAuctionsView.js +13 -15
- package/dist/features/seller/components/SellerClassifiedView.js +5 -0
- package/dist/features/seller/components/SellerDigitalCodesView.js +5 -0
- package/dist/features/seller/components/SellerLiveView.js +5 -0
- package/dist/features/seller/components/SellerOrdersView.js +31 -9
- package/dist/features/seller/components/SellerPayoutSettingsView.js +19 -18
- package/dist/features/seller/components/SellerPreOrdersView.js +5 -0
- package/dist/features/seller/components/SellerPrizeDrawsView.js +14 -16
- package/dist/features/seller/components/SellerProductShell.js +7 -1
- package/dist/features/seller/components/SellerProductsView.js +11 -8
- package/dist/features/seller/components/SellerStickersView.js +5 -0
- package/dist/features/seller/components/index.d.ts +0 -2
- package/dist/features/seller/components/index.js +0 -1
- package/dist/features/seller/repository/offer.repository.d.ts +73 -16
- package/dist/features/seller/repository/offer.repository.js +38 -3
- package/dist/features/seller/schemas/index.d.ts +2 -2
- package/dist/features/seller/schemas/offer-forms.d.ts +25 -0
- package/dist/features/seller/schemas/offer-forms.js +21 -0
- package/dist/features/seller/server.d.ts +0 -1
- package/dist/features/seller/server.js +0 -1
- package/dist/features/shell/SectionForm.d.ts +99 -0
- package/dist/features/shell/SectionForm.js +128 -0
- package/dist/features/shell/entity-form.d.ts +109 -0
- package/dist/features/shell/entity-form.js +96 -0
- package/dist/features/shell/index.d.ts +4 -0
- package/dist/features/shell/index.js +2 -0
- package/dist/features/stores/api/[storeSlug]/route.js +2 -25
- package/dist/features/stores/components/StoreAuctionsListing.js +15 -1
- package/dist/features/stores/components/StoreClassifiedsListing.js +12 -2
- package/dist/features/stores/components/StoreDetailLayoutView.js +24 -71
- package/dist/features/stores/components/StoreDigitalCodesListing.js +12 -2
- package/dist/features/stores/components/StoreLiveItemsListing.js +12 -2
- package/dist/features/stores/components/StorePreOrdersListing.js +12 -1
- package/dist/features/stores/components/StoreProductsListing.js +11 -1
- package/dist/features/stores/repository/store.repository.js +6 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/support/schemas/index.d.ts +4 -4
- package/dist/features/tester/actions/checklist-item-actions.d.ts +4 -4
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +119 -3
- package/dist/features/tester/seed-data/products-tester-seed-data.js +131 -1
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +105 -1
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.js +14 -9
- package/dist/next/routing/route-map.d.ts +7 -1
- package/dist/next/routing/route-map.js +5 -0
- package/dist/providers/db-firebase/base.repository.d.ts +30 -0
- package/dist/providers/db-firebase/base.repository.js +50 -1
- package/dist/providers/db-firebase/index.d.ts +1 -1
- package/dist/providers/db-firebase/index.js +1 -1
- package/dist/providers/db-firebase/sieve.d.ts +25 -0
- package/dist/providers/db-firebase/sieve.js +52 -18
- package/dist/react/hooks/useUrlTable.js +10 -1
- package/dist/schemas/registry.d.ts +68 -68
- package/dist/seed/_helpers/category-forest.d.ts +2 -0
- package/dist/seed/_helpers/category-forest.js +309 -0
- package/dist/seed/_helpers/category-tree.d.ts +27 -0
- package/dist/seed/_helpers/category-tree.js +103 -0
- package/dist/seed/catalogue-seed-data.js +12 -12
- package/dist/seed/categories-seed-data.js +177 -162
- package/dist/seed/events-seed-data.js +61 -10
- package/dist/seed/homepage-sections-seed-data.js +5 -1
- package/dist/seed/offers-seed-data.js +32 -27
- package/dist/seed/products-art-seed-data.js +50 -12
- package/dist/seed/products-auctions-seed-data.js +97 -18
- package/dist/seed/products-classifieds-seed-data.js +80 -16
- package/dist/seed/products-digital-codes-seed-data.js +66 -18
- package/dist/seed/products-live-items-seed-data.js +64 -13
- package/dist/seed/products-preorders-seed-data.d.ts +0 -1
- package/dist/seed/products-preorders-seed-data.js +52 -13
- package/dist/seed/products-prize-draws-seed-data.js +63 -14
- package/dist/seed/products-standard-seed-data.js +99 -26
- package/dist/seed/products-stickers-seed-data.js +47 -12
- package/dist/seed/reviews-seed-data.js +6 -1
- package/dist/seed/site-settings-seed-data.d.ts +1 -38
- package/dist/seed/site-settings-seed-data.js +38 -76
- package/dist/seed/stores-seed-data.js +71 -1
- package/dist/seed/users-seed-data.js +15 -5
- package/dist/server-entry.d.ts +1 -2
- package/dist/server-entry.js +4 -3
- package/dist/server.d.ts +4 -3
- package/dist/server.js +8 -4
- package/dist/styles.css +78 -12
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.style.css +19 -4
- package/dist/ui/components/CollapsibleSection.d.ts +17 -1
- package/dist/ui/components/CollapsibleSection.js +6 -2
- package/dist/ui/components/FilterChipGroup.d.ts +25 -1
- package/dist/ui/components/FilterChipGroup.js +21 -4
- package/dist/ui/components/HandMode.style.css +47 -0
- package/dist/ui/components/Layout.d.ts +9 -2
- package/dist/ui/components/Layout.js +1 -1
- package/dist/ui/components/ListingLayout.js +8 -8
- package/dist/ui/components/ListingLayout.style.css +8 -7
- package/dist/ui/components/StickyToolbar.d.ts +3 -1
- package/dist/ui/components/StickyToolbar.js +62 -20
- package/dist/ui/components/bottom-chrome-slot.d.ts +21 -0
- package/dist/ui/components/bottom-chrome-slot.js +29 -0
- package/dist/ui/components/index.style.css +3 -0
- package/dist/ui/forms/FormShell.d.ts +43 -13
- package/dist/ui/forms/FormShell.js +22 -11
- package/dist/ui/forms/index.d.ts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -217,13 +217,28 @@
|
|
|
217
217
|
* That is exactly what happened to every image-tile button in the app when
|
|
218
218
|
* the ripple landed.
|
|
219
219
|
*
|
|
220
|
-
*
|
|
221
|
-
* `
|
|
222
|
-
* deeper than the
|
|
220
|
+
* ALL FOUR flex-container properties must be inherited — `flex-direction` and
|
|
221
|
+
* `align-items` as much as `justify-content` and `gap` — because the real
|
|
222
|
+
* children now sit one level deeper than the container declaring them. The
|
|
223
|
+
* first pass at this fix inherited only two and hard-coded `align-items:
|
|
224
|
+
* center`, so a Button asking for `flex-col` silently still laid its children
|
|
225
|
+
* out in a row: the prize-draw collage, the media picker and the concern card
|
|
226
|
+
* each rendered an image tile BESIDE its caption instead of above it, at a
|
|
227
|
+
* fraction of the intended width. `inherit` is behaviour-identical for every
|
|
228
|
+
* ordinary button — `.appkit-button` declares `align-items: center` and never
|
|
229
|
+
* declares `flex-direction`, so it computes to the initial `row`.
|
|
230
|
+
*
|
|
231
|
+
* One thing this CSS cannot defend against: a caller putting a bare `block` /
|
|
232
|
+
* `flex` / `hidden` Tailwind utility on the Button. The consumer's globals.css
|
|
233
|
+
* declares those un-layered and `!important`, which beats `.appkit-button`'s
|
|
234
|
+
* `display: inline-flex` — and every rule below applies only to a flex ITEM, so
|
|
235
|
+
* the whole contract goes inert and fill children collapse to 0x0 again. That
|
|
236
|
+
* is guarded from the call-site side by scripts/audit-primitive-child-wrappers.mjs.
|
|
223
237
|
*/
|
|
224
238
|
.appkit-button__content {
|
|
225
239
|
display: inline-flex;
|
|
226
|
-
|
|
240
|
+
flex-direction: inherit;
|
|
241
|
+
align-items: inherit;
|
|
227
242
|
justify-content: inherit;
|
|
228
243
|
gap: inherit;
|
|
229
244
|
flex: 1 1 auto;
|
|
@@ -5,6 +5,22 @@ export interface CollapsibleSectionProps {
|
|
|
5
5
|
onToggle: () => void;
|
|
6
6
|
/** Optional right-aligned content next to the title (badges, counts). */
|
|
7
7
|
renderHeaderExtra?: () => React.ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Keep collapsed children mounted (hidden via CSS) instead of unmounting them.
|
|
10
|
+
*
|
|
11
|
+
* `<Collapse>` renders `{isOpen && <motion.div>}` — collapsing therefore
|
|
12
|
+
* UNMOUNTS the subtree and destroys any uncommitted state inside it. That is
|
|
13
|
+
* harmless for inputs driven entirely off a parent `values` object, but it
|
|
14
|
+
* discards in-flight work for anything holding its own: a `useMediaUpload`
|
|
15
|
+
* transfer, a rich-text editor buffer, a partially-filled multi-select.
|
|
16
|
+
*
|
|
17
|
+
* Set this on any section that can hold uncommitted state. The trade-off is
|
|
18
|
+
* that hidden children still render, so don't enable it for expensive
|
|
19
|
+
* subtrees that are purely presentational.
|
|
20
|
+
*/
|
|
21
|
+
keepMounted?: boolean;
|
|
22
|
+
/** Anchor id on the section root — lets a caller scroll/link to it. */
|
|
23
|
+
id?: string;
|
|
8
24
|
className?: string;
|
|
9
25
|
children?: React.ReactNode;
|
|
10
26
|
}
|
|
@@ -12,4 +28,4 @@ export interface CollapsibleSectionProps {
|
|
|
12
28
|
* per-user, accordion-scoped collapse state (see that hook for the
|
|
13
29
|
* server-side merge/default-collapsed semantics). Purely presentational
|
|
14
30
|
* here: isCollapsed/onToggle are always controlled by the caller. */
|
|
15
|
-
export declare function CollapsibleSection({ title, isCollapsed, onToggle, renderHeaderExtra, className, children, }: CollapsibleSectionProps): React.JSX.Element;
|
|
31
|
+
export declare function CollapsibleSection({ title, isCollapsed, onToggle, renderHeaderExtra, keepMounted, id, className, children, }: CollapsibleSectionProps): React.JSX.Element;
|
|
@@ -8,6 +8,10 @@ import { Collapse } from "./Motion";
|
|
|
8
8
|
* per-user, accordion-scoped collapse state (see that hook for the
|
|
9
9
|
* server-side merge/default-collapsed semantics). Purely presentational
|
|
10
10
|
* here: isCollapsed/onToggle are always controlled by the caller. */
|
|
11
|
-
export function CollapsibleSection({ title, isCollapsed, onToggle, renderHeaderExtra, className = "", children, }) {
|
|
12
|
-
return (_jsxs(Div, { className: className, rounded: "xl", border: "default", surface: "default", children: [_jsxs(Row, { align: "center", justify: "between", paddingX: "x-md", paddingY: "y-sm", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: onToggle, paddingX: "none", paddingY: "none", rounded: "none", className: "min-w-0 flex-1", "aria-expanded": !isCollapsed, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Span, { weight: "semibold", size: "sm", children: title }), _jsx("svg", { className: `w-4 h-4 transition-transform duration-150 ${isCollapsed ? "" : "rotate-180"}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] }) }), renderHeaderExtra && _jsx(Div, { className: "ml-3 shrink-0", children: renderHeaderExtra() })] }),
|
|
11
|
+
export function CollapsibleSection({ title, isCollapsed, onToggle, renderHeaderExtra, keepMounted = false, id, className = "", children, }) {
|
|
12
|
+
return (_jsxs(Div, { id: id, className: className, rounded: "xl", border: "default", surface: "default", children: [_jsxs(Row, { align: "center", justify: "between", paddingX: "x-md", paddingY: "y-sm", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: onToggle, paddingX: "none", paddingY: "none", rounded: "none", className: "min-w-0 flex-1", "aria-expanded": !isCollapsed, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Span, { weight: "semibold", size: "sm", children: title }), _jsx("svg", { className: `w-4 h-4 transition-transform duration-150 ${isCollapsed ? "" : "rotate-180"}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] }) }), renderHeaderExtra && _jsx(Div, { className: "ml-3 shrink-0", children: renderHeaderExtra() })] }), keepMounted ? (
|
|
13
|
+
// No <Collapse>: it unmounts on close, which would discard uncommitted
|
|
14
|
+
// child state (see `keepMounted` docs). `hidden` keeps the subtree
|
|
15
|
+
// mounted and removes it from the a11y tree at the same time.
|
|
16
|
+
_jsx(Div, { padding: "md", border: "top", hidden: isCollapsed, children: children })) : (_jsx(Collapse, { isOpen: !isCollapsed, children: _jsx(Div, { padding: "md", border: "top", children: children }) }))] }));
|
|
13
17
|
}
|
|
@@ -22,6 +22,16 @@ import React from "react";
|
|
|
22
22
|
export interface FilterChipGroupTab {
|
|
23
23
|
id: string;
|
|
24
24
|
label: string;
|
|
25
|
+
/**
|
|
26
|
+
* Rows matching this chip within the surface's current scope. Rendered as a
|
|
27
|
+
* trailing count and, with `hideEmpty`, used to drop chips that would return
|
|
28
|
+
* nothing.
|
|
29
|
+
*
|
|
30
|
+
* `undefined` means "not counted / count failed" — NOT zero. Such a chip is
|
|
31
|
+
* always kept, so a surface that supplies no counts behaves exactly as before
|
|
32
|
+
* and a failed count can never hide a filter that has rows (Root Cause #59).
|
|
33
|
+
*/
|
|
34
|
+
count?: number;
|
|
25
35
|
}
|
|
26
36
|
export interface FilterChipGroupProps {
|
|
27
37
|
/** Section label shown above the chips. */
|
|
@@ -52,7 +62,21 @@ export interface FilterChipGroupProps {
|
|
|
52
62
|
* same state that every caller would have to remember to clear.
|
|
53
63
|
*/
|
|
54
64
|
multiple?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Drop chips whose `count` is exactly 0 — a filter that can only ever return
|
|
67
|
+
* an empty list is noise.
|
|
68
|
+
*
|
|
69
|
+
* Opt-in (default `false`) because most of this component's ~45 call sites
|
|
70
|
+
* supply no counts at all, and because it is only ever correct for a FILTER
|
|
71
|
+
* over existing rows. Never enable it on a picker that CREATES something: a
|
|
72
|
+
* seller with no auctions yet must still be able to make their first one.
|
|
73
|
+
*
|
|
74
|
+
* A chip whose count is `undefined` is always kept — see `FilterChipGroupTab.count`.
|
|
75
|
+
* The currently-selected chip is also always kept, so an active filter can
|
|
76
|
+
* never vanish from under the user mid-interaction.
|
|
77
|
+
*/
|
|
78
|
+
hideEmpty?: boolean;
|
|
55
79
|
/** Optional className spread onto the outer wrapper. */
|
|
56
80
|
className?: string;
|
|
57
81
|
}
|
|
58
|
-
export declare function FilterChipGroup({ label, tabs, value, onChange, allId, multiple, className, }: FilterChipGroupProps): React.JSX.Element;
|
|
82
|
+
export declare function FilterChipGroup({ label, tabs, value, onChange, allId, multiple, hideEmpty, className, }: FilterChipGroupProps): React.JSX.Element;
|
|
@@ -6,16 +6,33 @@ const ACTIVE_CLS = "bg-[var(--appkit-color-primary)] text-white border-[var(--ap
|
|
|
6
6
|
const INACTIVE_CLS = "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]";
|
|
7
7
|
const CHIP_BASE_CLS = "rounded-full px-3 py-1 text-xs font-medium border transition-colors";
|
|
8
8
|
const LABEL_CLS = "text-xs font-semibold uppercase tracking-widest text-[var(--appkit-color-text-muted)]";
|
|
9
|
+
// `opacity-70` rather than a fixed colour so the count stays legible against
|
|
10
|
+
// both the active (primary fill) and inactive (surface) chip backgrounds —
|
|
11
|
+
// a literal text colour would be invisible on one of them in some theme
|
|
12
|
+
// (Root Cause #67).
|
|
13
|
+
const COUNT_CLS = "ml-1.5 tabular-nums opacity-70";
|
|
9
14
|
/** Split a pipe-joined multi-select value into its ids. */
|
|
10
15
|
function parseMulti(value) {
|
|
11
16
|
return value ? value.split("|").filter(Boolean) : [];
|
|
12
17
|
}
|
|
13
|
-
export function FilterChipGroup({ label, tabs, value, onChange, allId = "All", multiple = false, className, }) {
|
|
18
|
+
export function FilterChipGroup({ label, tabs, value, onChange, allId = "All", multiple = false, hideEmpty = false, className, }) {
|
|
14
19
|
const selected = new Set(multiple ? parseMulti(value) : []);
|
|
15
20
|
const current = value || allId;
|
|
16
21
|
// In multi-select the "All" sentinel is redundant with an empty selection —
|
|
17
22
|
// see the `multiple` prop docs.
|
|
18
|
-
const
|
|
23
|
+
const allTabs = multiple ? tabs.filter((t) => t.id !== allId) : tabs;
|
|
24
|
+
const visibleTabs = hideEmpty
|
|
25
|
+
? allTabs.filter((t) => {
|
|
26
|
+
// Never hide the "All" sentinel, and never hide a chip the user has
|
|
27
|
+
// already picked — a filter disappearing while it is applied would
|
|
28
|
+
// leave the URL holding a value with no way to clear it.
|
|
29
|
+
if (t.id === allId)
|
|
30
|
+
return true;
|
|
31
|
+
if (multiple ? selected.has(t.id) : current === t.id)
|
|
32
|
+
return true;
|
|
33
|
+
return t.count === undefined || t.count > 0;
|
|
34
|
+
})
|
|
35
|
+
: allTabs;
|
|
19
36
|
const handleClick = (tabId) => {
|
|
20
37
|
if (!multiple) {
|
|
21
38
|
onChange(tabId === allId ? "" : tabId);
|
|
@@ -36,9 +53,9 @@ export function FilterChipGroup({ label, tabs, value, onChange, allId = "All", m
|
|
|
36
53
|
};
|
|
37
54
|
return (_jsxs(Div, { className: `space-y-2 ${className ?? ""}`.trim(), children: [_jsx(Text, { as: "p", className: LABEL_CLS, children: label }), _jsx(Div, { className: "flex flex-wrap gap-2", role: multiple ? "group" : undefined, "aria-label": multiple ? label : undefined, children: visibleTabs.map((tab) => {
|
|
38
55
|
const isActive = multiple ? selected.has(tab.id) : current === tab.id;
|
|
39
|
-
return (
|
|
56
|
+
return (_jsxs("button", { type: "button",
|
|
40
57
|
// Checkboxes report checked state, not pressed state — a screen
|
|
41
58
|
// reader announcing "pressed" for a filter that stays on is wrong.
|
|
42
|
-
role: multiple ? "checkbox" : undefined, "aria-checked": multiple ? isActive : undefined, "aria-pressed": multiple ? undefined : isActive, onClick: () => handleClick(tab.id), className: `${CHIP_BASE_CLS} ${isActive ? ACTIVE_CLS : INACTIVE_CLS}`, children: tab.label }, tab.id));
|
|
59
|
+
role: multiple ? "checkbox" : undefined, "aria-checked": multiple ? isActive : undefined, "aria-pressed": multiple ? undefined : isActive, onClick: () => handleClick(tab.id), className: `${CHIP_BASE_CLS} ${isActive ? ACTIVE_CLS : INACTIVE_CLS}`, children: [tab.label, typeof tab.count === "number" && (_jsx("span", { className: COUNT_CLS, children: tab.count > 99 ? "99+" : tab.count }))] }, tab.id));
|
|
43
60
|
}) })] }));
|
|
44
61
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* Hand-mode mirroring — CSS-only, driven by `<html data-hand>`.
|
|
2
|
+
*
|
|
3
|
+
* `data-hand` is written before first paint by the blocking script in the
|
|
4
|
+
* consumer's root layout, so these rules apply on the FIRST paint: no flash,
|
|
5
|
+
* no server/client hydration mismatch (`HandModeProvider` reads localStorage
|
|
6
|
+
* in its useState initialiser, so a className derived from `hand` would
|
|
7
|
+
* differ server vs client), and no "use client" forced onto server-safe
|
|
8
|
+
* primitives (Root Cause #12). These are hand-authored classes, not Tailwind
|
|
9
|
+
* output, so they also survive the consumer's `@source not "../../appkit"`
|
|
10
|
+
* purge (Root Cause #3).
|
|
11
|
+
*
|
|
12
|
+
* NOTE: both appkit's and the consumer's Tailwind builds set
|
|
13
|
+
* `important: true`. Any call site using these classes MUST NOT also carry
|
|
14
|
+
* the equivalent utility (`flex-row-reverse`, `-right-*`) — an !important
|
|
15
|
+
* declaration in @layer utilities beats these unlayered rules, so the class
|
|
16
|
+
* would silently do nothing.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/* Mirror a flex row's VISUAL order only. DOM order — and therefore reading
|
|
20
|
+
order, aria-* and the focus sequence — is unchanged. */
|
|
21
|
+
[data-hand="left"] .appkit-hand-mirror {
|
|
22
|
+
flex-direction: row-reverse;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Corner count badge hugging the OUTER top corner of its icon: top-right by
|
|
26
|
+
default, top-left in left-hand mode. Owns the HORIZONTAL axis only — the
|
|
27
|
+
vertical offset stays a `-top-*` utility at the call site.
|
|
28
|
+
|
|
29
|
+
The offset comes from `--appkit-badge-offset`, declared only by the size
|
|
30
|
+
modifiers below. That matters: a `--lg { right: -0.5rem }` variant would be
|
|
31
|
+
specificity (0,1,0) and would LOSE to `[data-hand="left"] .appkit-hand-badge`
|
|
32
|
+
at (0,2,0), so left-hand mode would silently fall back to the small offset.
|
|
33
|
+
A custom property has no such race. */
|
|
34
|
+
.appkit-hand-badge {
|
|
35
|
+
right: calc(var(--appkit-badge-offset, 0.125rem) * -1);
|
|
36
|
+
left: auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-hand="left"] .appkit-hand-badge {
|
|
40
|
+
left: calc(var(--appkit-badge-offset, 0.125rem) * -1);
|
|
41
|
+
right: auto;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* 0.5rem inset — the offset the bottom-nav badges expressed as `-right-2`. */
|
|
45
|
+
.appkit-hand-badge--lg {
|
|
46
|
+
--appkit-badge-offset: var(--appkit-space-2, 0.5rem);
|
|
47
|
+
}
|
|
@@ -281,8 +281,15 @@ export interface RowProps extends React.HTMLAttributes<HTMLElement>, SurfaceProp
|
|
|
281
281
|
wrap?: boolean;
|
|
282
282
|
/** Reverse the visual order of children (`flex-direction: row-reverse`) without
|
|
283
283
|
* touching DOM/source order. Used for hand-mode-aware layouts (e.g. moving a
|
|
284
|
-
* close button to the opposite header edge) — replaces raw `flex-row-reverse`.
|
|
285
|
-
|
|
284
|
+
* close button to the opposite header edge) — replaces raw `flex-row-reverse`.
|
|
285
|
+
*
|
|
286
|
+
* `true` reverses unconditionally. `"hand"` defers the decision to the
|
|
287
|
+
* `data-hand` preference: it mirrors only in left-hand mode, entirely in CSS
|
|
288
|
+
* (`HandMode.style.css`), so `Row` stays hook-free and server-safe and the
|
|
289
|
+
* flip lands on the FIRST paint — no flash, no hydration mismatch. Prefer
|
|
290
|
+
* `"hand"` over `useHandMode()` + `reverse={hand === "left"}` for anything
|
|
291
|
+
* rendered above the fold. */
|
|
292
|
+
reverse?: boolean | "hand";
|
|
286
293
|
/** Zebra-stripe pattern when this Row is a repeating list element (rendered with `even:bg-*`). */
|
|
287
294
|
oddEven?: "none" | "zebra";
|
|
288
295
|
/**
|
|
@@ -235,7 +235,7 @@ export function Row({ gap = "md", centered = false, align = "center", justify =
|
|
|
235
235
|
const Tag = (as ?? "div");
|
|
236
236
|
const classes = [
|
|
237
237
|
"appkit-row",
|
|
238
|
-
reverse ? "appkit-row--reverse" : "",
|
|
238
|
+
reverse === "hand" ? "appkit-hand-mirror" : reverse ? "appkit-row--reverse" : "",
|
|
239
239
|
centered ? "appkit-row--centered" : align !== "center" ? ITEMS_MAP[align] : "",
|
|
240
240
|
!centered && justify !== "start" ? JUSTIFY_MAP[justify] : "",
|
|
241
241
|
GAP_MAP[gap],
|
|
@@ -20,6 +20,8 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
20
20
|
* └----------┴-------------------------------------------------------┘
|
|
21
21
|
*/
|
|
22
22
|
import { useState } from "react";
|
|
23
|
+
import { createPortal } from "react-dom";
|
|
24
|
+
import { useBottomChromeSlot } from "./bottom-chrome-slot";
|
|
23
25
|
import { Aside, Nav } from "./Semantic";
|
|
24
26
|
import { Text, Span } from "./Typography";
|
|
25
27
|
import { Button } from "./Button";
|
|
@@ -42,6 +44,9 @@ export function ListingLayout({ headerSlot, statusTabsSlot, filterContent, filte
|
|
|
42
44
|
// Rules of Hooks.
|
|
43
45
|
const [sidebarOpen, setSidebarOpen] = useState(defaultSidebarOpen);
|
|
44
46
|
const [mobileFilterOpen, setMobileFilterOpen] = useState(false);
|
|
47
|
+
// Must run before the detail-view short-circuit below — hooks cannot sit
|
|
48
|
+
// after a conditional return.
|
|
49
|
+
const bottomChromeSlot = useBottomChromeSlot();
|
|
45
50
|
// Detail view short-circuit (folded from ListingViewShell)
|
|
46
51
|
if (detailView) {
|
|
47
52
|
return _jsx(_Fragment, { children: detailView });
|
|
@@ -92,14 +97,9 @@ export function ListingLayout({ headerSlot, statusTabsSlot, filterContent, filte
|
|
|
92
97
|
: "appkit-listing-layout__sidebar--collapsed",
|
|
93
98
|
].join(" "), children: _jsxs(Div, { className: "appkit-listing-layout__sidebar-panel", children: [_jsxs(Div, { className: "appkit-listing-layout__sidebar-header", children: [_jsx(Text, { weight: "semibold", size: "sm", children: panelTitle }), filterActiveCount > 0 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onFilterClear, className: "text-xs text-primary hover:text-primary/80 hover:underline p-0 h-auto leading-none font-medium", children: l.clearAll }))] }), _jsx(Div, { className: "appkit-listing-layout__sidebar-facets", children: filterContent }), _jsx(Div, { className: "appkit-listing-layout__sidebar-footer", children: _jsx(Button, { type: "button", variant: "primary", className: "w-full rounded-xl", size: "sm", onClick: onFilterApply, children: filterPendingCount != null && filterPendingCount > 0
|
|
94
99
|
? `${l.applyFilters} (${filterPendingCount})`
|
|
95
|
-
: l.applyFilters }) })] }) })), _jsxs(Div, { className: "appkit-listing-layout__content", children: [activeFiltersSlot, resultCountSlot && (_jsx(Div, { className: "appkit-listing-layout__result-count", children: resultCountSlot })), errorSlot ? (errorSlot) : (_jsxs(_Fragment, { children: [children, paginationSlot && (_jsx(Div, { className: "appkit-listing-layout__pagination", children: paginationSlot }))] }))] })] }), toolbarPaginationSlot &&
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
? "appkit-listing-layout__mobile-pagination--dashboard"
|
|
99
|
-
: selectedCount > 0
|
|
100
|
-
? "appkit-listing-layout__mobile-pagination--bulk"
|
|
101
|
-
: "appkit-listing-layout__mobile-pagination--default",
|
|
102
|
-
].join(" "), children: toolbarPaginationSlot })), hasFilter && (_jsx(Drawer, { isOpen: mobileFilterOpen, onClose: () => setMobileFilterOpen(false), side: "bottom", title: filterActiveCount > 0
|
|
100
|
+
: l.applyFilters }) })] }) })), _jsxs(Div, { className: "appkit-listing-layout__content", children: [activeFiltersSlot, resultCountSlot && (_jsx(Div, { className: "appkit-listing-layout__result-count", children: resultCountSlot })), errorSlot ? (errorSlot) : (_jsxs(_Fragment, { children: [children, paginationSlot && (_jsx(Div, { className: "appkit-listing-layout__pagination", children: paginationSlot }))] }))] })] }), toolbarPaginationSlot &&
|
|
101
|
+
bottomChromeSlot &&
|
|
102
|
+
createPortal(_jsx(Nav, { "aria-label": "Pagination", className: "appkit-listing-layout__mobile-pagination", children: toolbarPaginationSlot }), bottomChromeSlot), hasFilter && (_jsx(Drawer, { isOpen: mobileFilterOpen, onClose: () => setMobileFilterOpen(false), side: "bottom", title: filterActiveCount > 0
|
|
103
103
|
? `${panelTitle} (${filterActiveCount})`
|
|
104
104
|
: panelTitle, footer: _jsxs(Div, { className: "appkit-listing-layout__mobile-overlay-footer", children: [_jsx(Button, { type: "button", variant: "secondary", className: "flex-1 rounded-xl", onClick: () => onFilterClear?.(), children: l.clearAll }), _jsx(Button, { type: "button", variant: "primary", className: "flex-1 rounded-xl", onClick: handleMobileApply, children: filterPendingCount != null && filterPendingCount > 0
|
|
105
105
|
? `${l.applyFilters} (${filterPendingCount})`
|
|
@@ -376,11 +376,10 @@
|
|
|
376
376
|
|
|
377
377
|
/* -- Mobile sticky pagination bar ------------------- */
|
|
378
378
|
|
|
379
|
+
/* Positioned by <BottomChrome>, the shell's bottom-edge tier — this element is
|
|
380
|
+
a flex child of it, so it owns no position, offset or z-index of its own. */
|
|
379
381
|
.appkit-listing-layout__mobile-pagination {
|
|
380
|
-
|
|
381
|
-
left: 0;
|
|
382
|
-
right: 0;
|
|
383
|
-
z-index: 39;
|
|
382
|
+
pointer-events: auto;
|
|
384
383
|
background: rgba(255, 255, 255, 0.9);
|
|
385
384
|
backdrop-filter: blur(12px);
|
|
386
385
|
border-top: 1px solid rgba(228, 228, 231, 0.8);
|
|
@@ -406,9 +405,11 @@
|
|
|
406
405
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.2);
|
|
407
406
|
}
|
|
408
407
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
.
|
|
408
|
+
/* The --dashboard / --default / --bulk offset modifiers are gone. --bulk only
|
|
409
|
+
ever meant "the CTA bar is up", expressed as "rows are selected", and it
|
|
410
|
+
hardcoded 3.5rem for that bar's height; --dashboard's `bottom: 0` only
|
|
411
|
+
existed because the dashboard nav published no height. The tier answers both
|
|
412
|
+
questions directly now. */
|
|
412
413
|
|
|
413
414
|
/* -- Mobile filter overlay --------------------------- */
|
|
414
415
|
|
|
@@ -12,7 +12,9 @@ import { type ReactNode } from "react";
|
|
|
12
12
|
* Dismiss/hide: pass `dismissible` (with a stable `id`) to let the user
|
|
13
13
|
* collapse the bar to a thin re-expand strip for the rest of the browser
|
|
14
14
|
* session — a viewport-annoyance-avoidance toggle, not a durable
|
|
15
|
-
* preference, so it resets on reload rather than persisting forever.
|
|
15
|
+
* preference, so it resets on reload rather than persisting forever. Both
|
|
16
|
+
* directions render the same centred, labelled strip ("Hide Toolbar" /
|
|
17
|
+
* "Show Toolbar") so the control is symmetric and self-describing. This
|
|
16
18
|
* is what closes the mobile-overlap complaint the sticky toolbar pattern
|
|
17
19
|
* caused across listing pages: at narrow widths, any sticky bar competing
|
|
18
20
|
* with page content for vertical space needs a way out that doesn't require
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { ChevronDown } from "lucide-react";
|
|
5
5
|
import { normalizeError } from "../../errors/normalize";
|
|
6
6
|
const TONE_CLS = {
|
|
@@ -24,19 +24,22 @@ function resolveOffsetClass(offset) {
|
|
|
24
24
|
return "top-[calc(var(--header-height,0px)+var(--appkit-navbar-height,2.5rem))]";
|
|
25
25
|
}
|
|
26
26
|
if (offset === "header+pagination") {
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
|
|
27
|
+
// The sticky pagination-row offset repeated verbatim across every
|
|
28
|
+
// DataListingView-style index listing — consolidated here instead of
|
|
29
|
+
// copy-pasted. It tracks the toolbar's REAL height via
|
|
30
|
+
// --appkit-toolbar-height, which a dismissible StickyToolbar publishes
|
|
31
|
+
// from its own ResizeObserver (see TOOLBAR_HEIGHT_VAR below). A fixed
|
|
32
|
+
// constant can only ever be right in one state: the toolbar is ~64px
|
|
33
|
+
// expanded but ~20px collapsed, so hard-coding 64px left a ~44px gap
|
|
34
|
+
// through which page content scrolled between the two pinned bars.
|
|
35
|
+
// The 64px fallback is the expanded height, used on any page whose
|
|
36
|
+
// toolbar isn't dismissible and therefore publishes nothing.
|
|
37
|
+
return "top-[calc(var(--header-height,0px)+var(--appkit-toolbar-height,64px))]";
|
|
35
38
|
}
|
|
36
39
|
if (offset === "header+bulk-actions") {
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
return "top-[calc(var(--header-height,0px)+
|
|
40
|
+
// Stacks below both the filter toolbar (same variable as above) and the
|
|
41
|
+
// pagination row between them (~52px).
|
|
42
|
+
return "top-[calc(var(--header-height,0px)+var(--appkit-toolbar-height,64px)+52px)]";
|
|
40
43
|
}
|
|
41
44
|
// Numeric offsets are applied via inline style instead (see below) —
|
|
42
45
|
// Tailwind's static scanner can never see a dynamically-interpolated
|
|
@@ -44,6 +47,13 @@ function resolveOffsetClass(offset) {
|
|
|
44
47
|
// generated for it in the compiled stylesheet.
|
|
45
48
|
return "";
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Written to `<html>` by every dismissible StickyToolbar from a
|
|
52
|
+
* ResizeObserver, and consumed by the `header+pagination` /
|
|
53
|
+
* `header+bulk-actions` offsets so a bar stacked underneath tracks the real
|
|
54
|
+
* height in both the expanded and collapsed states.
|
|
55
|
+
*/
|
|
56
|
+
const TOOLBAR_HEIGHT_VAR = "--appkit-toolbar-height";
|
|
47
57
|
const STORAGE_PREFIX = "appkit:sticky-toolbar-collapsed:";
|
|
48
58
|
function readCollapsed(id) {
|
|
49
59
|
if (typeof window === "undefined")
|
|
@@ -69,12 +79,45 @@ function writeCollapsed(id, value) {
|
|
|
69
79
|
// works for the current render, just doesn't survive a re-mount.
|
|
70
80
|
}
|
|
71
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* The collapse/expand control — one component for both states so the two
|
|
84
|
+
* halves of the affordance can't drift apart (the collapsed strip read
|
|
85
|
+
* "Show Toolbar" while the expanded one was a bare, unlabelled chevron
|
|
86
|
+
* pinned to the far right until 2026-08-24).
|
|
87
|
+
*/
|
|
88
|
+
function CollapseStrip({ collapsed, label, onToggle, className, }) {
|
|
89
|
+
return (_jsx("div", { className: `flex justify-center ${className ?? ""}`, children: _jsxs("button", { type: "button", onClick: onToggle, "aria-label": `${collapsed ? "Show" : "Hide"} ${label}`, "aria-expanded": !collapsed, className: "flex items-center gap-1 px-4 py-0.5 text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)]", children: [_jsx(ChevronDown, { className: `h-3.5 w-3.5 transition-transform duration-150 ${collapsed ? "" : "rotate-180"}`, "aria-hidden": "true" }), collapsed ? "Show" : "Hide", " ", label] }) }));
|
|
90
|
+
}
|
|
72
91
|
export function StickyToolbar({ children, offset = "header", tone = "translucent", border = true, padding = "toolbar", z = "above-content", role, className, dataTestId, dismissible = false, id, label = "Toolbar", }) {
|
|
73
92
|
const [collapsed, setCollapsed] = useState(false);
|
|
93
|
+
const rootRef = useRef(null);
|
|
74
94
|
useEffect(() => {
|
|
75
95
|
if (dismissible && id)
|
|
76
96
|
setCollapsed(readCollapsed(id));
|
|
77
97
|
}, [dismissible, id]);
|
|
98
|
+
// Publish the rendered height so a bar stacked below (sticky pagination,
|
|
99
|
+
// bulk-action bar) can offset itself against what's actually on screen.
|
|
100
|
+
// `collapsed` is a dependency because the two states are distinct elements
|
|
101
|
+
// — React remounts the node, so the observer must re-attach to the new one.
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!dismissible || !id)
|
|
104
|
+
return;
|
|
105
|
+
const el = rootRef.current;
|
|
106
|
+
if (!el)
|
|
107
|
+
return;
|
|
108
|
+
const write = () => {
|
|
109
|
+
document.documentElement.style.setProperty(TOOLBAR_HEIGHT_VAR, `${Math.round(el.getBoundingClientRect().height)}px`);
|
|
110
|
+
};
|
|
111
|
+
write();
|
|
112
|
+
const observer = new ResizeObserver(write);
|
|
113
|
+
observer.observe(el);
|
|
114
|
+
return () => {
|
|
115
|
+
observer.disconnect();
|
|
116
|
+
// Drop it on unmount so a route with no dismissible toolbar falls back
|
|
117
|
+
// to the 64px default instead of inheriting the previous page's value.
|
|
118
|
+
document.documentElement.style.removeProperty(TOOLBAR_HEIGHT_VAR);
|
|
119
|
+
};
|
|
120
|
+
}, [dismissible, id, collapsed]);
|
|
78
121
|
const offsetCls = resolveOffsetClass(offset);
|
|
79
122
|
const offsetStyle = typeof offset === "number" ? { top: `${offset}px` } : undefined;
|
|
80
123
|
const borderCls = border ? "border-b border-[var(--appkit-color-border)]" : "";
|
|
@@ -86,15 +129,14 @@ export function StickyToolbar({ children, offset = "header", tone = "translucent
|
|
|
86
129
|
writeCollapsed(id, next);
|
|
87
130
|
};
|
|
88
131
|
if (dismissible && id && collapsed) {
|
|
89
|
-
return (_jsx("div", { "data-testid": dataTestId, style: offsetStyle, className: `sticky ${offsetCls} ${zCls} ${TONE_CLS[tone]} ${borderCls}
|
|
132
|
+
return (_jsx("div", { ref: rootRef, "data-testid": dataTestId, style: offsetStyle, className: `sticky ${offsetCls} ${zCls} ${TONE_CLS[tone]} ${borderCls}`, children: _jsx(CollapseStrip, { collapsed: true, label: label, onToggle: toggle }) }));
|
|
90
133
|
}
|
|
91
|
-
return (_jsxs("div", { role: role, "data-testid": dataTestId, style: offsetStyle,
|
|
134
|
+
return (_jsxs("div", { ref: rootRef, role: role, "data-testid": dataTestId, style: offsetStyle,
|
|
92
135
|
// for the translucent sticky-toolbar pattern. The header offset is
|
|
93
136
|
// sourced from --header-height (set by AppLayoutShell at runtime).
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
className: `sticky ${offsetCls} ${zCls} ${TONE_CLS[tone]} ${borderCls} ${PADDING_CLS[padding]} ${dismissible ? "relative pr-8" : ""} ${className ?? ""}`, children: [children, dismissible && id && (_jsx("button", { type: "button", onClick: toggle, "aria-label": `Hide ${label}`, "aria-expanded": true, className: "absolute right-1.5 top-1/2 -translate-y-1/2 rounded p-1 text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-surface-elevated)] hover:text-[var(--appkit-color-text)]", children: _jsx(ChevronDown, { className: "h-3.5 w-3.5 rotate-180 transition-transform duration-150", "aria-hidden": "true" }) }))] }));
|
|
137
|
+
// The collapse control is a full-width strip appended AFTER `children`
|
|
138
|
+
// rather than an element positioned over them, so it never competes
|
|
139
|
+
// with the internal Row/Div layout each of the 27+ migrated call sites
|
|
140
|
+
// brings of its own.
|
|
141
|
+
className: `sticky ${offsetCls} ${zCls} ${TONE_CLS[tone]} ${borderCls} ${PADDING_CLS[padding]} ${className ?? ""}`, children: [children, dismissible && id && (_jsx(CollapseStrip, { collapsed: false, label: label, onToggle: toggle, className: "mt-1.5" }))] }));
|
|
100
142
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The portal target inside `<BottomChrome>` — the middle tier of the bottom
|
|
3
|
+
* edge, between the nav bar and BackToTop.
|
|
4
|
+
*
|
|
5
|
+
* Bars that live in the app shell (BottomActions) are rendered as children of
|
|
6
|
+
* the tier directly. Bars authored deep in the tree (ListingLayout's mobile
|
|
7
|
+
* pagination) portal into this node instead, so the tier still measures them
|
|
8
|
+
* and every offset above stays correct.
|
|
9
|
+
*
|
|
10
|
+
* This lives in `ui/` rather than next to `<BottomChrome>` in `features/layout/`
|
|
11
|
+
* on purpose: `features/layout` imports from `ui`, so a `ui` component reaching
|
|
12
|
+
* back into `features/layout` would close an import cycle through the `ui`
|
|
13
|
+
* barrel. Nothing here imports anything but React.
|
|
14
|
+
*/
|
|
15
|
+
export declare const BOTTOM_CHROME_SLOT_ID = "appkit-bottom-chrome-slot";
|
|
16
|
+
/**
|
|
17
|
+
* Resolves the tier's portal target. Returns `null` until after mount, so a
|
|
18
|
+
* consumer never touches the DOM during render — render nothing while it is
|
|
19
|
+
* null, and portal into it once it resolves.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useBottomChromeSlot(): HTMLElement | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* The portal target inside `<BottomChrome>` — the middle tier of the bottom
|
|
5
|
+
* edge, between the nav bar and BackToTop.
|
|
6
|
+
*
|
|
7
|
+
* Bars that live in the app shell (BottomActions) are rendered as children of
|
|
8
|
+
* the tier directly. Bars authored deep in the tree (ListingLayout's mobile
|
|
9
|
+
* pagination) portal into this node instead, so the tier still measures them
|
|
10
|
+
* and every offset above stays correct.
|
|
11
|
+
*
|
|
12
|
+
* This lives in `ui/` rather than next to `<BottomChrome>` in `features/layout/`
|
|
13
|
+
* on purpose: `features/layout` imports from `ui`, so a `ui` component reaching
|
|
14
|
+
* back into `features/layout` would close an import cycle through the `ui`
|
|
15
|
+
* barrel. Nothing here imports anything but React.
|
|
16
|
+
*/
|
|
17
|
+
export const BOTTOM_CHROME_SLOT_ID = "appkit-bottom-chrome-slot";
|
|
18
|
+
/**
|
|
19
|
+
* Resolves the tier's portal target. Returns `null` until after mount, so a
|
|
20
|
+
* consumer never touches the DOM during render — render nothing while it is
|
|
21
|
+
* null, and portal into it once it resolves.
|
|
22
|
+
*/
|
|
23
|
+
export function useBottomChromeSlot() {
|
|
24
|
+
const [slot, setSlot] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
setSlot(document.getElementById(BOTTOM_CHROME_SLOT_ID));
|
|
27
|
+
}, []);
|
|
28
|
+
return slot;
|
|
29
|
+
}
|
|
@@ -74,3 +74,6 @@
|
|
|
74
74
|
@import "./UnsavedChangesModal.style.css";
|
|
75
75
|
@import "../DataTable.style.css";
|
|
76
76
|
@import "../rich-text/RichText.style.css";
|
|
77
|
+
/* Last on purpose: hand-mode rules are cross-cutting overrides keyed on
|
|
78
|
+
`[data-hand]`, not a component's own base styles. */
|
|
79
|
+
@import "./HandMode.style.css";
|
|
@@ -1,19 +1,37 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
2
|
import type { FormValues } from "../../schemas/types";
|
|
3
3
|
/**
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* A navigable form segment — a wizard step historically, a `<SectionForm>`
|
|
5
|
+
* section today. `FormShellContextValue.steps` carries these purely so
|
|
6
|
+
* `<FormErrorSummary>` can name the segment that owns an error and offer a
|
|
7
|
+
* jump link.
|
|
8
|
+
*
|
|
9
|
+
* `content` is optional because the common producer (`useSectionFormNav`)
|
|
10
|
+
* builds descriptors from section metadata alone — it has an id and a label
|
|
11
|
+
* to render in the summary, and no node to hand over. Requiring a node here
|
|
12
|
+
* is what previously forced both context producers to give up and populate
|
|
13
|
+
* `steps: []`, which silently disabled the jump link everywhere.
|
|
10
14
|
*/
|
|
11
15
|
export interface FormShellStep {
|
|
12
16
|
id: string;
|
|
13
17
|
label: string;
|
|
14
18
|
/** Field names required in this step — drives publish gate + error badge */
|
|
15
19
|
requiredFields?: string[];
|
|
16
|
-
content
|
|
20
|
+
content?: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Navigation wiring for a form split into steps or collapsible sections.
|
|
24
|
+
*
|
|
25
|
+
* Supplying this is what makes `<FormErrorSummary>`'s "jump to section" link
|
|
26
|
+
* work: it needs `sections` to name the owning segment and `onGoToSection` to
|
|
27
|
+
* actually move there. Omit it for single-segment forms — the summary then
|
|
28
|
+
* renders a flat list, which is correct for them.
|
|
29
|
+
*/
|
|
30
|
+
export interface FormShellNav {
|
|
31
|
+
sections?: FormShellStep[];
|
|
32
|
+
onGoToSection?: (index: number) => void;
|
|
33
|
+
/** Maps a (dotted) error key to the index of the section that owns it. */
|
|
34
|
+
fieldToSectionIndex?: Record<string, number>;
|
|
17
35
|
}
|
|
18
36
|
export interface FormShellContextValue {
|
|
19
37
|
errors: Record<string, string>;
|
|
@@ -73,12 +91,17 @@ export declare function applyZodIssues(issues: ReadonlyArray<{
|
|
|
73
91
|
message: string;
|
|
74
92
|
}>, setFieldError: (name: string, error: string | null) => void): void;
|
|
75
93
|
/**
|
|
76
|
-
* `useFormShellState(schema?)` — caller-owned form state with optional
|
|
77
|
-
* validation. When a schema is supplied, `validate(values)` runs it and
|
|
78
|
-
* issues into the FormShellContext error map. `audit-form-schema`
|
|
79
|
-
* every callsite to pass a schema.
|
|
94
|
+
* `useFormShellState(schema?, nav?)` — caller-owned form state with optional
|
|
95
|
+
* Zod validation. When a schema is supplied, `validate(values)` runs it and
|
|
96
|
+
* pipes issues into the FormShellContext error map. `audit-form-schema`
|
|
97
|
+
* requires every callsite to pass a schema.
|
|
98
|
+
*
|
|
99
|
+
* Pass `nav` when the form is split into sections (see `useSectionFormNav`)
|
|
100
|
+
* so `<FormErrorSummary>` can name the owning section and jump to it. Omit it
|
|
101
|
+
* for single-segment forms; the summary renders a flat list, which is right
|
|
102
|
+
* for them.
|
|
80
103
|
*/
|
|
81
|
-
export declare function useFormShellState<TSchema extends import("zod").ZodTypeAny = import("zod").ZodTypeAny>(schema?: TSchema): UseFormShellStateResult;
|
|
104
|
+
export declare function useFormShellState<TSchema extends import("zod").ZodTypeAny = import("zod").ZodTypeAny>(schema?: TSchema, nav?: FormShellNav): UseFormShellStateResult;
|
|
82
105
|
export interface FormShellProviderProps {
|
|
83
106
|
children: ReactNode;
|
|
84
107
|
/** Called on debounced auto-save when isDirty changes */
|
|
@@ -105,5 +128,12 @@ export interface FormShellProviderProps {
|
|
|
105
128
|
fieldToStepIndex?: Record<string, number>;
|
|
106
129
|
/** Wired into `FormShellContextValue.goToStep` when the caller has real step navigation to drive (e.g. a step-wizard's `setCurrentStep`). */
|
|
107
130
|
onGoToStep?: (n: number) => void;
|
|
131
|
+
/**
|
|
132
|
+
* The navigable segments this form is split into, in order. Without these
|
|
133
|
+
* `<FormErrorSummary>` can call `goToStep(i)` but has no label to render for
|
|
134
|
+
* segment `i`, so it silently falls back to a flat list — which is why this
|
|
135
|
+
* used to be hardcoded `[]`. Supply alongside `fieldToStepIndex`.
|
|
136
|
+
*/
|
|
137
|
+
sections?: FormShellStep[];
|
|
108
138
|
}
|
|
109
|
-
export declare function FormShellProvider({ children, onSaveDraft, isDirty, autoSaveDelayMs, values, schema, fieldToStepIndex, onGoToStep, }: FormShellProviderProps): React.JSX.Element;
|
|
139
|
+
export declare function FormShellProvider({ children, onSaveDraft, isDirty, autoSaveDelayMs, values, schema, fieldToStepIndex, onGoToStep, sections, }: FormShellProviderProps): React.JSX.Element;
|