@snacky/ui 0.6.1 → 0.7.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 CHANGED
@@ -4,6 +4,28 @@ 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
+ ## ImagePlaceholder added, a non-Figma utility (0.7.0)
8
+
9
+ Every image prop (`ProductCard.imageUrl`, `ProductImage.src`, `Avatar.src`,
10
+ the Banner family's `imageUrl`) has always been required, deliberately - this
11
+ package ships no photography, so there was never anything to default to.
12
+ That was correct as far as it went, but it left a real gap: a consumer with a
13
+ genuinely empty state (a new product with no photo yet) had no sanctioned way
14
+ to say so, and either left `src` empty (silently falling through to the
15
+ browser's own broken-image icon) or invented their own placeholder, which is
16
+ exactly the kind of gap that produced emoji fallbacks elsewhere in this
17
+ project's history.
18
+
19
+ `ImagePlaceholder` closes it: a neutral `bg-surface-variant` box with a
20
+ generic "no image" glyph in `icon-disabled`. The glyph is hand-drawn
21
+ (frame/circle/mountain outline), not one of `SnackyIcons` - it is decorative
22
+ placeholder artwork, not a real icon prop, and the first instinct (reuse the
23
+ package's own `camera` icon, reasoning "at least it's a real glyph") read as
24
+ "take a photo" rather than "no image here" once someone actually looked at
25
+ it. This is a standalone utility, not the 25th documented component - there
26
+ is no Figma node for it, and the README says so explicitly rather than
27
+ letting the count quietly drift.
28
+
7
29
  ## Icon set replaced with the real Figma artwork (0.3.0)
8
30
 
9
31
  The package originally shipped a hand-drawn "starter" icon set: roughly 30
@@ -91,3 +113,16 @@ unverified - see the README's Verification status.
91
113
  not: tsup extracts the CSS to a standalone `dist/index.css` and never
92
114
  re-injects it into the JS entry, so anyone following the snippet verbatim got
93
115
  unstyled components. The correct import is `@snacky/ui/styles.css`.
116
+ - **PointBalanceBanner stretched to fill its container (0.6.2).** Figma's frame
117
+ hugs its content at 312px, it was never meant to fill full-bleed, but the
118
+ component set `width: 100%` plus `justify-content: space-between` anyway.
119
+ Inside any container wider than 312px (which is most of them), the Points and
120
+ Balance groups spread apart across the extra width instead of staying grouped
121
+ on the left like Figma. Switched to `display: inline-flex` (hugs by default)
122
+ with an explicit `gap`, matching the value already recorded in
123
+ `components.json`'s spec for this variant.
124
+ - **AlertBanner clipped a long message (0.6.2).** The row had a fixed
125
+ `height: 40px`, Figma's single-line sample height, not a cap. A message long
126
+ enough to wrap onto a second line got clipped instead of growing the banner.
127
+ Changed to `min-height: 40px` and let the message text take `flex: 1` so it
128
+ shrinks and wraps within the row instead of overflowing sideways.
package/README.md CHANGED
@@ -94,6 +94,32 @@ normally pass no colour. To tint one deliberately, use `color`:
94
94
 
95
95
  Names are listed under **What's here** below. `outline` has 42, `solid` has 11.
96
96
 
97
+ ### 4. Handle a missing image
98
+
99
+ Every image slot (`ProductCard`'s `imageUrl`, `ProductImage`'s `src`,
100
+ `Avatar`'s `src`, the Banner family's `imageUrl`) is a **required** prop, on
101
+ purpose - this package ships no photography, so there is no fallback to fall
102
+ back to. If you leave one out anyway, you get the browser's own broken-image
103
+ icon, not anything from this design system.
104
+
105
+ For a genuinely empty state (a new product with no photo yet, a user with no
106
+ avatar), pass `ImagePlaceholder` explicitly instead of inventing your own:
107
+
108
+ ```tsx
109
+ import { ImagePlaceholder, ProductCard } from '@snacky/ui';
110
+
111
+ {photo ? (
112
+ <ProductCard imageUrl={photo} ... />
113
+ ) : (
114
+ <ImagePlaceholder width={152} height={128} />
115
+ )}
116
+ ```
117
+
118
+ It renders a neutral `bg-surface-variant` box with a generic "no image" glyph
119
+ in `icon-disabled` - not a `SnackyIcons` icon, since this is decorative
120
+ placeholder artwork rather than a real icon prop. Apply your own
121
+ `className`/border radius to match whatever slot it fills.
122
+
97
123
  ## What's here
98
124
 
99
125
  All 24 documented components, each matching its `code.tsx` sample's prop
@@ -118,6 +144,9 @@ the same shell with different `children`, so you get two components rather
118
144
  than 22 near-duplicates. Their spacing varies per variant in Figma, so the
119
145
  shells ship sensible defaults and expect `children` to override it.
120
146
 
147
+ Plus `ImagePlaceholder`, a standalone utility (see **Handle a missing image**
148
+ above) - not one of the 24, there is no Figma node for it.
149
+
121
150
  ## Verification status
122
151
 
123
152
  Every component is diffed against `index.html`'s own Live Preview
package/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  HeroBanner: () => HeroBanner,
39
39
  IconButton: () => IconButton,
40
40
  Illustration: () => Illustration,
41
+ ImagePlaceholder: () => ImagePlaceholder,
41
42
  NavBar: () => NavBar,
42
43
  NotificationBadge: () => NotificationBadge,
43
44
  NotificationListItem: () => NotificationListItem,
@@ -1257,6 +1258,39 @@ function ProductCard(props) {
1257
1258
  }
1258
1259
  );
1259
1260
  }
1261
+
1262
+ // src/components/ImagePlaceholder/ImagePlaceholder.tsx
1263
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1264
+ function ImagePlaceholder({ width, height, className }) {
1265
+ const iconSize = Math.round(Math.min(width, height) * 0.32);
1266
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1267
+ "div",
1268
+ {
1269
+ className: cx("snacky-image-placeholder", className),
1270
+ style: { width, height },
1271
+ role: "img",
1272
+ "aria-label": "No image",
1273
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
1274
+ "svg",
1275
+ {
1276
+ width: iconSize,
1277
+ height: iconSize,
1278
+ viewBox: "0 0 24 24",
1279
+ fill: "none",
1280
+ stroke: "currentColor",
1281
+ strokeWidth: 2,
1282
+ strokeLinecap: "round",
1283
+ strokeLinejoin: "round",
1284
+ children: [
1285
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1286
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5", fill: "currentColor", stroke: "none" }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("polyline", { points: "21 15 16 10 5 21" })
1288
+ ]
1289
+ }
1290
+ )
1291
+ }
1292
+ );
1293
+ }
1260
1294
  // Annotate the CommonJS export names for ESM import in node:
1261
1295
  0 && (module.exports = {
1262
1296
  Accordion,
@@ -1277,6 +1311,7 @@ function ProductCard(props) {
1277
1311
  HeroBanner,
1278
1312
  IconButton,
1279
1313
  Illustration,
1314
+ ImagePlaceholder,
1280
1315
  NavBar,
1281
1316
  NotificationBadge,
1282
1317
  NotificationListItem,