@mohasinac/appkit 4.62.0 → 4.63.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 (391) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -29
  3. package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
  4. package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
  5. package/dist/_internal/server/features/ads/booking.d.ts +118 -0
  6. package/dist/_internal/server/features/ads/booking.js +326 -0
  7. package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
  8. package/dist/_internal/server/features/checkout/actions.js +850 -79
  9. package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
  10. package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
  11. package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
  12. package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
  13. package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
  14. package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
  15. package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
  16. package/dist/_internal/server/features/dashboard/attention.js +183 -0
  17. package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
  18. package/dist/_internal/server/features/dashboard/data.js +82 -0
  19. package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
  20. package/dist/_internal/server/features/inventory/reservations.js +273 -0
  21. package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
  22. package/dist/_internal/server/features/invoicing/allocate.js +162 -0
  23. package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
  24. package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
  25. package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
  26. package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
  27. package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
  28. package/dist/_internal/server/features/invoicing/issue.js +202 -0
  29. package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
  30. package/dist/_internal/server/features/offers/destinations.js +65 -0
  31. package/dist/_internal/server/features/orders/actions.d.ts +8 -1
  32. package/dist/_internal/server/features/orders/actions.js +81 -8
  33. package/dist/_internal/server/features/orders/adapters.js +54 -0
  34. package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
  35. package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
  36. package/dist/_internal/server/features/orders/balance.d.ts +89 -0
  37. package/dist/_internal/server/features/orders/balance.js +256 -0
  38. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
  39. package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
  40. package/dist/_internal/server/features/points/award.js +46 -4
  41. package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
  42. package/dist/_internal/server/features/pricing/actions.js +144 -0
  43. package/dist/_internal/server/features/refunds/actions.js +26 -0
  44. package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
  45. package/dist/_internal/server/features/shipping/book-split.js +130 -0
  46. package/dist/_internal/server/features/shipping/book.d.ts +61 -0
  47. package/dist/_internal/server/features/shipping/book.js +176 -0
  48. package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
  49. package/dist/_internal/server/features/shipping/courier-block.js +264 -0
  50. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  51. package/dist/_internal/server/features/site-settings/adapters.js +29 -0
  52. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  53. package/dist/_internal/server/features/stores/adapters.js +65 -0
  54. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  55. package/dist/_internal/server/functions/scheduled.js +95 -2
  56. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
  57. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
  58. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
  59. package/dist/_internal/server/jobs/core/index.d.ts +2 -1
  60. package/dist/_internal/server/jobs/core/index.js +2 -1
  61. package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
  62. package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
  63. package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
  64. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
  65. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
  66. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
  67. package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
  68. package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
  69. package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
  70. package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
  71. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
  72. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  73. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  74. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
  75. package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
  76. package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
  77. package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
  78. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  79. package/dist/_internal/shared/actions/action-registry.js +296 -0
  80. package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
  81. package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
  82. package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
  83. package/dist/_internal/shared/checkout/order-math.js +159 -0
  84. package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
  85. package/dist/_internal/shared/checkout/refundable-base.js +13 -1
  86. package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
  87. package/dist/_internal/shared/checkout/rules/index.js +1 -1
  88. package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
  89. package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
  90. package/dist/_internal/shared/checkout/split.d.ts +75 -0
  91. package/dist/_internal/shared/checkout/split.js +120 -0
  92. package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
  93. package/dist/_internal/shared/content/disclaimers.js +217 -0
  94. package/dist/_internal/shared/content/published-values.d.ts +93 -0
  95. package/dist/_internal/shared/content/published-values.js +206 -0
  96. package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
  97. package/dist/_internal/shared/features/admin/integrations.js +263 -0
  98. package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
  99. package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
  100. package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
  101. package/dist/_internal/shared/features/emi/choice.js +69 -0
  102. package/dist/_internal/shared/features/emi/group.d.ts +84 -0
  103. package/dist/_internal/shared/features/emi/group.js +126 -0
  104. package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
  105. package/dist/_internal/shared/features/ledger/posting.js +165 -0
  106. package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
  107. package/dist/_internal/shared/features/ledger/reports.js +127 -0
  108. package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
  109. package/dist/_internal/shared/features/ledger/rules.js +221 -0
  110. package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
  111. package/dist/_internal/shared/features/offers/coordination.js +80 -0
  112. package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
  113. package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
  114. package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
  115. package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
  116. package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
  117. package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
  118. package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
  119. package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
  120. package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
  121. package/dist/_internal/shared/features/points/accepts.js +49 -0
  122. package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
  123. package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
  124. package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
  125. package/dist/_internal/shared/features/shipping/parcel.js +139 -0
  126. package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
  127. package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
  128. package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
  129. package/dist/_internal/shared/features/site-settings/fees.js +12 -8
  130. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  131. package/dist/_internal/shared/fees/calculator.d.ts +33 -1
  132. package/dist/_internal/shared/fees/calculator.js +32 -2
  133. package/dist/_internal/shared/fees/explain.d.ts +81 -0
  134. package/dist/_internal/shared/fees/explain.js +101 -0
  135. package/dist/_internal/shared/history/index.d.ts +1 -1
  136. package/dist/_internal/shared/history/index.js +1 -1
  137. package/dist/_internal/shared/history/types.d.ts +7 -1
  138. package/dist/_internal/shared/history/types.js +25 -0
  139. package/dist/client.d.ts +21 -0
  140. package/dist/client.js +43 -0
  141. package/dist/constants/api-endpoints.d.ts +114 -0
  142. package/dist/constants/api-endpoints.js +55 -0
  143. package/dist/constants/field-names.d.ts +42 -0
  144. package/dist/constants/field-names.js +52 -0
  145. package/dist/contracts/index.d.ts +1 -1
  146. package/dist/contracts/shipping.d.ts +45 -0
  147. package/dist/contracts/shipping.js +15 -0
  148. package/dist/features/about/components/AboutView.js +1 -1
  149. package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
  150. package/dist/features/account/components/UserOrdersView.js +47 -35
  151. package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
  152. package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
  153. package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
  154. package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
  155. package/dist/features/admin/components/AdminInvoicingView.js +65 -0
  156. package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
  157. package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
  158. package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
  159. package/dist/features/admin/components/AdminOrdersView.js +86 -5
  160. package/dist/features/admin/components/OwnerQuickActions.js +24 -2
  161. package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
  162. package/dist/features/admin/constants/filter-tabs.js +6 -0
  163. package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
  164. package/dist/features/admin/hooks/useAdminListingData.js +16 -0
  165. package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
  166. package/dist/features/admin/schemas/firestore.d.ts +62 -0
  167. package/dist/features/admin/schemas/firestore.js +5 -0
  168. package/dist/features/ads/schemas/booking-write.d.ts +120 -0
  169. package/dist/features/ads/schemas/booking-write.js +75 -0
  170. package/dist/features/ads/schemas/creative-form.d.ts +18 -0
  171. package/dist/features/ads/schemas/creative-form.js +51 -0
  172. package/dist/features/ads/schemas/firestore.d.ts +140 -0
  173. package/dist/features/ads/schemas/firestore.js +109 -0
  174. package/dist/features/auctions/repository/bid.repository.js +3 -1
  175. package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
  176. package/dist/features/audit-log/schemas/firestore.js +89 -0
  177. package/dist/features/auth/actions/profile-actions.d.ts +69 -1
  178. package/dist/features/auth/actions/profile-actions.js +62 -1
  179. package/dist/features/auth/permissions/constants.js +13 -0
  180. package/dist/features/auth/schemas/firestore.d.ts +16 -2
  181. package/dist/features/auth/schemas/firestore.js +2 -1
  182. package/dist/features/blog/actions/blog-actions.d.ts +6 -0
  183. package/dist/features/blog/actions/blog-actions.js +17 -2
  184. package/dist/features/blog/api/route.js +4 -1
  185. package/dist/features/blog/columns/index.js +5 -0
  186. package/dist/features/blog/components/BlogIndexPageView.js +2 -1
  187. package/dist/features/blog/repository/blog.repository.d.ts +4 -0
  188. package/dist/features/blog/repository/blog.repository.js +5 -0
  189. package/dist/features/blog/schemas/blog-form.d.ts +3 -0
  190. package/dist/features/blog/schemas/blog-form.js +1 -0
  191. package/dist/features/blog/schemas/firestore.d.ts +38 -1
  192. package/dist/features/blog/schemas/firestore.js +23 -0
  193. package/dist/features/blog/schemas/index.d.ts +6 -0
  194. package/dist/features/blog/schemas/index.js +2 -0
  195. package/dist/features/blog/types/index.d.ts +2 -0
  196. package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
  197. package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
  198. package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
  199. package/dist/features/cart/components/PointsTenderPicker.js +15 -0
  200. package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
  201. package/dist/features/cart/components/index.d.ts +2 -0
  202. package/dist/features/cart/components/index.js +1 -0
  203. package/dist/features/cart/repository/cart.repository.d.ts +33 -0
  204. package/dist/features/cart/repository/cart.repository.js +47 -0
  205. package/dist/features/cart/schemas/firestore.d.ts +116 -0
  206. package/dist/features/contact/email.d.ts +27 -10
  207. package/dist/features/contact/email.js +20 -3
  208. package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
  209. package/dist/features/dashboard/components/DashboardHubView.js +56 -0
  210. package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
  211. package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
  212. package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
  213. package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
  214. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
  215. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
  216. package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
  217. package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
  218. package/dist/features/events/components/EventSaleBanner.js +1 -1
  219. package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
  220. package/dist/features/faq/components/FAQAccordion.js +29 -4
  221. package/dist/features/faq/components/FAQPageContent.js +2 -2
  222. package/dist/features/gateway-events/schemas/index.d.ts +2 -2
  223. package/dist/features/homepage/schemas/index.d.ts +8 -8
  224. package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
  225. package/dist/features/inventory/schemas/stock-reservation.js +103 -0
  226. package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
  227. package/dist/features/invoicing/schemas/firestore.js +45 -0
  228. package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
  229. package/dist/features/invoicing/utils/financial-year.js +53 -0
  230. package/dist/features/jobs/actions/enqueue-job.js +18 -1
  231. package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
  232. package/dist/features/jobs/repository/jobs.repository.js +84 -1
  233. package/dist/features/jobs/schemas/firestore.d.ts +80 -0
  234. package/dist/features/jobs/schemas/firestore.js +37 -0
  235. package/dist/features/layout/AppLayoutShell.d.ts +9 -1
  236. package/dist/features/layout/AppLayoutShell.js +12 -4
  237. package/dist/features/layout/BottomActions.js +2 -1
  238. package/dist/features/layout/BottomNavbar.d.ts +10 -2
  239. package/dist/features/layout/SideActionDock.js +52 -2
  240. package/dist/features/layout/TitleBarLayout.js +13 -4
  241. package/dist/features/layout/TitleBarLayout.style.css +59 -0
  242. package/dist/features/layout/useCtaReveal.d.ts +16 -1
  243. package/dist/features/layout/useCtaReveal.js +17 -26
  244. package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
  245. package/dist/features/ledger/repository/journal.repository.js +312 -0
  246. package/dist/features/ledger/schemas/expenses.d.ts +87 -0
  247. package/dist/features/ledger/schemas/expenses.js +27 -0
  248. package/dist/features/ledger/schemas/firestore.d.ts +183 -0
  249. package/dist/features/ledger/schemas/firestore.js +69 -0
  250. package/dist/features/lottery/schemas/zod.d.ts +6 -6
  251. package/dist/features/media/MediaImage.js +22 -1
  252. package/dist/features/media/upload/ImageUpload.js +1 -1
  253. package/dist/features/obligations/constants/policies.js +24 -1
  254. package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
  255. package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
  256. package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
  257. package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
  258. package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
  259. package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
  260. package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
  261. package/dist/features/orders/components/RefundRequestView.js +19 -1
  262. package/dist/features/orders/components/index.d.ts +4 -0
  263. package/dist/features/orders/components/index.js +2 -0
  264. package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
  265. package/dist/features/orders/constants/order-lane-tabs.js +88 -0
  266. package/dist/features/orders/repository/orders.repository.d.ts +85 -1
  267. package/dist/features/orders/repository/orders.repository.js +205 -6
  268. package/dist/features/orders/schemas/balance.d.ts +40 -0
  269. package/dist/features/orders/schemas/balance.js +47 -0
  270. package/dist/features/orders/schemas/firestore.d.ts +398 -1
  271. package/dist/features/orders/schemas/firestore.js +43 -0
  272. package/dist/features/orders/schemas/index.d.ts +56 -8
  273. package/dist/features/orders/schemas/index.js +12 -0
  274. package/dist/features/orders/types/index.d.ts +47 -0
  275. package/dist/features/orders/utils/courier-block.d.ts +25 -0
  276. package/dist/features/orders/utils/courier-block.js +23 -0
  277. package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
  278. package/dist/features/payment-cases/schemas/firestore.js +1 -0
  279. package/dist/features/payments/repository/payout.repository.js +3 -2
  280. package/dist/features/payments/schemas/firestore.d.ts +92 -1
  281. package/dist/features/payments/schemas/firestore.js +23 -0
  282. package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
  283. package/dist/features/pricing/components/AdminPricingView.js +157 -0
  284. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  285. package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
  286. package/dist/features/products/components/ProductDetailPageView.js +2 -2
  287. package/dist/features/products/schemas/firestore.d.ts +26 -1
  288. package/dist/features/products/schemas/firestore.js +2 -0
  289. package/dist/features/products/schemas/index.d.ts +2 -2
  290. package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
  291. package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
  292. package/dist/features/promotions/actions/coupon-stacking.js +21 -2
  293. package/dist/features/promotions/components/CouponCard.js +13 -0
  294. package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
  295. package/dist/features/promotions/constants/coupon-help.js +9 -1
  296. package/dist/features/promotions/schemas/firestore.d.ts +24 -0
  297. package/dist/features/promotions/schemas/firestore.js +4 -0
  298. package/dist/features/promotions/types/index.d.ts +19 -1
  299. package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
  300. package/dist/features/reviews/repository/reviews.repository.js +16 -0
  301. package/dist/features/scams/components/ScamProfileView.js +2 -2
  302. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  303. package/dist/features/scams/repository/scammer.repository.js +2 -1
  304. package/dist/features/scams/schemas/firestore.d.ts +2 -1
  305. package/dist/features/scams/schemas/firestore.js +2 -1
  306. package/dist/features/search/action-index/tab-entries.js +1 -1
  307. package/dist/features/seller/actions/offer-actions.js +56 -0
  308. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  309. package/dist/features/seller/actions/seller-actions.js +37 -3
  310. package/dist/features/seller/components/DispatchForm.d.ts +11 -0
  311. package/dist/features/seller/components/DispatchForm.js +190 -0
  312. package/dist/features/seller/components/SellerOrdersView.js +221 -27
  313. package/dist/features/seller/components/index.d.ts +1 -0
  314. package/dist/features/seller/components/index.js +1 -0
  315. package/dist/features/seller/hooks/useSellerListingData.js +25 -0
  316. package/dist/features/seller/repository/offer.repository.js +4 -3
  317. package/dist/features/seller/schemas/firestore.d.ts +23 -2
  318. package/dist/features/seller/schemas/firestore.js +3 -2
  319. package/dist/features/seller/schemas/index.d.ts +4 -4
  320. package/dist/features/seller/schemas/order-forms.d.ts +61 -4
  321. package/dist/features/seller/schemas/order-forms.js +41 -8
  322. package/dist/features/shipments/schemas/firestore.d.ts +25 -0
  323. package/dist/features/shipments/schemas/validation.d.ts +4 -4
  324. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
  325. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
  326. package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
  327. package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
  328. package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
  329. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
  330. package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
  331. package/dist/features/stores/repository/store.repository.d.ts +18 -0
  332. package/dist/features/stores/repository/store.repository.js +27 -1
  333. package/dist/features/stores/schemas/firestore.d.ts +112 -0
  334. package/dist/features/stores/schemas/firestore.js +20 -0
  335. package/dist/features/stores/schemas/index.d.ts +6 -6
  336. package/dist/features/stores/types/index.d.ts +19 -0
  337. package/dist/features/support/repository/support.repository.js +72 -6
  338. package/dist/features/support/schemas/firestore.d.ts +17 -0
  339. package/dist/features/support/schemas/index.d.ts +8 -8
  340. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  341. package/dist/index.d.ts +11 -1
  342. package/dist/index.js +33 -1
  343. package/dist/next/routing/route-map.d.ts +112 -0
  344. package/dist/next/routing/route-map.js +63 -0
  345. package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
  346. package/dist/providers/shipping-shiprocket/index.js +84 -1
  347. package/dist/react/contexts/SessionContext.d.ts +17 -1
  348. package/dist/schemas/registry.d.ts +69 -34
  349. package/dist/schemas/sieve.d.ts +2 -2
  350. package/dist/security/pii-schemas.d.ts +1 -1
  351. package/dist/security/pii-schemas.js +45 -0
  352. package/dist/server-entry.d.ts +2 -2
  353. package/dist/server-entry.js +8 -1
  354. package/dist/server.d.ts +36 -1
  355. package/dist/server.js +183 -1
  356. package/dist/styles.css +412 -80
  357. package/dist/tailwind-utilities.css +1 -1
  358. package/dist/tokens/themes/default-dark.js +1 -0
  359. package/dist/tokens/themes/default-light.js +1 -0
  360. package/dist/tokens/themes/required.d.ts +1 -1
  361. package/dist/tokens/themes/required.js +1 -0
  362. package/dist/tokens/tokens.css +15 -0
  363. package/dist/ui/components/Button.d.ts +10 -1
  364. package/dist/ui/components/Button.js +25 -3
  365. package/dist/ui/components/Chart.d.ts +63 -0
  366. package/dist/ui/components/Chart.js +169 -0
  367. package/dist/ui/components/Chart.style.css +214 -0
  368. package/dist/ui/components/Disclaimer.d.ts +19 -0
  369. package/dist/ui/components/Disclaimer.js +83 -0
  370. package/dist/ui/components/OverflowRow.js +54 -2
  371. package/dist/ui/components/OverflowRow.style.css +38 -0
  372. package/dist/ui/components/RichTextEditor.js +99 -8
  373. package/dist/ui/components/chart-spec.d.ts +68 -0
  374. package/dist/ui/components/chart-spec.js +140 -0
  375. package/dist/ui/components/index.style.css +1 -0
  376. package/dist/ui/components/surface-tokens.d.ts +1 -1
  377. package/dist/ui/components/surface-tokens.js +9 -0
  378. package/dist/ui/components/tabs-overflow.js +64 -11
  379. package/dist/ui/components/toolbar-collapse.d.ts +13 -0
  380. package/dist/ui/components/toolbar-collapse.js +10 -1
  381. package/dist/ui/index.d.ts +8 -0
  382. package/dist/ui/index.js +9 -0
  383. package/dist/ui/rich-text/RichText.d.ts +10 -1
  384. package/dist/ui/rich-text/RichText.js +33 -2
  385. package/dist/ui/rich-text/RichText.style.css +83 -79
  386. package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
  387. package/dist/ui/rich-text/RichTextRenderer.js +34 -2
  388. package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
  389. package/dist/ui/rich-text/chart-blocks.js +87 -0
  390. package/package.json +1 -1
  391. package/scripts/seed-cli.mjs +1834 -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);
