@mohasinac/appkit 4.27.0 → 4.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +16 -16
  2. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +29 -6
  3. package/dist/_internal/client/features/lottery/LotteryListView.js +13 -1
  4. package/dist/_internal/server/features/checkout/actions.js +6 -4
  5. package/dist/_internal/server/features/classified/metadata.js +3 -1
  6. package/dist/_internal/server/features/digital-code/metadata.js +3 -1
  7. package/dist/_internal/server/features/live/metadata.js +3 -1
  8. package/dist/_internal/server/features/refunds/actions.js +3 -2
  9. package/dist/_internal/server/features/reviews/actions.js +3 -2
  10. package/dist/_internal/server/features/seo/sitemap.js +189 -40
  11. package/dist/_internal/server/jobs/core/listingProcessor.d.ts +0 -1
  12. package/dist/_internal/server/jobs/core/listingProcessor.js +19 -1
  13. package/dist/_internal/shared/actions/action-registry.js +14 -0
  14. package/dist/_internal/shared/checkout/order-math.d.ts +25 -3
  15. package/dist/_internal/shared/features/checkout/config.d.ts +3 -3
  16. package/dist/_internal/shared/features/checkout/config.js +6 -3
  17. package/dist/client.d.ts +32 -2
  18. package/dist/client.js +37 -2
  19. package/dist/constants/api-endpoints.d.ts +21 -3
  20. package/dist/constants/api-endpoints.js +14 -1
  21. package/dist/constants/field-names.d.ts +2 -2
  22. package/dist/constants/field-names.js +2 -2
  23. package/dist/core/newsletter.repository.js +14 -1
  24. package/dist/features/about/components/FAQPageView.js +1 -1
  25. package/dist/features/about/components/FeesView.js +1 -1
  26. package/dist/features/account/components/AddressForm.d.ts +2 -0
  27. package/dist/features/account/components/AddressForm.js +5 -1
  28. package/dist/features/account/components/UserBidsView.js +1 -1
  29. package/dist/features/account/components/UserSidebar.js +1 -1
  30. package/dist/features/account/components/UserSupportView.js +24 -2
  31. package/dist/features/account/hooks/useAddresses.d.ts +29 -1
  32. package/dist/features/account/hooks/useAddresses.js +4 -1
  33. package/dist/features/account/hooks/useProfile.d.ts +1 -1
  34. package/dist/features/account/hooks/useProfile.js +1 -1
  35. package/dist/features/addresses/repository/addresses.repository.d.ts +13 -0
  36. package/dist/features/addresses/repository/addresses.repository.js +19 -0
  37. package/dist/features/admin/actions/chat-actions.js +5 -1
  38. package/dist/features/admin/components/AdminAdsView.js +1 -1
  39. package/dist/features/admin/components/AdminBidsView.js +6 -1
  40. package/dist/features/admin/components/AdminCarouselGroupEditorView.d.ts +9 -1
  41. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +42 -10
  42. package/dist/features/admin/components/AdminCarouselView.js +1 -1
  43. package/dist/features/admin/components/AdminFeatureEditorView.js +1 -1
  44. package/dist/features/admin/components/AdminGroupedListingsView.js +14 -2
  45. package/dist/features/admin/components/AdminSidebar.js +1 -1
  46. package/dist/features/admin/components/AdminViewCards.js +2 -2
  47. package/dist/features/admin/components/DataTable.js +2 -2
  48. package/dist/features/admin/schemas/firestore.js +9 -3
  49. package/dist/features/auctions/actions/bid-actions.js +45 -4
  50. package/dist/features/auctions/components/AuctionBottomActions.d.ts +21 -6
  51. package/dist/features/auctions/components/AuctionBottomActions.js +42 -11
  52. package/dist/features/auctions/components/AuctionDetailPageView.d.ts +8 -3
  53. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  54. package/dist/features/auctions/components/MarketplaceAuctionCard.js +4 -5
  55. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +27 -2
  56. package/dist/features/auctions/components/PlaceBidFormClient.js +42 -20
  57. package/dist/features/auth/components/SocialAuthButtons.js +1 -1
  58. package/dist/features/auth/hooks/useAuth.d.ts +23 -1
  59. package/dist/features/auth/hooks/useAuth.js +27 -1
  60. package/dist/features/auth/permissions/constants.d.ts +1 -1
  61. package/dist/features/auth/permissions/constants.js +3 -0
  62. package/dist/features/auth/repository/session.repository.d.ts +16 -1
  63. package/dist/features/auth/repository/session.repository.js +23 -0
  64. package/dist/features/auth/repository/user.repository.js +13 -2
  65. package/dist/features/blog/components/BlogListView.js +2 -2
  66. package/dist/features/cart/components/CartPriceBreakdown.d.ts +11 -1
  67. package/dist/features/cart/components/CartPriceBreakdown.js +3 -3
  68. package/dist/features/cart/components/StoreAddonsPicker.d.ts +9 -0
  69. package/dist/features/cart/components/StoreAddonsPicker.js +15 -5
  70. package/dist/features/cart/components/index.d.ts +1 -1
  71. package/dist/features/cart/components/index.js +1 -1
  72. package/dist/features/cart/hooks/useGuestCartMerge.d.ts +8 -1
  73. package/dist/features/cart/hooks/useGuestCartMerge.js +2 -1
  74. package/dist/features/cart/utils/line-total.d.ts +25 -0
  75. package/dist/features/cart/utils/line-total.js +26 -0
  76. package/dist/features/catalogue/repository/catalogue.repository.d.ts +12 -0
  77. package/dist/features/catalogue/repository/catalogue.repository.js +15 -0
  78. package/dist/features/categories/components/CategoryTree.js +2 -2
  79. package/dist/features/contact/components/ContactForm.js +1 -1
  80. package/dist/features/copilot/hooks/useCopilotFeedback.d.ts +1 -1
  81. package/dist/features/copilot/hooks/useCopilotFeedback.js +1 -1
  82. package/dist/features/events/components/AdminEventEditorView.js +16 -9
  83. package/dist/features/events/components/AdminEventEntriesView.js +7 -13
  84. package/dist/features/events/components/EventRafflesSection.js +14 -2
  85. package/dist/features/events/components/EventStatusBadge.js +1 -1
  86. package/dist/features/events/components/event-entry-detail-fields.d.ts +24 -0
  87. package/dist/features/events/components/event-entry-detail-fields.js +13 -0
  88. package/dist/features/faq/components/ContactCTA.js +1 -1
  89. package/dist/features/faq/components/FAQHelpfulButtons.js +2 -2
  90. package/dist/features/faq/repository/faqs.repository.d.ts +16 -1
  91. package/dist/features/faq/repository/faqs.repository.js +64 -54
  92. package/dist/features/faq/schemas/firestore.d.ts +3 -2
  93. package/dist/features/faq/schemas/firestore.js +2 -2
  94. package/dist/features/faq/schemas/index.d.ts +3 -3
  95. package/dist/features/faq/schemas/index.js +1 -1
  96. package/dist/features/filters/FilterFacetSection.js +2 -2
  97. package/dist/features/forms/Toggle.js +1 -1
  98. package/dist/features/grouped/components/GroupedListingEditorView.d.ts +18 -0
  99. package/dist/features/grouped/components/GroupedListingEditorView.js +192 -0
  100. package/dist/features/homepage/components/AdvertisementBanner.js +2 -2
  101. package/dist/features/homepage/components/BrandsSection.js +1 -1
  102. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  103. package/dist/features/homepage/components/HomepageCustomerReviewsSection.js +1 -1
  104. package/dist/features/homepage/components/HomepageSectionBoundary.d.ts +39 -0
  105. package/dist/features/homepage/components/HomepageSectionBoundary.js +49 -0
  106. package/dist/features/homepage/components/ShopByCategorySection.js +1 -1
  107. package/dist/features/homepage/components/WelcomeSection.js +1 -1
  108. package/dist/features/homepage/lib/section-renderer.js +2 -1
  109. package/dist/features/layout/AppLayoutShell.js +5 -5
  110. package/dist/features/layout/BottomActions.js +5 -5
  111. package/dist/features/layout/BottomSheet.js +1 -1
  112. package/dist/features/layout/MainNavbar.js +1 -1
  113. package/dist/features/layout/NavbarLayout.js +1 -1
  114. package/dist/features/layout/TitleBarLayout.js +3 -3
  115. package/dist/features/layout/hooks/useFormBottomActions.d.ts +11 -1
  116. package/dist/features/layout/hooks/useFormBottomActions.js +16 -2
  117. package/dist/features/lottery/schemas/config-write.d.ts +141 -0
  118. package/dist/features/lottery/schemas/config-write.js +139 -0
  119. package/dist/features/media/MediaPickerModal.js +3 -1
  120. package/dist/features/media/MediaVideo.js +4 -2
  121. package/dist/features/media/components/MediaSlider.js +1 -1
  122. package/dist/features/orders/components/OrdersList.js +2 -2
  123. package/dist/features/payments/repository/payout.repository.d.ts +11 -1
  124. package/dist/features/payments/repository/payout.repository.js +14 -6
  125. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -2
  126. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  127. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  128. package/dist/features/products/columns/productTableColumns.js +3 -3
  129. package/dist/features/products/components/CompareOverlay.js +1 -1
  130. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  131. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -2
  132. package/dist/features/products/components/PrizeDrawsSection.js +5 -1
  133. package/dist/features/products/components/ProductDetailActions.js +11 -7
  134. package/dist/features/products/components/ProductDetailPageView.js +3 -3
  135. package/dist/features/products/components/ProductFeatureBadges.js +2 -2
  136. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  137. package/dist/features/products/components/ProductFilters.js +15 -8
  138. package/dist/features/products/components/ProductGrid.js +8 -17
  139. package/dist/features/products/components/ProductTabs.js +7 -4
  140. package/dist/features/products/components/ProductTabsShell.js +2 -7
  141. package/dist/features/products/constants/action-defs.d.ts +21 -4
  142. package/dist/features/products/constants/action-defs.js +7 -3
  143. package/dist/features/products/hooks/useRelatedProducts.js +2 -1
  144. package/dist/features/products/repository/products.repository.d.ts +1 -1
  145. package/dist/features/products/repository/products.repository.js +27 -13
  146. package/dist/features/products/schemas/firestore.d.ts +3 -2
  147. package/dist/features/products/schemas/firestore.js +1 -1
  148. package/dist/features/reviews/actions/review-actions.d.ts +8 -1
  149. package/dist/features/reviews/actions/review-actions.js +14 -3
  150. package/dist/features/reviews/components/ReviewDetailShell.js +10 -4
  151. package/dist/features/reviews/components/ReviewModal.js +1 -1
  152. package/dist/features/reviews/repository/reviews.repository.d.ts +25 -1
  153. package/dist/features/reviews/repository/reviews.repository.js +53 -13
  154. package/dist/features/reviews/schemas/firestore.d.ts +6 -0
  155. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  156. package/dist/features/search/components/Search.js +3 -3
  157. package/dist/features/search/components/SearchResultsSection.js +1 -1
  158. package/dist/features/seller/components/SellerAddressesView.js +3 -1
  159. package/dist/features/seller/components/SellerBidsView.js +6 -1
  160. package/dist/features/seller/components/SellerSidebar.js +1 -1
  161. package/dist/features/shell/SectionForm.d.ts +21 -1
  162. package/dist/features/shell/SectionForm.js +15 -3
  163. package/dist/features/shell/build-sections.js +10 -1
  164. package/dist/features/shell/field-ui-meta.d.ts +21 -0
  165. package/dist/features/shipments/components/AdminShipmentLotItemsView.js +23 -6
  166. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  167. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +21 -4
  168. package/dist/features/store-extensions/repository/store-extensions.repositories.js +24 -4
  169. package/dist/features/store-extensions/schemas/shipping-config-form.js +13 -0
  170. package/dist/features/store-extensions/schemas/store-category-form.js +1 -1
  171. package/dist/features/stores/actions/store-query-actions.js +25 -1
  172. package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
  173. package/dist/features/stores/components/StoreHeader.js +1 -1
  174. package/dist/features/stores/components/StoreNavTabs.js +20 -8
  175. package/dist/features/support/repository/support.repository.d.ts +12 -0
  176. package/dist/features/support/repository/support.repository.js +15 -0
  177. package/dist/features/support/schemas/ticket-create-form.d.ts +33 -0
  178. package/dist/features/support/schemas/ticket-create-form.js +82 -0
  179. package/dist/features/tester/seed-data/products-tester-seed-data.js +2 -2
  180. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +138 -1
  181. package/dist/features/wishlist/components/WishlistHeartButton.d.ts +55 -0
  182. package/dist/features/wishlist/components/WishlistHeartButton.js +52 -0
  183. package/dist/features/wishlist/components/index.d.ts +2 -1
  184. package/dist/features/wishlist/components/index.js +1 -1
  185. package/dist/index.d.ts +10 -3
  186. package/dist/index.js +19 -4
  187. package/dist/monitoring/error-tracking.js +39 -5
  188. package/dist/monitoring/server-logger.js +70 -32
  189. package/dist/next/components/ErrorView.js +1 -1
  190. package/dist/next/routing/route-map.d.ts +39 -7
  191. package/dist/next/routing/route-map.js +34 -4
  192. package/dist/providers/db-firebase/base.repository.d.ts +30 -0
  193. package/dist/providers/db-firebase/base.repository.js +56 -9
  194. package/dist/react/ErrorBoundary.js +9 -1
  195. package/dist/react/contexts/SessionContext.js +6 -2
  196. package/dist/react/hooks/useAuthGate.d.ts +22 -0
  197. package/dist/react/hooks/useAuthGate.js +86 -7
  198. package/dist/schemas/registry.d.ts +3 -3
  199. package/dist/security/index.d.ts +1 -1
  200. package/dist/security/index.js +1 -1
  201. package/dist/security/pii-encrypt.d.ts +13 -5
  202. package/dist/security/pii-encrypt.js +132 -6
  203. package/dist/security/pii-schemas.d.ts +20 -4
  204. package/dist/security/pii-schemas.js +23 -5
  205. package/dist/seed/_helpers/product-search-txt.d.ts +18 -0
  206. package/dist/seed/_helpers/product-search-txt.js +33 -0
  207. package/dist/seed/faq-seed-data.d.ts +16 -0
  208. package/dist/seed/faq-seed-data.js +22 -1
  209. package/dist/seed/products-art-seed-data.js +49 -7
  210. package/dist/seed/products-auctions-seed-data.js +12 -4
  211. package/dist/seed/products-classifieds-seed-data.d.ts +5 -0
  212. package/dist/seed/products-classifieds-seed-data.js +65 -9
  213. package/dist/seed/products-digital-codes-seed-data.d.ts +5 -0
  214. package/dist/seed/products-digital-codes-seed-data.js +65 -9
  215. package/dist/seed/products-live-items-seed-data.d.ts +5 -0
  216. package/dist/seed/products-live-items-seed-data.js +33 -5
  217. package/dist/seed/products-preorders-seed-data.d.ts +1 -1
  218. package/dist/seed/products-preorders-seed-data.js +6 -2
  219. package/dist/seed/products-prize-draws-seed-data.d.ts +5 -0
  220. package/dist/seed/products-prize-draws-seed-data.js +57 -8
  221. package/dist/seed/products-standard-seed-data.js +6 -2
  222. package/dist/seed/products-stickers-seed-data.js +49 -7
  223. package/dist/seed/site-settings-seed-data.js +5 -3
  224. package/dist/seo/json-ld.d.ts +44 -2
  225. package/dist/seo/json-ld.js +57 -11
  226. package/dist/styles.css +368 -90
  227. package/dist/tailwind-utilities.css +1 -1
  228. package/dist/tokens/index.d.ts +1 -1
  229. package/dist/tokens/index.js +1 -1
  230. package/dist/tokens/themes/default-dark.js +6 -0
  231. package/dist/tokens/themes/default-light.js +5 -0
  232. package/dist/tokens/tokens.css +84 -0
  233. package/dist/ui/DataTable.js +1 -1
  234. package/dist/ui/DataTable.style.css +3 -3
  235. package/dist/ui/components/BulkActionBar.style.css +1 -3
  236. package/dist/ui/components/Button.js +15 -6
  237. package/dist/ui/components/Dropdown.style.css +1 -4
  238. package/dist/ui/components/FilterChipGroup.js +1 -1
  239. package/dist/ui/components/FilterDrawer.style.css +1 -1
  240. package/dist/ui/components/Icon.d.ts +53 -0
  241. package/dist/ui/components/Icon.js +41 -0
  242. package/dist/ui/components/IconButton.d.ts +13 -0
  243. package/dist/ui/components/IconButton.js +13 -0
  244. package/dist/ui/components/IconButton.style.css +18 -10
  245. package/dist/ui/components/ListingLayout.style.css +2 -10
  246. package/dist/ui/components/ListingToolbar.js +6 -6
  247. package/dist/ui/components/Modal.js +1 -1
  248. package/dist/ui/components/PaginatedSelect.style.css +3 -3
  249. package/dist/ui/components/Pagination.style.css +1 -6
  250. package/dist/ui/components/RichTextEditor.js +1 -1
  251. package/dist/ui/components/RowActionMenu.style.css +1 -1
  252. package/dist/ui/components/SideDrawer.style.css +1 -1
  253. package/dist/ui/components/Slider.js +1 -1
  254. package/dist/ui/components/TabBarShell.d.ts +78 -0
  255. package/dist/ui/components/TabBarShell.js +95 -0
  256. package/dist/ui/components/Tabs.js +12 -8
  257. package/dist/ui/components/Tabs.style.css +249 -41
  258. package/dist/ui/components/ViewToggle.style.css +1 -5
  259. package/dist/ui/components/tabs-overflow.d.ts +17 -0
  260. package/dist/ui/components/tabs-overflow.js +142 -0
  261. package/dist/ui/icons/icon-registry.d.ts +38 -0
  262. package/dist/ui/icons/icon-registry.js +37 -0
  263. package/dist/ui/index.d.ts +6 -0
  264. package/dist/ui/index.js +3 -0
  265. package/dist/utils/index.d.ts +1 -1
  266. package/dist/utils/index.js +1 -1
  267. package/dist/utils/media-url.d.ts +27 -4
  268. package/dist/utils/media-url.js +37 -6
  269. package/dist/utils/search-txt.d.ts +71 -0
  270. package/dist/utils/search-txt.js +118 -0
  271. package/package.json +1 -1
