@absolutejs/commerce 0.2.1-beta.0 → 0.3.0-beta.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.
@@ -3,6 +3,8 @@ export type CartStore<T> = {
3
3
  write(items: T[]): void;
4
4
  add(item: T): void;
5
5
  clear(): void;
6
+ subscribe(listener: () => void): () => void;
7
+ getSnapshot(): T[];
6
8
  };
7
9
  /**
8
10
  * Create a cart store for a localStorage key. Pass `normalize` to migrate or
@@ -1,10 +1,9 @@
1
1
  // src/client/cartStore.ts
2
+ var EMPTY = [];
2
3
  var createCartStore = (key, normalize) => {
3
- const read = () => {
4
- if (typeof window === "undefined")
5
- return [];
4
+ const eventName = `commerce-cart:${key}`;
5
+ const parse = (raw) => {
6
6
  try {
7
- const raw = window.localStorage.getItem(key);
8
7
  const parsed = raw ? JSON.parse(raw) : [];
9
8
  if (normalize)
10
9
  return normalize(parsed);
@@ -13,10 +12,32 @@ var createCartStore = (key, normalize) => {
13
12
  return [];
14
13
  }
15
14
  };
15
+ const read = () => {
16
+ if (typeof window === "undefined")
17
+ return [];
18
+ return parse(window.localStorage.getItem(key));
19
+ };
20
+ let lastRaw = null;
21
+ let cache = EMPTY;
22
+ const getSnapshot = () => {
23
+ if (typeof window === "undefined")
24
+ return EMPTY;
25
+ const raw = window.localStorage.getItem(key) ?? "";
26
+ if (raw !== lastRaw) {
27
+ lastRaw = raw;
28
+ cache = parse(raw);
29
+ }
30
+ return cache;
31
+ };
32
+ const announce = () => {
33
+ if (typeof window !== "undefined")
34
+ window.dispatchEvent(new Event(eventName));
35
+ };
16
36
  const write = (items) => {
17
37
  if (typeof window === "undefined")
18
38
  return;
19
39
  window.localStorage.setItem(key, JSON.stringify(items));
40
+ announce();
20
41
  };
21
42
  return {
22
43
  add(item) {
@@ -26,8 +47,26 @@ var createCartStore = (key, normalize) => {
26
47
  if (typeof window === "undefined")
27
48
  return;
28
49
  window.localStorage.removeItem(key);
50
+ announce();
29
51
  },
52
+ getSnapshot,
30
53
  read,
54
+ subscribe(listener) {
55
+ if (typeof window === "undefined")
56
+ return () => {
57
+ return;
58
+ };
59
+ const onStorage = (event) => {
60
+ if (event.key === key)
61
+ listener();
62
+ };
63
+ window.addEventListener(eventName, listener);
64
+ window.addEventListener("storage", onStorage);
65
+ return () => {
66
+ window.removeEventListener(eventName, listener);
67
+ window.removeEventListener("storage", onStorage);
68
+ };
69
+ },
31
70
  write
32
71
  };
33
72
  };
@@ -0,0 +1,8 @@
1
+ import type { CartStore } from '../client/cartStore';
2
+ /** Live cart items for a store — re-renders on add/clear and cross-tab changes. */
3
+ export declare const useCart: <T>(store: CartStore<T>) => T[];
4
+ /**
5
+ * Live derived value over the cart (e.g. item count, subtotal). `select` runs
6
+ * on the current items each render.
7
+ */
8
+ export declare const useCartValue: <T, V>(store: CartStore<T>, select: (items: T[]) => V) => V;
@@ -0,0 +1,10 @@
1
+ // @bun
2
+ // src/react/index.ts
3
+ import { useSyncExternalStore } from "react";
4
+ var EMPTY = [];
5
+ var useCart = (store) => useSyncExternalStore(store.subscribe, store.getSnapshot, () => EMPTY);
6
+ var useCartValue = (store, select) => select(useCart(store));
7
+ export {
8
+ useCartValue,
9
+ useCart
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/commerce",
3
- "version": "0.2.1-beta.0",
3
+ "version": "0.3.0-beta.0",
4
4
  "description": "Provider-agnostic commerce primitives (cart, orders, fulfillment, shipping) for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,6 +28,11 @@
28
28
  "import": "./dist/client/index.js",
29
29
  "types": "./dist/client/index.d.ts"
30
30
  },
31
+ "./react": {
32
+ "browser": "./dist/react/index.js",
33
+ "import": "./dist/react/index.js",
34
+ "types": "./dist/react/index.d.ts"
35
+ },
31
36
  "./drizzle": {
32
37
  "import": "./dist/drizzle/index.js",
33
38
  "types": "./dist/drizzle/index.d.ts",
@@ -37,22 +42,28 @@
37
42
  "license": "BSL-1.1",
38
43
  "author": "Alex Kahn",
39
44
  "scripts": {
40
- "build": "rm -rf dist && bun build ./src/index.ts ./src/drizzle/index.ts --outdir dist --target bun --external drizzle-orm && bun build ./src/client/index.ts --outdir dist/client --target browser --format esm && tsc --emitDeclarationOnly --project tsconfig.json",
45
+ "build": "rm -rf dist && bun build ./src/index.ts ./src/drizzle/index.ts ./src/react/index.ts --outdir dist --target bun --external drizzle-orm --external react && bun build ./src/client/index.ts --outdir dist/client --target browser --format esm && tsc --emitDeclarationOnly --project tsconfig.json",
41
46
  "format": "prettier --write \"./**/*.{js,ts,json,md}\"",
42
47
  "release": "bun run build && bun publish --tag beta",
43
48
  "typecheck": "tsc --noEmit"
44
49
  },
45
50
  "peerDependencies": {
46
- "drizzle-orm": ">=0.30.0"
51
+ "drizzle-orm": ">=0.30.0",
52
+ "react": ">=18.0.0"
47
53
  },
48
54
  "peerDependenciesMeta": {
49
55
  "drizzle-orm": {
50
56
  "optional": true
57
+ },
58
+ "react": {
59
+ "optional": true
51
60
  }
52
61
  },
53
62
  "devDependencies": {
54
63
  "@types/bun": "1.3.9",
64
+ "@types/react": "^19.0.0",
55
65
  "drizzle-orm": "^0.44.0",
66
+ "react": "^19.0.0",
56
67
  "typescript": "^5.9.3"
57
68
  }
58
69
  }