@patientos/website-kit 0.2.7 → 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.
@@ -18,7 +18,7 @@ import {
18
18
  } from "./chunk-S3ZQQOQT.js";
19
19
  import {
20
20
  StoreClient
21
- } from "./chunk-673YEXAI.js";
21
+ } from "./chunk-UTAMB2SK.js";
22
22
 
23
23
  // src/islands-registry.tsx
24
24
  var ISLANDS = {
@@ -17,6 +17,29 @@ import {
17
17
  import * as React from "react";
18
18
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
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
+ }
20
43
  function StoreClient({
21
44
  categoryHandle,
22
45
  productHandle,
@@ -70,6 +93,13 @@ function StoreClient({
70
93
  }
71
94
  const gridStyle = columns ? { "--sk-store-columns": columns } : void 0;
72
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,
73
103
  /* @__PURE__ */ jsxs("div", { className: "sk-store__header", children: [
74
104
  /* @__PURE__ */ jsx("h2", { className: "sk-store__heading", children: title ?? "Shop" }),
75
105
  hideCartLink ? null : /* @__PURE__ */ jsxs("a", { className: "sk-store__cart-link", href: "/cart", children: [
@@ -99,10 +129,26 @@ function StoreCard({ product }) {
99
129
  const [addFeedback, setAddFeedback] = React.useState(null);
100
130
  const variant = product.variants.find((v) => v.id === variantId) ?? product.variants[0];
101
131
  const image = product.thumbnailUrl ?? product.images[0]?.url ?? null;
102
- async function onAdd() {
103
- const result = await addToCart(variant.id, 1);
132
+ const addRef = React.useRef(null);
133
+ const add = React.useCallback(async (id) => {
134
+ const result = await addToCart(id, 1);
104
135
  setAddFeedback(result.status);
105
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);
106
152
  }
107
153
  return /* @__PURE__ */ jsxs("li", { className: "sk-store__card", children: [
108
154
  /* @__PURE__ */ jsxs("a", { className: "sk-store__card-link", href: `/store/${product.handle}`, children: [
@@ -151,7 +197,10 @@ function StoreCard({ product }) {
151
197
  {
152
198
  type: "button",
153
199
  className: "sk-store__add",
154
- onClick: () => void onAdd(),
200
+ ref: addRef,
201
+ "data-sk-store-add": "",
202
+ "data-sk-store-variant": variant.id,
203
+ onClick: (event) => onAdd(event.nativeEvent),
155
204
  disabled: !variant.inStock,
156
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"
157
206
  }
@@ -160,5 +209,6 @@ function StoreCard({ product }) {
160
209
  }
161
210
 
162
211
  export {
212
+ STORE_PREHYDRATION_SCRIPT,
163
213
  StoreClient
164
214
  };
package/dist/index.d.ts CHANGED
@@ -217,6 +217,6 @@ interface PortalSession {
217
217
  */
218
218
  declare function usePortalSession(): PortalSession;
219
219
 
220
- declare const WEBSITE_KIT_VERSION = "0.2.7";
220
+ declare const WEBSITE_KIT_VERSION = "0.2.8";
221
221
 
222
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
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  ISLANDS,
13
13
  mountIslands
14
- } from "./chunk-HYXTDUP2.js";
14
+ } from "./chunk-HTVKKLWI.js";
15
15
  import {
16
16
  PortalAccount,
17
17
  PortalPanel,
@@ -48,7 +48,7 @@ import {
48
48
  TURNSTILE_SCRIPT_ORIGIN,
49
49
  TURNSTILE_SCRIPT_URL
50
50
  } from "./chunk-ZOF22TJA.js";
51
- import "./chunk-673YEXAI.js";
51
+ import "./chunk-UTAMB2SK.js";
52
52
  import {
53
53
  fetchStoreCatalog,
54
54
  normalizeCatalogResponse,
@@ -511,7 +511,7 @@ function Checkout({
511
511
  }
512
512
 
513
513
  // src/index.ts
514
- var WEBSITE_KIT_VERSION = "0.2.7";
514
+ var WEBSITE_KIT_VERSION = "0.2.8";
515
515
  export {
516
516
  BPOINT_SCRIPT_ORIGIN,
517
517
  BPOINT_SCRIPT_URL,
@@ -2,7 +2,7 @@ import {
2
2
  CheckoutClient
3
3
  } from "../chunk-S3ZQQOQT.js";
4
4
  import "../chunk-ZOF22TJA.js";
5
- import "../chunk-673YEXAI.js";
5
+ import "../chunk-UTAMB2SK.js";
6
6
  import "../chunk-WQSJ46TP.js";
7
7
  import "../chunk-7BUDUYXN.js";
8
8
  import "../chunk-4NF7SSIX.js";
@@ -17,6 +17,14 @@ type StoreClientProps = StoreProps & {
17
17
  */
18
18
  initialCatalog?: StoreCatalog | null;
19
19
  };
20
+ /**
21
+ * The inline script rendered into SERVER HTML beside a seeded grid.
22
+ *
23
+ * Deliberately tiny, dependency-free and idempotent (several store islands can share
24
+ * one page). It only records — it never writes the cart, because the cart writer is
25
+ * async, lock-serialised, and lives in the bundle that has not arrived yet.
26
+ */
27
+ declare const STORE_PREHYDRATION_SCRIPT = "(function(){\nif(window.__skStoreArmed)return;window.__skStoreArmed=1;\ndocument.addEventListener('click',function(e){\nvar t=e.target;if(!t||!t.closest)return;\nvar b=t.closest('button[data-sk-store-add]');if(!b||b.disabled)return;\nvar c=b.closest('.sk-store__card');var s=c?c.querySelector('select'):null;\nvar v=(s&&s.value)||b.getAttribute('data-sk-store-variant');if(!v)return;\n(b.__skStoreQueue||(b.__skStoreQueue=[])).push({variantId:v,event:e});\n},true);\n})();";
20
28
  declare function StoreClient({ categoryHandle, productHandle, storeApiOrigin, title, columns, hideCartLink, initialCatalog, }: StoreClientProps): React.ReactElement;
21
29
 
22
- export { StoreClient, type StoreClientProps };
30
+ export { STORE_PREHYDRATION_SCRIPT, StoreClient, type StoreClientProps };
@@ -1,6 +1,7 @@
1
1
  import {
2
+ STORE_PREHYDRATION_SCRIPT,
2
3
  StoreClient
3
- } from "../chunk-673YEXAI.js";
4
+ } from "../chunk-UTAMB2SK.js";
4
5
  import "../chunk-WQSJ46TP.js";
5
6
  import {
6
7
  formatMoney
@@ -9,6 +10,7 @@ import "../chunk-4NF7SSIX.js";
9
10
  import "../chunk-FZ4WKWIE.js";
10
11
  import "../chunk-MLKGABMK.js";
11
12
  export {
13
+ STORE_PREHYDRATION_SCRIPT,
12
14
  StoreClient,
13
15
  formatMoney
14
16
  };
@@ -20,7 +20,7 @@ import {
20
20
  import "./chunk-ZOF22TJA.js";
21
21
  import {
22
22
  StoreClient
23
- } from "./chunk-673YEXAI.js";
23
+ } from "./chunk-UTAMB2SK.js";
24
24
  import "./chunk-WQSJ46TP.js";
25
25
  import "./chunk-7BUDUYXN.js";
26
26
  import "./chunk-4NF7SSIX.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ISLANDS,
3
3
  mountIslands
4
- } from "./chunk-HYXTDUP2.js";
4
+ } from "./chunk-HTVKKLWI.js";
5
5
  import "./chunk-4GKSSM5N.js";
6
6
  import "./chunk-3T7UWKAH.js";
7
7
  import "./chunk-QDO3SJWR.js";
@@ -11,7 +11,7 @@ import "./chunk-ZNH6TSYP.js";
11
11
  import "./chunk-IOC6QLB7.js";
12
12
  import "./chunk-S3ZQQOQT.js";
13
13
  import "./chunk-ZOF22TJA.js";
14
- import "./chunk-673YEXAI.js";
14
+ import "./chunk-UTAMB2SK.js";
15
15
  import "./chunk-WQSJ46TP.js";
16
16
  import "./chunk-7BUDUYXN.js";
17
17
  import "./chunk-4NF7SSIX.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patientos/website-kit",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "PatientOS clinic website components and patient-facing interactive islands.",
5
5
  "type": "module",
6
6
  "sideEffects": [