@best-bundles/bundle-ui 0.0.14 → 0.0.16
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/README.md +158 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/liquid/bundle-ui.iife.js +1 -1
- package/dist/liquid/bundle-ui.iife.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# @best-bundles/bundle-ui
|
|
2
|
+
|
|
3
|
+
Bundle Builder UI components and hooks for Shopify storefronts.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @best-bundles/bundle-ui lucide-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Peer deps: `react`, `react-dom`, and `lucide-react`.
|
|
12
|
+
|
|
13
|
+
## Hydrogen setup
|
|
14
|
+
|
|
15
|
+
### 1) Create a cart adapter (passthrough to Hydrogen cart handlers)
|
|
16
|
+
|
|
17
|
+
Create a small adapter that forwards Bundle Builder line changes to your Hydrogen cart.
|
|
18
|
+
Adjust the cart UI open/close helpers to match your storefront.
|
|
19
|
+
|
|
20
|
+
`app/lib/bundleCartAdapter.tsx`
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { useMemo } from "react";
|
|
24
|
+
import type { BundleCartAdapter } from "@best-bundles/bundle-ui";
|
|
25
|
+
import { useCart } from "@shopify/hydrogen";
|
|
26
|
+
|
|
27
|
+
export function useHydrogenBundleCartAdapter(): BundleCartAdapter {
|
|
28
|
+
const { linesAdd, linesUpdate, linesRemove, openCart, closeCart } = useCart();
|
|
29
|
+
|
|
30
|
+
return useMemo(
|
|
31
|
+
() => ({
|
|
32
|
+
async linesAdd(lines) {
|
|
33
|
+
await linesAdd(lines);
|
|
34
|
+
},
|
|
35
|
+
async linesUpdate(lines) {
|
|
36
|
+
await linesUpdate(lines);
|
|
37
|
+
},
|
|
38
|
+
async linesRemove(lineIds) {
|
|
39
|
+
await linesRemove(lineIds);
|
|
40
|
+
},
|
|
41
|
+
openCartUI() {
|
|
42
|
+
openCart?.();
|
|
43
|
+
},
|
|
44
|
+
closeCartUI() {
|
|
45
|
+
closeCart?.();
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
[linesAdd, linesUpdate, linesRemove, openCart, closeCart],
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If your Hydrogen setup uses `@shopify/hydrogen-react`, import `useCart` from there instead.
|
|
54
|
+
|
|
55
|
+
### 2) Wrap the app in `root.tsx` with `BundleProvider`
|
|
56
|
+
|
|
57
|
+
Place the provider inside your Hydrogen `CartProvider` so `useCart()` is available.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { BundleProvider } from "@best-bundles/bundle-ui";
|
|
61
|
+
import { useHydrogenBundleCartAdapter } from "~/lib/bundleCartAdapter";
|
|
62
|
+
|
|
63
|
+
export default function App() {
|
|
64
|
+
const { env } = useLoaderData<typeof loader>();
|
|
65
|
+
const cartAdapter = useHydrogenBundleCartAdapter();
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<CartProvider>
|
|
69
|
+
<BundleProvider
|
|
70
|
+
apiBaseUrl={env.BEST_BUNDLES_API_BASE_URL}
|
|
71
|
+
shop={env.PUBLIC_STORE_DOMAIN}
|
|
72
|
+
cartAdapter={cartAdapter}
|
|
73
|
+
>
|
|
74
|
+
<Layout>
|
|
75
|
+
<Outlet />
|
|
76
|
+
</Layout>
|
|
77
|
+
</BundleProvider>
|
|
78
|
+
</CartProvider>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Required props:
|
|
84
|
+
- `apiBaseUrl`: Base URL of the Best Bundles app (used for config + analytics).
|
|
85
|
+
- `shop`: Your shop domain (used to fetch the bundle config).
|
|
86
|
+
- `cartAdapter`: The passthrough adapter from step 1.
|
|
87
|
+
|
|
88
|
+
Optional props:
|
|
89
|
+
- `configHandle`: Defaults to `"default"`.
|
|
90
|
+
- `analyticsEndpoint`: Defaults to `${apiBaseUrl}/api/public/bundle-analytics`.
|
|
91
|
+
|
|
92
|
+
### 3) Mount the drawer UI in `Layout.tsx`
|
|
93
|
+
|
|
94
|
+
Render the drawer once in your layout so it can be opened anywhere.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { BundleBuilderDrawer, BundleButton } from "@best-bundles/bundle-ui";
|
|
98
|
+
|
|
99
|
+
export function Layout({ children }: { children: React.ReactNode }) {
|
|
100
|
+
return (
|
|
101
|
+
<>
|
|
102
|
+
<header>
|
|
103
|
+
<BundleButton>Build a bundle</BundleButton>
|
|
104
|
+
</header>
|
|
105
|
+
|
|
106
|
+
{children}
|
|
107
|
+
|
|
108
|
+
<BundleBuilderDrawer />
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## `useBundleBuilder` hook
|
|
115
|
+
|
|
116
|
+
The hook exposes drawer state, selections, and submit actions. It must be used
|
|
117
|
+
inside `BundleProvider`.
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { useBundleBuilder } from "@best-bundles/bundle-ui";
|
|
121
|
+
|
|
122
|
+
export function CustomBundleTrigger() {
|
|
123
|
+
const { toggle, canSubmit, bundleSize, minRequired } = useBundleBuilder();
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<button type="button" onClick={toggle} disabled={!canSubmit && bundleSize < minRequired}>
|
|
127
|
+
Build a bundle
|
|
128
|
+
</button>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Key fields include:
|
|
134
|
+
- `isOpen`, `open`, `close`, `toggle`
|
|
135
|
+
- `loading`, `submitting`, `error`
|
|
136
|
+
- `config`, `eligibleVariants`
|
|
137
|
+
- `selections`, `selectionOrder`, `setQuantity`, `clearSelections`
|
|
138
|
+
- `bundleSize`, `minRequired`, `canSubmit`, `submit`
|
|
139
|
+
|
|
140
|
+
## Bundle cart adapter shape
|
|
141
|
+
|
|
142
|
+
If you need to build your own adapter, implement `BundleCartAdapter`:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
export type BundleCartAdapter = {
|
|
146
|
+
linesAdd(lines: Array<{
|
|
147
|
+
merchandiseId: string;
|
|
148
|
+
quantity: number;
|
|
149
|
+
attributes?: { key: string; value: string }[];
|
|
150
|
+
}>): Promise<void> | void;
|
|
151
|
+
linesUpdate?(lines: Array<{ id: string; quantity: number; attributes?: { key: string; value: string }[] }>): Promise<void> | void;
|
|
152
|
+
linesRemove?(lineIds: string[]): Promise<void> | void;
|
|
153
|
+
openCartUI?(): void;
|
|
154
|
+
closeCartUI?(): void;
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
For Liquid storefronts, `createLiquidCartAdapter()` is available.
|
package/dist/index.js
CHANGED
|
@@ -1235,7 +1235,7 @@ function Hn(i) {
|
|
|
1235
1235
|
/* @__PURE__ */ h("button", { type: "button", onClick: re, disabled: !J, className: u.cta, children: r ? "Adding…" : b > 0 ? `Add ${b} more product${b === 1 ? "" : "s"}` : "Add to Basket" }),
|
|
1236
1236
|
/* @__PURE__ */ R("div", { className: u.poweredBy, children: [
|
|
1237
1237
|
"powered by ",
|
|
1238
|
-
/* @__PURE__ */ h("a", { href: "https://best-bundles
|
|
1238
|
+
/* @__PURE__ */ h("a", { href: "https://apps.shopify.com/best-bundles", target: "_blank", rel: "noopener noreferrer", children: " BestBundles" })
|
|
1239
1239
|
] })
|
|
1240
1240
|
] })
|
|
1241
1241
|
] })
|