@mohasinac/appkit 4.61.0 → 4.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +19 -3
  3. package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +1 -1
  4. package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +1 -1
  5. package/dist/_internal/server/features/checkout/actions.d.ts +80 -0
  6. package/dist/_internal/server/features/checkout/actions.js +542 -26
  7. package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
  8. package/dist/_internal/server/features/invoicing/allocate.js +162 -0
  9. package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
  10. package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
  11. package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
  12. package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
  13. package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
  14. package/dist/_internal/server/features/invoicing/issue.js +202 -0
  15. package/dist/_internal/server/features/orders/actions.d.ts +8 -1
  16. package/dist/_internal/server/features/orders/actions.js +81 -8
  17. package/dist/_internal/server/features/orders/adapters.js +33 -0
  18. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
  19. package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
  20. package/dist/_internal/server/features/points/award.js +46 -4
  21. package/dist/_internal/server/features/refunds/actions.js +26 -0
  22. package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
  23. package/dist/_internal/server/features/shipping/courier-block.js +239 -0
  24. package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
  25. package/dist/_internal/server/features/site-settings/adapters.js +15 -0
  26. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  27. package/dist/_internal/server/features/stores/adapters.js +51 -0
  28. package/dist/_internal/server/functions/scheduled.js +38 -1
  29. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +9 -2
  30. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
  31. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
  32. package/dist/_internal/server/jobs/core/index.d.ts +2 -1
  33. package/dist/_internal/server/jobs/core/index.js +2 -1
  34. package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
  35. package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
  36. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
  37. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +62 -0
  38. package/dist/_internal/server/jobs/core/paymentReconcile.js +87 -97
  39. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
  40. package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
  41. package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
  42. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +10 -2
  43. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
  44. package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
  45. package/dist/_internal/shared/actions/action-registry.js +177 -9
  46. package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
  47. package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
  48. package/dist/_internal/shared/checkout/order-math.d.ts +145 -0
  49. package/dist/_internal/shared/checkout/order-math.js +173 -0
  50. package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
  51. package/dist/_internal/shared/checkout/refundable-base.js +13 -1
  52. package/dist/_internal/shared/checkout/split.d.ts +87 -0
  53. package/dist/_internal/shared/checkout/split.js +100 -0
  54. package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
  55. package/dist/_internal/shared/content/disclaimers.js +217 -0
  56. package/dist/_internal/shared/content/published-values.d.ts +88 -0
  57. package/dist/_internal/shared/content/published-values.js +198 -0
  58. package/dist/_internal/shared/features/admin/integrations.d.ts +109 -0
  59. package/dist/_internal/shared/features/admin/integrations.js +253 -0
  60. package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
  61. package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
  62. package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
  63. package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
  64. package/dist/_internal/shared/features/points/accepts.d.ts +36 -0
  65. package/dist/_internal/shared/features/points/accepts.js +43 -0
  66. package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
  67. package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
  68. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  69. package/dist/_internal/shared/fees/calculator.d.ts +33 -1
  70. package/dist/_internal/shared/fees/calculator.js +32 -2
  71. package/dist/_internal/shared/media/limits.d.ts +10 -0
  72. package/dist/_internal/shared/media/limits.js +10 -0
  73. package/dist/_internal/shared/types/action-result.js +15 -1
  74. package/dist/client/api/surface-error.js +16 -2
  75. package/dist/client/api/useApiMutation.js +17 -1
  76. package/dist/client.d.ts +12 -1
  77. package/dist/client.js +31 -1
  78. package/dist/constants/api-endpoints.d.ts +45 -0
  79. package/dist/constants/api-endpoints.js +15 -0
  80. package/dist/constants/field-names.d.ts +18 -0
  81. package/dist/constants/field-names.js +28 -0
  82. package/dist/contracts/index.d.ts +1 -1
  83. package/dist/contracts/shipping.d.ts +45 -0
  84. package/dist/contracts/shipping.js +15 -0
  85. package/dist/core/server-action.js +19 -3
  86. package/dist/errors/error-mapping.js +26 -1
  87. package/dist/features/about/components/AboutView.js +1 -1
  88. package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
  89. package/dist/features/account/components/UserOffersPanel.js +5 -3
  90. package/dist/features/account/components/UserOrdersView.js +19 -33
  91. package/dist/features/admin/components/AdminActionIndexView.js +100 -5
  92. package/dist/features/admin/components/AdminAddressClustersView.js +21 -2
  93. package/dist/features/admin/components/AdminBlogEditorView.js +8 -8
  94. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  95. package/dist/features/admin/components/AdminCarouselView.js +96 -4
  96. package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
  97. package/dist/features/admin/components/AdminFulfillmentView.js +3 -2
  98. package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
  99. package/dist/features/admin/components/AdminInvoicingView.js +65 -0
  100. package/dist/features/admin/components/AdminMediaView.js +36 -3
  101. package/dist/features/admin/components/AdminNavigationView.js +4 -1
  102. package/dist/features/admin/components/AdminOffersView.js +2 -1
  103. package/dist/features/admin/components/AdminOrderEditorView.d.ts +18 -1
  104. package/dist/features/admin/components/AdminOrderEditorView.js +11 -2
  105. package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
  106. package/dist/features/admin/components/AdminOrdersView.js +67 -5
  107. package/dist/features/admin/components/AdminPaymentClustersView.js +19 -2
  108. package/dist/features/admin/components/AdminProductEditorView.js +2 -2
  109. package/dist/features/admin/components/AdminSectionsView.d.ts +10 -0
  110. package/dist/features/admin/components/AdminSectionsView.js +486 -224
  111. package/dist/features/admin/components/OwnerQuickActions.js +24 -2
  112. package/dist/features/admin/components/ReferenceRecordEditor.js +1 -1
  113. package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
  114. package/dist/features/admin/constants/filter-tabs.js +6 -0
  115. package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
  116. package/dist/features/admin/hooks/useAdminListingData.js +16 -0
  117. package/dist/features/admin/hooks/useOptimisticRowFlag.d.ts +33 -0
  118. package/dist/features/admin/hooks/useOptimisticRowFlag.js +87 -0
  119. package/dist/features/admin/repository/notification.repository.d.ts +15 -0
  120. package/dist/features/admin/repository/notification.repository.js +32 -0
  121. package/dist/features/admin/schemas/action-index-form.d.ts +34 -0
  122. package/dist/features/admin/schemas/action-index-form.js +115 -0
  123. package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
  124. package/dist/features/admin/schemas/firestore.d.ts +30 -0
  125. package/dist/features/admin/schemas/firestore.js +5 -0
  126. package/dist/features/audit-log/schemas/firestore.d.ts +30 -0
  127. package/dist/features/audit-log/schemas/firestore.js +15 -0
  128. package/dist/features/auth/components/RegisterForm.js +2 -1
  129. package/dist/features/auth/permissions/constants.js +13 -0
  130. package/dist/features/cart/components/CartPriceBreakdown.d.ts +13 -0
  131. package/dist/features/cart/components/CartPriceBreakdown.js +6 -2
  132. package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
  133. package/dist/features/cart/components/PointsTenderPicker.js +15 -0
  134. package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
  135. package/dist/features/cart/components/index.d.ts +2 -0
  136. package/dist/features/cart/components/index.js +1 -0
  137. package/dist/features/cart/repository/cart.repository.d.ts +19 -0
  138. package/dist/features/cart/repository/cart.repository.js +27 -0
  139. package/dist/features/cart/schemas/firestore.d.ts +92 -0
  140. package/dist/features/catalogue/components/CatalogueItemEditorView.js +3 -3
  141. package/dist/features/contact/email.d.ts +27 -10
  142. package/dist/features/contact/email.js +20 -3
  143. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +38 -0
  144. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +80 -0
  145. package/dist/features/dispute-reasons/schemas/firestore.d.ts +64 -0
  146. package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
  147. package/dist/features/events/components/AdminEventEditorView.js +8 -6
  148. package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
  149. package/dist/features/faq/components/FAQAccordion.js +29 -4
  150. package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
  151. package/dist/features/invoicing/schemas/firestore.js +45 -0
  152. package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
  153. package/dist/features/invoicing/utils/financial-year.js +53 -0
  154. package/dist/features/jobs/actions/enqueue-job.js +18 -1
  155. package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
  156. package/dist/features/jobs/repository/jobs.repository.js +84 -1
  157. package/dist/features/jobs/schemas/firestore.d.ts +80 -0
  158. package/dist/features/jobs/schemas/firestore.js +37 -0
  159. package/dist/features/layout/hooks/useFormBottomActions.js +20 -1
  160. package/dist/features/lottery/schemas/zod.d.ts +6 -6
  161. package/dist/features/media/MediaImage.js +22 -1
  162. package/dist/features/media/upload/ImageUpload.js +1 -1
  163. package/dist/features/obligations/constants/policies.js +24 -1
  164. package/dist/features/orders/components/EmiInstallmentsPanel.js +25 -7
  165. package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
  166. package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
  167. package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
  168. package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
  169. package/dist/features/orders/components/RaiseDisputeForm.js +111 -0
  170. package/dist/features/orders/components/RefundRequestView.js +22 -4
  171. package/dist/features/orders/components/index.d.ts +4 -0
  172. package/dist/features/orders/components/index.js +2 -0
  173. package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
  174. package/dist/features/orders/constants/order-lane-tabs.js +88 -0
  175. package/dist/features/orders/repository/orders.repository.d.ts +57 -0
  176. package/dist/features/orders/repository/orders.repository.js +145 -0
  177. package/dist/features/orders/schemas/firestore.d.ts +196 -1
  178. package/dist/features/orders/schemas/index.d.ts +60 -12
  179. package/dist/features/orders/schemas/index.js +12 -0
  180. package/dist/features/orders/types/index.d.ts +26 -0
  181. package/dist/features/orders/utils/courier-block.d.ts +25 -0
  182. package/dist/features/orders/utils/courier-block.js +23 -0
  183. package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
  184. package/dist/features/payment-cases/schemas/firestore.js +1 -0
  185. package/dist/features/products/components/GroupMemberPicker.js +4 -1
  186. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  187. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
  188. package/dist/features/products/components/ProductDetailActions.js +2 -1
  189. package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
  190. package/dist/features/products/components/ProductDetailPageView.js +2 -2
  191. package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
  192. package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
  193. package/dist/features/promotions/actions/coupon-stacking.js +21 -2
  194. package/dist/features/promotions/components/CouponCard.js +13 -0
  195. package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
  196. package/dist/features/promotions/constants/coupon-help.js +9 -1
  197. package/dist/features/promotions/schemas/firestore.d.ts +24 -0
  198. package/dist/features/promotions/schemas/firestore.js +4 -0
  199. package/dist/features/promotions/types/index.d.ts +19 -1
  200. package/dist/features/scams/components/ScamProfileView.js +2 -2
  201. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  202. package/dist/features/search/action-index/tab-entries.js +1 -1
  203. package/dist/features/seller/actions/seller-actions.js +33 -3
  204. package/dist/features/seller/components/FulfillmentView.js +3 -2
  205. package/dist/features/seller/components/SellerAddressesView.js +32 -4
  206. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +62 -3
  207. package/dist/features/seller/components/SellerBundlesView.js +53 -14
  208. package/dist/features/seller/components/SellerGroupedListingsView.js +23 -3
  209. package/dist/features/seller/components/SellerListingTypeView.js +56 -10
  210. package/dist/features/seller/components/SellerOrdersView.js +129 -27
  211. package/dist/features/seller/components/SellerPayoutMethodsView.js +33 -1
  212. package/dist/features/seller/components/SellerPayoutSettingsView.js +48 -9
  213. package/dist/features/seller/components/SellerProductsView.js +5 -1
  214. package/dist/features/seller/components/SellerShippingConfigsView.js +33 -1
  215. package/dist/features/seller/components/SellerShippingView.js +2 -1
  216. package/dist/features/seller/components/SellerStoreCategoriesView.js +33 -1
  217. package/dist/features/seller/components/SellerSupportView.js +69 -2
  218. package/dist/features/seller/hooks/useSellerListingData.js +25 -0
  219. package/dist/features/shell/SectionForm.js +20 -16
  220. package/dist/features/shell/build-sections.js +14 -1
  221. package/dist/features/shipments/components/AdminShipmentLotItemsView.js +54 -1
  222. package/dist/features/shipments/components/AdminShipmentProjectionsView.js +3 -2
  223. package/dist/features/shipments/schemas/validation.d.ts +4 -4
  224. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +43 -0
  225. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +90 -0
  226. package/dist/features/shipping-boxes/schemas/firestore.d.ts +82 -0
  227. package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
  228. package/dist/features/sticker-trace/components/StickerCommitPanel.js +2 -1
  229. package/dist/features/sticker-trace/components/StickerPrintPanel.js +2 -1
  230. package/dist/features/sticker-trace/components/StickerRetryPanel.js +24 -4
  231. package/dist/features/sticker-trace/components/StickerTraceStudio.js +2 -1
  232. package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
  233. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
  234. package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
  235. package/dist/features/stores/schemas/firestore.d.ts +71 -0
  236. package/dist/features/stores/types/index.d.ts +19 -0
  237. package/dist/features/support/schemas/index.d.ts +6 -6
  238. package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +3 -2
  239. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  240. package/dist/index.d.ts +11 -2
  241. package/dist/index.js +17 -2
  242. package/dist/next/routing/route-map.d.ts +24 -0
  243. package/dist/next/routing/route-map.js +19 -0
  244. package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
  245. package/dist/providers/shipping-shiprocket/index.js +84 -1
  246. package/dist/schemas/registry.d.ts +51 -22
  247. package/dist/schemas/sieve.d.ts +5 -5
  248. package/dist/server-entry.d.ts +2 -2
  249. package/dist/server-entry.js +8 -1
  250. package/dist/server.d.ts +11 -2
  251. package/dist/server.js +40 -2
  252. package/dist/styles.css +64 -80
  253. package/dist/tailwind-utilities.css +1 -1
  254. package/dist/tokens/themes/default-dark.js +1 -0
  255. package/dist/tokens/themes/default-light.js +1 -0
  256. package/dist/tokens/themes/required.d.ts +1 -1
  257. package/dist/tokens/themes/required.js +1 -0
  258. package/dist/tokens/tokens.css +15 -0
  259. package/dist/ui/components/Checkbox.js +10 -2
  260. package/dist/ui/components/DateInput.js +8 -1
  261. package/dist/ui/components/Disclaimer.d.ts +19 -0
  262. package/dist/ui/components/Disclaimer.js +74 -0
  263. package/dist/ui/components/Input.js +22 -2
  264. package/dist/ui/components/PaginatedSelect.d.ts +8 -19
  265. package/dist/ui/components/PaginatedSelect.js +43 -9
  266. package/dist/ui/components/Radio.js +8 -1
  267. package/dist/ui/components/Select.js +10 -2
  268. package/dist/ui/components/TagInput.d.ts +8 -1
  269. package/dist/ui/components/TagInput.js +4 -3
  270. package/dist/ui/components/Textarea.js +10 -2
  271. package/dist/ui/components/tabs-overflow.js +64 -11
  272. package/dist/ui/forms/FieldCheckbox.js +1 -1
  273. package/dist/ui/forms/FormErrorList.d.ts +0 -16
  274. package/dist/ui/forms/FormErrorList.js +34 -1
  275. package/dist/ui/forms/apply-zod-issues.d.ts +19 -1
  276. package/dist/ui/forms/apply-zod-issues.js +23 -1
  277. package/dist/ui/index.d.ts +2 -0
  278. package/dist/ui/index.js +6 -0
  279. package/dist/ui/rich-text/RichText.style.css +48 -79
  280. package/package.json +1 -1
  281. package/scripts/seed-cli.mjs +1831 -1822
