vlite3 1.4.3 → 1.4.5
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/components/AppShell/AppShellLayoutStorefront.vue.js +2 -2
- package/components/AvatarUploader/AvatarUploader.vue.d.ts +2 -2
- package/components/Cart/Cart.vue.d.ts +27 -0
- package/components/Cart/Cart.vue.js +242 -0
- package/components/Cart/Cart.vue2.js +4 -0
- package/components/Cart/CartCouponInput.vue.d.ts +32 -0
- package/components/Cart/CartCouponInput.vue.js +176 -0
- package/components/Cart/CartCouponInput.vue2.js +4 -0
- package/components/Cart/CartEmptyState.vue.d.ts +17 -0
- package/components/Cart/CartEmptyState.vue.js +48 -0
- package/components/Cart/CartEmptyState.vue2.js +4 -0
- package/components/Cart/CartLineItem.vue.d.ts +29 -0
- package/components/Cart/CartLineItem.vue.js +341 -0
- package/components/Cart/CartLineItem.vue2.js +4 -0
- package/components/Cart/CartSummary.vue.d.ts +29 -0
- package/components/Cart/CartSummary.vue.js +157 -0
- package/components/Cart/CartSummary.vue2.js +4 -0
- package/components/Cart/CartVariant1.vue.d.ts +42 -0
- package/components/Cart/CartVariant1.vue.js +156 -0
- package/components/Cart/CartVariant1.vue2.js +4 -0
- package/components/Cart/CartVariant2.vue.d.ts +42 -0
- package/components/Cart/CartVariant2.vue.js +154 -0
- package/components/Cart/CartVariant2.vue2.js +4 -0
- package/components/Cart/CartVariant3.vue.d.ts +41 -0
- package/components/Cart/CartVariant3.vue.js +192 -0
- package/components/Cart/CartVariant3.vue2.js +4 -0
- package/components/Cart/CartVariant4.vue.d.ts +41 -0
- package/components/Cart/CartVariant4.vue.js +145 -0
- package/components/Cart/CartVariant4.vue2.js +4 -0
- package/components/Cart/composables/useCart.d.ts +46 -0
- package/components/Cart/composables/useCart.js +110 -0
- package/components/Cart/composables/useCartCalculation.d.ts +91 -0
- package/components/Cart/composables/useCartCalculation.js +145 -0
- package/components/Cart/index.d.ts +9 -0
- package/components/Cart/types.d.ts +391 -0
- package/components/CategoryManager/CategoryManager.vue.d.ts +2 -2
- package/components/CategoryManager/CategoryManager.vue.js +3 -3
- package/components/CategoryManager/CategoryManager.vue2.js +224 -248
- package/components/CategoryManager/utils.d.ts +3 -0
- package/components/CategoryManager/utils.js +31 -0
- package/components/CategoryMenu/CategoryMenu.vue.d.ts +2 -0
- package/components/CategoryMenu/CategoryMenu.vue.js +46 -40
- package/components/CategoryMenu/CategoryMenuVariant1.vue.d.ts +5 -1
- package/components/CategoryMenu/CategoryMenuVariant1.vue.js +5 -144
- package/components/CategoryMenu/CategoryMenuVariant1.vue2.js +220 -2
- package/components/CategoryMenu/CategoryMenuVariant2.vue.d.ts +5 -1
- package/components/CategoryMenu/CategoryMenuVariant2.vue.js +5 -160
- package/components/CategoryMenu/CategoryMenuVariant2.vue2.js +235 -2
- package/components/CategoryMenu/types.d.ts +5 -2
- package/components/Clipboard.vue.d.ts +2 -2
- package/components/Dropdown/Dropdown.vue.d.ts +1 -0
- package/components/Dropdown/Dropdown.vue.js +31 -29
- package/components/FilePicker/FilePicker.vue.d.ts +2 -2
- package/components/FilePicker/FilePicker.vue.js +278 -202
- package/components/Form/CustomFields.vue.d.ts +4 -0
- package/components/Form/CustomFields.vue.js +2 -2
- package/components/Form/CustomFields.vue2.js +349 -145
- package/components/Form/FormField.vue.d.ts +1 -1
- package/components/Form/FormField.vue.js +1 -1
- package/components/Form/types.d.ts +3 -0
- package/components/Modal.vue.d.ts +2 -0
- package/components/Modal.vue.js +1 -1
- package/components/Modal.vue2.js +30 -28
- package/components/OTPInput/OTPInput.vue.d.ts +1 -1
- package/components/Rating/Rating.vue.d.ts +1 -1
- package/components/Screen/ScreenFilter.vue.js +3 -2
- package/components/SidePanel.vue.d.ts +2 -0
- package/components/SidePanel.vue.js +1 -1
- package/components/SidePanel.vue2.js +25 -23
- package/components/SidebarMenu/SidebarMenu.vue.js +145 -128
- package/components/index.d.ts +1 -0
- package/core/config.d.ts +128 -0
- package/index.d.ts +1 -0
- package/index.js +327 -306
- package/package.json +1 -1
- package/style.css +1 -1
- package/types/config.type.d.ts +2 -0
|
@@ -10,7 +10,7 @@ import { normalizeRoutePrefix as E } from "../CategoryMenu/utils.js";
|
|
|
10
10
|
const L = { class: "vlite-app-layout flex flex-col w-full h-full min-h-0 bg-body text-foreground overflow-hidden" }, M = {
|
|
11
11
|
key: 0,
|
|
12
12
|
class: "shrink-0 w-full"
|
|
13
|
-
}, O = { class: "w-full mx-auto max-w-7xl px-3 sm:px-4 md:px-6 lg:px-8" }, A = { class: "flex items-center gap-2 min-w-0" }, U = ["aria-label"], Y = { class: "w-full
|
|
13
|
+
}, O = { class: "w-full mx-auto max-w-7xl px-3 sm:px-4 md:px-6 lg:px-8" }, A = { class: "flex items-center gap-2 min-w-0" }, U = ["aria-label"], Y = { class: "w-full min-w-0 max-w-7xl mx-auto overflow-hidden px-3 sm:px-4 md:px-6 lg:px-8" }, D = {
|
|
14
14
|
key: 0,
|
|
15
15
|
class: "shrink-0 w-full"
|
|
16
16
|
}, H = {
|
|
@@ -126,7 +126,7 @@ const L = { class: "vlite-app-layout flex flex-col w-full h-full min-h-0 bg-body
|
|
|
126
126
|
]),
|
|
127
127
|
e.$slots.categories ? (r(), t("div", {
|
|
128
128
|
key: 0,
|
|
129
|
-
class: a(["w-full border-t border-border bg-background", [s(m).desktopContent, s(l).menuClass]])
|
|
129
|
+
class: a(["w-full min-w-0 overflow-hidden border-t border-border bg-background", [s(m).desktopContent, s(l).menuClass]])
|
|
130
130
|
}, [
|
|
131
131
|
d("div", Y, [
|
|
132
132
|
o(e.$slots, "categories", { categoryRoutePrefix: h.value })
|
|
@@ -13,12 +13,12 @@ export interface Props {
|
|
|
13
13
|
className?: string;
|
|
14
14
|
}
|
|
15
15
|
declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
16
|
-
change: (value: FilePickerValue) => any;
|
|
17
16
|
error: (error: string) => any;
|
|
17
|
+
change: (value: FilePickerValue) => any;
|
|
18
18
|
"update:modelValue": (value: any) => any;
|
|
19
19
|
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
20
|
-
onChange?: (value: FilePickerValue) => any;
|
|
21
20
|
onError?: (error: string) => any;
|
|
21
|
+
onChange?: (value: FilePickerValue) => any;
|
|
22
22
|
"onUpdate:modelValue"?: (value: any) => any;
|
|
23
23
|
}>, {
|
|
24
24
|
alt: string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CartProps, CartCoupon, CartTotals } from './types';
|
|
2
|
+
declare const _default: import('vue').DefineComponent<CartProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
3
|
+
clear: () => any;
|
|
4
|
+
remove: (itemId: string | number) => any;
|
|
5
|
+
continue: () => any;
|
|
6
|
+
"update:quantity": (itemId: string | number, quantity: number) => any;
|
|
7
|
+
"continue-shopping": () => any;
|
|
8
|
+
"apply-coupon": (code: string) => any;
|
|
9
|
+
"remove-coupon": () => any;
|
|
10
|
+
"coupon-change": (code: string) => any;
|
|
11
|
+
"update:coupon": (coupon: CartCoupon) => any;
|
|
12
|
+
"update:totals": (totals: CartTotals) => any;
|
|
13
|
+
}, string, import('vue').PublicProps, Readonly<CartProps> & Readonly<{
|
|
14
|
+
onClear?: () => any;
|
|
15
|
+
onRemove?: (itemId: string | number) => any;
|
|
16
|
+
onContinue?: () => any;
|
|
17
|
+
"onUpdate:quantity"?: (itemId: string | number, quantity: number) => any;
|
|
18
|
+
"onContinue-shopping"?: () => any;
|
|
19
|
+
"onApply-coupon"?: (code: string) => any;
|
|
20
|
+
"onRemove-coupon"?: () => any;
|
|
21
|
+
"onCoupon-change"?: (code: string) => any;
|
|
22
|
+
"onUpdate:coupon"?: (coupon: CartCoupon) => any;
|
|
23
|
+
"onUpdate:totals"?: (totals: CartTotals) => any;
|
|
24
|
+
}>, {
|
|
25
|
+
variant: import('./types').CartVariant;
|
|
26
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
27
|
+
export default _default;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { defineComponent as N, computed as s, ref as R, watch as f, openBlock as Q, createBlock as U, resolveDynamicComponent as F } from "vue";
|
|
2
|
+
import { getComponentConfig as P } from "../../utils/configUtils.js";
|
|
3
|
+
import { calculateCartTotals as z } from "./composables/useCartCalculation.js";
|
|
4
|
+
import H from "./CartVariant1.vue.js";
|
|
5
|
+
import L from "./CartVariant2.vue.js";
|
|
6
|
+
import j from "./CartVariant3.vue.js";
|
|
7
|
+
import E from "./CartVariant4.vue.js";
|
|
8
|
+
const Y = /* @__PURE__ */ N({
|
|
9
|
+
__name: "Cart",
|
|
10
|
+
props: {
|
|
11
|
+
data: {},
|
|
12
|
+
variant: { default: "Variant1" },
|
|
13
|
+
actions: {},
|
|
14
|
+
features: {},
|
|
15
|
+
labels: {},
|
|
16
|
+
containerClass: {},
|
|
17
|
+
validateCoupon: {}
|
|
18
|
+
},
|
|
19
|
+
emits: ["update:quantity", "remove", "clear", "apply-coupon", "remove-coupon", "coupon-change", "continue", "continue-shopping", "update:coupon", "update:totals"],
|
|
20
|
+
setup(v, { emit: C }) {
|
|
21
|
+
const t = v, o = C, c = P("cart") || {}, g = s(() => {
|
|
22
|
+
switch (t.variant ?? c.variant ?? "Variant1") {
|
|
23
|
+
case "Variant2":
|
|
24
|
+
return L;
|
|
25
|
+
case "Variant3":
|
|
26
|
+
return j;
|
|
27
|
+
case "Variant4":
|
|
28
|
+
return E;
|
|
29
|
+
default:
|
|
30
|
+
return H;
|
|
31
|
+
}
|
|
32
|
+
}), h = s(() => {
|
|
33
|
+
const e = {
|
|
34
|
+
editableQuantity: !0,
|
|
35
|
+
removable: !0,
|
|
36
|
+
clearable: !0,
|
|
37
|
+
coupon: !0,
|
|
38
|
+
subtotal: !0,
|
|
39
|
+
discount: !0,
|
|
40
|
+
estimatedTax: !0,
|
|
41
|
+
shipping: !0,
|
|
42
|
+
totalSavings: !0,
|
|
43
|
+
continue: !0,
|
|
44
|
+
continueShopping: !0,
|
|
45
|
+
thumbnails: !0,
|
|
46
|
+
description: !0,
|
|
47
|
+
sku: !0,
|
|
48
|
+
itemVariant: !0,
|
|
49
|
+
emptyState: !0,
|
|
50
|
+
trustSignals: !0
|
|
51
|
+
}, n = c.features ?? {}, u = t.features ?? {}, i = t.data?.readonly ? { editableQuantity: !1, removable: !1, clearable: !1, coupon: !1 } : {};
|
|
52
|
+
return { ...e, ...n, ...u, ...i };
|
|
53
|
+
}), y = s(() => ({
|
|
54
|
+
showContinue: !0,
|
|
55
|
+
showContinueShopping: !0,
|
|
56
|
+
continueDisabled: !1,
|
|
57
|
+
continueShoppingDisabled: !1,
|
|
58
|
+
...c.actions ?? {},
|
|
59
|
+
...t.actions ?? {}
|
|
60
|
+
})), r = R(null), p = s(() => r.value ?? t.data.coupon), d = s(() => z({
|
|
61
|
+
items: t.data.items || [],
|
|
62
|
+
tax: t.data.tax,
|
|
63
|
+
shipping: t.data.shipping,
|
|
64
|
+
coupon: p.value,
|
|
65
|
+
currency: t.data.currency
|
|
66
|
+
}).totals);
|
|
67
|
+
s(() => t.data.totals === void 0);
|
|
68
|
+
const m = s(() => t.data.totals ? t.data.totals : d.value);
|
|
69
|
+
f(
|
|
70
|
+
m,
|
|
71
|
+
(e) => o("update:totals", e),
|
|
72
|
+
{ deep: !0 }
|
|
73
|
+
);
|
|
74
|
+
const b = s(
|
|
75
|
+
() => !!t.validateCoupon || !!t.data.coupons?.length
|
|
76
|
+
);
|
|
77
|
+
f(
|
|
78
|
+
() => t.data.coupon,
|
|
79
|
+
(e) => {
|
|
80
|
+
e && r.value && e.code === r.value.code ? r.value = null : e || (r.value = null);
|
|
81
|
+
},
|
|
82
|
+
{ deep: !0 }
|
|
83
|
+
);
|
|
84
|
+
async function k(e) {
|
|
85
|
+
const n = e.trim().toUpperCase(), u = d.value.subtotal, i = t.data.currency;
|
|
86
|
+
if (t.data.coupons?.length) {
|
|
87
|
+
const a = t.data.coupons.find(
|
|
88
|
+
(l) => l.code.trim().toUpperCase() === n
|
|
89
|
+
);
|
|
90
|
+
if (!a)
|
|
91
|
+
return {
|
|
92
|
+
ok: !1,
|
|
93
|
+
coupon: {
|
|
94
|
+
code: e,
|
|
95
|
+
state: "invalid",
|
|
96
|
+
message: `Coupon code "${e}" is not recognised.`
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
if (a.expiresAt) {
|
|
100
|
+
const l = a.expiresAt instanceof Date ? a.expiresAt : new Date(a.expiresAt);
|
|
101
|
+
if (!Number.isNaN(l.getTime()) && l.getTime() < Date.now())
|
|
102
|
+
return {
|
|
103
|
+
ok: !1,
|
|
104
|
+
coupon: {
|
|
105
|
+
code: e,
|
|
106
|
+
state: "expired",
|
|
107
|
+
message: `Coupon "${e}" expired on ${l.toLocaleDateString()}.`
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return a.minSubtotal !== void 0 && u < a.minSubtotal ? {
|
|
112
|
+
ok: !1,
|
|
113
|
+
coupon: {
|
|
114
|
+
code: e,
|
|
115
|
+
state: "error",
|
|
116
|
+
message: `Add ${(a.minSubtotal - u).toFixed(2)} more to use "${e}".`
|
|
117
|
+
}
|
|
118
|
+
} : a.minItems !== void 0 && (t.data.items || []).reduce(
|
|
119
|
+
(B, I) => B + (I.quantity || 0),
|
|
120
|
+
0
|
|
121
|
+
) < a.minItems ? {
|
|
122
|
+
ok: !1,
|
|
123
|
+
coupon: {
|
|
124
|
+
code: e,
|
|
125
|
+
state: "error",
|
|
126
|
+
message: `"${e}" requires at least ${a.minItems} items.`
|
|
127
|
+
}
|
|
128
|
+
} : a.currency && i && a.currency !== i ? {
|
|
129
|
+
ok: !1,
|
|
130
|
+
coupon: {
|
|
131
|
+
code: e,
|
|
132
|
+
state: "error",
|
|
133
|
+
message: `"${e}" is only valid for ${a.currency} orders.`
|
|
134
|
+
}
|
|
135
|
+
} : { ok: !0, definition: a };
|
|
136
|
+
}
|
|
137
|
+
if (t.validateCoupon)
|
|
138
|
+
try {
|
|
139
|
+
const a = await t.validateCoupon(e, {
|
|
140
|
+
subtotal: u,
|
|
141
|
+
currency: i,
|
|
142
|
+
items: t.data.items || []
|
|
143
|
+
});
|
|
144
|
+
return a ? "type" in a ? { ok: !0, definition: a } : {
|
|
145
|
+
ok: !1,
|
|
146
|
+
coupon: {
|
|
147
|
+
code: e,
|
|
148
|
+
state: a.state || "error",
|
|
149
|
+
message: a.message
|
|
150
|
+
}
|
|
151
|
+
} : {
|
|
152
|
+
ok: !1,
|
|
153
|
+
coupon: {
|
|
154
|
+
code: e,
|
|
155
|
+
state: "invalid",
|
|
156
|
+
message: `Coupon code "${e}" is not recognised.`
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
} catch (a) {
|
|
160
|
+
return {
|
|
161
|
+
ok: !1,
|
|
162
|
+
coupon: {
|
|
163
|
+
code: e,
|
|
164
|
+
state: "error",
|
|
165
|
+
message: a?.message || `Could not validate "${e}". Please try again.`
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
ok: !1,
|
|
171
|
+
coupon: { code: e, state: "error", message: "No coupon validator configured." }
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function x(e, n) {
|
|
175
|
+
return {
|
|
176
|
+
code: n.code,
|
|
177
|
+
description: n.description,
|
|
178
|
+
state: "applied",
|
|
179
|
+
definition: n,
|
|
180
|
+
expiresAt: n.expiresAt
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function $(e, n) {
|
|
184
|
+
o("update:quantity", e, n);
|
|
185
|
+
}
|
|
186
|
+
function _(e) {
|
|
187
|
+
o("remove", e);
|
|
188
|
+
}
|
|
189
|
+
function S() {
|
|
190
|
+
o("clear");
|
|
191
|
+
}
|
|
192
|
+
async function A(e) {
|
|
193
|
+
if (o("apply-coupon", e), !b.value)
|
|
194
|
+
return;
|
|
195
|
+
const n = e.trim();
|
|
196
|
+
r.value = { code: n, state: "applying" }, t.validateCoupon || await new Promise((i) => setTimeout(i, 120));
|
|
197
|
+
const u = await k(n);
|
|
198
|
+
if (u.ok === !0) {
|
|
199
|
+
const i = x(n, u.definition);
|
|
200
|
+
r.value = null, o("update:coupon", i);
|
|
201
|
+
} else
|
|
202
|
+
r.value = null, o("update:coupon", u.coupon);
|
|
203
|
+
}
|
|
204
|
+
function w() {
|
|
205
|
+
r.value = null, o("update:coupon", null), o("remove-coupon");
|
|
206
|
+
}
|
|
207
|
+
function V(e) {
|
|
208
|
+
o("coupon-change", e);
|
|
209
|
+
}
|
|
210
|
+
function D() {
|
|
211
|
+
o("continue");
|
|
212
|
+
}
|
|
213
|
+
function T() {
|
|
214
|
+
o("continue-shopping");
|
|
215
|
+
}
|
|
216
|
+
const q = s(() => ({
|
|
217
|
+
...t.data,
|
|
218
|
+
items: t.data.items || [],
|
|
219
|
+
totals: m.value,
|
|
220
|
+
coupon: p.value
|
|
221
|
+
}));
|
|
222
|
+
return (e, n) => (Q(), U(F(g.value), {
|
|
223
|
+
data: q.value,
|
|
224
|
+
variant: t.variant,
|
|
225
|
+
actions: y.value,
|
|
226
|
+
features: h.value,
|
|
227
|
+
labels: t.labels,
|
|
228
|
+
"container-class": t.containerClass,
|
|
229
|
+
"onUpdate:quantity": $,
|
|
230
|
+
onRemove: _,
|
|
231
|
+
onClear: S,
|
|
232
|
+
onApplyCoupon: A,
|
|
233
|
+
onRemoveCoupon: w,
|
|
234
|
+
onCouponChange: V,
|
|
235
|
+
onContinue: D,
|
|
236
|
+
onContinueShopping: T
|
|
237
|
+
}, null, 40, ["data", "variant", "actions", "features", "labels", "container-class"]));
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
export {
|
|
241
|
+
Y as default
|
|
242
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CartCoupon, CartLabels } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Coupon field with all UX states modelled as a discriminated union.
|
|
4
|
+
*
|
|
5
|
+
* - idle → empty input, no validation feedback
|
|
6
|
+
* - applying → request in flight (spinner, input + button disabled)
|
|
7
|
+
* - applied → success state, shows remove action and discount summary
|
|
8
|
+
* - invalid → code not recognised (red border + helper text)
|
|
9
|
+
* - expired → coupon no longer valid (amber border + helper text)
|
|
10
|
+
* - error → generic API error, uses `coupon.message` for helper text
|
|
11
|
+
*
|
|
12
|
+
* The parent owns validation logic; the component only renders.
|
|
13
|
+
*/
|
|
14
|
+
type __VLS_Props = {
|
|
15
|
+
coupon?: CartCoupon;
|
|
16
|
+
labels: CartLabels;
|
|
17
|
+
compact?: boolean;
|
|
18
|
+
readonly?: boolean;
|
|
19
|
+
};
|
|
20
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
21
|
+
remove: () => any;
|
|
22
|
+
apply: (code: string) => any;
|
|
23
|
+
change: (code: string) => any;
|
|
24
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
25
|
+
onRemove?: () => any;
|
|
26
|
+
onApply?: (code: string) => any;
|
|
27
|
+
onChange?: (code: string) => any;
|
|
28
|
+
}>, {
|
|
29
|
+
compact: boolean;
|
|
30
|
+
readonly: boolean;
|
|
31
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
32
|
+
export default _default;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { defineComponent as S, computed as t, ref as K, watch as D, openBlock as a, createElementBlock as i, normalizeClass as n, createElementVNode as p, createVNode as u, withKeys as L, createSlots as M, withCtx as T, createTextVNode as x, toDisplayString as f, createCommentVNode as r, unref as z, createBlock as R } from "vue";
|
|
2
|
+
import C from "../Icon.vue.js";
|
|
3
|
+
import U from "../Input.vue.js";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import B from "../Button.vue.js";
|
|
6
|
+
import E from "../Price/Price.vue.js";
|
|
7
|
+
const W = { class: "flex-1 min-w-0" }, q = { class: "flex items-center gap-2 min-w-0 flex-1" }, F = { class: "shrink-0 inline-flex items-center justify-center w-7 h-7 rounded-full bg-success text-success-fg" }, G = { class: "min-w-0 flex-1" }, H = { class: "flex items-center gap-1.5 flex-wrap" }, _ = /* @__PURE__ */ S({
|
|
8
|
+
__name: "CartCouponInput",
|
|
9
|
+
props: {
|
|
10
|
+
coupon: {},
|
|
11
|
+
labels: {},
|
|
12
|
+
compact: { type: Boolean, default: !1 },
|
|
13
|
+
readonly: { type: Boolean, default: !1 }
|
|
14
|
+
},
|
|
15
|
+
emits: ["apply", "remove", "change"],
|
|
16
|
+
setup(e, { emit: N }) {
|
|
17
|
+
const c = e, g = N, m = t(() => c.labels || {}), o = K(c.coupon?.code ?? "");
|
|
18
|
+
D(
|
|
19
|
+
() => c.coupon?.code,
|
|
20
|
+
(l) => {
|
|
21
|
+
l !== void 0 && l !== o.value && (o.value = l);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
const v = t(() => c.coupon?.state ?? "idle"), h = t(() => v.value === "applied"), A = t(() => v.value === "applying"), b = t(() => v.value === "invalid"), y = t(() => v.value === "expired"), k = t(() => v.value === "error"), I = t(() => A.value || h.value || c.readonly), w = t(() => b.value ? c.coupon?.message || "Invalid coupon code. Please try again." : y.value ? c.coupon?.message || "This coupon has expired and can no longer be applied." : k.value ? c.coupon?.message || "We could not apply this coupon. Please try again." : ""), s = t(() => b.value ? {
|
|
25
|
+
rightIcon: "lucide:circle-x",
|
|
26
|
+
borderClass: "border-danger focus-within:border-danger",
|
|
27
|
+
helperClass: "text-danger",
|
|
28
|
+
helperText: w.value
|
|
29
|
+
} : y.value ? {
|
|
30
|
+
rightIcon: "lucide:clock-alert",
|
|
31
|
+
borderClass: "border-warning focus-within:border-warning",
|
|
32
|
+
helperClass: "text-warning",
|
|
33
|
+
helperText: w.value
|
|
34
|
+
} : k.value ? {
|
|
35
|
+
rightIcon: "lucide:triangle-alert",
|
|
36
|
+
borderClass: "border-danger focus-within:border-danger",
|
|
37
|
+
helperClass: "text-danger",
|
|
38
|
+
helperText: w.value
|
|
39
|
+
} : null);
|
|
40
|
+
function $(l) {
|
|
41
|
+
o.value = String(l), g("change", o.value);
|
|
42
|
+
}
|
|
43
|
+
function V() {
|
|
44
|
+
const l = o.value.trim();
|
|
45
|
+
l && g("apply", l);
|
|
46
|
+
}
|
|
47
|
+
function j() {
|
|
48
|
+
o.value = "", g("remove");
|
|
49
|
+
}
|
|
50
|
+
return (l, d) => (a(), i("div", {
|
|
51
|
+
class: n(["v-cart-coupon w-full", e.compact ? "space-y-1.5" : "space-y-2"])
|
|
52
|
+
}, [
|
|
53
|
+
h.value ? r("", !0) : (a(), i("div", {
|
|
54
|
+
key: 0,
|
|
55
|
+
class: n(["flex items-center gap-2", e.compact ? "flex-col items-stretch gap-1.5" : "flex-col sm:flex-row sm:items-stretch"])
|
|
56
|
+
}, [
|
|
57
|
+
p("div", W, [
|
|
58
|
+
u(U, {
|
|
59
|
+
modelValue: o.value,
|
|
60
|
+
"onUpdate:modelValue": [
|
|
61
|
+
d[0] || (d[0] = (P) => o.value = P),
|
|
62
|
+
$
|
|
63
|
+
],
|
|
64
|
+
placeholder: m.value.couponPlaceholder || "Enter coupon code",
|
|
65
|
+
icon: "lucide:ticket-percent",
|
|
66
|
+
"input-class": s.value ? s.value.borderClass : "",
|
|
67
|
+
disabled: I.value,
|
|
68
|
+
readonly: e.readonly,
|
|
69
|
+
"show-clear-button": !1,
|
|
70
|
+
size: "md",
|
|
71
|
+
rounded: "md",
|
|
72
|
+
"aria-label": m.value.coupon || "Coupon code",
|
|
73
|
+
onKeyup: L(V, ["enter"])
|
|
74
|
+
}, M({ _: 2 }, [
|
|
75
|
+
s.value ? {
|
|
76
|
+
name: "addon-right",
|
|
77
|
+
fn: T(() => [
|
|
78
|
+
u(C, {
|
|
79
|
+
icon: s.value.rightIcon,
|
|
80
|
+
class: n([
|
|
81
|
+
"h-4 w-4",
|
|
82
|
+
b.value || k.value ? "text-danger" : y.value ? "text-warning" : ""
|
|
83
|
+
])
|
|
84
|
+
}, null, 8, ["icon", "class"])
|
|
85
|
+
]),
|
|
86
|
+
key: "0"
|
|
87
|
+
} : void 0
|
|
88
|
+
]), 1032, ["modelValue", "placeholder", "input-class", "disabled", "readonly", "aria-label"])
|
|
89
|
+
]),
|
|
90
|
+
u(B, {
|
|
91
|
+
variant: "primary",
|
|
92
|
+
size: "md",
|
|
93
|
+
loading: A.value,
|
|
94
|
+
disabled: !o.value.trim() || I.value,
|
|
95
|
+
"aria-label": m.value.applyCoupon || "Apply coupon",
|
|
96
|
+
class: "shrink-0",
|
|
97
|
+
onClick: V
|
|
98
|
+
}, {
|
|
99
|
+
default: T(() => [
|
|
100
|
+
x(f(m.value.applyCoupon || "Apply"), 1)
|
|
101
|
+
]),
|
|
102
|
+
_: 1
|
|
103
|
+
}, 8, ["loading", "disabled", "aria-label"])
|
|
104
|
+
], 2)),
|
|
105
|
+
s.value && !e.compact ? (a(), i("p", {
|
|
106
|
+
key: 1,
|
|
107
|
+
class: n(["text-xs font-medium flex items-center gap-1.5", s.value.helperClass])
|
|
108
|
+
}, [
|
|
109
|
+
u(C, {
|
|
110
|
+
icon: s.value.rightIcon,
|
|
111
|
+
class: "w-3.5 h-3.5 shrink-0"
|
|
112
|
+
}, null, 8, ["icon"]),
|
|
113
|
+
x(" " + f(s.value.helperText), 1)
|
|
114
|
+
], 2)) : r("", !0),
|
|
115
|
+
h.value && e.coupon ? (a(), i("div", {
|
|
116
|
+
key: 2,
|
|
117
|
+
class: n(["flex items-center justify-between gap-2 rounded-md border border-success/40 bg-success-light/40 p-2.5", e.compact ? "p-2" : "p-2.5"])
|
|
118
|
+
}, [
|
|
119
|
+
p("div", q, [
|
|
120
|
+
p("div", F, [
|
|
121
|
+
u(C, {
|
|
122
|
+
icon: "lucide:check",
|
|
123
|
+
class: "w-4 h-4"
|
|
124
|
+
})
|
|
125
|
+
]),
|
|
126
|
+
p("div", G, [
|
|
127
|
+
p("div", H, [
|
|
128
|
+
p("p", {
|
|
129
|
+
class: n(["font-bold text-foreground uppercase tracking-wider", e.compact ? "text-[10px]" : "text-xs"])
|
|
130
|
+
}, f(e.coupon.code), 3),
|
|
131
|
+
e.coupon.definition?.type === "percentage" ? (a(), i("span", {
|
|
132
|
+
key: 0,
|
|
133
|
+
class: n(["inline-flex items-center px-1.5 py-0.5 rounded bg-success/30 text-success font-bold tabular-nums", e.compact ? "text-[9px]" : "text-[10px]"])
|
|
134
|
+
}, " −" + f(e.coupon.definition.value) + "% ", 3)) : e.coupon.discountAmount && e.coupon.discountAmount > 0 ? (a(), i("span", {
|
|
135
|
+
key: 1,
|
|
136
|
+
class: n(["inline-flex items-center px-1.5 py-0.5 rounded bg-success/10 text-success font-bold", e.compact ? "text-[9px]" : "text-[10px]"])
|
|
137
|
+
}, [
|
|
138
|
+
d[1] || (d[1] = x(" −", -1)),
|
|
139
|
+
u(z(E), {
|
|
140
|
+
value: e.coupon.discountAmount,
|
|
141
|
+
class: "text-success"
|
|
142
|
+
}, null, 8, ["value"])
|
|
143
|
+
], 2)) : r("", !0),
|
|
144
|
+
e.coupon.definition?.type === "percentage" && e.coupon.discountAmount && e.coupon.discountAmount > 0 ? (a(), i("span", {
|
|
145
|
+
key: 2,
|
|
146
|
+
class: n(["inline-flex items-center px-1.5 py-0.5 rounded bg-success/5 text-success font-semibold", e.compact ? "text-[9px]" : "text-[10px]"])
|
|
147
|
+
}, [
|
|
148
|
+
u(z(E), {
|
|
149
|
+
value: e.coupon.discountAmount,
|
|
150
|
+
class: "text-success"
|
|
151
|
+
}, null, 8, ["value"]),
|
|
152
|
+
d[2] || (d[2] = x(" off ", -1))
|
|
153
|
+
], 2)) : r("", !0)
|
|
154
|
+
]),
|
|
155
|
+
e.coupon.description ? (a(), i("p", {
|
|
156
|
+
key: 0,
|
|
157
|
+
class: n(["text-muted-foreground leading-snug truncate", e.compact ? "text-[10px] mt-0.5" : "text-xs mt-0.5"])
|
|
158
|
+
}, f(e.coupon.description), 3)) : r("", !0)
|
|
159
|
+
])
|
|
160
|
+
]),
|
|
161
|
+
e.readonly ? r("", !0) : (a(), R(B, {
|
|
162
|
+
key: 0,
|
|
163
|
+
variant: "ghost",
|
|
164
|
+
size: e.compact ? "xs" : "sm",
|
|
165
|
+
icon: "lucide:x",
|
|
166
|
+
class: "shrink-0 inline-flex items-center justify-center rounded-md text-muted-foreground hover:bg-success/20 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
167
|
+
"aria-label": m.value.removeCoupon || "Remove coupon",
|
|
168
|
+
onClick: j
|
|
169
|
+
}, null, 8, ["size", "aria-label"]))
|
|
170
|
+
], 2)) : r("", !0)
|
|
171
|
+
], 2));
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
export {
|
|
175
|
+
_ as default
|
|
176
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CartLabels } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Empty-cart state, rendered when items.length === 0 (and features.emptyState).
|
|
4
|
+
* Same look across all variants; the parent controls size via `compact`.
|
|
5
|
+
*/
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
labels: CartLabels;
|
|
8
|
+
compact?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
11
|
+
"continue-shopping": () => any;
|
|
12
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
13
|
+
"onContinue-shopping"?: () => any;
|
|
14
|
+
}>, {
|
|
15
|
+
compact: boolean;
|
|
16
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defineComponent as r, computed as p, openBlock as u, createElementBlock as d, normalizeClass as t, createElementVNode as o, createVNode as s, toDisplayString as n, withCtx as f, createTextVNode as x } from "vue";
|
|
2
|
+
import y from "../Icon.vue.js";
|
|
3
|
+
import g from "../Button.vue.js";
|
|
4
|
+
const h = { class: "space-y-1" }, z = /* @__PURE__ */ r({
|
|
5
|
+
__name: "CartEmptyState",
|
|
6
|
+
props: {
|
|
7
|
+
labels: {},
|
|
8
|
+
compact: { type: Boolean, default: !1 }
|
|
9
|
+
},
|
|
10
|
+
emits: ["continue-shopping"],
|
|
11
|
+
setup(e, { emit: i }) {
|
|
12
|
+
const m = e, l = i, c = p(() => m.labels || {});
|
|
13
|
+
return (v, a) => (u(), d("div", {
|
|
14
|
+
class: t(["v-cart-empty flex flex-col items-center justify-center text-center", e.compact ? "py-10 px-4 gap-3" : "py-16 px-6 gap-4"])
|
|
15
|
+
}, [
|
|
16
|
+
o("div", {
|
|
17
|
+
class: t(["inline-flex items-center justify-center rounded-full bg-muted text-muted-foreground", e.compact ? "w-14 h-14" : "w-20 h-20"])
|
|
18
|
+
}, [
|
|
19
|
+
s(y, {
|
|
20
|
+
icon: "lucide:shopping-bag",
|
|
21
|
+
class: t(e.compact ? "w-6 h-6" : "w-9 h-9")
|
|
22
|
+
}, null, 8, ["class"])
|
|
23
|
+
], 2),
|
|
24
|
+
o("div", h, [
|
|
25
|
+
o("p", {
|
|
26
|
+
class: t(["font-bold text-foreground", e.compact ? "text-sm" : "text-lg"])
|
|
27
|
+
}, n(c.value.emptyTitle || "Your cart is empty"), 3),
|
|
28
|
+
o("p", {
|
|
29
|
+
class: t(["text-muted-foreground max-w-xs", e.compact ? "text-xs" : "text-sm"])
|
|
30
|
+
}, n(c.value.emptyDescription || "Add items to your cart to see them here."), 3)
|
|
31
|
+
]),
|
|
32
|
+
s(g, {
|
|
33
|
+
variant: "primary",
|
|
34
|
+
size: e.compact ? "sm" : "md",
|
|
35
|
+
icon: "lucide:arrow-left",
|
|
36
|
+
onClick: a[0] || (a[0] = (w) => l("continue-shopping"))
|
|
37
|
+
}, {
|
|
38
|
+
default: f(() => [
|
|
39
|
+
x(n(c.value.emptyAction || "Continue shopping"), 1)
|
|
40
|
+
]),
|
|
41
|
+
_: 1
|
|
42
|
+
}, 8, ["size"])
|
|
43
|
+
], 2));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
export {
|
|
47
|
+
z as default
|
|
48
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CartItem, CartFeatures, CartLabels } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Internal layout hints — passed by the variant parent to switch presentation.
|
|
4
|
+
* - 'drawer' : full image, name, sku, variant, qty stepper, price, remove
|
|
5
|
+
* - 'compact': no image, dense single-line per item (POS / register)
|
|
6
|
+
* - 'card' : image + name + variant stacked, controls in a row below
|
|
7
|
+
* - 'mini' : single line, name, qty, price; minimal controls
|
|
8
|
+
*/
|
|
9
|
+
type Layout = 'drawer' | 'compact' | 'card' | 'mini';
|
|
10
|
+
type __VLS_Props = {
|
|
11
|
+
item: CartItem;
|
|
12
|
+
features: CartFeatures;
|
|
13
|
+
labels: CartLabels;
|
|
14
|
+
compact?: boolean;
|
|
15
|
+
readonly?: boolean;
|
|
16
|
+
layout?: Layout;
|
|
17
|
+
};
|
|
18
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
19
|
+
remove: (itemId: string | number) => any;
|
|
20
|
+
"update:quantity": (itemId: string | number, quantity: number) => any;
|
|
21
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
|
+
onRemove?: (itemId: string | number) => any;
|
|
23
|
+
"onUpdate:quantity"?: (itemId: string | number, quantity: number) => any;
|
|
24
|
+
}>, {
|
|
25
|
+
compact: boolean;
|
|
26
|
+
readonly: boolean;
|
|
27
|
+
layout: Layout;
|
|
28
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
29
|
+
export default _default;
|