@@ -1,3 +1,16 @@
1
+ /** Below this the toolbar defaults to collapsed. Matches the `lg` boundary
2
+ * that both toolbars already use to switch between their mobile and desktop
3
+ * rows, so the default flips at the same width the layout does. */
4
+ /**
5
+ * Below `lg` — the complement of `DESKTOP_QUERY` in `features/layout`.
6
+ *
7
+ * Exported so `OverflowRow` can dock its collapsed control into the bottom bar
8
+ * at exactly the width the tab bar exists at. It is NOT imported from
9
+ * `features/layout`: this is `ui/`, and a `ui → features` edge inverts the
10
+ * layering and is how `audit-import-cycles` regressions start. One literal in
11
+ * the lower layer, shared, beats two that can drift apart.
12
+ */
13
+ export declare const MOBILE_QUERY = "(max-width: 1023px)";
1
14
  /**
2
15
  * Tri-state on purpose: `null` means "the user has never chosen", which is
3
16
  * what lets the viewport supply the default. A plain boolean cannot express
@@ -19,7 +19,16 @@ const STORAGE_PREFIX = "appkit:sticky-toolbar-collapsed:";
19
19
  /** Below this the toolbar defaults to collapsed. Matches the `lg` boundary
20
20
  * that both toolbars already use to switch between their mobile and desktop
21
21
  * rows, so the default flips at the same width the layout does. */
