@mohasinac/appkit 2.7.49 → 2.7.50

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 (110) hide show
  1. package/dist/_internal/client/features/layout/SidebarCollapseToggle.d.ts +19 -0
  2. package/dist/_internal/client/features/layout/SidebarCollapseToggle.js +15 -0
  3. package/dist/_internal/client/features/layout/index.d.ts +2 -0
  4. package/dist/_internal/client/features/layout/index.js +1 -0
  5. package/dist/_internal/server/features/checkout/actions.js +25 -2
  6. package/dist/_internal/server/features/promotions/actions.js +3 -1
  7. package/dist/_internal/shared/actions/action-registry.js +149 -0
  8. package/dist/client.d.ts +16 -0
  9. package/dist/client.js +11 -0
  10. package/dist/features/account/components/UserSidebar.js +2 -1
  11. package/dist/features/admin/components/AdminBlogEditorView.js +6 -2
  12. package/dist/features/admin/components/AdminSidebar.js +2 -1
  13. package/dist/features/auth/repository/session.repository.js +16 -1
  14. package/dist/features/cart/hooks/useAddToCart.d.ts +2 -0
  15. package/dist/features/cart/hooks/useAddToCart.js +2 -0
  16. package/dist/features/cart/hooks/useGuestCart.d.ts +2 -0
  17. package/dist/features/cart/utils/guest-cart.d.ts +7 -0
  18. package/dist/features/cart/utils/pending-ops.d.ts +6 -0
  19. package/dist/features/categories/components/CategoryBundlesListing.js +9 -1
  20. package/dist/features/categories/components/CategoryProductsListing.js +6 -10
  21. package/dist/features/categories/schemas/firestore.d.ts +9 -0
  22. package/dist/features/events/components/EventRaffleWinnerView.d.ts +9 -1
  23. package/dist/features/events/components/EventRaffleWinnerView.js +3 -3
  24. package/dist/features/events/components/SpinWheelView.js +3 -3
  25. package/dist/features/layout/BottomNavLayout.d.ts +5 -0
  26. package/dist/features/layout/BottomNavLayout.js +21 -0
  27. package/dist/features/layout/TitleBar.js +7 -1
  28. package/dist/features/layout/TitleBarLayout.d.ts +8 -2
  29. package/dist/features/layout/TitleBarLayout.js +11 -7
  30. package/dist/features/orders/schemas/index.d.ts +2 -2
  31. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +9 -5
  32. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  33. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +3 -1
  34. package/dist/features/products/components/PrizeDrawEntryActions.js +8 -12
  35. package/dist/features/products/components/ProductDetailActions.d.ts +5 -1
  36. package/dist/features/products/components/ProductDetailActions.js +3 -1
  37. package/dist/features/products/components/ProductDetailPageView.d.ts +2 -0
  38. package/dist/features/products/components/ProductDetailPageView.js +4 -0
  39. package/dist/features/products/components/ProductGrid.js +3 -3
  40. package/dist/features/products/components/ProductsIndexListing.js +15 -8
  41. package/dist/features/promotions/components/CouponCard.d.ts +11 -1
  42. package/dist/features/promotions/components/CouponCard.js +36 -2
  43. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +27 -0
  44. package/dist/features/promotions/repository/claimed-coupons.repository.js +115 -0
  45. package/dist/features/promotions/schemas/firestore.d.ts +34 -0
  46. package/dist/features/promotions/schemas/firestore.js +13 -0
  47. package/dist/features/seller/components/SellerAddressesView.js +3 -2
  48. package/dist/features/seller/components/SellerBidsView.js +33 -3
  49. package/dist/features/seller/components/SellerOrdersView.js +35 -0
  50. package/dist/features/seller/components/SellerProductShell.d.ts +2 -0
  51. package/dist/features/seller/components/SellerProductShell.js +26 -4
  52. package/dist/features/seller/components/SellerProductsCards.d.ts +19 -0
  53. package/dist/features/seller/components/SellerProductsCards.js +19 -0
  54. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +14 -0
  55. package/dist/features/seller/components/SellerProductsFilterDrawer.js +20 -0
  56. package/dist/features/seller/components/SellerProductsView.d.ts +3 -1
  57. package/dist/features/seller/components/SellerProductsView.js +68 -19
  58. package/dist/features/seller/components/SellerReviewsView.js +67 -4
  59. package/dist/features/seller/components/SellerSidebar.js +2 -1
  60. package/dist/features/seller/components/seller-products-styles.d.ts +7 -0
  61. package/dist/features/seller/components/seller-products-styles.js +14 -0
  62. package/dist/features/shell/FormShell.d.ts +7 -1
  63. package/dist/features/shell/FormShell.js +5 -2
  64. package/dist/features/store-extensions/index.d.ts +4 -0
  65. package/dist/features/store-extensions/index.js +4 -0
  66. package/dist/features/store-extensions/repository/rbac.repositories.d.ts +23 -0
  67. package/dist/features/store-extensions/repository/rbac.repositories.js +32 -0
  68. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +91 -0
  69. package/dist/features/store-extensions/repository/store-extensions.repositories.js +127 -0
  70. package/dist/features/store-extensions/schemas/firestore.d.ts +244 -0
  71. package/dist/features/store-extensions/schemas/firestore.js +158 -0
  72. package/dist/features/store-extensions/schemas/rbac.d.ts +65 -0
  73. package/dist/features/store-extensions/schemas/rbac.js +43 -0
  74. package/dist/features/stores/components/InteractiveStoreCard.js +7 -3
  75. package/dist/features/stores/components/StoreProductsListing.js +6 -10
  76. package/dist/features/stores/schemas/firestore.d.ts +2 -0
  77. package/dist/index.d.ts +6 -0
  78. package/dist/index.js +8 -0
  79. package/dist/next/routing/route-map.d.ts +79 -0
  80. package/dist/next/routing/route-map.js +34 -0
  81. package/dist/react/hooks/useFormStatePreservation.d.ts +17 -0
  82. package/dist/react/hooks/useFormStatePreservation.js +62 -0
  83. package/dist/react/hooks/useInlineRowEdit.d.ts +24 -0
  84. package/dist/react/hooks/useInlineRowEdit.js +68 -0
  85. package/dist/react/index.d.ts +4 -0
  86. package/dist/react/index.js +4 -0
  87. package/dist/repositories/index.d.ts +4 -0
  88. package/dist/repositories/index.js +5 -0
  89. package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
  90. package/dist/seed/claimed-coupons-seed-data.d.ts +13 -0
  91. package/dist/seed/claimed-coupons-seed-data.js +79 -0
  92. package/dist/seed/index.d.ts +2 -0
  93. package/dist/seed/index.js +3 -0
  94. package/dist/seed/manifest.js +17 -0
  95. package/dist/seed/store-extensions-seed-data.d.ts +19 -0
  96. package/dist/seed/store-extensions-seed-data.js +421 -0
  97. package/dist/tailwind-utilities.css +1 -1
  98. package/dist/ui/components/Button.style.css +20 -12
  99. package/dist/ui/components/ClaimCouponButton.d.ts +28 -0
  100. package/dist/ui/components/ClaimCouponButton.js +89 -0
  101. package/dist/ui/components/QuickCreateModal.d.ts +15 -0
  102. package/dist/ui/components/QuickCreateModal.js +48 -0
  103. package/dist/ui/components/QuickCreateModal.style.css +84 -0
  104. package/dist/ui/components/StickyBottomBar.d.ts +22 -0
  105. package/dist/ui/components/StickyBottomBar.js +20 -0
  106. package/dist/ui/components/VacationBanner.d.ts +11 -0
  107. package/dist/ui/components/VacationBanner.js +16 -0
  108. package/dist/ui/index.d.ts +8 -0
  109. package/dist/ui/index.js +4 -0
  110. package/package.json +1 -1
