@snacky/ui 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -3
- package/README.md +3 -2
- package/dist/index.cjs +151 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +75 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +150 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ How `@snacky/ui` got to its current state. The README documents what the
|
|
|
4
4
|
package *is*; this documents how it got there, including the mistakes, so the
|
|
5
5
|
verification claims in the README can be taken at face value.
|
|
6
6
|
|
|
7
|
+
## ProductGroupSection, and a mouse-draggable product row (0.13.0)
|
|
8
|
+
|
|
9
|
+
`ProductGroupSection` is a titled group of list `ProductCard`s with
|
|
10
|
+
`layout="horizontal" | "banner" | "grid"`. It packages three variants of Figma's
|
|
11
|
+
Section set (`Group-Products-Horizontal`, `-Banner`, `-vertical`), which between
|
|
12
|
+
them have 8 instances across the Home and product detail screens.
|
|
13
|
+
|
|
14
|
+
The reason it exists is that `Section` is a shell: a title, an optional see-more
|
|
15
|
+
chevron, and `children`. Those three variants were never props on it, so every
|
|
16
|
+
use meant rebuilding the same things by hand, and a design agent working from the
|
|
17
|
+
package had to improvise them: the trailing "See other products" card (which
|
|
18
|
+
Figma also draws by hand, twice), a row that runs out to the screen's right edge,
|
|
19
|
+
and for the banner variant, zero side padding plus a full-bleed banner with the
|
|
20
|
+
row laid over it from x160. The component carries all of that:
|
|
21
|
+
|
|
22
|
+
- `onSeeMore` shows the header chevron and, in the two scrolling layouts, the
|
|
23
|
+
trailing card (`seeMoreLabel` defaults to "See other products").
|
|
24
|
+
- `banner` is required for `layout="banner"`, normally a `SquareBanner`. The row
|
|
25
|
+
spans the full width with its first card at x160, so scrolling carries the cards
|
|
26
|
+
over the banner while the banner stays put.
|
|
27
|
+
- Rows scroll by touch and trackpad natively, and by mouse drag. The pointer is
|
|
28
|
+
captured only after a 4px move, so a tap on a card's cart button still lands.
|
|
29
|
+
|
|
30
|
+
Heights match the Figma nodes: 372 horizontal, 396 banner, 1278 for a grid of
|
|
31
|
+
eight cards. `Section` itself is unchanged; the order-screen Section variants have
|
|
32
|
+
no instances in Figma and stay compositions inside it.
|
|
33
|
+
|
|
34
|
+
compose-ui ships the same as `SnackyProductGroupSection` with
|
|
35
|
+
`ProductGroupLayout.Horizontal | Banner | Grid` in `compose-v2.3.0`, where the
|
|
36
|
+
banner is an image slot like the rest of the Banner family. `SnackySection`'s
|
|
37
|
+
header is now a shared internal `SnackySectionHeader`; its public API is
|
|
38
|
+
unchanged. Additive on both sides.
|
|
39
|
+
|
|
7
40
|
## The solid address icon (0.12.0)
|
|
8
41
|
|
|
9
42
|
`SnackyIcons.solid.address` is new: the filled map marker, added to Figma's
|
|
@@ -23,9 +56,10 @@ compose-ui ships the same icon as `SnackyIcons.Solid.Address` in
|
|
|
23
56
|
`SnackyTypographyToken.toTextStyle(color, fontFamily)`. compose-ui's type tokens
|
|
24
57
|
are raw values rather than `TextStyle`s (the package ships no font), and nothing
|
|
25
58
|
turned one into the other, so every component built the style by hand and 58 of
|
|
26
|
-
the docs site's Kotlin samples
|
|
27
|
-
that
|
|
28
|
-
|
|
59
|
+
the docs site's Kotlin samples were broken or incomplete: 24 called a
|
|
60
|
+
`toTextStyle()` that only existed as a helper the Foundations page told you to
|
|
61
|
+
paste in yourself, and the rest used flat names like
|
|
62
|
+
`SnackyTypography.smallRegular` that never existed at all. Those samples now use
|
|
29
63
|
`SnackyTypography.Small.regular.toTextStyle()`. The React samples had the same
|
|
30
64
|
flat-name problem (`typography.smallRegular`, 43 places) against an export that
|
|
31
65
|
is nested (`typography.small.regular`), and are fixed the same way. Additive on
|
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ placeholder artwork rather than a real icon prop. Apply your own
|
|
|
121
121
|
|
|
122
122
|
## What's here
|
|
123
123
|
|
|
124
|
-
All
|
|
124
|
+
All 26 documented components, matching the real Figma-sourced spec values
|
|
125
125
|
(padding, colors, radius, states - all sourced directly from the design
|
|
126
126
|
tokens, not eyeballed):
|
|
127
127
|
|
|
@@ -130,7 +130,8 @@ OtpField, CopyField, ChatInput, AddressResult), Chips (ProductChip/FilterChip),
|
|
|
130
130
|
RadioOption, Checkbox, Toggle, NavBar, TabRow, Header, PageIndicator, Banner
|
|
131
131
|
family, Badge family,
|
|
132
132
|
Callout, List (OrderListItem/NotificationListItem), Accordion, BottomSheet
|
|
133
|
-
(the shared Modal shell), Section (the shared content-block shell),
|
|
133
|
+
(the shared Modal shell), Section (the shared content-block shell),
|
|
134
|
+
ProductGroupSection (titled product rows and grids), Avatar,
|
|
134
135
|
Illustration, ProductImage, ProductCard.
|
|
135
136
|
|
|
136
137
|
Plus the icon set, as `SnackyIcons.outline.*` and `SnackyIcons.solid.*` (42
|
package/dist/index.cjs
CHANGED
|
@@ -49,6 +49,7 @@ __export(index_exports, {
|
|
|
49
49
|
PointBalanceBanner: () => PointBalanceBanner,
|
|
50
50
|
ProductCard: () => ProductCard,
|
|
51
51
|
ProductChip: () => ProductChip,
|
|
52
|
+
ProductGroupSection: () => ProductGroupSection,
|
|
52
53
|
ProductImage: () => ProductImage,
|
|
53
54
|
RadioOption: () => RadioOption,
|
|
54
55
|
SearchField: () => SearchField,
|
|
@@ -1067,18 +1068,102 @@ function Section({ title, onAction, children, className }) {
|
|
|
1067
1068
|
] });
|
|
1068
1069
|
}
|
|
1069
1070
|
|
|
1070
|
-
// src/components/
|
|
1071
|
+
// src/components/ProductGroupSection/ProductGroupSection.tsx
|
|
1072
|
+
var import_react12 = require("react");
|
|
1071
1073
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1074
|
+
function ProductGroupSection({
|
|
1075
|
+
title,
|
|
1076
|
+
layout,
|
|
1077
|
+
children,
|
|
1078
|
+
onSeeMore,
|
|
1079
|
+
seeMoreLabel = "See other products",
|
|
1080
|
+
banner,
|
|
1081
|
+
className
|
|
1082
|
+
}) {
|
|
1083
|
+
const drag = useDragScroll();
|
|
1084
|
+
const seeMore = onSeeMore && layout !== "grid" && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "snacky-product-group__see-more", children: [
|
|
1085
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(IconButton, { size: "small", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(angleSmallRight, {}), onClick: onSeeMore, ariaLabel: seeMoreLabel }),
|
|
1086
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "snacky-product-group__see-more-label", children: seeMoreLabel })
|
|
1087
|
+
] });
|
|
1088
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1089
|
+
Section,
|
|
1090
|
+
{
|
|
1091
|
+
title,
|
|
1092
|
+
onAction: onSeeMore,
|
|
1093
|
+
className: cx("snacky-product-group", `snacky-product-group--${layout}`, className),
|
|
1094
|
+
children: [
|
|
1095
|
+
layout === "grid" && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "snacky-product-group__grid", children }),
|
|
1096
|
+
layout === "horizontal" && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "snacky-product-group__row", ...drag, children: [
|
|
1097
|
+
children,
|
|
1098
|
+
seeMore
|
|
1099
|
+
] }),
|
|
1100
|
+
layout === "banner" && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "snacky-product-group__stage", children: [
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "snacky-product-group__banner", children: banner }),
|
|
1102
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "snacky-product-group__row", ...drag, children: [
|
|
1103
|
+
children,
|
|
1104
|
+
seeMore
|
|
1105
|
+
] })
|
|
1106
|
+
] })
|
|
1107
|
+
]
|
|
1108
|
+
}
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
function useDragScroll() {
|
|
1112
|
+
const state = (0, import_react12.useRef)(null);
|
|
1113
|
+
const justDragged = (0, import_react12.useRef)(false);
|
|
1114
|
+
return {
|
|
1115
|
+
onPointerDown(e) {
|
|
1116
|
+
if (e.pointerType !== "mouse") return;
|
|
1117
|
+
state.current = { x: e.clientX, left: e.currentTarget.scrollLeft, moved: false, id: e.pointerId };
|
|
1118
|
+
},
|
|
1119
|
+
onPointerMove(e) {
|
|
1120
|
+
const d = state.current;
|
|
1121
|
+
if (!d) return;
|
|
1122
|
+
const dx = e.clientX - d.x;
|
|
1123
|
+
if (!d.moved && Math.abs(dx) > 4) {
|
|
1124
|
+
d.moved = true;
|
|
1125
|
+
e.currentTarget.setPointerCapture(d.id);
|
|
1126
|
+
e.currentTarget.classList.add("snacky-product-group__row--dragging");
|
|
1127
|
+
}
|
|
1128
|
+
if (d.moved) e.currentTarget.scrollLeft = d.left - dx;
|
|
1129
|
+
},
|
|
1130
|
+
onPointerUp(e) {
|
|
1131
|
+
if (state.current?.moved) {
|
|
1132
|
+
e.currentTarget.classList.remove("snacky-product-group__row--dragging");
|
|
1133
|
+
justDragged.current = true;
|
|
1134
|
+
setTimeout(() => {
|
|
1135
|
+
justDragged.current = false;
|
|
1136
|
+
}, 0);
|
|
1137
|
+
}
|
|
1138
|
+
state.current = null;
|
|
1139
|
+
},
|
|
1140
|
+
onPointerCancel() {
|
|
1141
|
+
state.current = null;
|
|
1142
|
+
},
|
|
1143
|
+
onClickCapture(e) {
|
|
1144
|
+
if (justDragged.current) {
|
|
1145
|
+
e.stopPropagation();
|
|
1146
|
+
e.preventDefault();
|
|
1147
|
+
}
|
|
1148
|
+
},
|
|
1149
|
+
onDragStart(e) {
|
|
1150
|
+
e.preventDefault();
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// src/components/Stepper/Stepper.tsx
|
|
1156
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1072
1157
|
function Stepper({ steps, className }) {
|
|
1073
|
-
return /* @__PURE__ */ (0,
|
|
1158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("ol", { className: cx("snacky-stepper", className), children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
1074
1159
|
"li",
|
|
1075
1160
|
{
|
|
1076
1161
|
className: cx("snacky-stepper__step", i === steps.length - 1 && "snacky-stepper__step--last"),
|
|
1077
1162
|
children: [
|
|
1078
|
-
/* @__PURE__ */ (0,
|
|
1079
|
-
/* @__PURE__ */ (0,
|
|
1080
|
-
/* @__PURE__ */ (0,
|
|
1081
|
-
step.timestamp && /* @__PURE__ */ (0,
|
|
1163
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cx("snacky-stepper__dot", `snacky-stepper__dot--${step.state}`), children: step.state === "cancelled" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(close, { width: 12, height: 12 }) }),
|
|
1164
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "snacky-stepper__body", children: [
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cx("snacky-stepper__label", `snacky-stepper__label--${step.state}`), children: step.label }),
|
|
1166
|
+
step.timestamp && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "snacky-stepper__time", children: step.timestamp })
|
|
1082
1167
|
] })
|
|
1083
1168
|
]
|
|
1084
1169
|
},
|
|
@@ -1087,7 +1172,7 @@ function Stepper({ steps, className }) {
|
|
|
1087
1172
|
}
|
|
1088
1173
|
|
|
1089
1174
|
// src/components/Calendar/Calendar.tsx
|
|
1090
|
-
var
|
|
1175
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1091
1176
|
var WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
1092
1177
|
var MONTHS = [
|
|
1093
1178
|
"January",
|
|
@@ -1134,39 +1219,39 @@ function Calendar({
|
|
|
1134
1219
|
const [lo, hi] = range ? [range[0], range[1]].sort((a, b) => a.getTime() - b.getTime()) : [null, null];
|
|
1135
1220
|
const isEnd = (d) => single && sameDay(d, single) || lo && hi && (sameDay(d, lo) || sameDay(d, hi));
|
|
1136
1221
|
const isInRange = (d) => lo && hi && d > lo && d < hi;
|
|
1137
|
-
return /* @__PURE__ */ (0,
|
|
1138
|
-
/* @__PURE__ */ (0,
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1222
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: cx("snacky-calendar", className), children: [
|
|
1223
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "snacky-calendar__header", children: [
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1140
1225
|
"button",
|
|
1141
1226
|
{
|
|
1142
1227
|
type: "button",
|
|
1143
1228
|
className: "snacky-calendar__nav",
|
|
1144
1229
|
onClick: onPrevMonth,
|
|
1145
1230
|
"aria-label": "Previous month",
|
|
1146
|
-
children: /* @__PURE__ */ (0,
|
|
1231
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(back, { width: 24, height: 24 })
|
|
1147
1232
|
}
|
|
1148
1233
|
),
|
|
1149
|
-
/* @__PURE__ */ (0,
|
|
1234
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "snacky-calendar__label", children: [
|
|
1150
1235
|
MONTHS[month.getMonth()],
|
|
1151
1236
|
" ",
|
|
1152
1237
|
month.getFullYear()
|
|
1153
1238
|
] }),
|
|
1154
|
-
/* @__PURE__ */ (0,
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1155
1240
|
"button",
|
|
1156
1241
|
{
|
|
1157
1242
|
type: "button",
|
|
1158
1243
|
className: "snacky-calendar__nav snacky-calendar__nav--next",
|
|
1159
1244
|
onClick: onNextMonth,
|
|
1160
1245
|
"aria-label": "Next month",
|
|
1161
|
-
children: /* @__PURE__ */ (0,
|
|
1246
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(back, { width: 24, height: 24 })
|
|
1162
1247
|
}
|
|
1163
1248
|
)
|
|
1164
1249
|
] }),
|
|
1165
|
-
/* @__PURE__ */ (0,
|
|
1166
|
-
WEEKDAYS.map((d) => /* @__PURE__ */ (0,
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "snacky-calendar__grid", children: [
|
|
1251
|
+
WEEKDAYS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "snacky-calendar__weekday", children: d }, d)),
|
|
1167
1252
|
days.map((d, i) => {
|
|
1168
1253
|
const outside = d.getMonth() !== month.getMonth();
|
|
1169
|
-
return /* @__PURE__ */ (0,
|
|
1254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1170
1255
|
"button",
|
|
1171
1256
|
{
|
|
1172
1257
|
type: "button",
|
|
@@ -1180,26 +1265,26 @@ function Calendar({
|
|
|
1180
1265
|
disabled: outside,
|
|
1181
1266
|
"aria-current": isEnd(d) ? "date" : void 0,
|
|
1182
1267
|
children: [
|
|
1183
|
-
/* @__PURE__ */ (0,
|
|
1184
|
-
marked.some((m) => sameDay(m, d)) && /* @__PURE__ */ (0,
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "snacky-calendar__day-number", children: d.getDate() }),
|
|
1269
|
+
marked.some((m) => sameDay(m, d)) && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "snacky-calendar__marker" })
|
|
1185
1270
|
]
|
|
1186
1271
|
},
|
|
1187
1272
|
i
|
|
1188
1273
|
);
|
|
1189
1274
|
})
|
|
1190
1275
|
] }),
|
|
1191
|
-
onAction && /* @__PURE__ */ (0,
|
|
1276
|
+
onAction && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Button, { onClick: onAction, style: { width: "100%" }, children: actionLabel })
|
|
1192
1277
|
] });
|
|
1193
1278
|
}
|
|
1194
1279
|
|
|
1195
1280
|
// src/components/Avatar/Avatar.tsx
|
|
1196
|
-
var
|
|
1281
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1197
1282
|
function Avatar({ src, alt, size = "md", className }) {
|
|
1198
|
-
return /* @__PURE__ */ (0,
|
|
1283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("img", { src, alt, className: cx("snacky-avatar", `snacky-avatar--${size}`, className) });
|
|
1199
1284
|
}
|
|
1200
1285
|
|
|
1201
1286
|
// src/components/Illustration/Illustration.tsx
|
|
1202
|
-
var
|
|
1287
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1203
1288
|
var SIZE = {
|
|
1204
1289
|
empty: { width: 268, height: 200 },
|
|
1205
1290
|
createAccount: { width: 360, height: 240 },
|
|
@@ -1209,54 +1294,54 @@ var SIZE = {
|
|
|
1209
1294
|
};
|
|
1210
1295
|
function Illustration({ variant, src, alt, className }) {
|
|
1211
1296
|
const { width, height } = SIZE[variant];
|
|
1212
|
-
return /* @__PURE__ */ (0,
|
|
1297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("img", { src, alt, width, height, className: cx("snacky-illustration", className) });
|
|
1213
1298
|
}
|
|
1214
1299
|
|
|
1215
1300
|
// src/components/ProductImage/ProductImage.tsx
|
|
1216
|
-
var
|
|
1301
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1217
1302
|
function ProductImage({ src, alt, usage, sold = false, className }) {
|
|
1218
|
-
return /* @__PURE__ */ (0,
|
|
1219
|
-
/* @__PURE__ */ (0,
|
|
1220
|
-
sold && /* @__PURE__ */ (0,
|
|
1303
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: cx("snacky-product-image-wrap", `snacky-product-image-wrap--${usage}`, className), children: [
|
|
1304
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("img", { src, alt, className: cx("snacky-product-image", `snacky-product-image--${usage}`) }),
|
|
1305
|
+
sold && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "snacky-product-image-sold-overlay", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "snacky-product-image-sold-label", children: "Sold Out" }) })
|
|
1221
1306
|
] });
|
|
1222
1307
|
}
|
|
1223
1308
|
|
|
1224
1309
|
// src/components/ProductCard/ProductCard.tsx
|
|
1225
|
-
var
|
|
1310
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1226
1311
|
function ProductCard(props) {
|
|
1227
1312
|
if (props.variant === "details") {
|
|
1228
1313
|
const { productName: productName2, imageUrl: imageUrl2, price: price2, rating: rating2, originalPrice: originalPrice2, discountLabel: discountLabel2, ratingCount, favorited, onFavoriteClick, onShareClick, onChatClick, sold, ratingIcon: ratingIcon2, favoriteIcon, shareIcon, chatIcon, onClick: onClick2, className: className2 } = props;
|
|
1229
|
-
return /* @__PURE__ */ (0,
|
|
1230
|
-
/* @__PURE__ */ (0,
|
|
1231
|
-
/* @__PURE__ */ (0,
|
|
1232
|
-
sold && /* @__PURE__ */ (0,
|
|
1314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: cx("snacky-product-card", "snacky-product-card--details", className2), children: [
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "snacky-product-card__image-block", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__image-wrap", onClick: onClick2, children: [
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("img", { className: "snacky-product-card__image", src: imageUrl2, alt: productName2 }),
|
|
1317
|
+
sold && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__sold-overlay", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SoldOutBadge, {}) })
|
|
1233
1318
|
] }) }),
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1235
|
-
/* @__PURE__ */ (0,
|
|
1236
|
-
/* @__PURE__ */ (0,
|
|
1237
|
-
/* @__PURE__ */ (0,
|
|
1238
|
-
originalPrice2 && /* @__PURE__ */ (0,
|
|
1239
|
-
discountLabel2 && /* @__PURE__ */ (0,
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__details-body", children: [
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "snacky-product-card__name", children: productName2 }),
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__price-row", children: [
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__price", children: price2 }),
|
|
1323
|
+
originalPrice2 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__original-price", children: originalPrice2 }),
|
|
1324
|
+
discountLabel2 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DiscountTag, { label: discountLabel2 })
|
|
1240
1325
|
] }),
|
|
1241
|
-
/* @__PURE__ */ (0,
|
|
1242
|
-
/* @__PURE__ */ (0,
|
|
1243
|
-
/* @__PURE__ */ (0,
|
|
1326
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__footer-row", children: [
|
|
1327
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "snacky-product-card__rating", children: [
|
|
1328
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__rating-icon", children: ratingIcon2 ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(star, { width: 16, height: 16 }) }),
|
|
1244
1329
|
rating2,
|
|
1245
1330
|
" (",
|
|
1246
1331
|
ratingCount,
|
|
1247
1332
|
")"
|
|
1248
1333
|
] }),
|
|
1249
|
-
/* @__PURE__ */ (0,
|
|
1250
|
-
/* @__PURE__ */ (0,
|
|
1251
|
-
/* @__PURE__ */ (0,
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__actions snacky-product-card__actions--details", children: [
|
|
1335
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(IconButton, { variant: "secondary", icon: favoriteIcon ?? (favorited ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(heart2, { width: 20, height: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(heart, { width: 20, height: 20 })), selected: favorited, onClick: onFavoriteClick, ariaLabel: "Favorite" }),
|
|
1336
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(IconButton, { variant: "secondary", icon: shareIcon ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(share, { width: 20, height: 20 }), onClick: onShareClick, ariaLabel: "Share" }),
|
|
1337
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(IconButton, { variant: "secondary", icon: chatIcon ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(chat, { width: 20, height: 20 }), onClick: onChatClick, ariaLabel: "Chat with seller" })
|
|
1253
1338
|
] })
|
|
1254
1339
|
] })
|
|
1255
1340
|
] })
|
|
1256
1341
|
] });
|
|
1257
1342
|
}
|
|
1258
1343
|
const { productName, imageUrl, price, rating, originalPrice, discountLabel, onAddToCart, cartIcon, ratingIcon, onClick, className } = props;
|
|
1259
|
-
return /* @__PURE__ */ (0,
|
|
1344
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
1260
1345
|
"div",
|
|
1261
1346
|
{
|
|
1262
1347
|
className: cx("snacky-product-card", "snacky-product-card--list", className),
|
|
@@ -1265,25 +1350,25 @@ function ProductCard(props) {
|
|
|
1265
1350
|
onClick,
|
|
1266
1351
|
onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && onClick?.(),
|
|
1267
1352
|
children: [
|
|
1268
|
-
/* @__PURE__ */ (0,
|
|
1269
|
-
/* @__PURE__ */ (0,
|
|
1270
|
-
discountLabel && /* @__PURE__ */ (0,
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__image-wrap", children: [
|
|
1354
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("img", { className: "snacky-product-card__image", src: imageUrl, alt: productName }),
|
|
1355
|
+
discountLabel && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__discount", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DiscountTag, { label: discountLabel }) })
|
|
1271
1356
|
] }),
|
|
1272
|
-
/* @__PURE__ */ (0,
|
|
1273
|
-
/* @__PURE__ */ (0,
|
|
1274
|
-
/* @__PURE__ */ (0,
|
|
1275
|
-
originalPrice && /* @__PURE__ */ (0,
|
|
1357
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "snacky-product-card__name", children: productName }),
|
|
1358
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__price-row", children: [
|
|
1359
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__price", children: price }),
|
|
1360
|
+
originalPrice && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__original-price", children: originalPrice })
|
|
1276
1361
|
] }),
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1278
|
-
/* @__PURE__ */ (0,
|
|
1279
|
-
/* @__PURE__ */ (0,
|
|
1362
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "snacky-product-card__footer-row", children: [
|
|
1363
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "snacky-product-card__rating", children: [
|
|
1364
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "snacky-product-card__rating-icon", children: ratingIcon ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(star, { width: 16, height: 16 }) }),
|
|
1280
1365
|
rating
|
|
1281
1366
|
] }),
|
|
1282
|
-
/* @__PURE__ */ (0,
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1283
1368
|
IconButton,
|
|
1284
1369
|
{
|
|
1285
1370
|
variant: "primary",
|
|
1286
|
-
icon: cartIcon ?? /* @__PURE__ */ (0,
|
|
1371
|
+
icon: cartIcon ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(cartAdd, { width: 16, height: 16 }),
|
|
1287
1372
|
onClick: (e) => {
|
|
1288
1373
|
e.stopPropagation();
|
|
1289
1374
|
onAddToCart();
|
|
@@ -1298,17 +1383,17 @@ function ProductCard(props) {
|
|
|
1298
1383
|
}
|
|
1299
1384
|
|
|
1300
1385
|
// src/components/ImagePlaceholder/ImagePlaceholder.tsx
|
|
1301
|
-
var
|
|
1386
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1302
1387
|
function ImagePlaceholder({ width, height, className }) {
|
|
1303
1388
|
const iconSize = Math.round(Math.min(width, height) * 0.32);
|
|
1304
|
-
return /* @__PURE__ */ (0,
|
|
1389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1305
1390
|
"div",
|
|
1306
1391
|
{
|
|
1307
1392
|
className: cx("snacky-image-placeholder", className),
|
|
1308
1393
|
style: { width, height },
|
|
1309
1394
|
role: "img",
|
|
1310
1395
|
"aria-label": "No image",
|
|
1311
|
-
children: /* @__PURE__ */ (0,
|
|
1396
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
1312
1397
|
"svg",
|
|
1313
1398
|
{
|
|
1314
1399
|
width: iconSize,
|
|
@@ -1320,9 +1405,9 @@ function ImagePlaceholder({ width, height, className }) {
|
|
|
1320
1405
|
strokeLinecap: "round",
|
|
1321
1406
|
strokeLinejoin: "round",
|
|
1322
1407
|
children: [
|
|
1323
|
-
/* @__PURE__ */ (0,
|
|
1324
|
-
/* @__PURE__ */ (0,
|
|
1325
|
-
/* @__PURE__ */ (0,
|
|
1408
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
1409
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5", fill: "currentColor", stroke: "none" }),
|
|
1410
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("polyline", { points: "21 15 16 10 5 21" })
|
|
1326
1411
|
]
|
|
1327
1412
|
}
|
|
1328
1413
|
)
|
|
@@ -1360,6 +1445,7 @@ function ImagePlaceholder({ width, height, className }) {
|
|
|
1360
1445
|
PointBalanceBanner,
|
|
1361
1446
|
ProductCard,
|
|
1362
1447
|
ProductChip,
|
|
1448
|
+
ProductGroupSection,
|
|
1363
1449
|
ProductImage,
|
|
1364
1450
|
RadioOption,
|
|
1365
1451
|
SearchField,
|