22
- const MOBILE_QUERY = "(max-width: 1023px)";
22
+ /**
23
+ * Below `lg` — the complement of `DESKTOP_QUERY` in `features/layout`.
24
+ *
25
+ * Exported so `OverflowRow` can dock its collapsed control into the bottom bar
26
+ * at exactly the width the tab bar exists at. It is NOT imported from
27
+ * `features/layout`: this is `ui/`, and a `ui → features` edge inverts the
28
+ * layering and is how `audit-import-cycles` regressions start. One literal in
29
+ * the lower layer, shared, beats two that can drift apart.
30
+ */
31
+ export const MOBILE_QUERY = "(max-width: 1023px)";
23
32
  /**
24
33
  * Tri-state on purpose: `null` means "the user has never chosen", which is
25
34
  * what lets the viewport supply the default. A plain boolean cannot express
@@ -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";
@@ -93,6 +95,10 @@ export type { SliderProps } from "./components/Slider";
93
95
  export { Slider } from "./components/Slider";
94
96
  export type { CheckboxProps } from "./components/Checkbox";
95
97
  export { Checkbox } from "./components/Checkbox";
98
+ export type { ChartProps } from "./components/Chart";
99
+ export { Chart, ChartFromJson } from "./components/Chart";
100
+ export type { ChartKind, ChartSeries, ChartSpec, ChartSpecResult, } from "./components/chart-spec";
101
+ export { CHART_KINDS, CHART_MAX_SERIES, exceedsSeriesLimit, parseChartAttr, parseChartSpec, } from "./components/chart-spec";
96
102
  export type { RadioGroupProps, RadioOption, RadioItemProps } from "./components/Radio";
97
103
  export { RadioGroup, RadioItem } from "./components/Radio";
98
104
  export type { ToggleProps } from "./components/Toggle";
@@ -209,6 +215,8 @@ export type { RichTextProps } from "./rich-text/RichText";
209
215
  export { RichText } from "./rich-text/RichText";
210
216
  export type { RichTextRendererProps } from "./rich-text/RichTextRenderer";
211
217
  export { RichTextRenderer } from "./rich-text/RichTextRenderer";
218
+ export type { RichTextSegment } from "./rich-text/chart-blocks";
219
+ export { chartFigureHtml, hasChartBlock, splitChartBlocks, } from "./rich-text/chart-blocks";
212
220
  export type { RichTextEditorProps } from "./components/RichTextEditor";
213
221
  export { RichTextEditor } from "./components/RichTextEditor";
214
222
  export type { ListingLayoutProps, ListingLayoutLabels, } from "./components/ListingLayout";
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) --------------------
@@ -76,6 +82,8 @@ export { DateInput, DateRangeInput } from "./components/DateInput.js";
76
82
  export { Textarea } from "./components/Textarea.js";
77
83
  export { Slider } from "./components/Slider.js";
78
84
  export { Checkbox } from "./components/Checkbox.js";
85
+ export { Chart, ChartFromJson } from "./components/Chart.js";
86
+ export { CHART_KINDS, CHART_MAX_SERIES, exceedsSeriesLimit, parseChartAttr, parseChartSpec, } from "./components/chart-spec.js";
79
87
  export { RadioGroup, RadioItem } from "./components/Radio.js";
80
88
  export { Toggle } from "./components/Toggle.js";
81
89
  export { QuantityStepper } from "./components/QuantityStepper.js";
@@ -142,6 +150,7 @@ export { classNames, mergeTailwindClasses } from "./style.helper.js";
142
150
  export { SideModal } from "./components/SideModal.js";
143
151
  export { RichText } from "./rich-text/RichText.js";
144
152
  export { RichTextRenderer } from "./rich-text/RichTextRenderer.js";
153
+ export { chartFigureHtml, hasChartBlock, splitChartBlocks, } from "./rich-text/chart-blocks.js";
145
154
  export { RichTextEditor } from "./components/RichTextEditor.js";
146
155
  export { ListingLayout } from "./components/ListingLayout.js";
147
156
  export { SlottedListingView } from "./components/SlottedListingView.js";
@@ -29,6 +29,15 @@ export interface RichTextProps {
29
29
  * ```
30
30
  */
