@cmssy/react 0.1.8 → 0.2.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.
package/dist/client.js CHANGED
@@ -1,8 +1,11 @@
1
1
  "use client";
2
- import { useState, useRef, useEffect, useMemo, createElement } from 'react';
2
+ import { createContext, useState, useRef, useEffect, useMemo, useCallback, useContext, createElement } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  // src/registry.ts
6
+ function defineBlock(def) {
7
+ return def;
8
+ }
6
9
  function buildBlockMap(blocks) {
7
10
  const map = /* @__PURE__ */ Object.create(null);
8
11
  for (const block of blocks) map[block.type] = block.component;
@@ -745,5 +748,657 @@ function CmssyLazyLayout({ load, ...props }) {
745
748
  if (!blocks) return null;
746
749
  return /* @__PURE__ */ jsx(CmssyEditableLayout, { ...props, blocks });
747
750
  }
751
+ var CmssyAuthContext = createContext(null);
752
+ function CmssyAuthProvider({
753
+ children,
754
+ basePath = "/api/cmssy/auth",
755
+ initialUser
756
+ }) {
757
+ const seeded = initialUser !== void 0;
758
+ const [user, setUser] = useState(initialUser ?? null);
759
+ const [loading, setLoading] = useState(!seeded);
760
+ const generation = useRef(0);
761
+ const base = useMemo(() => basePath.replace(/\/+$/, ""), [basePath]);
762
+ const commitUser = useCallback((next) => {
763
+ generation.current += 1;
764
+ setUser(next);
765
+ }, []);
766
+ const fetchUser = useCallback(async () => {
767
+ try {
768
+ const res = await fetch(`${base}/me`, {
769
+ credentials: "same-origin",
770
+ cache: "no-store"
771
+ });
772
+ const data = await res.json();
773
+ return data.user ?? null;
774
+ } catch {
775
+ return null;
776
+ }
777
+ }, [base]);
778
+ useEffect(() => {
779
+ if (seeded) return;
780
+ const gen = generation.current;
781
+ void (async () => {
782
+ const next = await fetchUser();
783
+ if (gen === generation.current) {
784
+ setUser(next);
785
+ setLoading(false);
786
+ }
787
+ })();
788
+ }, [fetchUser, seeded]);
789
+ const postAction = useCallback(
790
+ async (action, body) => {
791
+ const res = await fetch(`${base}/${action}`, {
792
+ method: "POST",
793
+ credentials: "same-origin",
794
+ headers: { "content-type": "application/json" },
795
+ body: JSON.stringify(body)
796
+ });
797
+ return await res.json();
798
+ },
799
+ [base]
800
+ );
801
+ const signIn = useCallback(
802
+ async (identity, password) => {
803
+ const data = await postAction("sign-in", { identity, password });
804
+ if (data.ok && data.user) commitUser(data.user);
805
+ return { ok: Boolean(data.ok), message: data.message };
806
+ },
807
+ [postAction, commitUser]
808
+ );
809
+ const register = useCallback(
810
+ async (identity, password, fields2) => {
811
+ const data = await postAction("register", {
812
+ identity,
813
+ password,
814
+ fields: fields2 ?? {}
815
+ });
816
+ return { ok: Boolean(data.ok), message: data.message };
817
+ },
818
+ [postAction]
819
+ );
820
+ const signOut = useCallback(async () => {
821
+ try {
822
+ await postAction("sign-out", {});
823
+ } finally {
824
+ commitUser(null);
825
+ }
826
+ }, [postAction, commitUser]);
827
+ const refresh = useCallback(async () => {
828
+ const gen = generation.current;
829
+ const next = await fetchUser();
830
+ if (gen === generation.current) setUser(next);
831
+ }, [fetchUser]);
832
+ const value = useMemo(
833
+ () => ({ user, loading, signIn, register, signOut, refresh }),
834
+ [user, loading, signIn, register, signOut, refresh]
835
+ );
836
+ return /* @__PURE__ */ jsx(CmssyAuthContext.Provider, { value, children });
837
+ }
838
+ function useCmssyUser() {
839
+ const ctx = useContext(CmssyAuthContext);
840
+ if (!ctx) {
841
+ throw new Error("useCmssyUser must be used within <CmssyAuthProvider>");
842
+ }
843
+ return ctx;
844
+ }
845
+ var CmssyCommerceContext = createContext(null);
846
+ function CmssyCommerceProvider({
847
+ children,
848
+ basePath = "/api/cmssy/cart"
849
+ }) {
850
+ const base = useMemo(() => basePath.replace(/\/+$/, ""), [basePath]);
851
+ const generation = useRef(0);
852
+ const [cart, setCart] = useState(null);
853
+ const [loading, setLoading] = useState(true);
854
+ const [error, setError] = useState(null);
855
+ const post = useCallback(
856
+ async (action, body) => {
857
+ const res = await fetch(`${base}/${action}`, {
858
+ method: "POST",
859
+ credentials: "same-origin",
860
+ headers: { "content-type": "application/json" },
861
+ body: JSON.stringify(body)
862
+ });
863
+ const data = await res.json().catch(() => ({}));
864
+ if (!res.ok) {
865
+ throw new Error(
866
+ typeof data.message === "string" ? data.message : "Commerce request failed"
867
+ );
868
+ }
869
+ return data;
870
+ },
871
+ [base]
872
+ );
873
+ const runCart = useCallback(
874
+ async (action, body) => {
875
+ const gen = ++generation.current;
876
+ setError(null);
877
+ try {
878
+ const data = await post(action, body);
879
+ if (gen === generation.current) setCart(data.cart);
880
+ } catch (err) {
881
+ if (gen === generation.current) {
882
+ setError(
883
+ err instanceof Error ? err.message : "Commerce request failed"
884
+ );
885
+ }
886
+ throw err;
887
+ }
888
+ },
889
+ [post]
890
+ );
891
+ const refresh = useCallback(async () => {
892
+ setLoading(true);
893
+ try {
894
+ await runCart("cart", {});
895
+ } catch {
896
+ return;
897
+ } finally {
898
+ setLoading(false);
899
+ }
900
+ }, [runCart]);
901
+ useEffect(() => {
902
+ void refresh();
903
+ }, [refresh]);
904
+ const addToCart = useCallback(
905
+ (recordId, quantity = 1, options) => runCart("add", {
906
+ recordId,
907
+ quantity,
908
+ variantSelections: options?.variantSelections,
909
+ notes: options?.notes
910
+ }),
911
+ [runCart]
912
+ );
913
+ const updateItem = useCallback(
914
+ (itemId, quantity) => runCart("update", { itemId, quantity }),
915
+ [runCart]
916
+ );
917
+ const removeItem = useCallback(
918
+ (itemId) => runCart("remove", { itemId }),
919
+ [runCart]
920
+ );
921
+ const clearCart = useCallback(() => runCart("clear", {}), [runCart]);
922
+ const applyDiscount = useCallback(
923
+ (code) => runCart("apply-discount", { code }),
924
+ [runCart]
925
+ );
926
+ const removeDiscount = useCallback(
927
+ () => runCart("remove-discount", {}),
928
+ [runCart]
929
+ );
930
+ const checkout = useCallback(
931
+ async (customerEmail) => {
932
+ const gen = ++generation.current;
933
+ setError(null);
934
+ try {
935
+ const data = await post("checkout", {
936
+ customerEmail
937
+ });
938
+ if (gen === generation.current) setCart(null);
939
+ return data.order;
940
+ } catch (err) {
941
+ if (gen === generation.current) {
942
+ setError(err instanceof Error ? err.message : "Checkout failed");
943
+ }
944
+ throw err;
945
+ }
946
+ },
947
+ [post]
948
+ );
949
+ const fetchProduct = useCallback(
950
+ async (modelSlug, filter) => {
951
+ const data = await post("product", {
952
+ modelSlug,
953
+ filter
954
+ });
955
+ return data.product;
956
+ },
957
+ [post]
958
+ );
959
+ const value = useMemo(
960
+ () => ({
961
+ cart,
962
+ loading,
963
+ error,
964
+ addToCart,
965
+ updateItem,
966
+ removeItem,
967
+ clearCart,
968
+ applyDiscount,
969
+ removeDiscount,
970
+ checkout,
971
+ refresh,
972
+ fetchProduct
973
+ }),
974
+ [
975
+ cart,
976
+ loading,
977
+ error,
978
+ addToCart,
979
+ updateItem,
980
+ removeItem,
981
+ clearCart,
982
+ applyDiscount,
983
+ removeDiscount,
984
+ checkout,
985
+ refresh,
986
+ fetchProduct
987
+ ]
988
+ );
989
+ return /* @__PURE__ */ jsx(CmssyCommerceContext.Provider, { value, children });
990
+ }
991
+ function useCart() {
992
+ const ctx = useContext(CmssyCommerceContext);
993
+ if (!ctx) {
994
+ throw new Error("useCart must be used within <CmssyCommerceProvider>");
995
+ }
996
+ return ctx;
997
+ }
998
+
999
+ // src/fields.ts
1000
+ function control(type) {
1001
+ return (opts = {}) => ({
1002
+ type,
1003
+ label: opts.label ?? "",
1004
+ ...opts
1005
+ });
1006
+ }
1007
+ var fields = {
1008
+ singleLine: control("singleLine"),
1009
+ multiLine: control("multiLine"),
1010
+ richText: control("richText"),
1011
+ numeric: control("numeric"),
1012
+ date: control("date"),
1013
+ media: control("media"),
1014
+ link: control("link"),
1015
+ select: control("select"),
1016
+ multiselect: control("multiselect"),
1017
+ boolean: control("boolean"),
1018
+ color: control("color"),
1019
+ repeater: control("repeater")
1020
+ };
1021
+
1022
+ // src/commerce/money.ts
1023
+ var ZERO_DECIMAL = /* @__PURE__ */ new Set([
1024
+ "BIF",
1025
+ "CLP",
1026
+ "DJF",
1027
+ "GNF",
1028
+ "JPY",
1029
+ "KMF",
1030
+ "KRW",
1031
+ "MGA",
1032
+ "PYG",
1033
+ "RWF",
1034
+ "UGX",
1035
+ "VND",
1036
+ "VUV",
1037
+ "XAF",
1038
+ "XOF",
1039
+ "XPF"
1040
+ ]);
1041
+ var THREE_DECIMAL = /* @__PURE__ */ new Set([
1042
+ "BHD",
1043
+ "IQD",
1044
+ "JOD",
1045
+ "KWD",
1046
+ "LYD",
1047
+ "OMR",
1048
+ "TND"
1049
+ ]);
1050
+ function fractionDigits(currency) {
1051
+ const code = currency.toUpperCase();
1052
+ if (ZERO_DECIMAL.has(code)) return 0;
1053
+ if (THREE_DECIMAL.has(code)) return 3;
1054
+ return 2;
1055
+ }
1056
+ function fromMinorUnits(minor, currency) {
1057
+ return minor / 10 ** fractionDigits(currency);
1058
+ }
1059
+ function formatPrice(minor, currency) {
1060
+ if (!Number.isFinite(minor)) return "";
1061
+ const code = currency ?? "USD";
1062
+ const amount = fromMinorUnits(minor, code);
1063
+ try {
1064
+ return new Intl.NumberFormat(void 0, {
1065
+ style: "currency",
1066
+ currency: code
1067
+ }).format(amount);
1068
+ } catch {
1069
+ return `${amount.toFixed(fractionDigits(code))} ${code}`;
1070
+ }
1071
+ }
1072
+ function deriveAxes(variants) {
1073
+ const axes = /* @__PURE__ */ new Map();
1074
+ for (const variant of variants) {
1075
+ for (const option of variant.selectedOptions) {
1076
+ if (!axes.has(option.name)) axes.set(option.name, /* @__PURE__ */ new Set());
1077
+ axes.get(option.name).add(option.value);
1078
+ }
1079
+ }
1080
+ return [...axes.entries()].map(([name, values]) => ({
1081
+ name,
1082
+ values: [...values]
1083
+ }));
1084
+ }
1085
+ function matchVariant(variants, selections) {
1086
+ return variants.find(
1087
+ (variant) => variant.selectedOptions.every(
1088
+ (opt) => selections[opt.name] === opt.value
1089
+ )
1090
+ ) ?? null;
1091
+ }
1092
+ function ProductComponent({ content }) {
1093
+ const c = content;
1094
+ const { fetchProduct, addToCart } = useCart();
1095
+ const [product, setProduct] = useState(null);
1096
+ const [loading, setLoading] = useState(true);
1097
+ const [selections, setSelections] = useState({});
1098
+ const [adding, setAdding] = useState(false);
1099
+ const [added, setAdded] = useState(false);
1100
+ const [addError, setAddError] = useState(null);
1101
+ const modelSlug = c.modelSlug ?? "products";
1102
+ const slugField = c.slugField ?? "slug";
1103
+ const slug = c.slug ?? "";
1104
+ useEffect(() => {
1105
+ let active = true;
1106
+ setLoading(true);
1107
+ void (async () => {
1108
+ try {
1109
+ const result = slug ? await fetchProduct(modelSlug, { [slugField]: slug }) : null;
1110
+ if (active) setProduct(result);
1111
+ } finally {
1112
+ if (active) setLoading(false);
1113
+ }
1114
+ })();
1115
+ return () => {
1116
+ active = false;
1117
+ };
1118
+ }, [fetchProduct, modelSlug, slugField, slug]);
1119
+ const axes = useMemo(
1120
+ () => product ? deriveAxes(product.variants) : [],
1121
+ [product]
1122
+ );
1123
+ const variant = useMemo(
1124
+ () => product ? matchVariant(product.variants, selections) : null,
1125
+ [product, selections]
1126
+ );
1127
+ if (loading) {
1128
+ return /* @__PURE__ */ jsx("div", { "data-cmssy-product": "loading", children: "Loading\u2026" });
1129
+ }
1130
+ if (!product) {
1131
+ return /* @__PURE__ */ jsx("div", { "data-cmssy-product": "not-found", children: "Product not found" });
1132
+ }
1133
+ const data = product.data;
1134
+ const name = String(data[c.nameField ?? "name"] ?? "");
1135
+ const imageUrl = c.imageField ? data[c.imageField] : null;
1136
+ const hasVariants = product.variants.length > 0;
1137
+ const currency = data.currency ?? "USD";
1138
+ const priceMinor = hasVariants ? variant?.price : Number(data[c.priceField ?? "price"] ?? 0);
1139
+ const showPrice = priceMinor != null && Number.isFinite(priceMinor);
1140
+ const allAxesSelected = axes.every((axis) => selections[axis.name]);
1141
+ const outOfStock = variant != null && variant.inventory != null && variant.inventory <= 0;
1142
+ const canAdd = hasVariants ? Boolean(variant) && !outOfStock : true;
1143
+ async function onAdd() {
1144
+ if (!product) return;
1145
+ setAdding(true);
1146
+ setAdded(false);
1147
+ setAddError(null);
1148
+ try {
1149
+ await addToCart(
1150
+ product.id,
1151
+ 1,
1152
+ hasVariants ? { variantSelections: selections } : void 0
1153
+ );
1154
+ setAdded(true);
1155
+ } catch (err) {
1156
+ setAddError(err instanceof Error ? err.message : "Could not add to cart");
1157
+ } finally {
1158
+ setAdding(false);
1159
+ }
1160
+ }
1161
+ return /* @__PURE__ */ jsxs("div", { "data-cmssy-product": product.id, children: [
1162
+ imageUrl ? /* @__PURE__ */ jsx("img", { src: imageUrl, alt: name }) : null,
1163
+ /* @__PURE__ */ jsx("h3", { "data-cmssy-product-name": true, children: name }),
1164
+ showPrice ? /* @__PURE__ */ jsx("p", { "data-cmssy-product-price": true, children: formatPrice(priceMinor, currency) }) : null,
1165
+ axes.map((axis) => /* @__PURE__ */ jsxs("label", { "data-cmssy-variant-axis": axis.name, children: [
1166
+ /* @__PURE__ */ jsx("span", { children: axis.name }),
1167
+ /* @__PURE__ */ jsxs(
1168
+ "select",
1169
+ {
1170
+ value: selections[axis.name] ?? "",
1171
+ onChange: (e) => setSelections((prev) => ({
1172
+ ...prev,
1173
+ [axis.name]: e.target.value
1174
+ })),
1175
+ children: [
1176
+ /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
1177
+ axis.values.map((v) => /* @__PURE__ */ jsx("option", { value: v, children: v }, v))
1178
+ ]
1179
+ }
1180
+ )
1181
+ ] }, axis.name)),
1182
+ /* @__PURE__ */ jsx(
1183
+ "button",
1184
+ {
1185
+ type: "button",
1186
+ onClick: onAdd,
1187
+ disabled: adding || !canAdd || hasVariants && !allAxesSelected,
1188
+ "data-cmssy-add-to-cart": true,
1189
+ children: adding ? "Adding\u2026" : outOfStock ? "Out of stock" : added ? "Added" : "Add to cart"
1190
+ }
1191
+ ),
1192
+ addError ? /* @__PURE__ */ jsx("p", { "data-cmssy-product-error": true, children: addError }) : null
1193
+ ] });
1194
+ }
1195
+ var productBlock = defineBlock({
1196
+ type: "product",
1197
+ label: "Product",
1198
+ category: "Commerce",
1199
+ props: {
1200
+ modelSlug: fields.singleLine({ label: "Model slug" }),
1201
+ slugField: fields.singleLine({ label: "Slug field" }),
1202
+ slug: fields.singleLine({ label: "Product slug" }),
1203
+ nameField: fields.singleLine({ label: "Name field" }),
1204
+ priceField: fields.singleLine({ label: "Price field" }),
1205
+ imageField: fields.singleLine({ label: "Image field" })
1206
+ },
1207
+ component: ProductComponent
1208
+ });
1209
+ function CartComponent() {
1210
+ const {
1211
+ cart,
1212
+ loading,
1213
+ error,
1214
+ updateItem,
1215
+ removeItem,
1216
+ applyDiscount,
1217
+ removeDiscount
1218
+ } = useCart();
1219
+ const [code, setCode] = useState("");
1220
+ const [busy, setBusy] = useState(false);
1221
+ if (loading) {
1222
+ return /* @__PURE__ */ jsx("div", { "data-cmssy-cart": "loading", children: "Loading\u2026" });
1223
+ }
1224
+ if (!cart || cart.items.length === 0) {
1225
+ return /* @__PURE__ */ jsx("div", { "data-cmssy-cart": "empty", children: "Your cart is empty." });
1226
+ }
1227
+ const currency = cart.currency ?? "USD";
1228
+ async function withBusy(fn) {
1229
+ setBusy(true);
1230
+ try {
1231
+ await fn();
1232
+ } catch {
1233
+ setBusy(false);
1234
+ } finally {
1235
+ setBusy(false);
1236
+ }
1237
+ }
1238
+ return /* @__PURE__ */ jsxs("div", { "data-cmssy-cart": cart.id, children: [
1239
+ error ? /* @__PURE__ */ jsx("p", { "data-cmssy-cart-error": true, children: error }) : null,
1240
+ /* @__PURE__ */ jsx("ul", { "data-cmssy-cart-items": true, children: cart.items.map((item) => /* @__PURE__ */ jsxs("li", { "data-cmssy-cart-item": item.id, children: [
1241
+ /* @__PURE__ */ jsx("span", { "data-cmssy-item-name": true, children: item.snapshot.name }),
1242
+ /* @__PURE__ */ jsx(
1243
+ "input",
1244
+ {
1245
+ type: "number",
1246
+ min: "1",
1247
+ value: item.quantity,
1248
+ disabled: busy,
1249
+ onChange: (e) => {
1250
+ const qty = Number(e.target.value);
1251
+ if (Number.isInteger(qty) && qty >= 1) {
1252
+ void withBusy(() => updateItem(item.id, qty));
1253
+ }
1254
+ },
1255
+ "data-cmssy-item-qty": true
1256
+ }
1257
+ ),
1258
+ /* @__PURE__ */ jsx("span", { "data-cmssy-item-price": true, children: formatPrice(item.snapshot.price * item.quantity, currency) }),
1259
+ /* @__PURE__ */ jsx(
1260
+ "button",
1261
+ {
1262
+ type: "button",
1263
+ disabled: busy,
1264
+ onClick: () => void withBusy(() => removeItem(item.id)),
1265
+ "data-cmssy-item-remove": true,
1266
+ children: "Remove"
1267
+ }
1268
+ )
1269
+ ] }, item.id)) }),
1270
+ /* @__PURE__ */ jsx("div", { "data-cmssy-cart-discount": true, children: cart.appliedDiscount ? /* @__PURE__ */ jsxs("p", { children: [
1271
+ /* @__PURE__ */ jsx("span", { children: cart.appliedDiscount.code }),
1272
+ /* @__PURE__ */ jsx(
1273
+ "button",
1274
+ {
1275
+ type: "button",
1276
+ disabled: busy,
1277
+ onClick: () => void withBusy(() => removeDiscount()),
1278
+ children: "Remove"
1279
+ }
1280
+ )
1281
+ ] }) : /* @__PURE__ */ jsxs("p", { children: [
1282
+ /* @__PURE__ */ jsx(
1283
+ "input",
1284
+ {
1285
+ type: "text",
1286
+ value: code,
1287
+ placeholder: "Discount code",
1288
+ onChange: (e) => setCode(e.target.value),
1289
+ disabled: busy
1290
+ }
1291
+ ),
1292
+ /* @__PURE__ */ jsx(
1293
+ "button",
1294
+ {
1295
+ type: "button",
1296
+ disabled: busy || !code.trim(),
1297
+ onClick: () => void withBusy(async () => {
1298
+ await applyDiscount(code.trim());
1299
+ setCode("");
1300
+ }),
1301
+ children: "Apply"
1302
+ }
1303
+ )
1304
+ ] }) }),
1305
+ /* @__PURE__ */ jsxs("dl", { "data-cmssy-cart-totals": true, children: [
1306
+ /* @__PURE__ */ jsxs("div", { children: [
1307
+ /* @__PURE__ */ jsx("dt", { children: "Subtotal" }),
1308
+ /* @__PURE__ */ jsx("dd", { children: formatPrice(cart.subtotal, currency) })
1309
+ ] }),
1310
+ /* @__PURE__ */ jsxs("div", { children: [
1311
+ /* @__PURE__ */ jsx("dt", { children: "Total" }),
1312
+ /* @__PURE__ */ jsx("dd", { "data-cmssy-cart-total": true, children: formatPrice(cart.discountedTotal, currency) })
1313
+ ] })
1314
+ ] })
1315
+ ] });
1316
+ }
1317
+ var cartBlock = defineBlock({
1318
+ type: "cart",
1319
+ label: "Cart",
1320
+ category: "Commerce",
1321
+ props: {},
1322
+ component: CartComponent
1323
+ });
1324
+ var EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
1325
+ function CheckoutComponent({ content }) {
1326
+ const c = content;
1327
+ const { cart, loading, checkout } = useCart();
1328
+ const [email, setEmail] = useState("");
1329
+ const [busy, setBusy] = useState(false);
1330
+ const [error, setError] = useState(null);
1331
+ const [order, setOrder] = useState(null);
1332
+ if (order) {
1333
+ return /* @__PURE__ */ jsxs("div", { "data-cmssy-checkout": "done", children: [
1334
+ /* @__PURE__ */ jsx("p", { children: c.successMessage ?? "Order placed - awaiting payment." }),
1335
+ /* @__PURE__ */ jsx("p", { "data-cmssy-order-id": true, children: order.id }),
1336
+ /* @__PURE__ */ jsx("p", { "data-cmssy-order-total": true, children: formatPrice(order.total, order.currency) })
1337
+ ] });
1338
+ }
1339
+ if (loading) {
1340
+ return /* @__PURE__ */ jsx("div", { "data-cmssy-checkout": "loading", children: "Loading\u2026" });
1341
+ }
1342
+ if (!cart || cart.items.length === 0) {
1343
+ return /* @__PURE__ */ jsx("div", { "data-cmssy-checkout": "empty", children: "Your cart is empty." });
1344
+ }
1345
+ const emailValid = EMAIL_RE.test(email.trim());
1346
+ async function onSubmit() {
1347
+ setBusy(true);
1348
+ setError(null);
1349
+ try {
1350
+ setOrder(await checkout(email.trim()));
1351
+ } catch (err) {
1352
+ setError(err instanceof Error ? err.message : "Checkout failed");
1353
+ } finally {
1354
+ setBusy(false);
1355
+ }
1356
+ }
1357
+ return /* @__PURE__ */ jsxs(
1358
+ "form",
1359
+ {
1360
+ "data-cmssy-checkout": cart.id,
1361
+ onSubmit: (e) => {
1362
+ e.preventDefault();
1363
+ if (emailValid && !busy) void onSubmit();
1364
+ },
1365
+ children: [
1366
+ error ? /* @__PURE__ */ jsx("p", { "data-cmssy-checkout-error": true, children: error }) : null,
1367
+ /* @__PURE__ */ jsxs("label", { children: [
1368
+ /* @__PURE__ */ jsx("span", { children: "Email" }),
1369
+ /* @__PURE__ */ jsx(
1370
+ "input",
1371
+ {
1372
+ type: "email",
1373
+ value: email,
1374
+ onChange: (e) => setEmail(e.target.value),
1375
+ required: true,
1376
+ "data-cmssy-checkout-email": true
1377
+ }
1378
+ )
1379
+ ] }),
1380
+ /* @__PURE__ */ jsx("p", { "data-cmssy-checkout-total": true, children: formatPrice(cart.discountedTotal, cart.currency ?? "USD") }),
1381
+ /* @__PURE__ */ jsx(
1382
+ "button",
1383
+ {
1384
+ type: "submit",
1385
+ disabled: busy || !emailValid,
1386
+ "data-cmssy-checkout-submit": true,
1387
+ children: busy ? "Placing order\u2026" : "Place order"
1388
+ }
1389
+ )
1390
+ ]
1391
+ }
1392
+ );
1393
+ }
1394
+ var checkoutBlock = defineBlock({
1395
+ type: "checkout",
1396
+ label: "Checkout",
1397
+ category: "Commerce",
1398
+ props: {
1399
+ successMessage: fields.singleLine({ label: "Success message" })
1400
+ },
1401
+ component: CheckoutComponent
1402
+ });
748
1403
 
749
- export { CmssyEditableLayout, CmssyEditablePage, CmssyLazyEditor, CmssyLazyLayout, useEditBridge };
1404
+ export { CmssyAuthProvider, CmssyCommerceProvider, CmssyEditableLayout, CmssyEditablePage, CmssyLazyEditor, CmssyLazyLayout, cartBlock, checkoutBlock, formatPrice, fractionDigits, fromMinorUnits, productBlock, useCart, useCmssyUser, useEditBridge };