@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.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -29
- package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
- package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
- package/dist/_internal/server/features/ads/booking.d.ts +118 -0
- package/dist/_internal/server/features/ads/booking.js +326 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
- package/dist/_internal/server/features/checkout/actions.js +850 -79
- package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
- package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
- package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
- package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
- package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
- package/dist/_internal/server/features/dashboard/attention.js +183 -0
- package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
- package/dist/_internal/server/features/dashboard/data.js +82 -0
- package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
- package/dist/_internal/server/features/inventory/reservations.js +273 -0
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
- package/dist/_internal/server/features/offers/destinations.js +65 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +54 -0
- package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
- package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
- package/dist/_internal/server/features/orders/balance.d.ts +89 -0
- package/dist/_internal/server/features/orders/balance.js +256 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
- package/dist/_internal/server/features/pricing/actions.js +144 -0
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
- package/dist/_internal/server/features/shipping/book-split.js +130 -0
- package/dist/_internal/server/features/shipping/book.d.ts +61 -0
- package/dist/_internal/server/features/shipping/book.js +176 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +264 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +29 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +65 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +95 -2
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +296 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
- package/dist/_internal/shared/checkout/order-math.js +159 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
- package/dist/_internal/shared/checkout/rules/index.js +1 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
- package/dist/_internal/shared/checkout/split.d.ts +75 -0
- package/dist/_internal/shared/checkout/split.js +120 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +93 -0
- package/dist/_internal/shared/content/published-values.js +206 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
- package/dist/_internal/shared/features/admin/integrations.js +263 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
- package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
- package/dist/_internal/shared/features/emi/choice.js +69 -0
- package/dist/_internal/shared/features/emi/group.d.ts +84 -0
- package/dist/_internal/shared/features/emi/group.js +126 -0
- package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
- package/dist/_internal/shared/features/ledger/posting.js +165 -0
- package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
- package/dist/_internal/shared/features/ledger/reports.js +127 -0
- package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
- package/dist/_internal/shared/features/ledger/rules.js +221 -0
- package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
- package/dist/_internal/shared/features/offers/coordination.js +80 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
- package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
- package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
- package/dist/_internal/shared/features/points/accepts.js +49 -0
- package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
- package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
- package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
- package/dist/_internal/shared/features/shipping/parcel.js +139 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
- package/dist/_internal/shared/features/site-settings/fees.js +12 -8
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/_internal/shared/fees/explain.d.ts +81 -0
- package/dist/_internal/shared/fees/explain.js +101 -0
- package/dist/_internal/shared/history/index.d.ts +1 -1
- package/dist/_internal/shared/history/index.js +1 -1
- package/dist/_internal/shared/history/types.d.ts +7 -1
- package/dist/_internal/shared/history/types.js +25 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +43 -0
- package/dist/constants/api-endpoints.d.ts +114 -0
- package/dist/constants/api-endpoints.js +55 -0
- package/dist/constants/field-names.d.ts +42 -0
- package/dist/constants/field-names.js +52 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOrdersView.js +47 -35
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
- package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +86 -5
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +62 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/ads/schemas/booking-write.d.ts +120 -0
- package/dist/features/ads/schemas/booking-write.js +75 -0
- package/dist/features/ads/schemas/creative-form.d.ts +18 -0
- package/dist/features/ads/schemas/creative-form.js +51 -0
- package/dist/features/ads/schemas/firestore.d.ts +140 -0
- package/dist/features/ads/schemas/firestore.js +109 -0
- package/dist/features/auctions/repository/bid.repository.js +3 -1
- package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
- package/dist/features/audit-log/schemas/firestore.js +89 -0
- package/dist/features/auth/actions/profile-actions.d.ts +69 -1
- package/dist/features/auth/actions/profile-actions.js +62 -1
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/auth/schemas/firestore.d.ts +16 -2
- package/dist/features/auth/schemas/firestore.js +2 -1
- package/dist/features/blog/actions/blog-actions.d.ts +6 -0
- package/dist/features/blog/actions/blog-actions.js +17 -2
- package/dist/features/blog/api/route.js +4 -1
- package/dist/features/blog/columns/index.js +5 -0
- package/dist/features/blog/components/BlogIndexPageView.js +2 -1
- package/dist/features/blog/repository/blog.repository.d.ts +4 -0
- package/dist/features/blog/repository/blog.repository.js +5 -0
- package/dist/features/blog/schemas/blog-form.d.ts +3 -0
- package/dist/features/blog/schemas/blog-form.js +1 -0
- package/dist/features/blog/schemas/firestore.d.ts +38 -1
- package/dist/features/blog/schemas/firestore.js +23 -0
- package/dist/features/blog/schemas/index.d.ts +6 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +2 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
- package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +33 -0
- package/dist/features/cart/repository/cart.repository.js +47 -0
- package/dist/features/cart/schemas/firestore.d.ts +116 -0
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
- package/dist/features/dashboard/components/DashboardHubView.js +56 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/faq/components/FAQPageContent.js +2 -2
- package/dist/features/gateway-events/schemas/index.d.ts +2 -2
- package/dist/features/homepage/schemas/index.d.ts +8 -8
- package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
- package/dist/features/inventory/schemas/stock-reservation.js +103 -0
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/layout/AppLayoutShell.d.ts +9 -1
- package/dist/features/layout/AppLayoutShell.js +12 -4
- package/dist/features/layout/BottomActions.js +2 -1
- package/dist/features/layout/BottomNavbar.d.ts +10 -2
- package/dist/features/layout/SideActionDock.js +52 -2
- package/dist/features/layout/TitleBarLayout.js +13 -4
- package/dist/features/layout/TitleBarLayout.style.css +59 -0
- package/dist/features/layout/useCtaReveal.d.ts +16 -1
- package/dist/features/layout/useCtaReveal.js +17 -26
- package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
- package/dist/features/ledger/repository/journal.repository.js +312 -0
- package/dist/features/ledger/schemas/expenses.d.ts +87 -0
- package/dist/features/ledger/schemas/expenses.js +27 -0
- package/dist/features/ledger/schemas/firestore.d.ts +183 -0
- package/dist/features/ledger/schemas/firestore.js +69 -0
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
- package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
- package/dist/features/orders/components/RefundRequestView.js +19 -1
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +85 -1
- package/dist/features/orders/repository/orders.repository.js +205 -6
- package/dist/features/orders/schemas/balance.d.ts +40 -0
- package/dist/features/orders/schemas/balance.js +47 -0
- package/dist/features/orders/schemas/firestore.d.ts +398 -1
- package/dist/features/orders/schemas/firestore.js +43 -0
- package/dist/features/orders/schemas/index.d.ts +56 -8
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +47 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/payments/repository/payout.repository.js +3 -2
- package/dist/features/payments/schemas/firestore.d.ts +92 -1
- package/dist/features/payments/schemas/firestore.js +23 -0
- package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
- package/dist/features/pricing/components/AdminPricingView.js +157 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/firestore.d.ts +26 -1
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
- package/dist/features/reviews/repository/reviews.repository.js +16 -0
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/scams/repository/scammer.repository.js +2 -1
- package/dist/features/scams/schemas/firestore.d.ts +2 -1
- package/dist/features/scams/schemas/firestore.js +2 -1
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/offer-actions.js +56 -0
- package/dist/features/seller/actions/seller-actions.d.ts +1 -1
- package/dist/features/seller/actions/seller-actions.js +37 -3
- package/dist/features/seller/components/DispatchForm.d.ts +11 -0
- package/dist/features/seller/components/DispatchForm.js +190 -0
- package/dist/features/seller/components/SellerOrdersView.js +221 -27
- package/dist/features/seller/components/index.d.ts +1 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/seller/repository/offer.repository.js +4 -3
- package/dist/features/seller/schemas/firestore.d.ts +23 -2
- package/dist/features/seller/schemas/firestore.js +3 -2
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +61 -4
- package/dist/features/seller/schemas/order-forms.js +41 -8
- package/dist/features/shipments/schemas/firestore.d.ts +25 -0
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/repository/store.repository.d.ts +18 -0
- package/dist/features/stores/repository/store.repository.js +27 -1
- package/dist/features/stores/schemas/firestore.d.ts +112 -0
- package/dist/features/stores/schemas/firestore.js +20 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/repository/support.repository.js +72 -6
- package/dist/features/support/schemas/firestore.d.ts +17 -0
- package/dist/features/support/schemas/index.d.ts +8 -8
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +33 -1
- package/dist/next/routing/route-map.d.ts +112 -0
- package/dist/next/routing/route-map.js +63 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/react/contexts/SessionContext.d.ts +17 -1
- package/dist/schemas/registry.d.ts +69 -34
- package/dist/schemas/sieve.d.ts +2 -2
- package/dist/security/pii-schemas.d.ts +1 -1
- package/dist/security/pii-schemas.js +45 -0
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +36 -1
- package/dist/server.js +183 -1
- package/dist/styles.css +412 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Button.d.ts +10 -1
- package/dist/ui/components/Button.js +25 -3
- package/dist/ui/components/Chart.d.ts +63 -0
- package/dist/ui/components/Chart.js +169 -0
- package/dist/ui/components/Chart.style.css +214 -0
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +83 -0
- package/dist/ui/components/OverflowRow.js +54 -2
- package/dist/ui/components/OverflowRow.style.css +38 -0
- package/dist/ui/components/RichTextEditor.js +99 -8
- package/dist/ui/components/chart-spec.d.ts +68 -0
- package/dist/ui/components/chart-spec.js +140 -0
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/surface-tokens.d.ts +1 -1
- package/dist/ui/components/surface-tokens.js +9 -0
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/components/toolbar-collapse.d.ts +13 -0
- package/dist/ui/components/toolbar-collapse.js +10 -1
- package/dist/ui/index.d.ts +8 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/rich-text/RichText.d.ts +10 -1
- package/dist/ui/rich-text/RichText.js +33 -2
- package/dist/ui/rich-text/RichText.style.css +83 -79
- package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
- package/dist/ui/rich-text/RichTextRenderer.js +34 -2
- package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
- package/dist/ui/rich-text/chart-blocks.js +87 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +1834 -1822
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
/*
|
|
4
|
+
* Defining modules, not `../index` — Root Cause #18.
|
|
5
|
+
*
|
|
6
|
+
* The barrel re-exports THIS component, so importing three primitives back
|
|
7
|
+
* through it closed a two-module cycle (`audit-import-cycles` component 1).
|
|
8
|
+
* The deep paths below have one direction only.
|
|
9
|
+
*/
|
|
10
|
+
import { Div } from "./Div.js";
|
|
11
|
+
import { Stack } from "./Layout.js";
|
|
12
|
+
import { Text } from "./Typography.js";
|
|
13
|
+
import { DISCLAIMERS, } from "../../_internal/shared/content/disclaimers.js";
|
|
14
|
+
import { resolvePublishedCopy, resolvePublishedValues, } from "../../_internal/shared/content/published-values.js";
|
|
15
|
+
/**
|
|
16
|
+
* The one way to render a disclaimer (Phase 12).
|
|
17
|
+
*
|
|
18
|
+
* ## 🛑 `id` only — there is no `text` prop, deliberately
|
|
19
|
+
*
|
|
20
|
+
* A `text` escape hatch would make this a styled box, and then the legally
|
|
21
|
+
* material disclaimers would be written at their call sites again, drift, and
|
|
22
|
+
* end up weakest exactly where they matter most. That is the failure this
|
|
23
|
+
* registry exists to close. If a surface needs a disclaimer that does not
|
|
24
|
+
* exist, the fix is a new registry entry — which is also what gets it
|
|
25
|
+
* reviewed.
|
|
26
|
+
*
|
|
27
|
+
* ## Tokens resolve here
|
|
28
|
+
*
|
|
29
|
+
* The protection entry quotes `{{saleProtectionMaxValue}}` and the claim
|
|
30
|
+
* windows, so the published limits come from the constants that ENFORCE them
|
|
31
|
+
* (Phase 9's mechanism). A change to `SALE_PROTECTION_MAX_VALUE` updates the
|
|
32
|
+
* terms rather than contradicting them.
|
|
33
|
+
*
|
|
34
|
+
* Code-derived values are the default; a caller with settings in hand passes
|
|
35
|
+
* better ones for the money figures.
|
|
36
|
+
*
|
|
37
|
+
* ## Safe in a Server Component
|
|
38
|
+
*
|
|
39
|
+
* No hooks, no state, and the registry is a plain object — so this renders on
|
|
40
|
+
* either side of the boundary. Do not add state here without checking every
|
|
41
|
+
* RSC call site (Root Cause #76).
|
|
42
|
+
*/
|
|
43
|
+
const CODE_DERIVED_VALUES = resolvePublishedValues();
|
|
44
|
+
/**
|
|
45
|
+
* Renders `**bold**` and nothing else.
|
|
46
|
+
*
|
|
47
|
+
* 🛑 A deliberately tiny subset, not a markdown renderer. The emphasis is
|
|
48
|
+
* load-bearing in exactly the places it is used — "**not insurance**" in the
|
|
49
|
+
* protection entry, "**under review**" versus "**verified**" in the scam
|
|
50
|
+
* registry — and those are the phrases a reader skims past without it.
|
|
51
|
+
*
|
|
52
|
+
* 🛑 And it returns ELEMENTS, never HTML. The bodies are our own constants so
|
|
53
|
+
* injection is not the risk; the risk is that a `dangerouslySetInnerHTML`
|
|
54
|
+
* here would invite someone to pass admin-editable text through it later,
|
|
55
|
+
* which is how a disclaimer box becomes a stored-XSS surface.
|
|
56
|
+
*/
|
|
57
|
+
function renderEmphasis(text) {
|
|
58
|
+
return text.split(/(\*\*[^*]+\*\*)/g).map((part, i) => part.startsWith("**") && part.endsWith("**") && part.length > 4 ? (_jsx(Text, { as: "span", weight: "semibold", children: part.slice(2, -2) }, i)) : (_jsx(React.Fragment, { children: part }, i)));
|
|
59
|
+
}
|
|
60
|
+
export function Disclaimer({ id, publishedValues = CODE_DERIVED_VALUES, inline = false, className = "", }) {
|
|
61
|
+
const entry = DISCLAIMERS[id];
|
|
62
|
+
/*
|
|
63
|
+
* A `Record<DisclaimerId, …>` means this cannot happen through the type, but
|
|
64
|
+
* an `as DisclaimerId` cast at a call site could — and rendering nothing is
|
|
65
|
+
* the wrong failure here. A missing disclaimer is invisible, which is the
|
|
66
|
+
* whole problem; so it renders nothing only when the registry genuinely has
|
|
67
|
+
* no entry, and the audit is what catches that case before it ships.
|
|
68
|
+
*/
|
|
69
|
+
if (!entry)
|
|
70
|
+
return null;
|
|
71
|
+
const body = resolvePublishedCopy(entry.body, publishedValues);
|
|
72
|
+
const content = (_jsxs(Stack, { gap: "xs", children: [entry.heading && (_jsx(Text, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: entry.heading })), _jsx(Text, { size: "xs", color: "muted", className: "leading-relaxed", children: renderEmphasis(body) })] }));
|
|
73
|
+
if (inline)
|
|
74
|
+
return _jsx(Div, { className: className, children: content });
|
|
75
|
+
/*
|
|
76
|
+
* 🛑 `surface` + the matching ink, never a status background with literal
|
|
77
|
+
* white text. `-surface` is a near-white tint in light themes and a dark
|
|
78
|
+
* tint in dark ones, so a fixed `text-white` is invisible in exactly one
|
|
79
|
+
* theme — Root Cause #67, which shipped 26 invisible surfaces that way.
|
|
80
|
+
* `Text color="muted"` above pairs correctly with both.
|
|
81
|
+
*/
|
|
82
|
+
return (_jsx(Div, { surface: entry.tone === "warning" ? "warning-surface" : "muted", rounded: "lg", padding: "sm", className: className, children: content }));
|
|
83
|
+
}
|
|
@@ -26,14 +26,22 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
26
26
|
* @tag sideEffects:dom-measurement
|
|
27
27
|
*/
|
|
28
28
|
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
29
|
+
import { createPortal } from "react-dom";
|
|
29
30
|
import NextLink from "next/link.js";
|
|
30
31
|
import { Check, ChevronDown, Search } from "lucide-react";
|
|
31
32
|
import { Avatar } from "./Avatar.js";
|
|
32
33
|
import { Icon } from "./Icon.js";
|
|
33
34
|
import { Input } from "./Input.js";
|
|
34
35
|
import { useRowCollapse } from "./row-collapse.js";
|
|
36
|
+
import { MOBILE_QUERY } from "./toolbar-collapse.js";
|
|
37
|
+
import { useBottomChromeSlot } from "./bottom-chrome-slot.js";
|
|
38
|
+
import { useMediaQuery } from "../../react/hooks/useMediaQuery.js";
|
|
35
39
|
const UI_OVERFLOW_ROW = {
|
|
36
40
|
shell: "appkit-overflow-row",
|
|
41
|
+
/** The in-flow measuring box, once the control itself has been portalled away. */
|
|
42
|
+
shellDocked: "appkit-overflow-row--docked",
|
|
43
|
+
/** The portalled control, as its own row inside `BottomChrome`. */
|
|
44
|
+
dock: "appkit-overflow-row__dock",
|
|
37
45
|
row: "appkit-overflow-row__row",
|
|
38
46
|
pill: "appkit-overflow-row__pill",
|
|
39
47
|
pillActive: "appkit-overflow-row__pill--active",
|
|
@@ -77,11 +85,22 @@ export function OverflowRow({ items, ariaLabel, activeId, variant = "tabs", plac
|
|
|
77
85
|
const shellRef = useRef(null);
|
|
78
86
|
const rowRef = useRef(null);
|
|
79
87
|
const triggerRef = useRef(null);
|
|
88
|
+
/*
|
|
89
|
+
* The portalled control, when docked into the bottom bar. Needed only by the
|
|
90
|
+
* outside-click handler: a portal moves the node out of `shellRef`'s subtree
|
|
91
|
+
* in the DOM, so `shell.contains(target)` is FALSE for a click on the
|
|
92
|
+
* trigger itself — the dropdown would close on the very click that opened
|
|
93
|
+
* it, which reads as the control being dead.
|
|
94
|
+
*/
|
|
95
|
+
const dockRef = useRef(null);
|
|
80
96
|
const searchRef = useRef(null);
|
|
81
97
|
const listboxId = useId();
|
|
82
98
|
const [open, setOpen] = useState(false);
|
|
83
99
|
const [query, setQuery] = useState("");
|
|
84
100
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
101
|
+
// Both before any conditional return — the collapsed branch is one.
|
|
102
|
+
const bottomChromeSlot = useBottomChromeSlot();
|
|
103
|
+
const isMobile = useMediaQuery(MOBILE_QUERY);
|
|
85
104
|
const signature = useMemo(() => signatureOf(items), [items]);
|
|
86
105
|
const collapsed = useRowCollapse(shellRef, rowRef, signature, {
|
|
87
106
|
disabled: alwaysCollapsed,
|
|
@@ -92,7 +111,11 @@ export function OverflowRow({ items, ariaLabel, activeId, variant = "tabs", plac
|
|
|
92
111
|
if (!open)
|
|
93
112
|
return;
|
|
94
113
|
const onDown = (event) => {
|
|
95
|
-
|
|
114
|
+
const target = event.target;
|
|
115
|
+
const inShell = shellRef.current?.contains(target) ?? false;
|
|
116
|
+
// See `dockRef` — when docked, the control lives outside the shell.
|
|
117
|
+
const inDock = dockRef.current?.contains(target) ?? false;
|
|
118
|
+
if (!inShell && !inDock)
|
|
96
119
|
setOpen(false);
|
|
97
120
|
};
|
|
98
121
|
document.addEventListener("mousedown", onDown);
|
|
@@ -166,7 +189,7 @@ export function OverflowRow({ items, ariaLabel, activeId, variant = "tabs", plac
|
|
|
166
189
|
const hasAnyVisual = items.some((item) => item.imageUrl || item.iconName || item.emoji || item.dotTone);
|
|
167
190
|
// ── Collapsed: one searchable dropdown ──────────────────────────────────
|
|
168
191
|
if (collapsed) {
|
|
169
|
-
|
|
192
|
+
const dropdown = (_jsxs(_Fragment, { children: [_jsxs("button", { ref: triggerRef, type: "button", className: UI_OVERFLOW_ROW.trigger, "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": open ? listboxId : undefined, "aria-label": ariaLabel, onClick: () => setOpen((prev) => !prev), onKeyDown: (event) => {
|
|
170
193
|
if (!open && (event.key === "ArrowDown" || event.key === "Enter")) {
|
|
171
194
|
event.preventDefault();
|
|
172
195
|
setOpen(true);
|
|
@@ -186,6 +209,35 @@ export function OverflowRow({ items, ariaLabel, activeId, variant = "tabs", plac
|
|
|
186
209
|
const body = (_jsxs(_Fragment, { children: [hasAnyVisual ? visualOf(item, "option") : null, _jsx("span", { className: UI_OVERFLOW_ROW.optionLabel, children: item.label }), typeof item.count === "number" && (_jsx("span", { className: UI_OVERFLOW_ROW.optionCount, children: item.count > 99 ? "99+" : item.count })), isSelected && (_jsx(Check, { className: `w-4 h-4 ${UI_OVERFLOW_ROW.check}`, "aria-hidden": "true" }))] }));
|
|
187
210
|
return item.href ? (_jsx(Link, { ...linkProps, id: `${listboxId}-${item.id}`, role: "option", "aria-selected": isSelected, href: item.href, className: classes, onMouseEnter: () => setActiveIndex(index), children: body }, item.id)) : (_jsx("button", { id: `${listboxId}-${item.id}`, role: "option", type: "button", "aria-selected": isSelected, disabled: item.disabled, className: classes, onClick: () => commit(item), onMouseEnter: () => setActiveIndex(index), children: body }, item.id));
|
|
188
211
|
})] })] }))] }));
|
|
212
|
+
/*
|
|
213
|
+
* ── Mobile: the collapsed row docks into the bottom bar ────────────────
|
|
214
|
+
*
|
|
215
|
+
* A row that has collapsed to a dropdown is no longer a row — it is one
|
|
216
|
+
* control, and on a phone the place for one control is the thumb zone,
|
|
217
|
+
* not a band competing with the page heading. It joins `BottomChrome` as
|
|
218
|
+
* its OWN row, so it stacks above a CTA bar instead of overlapping it,
|
|
219
|
+
* and the tier's single `ResizeObserver` adds its height to
|
|
220
|
+
* `--bottom-chrome-height` — which is what keeps page content from being
|
|
221
|
+
* hidden behind it on scroll, with no consumer doing anything.
|
|
222
|
+
*
|
|
223
|
+
* 🛑 `shellRef` STAYS IN PLACE, always. It is what `useRowCollapse`
|
|
224
|
+
* measures the available width against; portal it into the bottom bar and
|
|
225
|
+
* it would measure the VIEWPORT instead, read as "there is room now",
|
|
226
|
+
* expand, return to the narrow container, collapse, and oscillate forever.
|
|
227
|
+
* So the shell remains an empty in-flow box at the original position and
|
|
228
|
+
* only the CONTROL is portalled. The expanded branch below is unchanged
|
|
229
|
+
* and still renders the real row there.
|
|
230
|
+
*/
|
|
231
|
+
const docked = isMobile && !!bottomChromeSlot;
|
|
232
|
+
return (_jsx("div", { ref: shellRef, className: [
|
|
233
|
+
UI_OVERFLOW_ROW.shell,
|
|
234
|
+
docked ? UI_OVERFLOW_ROW.shellDocked : "",
|
|
235
|
+
className,
|
|
236
|
+
]
|
|
237
|
+
.filter(Boolean)
|
|
238
|
+
.join(" "), "data-collapsed": "true", "data-docked": docked ? "true" : "false", children: docked
|
|
239
|
+
? createPortal(_jsx("div", { ref: dockRef, className: UI_OVERFLOW_ROW.dock, children: dropdown }), bottomChromeSlot)
|
|
240
|
+
: dropdown }));
|
|
189
241
|
}
|
|
190
242
|
// ── Expanded: the pill row ──────────────────────────────────────────────
|
|
191
243
|
return (_jsx("div", { ref: shellRef, className: [UI_OVERFLOW_ROW.shell, className].filter(Boolean).join(" "), "data-collapsed": "false", children: _jsx("div", { ref: rowRef, className: UI_OVERFLOW_ROW.row, role: variant === "tabs" ? "tablist" : undefined, "aria-label": ariaLabel, children: items.map((item) => {
|
|
@@ -233,3 +233,41 @@
|
|
|
233
233
|
font-size: var(--appkit-text-sm);
|
|
234
234
|
color: var(--appkit-color-text-muted);
|
|
235
235
|
}
|
|
236
|
+
|
|
237
|
+
/* ── Docked: the collapsed control lives in the bottom bar on mobile ────────
|
|
238
|
+
*
|
|
239
|
+
* The shell stays in flow as a zero-height measuring box — `useRowCollapse`
|
|
240
|
+
* compares the row's cached natural width against THIS element, so it must
|
|
241
|
+
* keep the original container's width. Portalling it instead would make it
|
|
242
|
+
* measure the viewport, read as "there is room", expand, and oscillate.
|
|
243
|
+
*/
|
|
244
|
+
.appkit-overflow-row--docked {
|
|
245
|
+
height: 0;
|
|
246
|
+
/* Not `display:none`: a hidden box has no width, and width is the entire
|
|
247
|
+
input to the collapse decision. */
|
|
248
|
+
overflow: hidden;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.appkit-overflow-row__dock {
|
|
252
|
+
position: relative;
|
|
253
|
+
display: flex;
|
|
254
|
+
width: 100%;
|
|
255
|
+
pointer-events: auto;
|
|
256
|
+
padding: var(--appkit-space-2) var(--appkit-space-4);
|
|
257
|
+
background: var(--appkit-color-surface-elevated);
|
|
258
|
+
border-top: 1px solid var(--appkit-color-border);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.appkit-overflow-row__dock > .appkit-overflow-row__trigger {
|
|
262
|
+
width: 100%;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* 🛑 Opens UPWARD when docked. The default popover is `top: 100%`, which from
|
|
266
|
+
a bar at the bottom edge renders off-screen — the control would look dead.
|
|
267
|
+
`BottomChrome` deliberately sets no `overflow`, so the panel may escape the
|
|
268
|
+
tier; that is the documented contract its own header relies on. */
|
|
269
|
+
.appkit-overflow-row__dock .appkit-overflow-row__popover {
|
|
270
|
+
top: auto;
|
|
271
|
+
bottom: calc(100% + var(--appkit-space-1));
|
|
272
|
+
width: 100%;
|
|
273
|
+
}
|
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { parseChartAttr, CHART_KINDS } from "./chart-spec.js";
|
|
5
|
+
import { chartFigureHtml } from "../rich-text/chart-blocks.js";
|
|
6
|
+
/**
|
|
7
|
+
* What the Chart button drops into the editor to be edited.
|
|
8
|
+
*
|
|
9
|
+
* A filled, working example rather than an empty skeleton: an author editing
|
|
10
|
+
* real numbers into a chart that already renders can see what each field does,
|
|
11
|
+
* where one facing `{"kind":"","categories":[],"series":[]}` has to guess the
|
|
12
|
+
* shape before anything appears at all.
|
|
13
|
+
*/
|
|
14
|
+
const STARTER_CHART = JSON.stringify({
|
|
15
|
+
kind: "groupedBar",
|
|
16
|
+
title: "Untitled chart",
|
|
17
|
+
categories: ["First", "Second", "Third"],
|
|
18
|
+
series: [
|
|
19
|
+
{ label: "Series A", values: [3, 5, 4] },
|
|
20
|
+
{ label: "Series B", values: [4, 2, 6] },
|
|
21
|
+
],
|
|
22
|
+
unit: "",
|
|
23
|
+
caption: "",
|
|
24
|
+
}, null, 2);
|
|
25
|
+
/** The chart JSON editor shown under the toolbar, with live validation. */
|
|
26
|
+
function ChartDraftPanel({ draft, onDraftChange, onInsert, onCancel, }) {
|
|
27
|
+
const result = useMemo(() => parseChartAttr(draft), [draft]);
|
|
28
|
+
/*
|
|
29
|
+
* 🛑 Generated, not a literal. Two RichTextEditors on one page — a category
|
|
30
|
+
* form with a description and an SEO blurb, say — would otherwise emit the
|
|
31
|
+
* SAME hardcoded id twice, so the second panel's `htmlFor` and
|
|
32
|
+
* `aria-describedby` resolve to the FIRST one's textarea and error. A screen
|
|
33
|
+
* reader then reads the wrong field's error and clicking the label focuses
|
|
34
|
+
* the wrong box, which is exactly the class of bug the `ariaLabelledBy` note
|
|
35
|
+
* at the top of this file exists about.
|
|
36
|
+
*/
|
|
37
|
+
const panelId = useId();
|
|
38
|
+
const fieldId = `${panelId}-draft`;
|
|
39
|
+
const errorId = `${panelId}-error`;
|
|
40
|
+
return (_jsxs("div", { className: "appkit-rich-text-editor__chart border-b p-2 border-[var(--appkit-color-border)]", children: [_jsxs("label", { className: "mb-1 block text-xs font-medium text-[var(--appkit-color-text-muted)]", htmlFor: fieldId, children: ["Chart data \u2014 kinds: ", CHART_KINDS.join(", "), ". Each series needs one value per category."] }), _jsx("textarea", { id: fieldId, value: draft, onChange: (e) => onDraftChange(e.target.value), rows: 12, spellCheck: false, "aria-invalid": !result.ok, "aria-describedby": result.ok ? undefined : errorId, className: "w-full rounded border p-2 font-mono text-xs border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-input)] text-[var(--appkit-color-text)]" }), result.ok ? null : (_jsx("p", { id: errorId, role: "alert", className: "mt-1 text-xs text-[var(--appkit-color-error)]", children: result.reason })), _jsxs("div", { className: "mt-2 flex gap-2", children: [_jsx("button", { type: "button", onClick: onInsert, disabled: !result.ok, className: "rounded px-2 py-1 text-xs font-medium transition disabled:cursor-not-allowed disabled:opacity-50 bg-[var(--appkit-color-primary)] text-[var(--appkit-color-text-on-primary)]", children: "Insert chart" }), _jsx("button", { type: "button", onClick: onCancel, className: "rounded px-2 py-1 text-xs font-medium transition hover:bg-surface-hover text-[var(--appkit-color-text-muted)]", children: "Cancel" })] })] }));
|
|
41
|
+
}
|
|
4
42
|
// Matches exactly what this editor's own toolbar (bold/italic/underline/
|
|
5
43
|
// lists/link/clear-formatting) and typing can legitimately produce.
|
|
6
44
|
// Anything else — <script>, <img onerror=...>, <iframe>, <svg>, <style>,
|
|
@@ -10,6 +48,9 @@ import { useEffect, useMemo, useRef } from "react";
|
|
|
10
48
|
const ALLOWED_TAGS = new Set([
|
|
11
49
|
"B", "STRONG", "I", "EM", "U", "S", "STRIKE",
|
|
12
50
|
"UL", "OL", "LI", "A", "BR", "DIV", "SPAN", "P",
|
|
51
|
+
// FIGURE is here only because the toolbar's "Chart" button produces it.
|
|
52
|
+
// It carries no text content — see sanitizeAttribute for the data-chart rule.
|
|
53
|
+
"FIGURE",
|
|
13
54
|
]);
|
|
14
55
|
function isSafeHref(href) {
|
|
15
56
|
const trimmed = href.trim();
|
|
@@ -18,14 +59,33 @@ function isSafeHref(href) {
|
|
|
18
59
|
// relative), or "#" — reject everything else including javascript:.
|
|
19
60
|
return /^(https?:\/\/|mailto:|\/(?!\/)|#)/i.test(trimmed);
|
|
20
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* 🛑 This is the SAVE-time sanitiser, and it is a different, stricter one from
|
|
64
|
+
* `RichText.tsx`'s render-time `sanitiseHtml`. Both had to learn about
|
|
65
|
+
* `data-chart` — teaching only the renderer, as a first pass here did, means a
|
|
66
|
+
* chart inserted in the editor is silently deleted the moment it is saved,
|
|
67
|
+
* with the toolbar button appearing to work perfectly.
|
|
68
|
+
*
|
|
69
|
+
* The rule is stricter than the renderer's on purpose: the value is not merely
|
|
70
|
+
* allowed through, it must PARSE as a valid ChartSpec. Invalid JSON or a spec
|
|
71
|
+
* that fails validation loses the attribute, and the empty `<figure>` that
|
|
72
|
+
* remains is then dropped by `sanitizeElement`. So malformed chart data cannot
|
|
73
|
+
* be persisted at all, which is the right place to stop it — once stored, it
|
|
74
|
+
* is every future reader's problem.
|
|
75
|
+
*/
|
|
21
76
|
function sanitizeAttribute(el, attr) {
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
|
|
77
|
+
const name = attr.name.toLowerCase();
|
|
78
|
+
if (el.tagName === "A" && name === "href") {
|
|
79
|
+
if (!isSafeHref(attr.value))
|
|
80
|
+
el.setAttribute("href", "#");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (el.tagName === "FIGURE" && name === "data-chart") {
|
|
84
|
+
if (!parseChartAttr(attr.value).ok)
|
|
85
|
+
el.removeAttribute(attr.name);
|
|
25
86
|
return;
|
|
26
87
|
}
|
|
27
|
-
|
|
28
|
-
el.setAttribute("href", "#");
|
|
88
|
+
el.removeAttribute(attr.name);
|
|
29
89
|
}
|
|
30
90
|
function sanitizeElement(root, el) {
|
|
31
91
|
if (!ALLOWED_TAGS.has(el.tagName)) {
|
|
@@ -33,6 +93,14 @@ function sanitizeElement(root, el) {
|
|
|
33
93
|
return;
|
|
34
94
|
}
|
|
35
95
|
Array.from(el.attributes).forEach((attr) => sanitizeAttribute(el, attr));
|
|
96
|
+
// A <figure> is only legal here as a chart carrier. If the attribute did not
|
|
97
|
+
// survive validation above, what is left is an empty element with no text and
|
|
98
|
+
// no meaning — drop it rather than persist a blank block the author cannot
|
|
99
|
+
// see, select, or delete.
|
|
100
|
+
if (el.tagName === "FIGURE" && !el.hasAttribute("data-chart")) {
|
|
101
|
+
root.removeChild(el);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
36
104
|
sanitizeChildren(el);
|
|
37
105
|
}
|
|
38
106
|
function sanitizeChildren(root) {
|
|
@@ -55,6 +123,7 @@ function sanitizeRichTextHtml(html) {
|
|
|
55
123
|
}
|
|
56
124
|
export function RichTextEditor({ value, onChange, disabled = false, className = "", minHeightClassName = "min-h-[180px]", placeholder = "Write formatted content...", ariaLabelledBy, ariaLabel, }) {
|
|
57
125
|
const editorRef = useRef(null);
|
|
126
|
+
const [chartDraft, setChartDraft] = useState(null);
|
|
58
127
|
const emitChange = () => {
|
|
59
128
|
if (!editorRef.current)
|
|
60
129
|
return;
|
|
@@ -102,12 +171,34 @@ export function RichTextEditor({ value, onChange, disabled = false, className =
|
|
|
102
171
|
exec("createLink", href);
|
|
103
172
|
},
|
|
104
173
|
},
|
|
174
|
+
{
|
|
175
|
+
label: "Chart",
|
|
176
|
+
title: "Insert chart",
|
|
177
|
+
run: () => setChartDraft(STARTER_CHART),
|
|
178
|
+
},
|
|
105
179
|
{
|
|
106
180
|
label: "Clear",
|
|
107
181
|
title: "Clear formatting",
|
|
108
182
|
run: () => exec("removeFormat"),
|
|
109
183
|
},
|
|
110
184
|
], []);
|
|
185
|
+
/*
|
|
186
|
+
* `insertHTML` rather than building a node and splicing it in: the editor is
|
|
187
|
+
* a contenteditable and execCommand is already how every other toolbar action
|
|
188
|
+
* writes, so this keeps the caret and the undo stack behaving the same way.
|
|
189
|
+
* The inserted markup then goes straight through `emitChange` →
|
|
190
|
+
* `sanitizeRichTextHtml`, so the chart is validated on the way out exactly as
|
|
191
|
+
* a pasted one would be — the button gets no privileged path.
|
|
192
|
+
*/
|
|
193
|
+
const insertChart = () => {
|
|
194
|
+
if (chartDraft === null)
|
|
195
|
+
return;
|
|
196
|
+
const parsed = parseChartAttr(chartDraft);
|
|
197
|
+
if (!parsed.ok)
|
|
198
|
+
return;
|
|
199
|
+
exec("insertHTML", chartFigureHtml(parsed.spec));
|
|
200
|
+
setChartDraft(null);
|
|
201
|
+
};
|
|
111
202
|
useEffect(() => {
|
|
112
203
|
const editor = editorRef.current;
|
|
113
204
|
if (!editor)
|
|
@@ -120,7 +211,7 @@ export function RichTextEditor({ value, onChange, disabled = false, className =
|
|
|
120
211
|
editor.innerHTML = safeValue;
|
|
121
212
|
}
|
|
122
213
|
}, [value]);
|
|
123
|
-
return (_jsxs("div", { className: `appkit-rich-text-editor rounded-lg border border-zinc-200 bg-[var(--appkit-color-surface)] border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] ${className}`, "data-section": "richtexteditor-div-582", children: [_jsx("div", { className: "appkit-rich-text-editor__toolbar flex flex-wrap gap-1 border-b p-2 border-[var(--appkit-color-border)]", "data-section": "richtexteditor-div-583", children: toolbarActions.map((action) => (_jsx("button", { type: "button", title: action.title, onClick: action.run, disabled: disabled, className: "appkit-rich-text-editor__btn rounded px-2 py-1 text-xs font-medium transition hover:bg-surface-hover disabled:cursor-not-allowed disabled:opacity-50 text-[var(--appkit-color-text-muted)]", children: action.label }, action.title))) }), _jsx("div", { ref: editorRef,
|
|
214
|
+
return (_jsxs("div", { className: `appkit-rich-text-editor rounded-lg border border-zinc-200 bg-[var(--appkit-color-surface)] border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] ${className}`, "data-section": "richtexteditor-div-582", children: [_jsx("div", { className: "appkit-rich-text-editor__toolbar flex flex-wrap gap-1 border-b p-2 border-[var(--appkit-color-border)]", "data-section": "richtexteditor-div-583", children: toolbarActions.map((action) => (_jsx("button", { type: "button", title: action.title, onClick: action.run, disabled: disabled, className: "appkit-rich-text-editor__btn rounded px-2 py-1 text-xs font-medium transition hover:bg-surface-hover disabled:cursor-not-allowed disabled:opacity-50 text-[var(--appkit-color-text-muted)]", children: action.label }, action.title))) }), chartDraft !== null ? (_jsx(ChartDraftPanel, { draft: chartDraft, onDraftChange: setChartDraft, onInsert: insertChart, onCancel: () => setChartDraft(null) })) : null, _jsx("div", { ref: editorRef,
|
|
124
215
|
/*
|
|
125
216
|
* 🛑 `role` and `aria-label` USED TO BE DECLARED HERE TOO, hardcoded
|
|
126
217
|
* to "Rich text editor" — and when the labelling props were added
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export declare const CHART_KINDS: readonly ["bar", "groupedBar", "line", "area"];
|
|
2
|
+
export type ChartKind = (typeof CHART_KINDS)[number];
|
|
3
|
+
/**
|
|
4
|
+
* 🛑 Eight, and a ninth is never a generated hue.
|
|
5
|
+
*
|
|
6
|
+
* The categorical palette is a fixed, validated ORDER of eight steps, checked
|
|
7
|
+
* for colourblind separation between adjacent pairs. A 9th colour generated at
|
|
8
|
+
* runtime cannot be validated, so a 9-series chart is REFUSED and the author is
|
|
9
|
+
* told to fold the tail into "Other" or split into small multiples.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CHART_MAX_SERIES = 8;
|
|
12
|
+
export interface ChartSeries {
|
|
13
|
+
label: string;
|
|
14
|
+
values: number[];
|
|
15
|
+
}
|
|
16
|
+
export interface ChartSpec {
|
|
17
|
+
kind: ChartKind;
|
|
18
|
+
/** X-axis categories. `series[].values` must be exactly this long. */
|
|
19
|
+
categories: string[];
|
|
20
|
+
series: ChartSeries[];
|
|
21
|
+
/** Appended to every value in tooltips and the table view. */
|
|
22
|
+
unit?: string;
|
|
23
|
+
/** Rendered under the plot. */
|
|
24
|
+
caption?: string;
|
|
25
|
+
/** Accessible name. Falls back to the caption. */
|
|
26
|
+
title?: string;
|
|
27
|
+
}
|
|
28
|
+
export type ChartSpecResult = {
|
|
29
|
+
ok: true;
|
|
30
|
+
spec: ChartSpec;
|
|
31
|
+
} | {
|
|
32
|
+
ok: false;
|
|
33
|
+
reason: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Validate an untrusted object into a `ChartSpec`.
|
|
37
|
+
*
|
|
38
|
+
* 🛑 Returns a REASON rather than throwing or silently returning null. This
|
|
39
|
+
* parses author-supplied JSON out of a `data-chart` attribute, and an author
|
|
40
|
+
* who mistyped needs to be told which rule they broke — a chart that quietly
|
|
41
|
+
* renders nothing is the failure mode this codebase keeps paying for.
|
|
42
|
+
*
|
|
43
|
+
* 🛑 There is deliberately no second y-axis in the shape. A dual-axis chart
|
|
44
|
+
* invites comparing two incommensurable scales on one plot; two measures mean
|
|
45
|
+
* two charts, small multiples, or indexing to a common base.
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseChartSpec(input: unknown): ChartSpecResult;
|
|
48
|
+
/**
|
|
49
|
+
* Parse the JSON string carried by a `data-chart` attribute.
|
|
50
|
+
*
|
|
51
|
+
* 🛑 The normalised error is deliberately NOT surfaced to the caller. The
|
|
52
|
+
* thrown value is a `SyntaxError` from `JSON.parse` carrying nothing an author
|
|
53
|
+
* can act on beyond "it is not JSON" — which the returned reason already says,
|
|
54
|
+
* in their language, at the place they will read it. Returning the engine's
|
|
55
|
+
* message instead is how server text reaches a user (Root Cause #86). Malformed
|
|
56
|
+
* authored content is an expected input here, not an incident to report.
|
|
57
|
+
*
|
|
58
|
+
* `normalizeError` is still called, because that is what `audit-catch-normalize`
|
|
59
|
+
* actually accepts: its header also lists "return immediately" as sufficient,
|
|
60
|
+
* but the implementation only tests for `normalizeError(var)` or `throw var`
|
|
61
|
+
* (audit-catch-normalize.mjs:210-213), so a bare early return is reported.
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseChartAttr(json: string): ChartSpecResult;
|
|
64
|
+
/**
|
|
65
|
+
* How many series the palette can colour. Exposed so a caller can decide to
|
|
66
|
+
* fold a tail into "Other" BEFORE validation rejects the whole chart.
|
|
67
|
+
*/
|
|
68
|
+
export declare function exceedsSeriesLimit(count: number): boolean;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The chart DATA contract — pure, and deliberately separate from `<Chart>`.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 Why this is not in Chart.tsx
|
|
5
|
+
*
|
|
6
|
+
* `Chart.tsx` is `"use client"` and statically reaches recharts. Anything that
|
|
7
|
+
* imports it inherits both. But the validator needs to be callable from places
|
|
8
|
+
* that are neither:
|
|
9
|
+
*
|
|
10
|
+
* - `chart-blocks.ts`, which must stay SSR-safe because `RichTextRenderer`
|
|
11
|
+
* is a Server Component;
|
|
12
|
+
* - a route handler or a seed script validating authored content before it
|
|
13
|
+
* is stored, where pulling in recharts would be absurd.
|
|
14
|
+
*
|
|
15
|
+
* Keeping the types and the parser here means a server-side caller gets the
|
|
16
|
+
* contract without the renderer — the same split as Root Cause #24's lesson
|
|
17
|
+
* about a file that mixed Node-only crypto with client-safe display helpers.
|
|
18
|
+
*
|
|
19
|
+
* No React, no DOM, no recharts.
|
|
20
|
+
*/
|
|
21
|
+
import { normalizeError } from "../../errors/normalize.js";
|
|
22
|
+
export const CHART_KINDS = ["bar", "groupedBar", "line", "area"];
|
|
23
|
+
/**
|
|
24
|
+
* 🛑 Eight, and a ninth is never a generated hue.
|
|
25
|
+
*
|
|
26
|
+
* The categorical palette is a fixed, validated ORDER of eight steps, checked
|
|
27
|
+
* for colourblind separation between adjacent pairs. A 9th colour generated at
|
|
28
|
+
* runtime cannot be validated, so a 9-series chart is REFUSED and the author is
|
|
29
|
+
* told to fold the tail into "Other" or split into small multiples.
|
|
30
|
+
*/
|
|
31
|
+
export const CHART_MAX_SERIES = 8;
|
|
32
|
+
/**
|
|
33
|
+
* Validate an untrusted object into a `ChartSpec`.
|
|
34
|
+
*
|
|
35
|
+
* 🛑 Returns a REASON rather than throwing or silently returning null. This
|
|
36
|
+
* parses author-supplied JSON out of a `data-chart` attribute, and an author
|
|
37
|
+
* who mistyped needs to be told which rule they broke — a chart that quietly
|
|
38
|
+
* renders nothing is the failure mode this codebase keeps paying for.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 There is deliberately no second y-axis in the shape. A dual-axis chart
|
|
41
|
+
* invites comparing two incommensurable scales on one plot; two measures mean
|
|
42
|
+
* two charts, small multiples, or indexing to a common base.
|
|
43
|
+
*/
|
|
44
|
+
export function parseChartSpec(input) {
|
|
45
|
+
if (typeof input !== "object" || input === null) {
|
|
46
|
+
return { ok: false, reason: "Chart data must be an object." };
|
|
47
|
+
}
|
|
48
|
+
const o = input;
|
|
49
|
+
const kind = o.kind;
|
|
50
|
+
if (typeof kind !== "string" || !CHART_KINDS.includes(kind)) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
reason: `Chart "kind" must be one of ${CHART_KINDS.join(", ")}.`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!Array.isArray(o.categories) ||
|
|
57
|
+
o.categories.length === 0 ||
|
|
58
|
+
!o.categories.every((c) => typeof c === "string" && c.length > 0)) {
|
|
59
|
+
return { ok: false, reason: 'Chart "categories" must be a non-empty array of labels.' };
|
|
60
|
+
}
|
|
61
|
+
const categories = o.categories;
|
|
62
|
+
if (!Array.isArray(o.series) || o.series.length === 0) {
|
|
63
|
+
return { ok: false, reason: 'Chart "series" must be a non-empty array.' };
|
|
64
|
+
}
|
|
65
|
+
if (o.series.length > CHART_MAX_SERIES) {
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
reason: `A chart carries at most ${CHART_MAX_SERIES} series (got ${o.series.length}). ` +
|
|
69
|
+
`Fold the smallest into an "Other" series, or split into separate charts — ` +
|
|
70
|
+
`a 9th colour cannot be checked for colourblind separation.`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const series = [];
|
|
74
|
+
for (const [i, raw] of o.series.entries()) {
|
|
75
|
+
if (typeof raw !== "object" || raw === null) {
|
|
76
|
+
return { ok: false, reason: `Series ${i + 1} must be an object.` };
|
|
77
|
+
}
|
|
78
|
+
const s = raw;
|
|
79
|
+
if (typeof s.label !== "string" || s.label.length === 0) {
|
|
80
|
+
return { ok: false, reason: `Series ${i + 1} needs a non-empty "label".` };
|
|
81
|
+
}
|
|
82
|
+
if (!Array.isArray(s.values) ||
|
|
83
|
+
!s.values.every((v) => typeof v === "number" && Number.isFinite(v))) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
reason: `Series "${s.label}" — "values" must be an array of finite numbers.`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (s.values.length !== categories.length) {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
reason: `Series "${s.label}" has ${s.values.length} values but there are ` +
|
|
93
|
+
`${categories.length} categories. They must match one-to-one.`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
series.push({ label: s.label, values: s.values });
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
ok: true,
|
|
100
|
+
spec: {
|
|
101
|
+
kind: kind,
|
|
102
|
+
categories,
|
|
103
|
+
series,
|
|
104
|
+
...(typeof o.unit === "string" ? { unit: o.unit } : {}),
|
|
105
|
+
...(typeof o.caption === "string" ? { caption: o.caption } : {}),
|
|
106
|
+
...(typeof o.title === "string" ? { title: o.title } : {}),
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse the JSON string carried by a `data-chart` attribute.
|
|
112
|
+
*
|
|
113
|
+
* 🛑 The normalised error is deliberately NOT surfaced to the caller. The
|
|
114
|
+
* thrown value is a `SyntaxError` from `JSON.parse` carrying nothing an author
|
|
115
|
+
* can act on beyond "it is not JSON" — which the returned reason already says,
|
|
116
|
+
* in their language, at the place they will read it. Returning the engine's
|
|
117
|
+
* message instead is how server text reaches a user (Root Cause #86). Malformed
|
|
118
|
+
* authored content is an expected input here, not an incident to report.
|
|
119
|
+
*
|
|
120
|
+
* `normalizeError` is still called, because that is what `audit-catch-normalize`
|
|
121
|
+
* actually accepts: its header also lists "return immediately" as sufficient,
|
|
122
|
+
* but the implementation only tests for `normalizeError(var)` or `throw var`
|
|
123
|
+
* (audit-catch-normalize.mjs:210-213), so a bare early return is reported.
|
|
124
|
+
*/
|
|
125
|
+
export function parseChartAttr(json) {
|
|
126
|
+
try {
|
|
127
|
+
return parseChartSpec(JSON.parse(json));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
void normalizeError(err);
|
|
131
|
+
return { ok: false, reason: "Chart data is not valid JSON." };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* How many series the palette can colour. Exposed so a caller can decide to
|
|
136
|
+
* fold a tail into "Other" BEFORE validation rejects the whole chart.
|
|
137
|
+
*/
|
|
138
|
+
export function exceedsSeriesLimit(count) {
|
|
139
|
+
return count > CHART_MAX_SERIES;
|
|
140
|
+
}
|
|
@@ -226,7 +226,7 @@ export declare const PADDING_PRESETS: {
|
|
|
226
226
|
readonly "content-banner": "py-[var(--appkit-space-10)] md:py-[var(--appkit-space-12)] lg:py-[var(--appkit-space-16)]";
|
|
227
227
|
};
|
|
228
228
|
export type PaddingPresetKey = PaddingKey;
|
|
229
|
-
export type XPaddingKey = "none" | "x-xs" | "x-sm" | "x-md" | "x-5" | "x-lg" | "x-xl" | "x-sm-md" | "x-sm-lg-md" | "x-md-lg" | "x-md-xl" | "x-md-2xl" | "x-page" | "l-xl";
|
|
229
|
+
export type XPaddingKey = "none" | "x-xs" | "x-sm" | "x-md" | "x-5" | "x-lg" | "x-xl" | "x-sm-md" | "x-sm-lg-md" | "x-md-lg" | "x-md-xl" | "x-md-2xl" | "x-page" | "l-md" | "l-xl";
|
|
230
230
|
type YPaddingKey = "none" | "y-2xs" | "y-2xs-tall" | "y-xs" | "y-xs-tall" | "y-sm" | "y-sm-tall" | "y-md" | "y-md-lg" | "y-lg" | "y-xl" | "y-2xl" | "y-3xl" | "y-4xl" | "y-5xl" | "y-6xl" | "y-2-5xl" | "t-2xs" | "b-2xs" | "t-xs" | "b-xs" | "t-sm" | "b-sm" | "t-md" | "b-md" | "b-md-lg" | "b-lg" | "t-md-b-lg";
|
|
231
231
|
export declare const X_ONLY_MAP: Record<XPaddingKey, string>;
|
|
232
232
|
export type OverflowKey = "auto" | "hidden" | "scroll" | "visible" | "x-auto" | "x-hidden" | "y-auto" | "y-hidden";
|
|
@@ -232,6 +232,15 @@ export const X_ONLY_MAP = {
|
|
|
232
232
|
// selection-checkbox gutter).
|
|
233
233
|
/** Asymmetric: `pl-8` — reserves a left gutter (e.g. for an overlaid selection checkbox). */
|
|
234
234
|
"l-xl": "pl-[var(--appkit-space-8)]",
|
|
235
|
+
/**
|
|
236
|
+
* Asymmetric: `pl-4` — indents a nested block under its own heading.
|
|
237
|
+
*
|
|
238
|
+
* The grouped order-item rows (admin and seller) are the motivating pair:
|
|
239
|
+
* a group header followed by its member lines, where the indent is the only
|
|
240
|
+
* thing expressing the nesting. `x-md` would pad the right edge too, which
|
|
241
|
+
* is not what an indent means.
|
|
242
|
+
*/
|
|
243
|
+
"l-md": "pl-[var(--appkit-space-4)]",
|
|
235
244
|
};
|
|
236
245
|
const Y_ONLY_MAP = {
|
|
237
246
|
none: "",
|