31
31
  highlightCode?: (code: string, lang: string) => string;
32
+ /**
33
+ * Render `<figure data-chart>` placeholders as live charts. Default true.
34
+ *
35
+ * Set `false` for untrusted user-generated content where an author should not
36
+ * be able to mount a component at all — the placeholder then renders as the
37
+ * empty `<figure>` it is. The JSON is still validated either way; this is
38
+ * about whether a chart is an affordance on that surface.
39
+ */
40
+ charts?: boolean;
32
41
  }
33
42
  /**
34
43
  * RichText renders sanitised HTML from a CMS / ProseMirror output.
@@ -42,4 +51,4 @@ export interface RichTextProps {
42
51
  * <RichText html={desc} copyableCode />
43
52
  * ```
44
53
  */
45
- export declare function RichText({ html, className, proseClass, copyableCode, highlightCode, }: RichTextProps): import("react").JSX.Element;
54
+ export declare function RichText({ html, className, proseClass, copyableCode, highlightCode, charts, }: RichTextProps): import("react").JSX.Element;
@@ -3,6 +3,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useMemo } from "react";
4
4
  import { Div } from "../components/Div.js";
5
5
  import { normalizeRichTextHtml } from "../../utils/string.formatter.js";
6
+ import { splitChartBlocks } from "./chart-blocks.js";
7
+ import { ChartFromJson } from "../components/Chart.js";
6
8
  // --- Allowed HTML tags (safe subset — no script/object; iframe allowed for YouTube only) -------
