@snowcone-app/ui 0.4.6 → 0.4.8
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 +15 -0
- package/dist/index.cjs +890 -859
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +357 -328
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/composed/HeroProductImage.tsx +10 -0
- package/src/index.ts +7 -0
- package/src/patterns/MockupBackground.tsx +43 -0
- package/src/patterns/RealtimeProvider.tsx +13 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snowcone-app/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "React components for merchandise visualization and customization",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"react-instantsearch": "^7.15.5",
|
|
104
104
|
"react-zoom-pan-pinch": "^3.6.4",
|
|
105
105
|
"tailwind-merge": "^3.0.0",
|
|
106
|
-
"@snowcone-app/sdk": "0.20.
|
|
106
|
+
"@snowcone-app/sdk": "0.20.1"
|
|
107
107
|
},
|
|
108
108
|
"devDependencies": {
|
|
109
109
|
"@chromatic-com/storybook": "^4.1.2",
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { useShopOptional } from "../patterns/ShopProvider";
|
|
17
17
|
import { useRealtimeOptional } from "../patterns/RealtimeProvider";
|
|
18
18
|
import { useMockupPriorityOptional } from "../patterns/MockupPriorityProvider";
|
|
19
|
+
import { useMockupBackgroundOptional } from "../patterns/MockupBackground";
|
|
19
20
|
import { LoadingOverlayPrismCandyInline } from "../components/LoadingOverlayPrismCandy";
|
|
20
21
|
import {
|
|
21
22
|
createDesignForPlacements,
|
|
@@ -82,6 +83,8 @@ function buildHeroMockupUrl(args: {
|
|
|
82
83
|
mockupId: string;
|
|
83
84
|
variantId: string;
|
|
84
85
|
width: number;
|
|
86
|
+
/** Canonical 6-hex background (see MockupBackground) — painted behind alpha scenes. */
|
|
87
|
+
bg?: string;
|
|
85
88
|
}): string | null {
|
|
86
89
|
const snow =
|
|
87
90
|
(typeof window !== "undefined" &&
|
|
@@ -97,6 +100,7 @@ function buildHeroMockupUrl(args: {
|
|
|
97
100
|
width: args.width,
|
|
98
101
|
view: args.mockupId,
|
|
99
102
|
variant: args.variantId,
|
|
103
|
+
...(args.bg ? { bg: args.bg } : {}),
|
|
100
104
|
...(snow.resolver ? { base: snow.resolver } : {}),
|
|
101
105
|
});
|
|
102
106
|
}
|
|
@@ -204,6 +208,8 @@ export const HeroProductImage = memo(function HeroProductImage({
|
|
|
204
208
|
const shopContext = useShopOptional();
|
|
205
209
|
const realtimeContext = useRealtimeOptional();
|
|
206
210
|
const priorityContext = useMockupPriorityOptional();
|
|
211
|
+
// Page background baked into static mockup URLs (see MockupBackground).
|
|
212
|
+
const mockupBg = useMockupBackgroundOptional();
|
|
207
213
|
const priorityContextRef = useRef(priorityContext);
|
|
208
214
|
priorityContextRef.current = priorityContext;
|
|
209
215
|
|
|
@@ -295,6 +301,7 @@ export const HeroProductImage = memo(function HeroProductImage({
|
|
|
295
301
|
mockupId: actualMockupId,
|
|
296
302
|
variantId: actualGvid,
|
|
297
303
|
width,
|
|
304
|
+
bg: mockupBg,
|
|
298
305
|
});
|
|
299
306
|
}, [
|
|
300
307
|
realtimeUrl,
|
|
@@ -304,6 +311,7 @@ export const HeroProductImage = memo(function HeroProductImage({
|
|
|
304
311
|
actualProductId,
|
|
305
312
|
actualMockupId,
|
|
306
313
|
actualGvid,
|
|
314
|
+
mockupBg,
|
|
307
315
|
product?.placements,
|
|
308
316
|
context?.product?.placements,
|
|
309
317
|
images,
|
|
@@ -728,6 +736,7 @@ export const HeroProductImage = memo(function HeroProductImage({
|
|
|
728
736
|
mockupId: actualMockupId,
|
|
729
737
|
variantId: actualGvid,
|
|
730
738
|
width: width,
|
|
739
|
+
bg: mockupBg,
|
|
731
740
|
});
|
|
732
741
|
if (!url) return;
|
|
733
742
|
|
|
@@ -815,6 +824,7 @@ export const HeroProductImage = memo(function HeroProductImage({
|
|
|
815
824
|
actualProductId,
|
|
816
825
|
actualMockupId,
|
|
817
826
|
actualGvid,
|
|
827
|
+
mockupBg,
|
|
818
828
|
images,
|
|
819
829
|
width,
|
|
820
830
|
effects,
|
package/src/index.ts
CHANGED
|
@@ -170,6 +170,13 @@ export type {
|
|
|
170
170
|
PriorityLevel,
|
|
171
171
|
} from "./patterns/MockupPriorityProvider";
|
|
172
172
|
|
|
173
|
+
// MockupBackground - page background baked into static mockup URLs (bg=)
|
|
174
|
+
export {
|
|
175
|
+
MockupBackground,
|
|
176
|
+
useMockupBackgroundOptional,
|
|
177
|
+
} from "./patterns/MockupBackground";
|
|
178
|
+
export type { MockupBackgroundProps } from "./patterns/MockupBackground";
|
|
179
|
+
|
|
173
180
|
// ProductPageProvider - Quick-start providers for product pages
|
|
174
181
|
export {
|
|
175
182
|
ProductPageProvider,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MockupBackground — page-level background color for mockup renders.
|
|
5
|
+
*
|
|
6
|
+
* Wrap a subtree to have every `HeroProductImage` inside it append
|
|
7
|
+
* `bg=<hex>` to the static mockup URLs it builds. The renderer paints the
|
|
8
|
+
* color at the bottom of the stage, so it only shows through mockup scenes
|
|
9
|
+
* whose background has alpha (studio cutouts) — opaque scenes are unaffected.
|
|
10
|
+
*
|
|
11
|
+
* Why: cutout mockups are transparent where the scene ends. Layout tricks
|
|
12
|
+
* that stack a blurred copy of the image behind the sharp one (the PDP
|
|
13
|
+
* edge-blur width extension) bleed through that transparency. Baking the
|
|
14
|
+
* page background into the render makes the image opaque and self-contained
|
|
15
|
+
* (zoom overlays, saved snapshots, and the blur layers all inherit it).
|
|
16
|
+
*
|
|
17
|
+
* `bg` must be the canonical public grammar: lowercase 6-hex, no "#"
|
|
18
|
+
* (URLs are cache keys). Invalid values throw at URL-build time via
|
|
19
|
+
* `getMockupUrl` — loudly, dev and prod.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import React, { createContext, useContext } from "react";
|
|
23
|
+
|
|
24
|
+
const MockupBackgroundContext = createContext<string | undefined>(undefined);
|
|
25
|
+
|
|
26
|
+
export interface MockupBackgroundProps {
|
|
27
|
+
/** Canonical background hex (lowercase 6-hex, no "#"), or undefined to leave URLs untouched. */
|
|
28
|
+
bg?: string;
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function MockupBackground({ bg, children }: MockupBackgroundProps) {
|
|
33
|
+
return (
|
|
34
|
+
<MockupBackgroundContext.Provider value={bg}>
|
|
35
|
+
{children}
|
|
36
|
+
</MockupBackgroundContext.Provider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Background hex from the nearest MockupBackground, or undefined outside one. */
|
|
41
|
+
export function useMockupBackgroundOptional(): string | undefined {
|
|
42
|
+
return useContext(MockupBackgroundContext);
|
|
43
|
+
}
|
|
@@ -42,6 +42,7 @@ import type { RealtimeRenderError } from "@snowcone-app/sdk";
|
|
|
42
42
|
import { readEnv } from "../lib/env";
|
|
43
43
|
import { useProductOptional } from "./Product";
|
|
44
44
|
import type { ReactProductContext } from "./Product";
|
|
45
|
+
import { useMockupBackgroundOptional } from "./MockupBackground";
|
|
45
46
|
|
|
46
47
|
// Default artboard size for export calculations (matches @snowcone-app/canvas default)
|
|
47
48
|
const DEFAULT_ARTBOARD_SIZE = 2000;
|
|
@@ -273,6 +274,9 @@ export function RealtimeProvider({
|
|
|
273
274
|
grantUrl,
|
|
274
275
|
}: RealtimeProviderProps) {
|
|
275
276
|
const productContext = useProductOptional();
|
|
277
|
+
// Page background for renders (see MockupBackground) — sent on the config so
|
|
278
|
+
// realtime results match static `bg=` mockup URLs.
|
|
279
|
+
const mockupBg = useMockupBackgroundOptional();
|
|
276
280
|
|
|
277
281
|
const [isEnabled, setIsEnabled] = useState(autoEnable);
|
|
278
282
|
|
|
@@ -305,6 +309,7 @@ export function RealtimeProvider({
|
|
|
305
309
|
|
|
306
310
|
// Track last sent variantId to detect when we need to re-send config
|
|
307
311
|
const lastSentVariantIdRef = useRef<string | null>(null);
|
|
312
|
+
const lastSentBgRef = useRef<string | undefined>(undefined);
|
|
308
313
|
|
|
309
314
|
// Track last sent colors to prevent duplicates
|
|
310
315
|
const lastSentColorsRef = useRef<Record<string, string>>({});
|
|
@@ -577,6 +582,7 @@ export function RealtimeProvider({
|
|
|
577
582
|
disconnect();
|
|
578
583
|
configSentRef.current = false;
|
|
579
584
|
lastSentVariantIdRef.current = null;
|
|
585
|
+
lastSentBgRef.current = undefined;
|
|
580
586
|
lastSentColorsRef.current = {};
|
|
581
587
|
};
|
|
582
588
|
}
|
|
@@ -611,8 +617,10 @@ export function RealtimeProvider({
|
|
|
611
617
|
const isFirstSend = !configSentRef.current;
|
|
612
618
|
const variantChanged = lastSentVariantIdRef.current !== null &&
|
|
613
619
|
lastSentVariantIdRef.current !== variantId;
|
|
620
|
+
// 3. Background changed (theme flip swaps the MockupBackground hex)
|
|
621
|
+
const bgChanged = configSentRef.current && lastSentBgRef.current !== mockupBg;
|
|
614
622
|
|
|
615
|
-
if (!isFirstSend && !variantChanged) {
|
|
623
|
+
if (!isFirstSend && !variantChanged && !bgChanged) {
|
|
616
624
|
return; // Nothing changed, skip
|
|
617
625
|
}
|
|
618
626
|
|
|
@@ -637,6 +645,7 @@ export function RealtimeProvider({
|
|
|
637
645
|
variantId,
|
|
638
646
|
shop: shop as string,
|
|
639
647
|
width: mockupWidth,
|
|
648
|
+
...(mockupBg ? { bg: mockupBg } : {}),
|
|
640
649
|
placementSettings: { ...placementSettingsOverridesRef.current },
|
|
641
650
|
}
|
|
642
651
|
: {
|
|
@@ -646,6 +655,7 @@ export function RealtimeProvider({
|
|
|
646
655
|
shop: "hTidnpNnNa",
|
|
647
656
|
seal: "bypass-sig-for-k6-load-test",
|
|
648
657
|
width: mockupWidth,
|
|
658
|
+
...(mockupBg ? { bg: mockupBg } : {}),
|
|
649
659
|
placementSettings: { ...placementSettingsOverridesRef.current },
|
|
650
660
|
};
|
|
651
661
|
|
|
@@ -662,6 +672,7 @@ export function RealtimeProvider({
|
|
|
662
672
|
|
|
663
673
|
configSentRef.current = true;
|
|
664
674
|
lastSentVariantIdRef.current = variantId;
|
|
675
|
+
lastSentBgRef.current = mockupBg;
|
|
665
676
|
|
|
666
677
|
// Send default colors for color placements
|
|
667
678
|
setTimeout(() => {
|
|
@@ -682,6 +693,7 @@ export function RealtimeProvider({
|
|
|
682
693
|
sendConfigRaw,
|
|
683
694
|
sendColorBlobTracked,
|
|
684
695
|
mockupWidth,
|
|
696
|
+
mockupBg,
|
|
685
697
|
]);
|
|
686
698
|
|
|
687
699
|
// Watch for color placement changes
|