@mohasinac/appkit 2.7.57 → 2.7.58

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 (184) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +7 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -2
  3. package/dist/client.d.ts +1 -1
  4. package/dist/client.js +1 -1
  5. package/dist/configs/tailwind.d.ts +16 -3
  6. package/dist/configs/tailwind.js +18 -5
  7. package/dist/features/account/components/AddressBook.js +1 -1
  8. package/dist/features/account/components/BuyerAccountGuideView.js +7 -7
  9. package/dist/features/account/components/BuyerAuctionsGuideView.js +7 -7
  10. package/dist/features/account/components/BuyerOrdersGuideView.js +6 -6
  11. package/dist/features/account/components/BuyerShoppingGuideView.js +7 -7
  12. package/dist/features/account/components/UserOffersPanel.js +1 -1
  13. package/dist/features/account/components/UserSupportView.js +4 -4
  14. package/dist/features/admin/components/AdminAdsView.js +1 -1
  15. package/dist/features/admin/components/AdminAllEventEntriesView.js +1 -1
  16. package/dist/features/admin/components/AdminAnalyticsGuideView.js +3 -3
  17. package/dist/features/admin/components/AdminBidsView.js +1 -1
  18. package/dist/features/admin/components/AdminBlogView.js +1 -1
  19. package/dist/features/admin/components/AdminBrandsView.js +1 -1
  20. package/dist/features/admin/components/AdminBundlesView.js +1 -1
  21. package/dist/features/admin/components/AdminCarouselView.js +2 -2
  22. package/dist/features/admin/components/AdminCartsView.js +1 -1
  23. package/dist/features/admin/components/AdminCatalogGuideView.js +5 -5
  24. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  25. package/dist/features/admin/components/AdminContactEditorView.js +2 -2
  26. package/dist/features/admin/components/AdminContactView.js +1 -1
  27. package/dist/features/admin/components/AdminContentGuideView.js +6 -6
  28. package/dist/features/admin/components/AdminCouponsView.js +1 -1
  29. package/dist/features/admin/components/AdminFaqsView.js +1 -1
  30. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
  31. package/dist/features/admin/components/AdminFeaturesView.js +1 -1
  32. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  33. package/dist/features/admin/components/AdminHistoryView.js +1 -1
  34. package/dist/features/admin/components/AdminListingScaffold.js +1 -1
  35. package/dist/features/admin/components/AdminNewsletterView.js +1 -1
  36. package/dist/features/admin/components/AdminNotificationsView.js +1 -1
  37. package/dist/features/admin/components/AdminOrdersGuideView.js +5 -5
  38. package/dist/features/admin/components/AdminOrdersView.js +1 -1
  39. package/dist/features/admin/components/AdminPayoutsView.js +1 -1
  40. package/dist/features/admin/components/AdminProductsView.js +1 -1
  41. package/dist/features/admin/components/AdminReturnRequestsView.js +1 -1
  42. package/dist/features/admin/components/AdminReviewsView.js +1 -1
  43. package/dist/features/admin/components/AdminScammerEditorView.js +3 -3
  44. package/dist/features/admin/components/AdminScammersView.js +4 -4
  45. package/dist/features/admin/components/AdminSectionsView.js +1 -1
  46. package/dist/features/admin/components/AdminSessionsView.js +1 -1
  47. package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
  48. package/dist/features/admin/components/AdminStoreAddressesView.js +1 -1
  49. package/dist/features/admin/components/AdminStoresGuideView.js +6 -6
  50. package/dist/features/admin/components/AdminStoresView.js +1 -1
  51. package/dist/features/admin/components/AdminSublistingCategoriesView.js +1 -1
  52. package/dist/features/admin/components/AdminSupportTicketDetailView.js +4 -4
  53. package/dist/features/admin/components/AdminSupportTicketsView.js +7 -7
  54. package/dist/features/admin/components/AdminTeamGuideView.js +4 -4
  55. package/dist/features/admin/components/AdminTeamView.js +1 -1
  56. package/dist/features/admin/components/AdminTrustGuideView.js +5 -5
  57. package/dist/features/admin/components/AdminUserEditorView.js +1 -1
  58. package/dist/features/admin/components/AdminUsersGuideView.js +5 -5
  59. package/dist/features/admin/components/AdminUsersView.js +1 -1
  60. package/dist/features/admin/components/AdminViewCards.js +1 -1
  61. package/dist/features/admin/components/AdminWishlistsView.js +1 -1
  62. package/dist/features/admin/components/DataTable.js +1 -1
  63. package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
  64. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  65. package/dist/features/auctions/components/MarketplaceAuctionCard.js +2 -2
  66. package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
  67. package/dist/features/auth/components/VerifyEmailView.js +1 -1
  68. package/dist/features/blog/components/BlogListView.js +1 -1
  69. package/dist/features/blog/components/BlogPostView.js +1 -1
  70. package/dist/features/cart/components/CartDrawer.js +1 -1
  71. package/dist/features/categories/components/CategoryDetailPageView.js +1 -1
  72. package/dist/features/checkout/components/CheckoutStepper.js +1 -1
  73. package/dist/features/collections/components/CollectionCard.js +1 -1
  74. package/dist/features/copilot/components/AdminCopilotView.js +2 -2
  75. package/dist/features/events/components/AdminEventsView.js +1 -1
  76. package/dist/features/events/components/EventPollWidget.js +2 -2
  77. package/dist/features/events/components/EventStatusBadge.js +4 -4
  78. package/dist/features/events/components/SpinWheelView.js +1 -1
  79. package/dist/features/faq/components/FAQAccordion.js +2 -2
  80. package/dist/features/forms/Input.js +3 -3
  81. package/dist/features/forms/Select.js +2 -2
  82. package/dist/features/forms/Textarea.js +2 -2
  83. package/dist/features/forms/utils.d.ts +1 -1
  84. package/dist/features/forms/utils.js +1 -1
  85. package/dist/features/homepage/components/CharacterHotspotForm.js +2 -2
  86. package/dist/features/layout/BottomActions.js +2 -2
  87. package/dist/features/layout/ListingLayout.js +3 -3
  88. package/dist/features/layout/TitleBarLayout.js +1 -1
  89. package/dist/features/media/index.d.ts +2 -0
  90. package/dist/features/media/index.js +1 -0
  91. package/dist/features/media/modals/ImageCropModal.js +1 -1
  92. package/dist/features/media/modals/ImageEditor.d.ts +12 -0
  93. package/dist/features/media/modals/ImageEditor.js +73 -0
  94. package/dist/features/media/upload/ImageUpload.d.ts +5 -1
  95. package/dist/features/media/upload/ImageUpload.js +33 -8
  96. package/dist/features/media/upload/MediaUploadField.d.ts +5 -1
  97. package/dist/features/media/upload/MediaUploadField.js +26 -12
  98. package/dist/features/orders/components/OrdersList.js +7 -7
  99. package/dist/features/orders/components/RefundHistoryTable.js +2 -2
  100. package/dist/features/orders/components/RefundRequestView.js +3 -3
  101. package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
  102. package/dist/features/pre-orders/components/PreOrderBadge.js +4 -4
  103. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  104. package/dist/features/pre-orders/components/PreorderCard.js +2 -2
  105. package/dist/features/products/components/CustomSectionsEditor.js +1 -1
  106. package/dist/features/products/components/MakeOfferButton.js +2 -2
  107. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  108. package/dist/features/products/components/PrizeDrawItemsEditor.js +3 -3
  109. package/dist/features/products/components/PrizeRevealModal.js +3 -3
  110. package/dist/features/products/components/ProductDetailPageView.js +4 -4
  111. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  112. package/dist/features/products/components/ProductGrid.js +3 -3
  113. package/dist/features/promotions/components/CouponCard.js +2 -2
  114. package/dist/features/promotions/components/PromotionsView.js +1 -1
  115. package/dist/features/reviews/components/ReviewDetailShell.js +2 -2
  116. package/dist/features/reviews/components/ReviewsList.js +1 -1
  117. package/dist/features/seller/components/SellerAddressesView.js +2 -2
  118. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +2 -2
  119. package/dist/features/seller/components/SellerAuctionsView.js +1 -1
  120. package/dist/features/seller/components/SellerBidsView.js +1 -1
  121. package/dist/features/seller/components/SellerBundlesView.js +2 -2
  122. package/dist/features/seller/components/SellerClassifiedView.js +3 -3
  123. package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
  124. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  125. package/dist/features/seller/components/SellerDigitalCodesView.js +2 -2
  126. package/dist/features/seller/components/SellerFeaturesView.js +1 -1
  127. package/dist/features/seller/components/SellerLiveView.js +4 -4
  128. package/dist/features/seller/components/SellerOffersPanel.js +2 -2
  129. package/dist/features/seller/components/SellerOffersView.js +1 -1
  130. package/dist/features/seller/components/SellerOrdersView.js +2 -2
  131. package/dist/features/seller/components/SellerPayoutMethodsView.js +2 -2
  132. package/dist/features/seller/components/SellerPayoutsView.js +1 -1
  133. package/dist/features/seller/components/SellerProductsCards.js +1 -1
  134. package/dist/features/seller/components/SellerProductsView.js +1 -1
  135. package/dist/features/seller/components/SellerReviewsView.js +1 -1
  136. package/dist/features/seller/components/SellerShippingConfigsView.js +3 -3
  137. package/dist/features/seller/components/SellerStoreCategoriesView.js +2 -2
  138. package/dist/features/seller/components/SellerTemplatesView.js +2 -2
  139. package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
  140. package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
  141. package/dist/features/stores/components/StoreHeader.js +1 -1
  142. package/dist/features/stores/components/StoreListingsGuideView.js +3 -3
  143. package/dist/features/stores/components/StoreOrdersGuideView.js +4 -4
  144. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -2
  145. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +4 -4
  146. package/dist/features/wishlist/components/WishlistPage.js +1 -1
  147. package/dist/index.d.ts +2 -0
  148. package/dist/index.js +3 -0
  149. package/dist/styles.css +286 -3
  150. package/dist/tailwind-utilities.css +1 -1
  151. package/dist/tokens/motion.d.ts +162 -0
  152. package/dist/tokens/motion.js +89 -0
  153. package/dist/ui/DataTable.js +3 -2
  154. package/dist/ui/components/Accordion.js +2 -1
  155. package/dist/ui/components/Card.d.ts +5 -2
  156. package/dist/ui/components/Card.js +29 -11
  157. package/dist/ui/components/Div.d.ts +2 -16
  158. package/dist/ui/components/Div.js +2 -16
  159. package/dist/ui/components/Layout.d.ts +9 -19
  160. package/dist/ui/components/Layout.js +9 -7
  161. package/dist/ui/components/Modal.js +7 -4
  162. package/dist/ui/components/Motion.d.ts +75 -0
  163. package/dist/ui/components/Motion.js +122 -0
  164. package/dist/ui/components/Semantic.d.ts +81 -14
  165. package/dist/ui/components/Semantic.js +75 -10
  166. package/dist/ui/components/Semantic.style.css +261 -2
  167. package/dist/ui/components/SideDrawer.d.ts +1 -1
  168. package/dist/ui/components/SideDrawer.js +8 -6
  169. package/dist/ui/components/SideModal.d.ts +1 -1
  170. package/dist/ui/components/SideModal.js +11 -9
  171. package/dist/ui/components/StackedViewShell.js +6 -1
  172. package/dist/ui/components/Toast.js +5 -2
  173. package/dist/ui/components/Typography.d.ts +44 -3
  174. package/dist/ui/components/Typography.js +15 -30
  175. package/dist/ui/components/Typography.style.css +24 -0
  176. package/dist/ui/components/VacationBanner.js +2 -1
  177. package/dist/ui/components/surface-tokens.d.ts +70 -0
  178. package/dist/ui/components/surface-tokens.js +68 -0
  179. package/dist/ui/forms/FormShell.d.ts +6 -1
  180. package/dist/ui/forms/FormShell.js +32 -4
  181. package/dist/ui/index.d.ts +9 -2
  182. package/dist/ui/index.js +4 -2
  183. package/dist/validation/schemas.d.ts +28 -28
  184. package/package.json +3 -1