@@ -268,7 +268,7 @@ export declare const LAYOUT: {
268
268
  readonly navbarBg: "bg-[color-mix(in_srgb,var(--appkit-color-bg)_90%,transparent)] backdrop-blur-md border-b border-[var(--appkit-color-border)]";
269
269
  readonly sidebarBg: "bg-[var(--appkit-color-surface)] border-l border-[var(--appkit-color-border-subtle)]";
270
270
  readonly bottomNavBg: "bg-[color-mix(in_srgb,var(--appkit-color-bg)_90%,transparent)] backdrop-blur-md border-t border-[var(--appkit-color-border)]";
271
- readonly footerBg: "bg-zinc-50 bg-[var(--appkit-color-surface)] border-t border-[var(--appkit-color-border-subtle)]";
271
+ readonly footerBg: " bg-[var(--appkit-color-surface)] border-t border-[var(--appkit-color-border-subtle)]";
272
272
  readonly fullScreen: "min-h-screen";
273
273
  readonly flexCenter: "flex items-center justify-center";
274
274
  readonly centerText: "text-center";
@@ -205,7 +205,7 @@ export const LAYOUT = {
205
205
  navbarBg: "bg-[color-mix(in_srgb,var(--appkit-color-bg)_90%,transparent)] backdrop-blur-md border-b border-[var(--appkit-color-border)]",
206
206
  sidebarBg: "bg-[var(--appkit-color-surface)] border-l border-[var(--appkit-color-border-subtle)]",
207
207
  bottomNavBg: "bg-[color-mix(in_srgb,var(--appkit-color-bg)_90%,transparent)] backdrop-blur-md border-t border-[var(--appkit-color-border)]",
208
- footerBg: "bg-zinc-50 bg-[var(--appkit-color-surface)] border-t border-[var(--appkit-color-border-subtle)]",
208
+ footerBg: " bg-[var(--appkit-color-surface)] border-t border-[var(--appkit-color-border-subtle)]",
209
209
  fullScreen: "min-h-screen",
210
210
  flexCenter: "flex items-center justify-center",
211
211
  centerText: "text-center",
@@ -43,6 +43,12 @@ export const DEFAULT_DARK_THEME = {
43
43
  "appkit-color-surface": "#0f172a",
44
44
  "appkit-color-surface-elevated": "rgba(15, 23, 42, 0.9)",
45
45
  "appkit-color-surface-input": "rgba(30, 41, 59, 0.6)",
46
+ // Theme-inverting interactive fills. Must stay byte-identical to the
47
+ // [data-theme="default-dark"] block in tokens.css — audit-theme-drift
48
+ // compares them.
49
+ "appkit-color-surface-hover": "rgba(148, 163, 184, 0.12)",
50
+ "appkit-color-surface-raised": "rgba(30, 41, 59, 0.7)",
51
+ "appkit-color-primary-surface": "rgba(239, 68, 68, 0.16)",
46
52
  "appkit-color-border": "#334155",
47
53
  "appkit-color-border-subtle": "rgba(30, 41, 59, 0.6)",
48
54
  "appkit-color-text": "#fafafa",
@@ -46,6 +46,11 @@ export const DEFAULT_LIGHT_THEME = {
46
46
  "appkit-color-surface": "#ffffff",
47
47
  "appkit-color-surface-elevated": "#ffffff",
48
48
  "appkit-color-surface-input": "#ffffff",
49
+ // Theme-inverting interactive fills. Must stay byte-identical to the
50
+ // matching :root block in tokens.css — audit-theme-drift compares them.
51
+ "appkit-color-surface-hover": "#f4f4f5",
52
+ "appkit-color-surface-raised": "#fafafa",
53
+ "appkit-color-primary-surface": "#f0fdfa",
49
54
  "appkit-color-border": "#e4e4e7",
50
55
  "appkit-color-border-subtle": "#f4f4f5",
51
56
  "appkit-color-text": "#18181b",
@@ -262,6 +262,27 @@
262
262
  --appkit-color-surface-elevated: #ffffff;
263
263
  --appkit-color-surface-input: #ffffff;
264
264
 
265
+ /* --- Interactive surfaces ------------------------------------------------
266
+ * `-hover` is the neutral chrome hover fill; `-raised` is a resting panel one
267
+ * step off the page surface; `primary-surface` is the brand-tinted hover.
268
+ *
269
+ * All three INVERT with the theme, and that is the whole point. A hardcoded
270
+ * a hardcoded `zinc-50` hover fill is near-white in every theme, and sits under
271
+ * `dark:hover:text-*` white ink and is unreadable; `--appkit-color-zinc-*`
272
+ * are declared once under :root and never inverted either. `surface-elevated`
273
+ * is not a substitute — it EQUALS `surface` in default-light and sunset, so a
274
+ * hover built on it does nothing at all in a light theme.
275
+ *
276
+ * `surface-hover` and `surface-raised` were referenced by 10 call sites for a
277
+ * long time while being declared nowhere, so they computed to nothing.
278
+ * NB: never write a closing curly brace in a comment in this file —
279
+ * audit-theme-drift matches each block non-greedily and a brace truncates it.
280
+ */
281
+ --appkit-color-surface-hover: #f4f4f5;
282
+ --appkit-color-surface-raised: #fafafa;
283
+ --appkit-color-primary-surface: #f0fdfa;
284
+
285
+
265
286
  --appkit-color-border: #e4e4e7; /* zinc-200 */
266
287
  --appkit-color-border-subtle: #f4f4f5; /* zinc-100 */
267
288
 
@@ -383,6 +404,27 @@
383
404
  --appkit-color-surface-elevated: rgba(15, 23, 42, 0.9);
384
405
  --appkit-color-surface-input: rgba(30, 41, 59, 0.6); /* slate-800/60 */
385
406
 
407
+ /* --- Interactive surfaces ------------------------------------------------
408
+ * `-hover` is the neutral chrome hover fill; `-raised` is a resting panel one
409
+ * step off the page surface; `primary-surface` is the brand-tinted hover.
410
+ *
411
+ * All three INVERT with the theme, and that is the whole point. A hardcoded
412
+ * a hardcoded `zinc-50` hover fill is near-white in every theme, and sits under
413
+ * `dark:hover:text-*` white ink and is unreadable; `--appkit-color-zinc-*`
414
+ * are declared once under :root and never inverted either. `surface-elevated`
415
+ * is not a substitute — it EQUALS `surface` in default-light and sunset, so a
416
+ * hover built on it does nothing at all in a light theme.
417
+ *
418
+ * `surface-hover` and `surface-raised` were referenced by 10 call sites for a
419
+ * long time while being declared nowhere, so they computed to nothing.
420
+ * NB: never write a closing curly brace in a comment in this file —
421
+ * audit-theme-drift matches each block non-greedily and a brace truncates it.
422
+ */
423
+ --appkit-color-surface-hover: rgba(148, 163, 184, 0.12);
424
+ --appkit-color-surface-raised: rgba(30, 41, 59, 0.7);
425
+ --appkit-color-primary-surface: rgba(239, 68, 68, 0.16);
426
+
427
+
386
428
  --appkit-color-border: #334155; /* slate-700 */
387
429
  --appkit-color-border-subtle: rgba(30, 41, 59, 0.6); /* slate-800/60 */
388
430
 
@@ -479,6 +521,27 @@
479
521
  --appkit-color-surface-elevated: rgba(21, 54, 180, 0.9);
480
522
  --appkit-color-surface-input: rgba(24, 49, 142, 0.6);
481
523
 
524
+ /* --- Interactive surfaces ------------------------------------------------
525
+ * `-hover` is the neutral chrome hover fill; `-raised` is a resting panel one
526
+ * step off the page surface; `primary-surface` is the brand-tinted hover.
527
+ *
528
+ * All three INVERT with the theme, and that is the whole point. A hardcoded
529
+ * a hardcoded `zinc-50` hover fill is near-white in every theme, and sits under
530
+ * `dark:hover:text-*` white ink and is unreadable; `--appkit-color-zinc-*`
531
+ * are declared once under :root and never inverted either. `surface-elevated`
532
+ * is not a substitute — it EQUALS `surface` in default-light and sunset, so a
533
+ * hover built on it does nothing at all in a light theme.
534
+ *
535
+ * `surface-hover` and `surface-raised` were referenced by 10 call sites for a
536
+ * long time while being declared nowhere, so they computed to nothing.
537
+ * NB: never write a closing curly brace in a comment in this file —
538
+ * audit-theme-drift matches each block non-greedily and a brace truncates it.
539
+ */
540
+ --appkit-color-surface-hover: rgba(137, 185, 255, 0.14);
541
+ --appkit-color-surface-raised: rgba(24, 49, 142, 0.7);
542
+ --appkit-color-primary-surface: rgba(89, 146, 255, 0.18);
543
+
544
+
482
545
  --appkit-color-border: #1343de; /* primary-700 */
483
546
  --appkit-color-border-subtle: rgba(24, 49, 142, 0.6);
484
547
 
@@ -518,6 +581,27 @@
518
581
  --appkit-color-surface-elevated: #ffffff;
519
582
  --appkit-color-surface-input: #fffbeb; /* amber-50 */
520
583
 
584
+ /* --- Interactive surfaces ------------------------------------------------
585
+ * `-hover` is the neutral chrome hover fill; `-raised` is a resting panel one
586
+ * step off the page surface; `primary-surface` is the brand-tinted hover.
587
+ *
588
+ * All three INVERT with the theme, and that is the whole point. A hardcoded
589
+ * a hardcoded `zinc-50` hover fill is near-white in every theme, and sits under
590
+ * `dark:hover:text-*` white ink and is unreadable; `--appkit-color-zinc-*`
591
+ * are declared once under :root and never inverted either. `surface-elevated`
592
+ * is not a substitute — it EQUALS `surface` in default-light and sunset, so a
593
+ * hover built on it does nothing at all in a light theme.
594
+ *
595
+ * `surface-hover` and `surface-raised` were referenced by 10 call sites for a
596
+ * long time while being declared nowhere, so they computed to nothing.
597
+ * NB: never write a closing curly brace in a comment in this file —
598
+ * audit-theme-drift matches each block non-greedily and a brace truncates it.
599
+ */
600
+ --appkit-color-surface-hover: #ffedd5;
601
+ --appkit-color-surface-raised: #fff7ed;
602
+ --appkit-color-primary-surface: #fef3c7;
603
+
604
+
521
605
  --appkit-color-border: #fed7aa; /* orange-200 */
522
606
  --appkit-color-border-subtle: #ffedd5; /* orange-100 */
523
607
 
@@ -158,5 +158,5 @@ function SelectableCard({ id, selectable, selected, onToggle, children, listMode
158
158
  selected
159
159
  ? "border-2 border-primary bg-primary"
160
160
  : "border-2 border-zinc-500 dark:border-slate-400 bg-transparent group-hover:border-primary",
161
- ].join(" "), checked: selected, onChange: (e) => onToggle(id, e.target.checked), "aria-label": "Select item" }), selected && (_jsx("svg", { className: "absolute inset-0 m-auto w-2.5 h-2.5 text-white pointer-events-none", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 13l4 4L19 7" }) }))] }) }) }), selected && (_jsx(Div, { className: "absolute inset-0 z-[var(--appkit-z-raised)] ring-2 ring-primary ring-offset-0 pointer-events-none", rounded: "xl", "aria-hidden": "true" })), children] }));
161
+ ].join(" "), checked: selected, onChange: (e) => onToggle(id, e.target.checked), "aria-label": "Select item" }), selected && (_jsx("svg", { className: "absolute inset-0 m-auto h-3 w-3 text-white pointer-events-none", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M5 13l4 4L19 7" }) }))] }) }) }), selected && (_jsx(Div, { className: "absolute inset-0 z-[var(--appkit-z-raised)] ring-2 ring-primary ring-offset-0 pointer-events-none", rounded: "xl", "aria-hidden": "true" })), children] }));
162
162
  }
@@ -63,7 +63,7 @@
63
63
  }
64
64
 
65
65
  .appkit-data-table__th--sortable:hover {
66
- background: var(--appkit-color-zinc-100);
66
+ background: var(--appkit-color-surface-hover);
67
67
  }
68
68
 
69
69
  :is(.dark) .appkit-data-table__th--sortable:hover {
@@ -95,7 +95,7 @@
95
95
  }
96
96
 
97
97
  .appkit-data-table__row--clickable:hover {
98
- background: var(--appkit-color-zinc-50);
98
+ background: var(--appkit-color-surface-hover);
99
99
  }
100
100
 
101
101
  :is(.dark) .appkit-data-table__row--clickable:hover {
@@ -160,7 +160,7 @@
160
160
  }
161
161
 
162
162
  .appkit-data-table__view-btn:hover {
163
- background: var(--appkit-color-zinc-100);
163
+ background: var(--appkit-color-surface-hover);
164
164
  }
165
165
 
166
166
  :is(.dark) .appkit-data-table__view-btn:hover {
@@ -76,7 +76,7 @@
76
76
  transition: background-color 0.15s ease;
77
77
  }
78
78
 
79
- .appkit-bulk-bar__picker-trigger:hover { background: var(--appkit-color-zinc-100); }
79
+ .appkit-bulk-bar__picker-trigger:hover { background: var(--appkit-color-surface-hover); }
80
80
  .appkit-bulk-bar__picker-trigger--danger { color: var(--appkit-color-rose-700); }
81
81
 
82
82
  .appkit-bulk-bar__picker-icon {
@@ -182,8 +182,6 @@
182
182
  background: rgba(30, 41, 59, 0.6);
183
183
  color: var(--appkit-color-text);
184
184
  }
185
-
186
- .dark .appkit-bulk-bar__picker-trigger:hover { background: rgba(51, 65, 85, 0.6); }
187
185
  .dark .appkit-bulk-bar__picker-trigger--danger { color: var(--appkit-color-rose-300); }
188
186
 
189
187
  .dark .appkit-bulk-bar__dropdown {
@@ -7,7 +7,7 @@ import { Loader2 } from "lucide-react";
7
7
  import { surfaceError } from "../../client/api/surface-error";
8
8
  import { useToastSafe } from "./Toast";
9
9
  import { SHADOW_MAP } from "./surface-tokens";
10
- import { resolveIcon } from "../icons/icon-registry";
10
+ import { resolveIcon, ICON_SIZE } from "../icons/icon-registry";
11
11
  function spawnRipple(host, clientX, clientY) {
12
12
  const rect = host.getBoundingClientRect();
13
13
  const size = Math.max(rect.width, rect.height);
@@ -117,11 +117,20 @@ const BUTTON_JUSTIFY_MAP = {
117
117
  * `aria-hidden` because the label (or `ariaLabel`) already names the action;
118
118
  * announcing the glyph as well would read it twice.
119
119
  */
120
- function ActionIcon({ action }) {
121
- const Icon = resolveIcon(action?.iconKey);
122
- if (!Icon)
120
+ /**
121
+ * Icon size follows the BUTTON's size. It used to be hardcoded `h-4 w-4` for
122
+ * every size, so a `lg` button carried the same 16px glyph as an `sm` one.
123
+ */
124
+ const ACTION_ICON_SIZE = {
125
+ sm: "sm",
126
+ md: "md",
127
+ lg: "lg",
128
+ };
129
+ function ActionIcon({ action, size, }) {
130
+ const Glyph = resolveIcon(action?.iconKey);
131
+ if (!Glyph)
123
132
  return null;
124
- return _jsx(Icon, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" });
133
+ return (_jsx(Glyph, { className: `${ICON_SIZE[ACTION_ICON_SIZE[size]]} shrink-0`, "aria-hidden": "true" }));
125
134
  }
126
135
  // Map ActionKind → Button variant (caller can override via explicit variant prop)
127
136
  const ACTION_KIND_VARIANT = {
@@ -151,7 +160,7 @@ export function Button({ variant, size = "md", className = "", isLoading = false
151
160
  * label. If the caller passed children they have composed their own content,
152
161
  * and injecting a glyph into it would be a surprise.
153
162
  */
154
- const actionIcon = children === undefined && action?.iconKey ? _jsx(ActionIcon, { action: action }) : null;
163
+ const actionIcon = children === undefined && action?.iconKey ? _jsx(ActionIcon, { action: action, size: size }) : null;
155
164
  const resolvedChildren = children ??
156
165
  (action ? (actionIcon ? (_jsxs(_Fragment, { children: [actionIcon, action.label] })) : (action.label)) : undefined);
157
166
  const resolvedAriaLabel = props["aria-label"] ?? (action ? (action.ariaLabel ?? action.label) : undefined);
@@ -66,7 +66,7 @@
66
66
  color: var(--appkit-color-zinc-700);
67
67
  }
68
68
  .appkit-dropdown__composed-item:hover {
69
- background: var(--appkit-color-zinc-100);
69
+ background: var(--appkit-color-surface-hover);
70
70
  }
71
71
  .appkit-dropdown__composed-item:disabled {
72
72
  opacity: 0.5;
@@ -102,9 +102,6 @@
102
102
  .dark .appkit-dropdown__composed-item {
103
103
  color: var(--appkit-color-text);
104
104
  }
105
- .dark .appkit-dropdown__composed-item:hover {
106
- background: var(--appkit-color-slate-800);
107
- }
108
105
  .dark .appkit-dropdown__separator {
109
106
  border-color: var(--appkit-color-border);
110
107
  }
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Div } from "./Div";
4
4
  import { Text } from "./Typography";
5
5
  const ACTIVE_CLS = "bg-[var(--appkit-color-primary)] text-white border-[var(--appkit-color-primary)]";
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)]";
6
+ const INACTIVE_CLS = "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-surface-hover";
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
9
  // `opacity-70` rather than a fixed colour so the count stays legible against
@@ -15,7 +15,7 @@
15
15
  }
16
16
 
17
17
  .appkit-filter-drawer__trigger:hover {
18
- background: var(--appkit-color-zinc-100);
18
+ background: var(--appkit-color-surface-hover);
19
19
  }
20
20
 
21
21
  :is(.dark) .appkit-filter-drawer__trigger:hover {
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ import { ICONS, ICON_SIZE, type IconKey, type IconSizeKey } from "../icons/icon-registry";
3
+ /**
4
+ * Ink colour. Deliberately a small enum of THEME-INVERTING tokens rather than
5
+ * open className — a glyph that does not follow the theme is the same defect as
6
+ * a hardcoded `zinc-50` hover background, one property over.
7
+ */
8
+ declare const TONES: {
9
+ readonly current: "";
10
+ readonly default: "text-[var(--appkit-color-text)]";
11
+ readonly muted: "text-[var(--appkit-color-text-muted)]";
12
+ readonly faint: "text-[var(--appkit-color-text-faint)]";
13
+ readonly primary: "text-primary";
14
+ readonly success: "text-success";
15
+ readonly warning: "text-warning";
16
+ readonly error: "text-error";
17
+ readonly info: "text-info";
18
+ /** White ink, for a glyph on a solid brand/status fill or a dark scrim. */
19
+ readonly "on-solid": "text-white";
20
+ };
21
+ export type IconTone = keyof typeof TONES;
22
+ export interface IconProps extends Omit<React.SVGProps<SVGSVGElement>, "ref" | "name"> {
23
+ /** Registry key — a typo is a compile error, not a silent blank. */
24
+ name: IconKey;
25
+ /** Role-based size. See ICON_SIZE for which to pick. */
26
+ size?: IconSizeKey;
27
+ tone?: IconTone;
28
+ /**
29
+ * Filled rather than outlined — the wishlist heart's "saved" state, a
30
+ * rating star, etc. Lucide glyphs are stroked outlines by default.
31
+ */
32
+ filled?: boolean;
33
+ /**
34
+ * Give the glyph an accessible name. OMIT for decorative icons that sit
35
+ * beside a visible text label — the default is `aria-hidden`, because a
36
+ * screen reader announcing "heart, Add to wishlist" is worse than silence.
37
+ */
38
+ label?: string;
39
+ }
40
+ /**
41
+ * The single way to render an icon.
42
+ *
43
+ * 105 files imported `lucide-react` directly and each picked its own size, so
44
+ * "an icon" was whatever that file happened to choose. `icon-registry.ts` was
45
+ * built to be the indirection and had no consumer; this is it.
46
+ *
47
+ * Safe in a Server Component: `lucide-react` is plain CJS with no `"use client"`
48
+ * banner, and this file adds no hooks. Do NOT add state here without also
49
+ * checking every RSC call site (Root Cause #76).
50
+ */
51
+ export declare function Icon({ name, size, tone, filled, label, className, ...rest }: IconProps): React.JSX.Element | null;
52
+ export { ICONS, ICON_SIZE };
53
+ export type { IconKey, IconSizeKey };
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { twMerge } from "tailwind-merge";
3
+ import { ICONS, ICON_SIZE, resolveIcon, } from "../icons/icon-registry";
4
+ /**
5
+ * Ink colour. Deliberately a small enum of THEME-INVERTING tokens rather than
6
+ * open className — a glyph that does not follow the theme is the same defect as
7
+ * a hardcoded `zinc-50` hover background, one property over.
8
+ */
9
+ const TONES = {
10
+ current: "",
11
+ default: "text-[var(--appkit-color-text)]",
12
+ muted: "text-[var(--appkit-color-text-muted)]",
13
+ faint: "text-[var(--appkit-color-text-faint)]",
14
+ primary: "text-primary",
15
+ success: "text-success",
16
+ warning: "text-warning",
17
+ error: "text-error",
18
+ info: "text-info",
19
+ /** White ink, for a glyph on a solid brand/status fill or a dark scrim. */
20
+ "on-solid": "text-white",
21
+ };
22
+ /**
23
+ * The single way to render an icon.
24
+ *
25
+ * 105 files imported `lucide-react` directly and each picked its own size, so
26
+ * "an icon" was whatever that file happened to choose. `icon-registry.ts` was
27
+ * built to be the indirection and had no consumer; this is it.
28
+ *
29
+ * Safe in a Server Component: `lucide-react` is plain CJS with no `"use client"`
30
+ * banner, and this file adds no hooks. Do NOT add state here without also
31
+ * checking every RSC call site (Root Cause #76).
32
+ */
33
+ export function Icon({ name, size = "md", tone = "current", filled = false, label, className = "", ...rest }) {
34
+ const Glyph = resolveIcon(name);
35
+ // `resolveIcon` returns undefined for an unknown key on purpose — render
36
+ // nothing and leave the label intact rather than drawing a broken-image box.
37
+ if (!Glyph)
38
+ return null;
39
+ return (_jsx(Glyph, { className: twMerge(ICON_SIZE[size], TONES[tone], "shrink-0", className), fill: filled ? "currentColor" : "none", "aria-hidden": label ? undefined : true, "aria-label": label, role: label ? "img" : undefined, ...rest }));
40
+ }
41
+ export { ICONS, ICON_SIZE };
@@ -3,8 +3,21 @@ import { type RoundedKey } from "./surface-tokens";
3
3
  declare const SIZES: {
4
4
  readonly sm: "appkit-icon-button--sm";
5
5
  readonly md: "appkit-icon-button--md";
6
+ /** 44px — minimum comfortable tap target. See the CSS for when to use it. */
7
+ readonly touch: "appkit-icon-button--touch";
6
8
  readonly lg: "appkit-icon-button--lg";
7
9
  };
10
+ /**
11
+ * The glyph size each box wants. Callers should let the button decide rather
12
+ * than passing a size to the icon by hand — a mismatched pair (a 14px glyph in
13
+ * a 44px box) is the whole "the icon is very small" report.
14
+ */
15
+ export declare const ICON_BUTTON_ICON_SIZE: {
16
+ readonly sm: "sm";
17
+ readonly md: "md";
18
+ readonly touch: "lg";
19
+ readonly lg: "lg";
20
+ };
8
21
  declare const VARIANTS: {
9
22
  readonly ghost: "appkit-icon-button--ghost";
10
23
  readonly outline: "appkit-icon-button--outline";
@@ -5,8 +5,21 @@ const BASE = "appkit-icon-button";
5
5
  const SIZES = {
6
6
  sm: "appkit-icon-button--sm",
7
7
  md: "appkit-icon-button--md",
8
+ /** 44px — minimum comfortable tap target. See the CSS for when to use it. */
9
+ touch: "appkit-icon-button--touch",
8
10
  lg: "appkit-icon-button--lg",
9
11
  };
12
+ /**
13
+ * The glyph size each box wants. Callers should let the button decide rather
14
+ * than passing a size to the icon by hand — a mismatched pair (a 14px glyph in
15
+ * a 44px box) is the whole "the icon is very small" report.
16
+ */
17
+ export const ICON_BUTTON_ICON_SIZE = {
18
+ sm: "sm",
19
+ md: "md",
20
+ touch: "lg",
21
+ lg: "lg",
22
+ };
10
23
  const VARIANTS = {
11
24
  ghost: "appkit-icon-button--ghost",
12
25
  outline: "appkit-icon-button--outline",
@@ -36,23 +36,35 @@
36
36
  border-radius: 0.75rem;
37
37
  }
38
38
 
39
+ /* 44px — the minimum comfortable tap target. For a control that is the ONLY
40
+ * affordance in its area and has no text label to widen it: a product card's
41
+ * wishlist heart, a media overlay control. Sits between --md and --lg because
42
+ * those are round numbers, not accessibility thresholds.
43
+ *
44
+ * Use IconButton, not Button, for these: `.appkit-button--sm` sets
45
+ * `min-height: 36px`, and under `important: true` a caller's `h-8` (2rem)
46
+ * loses to it — which is how the card heart rendered as a 32x36 ellipse under
47
+ * `rounded-full`. These boxes set `width`+`height` with no min, so they are
48
+ * true squares. */
49
+ .appkit-icon-button--touch {
50
+ width: 2.75rem;
51
+ height: 2.75rem;
52
+ border-radius: 0.75rem;
53
+ }
54
+
39
55
  .appkit-icon-button--ghost {
40
56
  background: transparent;
41
57
  color: var(--appkit-color-zinc-600);
42
58
  }
43
59
 
44
60
  .appkit-icon-button--ghost:hover:not(:disabled) {
45
- background: var(--appkit-color-zinc-100);
61
+ background: var(--appkit-color-surface-hover);
46
62
  }
47
63
 
48
64
  .dark .appkit-icon-button--ghost {
49
65
  color: var(--appkit-color-text-faint);
50
66
  }
51
67
 
52
- .dark .appkit-icon-button--ghost:hover:not(:disabled) {
53
- background: var(--appkit-color-zinc-800);
54
- }
55
-
56
68
  .appkit-icon-button--outline {
57
69
  border-color: var(--appkit-color-border);
58
70
  background: var(--appkit-color-surface);
@@ -60,7 +72,7 @@
60
72
  }
61
73
 
62
74
  .appkit-icon-button--outline:hover:not(:disabled) {
63
- background: var(--appkit-color-zinc-50);
75
+ background: var(--appkit-color-surface-hover);
64
76
  }
65
77
 
66
78
  .dark .appkit-icon-button--outline {
@@ -69,10 +81,6 @@
69
81
  color: var(--appkit-color-zinc-300);
70
82
  }
71
83
 
72
- .dark .appkit-icon-button--outline:hover:not(:disabled) {
73
- background: var(--appkit-color-slate-800);
74
- }
75
-
76
84
  .appkit-icon-button--primary {
77
85
  background: var(--appkit-color-secondary-600);
78
86
  color: var(--appkit-color-text-on-primary);
@@ -184,7 +184,7 @@
184
184
 
185
185
  .appkit-listing-layout__filter-btn:hover {
186
186
  border-color: var(--appkit-color-zinc-300);
187
- background: var(--appkit-color-zinc-50);
187
+ background: var(--appkit-color-surface-hover);
188
188
  }
189
189
 
190
190
  .appkit-listing-layout__filter-btn--active {
@@ -197,10 +197,6 @@
197
197
  border-color: var(--appkit-color-slate-800);
198
198
  color: var(--appkit-color-slate-300);
199
199
  }
200
- .dark .appkit-listing-layout__filter-btn:hover {
201
- border-color: var(--appkit-color-slate-700);
202
- background: rgba(30, 41, 59, 0.6);
203
- }
204
200
 
205
201
  /* -- Filter badge ------------------------------------ */
206
202
 
@@ -494,9 +490,5 @@
494
490
  }
495
491
 
496
492
  .appkit-listing-layout__close-btn:hover {
497
- background: var(--appkit-color-zinc-100);
498
- }
499
-
500
- .dark .appkit-listing-layout__close-btn:hover {
501
- background: var(--appkit-color-slate-800);
493
+ background: var(--appkit-color-surface-hover);
502
494
  }
@@ -6,8 +6,8 @@ import { SortDropdown } from "./SortDropdown";
6
6
  import { Div } from "./Div";
7
7
  import { Span } from "./Typography";
8
8
  import { StickyToolbar } from "./StickyToolbar";
9
- const CLS_CLEAR_LINK = "text-xs text-zinc-400 hover:text-error text-[var(--appkit-color-text-muted)] transition-colors";
10
- const CLS_CLEAR_ICON_BTN = "flex shrink-0 items-center justify-center rounded-lg border border-[var(--appkit-color-border)] p-1.5 sm:p-2 text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)] hover:text-error dark:hover:text-error transition-colors";
9
+ const CLS_CLEAR_LINK = "text-xs hover:text-error text-[var(--appkit-color-text-muted)] transition-colors";
10
+ const CLS_CLEAR_ICON_BTN = "flex shrink-0 items-center justify-center rounded-lg border border-[var(--appkit-color-border)] p-1.5 sm:p-2 text-[var(--appkit-color-text-muted)] hover:bg-surface-hover hover:text-error dark:hover:text-error transition-colors";
11
11
  const DEFAULT_LABELS = {
12
12
  search: "Search",
13
13
  filters: "Filters",
@@ -23,7 +23,7 @@ const DEFAULT_LABELS = {
23
23
  };
24
24
  const VIEW_BTN_BASE = "p-1.5 sm:p-2 transition-colors";
25
25
  const VIEW_BTN_ACTIVE = "bg-[var(--appkit-color-primary)] text-white";
26
- const VIEW_BTN_INACTIVE = "text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text-muted)]";
26
+ const VIEW_BTN_INACTIVE = "text-[var(--appkit-color-text-muted)] hover:bg-surface-hover text-[var(--appkit-color-text-muted)]";
27
27
  export function ListingToolbar({ filterCount = 0, onFiltersClick, searchValue = "", searchPlaceholder = "Search…", onSearchChange, onSearchCommit, onSearchKeyDown, sortValue, sortOptions, onSortChange, view = "grid", onViewChange, hideViewToggle = false, showTableView = false, onResetAll, hasActiveState = false, bulkMode = false, bulkSelectedCount = 0, bulkTotalCount = 0, onBulkSelectAll, onBulkClear, toggles, extra, labels, className = "", dismissible = true, toolbarId, collapseLabel = "Toolbar", }) {
28
28
  const l = { ...DEFAULT_LABELS, ...labels };
29
29
  const pathname = usePathname();
@@ -37,9 +37,9 @@ export function ListingToolbar({ filterCount = 0, onFiltersClick, searchValue =
37
37
  }
38
38
  };
39
39
  const allSelected = bulkTotalCount > 0 && bulkSelectedCount === bulkTotalCount;
40
- return (_jsx(StickyToolbar, { dataTestId: "listing-toolbar", offset: "header", tone: "translucent", border: true, padding: "none", z: "above-toolbar", className: `py-3 px-3 sm:py-3.5 sm:px-4 shadow-sm ${className}`, dismissible: dismissible, id: resolvedToolbarId, label: collapseLabel, children: _jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center gap-2.5 sm:gap-3", children: [bulkMode ? (_jsxs("div", { className: "flex flex-1 items-center gap-2", children: [_jsxs("button", { type: "button", onClick: onBulkSelectAll, className: "flex items-center gap-1.5 rounded-lg border border-[var(--appkit-color-border)] px-3 py-1.5 text-sm font-medium text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)] transition-colors", children: [allSelected
40
+ return (_jsx(StickyToolbar, { dataTestId: "listing-toolbar", offset: "header", tone: "translucent", border: true, padding: "none", z: "above-toolbar", className: `py-3 px-3 sm:py-3.5 sm:px-4 shadow-sm ${className}`, dismissible: dismissible, id: resolvedToolbarId, label: collapseLabel, children: _jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center gap-2.5 sm:gap-3", children: [bulkMode ? (_jsxs("div", { className: "flex flex-1 items-center gap-2", children: [_jsxs("button", { type: "button", onClick: onBulkSelectAll, className: "flex items-center gap-1.5 rounded-lg border border-[var(--appkit-color-border)] px-3 py-1.5 text-sm font-medium text-[var(--appkit-color-text-muted)] hover:bg-surface-hover transition-colors", children: [allSelected
41
41
  ? _jsx(CheckSquare, { className: "h-4 w-4 text-[var(--appkit-color-primary)]" })
42
- : _jsx(Square, { className: "h-4 w-4" }), allSelected ? l.deselectAll : l.selectAll(bulkTotalCount)] }), _jsx(Span, { size: "sm", color: "muted", children: l.selected(bulkSelectedCount) }), _jsx("button", { type: "button", onClick: onBulkClear, className: CLS_CLEAR_LINK, children: l.clearSelection })] })) : onSearchChange ? (_jsxs("div", { className: "flex flex-1 items-center overflow-hidden rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] min-w-0", children: [_jsx("input", { type: "text", value: searchValue, onChange: (e) => onSearchChange(e.target.value), onKeyDown: handleKeyDown, placeholder: searchPlaceholder, className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-zinc-400 outline-none" }), _jsx("button", { type: "button", onClick: onSearchCommit, className: "flex shrink-0 items-center justify-center px-2.5 py-2 text-zinc-400 hover:text-[var(--appkit-color-primary)] transition-colors", "aria-label": l.search, children: _jsx(Search, { className: "h-4 w-4" }) })] })) : null, _jsxs("div", { className: "flex flex-wrap items-center gap-1.5 sm:gap-2 sm:shrink-0", children: [onFiltersClick && (_jsxs("button", { type: "button", onClick: onFiltersClick, className: "relative flex shrink-0 items-center gap-1.5 rounded-lg border border-[var(--appkit-color-border)] px-2.5 py-1.5 sm:px-3.5 sm:py-2 text-sm font-medium text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)] transition-colors", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: l.filters }), filterCount > 0 && (_jsx(Span, { weight: "bold", className: "absolute -top-1.5 -right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-[var(--appkit-color-primary)] text-[10px] text-white", children: filterCount }))] })), sortOptions && sortValue !== undefined && onSortChange && (_jsxs(Div, { className: "flex items-center gap-1.5 text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { size: "xs", className: "hidden md:inline whitespace-nowrap", children: l.sort }), _jsx(SortDropdown, { value: sortValue, onChange: onSortChange, options: sortOptions })] })), !hideViewToggle && onViewChange && (_jsxs("div", { className: "flex items-center rounded-lg border border-[var(--appkit-color-border)] overflow-hidden", children: [_jsx("button", { type: "button", onClick: () => onViewChange("grid"), "aria-label": l.gridView, className: `${VIEW_BTN_BASE} ${view === "grid" ? VIEW_BTN_ACTIVE : VIEW_BTN_INACTIVE}`, children: _jsx(LayoutGrid, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => onViewChange("list"), "aria-label": l.listView, className: `${VIEW_BTN_BASE} ${view === "list" ? VIEW_BTN_ACTIVE : VIEW_BTN_INACTIVE}`, children: _jsx(List, { className: "h-4 w-4" }) }), showTableView && (_jsx("button", { type: "button", onClick: () => onViewChange("table"), "aria-label": l.tableView, className: `${VIEW_BTN_BASE} ${view === "table" ? VIEW_BTN_ACTIVE : VIEW_BTN_INACTIVE}`, children: _jsx(Table2, { className: "h-4 w-4" }) }))] })), onResetAll && hasActiveState && (_jsx("button", { type: "button", onClick: onResetAll, "aria-label": l.resetAll, title: l.resetAll, className: CLS_CLEAR_ICON_BTN, children: _jsx(RotateCcw, { className: "h-4 w-4" }) })), toggles && toggles.length > 0 && (_jsx("div", { className: "flex items-center gap-1", children: toggles.map((t) => (_jsx("button", { type: "button", role: "switch", "aria-checked": t.active, onClick: () => t.onChange(!t.active), className: `rounded-full border px-2.5 py-1 text-xs font-medium transition-colors whitespace-nowrap ${t.active
42
+ : _jsx(Square, { className: "h-4 w-4" }), allSelected ? l.deselectAll : l.selectAll(bulkTotalCount)] }), _jsx(Span, { size: "sm", color: "muted", children: l.selected(bulkSelectedCount) }), _jsx("button", { type: "button", onClick: onBulkClear, className: CLS_CLEAR_LINK, children: l.clearSelection })] })) : onSearchChange ? (_jsxs("div", { className: "flex flex-1 items-center overflow-hidden rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] min-w-0", children: [_jsx("input", { type: "text", value: searchValue, onChange: (e) => onSearchChange(e.target.value), onKeyDown: handleKeyDown, placeholder: searchPlaceholder, className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-zinc-400 outline-none" }), _jsx("button", { type: "button", onClick: onSearchCommit, className: "flex shrink-0 items-center justify-center px-2.5 py-2 text-zinc-400 hover:text-[var(--appkit-color-primary)] transition-colors", "aria-label": l.search, children: _jsx(Search, { className: "h-4 w-4" }) })] })) : null, _jsxs("div", { className: "flex flex-wrap items-center gap-1.5 sm:gap-2 sm:shrink-0", children: [onFiltersClick && (_jsxs("button", { type: "button", onClick: onFiltersClick, className: "relative flex shrink-0 items-center gap-1.5 rounded-lg border border-[var(--appkit-color-border)] px-2.5 py-1.5 sm:px-3.5 sm:py-2 text-sm font-medium text-[var(--appkit-color-text-muted)] hover:bg-surface-hover transition-colors", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: l.filters }), filterCount > 0 && (_jsx(Span, { weight: "bold", className: "absolute -top-1.5 -right-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-[var(--appkit-color-primary)] text-[10px] text-white", children: filterCount }))] })), sortOptions && sortValue !== undefined && onSortChange && (_jsxs(Div, { className: "flex items-center gap-1.5 text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { size: "xs", className: "hidden md:inline whitespace-nowrap", children: l.sort }), _jsx(SortDropdown, { value: sortValue, onChange: onSortChange, options: sortOptions })] })), !hideViewToggle && onViewChange && (_jsxs("div", { className: "flex items-center rounded-lg border border-[var(--appkit-color-border)] overflow-hidden", children: [_jsx("button", { type: "button", onClick: () => onViewChange("grid"), "aria-label": l.gridView, className: `${VIEW_BTN_BASE} ${view === "grid" ? VIEW_BTN_ACTIVE : VIEW_BTN_INACTIVE}`, children: _jsx(LayoutGrid, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => onViewChange("list"), "aria-label": l.listView, className: `${VIEW_BTN_BASE} ${view === "list" ? VIEW_BTN_ACTIVE : VIEW_BTN_INACTIVE}`, children: _jsx(List, { className: "h-4 w-4" }) }), showTableView && (_jsx("button", { type: "button", onClick: () => onViewChange("table"), "aria-label": l.tableView, className: `${VIEW_BTN_BASE} ${view === "table" ? VIEW_BTN_ACTIVE : VIEW_BTN_INACTIVE}`, children: _jsx(Table2, { className: "h-4 w-4" }) }))] })), onResetAll && hasActiveState && (_jsx("button", { type: "button", onClick: onResetAll, "aria-label": l.resetAll, title: l.resetAll, className: CLS_CLEAR_ICON_BTN, children: _jsx(RotateCcw, { className: "h-4 w-4" }) })), toggles && toggles.length > 0 && (_jsx("div", { className: "flex items-center gap-1", children: toggles.map((t) => (_jsx("button", { type: "button", role: "switch", "aria-checked": t.active, onClick: () => t.onChange(!t.active), className: `rounded-full border px-2.5 py-1 text-xs font-medium transition-colors whitespace-nowrap ${t.active
43
43
  ? "border-transparent bg-[var(--appkit-color-primary)] text-white"
44
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: t.label }, t.label))) })), extra] })] }) }));
44
+ : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-surface-hover"}`, children: t.label }, t.label))) })), extra] })] }) }));
45
45
  }
