@patientos/website-kit 0.2.6 → 0.2.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/README.md +54 -2
- package/dist/booking-block-D-UOAPx3.d.ts +74 -0
- package/dist/cart-block-B-ytc9us.d.ts +20 -0
- package/dist/cart-button-BCLFittB.d.ts +24 -0
- package/dist/cart-storage.d.ts +110 -0
- package/dist/cart-storage.js +39 -0
- package/dist/checkout-block-BeXwpqYe.d.ts +24 -0
- package/dist/chunk-2CZFJOKK.js +79 -0
- package/dist/{chunk-ZYX4TXBN.js → chunk-3T7UWKAH.js} +4 -310
- package/dist/{chunk-7ZOQ6UKG.js → chunk-4GKSSM5N.js} +578 -3163
- package/dist/chunk-4NF7SSIX.js +367 -0
- package/dist/chunk-7BUDUYXN.js +80 -0
- package/dist/chunk-FZ4WKWIE.js +310 -0
- package/dist/{chunk-ZZFBTLR4.js → chunk-HTVKKLWI.js} +20 -5
- package/dist/chunk-IOC6QLB7.js +159 -0
- package/dist/chunk-S3ZQQOQT.js +2057 -0
- package/dist/chunk-UTAMB2SK.js +214 -0
- package/dist/chunk-WQSJ46TP.js +19 -0
- package/dist/chunk-ZNH6TSYP.js +167 -0
- package/dist/index.d.ts +12 -32
- package/dist/index.js +88 -26
- package/dist/islands-impl/cart-button.d.ts +19 -0
- package/dist/islands-impl/cart-button.js +13 -0
- package/dist/islands-impl/cart.d.ts +31 -0
- package/dist/islands-impl/cart.js +11 -0
- package/dist/islands-impl/checkout.d.ts +6 -0
- package/dist/islands-impl/checkout.js +13 -0
- package/dist/islands-impl/store.d.ts +30 -0
- package/dist/islands-impl/store.js +16 -0
- package/dist/islands-impl.d.ts +14 -10
- package/dist/islands-impl.js +22 -7
- package/dist/islands-registry.js +13 -4
- package/dist/{portal-account-8uQc_Ncx.d.ts → portal-account-DRJyr3nz.d.ts} +1 -82
- package/dist/{portal-account.client-BBe_q9yC.d.ts → portal-account.client-Bke4NsgW.d.ts} +2 -1
- package/dist/portal-booking-client.d.ts +3 -2
- package/dist/portal-booking-client.js +2 -1
- package/dist/portal-client-my3q5GME.d.ts +83 -0
- package/dist/store-block-CFxnsfKU.d.ts +37 -0
- package/dist/store-catalog-p7TFOpfk.d.ts +78 -0
- package/dist/store-catalog.d.ts +3 -0
- package/dist/store-catalog.js +11 -0
- package/dist/website-kit.css +193 -0
- package/package.json +31 -1
- package/dist/checkout-block-BdpPIuQ5.d.ts +0 -136
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeCatalogResponse,
|
|
3
|
+
storeCatalogPath
|
|
4
|
+
} from "./chunk-WQSJ46TP.js";
|
|
5
|
+
import {
|
|
6
|
+
createStoreClient,
|
|
7
|
+
formatMoney
|
|
8
|
+
} from "./chunk-7BUDUYXN.js";
|
|
9
|
+
import {
|
|
10
|
+
addToCart,
|
|
11
|
+
cartItemCount,
|
|
12
|
+
readCart,
|
|
13
|
+
subscribeToCart
|
|
14
|
+
} from "./chunk-4NF7SSIX.js";
|
|
15
|
+
|
|
16
|
+
// src/store-block.client.tsx
|
|
17
|
+
import * as React from "react";
|
|
18
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
var SKELETON_CARDS = 6;
|
|
20
|
+
var ADD_BUTTON_ATTR = "data-sk-store-add";
|
|
21
|
+
var STORE_PREHYDRATION_SCRIPT = `(function(){
|
|
22
|
+
if(window.__skStoreArmed)return;window.__skStoreArmed=1;
|
|
23
|
+
document.addEventListener('click',function(e){
|
|
24
|
+
var t=e.target;if(!t||!t.closest)return;
|
|
25
|
+
var b=t.closest('button[${ADD_BUTTON_ATTR}]');if(!b||b.disabled)return;
|
|
26
|
+
var c=b.closest('.sk-store__card');var s=c?c.querySelector('select'):null;
|
|
27
|
+
var v=(s&&s.value)||b.getAttribute('data-sk-store-variant');if(!v)return;
|
|
28
|
+
(b.__skStoreQueue||(b.__skStoreQueue=[])).push({variantId:v,event:e});
|
|
29
|
+
},true);
|
|
30
|
+
})();`;
|
|
31
|
+
function takeQueuedClicks(button) {
|
|
32
|
+
const queue = button?.__skStoreQueue;
|
|
33
|
+
if (!queue || queue.length === 0) return [];
|
|
34
|
+
button.__skStoreQueue = [];
|
|
35
|
+
return queue;
|
|
36
|
+
}
|
|
37
|
+
function dropQueuedClick(button, nativeEvent) {
|
|
38
|
+
const queue = button?.__skStoreQueue;
|
|
39
|
+
if (!queue) return;
|
|
40
|
+
const at = queue.findIndex((entry) => entry.event === nativeEvent);
|
|
41
|
+
if (at >= 0) queue.splice(at, 1);
|
|
42
|
+
}
|
|
43
|
+
function StoreClient({
|
|
44
|
+
categoryHandle,
|
|
45
|
+
productHandle,
|
|
46
|
+
storeApiOrigin,
|
|
47
|
+
title,
|
|
48
|
+
columns,
|
|
49
|
+
hideCartLink,
|
|
50
|
+
initialCatalog
|
|
51
|
+
}) {
|
|
52
|
+
const client = React.useMemo(
|
|
53
|
+
() => createStoreClient({ apiOrigin: storeApiOrigin }),
|
|
54
|
+
[storeApiOrigin]
|
|
55
|
+
);
|
|
56
|
+
const [catalog, setCatalog] = React.useState(
|
|
57
|
+
initialCatalog ?? null
|
|
58
|
+
);
|
|
59
|
+
const [failed, setFailed] = React.useState(false);
|
|
60
|
+
const [count, setCount] = React.useState(0);
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
setCount(cartItemCount(readCart()));
|
|
63
|
+
return subscribeToCart((cart) => setCount(cartItemCount(cart)));
|
|
64
|
+
}, []);
|
|
65
|
+
const hasSeed = initialCatalog != null;
|
|
66
|
+
React.useEffect(() => {
|
|
67
|
+
let alive = true;
|
|
68
|
+
void client.get(storeCatalogPath(productHandle)).then((result) => {
|
|
69
|
+
if (!alive) return;
|
|
70
|
+
if (!result.ok) {
|
|
71
|
+
setFailed((previous) => hasSeed ? previous : true);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
setCatalog(normalizeCatalogResponse(result.data));
|
|
75
|
+
setFailed(false);
|
|
76
|
+
});
|
|
77
|
+
return () => {
|
|
78
|
+
alive = false;
|
|
79
|
+
};
|
|
80
|
+
}, [client, productHandle, hasSeed]);
|
|
81
|
+
const products = React.useMemo(() => {
|
|
82
|
+
if (!catalog) return [];
|
|
83
|
+
if (productHandle || !categoryHandle) return catalog.products;
|
|
84
|
+
return catalog.products.filter(
|
|
85
|
+
(product) => product.categories.some((category) => category.handle === categoryHandle)
|
|
86
|
+
);
|
|
87
|
+
}, [catalog, categoryHandle, productHandle]);
|
|
88
|
+
if (failed && !catalog) {
|
|
89
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
90
|
+
/* @__PURE__ */ jsx("h2", { className: "sk-store__heading", children: title ?? "Shop" }),
|
|
91
|
+
/* @__PURE__ */ jsx("p", { className: "sk-store__placeholder", role: "note", children: "Our shop is unavailable right now. Please contact the clinic to order." })
|
|
92
|
+
] });
|
|
93
|
+
}
|
|
94
|
+
const gridStyle = columns ? { "--sk-store-columns": columns } : void 0;
|
|
95
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
96
|
+
hasSeed ? /* @__PURE__ */ jsx(
|
|
97
|
+
"script",
|
|
98
|
+
{
|
|
99
|
+
className: "sk-store__prehydration",
|
|
100
|
+
dangerouslySetInnerHTML: { __html: STORE_PREHYDRATION_SCRIPT }
|
|
101
|
+
}
|
|
102
|
+
) : null,
|
|
103
|
+
/* @__PURE__ */ jsxs("div", { className: "sk-store__header", children: [
|
|
104
|
+
/* @__PURE__ */ jsx("h2", { className: "sk-store__heading", children: title ?? "Shop" }),
|
|
105
|
+
hideCartLink ? null : /* @__PURE__ */ jsxs("a", { className: "sk-store__cart-link", href: "/cart", children: [
|
|
106
|
+
"Cart",
|
|
107
|
+
count > 0 ? ` (${count})` : ""
|
|
108
|
+
] })
|
|
109
|
+
] }),
|
|
110
|
+
!catalog ? (
|
|
111
|
+
// A fixed-height skeleton grid, not a line of text: the text-then-grid swap is
|
|
112
|
+
// what made the shop jump on every load.
|
|
113
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
114
|
+
/* @__PURE__ */ jsx("p", { className: "sk-store__placeholder sk-store__placeholder--sr", role: "status", children: "Loading the shop\u2026" }),
|
|
115
|
+
/* @__PURE__ */ jsx("ul", { className: "sk-store__grid", style: gridStyle, "aria-hidden": true, children: Array.from({ length: SKELETON_CARDS }, (_, index) => /* @__PURE__ */ jsxs("li", { className: "sk-store__card sk-store__card--skeleton", children: [
|
|
116
|
+
/* @__PURE__ */ jsx("span", { className: "sk-store__image sk-store__image--empty" }),
|
|
117
|
+
/* @__PURE__ */ jsx("span", { className: "sk-store__skeleton-line" }),
|
|
118
|
+
/* @__PURE__ */ jsx("span", { className: "sk-store__skeleton-line sk-store__skeleton-line--short" }),
|
|
119
|
+
/* @__PURE__ */ jsx("span", { className: "sk-store__skeleton-button" })
|
|
120
|
+
] }, index)) })
|
|
121
|
+
] })
|
|
122
|
+
) : products.length === 0 ? /* @__PURE__ */ jsx("p", { className: "sk-store__placeholder", role: "status", children: "Nothing is available to order online just now." }) : /* @__PURE__ */ jsx("ul", { className: "sk-store__grid", style: gridStyle, children: products.map((product) => /* @__PURE__ */ jsx(StoreCard, { product }, product.id)) })
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
function StoreCard({ product }) {
|
|
126
|
+
const [variantId, setVariantId] = React.useState(
|
|
127
|
+
() => (product.variants.find((v) => v.inStock) ?? product.variants[0]).id
|
|
128
|
+
);
|
|
129
|
+
const [addFeedback, setAddFeedback] = React.useState(null);
|
|
130
|
+
const variant = product.variants.find((v) => v.id === variantId) ?? product.variants[0];
|
|
131
|
+
const image = product.thumbnailUrl ?? product.images[0]?.url ?? null;
|
|
132
|
+
const addRef = React.useRef(null);
|
|
133
|
+
const add = React.useCallback(async (id) => {
|
|
134
|
+
const result = await addToCart(id, 1);
|
|
135
|
+
setAddFeedback(result.status);
|
|
136
|
+
window.setTimeout(() => setAddFeedback(null), 1600);
|
|
137
|
+
}, []);
|
|
138
|
+
const variants = product.variants;
|
|
139
|
+
React.useEffect(() => {
|
|
140
|
+
const queued = takeQueuedClicks(addRef.current);
|
|
141
|
+
if (queued.length === 0) return;
|
|
142
|
+
void (async () => {
|
|
143
|
+
for (const click of queued) {
|
|
144
|
+
const known = variants.some((v) => v.id === click.variantId);
|
|
145
|
+
await add(known ? click.variantId : variantId);
|
|
146
|
+
}
|
|
147
|
+
})();
|
|
148
|
+
}, []);
|
|
149
|
+
function onAdd(nativeEvent) {
|
|
150
|
+
dropQueuedClick(addRef.current, nativeEvent);
|
|
151
|
+
void add(variant.id);
|
|
152
|
+
}
|
|
153
|
+
return /* @__PURE__ */ jsxs("li", { className: "sk-store__card", children: [
|
|
154
|
+
/* @__PURE__ */ jsxs("a", { className: "sk-store__card-link", href: `/store/${product.handle}`, children: [
|
|
155
|
+
image ? (
|
|
156
|
+
// Square by contract (CSS `aspect-ratio` AND the intrinsic ratio in the
|
|
157
|
+
// markup), lazy, and decoded off the main thread: the card must hold its
|
|
158
|
+
// height before the bytes arrive or the whole grid reflows around it.
|
|
159
|
+
/* @__PURE__ */ jsx(
|
|
160
|
+
"img",
|
|
161
|
+
{
|
|
162
|
+
className: "sk-store__image",
|
|
163
|
+
src: image,
|
|
164
|
+
alt: product.images[0]?.alt ?? "",
|
|
165
|
+
width: 600,
|
|
166
|
+
height: 600,
|
|
167
|
+
loading: "lazy",
|
|
168
|
+
decoding: "async"
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
) : /* @__PURE__ */ jsx(
|
|
172
|
+
"span",
|
|
173
|
+
{
|
|
174
|
+
className: "sk-store__image sk-store__image--empty",
|
|
175
|
+
"aria-hidden": true
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ jsx("span", { className: "sk-store__title", children: product.title })
|
|
179
|
+
] }),
|
|
180
|
+
/* @__PURE__ */ jsxs("span", { className: "sk-store__price", children: [
|
|
181
|
+
formatMoney(variant.price),
|
|
182
|
+
product.gstApplicable ? /* @__PURE__ */ jsx("span", { className: "sk-store__gst", children: " incl. GST" }) : null
|
|
183
|
+
] }),
|
|
184
|
+
product.variants.length > 1 ? /* @__PURE__ */ jsxs("label", { className: "sk-store__variant", children: [
|
|
185
|
+
/* @__PURE__ */ jsx("span", { className: "sk-store__variant-label", children: "Option" }),
|
|
186
|
+
/* @__PURE__ */ jsx(
|
|
187
|
+
"select",
|
|
188
|
+
{
|
|
189
|
+
value: variantId,
|
|
190
|
+
onChange: (e) => setVariantId(e.target.value),
|
|
191
|
+
children: product.variants.map((v) => /* @__PURE__ */ jsx("option", { value: v.id, disabled: !v.inStock, children: (v.options.length ? v.options.join(" / ") : v.title) + (v.inStock ? "" : " \u2014 sold out") }, v.id))
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
] }) : null,
|
|
195
|
+
/* @__PURE__ */ jsx(
|
|
196
|
+
"button",
|
|
197
|
+
{
|
|
198
|
+
type: "button",
|
|
199
|
+
className: "sk-store__add",
|
|
200
|
+
ref: addRef,
|
|
201
|
+
"data-sk-store-add": "",
|
|
202
|
+
"data-sk-store-variant": variant.id,
|
|
203
|
+
onClick: (event) => onAdd(event.nativeEvent),
|
|
204
|
+
disabled: !variant.inStock,
|
|
205
|
+
children: !variant.inStock ? "Sold out" : addFeedback === "added" ? "Added \u2713" : addFeedback === "line_limit" ? "Cart full \u2014 50 products max" : addFeedback === "quantity_limit" ? "Maximum 99 in cart" : addFeedback === "cart_storage_unavailable" ? "This browser can\u2019t safely update the cart" : "Add to cart"
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
] });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export {
|
|
212
|
+
STORE_PREHYDRATION_SCRIPT,
|
|
213
|
+
StoreClient
|
|
214
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/store-catalog.ts
|
|
2
|
+
function storeCatalogPath(productHandle) {
|
|
3
|
+
return productHandle ? `/api/store/catalog/${encodeURIComponent(productHandle)}` : "/api/store/catalog";
|
|
4
|
+
}
|
|
5
|
+
function normalizeCatalogResponse(data) {
|
|
6
|
+
return "product" in data ? { products: [data.product], currency: data.currency } : data;
|
|
7
|
+
}
|
|
8
|
+
async function fetchStoreCatalog(client, options = {}) {
|
|
9
|
+
const result = await client.get(
|
|
10
|
+
storeCatalogPath(options.productHandle)
|
|
11
|
+
);
|
|
12
|
+
return result.ok ? normalizeCatalogResponse(result.data) : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
storeCatalogPath,
|
|
17
|
+
normalizeCatalogResponse,
|
|
18
|
+
fetchStoreCatalog
|
|
19
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CartLineList,
|
|
3
|
+
CartProblemList,
|
|
4
|
+
CartTotals,
|
|
5
|
+
UnsupportedCartLineList,
|
|
6
|
+
quoteSourceQuantities,
|
|
7
|
+
useCartQuote
|
|
8
|
+
} from "./chunk-IOC6QLB7.js";
|
|
9
|
+
import {
|
|
10
|
+
createStoreClient
|
|
11
|
+
} from "./chunk-7BUDUYXN.js";
|
|
12
|
+
import {
|
|
13
|
+
cartItemCount,
|
|
14
|
+
readCart,
|
|
15
|
+
subscribeToCart
|
|
16
|
+
} from "./chunk-4NF7SSIX.js";
|
|
17
|
+
|
|
18
|
+
// src/cart-button.client.tsx
|
|
19
|
+
import * as React from "react";
|
|
20
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
+
var EMPTY_CART = { v: 1, lines: [] };
|
|
22
|
+
function CartButtonClient({
|
|
23
|
+
storeApiOrigin,
|
|
24
|
+
label,
|
|
25
|
+
cartHref,
|
|
26
|
+
checkoutHref
|
|
27
|
+
}) {
|
|
28
|
+
const [count, setCount] = React.useState(0);
|
|
29
|
+
const [open, setOpen] = React.useState(false);
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
setCount(cartItemCount(readCart()));
|
|
32
|
+
return subscribeToCart((cart) => setCount(cartItemCount(cart)));
|
|
33
|
+
}, []);
|
|
34
|
+
const text = label ?? "Cart";
|
|
35
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36
|
+
/* @__PURE__ */ jsxs(
|
|
37
|
+
"button",
|
|
38
|
+
{
|
|
39
|
+
type: "button",
|
|
40
|
+
className: "sk-cart-button__trigger",
|
|
41
|
+
"aria-expanded": open,
|
|
42
|
+
"aria-haspopup": "dialog",
|
|
43
|
+
"aria-label": count > 0 ? `${text} \u2014 ${count} item${count === 1 ? "" : "s"}` : text,
|
|
44
|
+
onClick: () => setOpen((wasOpen) => !wasOpen),
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "sk-cart-button__label", children: text }),
|
|
47
|
+
count > 0 ? /* @__PURE__ */ jsx("span", { className: "sk-cart-button__badge", "aria-hidden": true, children: count > 99 ? "99+" : count }) : null
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
CartDrawer,
|
|
53
|
+
{
|
|
54
|
+
open,
|
|
55
|
+
onClose: () => setOpen(false),
|
|
56
|
+
storeApiOrigin,
|
|
57
|
+
cartHref,
|
|
58
|
+
checkoutHref
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
] });
|
|
62
|
+
}
|
|
63
|
+
function CartDrawer({
|
|
64
|
+
open,
|
|
65
|
+
onClose,
|
|
66
|
+
storeApiOrigin,
|
|
67
|
+
cartHref,
|
|
68
|
+
checkoutHref
|
|
69
|
+
}) {
|
|
70
|
+
const client = React.useMemo(
|
|
71
|
+
() => createStoreClient({ apiOrigin: storeApiOrigin }),
|
|
72
|
+
[storeApiOrigin]
|
|
73
|
+
);
|
|
74
|
+
const [cart, setCart] = React.useState(EMPTY_CART);
|
|
75
|
+
const [mutationUnavailable, setMutationUnavailable] = React.useState(false);
|
|
76
|
+
const closeRef = React.useRef(null);
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
setCart(readCart());
|
|
79
|
+
return subscribeToCart(setCart);
|
|
80
|
+
}, []);
|
|
81
|
+
React.useEffect(() => {
|
|
82
|
+
if (!open) return;
|
|
83
|
+
closeRef.current?.focus();
|
|
84
|
+
const onKeyDown = (event) => {
|
|
85
|
+
if (event.key === "Escape") onClose();
|
|
86
|
+
};
|
|
87
|
+
window.addEventListener("keydown", onKeyDown);
|
|
88
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
89
|
+
}, [open, onClose]);
|
|
90
|
+
const { quote, quoteSourceCart, failed } = useCartQuote(client, cart, open);
|
|
91
|
+
async function runMutation(mutation) {
|
|
92
|
+
const result = await mutation;
|
|
93
|
+
setMutationUnavailable(result.status === "cart_storage_unavailable");
|
|
94
|
+
}
|
|
95
|
+
if (!open) return null;
|
|
96
|
+
const quotedVariantIds = new Set(quote?.lines.map((l) => l.variantId) ?? []);
|
|
97
|
+
const unsupportedLines = cart.lines.filter(
|
|
98
|
+
(line) => line.kind !== "retail" || quote !== null && !quotedVariantIds.has(line.variantId)
|
|
99
|
+
);
|
|
100
|
+
return /* @__PURE__ */ jsxs("div", { className: "sk-cart-drawer", children: [
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
"div",
|
|
103
|
+
{
|
|
104
|
+
className: "sk-cart-drawer__scrim",
|
|
105
|
+
onClick: onClose,
|
|
106
|
+
"aria-hidden": true
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
/* @__PURE__ */ jsxs(
|
|
110
|
+
"aside",
|
|
111
|
+
{
|
|
112
|
+
className: "sk-cart-drawer__panel",
|
|
113
|
+
role: "dialog",
|
|
114
|
+
"aria-modal": "true",
|
|
115
|
+
"aria-label": "Your cart",
|
|
116
|
+
children: [
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { className: "sk-cart-drawer__head", children: [
|
|
118
|
+
/* @__PURE__ */ jsx("h2", { className: "sk-cart__heading", children: "Your cart" }),
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
"button",
|
|
121
|
+
{
|
|
122
|
+
type: "button",
|
|
123
|
+
ref: closeRef,
|
|
124
|
+
className: "sk-cart-drawer__close",
|
|
125
|
+
onClick: onClose,
|
|
126
|
+
children: "Close"
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
] }),
|
|
130
|
+
/* @__PURE__ */ jsx("div", { className: "sk-cart-drawer__body", children: cart.lines.length === 0 ? /* @__PURE__ */ jsx("p", { className: "sk-cart__placeholder", role: "status", children: "Your cart is empty." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
131
|
+
quote ? /* @__PURE__ */ jsx(CartProblemList, { problems: quote.problems }) : null,
|
|
132
|
+
failed ? /* @__PURE__ */ jsx("p", { className: "sk-cart__placeholder", role: "alert", children: "We couldn't price your cart just now. Please try again in a moment." }) : null,
|
|
133
|
+
mutationUnavailable ? /* @__PURE__ */ jsx("p", { className: "sk-cart__placeholder", role: "alert", children: "This browser can\u2019t safely update the cart. Try a supported browser with site storage enabled." }) : null,
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
UnsupportedCartLineList,
|
|
136
|
+
{
|
|
137
|
+
lines: unsupportedLines,
|
|
138
|
+
onMutate: (m) => void runMutation(m)
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
quote ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
CartLineList,
|
|
144
|
+
{
|
|
145
|
+
lines: quote.lines,
|
|
146
|
+
sourceQuantities: quoteSourceQuantities(quoteSourceCart),
|
|
147
|
+
onMutate: (m) => void runMutation(m)
|
|
148
|
+
}
|
|
149
|
+
),
|
|
150
|
+
/* @__PURE__ */ jsx(CartTotals, { quote }),
|
|
151
|
+
quote.requiresShipping ? /* @__PURE__ */ jsx("p", { className: "sk-cart__note", children: "Delivery details are confirmed at checkout." }) : null
|
|
152
|
+
] }) : failed ? null : /* @__PURE__ */ jsx("p", { className: "sk-cart__placeholder", role: "status", children: "Pricing your cart\u2026" })
|
|
153
|
+
] }) }),
|
|
154
|
+
/* @__PURE__ */ jsxs("div", { className: "sk-cart-drawer__foot", children: [
|
|
155
|
+
/* @__PURE__ */ jsx("a", { className: "sk-cart__continue", href: cartHref ?? "/cart", children: "View cart" }),
|
|
156
|
+
quote && quote.lines.length > 0 && unsupportedLines.length === 0 ? /* @__PURE__ */ jsx("a", { className: "sk-cart__checkout", href: checkoutHref ?? "/checkout", children: "Checkout" }) : null
|
|
157
|
+
] })
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
] });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export {
|
|
165
|
+
CartButtonClient,
|
|
166
|
+
CartDrawer
|
|
167
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,16 @@ export { BPOINT_SCRIPT_ORIGIN, BPOINT_SCRIPT_URL, CONSULT_CHUNK_PATH, THIRD_PART
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
export { ISLAND_ATTR, ISLAND_PROPS_ATTR, Island, IslandProps, IslandRegistry, mountIslandsWith, readIslandProps } from './islands.js';
|
|
4
4
|
export { ISLANDS, IslandName, mountIslands } from './islands-registry.js';
|
|
5
|
-
import { P as PortalClient, W as WhoAmI, a as PortalPrefill, b as PublicClaim
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
5
|
+
import { P as PortalClient, W as WhoAmI, a as PortalPrefill, b as PublicClaim } from './portal-client-my3q5GME.js';
|
|
6
|
+
export { F as FetchLike, c as PortalClientConfig, d as PortalResult, e as createPortalClient } from './portal-client-my3q5GME.js';
|
|
7
|
+
export { S as StoreCatalog, a as StoreCatalogResponse, b as StoreClient, c as StoreClientConfig, d as StoreProduct, e as StoreResult, f as StoreVariant, g as createStoreClient, h as fetchStoreCatalog, n as normalizeCatalogResponse, s as storeCatalogPath } from './store-catalog-p7TFOpfk.js';
|
|
8
|
+
export { CartLine, CartLineKind, CartMutationResult, Cart as StoredCart, addToCart, adjustCartQuantity, cartItemCount, cartToWireLines, clearCart, mutateCart, readCart, removeFromCart, setCartQuantity, subscribeToCart } from './cart-storage.js';
|
|
9
|
+
export { S as Store, a as StoreMarkerProps, b as StoreProps, f as formatMoney } from './store-block-CFxnsfKU.js';
|
|
10
|
+
export { B as BookingBlock, a as BookingBlockMarkerProps, b as BookingBlockProps, c as BookingTypeOption, C as CertificateFunnel, d as CertificateFunnelMarkerProps, e as CertificateFunnelProps, F as FunnelPublicApi, f as FunnelServiceOption } from './booking-block-D-UOAPx3.js';
|
|
11
|
+
export { P as PortalAccount, a as PortalAccountMarkerProps, b as PortalAccountProps, c as PortalAccountSurface, d as PortalPanel, e as PortalPanelMarkerProps, f as PortalPanelProps, g as PortalSurface } from './portal-account-DRJyr3nz.js';
|
|
12
|
+
export { C as Cart, a as CartMarkerProps, b as CartProps } from './cart-block-B-ytc9us.js';
|
|
13
|
+
export { C as CartButton, a as CartButtonMarkerProps, b as CartButtonProps } from './cart-button-BCLFittB.js';
|
|
14
|
+
export { C as Checkout, a as CheckoutMarkerProps, b as CheckoutProps } from './checkout-block-BeXwpqYe.js';
|
|
8
15
|
export { PatientSurfaceTheme, patientSurfaceTheme } from './patient-surface-theme.js';
|
|
9
16
|
export { Rgb, contrastRatio, deriveForeground, parseHexColor, relativeLuminance } from './contrast.js';
|
|
10
17
|
export { AnswerValue, Answers, ShowWhenCondition, evaluateShowWhen, visibleQuestions } from './show-when.js';
|
|
@@ -210,33 +217,6 @@ interface PortalSession {
|
|
|
210
217
|
*/
|
|
211
218
|
declare function usePortalSession(): PortalSession;
|
|
212
219
|
|
|
213
|
-
|
|
214
|
-
/** The validated PatientOS patient/API origin. Empty means same-origin. */
|
|
215
|
-
apiOrigin?: string | null;
|
|
216
|
-
/** Injectable browser transport for tests. */
|
|
217
|
-
fetchImpl?: FetchLike;
|
|
218
|
-
}
|
|
219
|
-
type StoreResult<T> = {
|
|
220
|
-
ok: true;
|
|
221
|
-
data: T;
|
|
222
|
-
} | {
|
|
223
|
-
ok: false;
|
|
224
|
-
status: number | null;
|
|
225
|
-
error: string | null;
|
|
226
|
-
message: string | null;
|
|
227
|
-
};
|
|
228
|
-
interface StoreClient {
|
|
229
|
-
readonly apiOrigin: string;
|
|
230
|
-
url(path: string): string;
|
|
231
|
-
get<T>(path: string): Promise<StoreResult<T>>;
|
|
232
|
-
post<T>(path: string, body: unknown, options?: {
|
|
233
|
-
signal?: AbortSignal;
|
|
234
|
-
}): Promise<StoreResult<T>>;
|
|
235
|
-
/** PatientOS magic-link sign-in that returns to this site's checkout. */
|
|
236
|
-
signInHref(returnPath?: string): string;
|
|
237
|
-
}
|
|
238
|
-
declare function createStoreClient(config?: StoreClientConfig): StoreClient;
|
|
239
|
-
|
|
240
|
-
declare const WEBSITE_KIT_VERSION = "0.1.0";
|
|
220
|
+
declare const WEBSITE_KIT_VERSION = "0.2.8";
|
|
241
221
|
|
|
242
|
-
export { Button, type ButtonProps, type ButtonVariant, Container, type ContainerProps, FAQ, type FAQProps, type FaqItem,
|
|
222
|
+
export { Button, type ButtonProps, type ButtonVariant, Container, type ContainerProps, FAQ, type FAQProps, type FaqItem, Hero, type HeroProps, Hours, type HoursProps, type HoursRow, MapEmbed, type MapEmbedProps, PortalClient, PortalPrefill, PortalProvider, type PortalProviderProps, type PortalSession, type PortalSessionStatus, PublicClaim, Row, type RowProps, Section, type SectionProps, type Service, ServiceGrid, type ServiceGridProps, Stack, type StackProps, TeamGrid, type TeamGridProps, type TeamMember, ThemeProvider, type ThemeProviderProps, WEBSITE_KIT_VERSION, WebsiteShell, type WebsiteShellProps, type WebsiteTheme, WhoAmI, defaultTheme, resolveTheme, themeToCssVars, usePortalClient, usePortalSession };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
contrastRatio,
|
|
3
|
+
deriveForeground,
|
|
4
|
+
derivePrimaryPair,
|
|
5
|
+
parseHexColor,
|
|
6
|
+
relativeLuminance
|
|
7
|
+
} from "./chunk-LCHW6XF4.js";
|
|
8
|
+
import {
|
|
9
|
+
patientSurfaceTheme
|
|
10
|
+
} from "./chunk-JTZ6GYA7.js";
|
|
1
11
|
import {
|
|
2
12
|
ISLANDS,
|
|
3
13
|
mountIslands
|
|
4
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HTVKKLWI.js";
|
|
5
15
|
import {
|
|
6
16
|
PortalAccount,
|
|
7
17
|
PortalPanel,
|
|
8
18
|
PortalProvider,
|
|
9
|
-
createStoreClient,
|
|
10
19
|
getAppointmentTypes,
|
|
11
20
|
getClinic,
|
|
12
21
|
getPublicApi,
|
|
@@ -14,15 +23,8 @@ import {
|
|
|
14
23
|
getThemeTokens,
|
|
15
24
|
usePortalClient,
|
|
16
25
|
usePortalSession
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import
|
|
19
|
-
BPOINT_SCRIPT_ORIGIN,
|
|
20
|
-
BPOINT_SCRIPT_URL,
|
|
21
|
-
CONSULT_CHUNK_PATH,
|
|
22
|
-
THIRD_PARTY_SCRIPT_ORIGINS,
|
|
23
|
-
TURNSTILE_SCRIPT_ORIGIN,
|
|
24
|
-
TURNSTILE_SCRIPT_URL
|
|
25
|
-
} from "./chunk-ZOF22TJA.js";
|
|
26
|
+
} from "./chunk-4GKSSM5N.js";
|
|
27
|
+
import "./chunk-3T7UWKAH.js";
|
|
26
28
|
import {
|
|
27
29
|
evaluateShowWhen,
|
|
28
30
|
visibleQuestions
|
|
@@ -34,19 +36,43 @@ import {
|
|
|
34
36
|
mountIslandsWith,
|
|
35
37
|
readIslandProps
|
|
36
38
|
} from "./chunk-THMT43MV.js";
|
|
39
|
+
import "./chunk-2CZFJOKK.js";
|
|
40
|
+
import "./chunk-ZNH6TSYP.js";
|
|
41
|
+
import "./chunk-IOC6QLB7.js";
|
|
42
|
+
import "./chunk-S3ZQQOQT.js";
|
|
37
43
|
import {
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
BPOINT_SCRIPT_ORIGIN,
|
|
45
|
+
BPOINT_SCRIPT_URL,
|
|
46
|
+
CONSULT_CHUNK_PATH,
|
|
47
|
+
THIRD_PARTY_SCRIPT_ORIGINS,
|
|
48
|
+
TURNSTILE_SCRIPT_ORIGIN,
|
|
49
|
+
TURNSTILE_SCRIPT_URL
|
|
50
|
+
} from "./chunk-ZOF22TJA.js";
|
|
51
|
+
import "./chunk-UTAMB2SK.js";
|
|
40
52
|
import {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
relativeLuminance
|
|
46
|
-
} from "./chunk-LCHW6XF4.js";
|
|
53
|
+
fetchStoreCatalog,
|
|
54
|
+
normalizeCatalogResponse,
|
|
55
|
+
storeCatalogPath
|
|
56
|
+
} from "./chunk-WQSJ46TP.js";
|
|
47
57
|
import {
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
createStoreClient,
|
|
59
|
+
formatMoney
|
|
60
|
+
} from "./chunk-7BUDUYXN.js";
|
|
61
|
+
import {
|
|
62
|
+
addToCart,
|
|
63
|
+
adjustCartQuantity,
|
|
64
|
+
cartItemCount,
|
|
65
|
+
cartToWireLines,
|
|
66
|
+
clearCart,
|
|
67
|
+
mutateCart,
|
|
68
|
+
readCart,
|
|
69
|
+
removeFromCart,
|
|
70
|
+
setCartQuantity,
|
|
71
|
+
subscribeToCart
|
|
72
|
+
} from "./chunk-4NF7SSIX.js";
|
|
73
|
+
import {
|
|
74
|
+
createPortalClient
|
|
75
|
+
} from "./chunk-FZ4WKWIE.js";
|
|
50
76
|
import "./chunk-MLKGABMK.js";
|
|
51
77
|
|
|
52
78
|
// src/tokens.tsx
|
|
@@ -408,13 +434,14 @@ function Store({
|
|
|
408
434
|
storeApiOrigin,
|
|
409
435
|
title,
|
|
410
436
|
columns,
|
|
437
|
+
hideCartLink,
|
|
411
438
|
className
|
|
412
439
|
}) {
|
|
413
440
|
return /* @__PURE__ */ jsxs5(
|
|
414
441
|
Island,
|
|
415
442
|
{
|
|
416
443
|
name: "store",
|
|
417
|
-
props: { categoryHandle, productHandle, storeApiOrigin, title, columns },
|
|
444
|
+
props: { categoryHandle, productHandle, storeApiOrigin, title, columns, hideCartLink },
|
|
418
445
|
className: ["sk-store", className].filter(Boolean).join(" "),
|
|
419
446
|
children: [
|
|
420
447
|
/* @__PURE__ */ jsx6("h2", { className: "sk-store__heading", children: title ?? "Shop" }),
|
|
@@ -441,8 +468,28 @@ function Cart({ storeApiOrigin, className }) {
|
|
|
441
468
|
);
|
|
442
469
|
}
|
|
443
470
|
|
|
471
|
+
// src/cart-button.tsx
|
|
472
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
473
|
+
function CartButton({
|
|
474
|
+
storeApiOrigin,
|
|
475
|
+
label,
|
|
476
|
+
cartHref,
|
|
477
|
+
checkoutHref,
|
|
478
|
+
className
|
|
479
|
+
}) {
|
|
480
|
+
return /* @__PURE__ */ jsx8(
|
|
481
|
+
Island,
|
|
482
|
+
{
|
|
483
|
+
name: "cart-button",
|
|
484
|
+
props: { storeApiOrigin, label, cartHref, checkoutHref },
|
|
485
|
+
className: ["sk-cart-button", className].filter(Boolean).join(" "),
|
|
486
|
+
children: /* @__PURE__ */ jsx8("a", { className: "sk-cart-button__trigger", href: cartHref ?? "/cart", children: label ?? "Cart" })
|
|
487
|
+
}
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
444
491
|
// src/checkout-block.tsx
|
|
445
|
-
import { jsx as
|
|
492
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
446
493
|
function Checkout({
|
|
447
494
|
storeApiOrigin,
|
|
448
495
|
ordersHref,
|
|
@@ -456,15 +503,15 @@ function Checkout({
|
|
|
456
503
|
props: { storeApiOrigin, ordersHref, completionHref },
|
|
457
504
|
className: ["sk-checkout", className].filter(Boolean).join(" "),
|
|
458
505
|
children: [
|
|
459
|
-
/* @__PURE__ */
|
|
460
|
-
/* @__PURE__ */
|
|
506
|
+
/* @__PURE__ */ jsx9("h2", { className: "sk-checkout__heading", children: "Checkout" }),
|
|
507
|
+
/* @__PURE__ */ jsx9("p", { className: "sk-checkout__placeholder", children: "Checkout needs JavaScript to load." })
|
|
461
508
|
]
|
|
462
509
|
}
|
|
463
510
|
);
|
|
464
511
|
}
|
|
465
512
|
|
|
466
513
|
// src/index.ts
|
|
467
|
-
var WEBSITE_KIT_VERSION = "0.
|
|
514
|
+
var WEBSITE_KIT_VERSION = "0.2.8";
|
|
468
515
|
export {
|
|
469
516
|
BPOINT_SCRIPT_ORIGIN,
|
|
470
517
|
BPOINT_SCRIPT_URL,
|
|
@@ -472,6 +519,7 @@ export {
|
|
|
472
519
|
Button,
|
|
473
520
|
CONSULT_CHUNK_PATH,
|
|
474
521
|
Cart,
|
|
522
|
+
CartButton,
|
|
475
523
|
CertificateFunnel,
|
|
476
524
|
Checkout,
|
|
477
525
|
Container,
|
|
@@ -498,19 +546,33 @@ export {
|
|
|
498
546
|
ThemeProvider,
|
|
499
547
|
WEBSITE_KIT_VERSION,
|
|
500
548
|
WebsiteShell,
|
|
549
|
+
addToCart,
|
|
550
|
+
adjustCartQuantity,
|
|
551
|
+
cartItemCount,
|
|
552
|
+
cartToWireLines,
|
|
553
|
+
clearCart,
|
|
501
554
|
contrastRatio,
|
|
502
555
|
createPortalClient,
|
|
503
556
|
createStoreClient,
|
|
504
557
|
defaultTheme,
|
|
505
558
|
deriveForeground,
|
|
506
559
|
evaluateShowWhen,
|
|
560
|
+
fetchStoreCatalog,
|
|
561
|
+
formatMoney,
|
|
507
562
|
mountIslands,
|
|
508
563
|
mountIslandsWith,
|
|
564
|
+
mutateCart,
|
|
565
|
+
normalizeCatalogResponse,
|
|
509
566
|
parseHexColor,
|
|
510
567
|
patientSurfaceTheme,
|
|
568
|
+
readCart,
|
|
511
569
|
readIslandProps,
|
|
512
570
|
relativeLuminance,
|
|
571
|
+
removeFromCart,
|
|
513
572
|
resolveTheme,
|
|
573
|
+
setCartQuantity,
|
|
574
|
+
storeCatalogPath,
|
|
575
|
+
subscribeToCart,
|
|
514
576
|
themeToCssVars,
|
|
515
577
|
usePortalClient,
|
|
516
578
|
usePortalSession,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { b as CartButtonProps } from '../cart-button-BCLFittB.js';
|
|
3
|
+
|
|
4
|
+
declare function CartButtonClient({ storeApiOrigin, label, cartHref, checkoutHref, }: CartButtonProps): React.ReactElement;
|
|
5
|
+
type CartDrawerProps = {
|
|
6
|
+
open: boolean;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
/** PatientOS patient/API origin. Omitted keeps the same-origin contract. */
|
|
9
|
+
storeApiOrigin?: string;
|
|
10
|
+
cartHref?: string;
|
|
11
|
+
checkoutHref?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The slide-over cart. Mounted always, INERT until `open` — that is what keeps the
|
|
15
|
+
* quote request lazy while still letting the hooks run unconditionally.
|
|
16
|
+
*/
|
|
17
|
+
declare function CartDrawer({ open, onClose, storeApiOrigin, cartHref, checkoutHref, }: CartDrawerProps): React.ReactElement | null;
|
|
18
|
+
|
|
19
|
+
export { CartButtonClient, CartDrawer, type CartDrawerProps };
|