@@ -2,11 +2,13 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState, useCallback } from "react";
4
4
  import { useTranslations } from "next-intl";
5
+ import { motion, AnimatePresence, useReducedMotion } from "motion/react";
5
6
  import { Button } from "./Button";
6
7
  import { Row } from "./Layout";
7
8
  import { Heading, Span } from "./Typography";
8
9
  import { useSwipe } from "../../react";
9
10
  import { Text } from "./Typography";
11
+ import { SPRING_SNAPPY } from "../../tokens/motion";
10
12
  const UI_SIDE_DRAWER = {
11
13
  backdrop: "appkit-side-drawer__backdrop",
12
14
  root: "appkit-side-drawer",
@@ -142,11 +144,11 @@ export function SideDrawer({ isOpen, onClose, title, children, footer, mode = "v
142
144
  : { onSwipeRight: () => attemptClose() }),
143
145
  minSwipeDistance: 60,
144
146
  });
145
- if (!isOpen)
146
- return null;
147
+ const reduced = useReducedMotion();
147
148
  const positionClass = side === "left" ? UI_SIDE_DRAWER.left : UI_SIDE_DRAWER.right;
148
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: UI_SIDE_DRAWER.backdrop, onClick: attemptClose, "aria-hidden": "true" }), _jsxs("div", { ref: drawerRef, className: [UI_SIDE_DRAWER.root, positionClass].join(" "), role: "dialog", "aria-modal": "true", "aria-labelledby": "drawer-title", "data-section": "sidedrawer-div-598", children: [_jsxs(Row, { justify: "between", gap: "none", className: [
149
- UI_SIDE_DRAWER.header,
150
- UI_SIDE_DRAWER.headerMode[mode],
151
- ].join(" "), children: [_jsxs(Row, { gap: "3", className: "min-w-0", children: [_jsx(Button, { variant: "ghost", onClick: attemptClose, className: UI_SIDE_DRAWER.closeBtn, "aria-label": tActions("close"), children: _jsx("svg", { className: UI_SIDE_DRAWER.closeIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }), _jsx(Heading, { level: 3, id: "drawer-title", className: "truncate", children: title })] }), mode === "delete" && (_jsx(Span, { className: UI_SIDE_DRAWER.deleteBadge, children: tActions("delete") }))] }), _jsx("div", { className: UI_SIDE_DRAWER.content, "data-section": "sidedrawer-div-599", children: children }), footer && _jsx("div", { className: UI_SIDE_DRAWER.footer, "data-section": "sidedrawer-div-600", children: footer })] }), showUnsavedWarning && (_jsxs(_Fragment, { children: [_jsx("div", { className: UI_SIDE_DRAWER.warnBackdrop, onClick: cancelClose }), _jsxs("div", { className: UI_SIDE_DRAWER.warnDialog, "data-section": "sidedrawer-div-601", children: [_jsxs("div", { className: UI_SIDE_DRAWER.warnHeader, "data-section": "sidedrawer-div-602", children: [_jsx("div", { className: UI_SIDE_DRAWER.warnIcon, "data-section": "sidedrawer-div-603", children: _jsx("svg", { fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }) }), _jsxs("div", { "data-section": "sidedrawer-div-604", children: [_jsx(Heading, { level: 4, className: "mb-1", children: tConfirm("unsavedChangesTitle") }), _jsx(Text, { className: UI_SIDE_DRAWER.warnText, children: tConfirm("unsavedChangesDescription") })] })] }), _jsxs("div", { className: UI_SIDE_DRAWER.warnActions, "data-section": "sidedrawer-div-605", children: [_jsx(Button, { variant: "outline", onClick: cancelClose, size: "sm", children: tActions("keepEditing") }), _jsx(Button, { variant: "danger", onClick: confirmClose, size: "sm", children: tActions("discardChanges") })] })] })] }))] }));
149
+ const slideX = side === "left" ? "-100%" : "100%";
150
+ return (_jsx(AnimatePresence, { children: isOpen && (_jsxs(_Fragment, { children: [_jsx(motion.div, { className: UI_SIDE_DRAWER.backdrop, onClick: attemptClose, "aria-hidden": "true", initial: reduced ? false : { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 } }), _jsxs(motion.div, { ref: drawerRef, className: [UI_SIDE_DRAWER.root, positionClass].join(" "), role: "dialog", "aria-modal": "true", "aria-labelledby": "drawer-title", initial: reduced ? false : { x: slideX }, animate: { x: 0 }, exit: { x: slideX }, transition: SPRING_SNAPPY, "data-section": "sidedrawer-div-598", children: [_jsxs(Row, { justify: "between", gap: "none", className: [
151
+ UI_SIDE_DRAWER.header,
152
+ UI_SIDE_DRAWER.headerMode[mode],
153
+ ].join(" "), children: [_jsxs(Row, { gap: "3", className: "min-w-0", children: [_jsx(Button, { variant: "ghost", onClick: attemptClose, className: UI_SIDE_DRAWER.closeBtn, "aria-label": tActions("close"), children: _jsx("svg", { className: UI_SIDE_DRAWER.closeIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }), _jsx(Heading, { level: 3, id: "drawer-title", className: "truncate", children: title })] }), mode === "delete" && (_jsx(Span, { className: UI_SIDE_DRAWER.deleteBadge, children: tActions("delete") }))] }), _jsx("div", { className: UI_SIDE_DRAWER.content, "data-section": "sidedrawer-div-599", children: children }), footer && _jsx("div", { className: UI_SIDE_DRAWER.footer, "data-section": "sidedrawer-div-600", children: footer })] }), showUnsavedWarning && (_jsxs(_Fragment, { children: [_jsx("div", { className: UI_SIDE_DRAWER.warnBackdrop, onClick: cancelClose }), _jsxs("div", { className: UI_SIDE_DRAWER.warnDialog, "data-section": "sidedrawer-div-601", children: [_jsxs("div", { className: UI_SIDE_DRAWER.warnHeader, "data-section": "sidedrawer-div-602", children: [_jsx("div", { className: UI_SIDE_DRAWER.warnIcon, "data-section": "sidedrawer-div-603", children: _jsx("svg", { fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }) }), _jsxs("div", { "data-section": "sidedrawer-div-604", children: [_jsx(Heading, { level: 4, className: "mb-1", children: tConfirm("unsavedChangesTitle") }), _jsx(Text, { className: UI_SIDE_DRAWER.warnText, children: tConfirm("unsavedChangesDescription") })] })] }), _jsxs("div", { className: UI_SIDE_DRAWER.warnActions, "data-section": "sidedrawer-div-605", children: [_jsx(Button, { variant: "outline", onClick: cancelClose, size: "sm", children: tActions("keepEditing") }), _jsx(Button, { variant: "danger", onClick: confirmClose, size: "sm", children: tActions("discardChanges") })] })] })] }))] })) }));
152
154
  }
@@ -21,4 +21,4 @@ export interface SideModalProps {
21
21
  * - backdrop click closes panel
22
22
  * - role="dialog" + aria-modal + aria-labelledby
23
23
  */
24
- export declare function SideModal({ isOpen, onClose, title, side, children, className, }: SideModalProps): import("react/jsx-runtime").JSX.Element | null;
24
+ export declare function SideModal({ isOpen, onClose, title, side, children, className, }: SideModalProps): import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef } from "react";
4
+ import { motion, AnimatePresence, useReducedMotion } from "motion/react";
4
5
  import { Button, Div, Heading } from "..";
6
+ import { SPRING_SNAPPY } from "../../tokens/motion";
5
7
  /**
6
8
  * SideModal — slides in from the right (or left) on desktop (60 vw),
7
9
  * full-screen drawer on mobile (< sm breakpoint).
@@ -48,13 +50,13 @@ export function SideModal({ isOpen, onClose, title, side = "right", children, cl
48
50
  document.body.style.overflow = "";
49
51
  };
50
52
  }, [isOpen]);
51
- if (!isOpen)
52
- return null;
53
- return (_jsxs(Div, { className: "appkit-side-modal", "aria-hidden": !isOpen, children: [_jsx(Div, { className: "appkit-side-modal__backdrop", onClick: onClose, "aria-hidden": "true" }), _jsxs(Div, { ref: panelRef, role: "dialog", "aria-modal": "true", "aria-labelledby": title ? titleId.current : undefined, className: [
54
- "appkit-side-modal__panel",
55
- `appkit-side-modal__panel--${side}`,
56
- className,
57
- ]
58
- .filter(Boolean)
59
- .join(" "), children: [title && (_jsxs(Div, { className: "appkit-side-modal__header", children: [_jsx(Heading, { level: 2, id: titleId.current, className: "text-base font-semibold text-neutral-900 dark:text-white truncate", children: title }), _jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, "aria-label": "Close panel", className: "ml-2 flex-shrink-0", children: "\u2715" })] })), _jsx(Div, { className: "appkit-side-modal__body", children: children })] })] }));
53
+ const reduced = useReducedMotion();
54
+ const slideX = side === "left" ? "-100%" : "100%";
55
+ return (_jsx(AnimatePresence, { children: isOpen && (_jsxs(Div, { className: "appkit-side-modal", "aria-hidden": !isOpen, children: [_jsx(motion.div, { className: "appkit-side-modal__backdrop", onClick: onClose, "aria-hidden": "true", initial: reduced ? false : { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 } }), _jsxs(motion.div, { ref: panelRef, role: "dialog", "aria-modal": "true", "aria-labelledby": title ? titleId.current : undefined, className: [
56
+ "appkit-side-modal__panel",
57
+ `appkit-side-modal__panel--${side}`,
58
+ className,
59
+ ]
60
+ .filter(Boolean)
61
+ .join(" "), initial: reduced ? false : { x: slideX }, animate: { x: 0 }, exit: { x: slideX }, transition: SPRING_SNAPPY, children: [title && (_jsxs(Div, { className: "appkit-side-modal__header", children: [_jsx(Heading, { level: 2, id: titleId.current, className: "text-base font-semibold text-neutral-900 dark:text-white truncate", children: title }), _jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, "aria-label": "Close panel", className: "ml-2 flex-shrink-0", children: "\u2715" })] })), _jsx(Div, { className: "appkit-side-modal__body", children: children })] })] })) }));
60
62
  }
@@ -33,5 +33,10 @@ export function StackedViewShell({ title, labels = {},
33
33
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
34
34
  portal, renderHeader, sections = [], isEmpty = false, renderEmpty, overlays, className = "", }) {
35
35
  const displayTitle = title ?? labels?.title;
36
- return (_jsxs(Div, { className: className, children: [renderHeader ? (renderHeader()) : displayTitle ? (_jsx(Heading, { level: 1, className: "text-2xl font-bold mb-6", children: displayTitle })) : null, isEmpty && renderEmpty ? (renderEmpty()) : (_jsx(_Fragment, { children: sections.map((slot, i) => (_jsx(React.Fragment, { children: resolveSlot(slot) }, i))) })), overlays] }));
36
+ return (_jsxs(Div, { className: className, children: [renderHeader ? (renderHeader()) : displayTitle ? (_jsx(Heading, { level: 1, className: "text-2xl font-bold mb-6", children: displayTitle })) : null, isEmpty && renderEmpty ? (renderEmpty()) : (_jsx(_Fragment, { children: sections.map((slot, i) => {
37
+ const resolved = resolveSlot(slot);
38
+ if (resolved == null)
39
+ return null;
40
+ return _jsx(React.Fragment, { children: resolved }, i);
41
+ }) })), overlays] }));
37
42
  }
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
+ import { motion, AnimatePresence, useReducedMotion } from "motion/react";
4
5
  import { Button } from "./Button";
5
6
  import { Text } from "./Typography";
7
+ import { SPRING_SNAPPY } from "../../tokens/motion";
6
8
  const ToastContext = React.createContext(undefined);
7
9
  function buildToastId() {
8
10
  return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
@@ -47,14 +49,15 @@ export function ToastProvider({ children, position = "top-right", }) {
47
49
  }, [hideToast]);
48
50
  return (_jsxs(ToastContext.Provider, { value: { showToast, hideToast }, children: [children, _jsx("div", { "aria-live": "polite", "aria-atomic": "true", "data-testid": "toast-container", className: [UI_TOAST.container, UI_TOAST.positions[position]]
49
51
  .filter(Boolean)
50
- .join(" "), "data-section": "toast-div-623", children: toasts.map((toast) => (_jsx(ToastRow, { toast: toast, onClose: hideToast }, toast.id))) })] }));
52
+ .join(" "), "data-section": "toast-div-623", children: _jsx(AnimatePresence, { mode: "popLayout", children: toasts.map((toast) => (_jsx(ToastRow, { toast: toast, onClose: hideToast }, toast.id))) }) })] }));
51
53
  }
52
54
  function ToastRow({ toast, onClose, }) {
55
+ const reduced = useReducedMotion();
53
56
  const iconMap = {
54
57
  success: _jsx("span", { "aria-hidden": "true", children: "\u2713" }),
55
58
  error: _jsx("span", { "aria-hidden": "true", children: "!" }),
56
59
  warning: _jsx("span", { "aria-hidden": "true", children: "!" }),
57
60
  info: _jsx("span", { "aria-hidden": "true", children: "i" }),
58
61
  };
59
- return (_jsxs("div", { role: "alert", "data-testid": "toast", className: [UI_TOAST.row, UI_TOAST.variants[toast.variant]].join(" "), "data-section": "toast-div-624", children: [_jsx("div", { className: UI_TOAST.icon, "data-section": "toast-div-625", children: iconMap[toast.variant] }), _jsx(Text, { as: "div", size: "sm", weight: "medium", className: "flex-1 pr-1", children: toast.message }), toast.action && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => { toast.action.onClick(); onClose(toast.id); }, className: "min-h-0 shrink-0 px-2 py-1 font-semibold underline", children: toast.action.label })), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onClose(toast.id), className: "min-h-0 shrink-0 px-2 py-1", "aria-label": "Close notification", children: "\u00D7" })] }));
62
+ return (_jsxs(motion.div, { role: "alert", "data-testid": "toast", className: [UI_TOAST.row, UI_TOAST.variants[toast.variant]].join(" "), layout: true, initial: reduced ? false : { opacity: 0, x: 24, scale: 0.95 }, animate: { opacity: 1, x: 0, scale: 1 }, exit: { opacity: 0, x: 24, scale: 0.95 }, transition: SPRING_SNAPPY, "data-section": "toast-div-624", children: [_jsx("div", { className: UI_TOAST.icon, "data-section": "toast-div-625", children: iconMap[toast.variant] }), _jsx(Text, { as: "div", size: "sm", weight: "medium", className: "flex-1 pr-1", children: toast.message }), toast.action && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => { toast.action.onClick(); onClose(toast.id); }, className: "min-h-0 shrink-0 px-2 py-1 font-semibold underline", children: toast.action.label })), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onClose(toast.id), className: "min-h-0 shrink-0 px-2 py-1", "aria-label": "Close notification", children: "\u00D7" })] }));
60
63
  }
@@ -1,19 +1,59 @@
1
1
  import React from "react";
2
+ declare const TYPOGRAPHY: {
3
+ readonly headingLevel: {
4
+ readonly 1: "appkit-heading--h1";
5
+ readonly 2: "appkit-heading--h2";
6
+ readonly 3: "appkit-heading--h3";
7
+ readonly 4: "appkit-heading--h4";
8
+ readonly 5: "appkit-heading--h5";
9
+ readonly 6: "appkit-heading--h6";
10
+ };
11
+ readonly textSize: {
12
+ readonly xs: "appkit-text--xs";
13
+ readonly sm: "appkit-text--sm";
14
+ readonly base: "appkit-text--base";
15
+ readonly lg: "appkit-text--lg";
16
+ readonly xl: "appkit-text--xl";
17
+ };
18
+ readonly textWeight: {
19
+ readonly normal: "appkit-font--normal";
20
+ readonly medium: "appkit-font--medium";
21
+ readonly semibold: "appkit-font--semibold";
22
+ readonly bold: "appkit-font--bold";
23
+ };
24
+ readonly colorVariant: {
25
+ readonly primary: "appkit-color--primary";
26
+ readonly secondary: "appkit-color--secondary";
27
+ readonly muted: "appkit-color--muted";
28
+ readonly faint: "appkit-color--faint";
29
+ readonly error: "appkit-color--error";
30
+ readonly danger: "appkit-color--error";
31
+ readonly success: "appkit-color--success";
32
+ readonly warning: "appkit-color--warning";
33
+ readonly info: "appkit-color--info";
34
+ readonly none: "";
35
+ readonly inherit: "";
36
+ readonly accent: "appkit-color--accent";
37
+ };
38
+ };
39
+ export type ColorVariant = keyof typeof TYPOGRAPHY.colorVariant;
2
40
  interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
3
41
  level?: 1 | 2 | 3 | 4 | 5 | 6;
4
42
  variant?: "primary" | "secondary" | "muted" | "none";
43
+ color?: ColorVariant;
5
44
  children: React.ReactNode;
6
45
  }
7
- export declare function Heading({ level, variant, className, children, ...props }: HeadingProps): import("react/jsx-runtime").JSX.Element;
46
+ export declare function Heading({ level, variant, color, className, children, ...props }: HeadingProps): import("react/jsx-runtime").JSX.Element;
8
47
  interface TextProps extends React.HTMLAttributes<HTMLParagraphElement> {
9
48
  variant?: "primary" | "secondary" | "muted" | "error" | "success" | "none";
49
+ color?: ColorVariant;
10
50
  size?: "xs" | "sm" | "base" | "lg" | "xl";
11
51
  weight?: "normal" | "medium" | "semibold" | "bold";
12
52
  /** Override the rendered element. Defaults to `p`. */
13
53
  as?: React.ElementType;
14
54
  children: React.ReactNode;
15
55
  }