@@ -20,9 +20,16 @@
20
20
  */
21
21
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
22
22
  /**
23
- * Slack used by the hysteresis rule below, in px. Matches
24
- * 2 x --appkit-tabs-arrow-size (2rem) — the width the two in-flow arrows
25
- * reclaim from the list when they unmount.
23
+ * Slack used by the hysteresis rule below, in px. Nominally
24
+ * 2 x --appkit-tabs-arrow-size (2rem), the width of the two in-flow arrows.
25
+ *
26
+ * 🛑 It is a SAFETY MARGIN, not a measurement, and the distinction is what
27
+ * this file got wrong badly enough to crash production. The arrows are not
28
+ * the only thing `data-arrows="true"` changes — it also hides the list's
29
+ * scrollbar — so the real width reclaimed on unmount is this number minus the
30
+ * platform scrollbar, and on a machine with overlay scrollbars it is this
31
+ * number exactly. The rule below is written to be stable for every value in
32
+ * that range rather than assuming one of them.
26
33
  */
27
34
  const ARROW_SLACK_PX = 64;
28
35
  /** Sub-pixel tolerance: scrollWidth/clientWidth can differ by <1px at some zooms. */
@@ -51,19 +58,65 @@ export function useTabsOverflow(listRef, activeKey) {
51
58
  const overflow = el.scrollWidth - el.clientWidth;
52
59
  const previous = stateRef.current.hasArrows;
53
60
  /*
54
- * 🛑 HYSTERESIS — do not collapse this to a single threshold.
61
+ * 🛑 HYSTERESIS — do not collapse this to a single threshold, and do not
62
+ * "tidy" the negative one below back to a positive number.
55
63
  *
56
64
  * The arrows are IN-FLOW, so mounting them shrinks the list's clientWidth
57
- * by ~ARROW_SLACK_PX, which INCREASES the measured overflow. With one
58
- * threshold a strip 10px wider than its container oscillates forever:
59
- * hidden -> overflow 10 -> show -> overflow 74 -> still overflowing
60
- * -> ... -> hide -> overflow -54 -> hide -> widen -> overflow 10 -> show
65
+ * and INCREASES the measured overflow. With one threshold a strip 10px
66
+ * wider than its container oscillates forever.
67
+ *
68
+ * ## 🛑 THE PREVIOUS RULE WAS `overflow > ARROW_SLACK_PX` AND IT CRASHED
69
+ * ## EVERY STORE PAGE IN PRODUCTION WITH React #185 (max update depth).
61
70
  *
62
- * Once the arrows are up they may only come down if the content would
71
+ * Its stability proof — "they may only come down if the content would
63
72
  * STILL fit after reclaiming their width, which by construction leaves
64
- * overflow <= 0 afterwards. That makes the rule provably stable.
73
+ * overflow <= 0" — rests on mounting the arrows changing the measured
74
+ * overflow by EXACTLY `ARROW_SLACK_PX`. That is true of the arrows alone
75
+ * and FALSE of the net effect, because of a rule 100 lines away in
76
+ * `Tabs.style.css`:
77
+ *
78
+ * .appkit-tabs-shell[data-arrows="true"] .appkit-tabs-list {
79
+ * scrollbar-width: none;
80
+ * }
81
+ * …__arrow is 2rem; …-list::-webkit-scrollbar { display: none }
82
+ *
83
+ * The same `data-arrows="true"` that mounts the arrows also HIDES the
84
+ * scrollbar, handing the list back ~15px of clientWidth. So the net
85
+ * reclaimed width is ~49px, not 64 — and for any strip overflowing by
86
+ * 2..15px the two thresholds each imply the other:
87
+ *
88
+ * hidden, overflow 10 -> 10 > 1 -> SHOW
89
+ * shown, overflow 59 -> 59 > 64? -> no -> HIDE
90
+ * hidden, overflow 10 -> …forever
91
+ *
92
+ * `useLayoutEffect` below runs on every render by design, so the loop is
93
+ * unbounded and React tears the tree down. The `sameState` guard cannot
94
+ * help: the state genuinely differs each pass.
95
+ *
96
+ * ## The rule now, stable for ANY reclaimed width
97
+ *
98
+ * Let r = whatever mounting the arrows adds to `overflow` (unknown, and
99
+ * provably NOT a constant — it depends on CSS this file cannot see, the
100
+ * platform's scrollbar width, and whether the user has overlay
101
+ * scrollbars). All we know is 0 <= r.
102
+ *
103
+ * show: hidden AND overflow > EPSILON
104
+ * hide: shown AND overflow <= -ARROW_SLACK_PX
105
+ *
106
+ * After SHOWING: overflow' = overflow + r > EPSILON >= -ARROW_SLACK_PX,
107
+ * so the hide test cannot fire. No loop.
108
+ * After HIDING: overflow' = overflow - r <= -ARROW_SLACK_PX <= EPSILON,
109
+ * so the show test cannot fire. No loop.
110
+ *
111
+ * Stable for every r >= 0, which is the point: the previous rule was
112
+ * stable only for one exact value of r that nothing enforced.
113
+ *
114
+ * The cost is deliberate conservatism — once up, the arrows stay up until
115
+ * the strip has a full ARROW_SLACK_PX of genuine slack. An arrow that
116
+ * lingers on a strip that just fits is a cosmetic blemish; the thing it
117
+ * replaces is a white screen.
65
118
  */
66
- const hasArrows = previous ? overflow > ARROW_SLACK_PX : overflow > EPSILON;
119
+ const hasArrows = previous ? overflow > -ARROW_SLACK_PX : overflow > EPSILON;
67
120
  const max = el.scrollWidth - el.clientWidth;
68
121
  // Math.abs: scrollLeft is negative (or inverted) in RTL depending on engine.
69
122
  const position = Math.abs(el.scrollLeft);
@@ -34,5 +34,5 @@ export function FieldCheckbox({ name, label, hint, checked, onChange, onBlur, di
34
34
  ctx?.setFieldTouched(name);
35
35
  onBlur?.();
36
36
  }
37
- return (_jsxs("div", { className: ["appkit-form-field", className].filter(Boolean).join(" "), children: [_jsx(Checkbox, { id: inputId, name: name, checked: checked, onChange: handleChange, onBlur: handleBlur, label: label, disabled: disabled, "aria-describedby": showError ? errorId : undefined }), !showError && hint && (_jsx(Text, { size: "sm", variant: "secondary", className: "appkit-form-field__hint", children: hint })), showError && (_jsx(Text, { id: errorId, size: "sm", variant: "error", className: "appkit-form-field__error", role: "alert", children: error }))] }));
37
+ return (_jsxs("div", { className: ["appkit-form-field", className].filter(Boolean).join(" "), children: [_jsx(Checkbox, { id: inputId, name: name, checked: checked, onChange: handleChange, onBlur: handleBlur, label: label, disabled: disabled, "aria-invalid": showError || undefined, "aria-describedby": showError ? errorId : undefined }), !showError && hint && (_jsx(Text, { size: "sm", variant: "secondary", className: "appkit-form-field__hint", children: hint })), showError && (_jsx(Text, { id: errorId, size: "sm", variant: "error", className: "appkit-form-field__error", role: "alert", children: error }))] }));
38
38
  }
@@ -9,21 +9,5 @@ export interface FormErrorListProps {
9
9
  ctx?: FormShellContextValue;
10
10
  className?: string;
11
11
  }
12
- /**
13
- * The `<ul>` of current validation errors, with a jump link per entry when
14
- * the form declares sections.
15
- *
16
- * WHY it is its own file: two surfaces render this exact list — the inline
17
- * `<FormErrorSummary>` beside the submit button on desktop, and the mobile
18
- * "Fix N issues" sheet in the bottom-chrome tier. Writing it twice would mean
19
- * a jump-link fix, an empty-state fix or a wording fix landing in one and not
20
- * the other, which is the bug-fix multiplier the Duplication Framework calls
21
- * out. There are exactly two consumers and they are the same list, so this is
22
- * a consolidation, not speculative abstraction.
23
- *
24
- * Renders nothing when there are no errors. It does NOT gate on
25
- * `submitAttempted` — that is the *summary's* decision, not the list's, and
26
- * the sheet needs to keep rendering while open.
27
- */
28
12
  export declare function FormErrorList({ ctx: ctxProp, className }: FormErrorListProps): import("react").JSX.Element | null;
29
13
  export default FormErrorList;
@@ -19,6 +19,39 @@ import { Span } from "../components/Typography.js";
19
19
  * `submitAttempted` — that is the *summary's* decision, not the list's, and
20
20
  * the sheet needs to keep rendering while open.
21
21
  */
22
+ /*
23
+ * 🛑 The two sides of this lookup use DIFFERENT key shapes, so an exact match
24
+ * silently loses every nested error.
25
+ *
26
+ * `errors` is keyed by the full dotted Zod path — `applyZodIssues` does
27
+ * `issue.path.map(String).join(".")`, giving `"address.line1"`. But
28
+ * `fieldToStepIndex` is built by `buildFieldToSectionIndex` from
29
+ * `SectionDef.fields`, which lists BARE field names — `"address"`. So
30
+ * `fieldToStepIndex["address.line1"]` was always `undefined`, the entry fell
31
+ * through to the plain `<Span>`, and the error that a section demonstrably
32
+ * owned rendered with no jump link.
33
+ *
34
+ * `SectionForm` already solved this for its own badge counts
35
+ * (`erroringSectionIds`, `errorCountFor`) with a prefix match. This is the same
36
+ * rule, so the list and the badges can no longer disagree about which section
37
+ * an error belongs to.
38
+ *
39
+ * Exact match is tried first: a field genuinely named `"address.line1"` must
40
+ * beat a prefix match on `"address"`.
41
+ */
42
+ function resolveStepIndex(ctx, key) {
43
+ const map = ctx.fieldToStepIndex;
44
+ if (!map)
45
+ return undefined;
46
+ const exact = map[key];
47
+ if (exact != null)
48
+ return exact;
49
+ for (const [field, index] of Object.entries(map)) {
50
+ if (key.startsWith(`${field}.`))
51
+ return index;
52
+ }
53
+ return undefined;
54
+ }
22
55
  export function FormErrorList({ ctx: ctxProp, className }) {
23
56
  const ambient = useContext(FormShellContext);
24
57
  const ctx = ctxProp ?? ambient;
@@ -28,7 +61,7 @@ export function FormErrorList({ ctx: ctxProp, className }) {
28
61
  if (entries.length === 0)
29
62
  return null;
30
63
  return (_jsx("ul", { className: ["appkit-formshell__error-summary__list", className].filter(Boolean).join(" "), children: entries.map(([key, message]) => {
31
- const stepIndex = ctx.fieldToStepIndex?.[key];
64
+ const stepIndex = resolveStepIndex(ctx, key);
32
65
  const stepLabel = stepIndex != null ? ctx.steps[stepIndex]?.label : undefined;
33
66
  return (_jsx("li", { children: stepLabel ? (_jsxs("button", { type: "button", className: "appkit-formshell__error-summary__step-link", onClick: () => ctx.goToStep(stepIndex), children: [_jsxs(Span, { weight: "semibold", children: [stepLabel, ":"] }), " ", message] })) : (_jsx(Span, { children: message })) }, key));
34
67
  }) }));
@@ -22,7 +22,16 @@
22
22
  *
23
23
  * Root-level `.refine()` issues (empty `path: []`, no owning field) are still
24
24
  * skipped — there is no field to attach them to, so the caller must surface
25
- * those some other way (they fall through to a toast in `surfaceError`).
25
+ * those some other way.
26
+ *
27
+ * 🛑 That last sentence used to end "(they fall through to a toast in
28
+ * `surfaceError`)", which was only true when EVERY issue was root-level.
29
+ * In the mixed case — one field error plus one cross-field `.refine()`, which
30
+ * is the common shape for "passwords must match" or "end date must be after
31
+ * start date" — `hasAttachableIssue` returned true, this function skipped the
32
+ * root issue, and `surfaceError` returned without a toast. The cross-field
33
+ * rule was enforced, the save was refused, and the user was told nothing
34
+ * about why. `rootLevelMessages` below is how a caller surfaces them.
26
35
  */
27
36
  export declare function applyZodIssues(issues: ReadonlyArray<{
28
37
  path?: ReadonlyArray<PropertyKey>;
@@ -32,3 +41,12 @@ export declare function applyZodIssues(issues: ReadonlyArray<{
32
41
  export declare function hasAttachableIssue(issues: ReadonlyArray<{
33
42
  path?: ReadonlyArray<PropertyKey>;
34
43
  }> | undefined): boolean;
44
+ /**
45
+ * The messages `applyZodIssues` cannot attach — the root-level `.refine()`
46
+ * ones with no owning field. A caller that has just run `applyZodIssues`
47
+ * should surface these separately, or they are silently discarded.
48
+ */
49
+ export declare function rootLevelMessages(issues: ReadonlyArray<{
50
+ path?: ReadonlyArray<PropertyKey>;
51
+ message: string;
52
+ }> | undefined): string[];
@@ -22,7 +22,16 @@
22
22
  *
23
23
  * Root-level `.refine()` issues (empty `path: []`, no owning field) are still
24
24
  * skipped — there is no field to attach them to, so the caller must surface
25
- * those some other way (they fall through to a toast in `surfaceError`).
25
+ * those some other way.
26
+ *
27
+ * 🛑 That last sentence used to end "(they fall through to a toast in
28
+ * `surfaceError`)", which was only true when EVERY issue was root-level.
29
+ * In the mixed case — one field error plus one cross-field `.refine()`, which
30
+ * is the common shape for "passwords must match" or "end date must be after
31
+ * start date" — `hasAttachableIssue` returned true, this function skipped the
32
+ * root issue, and `surfaceError` returned without a toast. The cross-field
33
+ * rule was enforced, the save was refused, and the user was told nothing
34
+ * about why. `rootLevelMessages` below is how a caller surfaces them.
26
35
  */
27
36
  export function applyZodIssues(issues, setFieldError) {
28
37
  for (const issue of issues) {
@@ -36,3 +45,16 @@ export function applyZodIssues(issues, setFieldError) {
36
45
  export function hasAttachableIssue(issues) {
37
46
  return Boolean(issues?.some((i) => i.path && i.path.length > 0));
38
47
  }
48
+ /**
49
+ * The messages `applyZodIssues` cannot attach — the root-level `.refine()`
50
+ * ones with no owning field. A caller that has just run `applyZodIssues`
51
+ * should surface these separately, or they are silently discarded.
52
+ */
53
+ export function rootLevelMessages(issues) {
54
+ if (!issues)
55
+ return [];
56
+ return issues
57
+ .filter((i) => !i.path || i.path.length === 0)
58
+ .map((i) => i.message)
59
+ .filter((m) => typeof m === "string" && m.length > 0);
60
+ }
@@ -16,6 +16,8 @@ export type { SectionProps, SectionBackgroundConfig, ArticleProps, MainProps, As
16
16
  export { Section, sectionBackgroundStyle, Article, Main, Aside, Nav, BlockHeader, BlockFooter, Ul, Ol, Li, Table, Thead, Tbody, Tr, Th, Td, Code, Pre, Blockquote, Figure, Figcaption, Dl, Dt, Dd, } from "./components/Semantic";
17
17
  export type { DivProps } from "./components/Div";
18
18
  export { Div } from "./components/Div";
19
+ export { Disclaimer } from "./components/Disclaimer";
20
+ export type { DisclaimerProps } from "./components/Disclaimer";
19
21
  export type { SpecTableProps, SpecTableRow } from "./components/SpecTable";
20
22
  export { SpecTable } from "./components/SpecTable";
21
23
  export type { ColorVariant } from "./components/Typography";
package/dist/ui/index.js CHANGED
@@ -30,6 +30,12 @@ export { FormErrorSummary } from "./forms/index.js";
30
30
  export { buildColumns, createColumnBuilder, renderBoolean, renderCurrency, renderCurrencyCompact, renderCount, renderNullable, renderRating, getStatusTone, getResourceIcon, } from "./columns/index.js";
31
31
  export { Section, sectionBackgroundStyle, Article, Main, Aside, Nav, BlockHeader, BlockFooter, Ul, Ol, Li, Table, Thead, Tbody, Tr, Th, Td, Code, Pre, Blockquote, Figure, Figcaption, Dl, Dt, Dd, } from "./components/Semantic.js";
32
32
  export { Div } from "./components/Div.js";
33
+ /*
34
+ * Phase 12 — the one way to render a disclaimer. `id` only: there is no `text`
35
+ * prop, because an escape hatch would make it a styled box and the legally
36
+ * material disclaimers would be written at their call sites again.
37
+ */
38
+ export { Disclaimer } from "./components/Disclaimer.js";
33
39
  export { SpecTable } from "./components/SpecTable.js";
34
40
  export { Heading, Text, Label, Caption, Span } from "./components/Typography.js";
35
41
  // --- Filter chip group (SB10-C completion, S8 2026-05-13) --------------------
@@ -43,77 +43,42 @@
43
43
 
44
44
 
45
45
  /* --------------------------------------------------------------------------
46
- * THE PROSE PALETTE — rebound to appkit theme tokens.
46
+ * THE PROSE PALETTE LIVES IN THE CONSUMER, NOT HERE.
47
47
  *
48
- * 🛑 `dark:prose-invert` CANNOT COMPILE IN THIS PROJECT. Do not "fix" dark-mode
49
- * rich text by adding it to a call site, and do not add
50
- * `@source inline("dark:prose-invert")` to globals.css.
51
- *
52
- * Every `proseClass` string in appkit carries `dark:prose-invert` and NONE of
53
- * them has ever generated a rule, because:
54
- * - the consumer build excludes appkit from scanning
55
- * (`src/app/globals.css` → `@source not "../../appkit"`), and
56
- * - `appkit/tailwind.config.js` does not load `@tailwindcss/typography`,
57
- * so appkit's own `dist/tailwind-utilities.css` cannot emit it either.
58
- *
59
- * So `--tw-prose-invert-*` is DEFINED and never switched on. Every rich-text
60
- * surface on the site — product and auction descriptions, blog posts, policy
61
- * pages, FAQ answers, category `contentBody`, pre-orders, classifieds, digital
62
- * codes, live items, prize draws, events — rendered the light-theme palette in
63
- * every theme: body at gray-700 and links at gray-900, i.e. near-black on a
64
- * dark page. The links were effectively invisible.
48
+ * 🛑 Do NOT reinstate a `:root .prose { --tw-prose-*: ... !important }` block
49
+ * in this file. One lived here for months and it NEVER APPLIED.
65
50
  *
66
- * It was not merely unstyled, it was OVERRIDING: `important: true` in
67
- * `tailwind.config.js` emits `.prose :where(a) { color: var(--tw-prose-links)
68
- * !important }`, which beat the themed `.dark .appkit-rich-text a` rule further
69
- * down this file. All that theme-aware CSS was dead on arrival.
51
+ * The typography plugin emits `.prose { --tw-prose-*: <tailwind gray> }`, and
52
+ * the consumer's `important: true` makes each of those `!important` inside
53
+ * `@layer utilities`. The block here was unlayered, and justified itself with
54
+ * "`:root .prose` is (0,2,0) against `.prose`'s (0,1,0), so specificity
55
+ * decides and the outcome does not depend on bundle order."
70
56
  *
71
- * Rebinding the VARIABLES fixes it at the only point both problems meet: every
72
- * prose rule reads `var(--tw-prose-*)`, so one block re-themes body, links,
73
- * headings, bold, lists, quotes, captions, code and tables at once — in both
74
- * built-in themes AND in any admin-authored custom theme, which `prose-invert`
75
- * could never have done (its palette is hardcoded Tailwind grays).
57
+ * Specificity is never consulted. For the IMPORTANT tier, cascade-layer order
58
+ * is REVERSED and unlayered sorts LOWEST, so a layered `!important` beats an
59
+ * unlayered one at any specificity (Root Cause #106, measured in a browser).
60
+ * The plugin's hardcoded light-mode grays therefore won in every theme —
61
+ * links at gray-900, i.e. near-black on the near-black dark page, and
62
+ * black-instead-of-teal in light. The fix was invisible to every gate because
63
+ * the CSS was present and correct-looking in `dist/styles.css`; only a
64
+ * rendered page shows it losing.
76
65
  *
77
- * 🛑 The specificity is deliberate and must not be lowered. `.prose` declares
78
- * these variables with `!important`, so an equal-importance override is decided
79
- * by EMISSION ORDER between two separate stylesheets — the non-deterministic
80
- * trap of Root Cause #79. `:root .prose` is (0,2,0) against `.prose`'s (0,1,0),
81
- * so specificity decides and the outcome does not depend on bundle order. The
82
- * dark block at (0,3,0) also outranks `.dark .prose-invert` (0,2,0), so this
83
- * stays correct even if someone later makes `prose-invert` compile.
66
+ * Owner is now `tailwind.config.js` → `theme.extend.typography`, which makes
67
+ * the plugin emit the appkit tokens in the first place so there is exactly
68
+ * one declaration and no contest. Each binds to an `--appkit-color-*` that is
69
+ * redefined per theme, so prose re-themes for the built-in themes and for any
70
+ * admin-authored one.
84
71
  *
85
- * Not scoped to `.appkit-rich-text` on purpose: `PolicyPageView` and the scams
86
- * FAQ page apply `prose` to a bare `<div>` and had the identical defect.
72
+ * 🛑 `dark:prose-invert` CANNOT COMPILE IN THIS PROJECT. Do not "fix" dark
73
+ * rich text by adding it to a call site, and do not add
74
+ * `@source inline("dark:prose-invert")` to globals.css. Every `proseClass`
75
+ * string in appkit carries it and none has ever generated a rule, because the
76
+ * consumer build excludes appkit from scanning (`src/app/globals.css` →
77
+ * `@source not "../../appkit"`) and `appkit/tailwind.config.js` does not load
78
+ * `@tailwindcss/typography`, so appkit's own `dist/tailwind-utilities.css`
79
+ * cannot emit it either. It is moot now regardless: the tokens above invert on
80
+ * their own, which `prose-invert` could never do with its hardcoded grays.
87
81
  * -------------------------------------------------------------------------- */
88
- :root .prose {
89
- --tw-prose-body: var(--appkit-color-text-muted) !important;
90
- --tw-prose-headings: var(--appkit-color-text) !important;
91
- --tw-prose-lead: var(--appkit-color-text-muted) !important;
92
- --tw-prose-links: var(--appkit-color-primary-600) !important;
93
- --tw-prose-bold: var(--appkit-color-text) !important;
94
- --tw-prose-counters: var(--appkit-color-text-faint) !important;
95
- --tw-prose-bullets: var(--appkit-color-text-faint) !important;
96
- --tw-prose-hr: var(--appkit-color-border) !important;
97
- --tw-prose-quotes: var(--appkit-color-text) !important;
98
- --tw-prose-quote-borders: var(--appkit-color-primary) !important;
99
- --tw-prose-captions: var(--appkit-color-text-faint) !important;
100
- --tw-prose-kbd: var(--appkit-color-text) !important;
101
- --tw-prose-kbd-shadows: 24 24 27 !important;
102
- --tw-prose-code: var(--appkit-color-text) !important;
103
- --tw-prose-pre-code: var(--appkit-color-slate-200) !important;
104
- --tw-prose-pre-bg: var(--appkit-color-slate-800) !important;
105
- --tw-prose-th-borders: var(--appkit-color-border) !important;
106
- --tw-prose-td-borders: var(--appkit-color-border) !important;
107
- }
108
-
109
- /* Only the values that are genuinely theme-specific. Everything above already
110
- * inverts, because `--appkit-color-text`/`-text-muted`/`-border` are redefined
111
- * per theme in tokens.css — which is the whole point of binding to them. */
112
- :root.dark .prose {
113
- --tw-prose-links: var(--appkit-color-secondary-400) !important;
114
- --tw-prose-kbd-shadows: 250 250 250 !important;
115
- --tw-prose-pre-bg: var(--appkit-color-surface) !important;
116
- }
117
82
 
118
83
  /* --------------------------------------------------------------------------
119
84
  * Base wrapper. All selectors are scoped to .appkit-rich-text so they
@@ -200,27 +165,31 @@
200
165
  }
201
166
 
202
167
  /* --- Links ---------------------------------------------------------------- */
168
+ /* No `.dark` variant, deliberately: `--appkit-color-link` is redefined per
169
+ * theme, so one rule covers every theme including admin-authored ones. The two
170
+ * `.dark .appkit-rich-text a` rules that used to sit here were also dead —
171
+ * non-important against the plugin's `.prose :where(a){color:…!important}`.
172
+ *
173
+ * Decoration binds to `currentColor` rather than naming the token a second
174
+ * time. That matters beyond brevity: the colour here IS still overridden by
175
+ * the plugin on any element that also carries `.prose`, so a hardcoded
176
+ * decoration colour could disagree with the ink actually rendered. With
177
+ * `currentColor` the underline follows whatever won. */
203
178
  .appkit-rich-text a {
204
- color: var(--appkit-color-primary-600);
179
+ color: var(--appkit-color-link);
205
180
  text-decoration: underline;
206
- text-decoration-color: color-mix(in srgb, var(--appkit-color-primary-600) 60%, transparent);
181
+ text-decoration-color: color-mix(in srgb, currentColor 60%, transparent);
207
182
  text-underline-offset: 2px;
208
183
  transition: color 150ms, text-decoration-color 150ms;
209
184
  }
210
185
 
186
+ /* Hover moves the link toward the page's own text colour, which darkens it in
187
+ * a light theme and lightens it in a dark one — so this needs no per-theme
188
+ * pair either. The plugin sets no `a:hover`, so unlike the resting colour
189
+ * above this rule is genuinely the one in effect. */
211
190
  .appkit-rich-text a:hover {
212
- color: var(--appkit-color-primary-700);
213
- text-decoration-color: color-mix(in srgb, var(--appkit-color-primary-700) 70%, transparent);
214
- }
215
-
216
- .dark .appkit-rich-text a {
217
- color: var(--appkit-color-secondary-400);
218
- text-decoration-color: color-mix(in srgb, var(--appkit-color-secondary-400) 60%, transparent);
219
- }
220
-
221
- .dark .appkit-rich-text a:hover {
222
- color: var(--appkit-color-secondary-300);
223
- text-decoration-color: color-mix(in srgb, var(--appkit-color-secondary-300) 60%, transparent);
191
+ color: color-mix(in srgb, var(--appkit-color-link) 80%, var(--appkit-color-text));
192
+ text-decoration-color: currentColor;
224
193
  }
225
194
 
226
195
  /* --- Tables --------------------------------------------------------------- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "4.61.0",
3
+ "version": "4.62.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"