7
9
  const ALLOWED_TAGS = new Set([
8
10
  "p",
@@ -52,6 +54,19 @@ const ALLOWED_ATTRS = {
52
54
  "*": ["class", "id", "lang", "dir", "aria-label", "role", "tabindex"],
53
55
  a: ["href", "title", "target", "rel"],
54
56
  img: ["src", "alt", "width", "height", "loading", "data-align"],
57
+ /*
58
+ * `data-chart` carries a JSON ChartSpec that the renderer hydrates into
59
+ * <Chart>. Safe to allow because it is DATA, never markup: it is read with
60
+ * `getAttribute`, run through `JSON.parse`, and then validated field-by-field
61
+ * by `parseChartSpec`, which accepts only a fixed `kind` enum, string labels
62
+ * and finite numbers. Nothing in it reaches `innerHTML`, so a script payload
63
+ * smuggled into the string fails validation and renders as an error message.
64
+ *
65
+ * 🛑 It must stay on `figure` only. Allowing it via "*" would let it ride on
66
+ * an <a> or <iframe>, where the surrounding element's own attack surface is
67
+ * the problem rather than the attribute.
68
+ */
69
+ figure: ["data-chart"],
55
70
  td: ["colspan", "rowspan"],
56
71
  th: ["colspan", "rowspan", "scope"],
57
72
  ol: ["type", "start"],
@@ -167,7 +182,7 @@ function attachCopyButtons(container) {
167
182
  * <RichText html={desc} copyableCode />
168
183
  * ```
169
184
  */
170
- export function RichText({ html, className = "", proseClass = "prose max-w-none dark:prose-invert", copyableCode = false, highlightCode, }) {
185
+ export function RichText({ html, className = "", proseClass = "prose max-w-none dark:prose-invert", copyableCode = false, highlightCode, charts = true, }) {
171
186
  const safe = useMemo(() => {
172
187
  const sanitized = sanitiseHtml(normalizeRichTextHtml(html));
173
188
  if (!highlightCode || typeof document === "undefined")
@@ -186,5 +201,21 @@ export function RichText({ html, className = "", proseClass = "prose max-w-none
186
201
  attachCopyButtons(el);
187
202
  }
188
203
  };
189
- return (_jsx(Div, { ref: ref, className: `appkit-rich-text ${proseClass} ${className}`, dangerouslySetInnerHTML: { __html: safe } }));
204
+ /*
205
+ * Split AFTER sanitising, never before.
206
+ *
207
+ * The sanitiser round-trips through `DOMParser` and re-serialises, which
208
+ * rewrites the single-quoted `data-chart='{"k":1}'` we emit into
209
+ * double-quoted `data-chart="{&quot;k&quot;:1}"`. `splitChartBlocks` handles
210
+ * both spellings precisely because of this step — splitting first would
211
+ * leave chart segments that the sanitiser never got to inspect.
212
+ */
213
+ const segments = useMemo(() => (charts ? splitChartBlocks(safe) : [{ type: "html", html: safe }]), [safe, charts]);
214
+ // Fast path: no charts. Byte-identical to the pre-chart render.
215
+ if (segments.length === 1 && segments[0].type === "html") {
216
+ return (_jsx(Div, { ref: ref, className: `appkit-rich-text ${proseClass} ${className}`, dangerouslySetInnerHTML: { __html: segments[0].html } }));
217
+ }
218
+ return (_jsx(Div, { ref: ref, className: `appkit-rich-text ${proseClass} ${className}`, children: segments.map((seg, i) => seg.type === "html" ? (_jsx("div", { className: "appkit-rich-text__seg", dangerouslySetInnerHTML: { __html: seg.html } }, `h${i}`)) : (
219
+ // eslint-disable-next-line react/no-array-index-key
220
+ _jsx(ChartFromJson, { json: seg.json }, `c${i}`))) }));
190
221
  }
@@ -25,6 +25,24 @@
25
25
  border-bottom-color: var(--appkit-color-border);
26
26
  }
27
27
 
28
+ /*
29
+ * The chart-draft panel the toolbar's "Chart" button opens.
30
+ *
31
+ * It sits between the toolbar and the editable area, so it needs the same
32
+ * recessive surface the toolbar has — without it the panel reads as part of the
33
+ * document being edited rather than as editor chrome, which is misleading when
34
+ * the thing inside it is a block of JSON.
35
+ */
36
+ .appkit-rich-text-editor__chart {
37
+ background-color: var(--appkit-color-surface-raised);
38
+ border-bottom: 1px solid var(--appkit-color-border);
39
+ }
40
+
41
+ .dark .appkit-rich-text-editor__chart {
42
+ background-color: var(--appkit-color-slate-900);
43
+ border-bottom-color: var(--appkit-color-border);
44
+ }
45
+
28
46
  .appkit-rich-text-editor__btn {
29
47
  border: 1px solid var(--appkit-color-border);
30
48
  color: var(--appkit-color-zinc-700);
@@ -43,77 +61,42 @@
43
61
 
44
62
 
45
63
  /* --------------------------------------------------------------------------
46
- * THE PROSE PALETTE — rebound to appkit theme tokens.
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.
64
+ * THE PROSE PALETTE LIVES IN THE CONSUMER, NOT HERE.
51
65
  *
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.
66
+ * 🛑 Do NOT reinstate a `:root .prose { --tw-prose-*: ... !important }` block
67
+ * in this file. One lived here for months and it NEVER APPLIED.
58
68
  *
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.
69
+ * The typography plugin emits `.prose { --tw-prose-*: <tailwind gray> }`, and
70
+ * the consumer's `important: true` makes each of those `!important` inside
71
+ * `@layer utilities`. The block here was unlayered, and justified itself with
72
+ * "`:root .prose` is (0,2,0) against `.prose`'s (0,1,0), so specificity
73
+ * decides and the outcome does not depend on bundle order."
65
74
  *
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.
75
+ * Specificity is never consulted. For the IMPORTANT tier, cascade-layer order
76
+ * is REVERSED and unlayered sorts LOWEST, so a layered `!important` beats an
77
+ * unlayered one at any specificity (Root Cause #106, measured in a browser).
78
+ * The plugin's hardcoded light-mode grays therefore won in every theme —
79
+ * links at gray-900, i.e. near-black on the near-black dark page, and
80
+ * black-instead-of-teal in light. The fix was invisible to every gate because
81
+ * the CSS was present and correct-looking in `dist/styles.css`; only a
82
+ * rendered page shows it losing.
70
83
  *
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).
84
+ * Owner is now `tailwind.config.js` → `theme.extend.typography`, which makes
85
+ * the plugin emit the appkit tokens in the first place so there is exactly
86
+ * one declaration and no contest. Each binds to an `--appkit-color-*` that is
87
+ * redefined per theme, so prose re-themes for the built-in themes and for any
88
+ * admin-authored one.
76
89
  *
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.
84
- *
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.
90
+ * 🛑 `dark:prose-invert` CANNOT COMPILE IN THIS PROJECT. Do not "fix" dark
91
+ * rich text by adding it to a call site, and do not add
92
+ * `@source inline("dark:prose-invert")` to globals.css. Every `proseClass`
93
+ * string in appkit carries it and none has ever generated a rule, because the
94
+ * consumer build excludes appkit from scanning (`src/app/globals.css` →
95
+ * `@source not "../../appkit"`) and `appkit/tailwind.config.js` does not load
96
+ * `@tailwindcss/typography`, so appkit's own `dist/tailwind-utilities.css`
97
+ * cannot emit it either. It is moot now regardless: the tokens above invert on
98
+ * their own, which `prose-invert` could never do with its hardcoded grays.
87
99
  * -------------------------------------------------------------------------- */
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
100
 
118
101
  /* --------------------------------------------------------------------------
119
102
  * Base wrapper. All selectors are scoped to .appkit-rich-text so they
@@ -200,27 +183,31 @@
200
183
  }
201
184
 
202
185
  /* --- Links ---------------------------------------------------------------- */
186
+ /* No `.dark` variant, deliberately: `--appkit-color-link` is redefined per
187
+ * theme, so one rule covers every theme including admin-authored ones. The two
188
+ * `.dark .appkit-rich-text a` rules that used to sit here were also dead —
189
+ * non-important against the plugin's `.prose :where(a){color:…!important}`.
190
+ *
191
+ * Decoration binds to `currentColor` rather than naming the token a second
192
+ * time. That matters beyond brevity: the colour here IS still overridden by
193
+ * the plugin on any element that also carries `.prose`, so a hardcoded
194
+ * decoration colour could disagree with the ink actually rendered. With
195
+ * `currentColor` the underline follows whatever won. */
203
196
  .appkit-rich-text a {
204
- color: var(--appkit-color-primary-600);
197
+ color: var(--appkit-color-link);
205
198
  text-decoration: underline;
206
- text-decoration-color: color-mix(in srgb, var(--appkit-color-primary-600) 60%, transparent);
199
+ text-decoration-color: color-mix(in srgb, currentColor 60%, transparent);
207
200
  text-underline-offset: 2px;
208
201
  transition: color 150ms, text-decoration-color 150ms;
209
202
  }
210
203
 
204
+ /* Hover moves the link toward the page's own text colour, which darkens it in
205
+ * a light theme and lightens it in a dark one — so this needs no per-theme
206
+ * pair either. The plugin sets no `a:hover`, so unlike the resting colour
207
+ * above this rule is genuinely the one in effect. */
211
208
  .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);
209
+ color: color-mix(in srgb, var(--appkit-color-link) 80%, var(--appkit-color-text));
210
+ text-decoration-color: currentColor;
224
211
  }
225
212
 
226
213
  /* --- Tables --------------------------------------------------------------- */
@@ -362,3 +349,20 @@
362
349
  .dark .appkit-rich-text del {
363
350
  color: var(--appkit-color-zinc-400);
364
351
  }
352
+
353
+ /*
354
+ * Chart-block segment wrapper.
355
+ *
356
+ * `RichTextRenderer` has to split the HTML around `<figure data-chart>` and
357
+ * each resulting run needs an element to carry `dangerouslySetInnerHTML` —
358
+ * there is no way to inject HTML without one. `display: contents` removes that
359
+ * element from the box tree so the runs lay out exactly as they did when they
360
+ * were one `innerHTML` dump.
361
+ *
362
+ * 🛑 Without this, `prose`'s adjacency and first/last-child margin rules
363
+ * restart at every chart, so paragraphs either side of a chart space
364
+ * differently from paragraphs anywhere else on the page.
365
+ */
366
+ .appkit-rich-text__seg {
367
+ display: contents;
368
+ }
@@ -3,6 +3,14 @@ export interface RichTextRendererProps {
3
3
  html?: string | null;
4
4
  className?: string;
5
5
  proseClass?: string;
6
+ /**
7
+ * Render `<figure data-chart>` placeholders as live charts. Default true.
8
+ *
9
+ * Pass `false` where a chart cannot work — an email body, a plain-text
10
+ * export, an OG image — so the placeholder is simply dropped rather than
11
+ * mounting a client component into a context that cannot hydrate it.
12
+ */
13
+ charts?: boolean;
6
14
  }
7
15
  /**
8
16
  * SSR-safe HTML renderer for admin/CMS-authored rich text content.
@@ -12,5 +20,26 @@ export interface RichTextRendererProps {
12
20
  *
13
21
  * For user-generated content or untrusted HTML, use <RichText> instead
14
22
  * (client-only, runs the DOM-based sanitizer).
23
+ *
24
+ * ## 🛑 It is no longer a single `innerHTML` dump, and why that is safe
25
+ *
26
+ * Chart blocks are stored as `<figure data-chart='{json}'>` and have to become
27
+ * real components to be theme-aware, so the HTML is split and the chart
28
+ * segments are replaced with `<ChartFromJson>`. Two properties keep this from
29
+ * being a regression:
30
+ *
31
+ * - **The fast path is unchanged.** `splitChartBlocks` rejects on a substring
32
+ * test, so content with no chart returns one segment and renders through the
33
+ * same single `dangerouslySetInnerHTML` as before.
34
+ * - **Splitting cannot introduce markup.** Segments are slices of the original
35
+ * string, concatenated in document order; nothing is rewritten. A malformed
36
+ * chart figure fails the match and stays ordinary HTML.
37
+ *
38
+ * 🛑 The prose wrapper stays on the OUTER element, and each segment's own
39
+ * wrapper is `display: contents` (`.appkit-rich-text__seg`). A segment needs an
40
+ * element to carry `dangerouslySetInnerHTML`, but leaving that element in the
41
+ * box tree restarts `prose`'s adjacency and first/last-child margin rules at
42
+ * every chart — so paragraphs either side of a chart would space differently
43
+ * from paragraphs anywhere else on the page.
15
44
  */
16
- export declare function RichTextRenderer({ html, className, proseClass, }: RichTextRendererProps): React.JSX.Element | null;
45
+ export declare function RichTextRenderer({ html, className, proseClass, charts, }: RichTextRendererProps): React.JSX.Element | null;
@@ -1,4 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { splitChartBlocks } from "./chart-blocks.js";
3
+ import { ChartFromJson } from "../components/Chart.js";
2
4
  /**
3
5
  * SSR-safe HTML renderer for admin/CMS-authored rich text content.
4
6
  *
@@ -7,9 +9,39 @@ import { jsx as _jsx } from "react/jsx-runtime";
7
9
  *
8
10
  * For user-generated content or untrusted HTML, use <RichText> instead
9
11
  * (client-only, runs the DOM-based sanitizer).
12
+ *
13
+ * ## 🛑 It is no longer a single `innerHTML` dump, and why that is safe
14
+ *
15
+ * Chart blocks are stored as `<figure data-chart='{json}'>` and have to become
16
+ * real components to be theme-aware, so the HTML is split and the chart
17
+ * segments are replaced with `<ChartFromJson>`. Two properties keep this from
18
+ * being a regression:
19
+ *
20
+ * - **The fast path is unchanged.** `splitChartBlocks` rejects on a substring
21
+ * test, so content with no chart returns one segment and renders through the
22
+ * same single `dangerouslySetInnerHTML` as before.
23
+ * - **Splitting cannot introduce markup.** Segments are slices of the original
24
+ * string, concatenated in document order; nothing is rewritten. A malformed
25
+ * chart figure fails the match and stays ordinary HTML.
26
+ *
27
+ * 🛑 The prose wrapper stays on the OUTER element, and each segment's own
28
+ * wrapper is `display: contents` (`.appkit-rich-text__seg`). A segment needs an
29
+ * element to carry `dangerouslySetInnerHTML`, but leaving that element in the
30
+ * box tree restarts `prose`'s adjacency and first/last-child margin rules at
31
+ * every chart — so paragraphs either side of a chart would space differently
32
+ * from paragraphs anywhere else on the page.
10
33
  */
11
- export function RichTextRenderer({ html, className = "", proseClass = "prose max-w-none dark:prose-invert", }) {
34
+ export function RichTextRenderer({ html, className = "", proseClass = "prose max-w-none dark:prose-invert", charts = true, }) {
12
35
  if (!html)
13
36
  return null;
14
- return (_jsx("div", { className: `appkit-rich-text ${proseClass} ${className}`.trim(), dangerouslySetInnerHTML: { __html: html } }));
37
+ const wrapperClass = `appkit-rich-text ${proseClass} ${className}`.trim();
38
+ const segments = charts ? splitChartBlocks(html) : [{ type: "html", html }];
39
+ // Single HTML segment — the overwhelmingly common case. Identical to the
40
+ // pre-chart behaviour, down to the element shape.
41
+ if (segments.length === 1 && segments[0].type === "html") {
42
+ return (_jsx("div", { className: wrapperClass, dangerouslySetInnerHTML: { __html: segments[0].html } }));
43
+ }
44
+ return (_jsx("div", { className: wrapperClass, children: segments.map((seg, i) => seg.type === "html" ? (_jsx("div", { className: "appkit-rich-text__seg", dangerouslySetInnerHTML: { __html: seg.html } }, `h${i}`)) : (
45
+ // eslint-disable-next-line react/no-array-index-key
46
+ _jsx(ChartFromJson, { json: seg.json }, `c${i}`))) }));
15
47
  }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Splitting rich-text HTML around `<figure data-chart>` placeholders.
3
+ *
4
+ * ## 🛑 Why this is regex and not a DOM parse
5
+ *
6
+ * `RichTextRenderer` is a React Server Component — no `DOMParser`, no
7
+ * `document`. So the split has to work on the string, and it is only safe to do
8
+ * that because the shape being matched is one we WRITE: a childless
9
+ * `<figure data-chart='…'></figure>` emitted by the chart toolbar button.
10
+ *
11
+ * This is deliberately not a general HTML parser and must not grow into one. It
12
+ * matches exactly one element shape and hands everything else through
13
+ * untouched, so a malformed chart figure degrades to "rendered as ordinary
14
+ * HTML" rather than corrupting the document around it.
15
+ *
16
+ * ## 🛑 Why the JSON needs entity decoding
17
+ *
18
+ * A `ChartSpec` is full of `"` characters, so the attribute is written
19
+ * single-quoted. But anything that round-trips the HTML through a DOM — the
20
+ * client sanitiser's `DOMParser`, a contenteditable surface, an admin preview —
21
+ * re-serialises it double-quoted with the inner quotes as `&quot;`. Both
22
+ * spellings therefore occur in stored content, and a renderer that handles only
23
+ * the one it writes will fail on its own saved output.
24
+ *
25
+ * Pure. No React, no DOM, safe on the server.
26
+ */
27
+ import type { ChartSpec } from "../components/chart-spec";
28
+ /** A run of ordinary HTML, or a chart placeholder's raw JSON payload. */
29
+ export type RichTextSegment = {
30
+ type: "html";
31
+ html: string;
32
+ } | {
33
+ type: "chart";
34
+ json: string;
35
+ };
36
+ /**
37
+ * Decode the entity subset an HTML serialiser can introduce inside an
38
+ * attribute value.
39
+ *
40
+ * 🛑 `&amp;` is decoded LAST. Decoding it first turns a legitimately encoded
41
+ * `&amp;quot;` into `&quot;` and then into `"`, which injects a quote the
42
+ * author never wrote and breaks the JSON parse — the classic double-decode bug.
43
+ */
44
+ export declare function decodeAttrEntities(s: string): string;
45
+ /**
46
+ * Split HTML into alternating prose and chart segments, in document order.
47
+ *
48
+ * Returns a single `html` segment when there are no charts, so the common case
49
+ * costs one regex test and the caller's fast path stays a plain innerHTML
50
+ * render.
51
+ */
52
+ export declare function splitChartBlocks(html: string): RichTextSegment[];
53
+ /** True when the content carries at least one chart placeholder. Stateless. */
54
+ export declare function hasChartBlock(html: string | null | undefined): boolean;
55
+ /**
56
+ * Build the placeholder a toolbar or a seed fixture should emit.
57
+ *
58
+ * Single-quoted, with any single quote in the payload escaped as `&#39;` so the
59
+ * attribute cannot be terminated early by a label containing an apostrophe —
60
+ * "Blader's choice" is an entirely ordinary series label.
61
+ */
62
+ export declare function chartFigureHtml(spec: ChartSpec): string;