16
- export declare function Text({ variant, size, weight, className, as: Tag, children, ...props }: TextProps): import("react/jsx-runtime").JSX.Element;
56
+ export declare function Text({ variant, color, size, weight, className, as: Tag, children, ...props }: TextProps): import("react/jsx-runtime").JSX.Element;
17
57
  interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
18
58
  required?: boolean;
19
59
  children: React.ReactNode;
@@ -42,9 +82,10 @@ export declare function Caption({ variant, className, children, ...props }: Capt
42
82
  interface SpanProps extends React.HTMLAttributes<HTMLSpanElement> {
43
83
  /** Colour variant. "inherit" (default) applies no colour class. */
44
84
  variant?: "inherit" | "primary" | "secondary" | "muted" | "error" | "success" | "accent";
85
+ color?: ColorVariant;
45
86
  size?: "xs" | "sm" | "base" | "lg" | "xl";
46
87
  weight?: "normal" | "medium" | "semibold" | "bold";
47
88
  children?: React.ReactNode;
48
89
  }
49
- export declare function Span({ variant, size, weight, className, children, ...props }: SpanProps): import("react/jsx-runtime").JSX.Element;
90
+ export declare function Span({ variant, color, size, weight, className, children, ...props }: SpanProps): import("react/jsx-runtime").JSX.Element;
50
91
  export {};
@@ -25,30 +25,36 @@ const TYPOGRAPHY = {
25
25
  primary: "appkit-color--primary",
26
26
  secondary: "appkit-color--secondary",
27
27
  muted: "appkit-color--muted",
28
+ faint: "appkit-color--faint",
28
29
  error: "appkit-color--error",
30
+ danger: "appkit-color--error",
29
31
  success: "appkit-color--success",
32
+ warning: "appkit-color--warning",
33
+ info: "appkit-color--info",
30
34
  none: "",
31
35
  inherit: "",
32
36
  accent: "appkit-color--accent",
33
37
  },
34
38
  };