@@ -81,41 +81,49 @@
81
81
  gap: 0.625rem;
82
82
  }
83
83
 
84
- .appkit-button--primary {
84
+ /* Filled variants — colour rules use a chained-class selector (specificity
85
+ (0,2,0)) so they beat single-class Tailwind text utilities (0,1,0). This
86
+ guarantees contrast-safe foregrounds even when call-sites add a stray
87
+ `text-*` className. Tailwind utilities still apply for non-color props
88
+ like `text-xs` (font-size). See plan §4 "Defensive layer" + the global
89
+ sweep request 2026-05-18. */
90
+
91
+ .appkit-button.appkit-button--primary {
85
92
  background: var(--appkit-color-primary-700);
86
93
  color: var(--appkit-color-text-on-primary);
87
94
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
88
95
  }
89
96
 
90
- .appkit-button--primary:hover:not(:disabled) {
97
+ .appkit-button.appkit-button--primary:hover:not(:disabled) {
91
98
  background: var(--appkit-color-primary-800);
92
99
  }
93
100
 
94
- .dark .appkit-button--primary {
101
+ .dark .appkit-button.appkit-button--primary {
95
102
  background: var(--appkit-color-secondary);
103
+ color: var(--appkit-color-text-on-primary);
96
104
  }
97
105
 
98
- .dark .appkit-button--primary:hover:not(:disabled) {
106
+ .dark .appkit-button.appkit-button--primary:hover:not(:disabled) {
99
107
  background: var(--appkit-color-secondary-400);
100
108
  }
101
109
 
102
- .appkit-button--secondary {
110
+ .appkit-button.appkit-button--secondary {
103
111
  background: var(--appkit-color-surface);
104
112
  border-color: var(--appkit-color-primary-700);
105
113
  color: var(--appkit-color-primary-700);
106
114
  }
107
115
 
108
- .appkit-button--secondary:hover:not(:disabled) {
116
+ .appkit-button.appkit-button--secondary:hover:not(:disabled) {
109
117
  background: color-mix(in srgb, var(--appkit-color-primary-700) 8%, transparent);
110
118
  }
111
119
 
112
- .dark .appkit-button--secondary {
120
+ .dark .appkit-button.appkit-button--secondary {
113
121
  background: transparent;
114
122
  border-color: var(--appkit-color-secondary);
115
123
  color: var(--appkit-color-secondary);
116
124
  }
117
125
 
118
- .dark .appkit-button--secondary:hover:not(:disabled) {
126
+ .dark .appkit-button.appkit-button--secondary:hover:not(:disabled) {
119
127
  background: color-mix(in srgb, var(--appkit-color-secondary) 12%, transparent);
120
128
  }
121
129
 
@@ -156,21 +164,21 @@
156
164
  background: rgba(30, 41, 59, 0.5);
157
165
  }
158
166
 
159
- .appkit-button--danger {
167
+ .appkit-button.appkit-button--danger {
160
168
  background: var(--appkit-color-error);
161
169
  color: var(--appkit-color-text-on-primary);
162
170
  }
163
171
 
164
- .appkit-button--danger:hover:not(:disabled) {
172
+ .appkit-button.appkit-button--danger:hover:not(:disabled) {
165
173
  background: var(--appkit-color-error-hover);
166
174
  }
167
175
 
168
- .appkit-button--warning {
176
+ .appkit-button.appkit-button--warning {
169
177
  background: var(--appkit-color-warning);
170
178
  color: var(--appkit-color-text-on-primary);
171
179
  }
172
180
 
173
- .appkit-button--warning:hover:not(:disabled) {
181
+ .appkit-button.appkit-button--warning:hover:not(:disabled) {
174
182
  background: var(--appkit-color-amber-400);
175
183
  }
176
184
 
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ClaimCouponButton — surfaced anywhere a user wins or earns a coupon
3
+ * (SpinWheel "YOU WON" panel, raffle winner page, prize-draw reveal modal,
4
+ * promotional inserts).
5
+ *
6
+ * Behaviour:
7
+ * 1. If the visitor is not signed in, opens the standard LoginRequiredModal —
8
+ * no coupon is copied or saved. The wallet is per-user, so anonymous
9
+ * claims would be lost.
10
+ * 2. POST `/api/user/coupons/claim` to persist the claim into the user's
11
+ * wallet (idempotent — second claim is a no-op).
12
+ * 3. Copy the code to the clipboard so the user can paste it at checkout.
13
+ *
14
+ * No more cart deep-link — the wallet ("My Coupons" page) is the single home
15
+ * for claimed coupons, and the user applies them from there at checkout.
16
+ */
17
+ import React from "react";
18
+ export interface ClaimCouponButtonProps {
19
+ couponCode: string;
20
+ /** Optional server-side claim handler — overrides the default wallet POST. */
21
+ onClaim?: (code: string) => Promise<void> | void;
22
+ /** Override the button label. */
23
+ label?: string;
24
+ className?: string;
25
+ size?: "sm" | "md" | "lg";
26
+ source?: "manual" | "promo" | "spin" | "raffle" | "prize-draw";
27
+ }
28
+ export declare function ClaimCouponButton({ couponCode, onClaim, label, className, size, source, }: ClaimCouponButtonProps): React.JSX.Element;
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * ClaimCouponButton — surfaced anywhere a user wins or earns a coupon
5
+ * (SpinWheel "YOU WON" panel, raffle winner page, prize-draw reveal modal,
6
+ * promotional inserts).
7
+ *
8
+ * Behaviour:
9
+ * 1. If the visitor is not signed in, opens the standard LoginRequiredModal —
10
+ * no coupon is copied or saved. The wallet is per-user, so anonymous
11
+ * claims would be lost.
12
+ * 2. POST `/api/user/coupons/claim` to persist the claim into the user's
13
+ * wallet (idempotent — second claim is a no-op).
14
+ * 3. Copy the code to the clipboard so the user can paste it at checkout.
15
+ *
16
+ * No more cart deep-link — the wallet ("My Coupons" page) is the single home
17
+ * for claimed coupons, and the user applies them from there at checkout.
18
+ */
19
+ import { useCallback, useState } from "react";
20
+ import { Button } from "./Button";
21
+ import { LoginRequiredModal } from "./LoginRequiredModal";
22
+ import { useSession } from "../../react/contexts/SessionContext";
23
+ import { useToast } from "./Toast";
24
+ async function postClaim(couponCode, source) {
25
+ if (typeof fetch === "undefined")
26
+ return false;
27
+ try {
28
+ const res = await fetch("/api/user/coupons/claim", {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ credentials: "include",
32
+ body: JSON.stringify({ couponCode, source }),
33
+ });
34
+ return res.ok;
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ async function copyToClipboard(text) {
41
+ if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
42
+ return false;
43
+ }
44
+ try {
45
+ await navigator.clipboard.writeText(text);
46
+ return true;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ export function ClaimCouponButton({ couponCode, onClaim, label, className, size = "md", source = "manual", }) {
53
+ const { user, loading } = useSession();
54
+ const { showToast } = useToast();
55
+ const [busy, setBusy] = useState(false);
56
+ const [claimed, setClaimed] = useState(false);
57
+ const [loginOpen, setLoginOpen] = useState(false);
58
+ const handleClick = useCallback(async () => {
59
+ if (busy || !couponCode)
60
+ return;
61
+ if (loading)
62
+ return;
63
+ if (!user) {
64
+ setLoginOpen(true);
65
+ return;
66
+ }
67
+ setBusy(true);
68
+ try {
69
+ const ok = onClaim != null
70
+ ? (await Promise.resolve(onClaim(couponCode)), true)
71
+ : await postClaim(couponCode, source);
72
+ if (!ok) {
73
+ showToast("Could not save coupon. Please try again.", "error");
74
+ return;
75
+ }
76
+ await copyToClipboard(couponCode);
77
+ setClaimed(true);
78
+ showToast(`${couponCode} saved to your coupons.`, "success");
79
+ }
80
+ finally {
81
+ setBusy(false);
82
+ }
83
+ }, [busy, couponCode, loading, onClaim, showToast, source, user]);
84
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "button", variant: "primary", size: size, onClick: handleClick, disabled: busy || !couponCode || loading, className: className, children: busy
85
+ ? "Saving…"
86
+ : claimed
87
+ ? "Saved to My Coupons"
88
+ : (label ?? "Claim coupon") }), _jsx(LoginRequiredModal, { isOpen: loginOpen, onClose: () => setLoginOpen(false), message: "Sign in to save coupons to your wallet." })] }));
89
+ }
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ export interface QuickCreateModalProps<T = unknown> {
3
+ isOpen: boolean;
4
+ title: string;
5
+ onSave: () => Promise<T> | T;
6
+ onSaved?: (doc: T) => void;
7
+ onCancel: () => void;
8
+ children: React.ReactNode;
9
+ fullPageHref?: string;
10
+ saveLabel?: string;
11
+ cancelLabel?: string;
12
+ isSaving?: boolean;
13
+ saveDisabled?: boolean;
14
+ }
15
+ export declare function QuickCreateModal<T = unknown>({ isOpen, title, onSave, onSaved, onCancel, children, fullPageHref, saveLabel, cancelLabel, isSaving, saveDisabled, }: QuickCreateModalProps<T>): React.ReactPortal | null;
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { createPortal } from "react-dom";
5
+ import { Button } from "./Button";
6
+ import { Div } from "./Div";
7
+ import { Heading } from "./Typography";
8
+ import { Row } from "./Layout";
9
+ export function QuickCreateModal({ isOpen, title, onSave, onSaved, onCancel, children, fullPageHref, saveLabel = "Save", cancelLabel = "Cancel", isSaving = false, saveDisabled = false, }) {
10
+ const [busy, setBusy] = React.useState(false);
11
+ const titleId = React.useId();
12
+ const panelRef = React.useRef(null);
13
+ React.useEffect(() => {
14
+ if (!isOpen)
15
+ return;
16
+ const prev = document.body.style.overflow;
17
+ document.body.style.overflow = "hidden";
18
+ return () => {
19
+ document.body.style.overflow = prev;
20
+ };
21
+ }, [isOpen]);
22
+ React.useEffect(() => {
23
+ if (!isOpen)
24
+ return;
25
+ const handler = (e) => {
26
+ if (e.key === "Escape" && !busy)
27
+ onCancel();
28
+ };
29
+ document.addEventListener("keydown", handler);
30
+ return () => document.removeEventListener("keydown", handler);
31
+ }, [isOpen, onCancel, busy]);
32
+ const handleSave = async () => {
33
+ if (saveDisabled || busy)
34
+ return;
35
+ setBusy(true);
36
+ try {
37
+ const doc = await onSave();
38
+ onSaved?.(doc);
39
+ }
40
+ finally {
41
+ setBusy(false);
42
+ }
43
+ };
44
+ if (!isOpen || typeof document === "undefined")
45
+ return null;
46
+ const saving = busy || isSaving;
47
+ return createPortal(_jsxs(Div, { className: "appkit-quick-create-modal", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [_jsx(Div, { className: "appkit-quick-create-modal__backdrop", "aria-hidden": "true", onClick: () => !saving && onCancel() }), _jsxs(Div, { ref: panelRef, tabIndex: -1, className: "appkit-quick-create-modal__panel", children: [_jsxs(Div, { className: "appkit-quick-create-modal__header", children: [_jsx(Heading, { level: 2, id: titleId, className: "appkit-quick-create-modal__title", children: title }), _jsx(Button, { variant: "ghost", size: "sm", type: "button", onClick: onCancel, "aria-label": "Close", disabled: saving, children: "\u00D7" })] }), _jsx(Div, { className: "appkit-quick-create-modal__body", children: children }), _jsxs(Div, { className: "appkit-quick-create-modal__footer", children: [fullPageHref ? (_jsx("a", { href: fullPageHref, target: "_blank", rel: "noreferrer", className: "appkit-quick-create-modal__full-link", children: "Add more details \u2192" })) : (_jsx("span", {})), _jsxs(Row, { className: "appkit-quick-create-modal__actions", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: onCancel, disabled: saving, children: cancelLabel }), _jsx(Button, { variant: "primary", type: "button", onClick: handleSave, disabled: saving || saveDisabled, isLoading: saving, children: saveLabel })] })] })] })] }), document.body);
48
+ }
@@ -0,0 +1,84 @@
1
+ .appkit-quick-create-modal {
2
+ position: fixed;
3
+ inset: 0;
4
+ z-index: var(--appkit-z-modal, 1000);
5
+ display: flex;
6
+ align-items: stretch;
7
+ justify-content: center;
8
+ }
9
+
10
+ .appkit-quick-create-modal__backdrop {
11
+ position: absolute;
12
+ inset: 0;
13
+ background: rgb(0 0 0 / 0.45);
14
+ }
15
+
16
+ .appkit-quick-create-modal__panel {
17
+ position: relative;
18
+ display: flex;
19
+ flex-direction: column;
20
+ background: var(--appkit-color-surface, #ffffff);
21
+ color: var(--appkit-color-foreground, inherit);
22
+ width: 100%;
23
+ max-width: 560px;
24
+ margin: auto;
25
+ max-height: 92vh;
26
+ border-radius: 0.75rem;
27
+ box-shadow: var(--appkit-shadow-lg, 0 20px 40px rgb(0 0 0 / 0.25));
28
+ outline: none;
29
+ }
30
+
31
+ .appkit-quick-create-modal__header {
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: space-between;
35
+ padding: 1rem 1.25rem;
36
+ border-bottom: 1px solid var(--appkit-color-border, rgb(0 0 0 / 0.1));
37
+ }
38
+
39
+ .appkit-quick-create-modal__title {
40
+ margin: 0;
41
+ font-size: 1.125rem;
42
+ font-weight: 600;
43
+ }
44
+
45
+ .appkit-quick-create-modal__body {
46
+ flex: 1 1 auto;
47
+ overflow-y: auto;
48
+ padding: 1.25rem;
49
+ }
50
+
51
+ .appkit-quick-create-modal__footer {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: space-between;
55
+ gap: 0.75rem;
56
+ padding: 1rem 1.25rem;
57
+ border-top: 1px solid var(--appkit-color-border, rgb(0 0 0 / 0.1));
58
+ }
59
+
60
+ .appkit-quick-create-modal__full-link {
61
+ font-size: 0.875rem;
62
+ color: var(--appkit-color-primary, #6366f1);
63
+ text-decoration: underline;
64
+ }
65
+
66
+ .appkit-quick-create-modal__actions {
67
+ gap: 0.5rem;
68
+ }
69
+
70
+ @media (max-width: 640px) {
71
+ .appkit-quick-create-modal {
72
+ align-items: flex-end;
73
+ }
74
+ .appkit-quick-create-modal__panel {
75
+ max-width: 100%;
76
+ margin: 0;
77
+ border-radius: 0.75rem 0.75rem 0 0;
78
+ max-height: 92vh;
79
+ }
80
+ }
81
+
82
+ [data-theme="dark"] .appkit-quick-create-modal__panel {
83
+ background: var(--appkit-color-surface-dark, #1e293b);
84
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * StickyBottomBar — fixed-bottom action bar that sits above the mobile
3
+ * BottomNavLayout (when present) and below any modals.
4
+ *
5
+ * Reads `--bottom-nav-height` written by `BottomNavLayout` (4rem when the
6
+ * navbar is rendered below `lg`, 0px otherwise). Falls back to 0px when the
7
+ * variable is unset so the bar still pins to the viewport bottom on routes
8
+ * that don't render a bottom nav.
9
+ *
10
+ * z-index sits above the navbar (`z-40`) but below modal overlays.
11
+ */
12
+ import React from "react";
13
+ export interface StickyBottomBarProps {
14
+ children: React.ReactNode;
15
+ /** Optional extra className appended to the bar wrapper. */
16
+ className?: string;
17
+ /** Hide on `lg` and up. Defaults to `true` — matches BottomNavLayout's responsive scope. */
18
+ mobileOnly?: boolean;
19
+ /** Test id passthrough. */
20
+ "data-testid"?: string;
21
+ }
22
+ export declare function StickyBottomBar({ children, className, mobileOnly, "data-testid": testId, }: StickyBottomBarProps): React.JSX.Element;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ const BAR_STYLE = {
4
+ bottom: "var(--bottom-nav-height, 0px)",
5
+ zIndex: 45,
6
+ };
7
+ export function StickyBottomBar({ children, className, mobileOnly = true, "data-testid": testId, }) {
8
+ return (_jsx("div", {
9
+ // eslint-disable-next-line lir/no-inline-static-style
10
+ style: BAR_STYLE, "data-testid": testId, className: [
11
+ "fixed left-0 right-0",
12
+ mobileOnly ? "lg:hidden" : "",
13
+ "bg-white/95 dark:bg-slate-950/95 backdrop-blur-md",
14
+ "border-t border-zinc-200 dark:border-slate-800",
15
+ "shadow-2xl pb-safe",
16
+ className ?? "",
17
+ ]
18
+ .filter(Boolean)
19
+ .join(" "), children: children }));
20
+ }
@@ -0,0 +1,11 @@
1
+ export interface VacationBannerProps {
2
+ storeName?: string;
3
+ message?: string;
4
+ returnDate?: Date | string;
5
+ className?: string;
6
+ }
7
+ /**
8
+ * S-STORE-6-A — Vacation-mode banner shown on product detail + checkout
9
+ * pages when the seller has paused new orders.
10
+ */
11
+ export declare function VacationBanner({ storeName, message, returnDate, className, }: VacationBannerProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Alert } from "./Alert";
4
+ /**
5
+ * S-STORE-6-A — Vacation-mode banner shown on product detail + checkout
6
+ * pages when the seller has paused new orders.
7
+ */
8
+ export function VacationBanner({ storeName, message, returnDate, className, }) {
9
+ const formattedDate = returnDate &&
10
+ new Date(returnDate).toLocaleDateString(undefined, {
11
+ year: "numeric",
12
+ month: "short",
13
+ day: "numeric",
14
+ });
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
+ }
@@ -50,6 +50,10 @@ export type { StatusBadgeProps, StatusBadgeStatus, BadgeOrderStatus, BadgePaymen
50
50
  export { StatusBadge } from "./components/StatusBadge";
51
51
  export type { ModalProps } from "./components/Modal";
52
52
  export { Modal, ModalFooter } from "./components/Modal";
53
+ export type { QuickCreateModalProps } from "./components/QuickCreateModal";
54
+ export { QuickCreateModal } from "./components/QuickCreateModal";
55
+ export type { VacationBannerProps } from "./components/VacationBanner";
56
+ export { VacationBanner } from "./components/VacationBanner";
53
57
  export type { UnsavedChangesModalProps, UnsavedChangesLabels, } from "./components/UnsavedChangesModal";
54
58
  export { UnsavedChangesModal } from "./components/UnsavedChangesModal";
55
59
  export type { LoginRequiredModalProps } from "./components/LoginRequiredModal";
@@ -187,6 +191,10 @@ export type { BulkActionBarProps, BulkActionBarLabels, BulkActionItem, } from ".
187
191
  export { BulkActionBar } from "./components/BulkActionBar";
188
192
  export type { BulkActionsBarProps, BulkAction } from "./components/BulkActionsBar";
189
193
  export { BulkActionsBar } from "./components/BulkActionsBar";
194
+ export type { StickyBottomBarProps } from "./components/StickyBottomBar";
195
+ export { StickyBottomBar } from "./components/StickyBottomBar";
196
+ export type { ClaimCouponButtonProps } from "./components/ClaimCouponButton";
197
+ export { ClaimCouponButton } from "./components/ClaimCouponButton";
190
198
  export type { FlowStep, FlowDiagramProps } from "./components/FlowDiagram";
191
199
  export { FlowDiagram } from "./components/FlowDiagram";
192
200
  export type { BaseListingCardRootProps, BaseListingCardHeroProps, BaseListingCardInfoProps, BaseListingCardCheckboxProps, } from "./components/BaseListingCard";
package/dist/ui/index.js CHANGED
@@ -29,6 +29,8 @@ export { Progress, IndeterminateProgress } from "./components/Progress";
29
29
  export { Pagination } from "./components/Pagination";
30
30
  export { StatusBadge } from "./components/StatusBadge";
31
31
  export { Modal, ModalFooter } from "./components/Modal";
32
+ export { QuickCreateModal } from "./components/QuickCreateModal";
33
+ export { VacationBanner } from "./components/VacationBanner";
32
34
  export { UnsavedChangesModal } from "./components/UnsavedChangesModal";
33
35
  export { LoginRequiredModal } from "./components/LoginRequiredModal";
34
36
  export { Drawer } from "./components/Drawer";
@@ -99,6 +101,8 @@ export { DetailViewShell } from "./components/DetailViewShell";
99
101
  export { StackedViewShell } from "./components/StackedViewShell";
100
102
  export { BulkActionBar } from "./components/BulkActionBar";
101
103
  export { BulkActionsBar } from "./components/BulkActionsBar";
104
+ export { StickyBottomBar } from "./components/StickyBottomBar";
105
+ export { ClaimCouponButton } from "./components/ClaimCouponButton";
102
106
  export { FlowDiagram } from "./components/FlowDiagram";
103
107
  export { BaseListingCard } from "./components/BaseListingCard";
104
108
  export { default as ImageGallery } from "./components/ImageGallery";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "2.7.49",
3
+ "version": "2.7.50",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"