@@ -76,7 +76,7 @@ export function Modal({ isOpen, open, onClose, title, children, size = "md", sho
76
76
  }
77
77
  export function ModalFooter({ children, className = "", }) {
78
78
  return (_jsx("div", { className: [
79
- "flex items-center justify-end gap-3 border-t border-zinc-100 px-6 py-4 border-[var(--appkit-color-border-subtle)]",
79
+ "flex items-center justify-end gap-3 border-t px-6 py-4 border-[var(--appkit-color-border-subtle)]",
80
80
  className,
81
81
  ]
82
82
  .filter(Boolean)
@@ -48,7 +48,7 @@
48
48
 
49
49
  .appkit-ps__chip-remove:hover {
50
50
  color: var(--appkit-color-text);
51
- background-color: var(--appkit-color-zinc-100);
51
+ background-color: var(--appkit-color-surface-hover);
52
52
  }
53
53
 
54
54
  :is(.dark) .appkit-ps__chip-remove:hover {
@@ -167,7 +167,7 @@
167
167
  }
168
168
 
169
169
  .appkit-ps__option:hover {
170
- background-color: var(--appkit-color-zinc-100);
170
+ background-color: var(--appkit-color-surface-hover);
171
171
  }
172
172
 
173
173
  :is(.dark) .appkit-ps__option:hover {
@@ -254,7 +254,7 @@
254
254
  }
255
255
 
256
256
  .appkit-ps__create-btn:hover {
257
- background-color: var(--appkit-color-zinc-50);
257
+ background-color: var(--appkit-color-surface-hover);
258
258
  }
259
259
 
260
260
  :is(.dark) .appkit-ps__create-btn:hover {
@@ -22,7 +22,7 @@
22
22
  }
23
23
 
24
24
  .appkit-pagination__button--default:hover {
25
- background: var(--appkit-color-zinc-50);
25
+ background: var(--appkit-color-surface-hover);
26
26
  border-color: var(--appkit-color-zinc-300);
27
27
  }
28
28
 
@@ -55,11 +55,6 @@
55
55
  color: var(--appkit-color-slate-300);
56
56
  }
57
57
 
58
- .dark .appkit-pagination__button--default:hover {
59
- background: var(--appkit-color-slate-800);
60
- border-color: var(--appkit-color-slate-600);
61
- }
62
-
63
58
  .dark .appkit-pagination__button--active {
64
59
  background: var(--appkit-color-primary);
65
60
  border-color: var(--appkit-color-primary);