35
- export function Heading({ level = 1, variant = "primary", className = "", children, ...props }) {
39
+ export function Heading({ level = 1, variant = "primary", color, className = "", children, ...props }) {
36
40
  const Tag = `h${level}`;
41
+ const resolvedColor = color ?? variant;
37
42
  return (_jsx(Tag, { className: [
38
43
  "appkit-heading",
39
44
  TYPOGRAPHY.headingLevel[level],
40
- TYPOGRAPHY.colorVariant[variant],
45
+ TYPOGRAPHY.colorVariant[resolvedColor],
41
46
  className,
42
47
  ]
43
48
  .filter(Boolean)
44
49
  .join(" "), ...props, children: children }));
45
50
  }
46
- export function Text({ variant = "primary", size = "base", weight = "normal", className = "", as: Tag = "p", children, ...props }) {
51
+ export function Text({ variant = "primary", color, size = "base", weight = "normal", className = "", as: Tag = "p", children, ...props }) {
52
+ const resolvedColor = color ?? variant;
47
53
  return (_jsx(Tag, { className: [
48
54
  "appkit-text",
49
55
  TYPOGRAPHY.textSize[size],
50
56
  TYPOGRAPHY.textWeight[weight],
51
- TYPOGRAPHY.colorVariant[variant],
57
+ TYPOGRAPHY.colorVariant[resolvedColor],
52
58
  className,
53
59
  ]
54
60
  .filter(Boolean)
@@ -67,34 +73,13 @@ export function Caption({ variant = "default", className = "", children, ...prop
67
73
  .filter(Boolean)
68
74
  .join(" "), ...props, children: children }));
69
75
  }
70
- export function Span({ variant = "inherit", size, weight, className = "", children, ...props }) {
71
- const variantClasses = {
72
- inherit: "",
73
- primary: "appkit-color--primary",
74
- secondary: "appkit-color--secondary",
75
- muted: "appkit-color--muted",
76
- error: "appkit-color--error",
77
- success: "appkit-color--success",
78
- accent: "appkit-color--accent",
79
- };
80
- const sizeClasses = {
81
- xs: "appkit-text--xs",
82
- sm: "appkit-text--sm",
83
- base: "appkit-text--base",
84
- lg: "appkit-text--lg",
85
- xl: "appkit-text--xl",
86
- };
87
- const weightClasses = {
88
- normal: "appkit-font--normal",
89
- medium: "appkit-font--medium",
90
- semibold: "appkit-font--semibold",
91
- bold: "appkit-font--bold",
92
- };
76
+ export function Span({ variant = "inherit", color, size, weight, className = "", children, ...props }) {
77
+ const resolvedColor = color ?? variant;
93
78
  const classes = [
94
79
  "appkit-span",
95
- size ? sizeClasses[size] : "",
96
- weight ? weightClasses[weight] : "",
97
- variantClasses[variant],
80
+ size ? TYPOGRAPHY.textSize[size] : "",
81
+ weight ? TYPOGRAPHY.textWeight[weight] : "",
82
+ TYPOGRAPHY.colorVariant[resolvedColor],
98
83
  className,
99
84
  ]
100
85
  .filter(Boolean)
@@ -107,6 +107,18 @@
107
107
  color: var(--appkit-color-secondary);
108
108
  }
109
109
 
110
+ .appkit-color--faint {
111
+ color: var(--appkit-color-zinc-400);
112
+ }
113
+
114
+ .appkit-color--warning {
115
+ color: var(--appkit-color-warning, #d97706);
116
+ }
117
+
118
+ .appkit-color--info {
119
+ color: var(--appkit-color-info, #0284c7);
120
+ }
121
+
110
122
  .dark .appkit-color--primary {
111
123
  color: var(--appkit-color-text);
112
124
  }
@@ -131,6 +143,18 @@
131
143
  color: var(--appkit-color-primary-400);
132
144
  }
133
145
 
146
+ .dark .appkit-color--faint {
147
+ color: var(--appkit-color-zinc-600);
148
+ }
149
+
150
+ .dark .appkit-color--warning {
151
+ color: var(--appkit-color-warning, #fbbf24);
152
+ }
153
+
154
+ .dark .appkit-color--info {
155
+ color: var(--appkit-color-info, #38bdf8);
156
+ }
157
+
134
158
  .appkit-label {
135
159
  display: block;
136
160
  margin-bottom: 0.375rem;
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Alert } from "./Alert";
4
+ import { Span } from "./Typography";
4
5
  /**
5
6
  * S-STORE-6-A — Vacation-mode banner shown on product detail + checkout
6
7
  * pages when the seller has paused new orders.
@@ -12,5 +13,5 @@ export function VacationBanner({ storeName, message, returnDate, className, }) {
12
13
  month: "short",
13
14
  day: "numeric",
14
15
  });
15
- return (_jsx(Alert, { variant: "warning", className: className, children: _jsxs("div", { className: "text-sm", children: [_jsx("strong", { children: storeName ? `${storeName} is on vacation` : "Store is on vacation" }), message ? _jsxs("span", { children: [" \u2014 ", message] }) : null, formattedDate ? _jsxs("span", { children: [" Returns ", formattedDate, "."] }) : null, _jsx("div", { className: "text-xs opacity-80 mt-1", children: "New orders are paused; you can still wishlist items." })] }) }));
16
+ return (_jsx(Alert, { variant: "warning", className: className, children: _jsxs("div", { className: "text-sm", children: [_jsx(Span, { weight: "bold", children: storeName ? `${storeName} is on vacation` : "Store is on vacation" }), message ? _jsxs("span", { children: [" \u2014 ", message] }) : null, formattedDate ? _jsxs("span", { children: [" Returns ", formattedDate, "."] }) : null, _jsx("div", { className: "text-xs opacity-80 mt-1", children: "New orders are paused; you can still wishlist items." })] }) }));
16
17
  }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Surface & layout tokens — shared prop maps for all layout primitives.
3
+ *
4
+ * These maps power the Bootstrap/MUI-style props (`surface`, `padding`,
5
+ * `rounded`, `border`, `shadow`) on Stack, Row, Grid, Container, Section,
6
+ * Article, Main, Aside, Div, BlockHeader, and BlockFooter.
7
+ */
8
+ export declare const SURFACE_MAP: {
9
+ readonly none: "";
10
+ readonly default: "bg-white dark:bg-slate-900";
11
+ readonly muted: "bg-zinc-50 dark:bg-slate-950";
12
+ readonly subtle: "bg-zinc-100 dark:bg-slate-900";
13
+ readonly inset: "bg-zinc-200 dark:bg-slate-800";
14
+ readonly card: "bg-white dark:bg-slate-900 border border-zinc-200 dark:border-slate-700 rounded-xl shadow-sm";
15
+ readonly elevated: "bg-white dark:bg-slate-900 border border-zinc-200 dark:border-slate-700 rounded-2xl shadow-md";
16
+ readonly interactive: "bg-white dark:bg-slate-900 border border-zinc-200 dark:border-slate-700 rounded-xl shadow-sm hover:shadow-md hover:border-primary-300/60 dark:hover:border-secondary-500/60 transition-all cursor-pointer";
17
+ readonly glass: "backdrop-blur-md bg-white/85 dark:bg-slate-900/85 border border-zinc-200/60 dark:border-slate-700/40 rounded-2xl shadow-lg";
18
+ readonly form: "bg-white dark:bg-slate-900 rounded-2xl border border-zinc-200 dark:border-slate-700 shadow-sm";
19
+ };
20
+ export type SurfaceKey = keyof typeof SURFACE_MAP;
21
+ export declare const PADDING_MAP: {
22
+ readonly none: "";
23
+ readonly xs: "p-2";
24
+ readonly sm: "p-3";
25
+ readonly md: "p-4";
26
+ readonly lg: "p-6";
27
+ readonly xl: "p-8";
28
+ readonly card: "p-5 sm:p-6 lg:p-8";
29
+ readonly section: "py-10 sm:py-14 xl:py-20";
30
+ readonly sectionSm: "py-6 sm:py-10";
31
+ readonly page: "py-6 sm:py-8 lg:py-10";
32
+ readonly inline: "px-4 py-3";
33
+ readonly inlineSm: "px-3 py-2";
34
+ readonly inlineLg: "px-6 py-4";
35
+ };
36
+ export type PaddingKey = keyof typeof PADDING_MAP;
37
+ export declare const ROUNDED_MAP: {
38
+ readonly none: "";
39
+ readonly sm: "rounded-sm";
40
+ readonly md: "rounded-md";
41
+ readonly lg: "rounded-lg";
42
+ readonly xl: "rounded-xl";
43
+ readonly "2xl": "rounded-2xl";
44
+ readonly full: "rounded-full";
45
+ };
46
+ export type RoundedKey = keyof typeof ROUNDED_MAP;
47
+ export declare const BORDER_MAP: {
48
+ readonly none: "";
49
+ readonly default: "border border-zinc-200 dark:border-slate-700";
50
+ readonly subtle: "border border-zinc-100 dark:border-slate-800/60";
51
+ readonly strong: "border border-zinc-300 dark:border-slate-600";
52
+ readonly dashed: "border border-dashed border-zinc-300 dark:border-slate-600";
53
+ };
54
+ export type BorderKey = keyof typeof BORDER_MAP;
55
+ export declare const SHADOW_MAP: {
56
+ readonly none: "";
57
+ readonly sm: "shadow-sm";
58
+ readonly md: "shadow-md";
59
+ readonly lg: "shadow-lg";
60
+ readonly xl: "shadow-xl";
61
+ };
62
+ export type ShadowKey = keyof typeof SHADOW_MAP;
63
+ export interface SurfaceProps {
64
+ surface?: SurfaceKey;
65
+ padding?: PaddingKey;
66
+ rounded?: RoundedKey;
67
+ border?: BorderKey;
68
+ shadow?: ShadowKey;
69
+ }
70
+ export declare function buildSurfaceClasses(props: SurfaceProps): string;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Surface & layout tokens — shared prop maps for all layout primitives.
3
+ *
4
+ * These maps power the Bootstrap/MUI-style props (`surface`, `padding`,
5
+ * `rounded`, `border`, `shadow`) on Stack, Row, Grid, Container, Section,
6
+ * Article, Main, Aside, Div, BlockHeader, and BlockFooter.
7
+ */
8
+ export const SURFACE_MAP = {
9
+ none: "",
10
+ default: "bg-white dark:bg-slate-900",
11
+ muted: "bg-zinc-50 dark:bg-slate-950",
12
+ subtle: "bg-zinc-100 dark:bg-slate-900",
13
+ inset: "bg-zinc-200 dark:bg-slate-800",
14
+ card: "bg-white dark:bg-slate-900 border border-zinc-200 dark:border-slate-700 rounded-xl shadow-sm",
15
+ elevated: "bg-white dark:bg-slate-900 border border-zinc-200 dark:border-slate-700 rounded-2xl shadow-md",
16
+ interactive: "bg-white dark:bg-slate-900 border border-zinc-200 dark:border-slate-700 rounded-xl shadow-sm hover:shadow-md hover:border-primary-300/60 dark:hover:border-secondary-500/60 transition-all cursor-pointer",
17
+ glass: "backdrop-blur-md bg-white/85 dark:bg-slate-900/85 border border-zinc-200/60 dark:border-slate-700/40 rounded-2xl shadow-lg",
18
+ form: "bg-white dark:bg-slate-900 rounded-2xl border border-zinc-200 dark:border-slate-700 shadow-sm",
19
+ };
20
+ export const PADDING_MAP = {
21
+ none: "",
22
+ xs: "p-2",
23
+ sm: "p-3",
24
+ md: "p-4",
25
+ lg: "p-6",
26
+ xl: "p-8",
27
+ card: "p-5 sm:p-6 lg:p-8",
28
+ section: "py-10 sm:py-14 xl:py-20",
29
+ sectionSm: "py-6 sm:py-10",
30
+ page: "py-6 sm:py-8 lg:py-10",
31
+ inline: "px-4 py-3",
32
+ inlineSm: "px-3 py-2",
33
+ inlineLg: "px-6 py-4",
34
+ };
35
+ export const ROUNDED_MAP = {
36
+ none: "",
37
+ sm: "rounded-sm",
38
+ md: "rounded-md",
39
+ lg: "rounded-lg",
40
+ xl: "rounded-xl",
41
+ "2xl": "rounded-2xl",
42
+ full: "rounded-full",
43
+ };
44
+ export const BORDER_MAP = {
45
+ none: "",
46
+ default: "border border-zinc-200 dark:border-slate-700",
47
+ subtle: "border border-zinc-100 dark:border-slate-800/60",
48
+ strong: "border border-zinc-300 dark:border-slate-600",
49
+ dashed: "border border-dashed border-zinc-300 dark:border-slate-600",
50
+ };
51
+ export const SHADOW_MAP = {
52
+ none: "",
53
+ sm: "shadow-sm",
54
+ md: "shadow-md",
55
+ lg: "shadow-lg",
56
+ xl: "shadow-xl",
57
+ };
58
+ export function buildSurfaceClasses(props) {
59
+ return [
60
+ props.surface ? SURFACE_MAP[props.surface] : "",
61
+ props.padding ? PADDING_MAP[props.padding] : "",
62
+ props.rounded ? ROUNDED_MAP[props.rounded] : "",
63
+ props.border ? BORDER_MAP[props.border] : "",
64
+ props.shadow ? SHADOW_MAP[props.shadow] : "",
65
+ ]
66
+ .filter(Boolean)
67
+ .join(" ");
68
+ }
@@ -1,4 +1,5 @@
1
1
  import React, { type ReactNode } from "react";
2
+ import type { ZodType } from "zod";
2
3
  export interface FormShellStep {
3
4
  id: string;
4
5
  label: string;
@@ -32,6 +33,10 @@ export interface FormShellProps {
32
33
  onPublish: (values: Record<string, unknown>) => Promise<void>;
33
34
  /** Current form values — caller owns state */
34
35
  values: Record<string, unknown>;
36
+ /** Zod schema for auto-validation on publish. Errors are mapped to field names. */
37
+ schema?: ZodType;
38
+ /** When true + schema provided, validate on every value change (not just publish). */
39
+ validateOnChange?: boolean;
35
40
  /** Whether any values differ from the persisted state */
36
41
  isDirty?: boolean;
37
42
  draftId?: string;
@@ -63,4 +68,4 @@ export interface FormShellProviderProps {
63
68
  values?: Record<string, unknown>;
64
69
  }
65
70
  export declare function FormShellProvider({ children, onSaveDraft, isDirty, autoSaveDelayMs, values, }: FormShellProviderProps): import("react/jsx-runtime").JSX.Element;
66
- export declare function FormShell({ steps, onSaveDraft, onPublish, values, isDirty, autoSaveDelayMs, publishLabel, saveDraftLabel, title, className, mobileAccordion, }: FormShellProps): import("react/jsx-runtime").JSX.Element;
71
+ export declare function FormShell({ steps, onSaveDraft, onPublish, values, schema, validateOnChange, isDirty, autoSaveDelayMs, publishLabel, saveDraftLabel, title, className, mobileAccordion, }: FormShellProps): import("react/jsx-runtime").JSX.Element;
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
4
4
  import { Button } from "../components/Button";
5
- import { Heading, Text } from "../components/Typography";
5
+ import { Heading, Span, Text } from "../components/Typography";
6
6
  // ─── Context ──────────────────────────────────────────────────────────────────
7
7
  export const FormShellContext = createContext(null);
8
8
  export function useFormShell() {
@@ -61,7 +61,7 @@ function ErrorSummary({ errors, visible }) {
61
61
  const entries = Object.entries(errors).filter(([, v]) => v);
62
62
  if (!visible || entries.length === 0)
63
63
  return null;
64
- return (_jsxs("div", { className: "appkit-formshell__error-summary", role: "alert", "aria-live": "assertive", children: [_jsxs(Text, { size: "sm", variant: "error", className: "appkit-formshell__error-summary__title", children: ["Please fix ", entries.length, " error", entries.length !== 1 ? "s" : "", " before publishing."] }), _jsx("ul", { className: "appkit-formshell__error-summary__list", children: entries.map(([field, msg]) => (_jsx("li", { children: _jsxs(Text, { size: "sm", variant: "error", children: [_jsx("strong", { children: field }), ": ", msg] }) }, field))) })] }));
64
+ return (_jsxs("div", { className: "appkit-formshell__error-summary", role: "alert", "aria-live": "assertive", children: [_jsxs(Text, { size: "sm", variant: "error", className: "appkit-formshell__error-summary__title", children: ["Please fix ", entries.length, " error", entries.length !== 1 ? "s" : "", " before publishing."] }), _jsx("ul", { className: "appkit-formshell__error-summary__list", children: entries.map(([field, msg]) => (_jsx("li", { children: _jsxs(Text, { size: "sm", variant: "error", children: [_jsx(Span, { weight: "bold", children: field }), ": ", msg] }) }, field))) })] }));
65
65
  }
66
66
  export function FormShellProvider({ children, onSaveDraft, isDirty = false, autoSaveDelayMs = 2000, values = {}, }) {
67
67
  const [errors, setErrors] = useState({});
@@ -122,8 +122,25 @@ export function FormShellProvider({ children, onSaveDraft, isDirty = false, auto
122
122
  }), [errors, touched, setFieldError, setFieldTouched, clearFieldError, isDirty]);
123
123
  return _jsx(FormShellContext.Provider, { value: ctx, children: children });
124
124
  }
125
+ // ─── Schema validation helper ────────────────────────────────────────────────
126
+ function validateSchema(schema, values, setFieldError, setErrors) {
127
+ const result = schema.safeParse(values);
128
+ if (result.success) {
129
+ setErrors({});
130
+ return true;
131
+ }
132
+ const newErrors = {};
133
+ for (const issue of result.error.issues) {
134
+ const path = issue.path.join(".");
135
+ if (path && !newErrors[path]) {
136
+ newErrors[path] = issue.message;
137
+ }
138
+ }
139
+ setErrors(newErrors);
140
+ return false;
141
+ }
125
142
  // ─── FormShell ────────────────────────────────────────────────────────────────
126
- export function FormShell({ steps, onSaveDraft, onPublish, values, isDirty = false, autoSaveDelayMs = 2000, publishLabel = "Publish", saveDraftLabel = "Save Draft", title, className = "", mobileAccordion = true, }) {
143
+ export function FormShell({ steps, onSaveDraft, onPublish, values, schema, validateOnChange = false, isDirty = false, autoSaveDelayMs = 2000, publishLabel = "Publish", saveDraftLabel = "Save Draft", title, className = "", mobileAccordion = true, }) {
127
144
  const [errors, setErrors] = useState({});
128
145
  const [touched, setTouched] = useState({});
129
146
  const [currentStep, setCurrentStep] = useState(0);
@@ -198,8 +215,19 @@ export function FormShell({ steps, onSaveDraft, onPublish, values, isDirty = fal
198
215
  setIsSubmitting(false);
199
216
  }
200
217
  }, [onSaveDraft, values]);
218
+ // Schema-driven live validation on value changes
219
+ useEffect(() => {
220
+ if (!schema || !validateOnChange)
221
+ return;
222
+ validateSchema(schema, values, setFieldError, setErrors);
223
+ }, [schema, validateOnChange, values, setFieldError]);
201
224
  const handlePublish = useCallback(async () => {
202
225
  setShowErrorSummary(true);
226
+ if (schema) {
227
+ const valid = validateSchema(schema, values, setFieldError, setErrors);
228
+ if (!valid)
229
+ return;
230
+ }
203
231
  if (!isPublishReady)
204
232
  return;
205
233
  setIsSubmitting(true);
@@ -209,7 +237,7 @@ export function FormShell({ steps, onSaveDraft, onPublish, values, isDirty = fal
209
237
  finally {
210
238
  setIsSubmitting(false);
211
239
  }
212
- }, [isPublishReady, onPublish, values]);
240
+ }, [isPublishReady, onPublish, values, schema, setFieldError]);
213
241
  const ctx = useMemo(() => ({
214
242
  errors,
215
243
  touched,
@@ -10,10 +10,11 @@ export type { FieldCheckboxProps } from "./forms";
10
10
  export { FieldCheckbox } from "./forms";
11
11
  export { buildColumns, createColumnBuilder, renderBoolean, renderCurrency, renderCurrencyCompact, renderCount, renderNullable, renderRating, } from "./columns";
12
12
  export type { BooleanRenderOpts, RatingMode, RatingRenderOpts, } from "./columns";
13
- export type { SectionProps, ArticleProps, MainProps, AsideProps, NavProps, BlockHeaderProps, BlockFooterProps, HeaderProps, FooterProps, UlProps, OlProps, LiProps, } from "./components/Semantic";
14
- export { Section, Article, Main, Aside, Nav, BlockHeader, BlockFooter, Header, Footer, Ul, Ol, Li, } from "./components/Semantic";
13
+ export type { SectionProps, ArticleProps, MainProps, AsideProps, NavProps, BlockHeaderProps, BlockFooterProps, HeaderProps, FooterProps, UlProps, OlProps, LiProps, TableProps, TheadProps, TbodyProps, TrProps, ThProps, TdProps, CodeProps, PreProps, BlockquoteProps, FigureProps, FigcaptionProps, DlProps, DtProps, DdProps, } from "./components/Semantic";
14
+ export { Section, Article, Main, Aside, Nav, BlockHeader, BlockFooter, Header, Footer, Ul, Ol, Li, Table, Thead, Tbody, Tr, Th, Td, Code, Pre, Blockquote, Figure, Figcaption, Dl, Dt, Dd, } from "./components/Semantic";
15
15
  export type { DivProps } from "./components/Div";
16
16
  export { Div } from "./components/Div";
17
+ export type { ColorVariant } from "./components/Typography";
17
18
  export { Heading, Text, Label, Caption, Span } from "./components/Typography";
18
19
  export { FilterChipGroup } from "./components/FilterChipGroup";
19
20
  export type { FilterChipGroupProps, FilterChipGroupTab, } from "./components/FilterChipGroup";
@@ -166,6 +167,8 @@ export type { DataTableProps, DataTableColumn } from "./DataTable";
166
167
  export { DataTable } from "./DataTable";
167
168
  export type { TableConfig, TableViewMode, PaginationConfig, StickyConfig, } from "../contracts";
168
169
  export { DEFAULT_TABLE_CONFIG, DEFAULT_PAGINATION_CONFIG, DEFAULT_STICKY_CONFIG, mergeTableConfig, } from "../contracts";
170
+ export type { SurfaceKey, PaddingKey, RoundedKey, BorderKey, ShadowKey, SurfaceProps, } from "./components/surface-tokens";
171
+ export { SURFACE_MAP, PADDING_MAP, ROUNDED_MAP, BORDER_MAP, SHADOW_MAP, buildSurfaceClasses, } from "./components/surface-tokens";
169
172
  export type { GapKey, ContainerSize, GridCols, ViewPortal, ContainerProps, StackProps, RowProps, GridProps, } from "./components/Layout";
170
173
  export { Container, Stack, Row, Grid, GRID_MAP } from "./components/Layout";
171
174
  export { classNames, mergeTailwindClasses } from "./style.helper";
@@ -203,3 +206,7 @@ export type { FormActionBarProps, FormActionBarBreadcrumb } from "./components/F
203
206
  export { FormActionBar } from "./components/FormActionBar";
204
207
  export type { ConfirmDeleteModalProps } from "./components/ConfirmDeleteModal";
205
208
  export { ConfirmDeleteModal } from "./components/ConfirmDeleteModal";
209
+ export type { FadeInProps, SlideUpProps, SlideInProps, ScaleInProps, CollapseProps, PressScaleProps, HoverLiftProps, AnimatedListProps, AnimatedDivProps, AnimatedStackProps, AnimatedRowProps, DraggableProps, SwipeableProps, } from "./components/Motion";
210
+ export { FadeIn, SlideUp, SlideIn, ScaleIn, Collapse, PressScale, HoverLift, AnimatedList, AnimatedDiv, AnimatedStack, AnimatedRow, Draggable, Swipeable, AnimatePresence, } from "./components/Motion";
211
+ export type { MotionPreset } from "../tokens/motion";
212
+ export { MOTION_PRESETS, SPRING_SNAPPY, SPRING_GENTLE, EASE_OUT, } from "../tokens/motion";