@zappie/theme-base 0.1.0 → 0.1.2
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/CHANGELOG.md +39 -0
- package/README.md +26 -53
- package/dist/address.js +99 -2
- package/dist/address.js.map +7 -1
- package/dist/cart/address-sheet.js +143 -0
- package/dist/cart/address-sheet.js.map +7 -0
- package/dist/cart/cart-issues.js +72 -0
- package/dist/cart/cart-issues.js.map +7 -0
- package/dist/cart/cart-line-groups.js +34 -0
- package/dist/cart/cart-line-groups.js.map +7 -0
- package/dist/{chunk-FB5DRCU7.js → cart/cart-line.js} +9 -70
- package/dist/cart/cart-line.js.map +7 -0
- package/dist/cart/cart-lines.js +27 -0
- package/dist/cart/cart-lines.js.map +7 -0
- package/dist/cart/cart-schedule.js +24 -0
- package/dist/cart/cart-schedule.js.map +7 -0
- package/dist/cart/cart-sheet.js +35 -0
- package/dist/cart/cart-sheet.js.map +7 -0
- package/dist/cart/checkout-cta.js +81 -0
- package/dist/cart/checkout-cta.js.map +7 -0
- package/dist/cart/checkout-state.js +74 -0
- package/dist/cart/checkout-state.js.map +7 -0
- package/dist/cart/clear-cart.js +44 -0
- package/dist/cart/clear-cart.js.map +7 -0
- package/dist/cart/customer-details.js +70 -0
- package/dist/cart/customer-details.js.map +7 -0
- package/dist/cart/delivery-distance.js +22 -0
- package/dist/cart/delivery-distance.js.map +7 -0
- package/dist/cart/empty-cart.js +14 -0
- package/dist/cart/empty-cart.js.map +7 -0
- package/dist/cart/fulfilment-panel.js +83 -0
- package/dist/cart/fulfilment-panel.js.map +7 -0
- package/dist/cart/line-editor.js +35 -0
- package/dist/cart/line-editor.js.map +7 -0
- package/dist/cart/line-options.js +96 -0
- package/dist/cart/line-options.js.map +7 -0
- package/dist/cart/loading.js +17 -0
- package/dist/cart/loading.js.map +7 -0
- package/dist/cart/promo-sheet.js +103 -0
- package/dist/cart/promo-sheet.js.map +7 -0
- package/dist/cart/region-picker.js +40 -0
- package/dist/cart/region-picker.js.map +7 -0
- package/dist/cart/rewards-sheet.js +86 -0
- package/dist/cart/rewards-sheet.js.map +7 -0
- package/dist/cart/schedule-sheet.js +87 -0
- package/dist/cart/schedule-sheet.js.map +7 -0
- package/dist/{chunk-JFEI2OUZ.js → cart/theme-class.js} +7 -5
- package/dist/cart/theme-class.js.map +7 -0
- package/dist/cart/totals.js +81 -0
- package/dist/cart/totals.js.map +7 -0
- package/dist/cart/use-address-selection.js +130 -0
- package/dist/cart/use-address-selection.js.map +7 -0
- package/dist/cart.js +21 -1069
- package/dist/cart.js.map +7 -1
- package/dist/catalogue/catalogue-cart.js +25 -0
- package/dist/catalogue/catalogue-cart.js.map +7 -0
- package/dist/catalogue/catalogue-header.js +88 -0
- package/dist/catalogue/catalogue-header.js.map +7 -0
- package/dist/catalogue/catalogue-pages.js +68 -0
- package/dist/catalogue/catalogue-pages.js.map +7 -0
- package/dist/catalogue/catalogue-search.js +89 -0
- package/dist/catalogue/catalogue-search.js.map +7 -0
- package/dist/catalogue/category-navigation.js +98 -0
- package/dist/catalogue/category-navigation.js.map +7 -0
- package/dist/catalogue/category-section.js +113 -0
- package/dist/catalogue/category-section.js.map +7 -0
- package/dist/catalogue/info-banners.js +148 -0
- package/dist/catalogue/info-banners.js.map +7 -0
- package/dist/catalogue/item-tile.js +55 -0
- package/dist/catalogue/item-tile.js.map +7 -0
- package/dist/catalogue/loader.js +136 -0
- package/dist/catalogue/loader.js.map +7 -0
- package/dist/{chunk-USSLDBDY.js → catalogue/presentation.js} +12 -9
- package/dist/catalogue/presentation.js.map +7 -0
- package/dist/catalogue/saved-catalogue-sync.js +115 -0
- package/dist/catalogue/saved-catalogue-sync.js.map +7 -0
- package/dist/catalogue/types.js +1 -0
- package/dist/catalogue/types.js.map +7 -0
- package/dist/catalogue/use-catalogue-data.js +88 -0
- package/dist/catalogue/use-catalogue-data.js.map +7 -0
- package/dist/catalogue/use-category-scroll.js +115 -0
- package/dist/catalogue/use-category-scroll.js.map +7 -0
- package/dist/catalogue/use-item-opener.js +46 -0
- package/dist/catalogue/use-item-opener.js.map +7 -0
- package/dist/catalogue/use-search-source.js +132 -0
- package/dist/catalogue/use-search-source.js.map +7 -0
- package/dist/catalogue.js +26 -1216
- package/dist/catalogue.js.map +7 -1
- package/dist/checkout.js +149 -2
- package/dist/checkout.js.map +7 -1
- package/dist/host-bridge.js +22 -2
- package/dist/host-bridge.js.map +7 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +7 -1
- package/dist/item/configurator-commit.js +15 -0
- package/dist/item/configurator-commit.js.map +7 -0
- package/dist/item/configurator-draft.js +63 -0
- package/dist/item/configurator-draft.js.map +7 -0
- package/dist/item/configurator.js +135 -0
- package/dist/item/configurator.js.map +7 -0
- package/dist/item/note.js +65 -0
- package/dist/item/note.js.map +7 -0
- package/dist/item/variant-status.js +23 -0
- package/dist/item/variant-status.js.map +7 -0
- package/dist/item-frame.js +60 -3
- package/dist/item-frame.js.map +7 -1
- package/dist/item.js +11 -11
- package/dist/item.js.map +7 -1
- package/dist/navigation.js +39 -2
- package/dist/navigation.js.map +7 -1
- package/dist/url-navigation-state.js +61 -0
- package/dist/url-navigation-state.js.map +7 -0
- package/dist/{chunk-ILOCSCZL.js → url-navigation.js} +12 -89
- package/dist/url-navigation.js.map +7 -0
- package/package.json +8 -7
- package/dist/chunk-2MV6KU3R.js +0 -352
- package/dist/chunk-2MV6KU3R.js.map +0 -1
- package/dist/chunk-FB5DRCU7.js.map +0 -1
- package/dist/chunk-IG63ONID.js +0 -139
- package/dist/chunk-IG63ONID.js.map +0 -1
- package/dist/chunk-ILOCSCZL.js.map +0 -1
- package/dist/chunk-JFEI2OUZ.js.map +0 -1
- package/dist/chunk-NTJONY3N.js +0 -95
- package/dist/chunk-NTJONY3N.js.map +0 -1
- package/dist/chunk-QWST2TA2.js +0 -22
- package/dist/chunk-QWST2TA2.js.map +0 -1
- package/dist/chunk-USSLDBDY.js.map +0 -1
- package/dist/chunk-VIAJ27YC.js +0 -59
- package/dist/chunk-VIAJ27YC.js.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/item/configurator.tsx
|
|
4
|
+
import { ItemForm, Money, Quantity } from "@zappie/foundations";
|
|
5
|
+
import { useZappie } from "@zappie/sdk/react";
|
|
6
|
+
import { countEvent } from "@zappie/sdk/visits";
|
|
7
|
+
import { Fragment, useState } from "react";
|
|
8
|
+
import { LineOptions } from "../cart/line-options.js";
|
|
9
|
+
import { createConfiguratorCommit } from "./configurator-commit.js";
|
|
10
|
+
import { useConfiguratorDraft } from "./configurator-draft.js";
|
|
11
|
+
import { ItemNote } from "./note.js";
|
|
12
|
+
import { VariantStatus } from "./variant-status.js";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
function ItemConfigurator({
|
|
15
|
+
item,
|
|
16
|
+
menuId,
|
|
17
|
+
line,
|
|
18
|
+
onComplete,
|
|
19
|
+
scope,
|
|
20
|
+
showPrice = false,
|
|
21
|
+
introduction
|
|
22
|
+
}) {
|
|
23
|
+
const client = useZappie();
|
|
24
|
+
const { clear, restored, setValue, value } = useConfiguratorDraft({
|
|
25
|
+
item,
|
|
26
|
+
...menuId !== void 0 ? { menuId } : {},
|
|
27
|
+
...line !== void 0 ? { line } : {},
|
|
28
|
+
scope
|
|
29
|
+
});
|
|
30
|
+
const [error, setError] = useState();
|
|
31
|
+
const onCommit = createConfiguratorCommit(client, line);
|
|
32
|
+
return /* @__PURE__ */ jsx(
|
|
33
|
+
ItemForm.Root,
|
|
34
|
+
{
|
|
35
|
+
item,
|
|
36
|
+
value,
|
|
37
|
+
onValueChange: (next) => {
|
|
38
|
+
const nextValue = { ...next };
|
|
39
|
+
delete nextValue.variantId;
|
|
40
|
+
setValue(nextValue);
|
|
41
|
+
setError(void 0);
|
|
42
|
+
},
|
|
43
|
+
...onCommit ? { onCommit } : {},
|
|
44
|
+
onAdded: () => {
|
|
45
|
+
if (!line) {
|
|
46
|
+
countEvent("add");
|
|
47
|
+
}
|
|
48
|
+
clear();
|
|
49
|
+
onComplete();
|
|
50
|
+
},
|
|
51
|
+
className: "z-base-configurator",
|
|
52
|
+
children: (configuration) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "z-base-item-summary", children: [
|
|
54
|
+
showPrice && /* @__PURE__ */ jsxs("p", { className: "z-base-item-price", children: [
|
|
55
|
+
/* @__PURE__ */ jsx(Money, { value: configuration.unitPrice }),
|
|
56
|
+
item.compareAtPrice && /* @__PURE__ */ jsx("del", { children: /* @__PURE__ */ jsx(Money, { value: item.compareAtPrice }) })
|
|
57
|
+
] }),
|
|
58
|
+
!line && /* @__PURE__ */ jsx(
|
|
59
|
+
ItemNote,
|
|
60
|
+
{
|
|
61
|
+
id: item.id,
|
|
62
|
+
value: value.note ?? "",
|
|
63
|
+
onChange: (note) => configuration.setValue({ ...value, note })
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] }),
|
|
67
|
+
line && /* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
|
|
68
|
+
"Note",
|
|
69
|
+
/* @__PURE__ */ jsx(
|
|
70
|
+
"textarea",
|
|
71
|
+
{
|
|
72
|
+
className: "z-base-input",
|
|
73
|
+
maxLength: line ? 280 : Math.max(35, value.note?.length ?? 0),
|
|
74
|
+
value: value.note ?? "",
|
|
75
|
+
onChange: (event) => configuration.setValue({ ...value, note: event.target.value })
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
] }),
|
|
79
|
+
showPrice && /* @__PURE__ */ jsx(VariantStatus, { item, value: configuration.value }),
|
|
80
|
+
introduction,
|
|
81
|
+
/* @__PURE__ */ jsx(LineOptions, {}),
|
|
82
|
+
configuration.issues.length > 0 && /* @__PURE__ */ jsx("div", { role: "alert", children: configuration.issues.map((issue, index) => /* @__PURE__ */ jsx("p", { children: issue.message }, `${issue.code}:${issue.groupId}:${index}`)) }),
|
|
83
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
|
|
84
|
+
line && /* @__PURE__ */ jsxs("p", { "aria-live": "polite", children: [
|
|
85
|
+
"Estimated total: ",
|
|
86
|
+
/* @__PURE__ */ jsx(Money, { value: configuration.total })
|
|
87
|
+
] }),
|
|
88
|
+
/* @__PURE__ */ jsxs("footer", { className: "z-base-item-purchase", children: [
|
|
89
|
+
/* @__PURE__ */ jsxs(
|
|
90
|
+
Quantity.Root,
|
|
91
|
+
{
|
|
92
|
+
className: "z-base-quantity",
|
|
93
|
+
value: configuration.quantity,
|
|
94
|
+
min: item.quantity.min,
|
|
95
|
+
max: Math.min(item.quantity.max ?? 99, 99),
|
|
96
|
+
step: item.quantity.step,
|
|
97
|
+
onValueChange: configuration.setQuantity,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ jsx(Quantity.Decrement, { "aria-label": "Decrease quantity", children: "\u2212" }),
|
|
100
|
+
/* @__PURE__ */ jsx(Quantity.Value, { "aria-label": "Item quantity" }),
|
|
101
|
+
/* @__PURE__ */ jsx(Quantity.Increment, { "aria-label": "Increase quantity", children: "+" })
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
/* @__PURE__ */ jsxs(
|
|
106
|
+
"button",
|
|
107
|
+
{
|
|
108
|
+
type: "button",
|
|
109
|
+
className: "z-base-button",
|
|
110
|
+
disabled: !restored || !item.isAvailable,
|
|
111
|
+
onClick: () => {
|
|
112
|
+
try {
|
|
113
|
+
configuration.add();
|
|
114
|
+
} catch (failure) {
|
|
115
|
+
setError(
|
|
116
|
+
failure instanceof Error ? failure.message : "Unable to save this item. Please try again."
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
children: [
|
|
121
|
+
item.isAvailable ? line ? "Save changes" : "Add" : item.stockLabel ?? "Unavailable",
|
|
122
|
+
" ",
|
|
123
|
+
!line && /* @__PURE__ */ jsx(Money, { value: configuration.total })
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
] })
|
|
128
|
+
] })
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
ItemConfigurator
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=configurator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/item/configurator.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\nimport { ItemForm, Money, Quantity } from \"@zappie/foundations\";\nimport type { CartLine, Item } from \"@zappie/sdk\";\nimport { useZappie } from \"@zappie/sdk/react\";\nimport { countEvent } from \"@zappie/sdk/visits\";\nimport { Fragment, useState, type ReactNode } from \"react\";\nimport { LineOptions } from \"../cart/line-options\";\nimport { createConfiguratorCommit } from \"./configurator-commit\";\nimport { useConfiguratorDraft } from \"./configurator-draft\";\nimport { ItemNote } from \"./note\";\nimport { VariantStatus } from \"./variant-status\";\n\n/** The same draft and validation workflow for an item, an inline row and a cart edit. */\nexport function ItemConfigurator({\n item,\n menuId,\n line,\n onComplete,\n scope,\n showPrice = false,\n introduction,\n}: {\n item: Item;\n menuId?: string;\n line?: CartLine;\n onComplete(): void;\n scope: string;\n showPrice?: boolean;\n introduction?: ReactNode;\n}) {\n const client = useZappie();\n const { clear, restored, setValue, value } = useConfiguratorDraft({\n item,\n ...(menuId !== undefined ? { menuId } : {}),\n ...(line !== undefined ? { line } : {}),\n scope,\n });\n const [error, setError] = useState<string>();\n const onCommit = createConfiguratorCommit(client, line);\n return (\n <ItemForm.Root\n item={item}\n value={value}\n onValueChange={(next) => {\n const nextValue = { ...next };\n delete nextValue.variantId;\n setValue(nextValue);\n setError(undefined);\n }}\n {...(onCommit ? { onCommit } : {})}\n onAdded={() => {\n if (!line) {\n countEvent(\"add\");\n }\n clear();\n onComplete();\n }}\n className=\"z-base-configurator\"\n >\n {(configuration) => (\n <Fragment>\n <div className=\"z-base-item-summary\">\n {showPrice && (\n <p className=\"z-base-item-price\">\n <Money value={configuration.unitPrice} />\n {item.compareAtPrice && (\n <del>\n <Money value={item.compareAtPrice} />\n </del>\n )}\n </p>\n )}\n {!line && (\n <ItemNote\n id={item.id}\n value={value.note ?? \"\"}\n onChange={(note) => configuration.setValue({ ...value, note })}\n />\n )}\n </div>\n {line && (\n <label className=\"z-base-field\">\n Note\n <textarea\n className=\"z-base-input\"\n maxLength={line ? 280 : Math.max(35, value.note?.length ?? 0)}\n value={value.note ?? \"\"}\n onChange={(event) =>\n configuration.setValue({ ...value, note: event.target.value })\n }\n />\n </label>\n )}\n {showPrice && (\n <VariantStatus item={item} value={configuration.value} />\n )}\n {introduction}\n <LineOptions />\n {configuration.issues.length > 0 && (\n <div role=\"alert\">\n {configuration.issues.map((issue, index) => (\n <p key={`${issue.code}:${issue.groupId}:${index}`}>\n {issue.message}\n </p>\n ))}\n </div>\n )}\n {error && <p role=\"alert\">{error}</p>}\n {line && (\n <p aria-live=\"polite\">\n Estimated total: <Money value={configuration.total} />\n </p>\n )}\n <footer className=\"z-base-item-purchase\">\n <Quantity.Root\n className=\"z-base-quantity\"\n value={configuration.quantity}\n min={item.quantity.min}\n max={Math.min(item.quantity.max ?? 99, 99)}\n step={item.quantity.step}\n onValueChange={configuration.setQuantity}\n >\n <Quantity.Decrement aria-label=\"Decrease quantity\">\n \u2212\n </Quantity.Decrement>\n <Quantity.Value aria-label=\"Item quantity\" />\n <Quantity.Increment aria-label=\"Increase quantity\">\n +\n </Quantity.Increment>\n </Quantity.Root>\n <button\n type=\"button\"\n className=\"z-base-button\"\n disabled={!restored || !item.isAvailable}\n onClick={() => {\n try {\n configuration.add();\n } catch (failure) {\n setError(\n failure instanceof Error\n ? failure.message\n : \"Unable to save this item. Please try again.\",\n );\n }\n }}\n >\n {item.isAvailable\n ? line\n ? \"Save changes\"\n : \"Add\"\n : (item.stockLabel ?? \"Unavailable\")}{\" \"}\n {!line && <Money value={configuration.total} />}\n </button>\n </footer>\n </Fragment>\n )}\n </ItemForm.Root>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/item/note.tsx
|
|
4
|
+
import { Overlay, useOverlay } from "@zappie/foundations";
|
|
5
|
+
import { useThemeClass } from "../cart/theme-class.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
function ItemNote({
|
|
8
|
+
id,
|
|
9
|
+
value,
|
|
10
|
+
onChange
|
|
11
|
+
}) {
|
|
12
|
+
const overlay = useOverlay("product_note", id);
|
|
13
|
+
const themeClass = useThemeClass("z-base-cart z-base-note");
|
|
14
|
+
return /* @__PURE__ */ jsxs(
|
|
15
|
+
Overlay.Root,
|
|
16
|
+
{
|
|
17
|
+
param: "product_note",
|
|
18
|
+
id,
|
|
19
|
+
presentation: { base: "drawer", lg: "dialog" },
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ jsx(Overlay.Trigger, { className: "z-base-button-secondary", children: value ? "Edit Note" : "Add Note" }),
|
|
22
|
+
/* @__PURE__ */ jsxs(Overlay.Content, { "data-zappie-theme": "base", className: themeClass, children: [
|
|
23
|
+
/* @__PURE__ */ jsxs("header", { className: "z-base-cart-header", children: [
|
|
24
|
+
/* @__PURE__ */ jsx(Overlay.Title, { children: "Add a note" }),
|
|
25
|
+
/* @__PURE__ */ jsx(
|
|
26
|
+
Overlay.Close,
|
|
27
|
+
{
|
|
28
|
+
className: "z-base-button-secondary",
|
|
29
|
+
"aria-label": "Close note",
|
|
30
|
+
children: "\u2715"
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
] }),
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { className: "z-base-cart-body", children: [
|
|
35
|
+
/* @__PURE__ */ jsxs("label", { className: "z-base-field", children: [
|
|
36
|
+
"Note",
|
|
37
|
+
/* @__PURE__ */ jsx(
|
|
38
|
+
"textarea",
|
|
39
|
+
{
|
|
40
|
+
className: "z-base-input",
|
|
41
|
+
maxLength: Math.max(35, value.length),
|
|
42
|
+
value,
|
|
43
|
+
onChange: (event) => onChange(event.target.value)
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
] }),
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
"button",
|
|
49
|
+
{
|
|
50
|
+
type: "button",
|
|
51
|
+
className: "z-base-button",
|
|
52
|
+
onClick: overlay.close,
|
|
53
|
+
children: "Add note"
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
] })
|
|
57
|
+
] })
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
ItemNote
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=note.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/item/note.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\nimport { Overlay, useOverlay } from \"@zappie/foundations\";\nimport { useThemeClass } from \"../cart/theme-class\";\nexport function ItemNote({\n id,\n value,\n onChange,\n}: {\n id: string;\n value: string;\n onChange(value: string): void;\n}) {\n const overlay = useOverlay(\"product_note\", id);\n const themeClass = useThemeClass(\"z-base-cart z-base-note\");\n return (\n <Overlay.Root\n param=\"product_note\"\n id={id}\n presentation={{ base: \"drawer\", lg: \"dialog\" }}\n >\n <Overlay.Trigger className=\"z-base-button-secondary\">\n {value ? \"Edit Note\" : \"Add Note\"}\n </Overlay.Trigger>\n <Overlay.Content data-zappie-theme=\"base\" className={themeClass}>\n <header className=\"z-base-cart-header\">\n <Overlay.Title>Add a note</Overlay.Title>\n <Overlay.Close\n className=\"z-base-button-secondary\"\n aria-label=\"Close note\"\n >\n \u2715\n </Overlay.Close>\n </header>\n <div className=\"z-base-cart-body\">\n <label className=\"z-base-field\">\n Note\n <textarea\n className=\"z-base-input\"\n maxLength={Math.max(35, value.length)}\n value={value}\n onChange={(event) => onChange(event.target.value)}\n />\n </label>\n <button\n type=\"button\"\n className=\"z-base-button\"\n onClick={overlay.close}\n >\n Add note\n </button>\n </div>\n </Overlay.Content>\n </Overlay.Root>\n );\n}\n"],
|
|
5
|
+
"mappings": ";;;AACA,SAAS,SAAS,kBAAkB;AACpC,SAAS,qBAAqB;AAkBxB,cAIE,YAJF;AAjBC,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,UAAU,WAAW,gBAAgB,EAAE;AAC7C,QAAM,aAAa,cAAc,yBAAyB;AAC1D,SACE;AAAA,IAAC,QAAQ;AAAA,IAAR;AAAA,MACC,OAAM;AAAA,MACN;AAAA,MACA,cAAc,EAAE,MAAM,UAAU,IAAI,SAAS;AAAA,MAE7C;AAAA,4BAAC,QAAQ,SAAR,EAAgB,WAAU,2BACxB,kBAAQ,cAAc,YACzB;AAAA,QACA,qBAAC,QAAQ,SAAR,EAAgB,qBAAkB,QAAO,WAAW,YACnD;AAAA,+BAAC,YAAO,WAAU,sBAChB;AAAA,gCAAC,QAAQ,OAAR,EAAc,wBAAU;AAAA,YACzB;AAAA,cAAC,QAAQ;AAAA,cAAR;AAAA,gBACC,WAAU;AAAA,gBACV,cAAW;AAAA,gBACZ;AAAA;AAAA,YAED;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,oBACb;AAAA,iCAAC,WAAM,WAAU,gBAAe;AAAA;AAAA,cAE9B;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,WAAW,KAAK,IAAI,IAAI,MAAM,MAAM;AAAA,kBACpC;AAAA,kBACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA;AAAA,cAClD;AAAA,eACF;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,QAAQ;AAAA,gBAClB;AAAA;AAAA,YAED;AAAA,aACF;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// src/item/variant-status.tsx
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
function VariantStatus({
|
|
4
|
+
item,
|
|
5
|
+
value
|
|
6
|
+
}) {
|
|
7
|
+
const matches = item.variants.filter(
|
|
8
|
+
(variant) => Object.entries(variant.attributeChoices).every(
|
|
9
|
+
([groupId, choiceId]) => value.choices?.some(
|
|
10
|
+
(choice) => choice.groupId === groupId && choice.choiceId === choiceId
|
|
11
|
+
)
|
|
12
|
+
)
|
|
13
|
+
);
|
|
14
|
+
const selected = matches.length === 1 ? matches[0] : void 0;
|
|
15
|
+
if (!item.isAvailable || !selected) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return !selected.isAvailable ? /* @__PURE__ */ jsx("p", { role: "status", children: "Out of stock" }) : selected.lowStock ? /* @__PURE__ */ jsx("p", { role: "status", children: "Low stock" }) : null;
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
VariantStatus
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=variant-status.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/item/variant-status.tsx"],
|
|
4
|
+
"sourcesContent": ["import type { CartLineInput, Item } from \"@zappie/sdk\";\n\nexport function VariantStatus({\n item,\n value,\n}: {\n item: Item;\n value: CartLineInput;\n}) {\n const matches = item.variants.filter((variant) =>\n Object.entries(variant.attributeChoices).every(([groupId, choiceId]) =>\n value.choices?.some(\n (choice) => choice.groupId === groupId && choice.choiceId === choiceId,\n ),\n ),\n );\n const selected = matches.length === 1 ? matches[0] : undefined;\n if (!item.isAvailable || !selected) {\n return null;\n }\n return !selected.isAvailable ? (\n <p role=\"status\">Out of stock</p>\n ) : selected.lowStock ? (\n <p role=\"status\">Low stock</p>\n ) : null;\n}\n"],
|
|
5
|
+
"mappings": ";AAqBI;AAnBG,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AACD,QAAM,UAAU,KAAK,SAAS;AAAA,IAAO,CAAC,YACpC,OAAO,QAAQ,QAAQ,gBAAgB,EAAE;AAAA,MAAM,CAAC,CAAC,SAAS,QAAQ,MAChE,MAAM,SAAS;AAAA,QACb,CAAC,WAAW,OAAO,YAAY,WAAW,OAAO,aAAa;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,QAAQ,WAAW,IAAI,QAAQ,CAAC,IAAI;AACrD,MAAI,CAAC,KAAK,eAAe,CAAC,UAAU;AAClC,WAAO;AAAA,EACT;AACA,SAAO,CAAC,SAAS,cACf,oBAAC,OAAE,MAAK,UAAS,0BAAY,IAC3B,SAAS,WACX,oBAAC,OAAE,MAAK,UAAS,uBAAS,IACxB;AACN;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/item-frame.js
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
// src/item/frame.tsx
|
|
4
|
+
import { Overlay } from "@zappie/foundations";
|
|
5
|
+
import { createContext, useRef } from "react";
|
|
6
|
+
import { ThemeClassProvider } from "./cart/theme-class.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var ItemEscapeContext = createContext(null);
|
|
9
|
+
function ItemFrame({
|
|
10
|
+
id,
|
|
11
|
+
name,
|
|
12
|
+
hasImages,
|
|
13
|
+
navigation,
|
|
14
|
+
themeClass,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
const escape = useRef(void 0);
|
|
18
|
+
const classes = [
|
|
19
|
+
"z-base-cart z-base-item",
|
|
20
|
+
hasImages ? "z-base-item-with-media" : "",
|
|
21
|
+
themeClass
|
|
22
|
+
].filter(Boolean).join(" ");
|
|
23
|
+
return /* @__PURE__ */ jsx(ItemEscapeContext.Provider, { value: escape, children: /* @__PURE__ */ jsx(ThemeClassProvider, { value: themeClass, children: /* @__PURE__ */ jsx(
|
|
24
|
+
Overlay.Root,
|
|
25
|
+
{
|
|
26
|
+
param: "modal_id",
|
|
27
|
+
id: `product_${id}`,
|
|
28
|
+
navigation,
|
|
29
|
+
presentation: { base: "drawer", lg: "dialog" },
|
|
30
|
+
children: /* @__PURE__ */ jsxs(
|
|
31
|
+
Overlay.Content,
|
|
32
|
+
{
|
|
33
|
+
"data-zappie-theme": "base",
|
|
34
|
+
className: classes,
|
|
35
|
+
"aria-label": name,
|
|
36
|
+
onEscape: (event) => {
|
|
37
|
+
if (escape.current) {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
escape.current();
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ jsx("header", { className: "z-base-item-header", children: /* @__PURE__ */ jsx(
|
|
44
|
+
Overlay.Close,
|
|
45
|
+
{
|
|
46
|
+
className: "z-base-button-secondary",
|
|
47
|
+
"aria-label": "Close product",
|
|
48
|
+
children: "\u2715"
|
|
49
|
+
}
|
|
50
|
+
) }),
|
|
51
|
+
children
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
) }) });
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
ItemEscapeContext,
|
|
60
|
+
ItemFrame
|
|
61
|
+
};
|
|
4
62
|
//# sourceMappingURL=item-frame.js.map
|
|
5
|
-
//# sourceMappingURL=item-frame.js.map
|
package/dist/item-frame.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/item/frame.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\nimport { Overlay } from \"@zappie/foundations\";\nimport { createContext, useRef, type ReactNode, type RefObject } from \"react\";\nimport { ThemeClassProvider } from \"../cart/theme-class\";\nexport const ItemEscapeContext = createContext<RefObject<\n (() => void) | undefined\n> | null>(null);\n/** The eager modal frame stays mounted while the configurator chunk loads. */\nexport function ItemFrame({\n id,\n name,\n hasImages,\n navigation,\n themeClass,\n children,\n}: {\n id: string;\n name: string;\n hasImages?: boolean;\n themeClass?: string | undefined;\n children: ReactNode;\n navigation: { isOpen: boolean; open(): void; close(): void };\n}) {\n const escape = useRef<(() => void) | undefined>(undefined);\n const classes = [\n \"z-base-cart z-base-item\",\n hasImages ? \"z-base-item-with-media\" : \"\",\n themeClass,\n ]\n .filter(Boolean)\n .join(\" \");\n return (\n <ItemEscapeContext.Provider value={escape}>\n <ThemeClassProvider value={themeClass}>\n <Overlay.Root\n param=\"modal_id\"\n id={`product_${id}`}\n navigation={navigation}\n presentation={{ base: \"drawer\", lg: \"dialog\" }}\n >\n <Overlay.Content\n data-zappie-theme=\"base\"\n className={classes}\n aria-label={name}\n onEscape={(event) => {\n if (escape.current) {\n event.preventDefault();\n escape.current();\n }\n }}\n >\n <header className=\"z-base-item-header\">\n <Overlay.Close\n className=\"z-base-button-secondary\"\n aria-label=\"Close product\"\n >\n \u2715\n </Overlay.Close>\n </header>\n {children}\n </Overlay.Content>\n </Overlay.Root>\n </ThemeClassProvider>\n </ItemEscapeContext.Provider>\n );\n}\n"],
|
|
5
|
+
"mappings": ";;;AACA,SAAS,eAAe;AACxB,SAAS,eAAe,cAA8C;AACtE,SAAS,0BAA0B;AAqCzB,SAYI,KAZJ;AApCH,IAAM,oBAAoB,cAEvB,IAAI;AAEP,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,SAAS,OAAiC,MAAS;AACzD,QAAM,UAAU;AAAA,IACd;AAAA,IACA,YAAY,2BAA2B;AAAA,IACvC;AAAA,EACF,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AACX,SACE,oBAAC,kBAAkB,UAAlB,EAA2B,OAAO,QACjC,8BAAC,sBAAmB,OAAO,YACzB;AAAA,IAAC,QAAQ;AAAA,IAAR;AAAA,MACC,OAAM;AAAA,MACN,IAAI,WAAW,EAAE;AAAA,MACjB;AAAA,MACA,cAAc,EAAE,MAAM,UAAU,IAAI,SAAS;AAAA,MAE7C;AAAA,QAAC,QAAQ;AAAA,QAAR;AAAA,UACC,qBAAkB;AAAA,UAClB,WAAW;AAAA,UACX,cAAY;AAAA,UACZ,UAAU,CAAC,UAAU;AACnB,gBAAI,OAAO,SAAS;AAClB,oBAAM,eAAe;AACrB,qBAAO,QAAQ;AAAA,YACjB;AAAA,UACF;AAAA,UAEA;AAAA,gCAAC,YAAO,WAAU,sBAChB;AAAA,cAAC,QAAQ;AAAA,cAAR;AAAA,gBACC,WAAU;AAAA,gBACV,cAAW;AAAA,gBACZ;AAAA;AAAA,YAED,GACF;AAAA,YACC;AAAA;AAAA;AAAA,MACH;AAAA;AAAA,EACF,GACF,GACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/item.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { ItemFrame, ItemEscapeContext } from './chunk-VIAJ27YC.js';
|
|
3
|
-
import { ItemImage, Description } from './chunk-USSLDBDY.js';
|
|
4
|
-
import { ItemConfigurator } from './chunk-2MV6KU3R.js';
|
|
5
|
-
import './chunk-QWST2TA2.js';
|
|
6
|
-
import './chunk-JFEI2OUZ.js';
|
|
7
|
-
import { Overlay } from '@zappie/foundations';
|
|
8
|
-
import { useState, useContext, useEffect, Fragment } from 'react';
|
|
9
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
10
2
|
|
|
3
|
+
// src/item/item-detail.tsx
|
|
4
|
+
import { Overlay } from "@zappie/foundations";
|
|
5
|
+
import { Fragment, useContext, useEffect, useState } from "react";
|
|
6
|
+
import { Description, ItemImage } from "./catalogue/presentation.js";
|
|
7
|
+
import { ItemConfigurator } from "./item/configurator.js";
|
|
8
|
+
import { ItemEscapeContext, ItemFrame } from "./item-frame.js";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
function ItemDetail(props) {
|
|
12
11
|
return /* @__PURE__ */ jsx(
|
|
13
12
|
ItemFrame,
|
|
@@ -147,7 +146,8 @@ function ItemContent({
|
|
|
147
146
|
}
|
|
148
147
|
);
|
|
149
148
|
}
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
export {
|
|
150
|
+
ItemContent,
|
|
151
|
+
ItemDetail
|
|
152
|
+
};
|
|
152
153
|
//# sourceMappingURL=item.js.map
|
|
153
|
-
//# sourceMappingURL=item.js.map
|
package/dist/item.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/item/item-detail.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\nimport { Overlay } from \"@zappie/foundations\";\nimport type { Item } from \"@zappie/sdk\";\nimport { Fragment, useContext, useEffect, useState } from \"react\";\nimport { Description, ItemImage } from \"../catalogue/presentation\";\nimport { ItemConfigurator } from \"./configurator\";\nimport { ItemEscapeContext, ItemFrame } from \"./frame\";\n\nexport type ItemDetailProps = {\n item: Item;\n menuId: string;\n scope: string;\n href: string;\n themeClass?: string;\n navigation: { isOpen: boolean; open(): void; close(): void };\n};\n/** Framework-independent SDK item screen, reusable through themeClass. */\nexport function ItemDetail(props: ItemDetailProps) {\n return (\n <ItemFrame\n id={props.item.id}\n name={props.item.name}\n hasImages={props.item.images.length > 0}\n navigation={props.navigation}\n themeClass={props.themeClass}\n >\n <ItemContent key={props.item.id} {...props} />\n </ItemFrame>\n );\n}\nexport function ItemContent({\n item,\n menuId,\n scope,\n href,\n navigation,\n}: ItemDetailProps) {\n const [image, setImage] = useState(0);\n const [lightbox, setLightbox] = useState(false);\n const [shareMessage, setShareMessage] = useState(\"\");\n const escape = useContext(ItemEscapeContext);\n useEffect(() => {\n if (!escape) {\n return;\n }\n escape.current = lightbox ? () => setLightbox(false) : undefined;\n return () => {\n escape.current = undefined;\n };\n }, [escape, lightbox]);\n return (\n <div\n className={`z-base-item-layout ${lightbox ? \"z-base-item-lightbox\" : \"\"}`}\n >\n {item.images.length > 0 && (\n <section className=\"z-base-item-media\" aria-label=\"Product images\">\n <button\n type=\"button\"\n className=\"z-base-item-photo\"\n aria-label={\n lightbox ? \"Close enlarged image\" : \"Enlarge product image\"\n }\n onClick={() => setLightbox(!lightbox)}\n >\n <ItemImage\n key={image}\n src={item.images[image] ?? item.images[0] ?? \"\"}\n sizes=\"(min-width: 768px) 450px, 100vw\"\n priority\n />\n </button>\n {item.images.length > 1 && (\n <nav aria-label=\"Image gallery\">\n <button\n type=\"button\"\n onClick={() =>\n setImage(\n (image + item.images.length - 1) % item.images.length,\n )\n }\n aria-label=\"Previous image\"\n >\n \u2190\n </button>\n <span>\n {image + 1} / {item.images.length}\n </span>\n <button\n type=\"button\"\n onClick={() => setImage((image + 1) % item.images.length)}\n aria-label=\"Next image\"\n >\n \u2192\n </button>\n </nav>\n )}\n {lightbox && (\n <button\n type=\"button\"\n className=\"z-base-button-secondary\"\n onClick={() => setLightbox(false)}\n >\n Back to product\n </button>\n )}\n </section>\n )}\n {!lightbox && (\n <div className=\"z-base-item-details\">\n <button\n type=\"button\"\n className=\"z-base-button-secondary\"\n aria-label=\"Share product\"\n onClick={() => {\n const url = new URL(href, window.location.origin).href;\n void Promise.resolve()\n .then(() =>\n navigator.share\n ? navigator.share({ title: item.name, url })\n : navigator.clipboard\n .writeText(url)\n .then(() => setShareMessage(\"Link copied\")),\n )\n .catch((failure) => {\n if (failure?.name !== \"AbortError\") {\n setShareMessage(\n \"Could not share the link. Please try again.\",\n );\n }\n });\n }}\n >\n Share\n </button>\n <Overlay.Title>{item.name}</Overlay.Title>\n {!item.isAvailable && (\n <p role=\"status\">{item.stockLabel ?? \"Unavailable\"}</p>\n )}\n {shareMessage && <p role=\"status\">{shareMessage}</p>}\n <ItemConfigurator\n showPrice\n introduction={\n <Fragment>\n {item.promo && <p>{item.promo.name}</p>}\n {item.description && <Description value={item.description} />}\n </Fragment>\n }\n key={`${scope}:${item.id}:${menuId}`}\n item={item}\n menuId={menuId}\n scope={scope}\n onComplete={navigation.close}\n />\n </div>\n )}\n </div>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/navigation.js
CHANGED
|
@@ -1,4 +1,41 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
// src/navigation.tsx
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
useContext,
|
|
7
|
+
useEffect,
|
|
8
|
+
useState
|
|
9
|
+
} from "react";
|
|
10
|
+
import { createUrlNavigation } from "./url-navigation.js";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
var Context = createContext(null);
|
|
13
|
+
function CatalogueNavigationProvider({
|
|
14
|
+
navigation,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
const [, refresh] = useState(0);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const update = () => refresh((value) => value + 1);
|
|
20
|
+
window.addEventListener("popstate", update);
|
|
21
|
+
return () => {
|
|
22
|
+
window.removeEventListener("popstate", update);
|
|
23
|
+
};
|
|
24
|
+
}, [navigation]);
|
|
25
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value: navigation, children });
|
|
26
|
+
}
|
|
27
|
+
function useCatalogueNavigation() {
|
|
28
|
+
const navigation = useContext(Context);
|
|
29
|
+
if (!navigation) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"useCatalogueNavigation requires CatalogueNavigationProvider"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return navigation;
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
CatalogueNavigationProvider,
|
|
38
|
+
createUrlNavigation,
|
|
39
|
+
useCatalogueNavigation
|
|
40
|
+
};
|
|
3
41
|
//# sourceMappingURL=navigation.js.map
|
|
4
|
-
//# sourceMappingURL=navigation.js.map
|
package/dist/navigation.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/navigation.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nimport type { Item } from \"@zappie/sdk\";\nimport type { StorefrontUrlOptions } from \"@zappie/sdk/url\";\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n type ReactNode,\n} from \"react\";\n\n/** URL-owned selection, shared by template routers and reusable base screens. */\nexport type CatalogueLocation = {\n pathname: string;\n menuId?: string;\n categoryId?: string;\n menuLayout?: \"GRID\" | \"LIST\" | \"CARD\";\n item?: { id: string; path: string; presentation: \"path\" | \"query\" };\n};\n\n/** Stable identities, not host selectors or retained DOM nodes. */\nexport type CatalogueFocusTarget = { itemId?: string; fallback: \"catalogue\" };\n\nexport type CatalogueNavigationTarget = {\n type: \"item\";\n itemId: string;\n menuId?: string;\n categoryId?: string;\n};\n\nexport type CatalogueNavigation = {\n /** Fresh URL snapshot on every read; providers re-render on history changes. */\n readonly location: CatalogueLocation;\n hrefFor(target: CatalogueNavigationTarget): string;\n selectMenu(menuId: string): void;\n selectCategory(categoryId: string): void;\n setLayout(layout: NonNullable<CatalogueLocation[\"menuLayout\"]>): void;\n openItem(input: {\n itemId: string;\n /** Already normalized catalogue/search item; opening it must not fetch it again. */\n item?: Item;\n menuId: string;\n categoryId?: string;\n }): Promise<void>;\n /** Resolves after history changes and the item releases its modal/focus lock. */\n closeItem(): Promise<void>;\n /** Close the active item/base overlay before opening another surface. */\n openCart(): Promise<void>;\n openBranchFinder(): Promise<void>;\n openBranchDetails?(): Promise<void>;\n switchFulfilment(mode: \"delivery\" | \"pickup\"): Promise<boolean>;\n /** Called after close settles; use a registered trigger, or the catalogue heading. */\n restoreFocus(target: CatalogueFocusTarget): void;\n};\n\nexport type UrlNavigationOptions = StorefrontUrlOptions & {\n window?: Window & typeof globalThis;\n};\nconst Context = createContext<CatalogueNavigation | null>(null);\n\nexport function CatalogueNavigationProvider({\n navigation,\n children,\n}: {\n navigation: CatalogueNavigation;\n children: ReactNode;\n}) {\n const [, refresh] = useState(0);\n useEffect(() => {\n const update = () => refresh((value) => value + 1);\n window.addEventListener(\"popstate\", update);\n return () => {\n window.removeEventListener(\"popstate\", update);\n };\n }, [navigation]);\n return <Context.Provider value={navigation}>{children}</Context.Provider>;\n}\n\nexport function useCatalogueNavigation() {\n const navigation = useContext(Context);\n if (!navigation) {\n throw new Error(\n \"useCatalogueNavigation requires CatalogueNavigationProvider\",\n );\n }\n return navigation;\n}\n\nexport { createUrlNavigation } from \"./url-navigation\";\n"],
|
|
5
|
+
"mappings": ";;;AAIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AA+EP,SAAS,2BAA2B;AAb3B;AAjBT,IAAM,UAAU,cAA0C,IAAI;AAEvD,SAAS,4BAA4B;AAAA,EAC1C;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,EAAE,OAAO,IAAI,SAAS,CAAC;AAC9B,YAAU,MAAM;AACd,UAAM,SAAS,MAAM,QAAQ,CAAC,UAAU,QAAQ,CAAC;AACjD,WAAO,iBAAiB,YAAY,MAAM;AAC1C,WAAO,MAAM;AACX,aAAO,oBAAoB,YAAY,MAAM;AAAA,IAC/C;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AACf,SAAO,oBAAC,QAAQ,UAAR,EAAiB,OAAO,YAAa,UAAS;AACxD;AAEO,SAAS,yBAAyB;AACvC,QAAM,aAAa,WAAW,OAAO;AACrC,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/url-navigation-state.ts
|
|
2
|
+
var NAVIGATION_ENTRY = "zappie:storefront-navigation-entry";
|
|
3
|
+
var routeBase = (route) => {
|
|
4
|
+
if (route.type === "item" || route.type === "order-menu") {
|
|
5
|
+
return {
|
|
6
|
+
business: route.business,
|
|
7
|
+
...route.branch !== void 0 ? { branch: route.branch } : {}
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
};
|
|
12
|
+
var stateWith = (state, values) => {
|
|
13
|
+
const query = { ...state.query };
|
|
14
|
+
const next = { ...state, query };
|
|
15
|
+
const update = (property, key, value) => {
|
|
16
|
+
if (!Object.hasOwn(values, property)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (value === void 0) {
|
|
20
|
+
delete query[key];
|
|
21
|
+
delete next[property];
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
query[key] = property === "mode" ? String(value === "pickup") : value;
|
|
25
|
+
if (property === "mode") {
|
|
26
|
+
next.mode = value === "pickup" ? "pickup" : "delivery";
|
|
27
|
+
} else if (property === "menuId") {
|
|
28
|
+
next.menuId = value;
|
|
29
|
+
} else if (property === "categoryId") {
|
|
30
|
+
next.categoryId = value;
|
|
31
|
+
} else if (property === "menuLayout") {
|
|
32
|
+
next.menuLayout = value;
|
|
33
|
+
} else {
|
|
34
|
+
next.modalId = value;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
update("menuId", "menu_id", values.menuId);
|
|
38
|
+
update("categoryId", "category_id", values.categoryId);
|
|
39
|
+
update("menuLayout", "menu_layout", values.menuLayout);
|
|
40
|
+
update("modalId", "modal_id", values.modalId);
|
|
41
|
+
update("mode", "pickup", values.mode);
|
|
42
|
+
return next;
|
|
43
|
+
};
|
|
44
|
+
var catalogueRoute = (route, state) => {
|
|
45
|
+
const base = routeBase(route);
|
|
46
|
+
if (!base) {
|
|
47
|
+
return route;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
type: "order-menu",
|
|
51
|
+
...base,
|
|
52
|
+
state
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export {
|
|
56
|
+
NAVIGATION_ENTRY,
|
|
57
|
+
catalogueRoute,
|
|
58
|
+
routeBase,
|
|
59
|
+
stateWith
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=url-navigation-state.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/url-navigation-state.ts"],
|
|
4
|
+
"sourcesContent": ["import type { StorefrontPageState, StorefrontRoute } from \"@zappie/sdk/url\";\n\n/** History-state key marking entries this provider pushed, so close can go Back. */\nexport const NAVIGATION_ENTRY = \"zappie:storefront-navigation-entry\";\n\nexport const routeBase = (route: StorefrontRoute) => {\n if (route.type === \"item\" || route.type === \"order-menu\") {\n return {\n business: route.business,\n ...(route.branch !== undefined ? { branch: route.branch } : {}),\n };\n }\n return null;\n};\n\nexport const stateWith = (\n state: StorefrontPageState,\n values: {\n menuId?: string | undefined;\n categoryId?: string | undefined;\n menuLayout?: string | undefined;\n modalId?: string | undefined;\n mode?: \"delivery\" | \"pickup\" | undefined;\n },\n): StorefrontPageState => {\n const query = { ...state.query };\n const next: StorefrontPageState = { ...state, query };\n const update = (\n property: \"menuId\" | \"categoryId\" | \"menuLayout\" | \"modalId\" | \"mode\",\n key: string,\n value: string | undefined,\n ) => {\n if (!Object.hasOwn(values, property)) {\n return;\n }\n if (value === undefined) {\n delete query[key];\n delete next[property];\n return;\n }\n query[key] = property === \"mode\" ? String(value === \"pickup\") : value;\n if (property === \"mode\") {\n next.mode = value === \"pickup\" ? \"pickup\" : \"delivery\";\n } else if (property === \"menuId\") {\n next.menuId = value;\n } else if (property === \"categoryId\") {\n next.categoryId = value;\n } else if (property === \"menuLayout\") {\n next.menuLayout = value;\n } else {\n next.modalId = value;\n }\n };\n update(\"menuId\", \"menu_id\", values.menuId);\n update(\"categoryId\", \"category_id\", values.categoryId);\n update(\"menuLayout\", \"menu_layout\", values.menuLayout);\n update(\"modalId\", \"modal_id\", values.modalId);\n update(\"mode\", \"pickup\", values.mode);\n return next;\n};\n\nexport const catalogueRoute = (\n route: StorefrontRoute,\n state: StorefrontPageState,\n): StorefrontRoute => {\n const base = routeBase(route);\n if (!base) {\n return route;\n }\n return {\n type: \"order-menu\",\n ...base,\n state,\n };\n};\n"],
|
|
5
|
+
"mappings": ";AAGO,IAAM,mBAAmB;AAEzB,IAAM,YAAY,CAAC,UAA2B;AACnD,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS,cAAc;AACxD,WAAO;AAAA,MACL,UAAU,MAAM;AAAA,MAChB,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,YAAY,CACvB,OACA,WAOwB;AACxB,QAAM,QAAQ,EAAE,GAAG,MAAM,MAAM;AAC/B,QAAM,OAA4B,EAAE,GAAG,OAAO,MAAM;AACpD,QAAM,SAAS,CACb,UACA,KACA,UACG;AACH,QAAI,CAAC,OAAO,OAAO,QAAQ,QAAQ,GAAG;AACpC;AAAA,IACF;AACA,QAAI,UAAU,QAAW;AACvB,aAAO,MAAM,GAAG;AAChB,aAAO,KAAK,QAAQ;AACpB;AAAA,IACF;AACA,UAAM,GAAG,IAAI,aAAa,SAAS,OAAO,UAAU,QAAQ,IAAI;AAChE,QAAI,aAAa,QAAQ;AACvB,WAAK,OAAO,UAAU,WAAW,WAAW;AAAA,IAC9C,WAAW,aAAa,UAAU;AAChC,WAAK,SAAS;AAAA,IAChB,WAAW,aAAa,cAAc;AACpC,WAAK,aAAa;AAAA,IACpB,WAAW,aAAa,cAAc;AACpC,WAAK,aAAa;AAAA,IACpB,OAAO;AACL,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AACA,SAAO,UAAU,WAAW,OAAO,MAAM;AACzC,SAAO,cAAc,eAAe,OAAO,UAAU;AACrD,SAAO,cAAc,eAAe,OAAO,UAAU;AACrD,SAAO,WAAW,YAAY,OAAO,OAAO;AAC5C,SAAO,QAAQ,UAAU,OAAO,IAAI;AACpC,SAAO;AACT;AAEO,IAAM,iBAAiB,CAC5B,OACA,UACoB;AACpB,QAAM,OAAO,UAAU,KAAK;AAC5B,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAG;AAAA,IACH;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|