@zappie/foundations 0.1.5 → 0.1.6
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 +15 -0
- package/README.md +5 -0
- package/dist/branch-map/markers.js +42 -2
- package/dist/branch-map/markers.js.map +2 -2
- package/dist/deferred/index.js +42 -11
- package/dist/deferred/index.js.map +2 -2
- package/dist/{engine-XTsgCwwe.d.ts → engine-Bfbv9M0D.d.ts} +1 -2
- package/dist/index.d.ts +20 -15
- package/dist/overlay/engine.d.ts +1 -2
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @zappie/foundations
|
|
2
2
|
|
|
3
|
+
## 0.1.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a4872fd: A `deferred()` overlay whose code fails to load can recover while it is still open. Pass `failed={(retry) => ...}` to show a message and a retry button. A later `preload()`, such as the one the next tap on the trigger starts, also retries, and the overlay renders as soon as that load succeeds. Before, a failed load showed nothing, and because the overlay was still marked open, further taps never loaded it again.
|
|
8
|
+
- afb46d4: Add storefront security lint rules, pass outbound hosts from `zappie.config.ts` to ESLint, and provide `safeRedirect` from `@zappie/sdk/redirect` for untrusted navigation targets.
|
|
9
|
+
- Updated dependencies [2b672c9]
|
|
10
|
+
- Updated dependencies [9b5b412]
|
|
11
|
+
- Updated dependencies [32ecccf]
|
|
12
|
+
- Updated dependencies [afb46d4]
|
|
13
|
+
- Updated dependencies [6a8e227]
|
|
14
|
+
- Updated dependencies [c0171ae]
|
|
15
|
+
- Updated dependencies [0cbc4da]
|
|
16
|
+
- @zappie/sdk@0.1.12
|
|
17
|
+
|
|
3
18
|
## 0.1.5
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -87,6 +87,11 @@ function Header() {
|
|
|
87
87
|
- Pass `fallback` to hold an inline part's place while its code loads, for
|
|
88
88
|
example a placeholder label. It shows only while `open` is true and the code
|
|
89
89
|
is not in yet, and it never suspends.
|
|
90
|
+
- Pass `failed` to show something when the code fails to load, such as a
|
|
91
|
+
message with a button that calls `retry`. It shows only while `open` is true.
|
|
92
|
+
Without it nothing shows, so a shopper who taps and sees nothing never knows
|
|
93
|
+
to tap again. A later `preload()`, such as the one the next tap on the
|
|
94
|
+
trigger starts, also retries, and the component renders when it succeeds.
|
|
90
95
|
- `preload()` starts the load and returns its promise. Calls share one load. A
|
|
91
96
|
failed load is forgotten, so the next `preload()` or the next open tries again.
|
|
92
97
|
- `preloadWhenIdle({ timeout? })` loads the code when the browser is idle and
|
|
@@ -20,7 +20,47 @@ function branchMarker(imageUrl, focused) {
|
|
|
20
20
|
shadow: focused ? "md" : "sm"
|
|
21
21
|
} : { kind: "dot", selected: focused };
|
|
22
22
|
}
|
|
23
|
-
var
|
|
23
|
+
var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
24
|
+
function houseIcon() {
|
|
25
|
+
const svg = document.createElementNS(SVG_NAMESPACE, "svg");
|
|
26
|
+
for (const [name, value] of Object.entries({
|
|
27
|
+
width: "20",
|
|
28
|
+
height: "20",
|
|
29
|
+
viewBox: "0 0 24 24",
|
|
30
|
+
fill: "none",
|
|
31
|
+
stroke: "currentColor",
|
|
32
|
+
"stroke-width": "2",
|
|
33
|
+
"stroke-linecap": "round",
|
|
34
|
+
"stroke-linejoin": "round",
|
|
35
|
+
"aria-hidden": "true"
|
|
36
|
+
})) {
|
|
37
|
+
svg.setAttribute(name, value);
|
|
38
|
+
}
|
|
39
|
+
svg.style.display = "block";
|
|
40
|
+
for (const data of [
|
|
41
|
+
[
|
|
42
|
+
"path",
|
|
43
|
+
"d",
|
|
44
|
+
"M15 22a1 1 0 0 1-1-1v-4a1 1 0 0 1 .445-.832l3-2a1 1 0 0 1 1.11 0l3 2A1 1 0 0 1 22 17v4a1 1 0 0 1-1 1z"
|
|
45
|
+
],
|
|
46
|
+
[
|
|
47
|
+
"path",
|
|
48
|
+
"d",
|
|
49
|
+
"M18 10a8 8 0 0 0-16 0c0 4.993 5.539 10.193 7.399 11.799a1 1 0 0 0 .601.2"
|
|
50
|
+
],
|
|
51
|
+
["path", "d", "M18 22v-3"],
|
|
52
|
+
["circle", "cx", "10"]
|
|
53
|
+
]) {
|
|
54
|
+
const child = document.createElementNS(SVG_NAMESPACE, data[0]);
|
|
55
|
+
child.setAttribute(data[1], data[2]);
|
|
56
|
+
if (data[0] === "circle") {
|
|
57
|
+
child.setAttribute("cy", "10");
|
|
58
|
+
child.setAttribute("r", "3");
|
|
59
|
+
}
|
|
60
|
+
svg.appendChild(child);
|
|
61
|
+
}
|
|
62
|
+
return svg;
|
|
63
|
+
}
|
|
24
64
|
function paintMarker(element, spec, colors) {
|
|
25
65
|
const { left, top } = element.style;
|
|
26
66
|
try {
|
|
@@ -60,7 +100,7 @@ function paint(element, spec, colors) {
|
|
|
60
100
|
}
|
|
61
101
|
element.style.cssText = `position:absolute;box-sizing:border-box;transform:translate(-50%,calc(-50% - ${spec.lift ?? MARKER_BOX / 2}px));width:32px;height:32px;padding:4px;border-radius:4px;border:2px solid white;background:${colors.accent};color:${spec.color};box-shadow:${SHADOW_MD}`;
|
|
62
102
|
if (!element.firstChild) {
|
|
63
|
-
element.
|
|
103
|
+
element.appendChild(houseIcon());
|
|
64
104
|
}
|
|
65
105
|
}
|
|
66
106
|
function paintLabel(element, options) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/branch-map/markers.ts"],
|
|
4
|
-
"sourcesContent": ["/// <reference types=\"google.maps\" />\nimport type { MapColors } from \"./colors\";\nimport type { Coordinates } from \"./geometry\";\n\nexport { DEFAULT_COLORS, type MapColors } from \"./colors\";\n\nconst SHADOW_SM =\n \"0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)\";\nconst SHADOW_MD =\n \"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)\";\n/** Every marker sits in a 40px box whose bottom centre is the location. */\nconst MARKER_BOX = 40;\nconst LABEL_GAP = 4;\n\n/** What a marker shows. */\nexport type MarkerSpec =\n | {\n kind: \"logo\";\n /** Outer diameter, including the white border. */\n size: number;\n imageUrl: string;\n shadow: \"sm\" | \"md\";\n /** Offset from the location to the logo's centre. Defaults to the 40px box. */\n lift?: number;\n }\n | { kind: \"dot\"; selected: boolean }\n | {\n kind: \"house\";\n /** Icon colour. The fill is the accent. */\n color: string;\n /** Offset from the location to the icon's centre. Defaults to the 40px box. */\n lift?: number;\n };\n\n/** Choose the branch marker: the logo when there is an image, otherwise the themed dot. */\nexport function branchMarker(\n imageUrl: string | undefined,\n focused: boolean,\n): MarkerSpec {\n return imageUrl\n ? {\n kind: \"logo\",\n size: focused ? 40 : 32,\n imageUrl,\n shadow: focused ? \"md\" : \"sm\",\n }\n : { kind: \"dot\", selected: focused };\n}\n\nconst
|
|
5
|
-
"mappings": ";;;;;;;;;AAIA,SAAS,sBAAsC;AAE/C,IAAM,YACJ;AACF,IAAM,YACJ;AAEF,IAAM,aAAa;AACnB,IAAM,YAAY;AAuBX,SAAS,aACd,UACA,SACY;AACZ,SAAO,WACH;AAAA,IACE,MAAM;AAAA,IACN,MAAM,UAAU,KAAK;AAAA,IACrB;AAAA,IACA,QAAQ,UAAU,OAAO;AAAA,EAC3B,IACA,EAAE,MAAM,OAAO,UAAU,QAAQ;AACvC;AAEA,IAAM,
|
|
4
|
+
"sourcesContent": ["/// <reference types=\"google.maps\" />\nimport type { MapColors } from \"./colors\";\nimport type { Coordinates } from \"./geometry\";\n\nexport { DEFAULT_COLORS, type MapColors } from \"./colors\";\n\nconst SHADOW_SM =\n \"0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)\";\nconst SHADOW_MD =\n \"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)\";\n/** Every marker sits in a 40px box whose bottom centre is the location. */\nconst MARKER_BOX = 40;\nconst LABEL_GAP = 4;\n\n/** What a marker shows. */\nexport type MarkerSpec =\n | {\n kind: \"logo\";\n /** Outer diameter, including the white border. */\n size: number;\n imageUrl: string;\n shadow: \"sm\" | \"md\";\n /** Offset from the location to the logo's centre. Defaults to the 40px box. */\n lift?: number;\n }\n | { kind: \"dot\"; selected: boolean }\n | {\n kind: \"house\";\n /** Icon colour. The fill is the accent. */\n color: string;\n /** Offset from the location to the icon's centre. Defaults to the 40px box. */\n lift?: number;\n };\n\n/** Choose the branch marker: the logo when there is an image, otherwise the themed dot. */\nexport function branchMarker(\n imageUrl: string | undefined,\n focused: boolean,\n): MarkerSpec {\n return imageUrl\n ? {\n kind: \"logo\",\n size: focused ? 40 : 32,\n imageUrl,\n shadow: focused ? \"md\" : \"sm\",\n }\n : { kind: \"dot\", selected: focused };\n}\n\nconst SVG_NAMESPACE = \"http://www.w3.org/2000/svg\";\n\nfunction houseIcon(): SVGSVGElement {\n const svg = document.createElementNS(SVG_NAMESPACE, \"svg\");\n for (const [name, value] of Object.entries({\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n \"aria-hidden\": \"true\",\n })) {\n svg.setAttribute(name, value);\n }\n svg.style.display = \"block\";\n for (const data of [\n [\n \"path\",\n \"d\",\n \"M15 22a1 1 0 0 1-1-1v-4a1 1 0 0 1 .445-.832l3-2a1 1 0 0 1 1.11 0l3 2A1 1 0 0 1 22 17v4a1 1 0 0 1-1 1z\",\n ],\n [\n \"path\",\n \"d\",\n \"M18 10a8 8 0 0 0-16 0c0 4.993 5.539 10.193 7.399 11.799a1 1 0 0 0 .601.2\",\n ],\n [\"path\", \"d\", \"M18 22v-3\"],\n [\"circle\", \"cx\", \"10\"],\n ] as const) {\n const child = document.createElementNS(SVG_NAMESPACE, data[0]);\n child.setAttribute(data[1], data[2]);\n if (data[0] === \"circle\") {\n child.setAttribute(\"cy\", \"10\");\n child.setAttribute(\"r\", \"3\");\n }\n svg.appendChild(child);\n }\n return svg;\n}\n\n/** Style a marker element in place, so selection changes keep the same node. */\nexport function paintMarker(\n element: HTMLElement,\n spec: MarkerSpec,\n colors: MapColors,\n) {\n const { left, top } = element.style;\n try {\n paint(element, spec, colors);\n } finally {\n element.style.left = left;\n element.style.top = top;\n }\n}\n\nfunction paint(element: HTMLElement, spec: MarkerSpec, colors: MapColors) {\n element.dataset.marker = spec.kind;\n if (spec.kind === \"logo\") {\n const lift = spec.lift ?? MARKER_BOX / 2;\n element.style.cssText = `position:absolute;box-sizing:border-box;transform:translate(-50%,calc(-50% - ${lift}px));width:${spec.size}px;height:${spec.size}px;padding:0;border-radius:9999px;overflow:hidden;border:2px solid white;background:white;box-shadow:${spec.shadow === \"md\" ? SHADOW_MD : SHADOW_SM};cursor:pointer;transition:width 150ms cubic-bezier(0.4,0,0.2,1),height 150ms cubic-bezier(0.4,0,0.2,1)`;\n let image = element.querySelector(\"img\");\n if (!image) {\n element.replaceChildren();\n image = document.createElement(\"img\");\n image.alt = \"\";\n image.decoding = \"async\";\n image.draggable = false;\n image.onerror = () => {\n image!.style.visibility = \"hidden\";\n };\n element.appendChild(image);\n }\n image.style.cssText =\n \"display:block;width:100%;height:100%;border-radius:9999px;object-fit:cover\";\n if (image.getAttribute(\"src\") !== spec.imageUrl) {\n image.src = spec.imageUrl;\n }\n return;\n }\n if (spec.kind === \"dot\") {\n element.replaceChildren();\n element.style.cssText = `position:absolute;transform:translate(-50%,-100%);width:var(--branch-map-pin-size,24px);height:var(--branch-map-pin-size,24px);border-radius:50%;border:2px solid var(--branch-map-pin-border,currentColor);background:var(${spec.selected ? \"--branch-map-pin-selected\" : \"--branch-map-pin\"},currentColor);cursor:pointer`;\n return;\n }\n element.style.cssText = `position:absolute;box-sizing:border-box;transform:translate(-50%,calc(-50% - ${spec.lift ?? MARKER_BOX / 2}px));width:32px;height:32px;padding:4px;border-radius:4px;border:2px solid white;background:${colors.accent};color:${spec.color};box-shadow:${SHADOW_MD}`;\n if (!element.firstChild) {\n element.appendChild(houseIcon());\n }\n}\n\n/** Style a label above a marker. Branch labels are capitalised like the default storefront's. */\nexport function paintLabel(\n element: HTMLElement,\n options: { offset: string; capitalize: boolean; colors: MapColors },\n) {\n const { left, top } = element.style;\n element.style.cssText = `position:absolute;box-sizing:border-box;transform:translate(-50%,calc(-100% - ${options.offset}));white-space:nowrap;pointer-events:none;padding:4px 8px;border-radius:8px;font-size:12px;line-height:16px;font-weight:500;${options.capitalize ? \"text-transform:capitalize;\" : \"\"}background:var(--branch-map-label-background,white);color:var(--branch-map-label-color,#111);border:2px solid var(--branch-map-label-border,${options.colors.accent});box-shadow:${SHADOW_MD}`;\n element.style.left = left;\n element.style.top = top;\n}\n\n/** Offset from the location to the bottom of a label above a marker. */\nexport function labelOffset(spec: MarkerSpec) {\n return spec.kind === \"dot\"\n ? `var(--branch-map-pin-size,24px) + ${LABEL_GAP}px`\n : `${MARKER_BOX + LABEL_GAP}px`;\n}\n\nexport type MarkerOverlay = google.maps.OverlayView & {\n readonly element: HTMLElement;\n readonly label: HTMLElement;\n /** The clusterer reads markers through these two methods. */\n getPosition(): google.maps.LatLng;\n getVisible(): boolean;\n setLabel(text: string | undefined): void;\n setPosition(position: Coordinates): void;\n};\n\n/**\n * An overlay that places one element (a button or a div) and an optional\n * label at a location. The DOM nodes persist across restyles.\n */\nexport function markerOverlayClass(\n maps: typeof google.maps,\n): new (\n key: string,\n position: Coordinates,\n element: HTMLElement,\n) => MarkerOverlay {\n return class Marker extends maps.OverlayView implements MarkerOverlay {\n // Declared first so two markers compare unequal at once (the clusterer deep-compares them).\n readonly key: string;\n readonly element: HTMLElement;\n readonly label: HTMLElement;\n #position: Coordinates;\n #pane: Element | undefined;\n constructor(key: string, position: Coordinates, element: HTMLElement) {\n super();\n this.key = key;\n this.element = element;\n this.#position = position;\n this.label = document.createElement(\"span\");\n this.label.setAttribute(\"aria-hidden\", \"true\");\n }\n getPosition() {\n return new maps.LatLng(this.#position);\n }\n getVisible() {\n return true;\n }\n setPosition(position: Coordinates) {\n this.#position = position;\n if (this.getMap()) {\n this.draw();\n }\n }\n // An unlabelled marker has no label node in the map.\n setLabel(text: string | undefined) {\n this.label.textContent = text ?? \"\";\n if (!text) {\n this.label.remove();\n } else if (this.#pane && !this.label.isConnected) {\n this.#pane.appendChild(this.label);\n }\n }\n onAdd() {\n this.#pane = this.getPanes()?.overlayMouseTarget;\n this.#pane?.appendChild(this.element);\n if (this.label.textContent) {\n this.#pane?.appendChild(this.label);\n }\n maps.OverlayView.preventMapHitsAndGesturesFrom(this.element);\n }\n draw() {\n const point = this.getProjection()?.fromLatLngToDivPixel(\n new maps.LatLng(this.#position),\n );\n if (point) {\n for (const node of [this.element, this.label]) {\n node.style.left = `${point.x}px`;\n node.style.top = `${point.y}px`;\n }\n }\n }\n onRemove() {\n this.#pane = undefined;\n this.element.remove();\n this.label.remove();\n }\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/deferred/index.js
CHANGED
|
@@ -19,15 +19,19 @@ var ignore = () => {
|
|
|
19
19
|
function deferred(load) {
|
|
20
20
|
let loaded;
|
|
21
21
|
let pending;
|
|
22
|
+
const waiting = /* @__PURE__ */ new Set();
|
|
22
23
|
const preload = () => {
|
|
23
24
|
if (loaded) {
|
|
24
25
|
return Promise.resolve(loaded);
|
|
25
26
|
}
|
|
26
27
|
if (!pending) {
|
|
27
|
-
const attempt = new Promise((resolve) => resolve(load())).then(
|
|
28
|
-
(
|
|
29
|
-
loaded =
|
|
30
|
-
|
|
28
|
+
const attempt = new Promise((resolve) => resolve(load())).then(component).then(
|
|
29
|
+
(result) => {
|
|
30
|
+
loaded = result;
|
|
31
|
+
for (const notify of waiting) {
|
|
32
|
+
notify(result);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
31
35
|
},
|
|
32
36
|
(error) => {
|
|
33
37
|
if (pending === attempt) {
|
|
@@ -58,33 +62,60 @@ function deferred(load) {
|
|
|
58
62
|
const handle = window.setTimeout(start, options.timeout ?? 1);
|
|
59
63
|
return () => window.clearTimeout(handle);
|
|
60
64
|
};
|
|
61
|
-
function DeferredComponent({
|
|
65
|
+
function DeferredComponent({
|
|
66
|
+
fallback = null,
|
|
67
|
+
failed,
|
|
68
|
+
...props
|
|
69
|
+
}) {
|
|
62
70
|
const { open } = props;
|
|
63
71
|
const [ready, setReady] = useState(() => loaded);
|
|
64
72
|
const [opened, setOpened] = useState(open);
|
|
73
|
+
const [failure, setFailure] = useState(false);
|
|
74
|
+
const [retries, setRetries] = useState(0);
|
|
65
75
|
if (open && !opened) {
|
|
66
76
|
setOpened(true);
|
|
67
77
|
}
|
|
68
78
|
const Loaded = ready ?? loaded;
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (Loaded) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const notify = (value) => setReady(() => value);
|
|
84
|
+
waiting.add(notify);
|
|
85
|
+
return () => {
|
|
86
|
+
waiting.delete(notify);
|
|
87
|
+
};
|
|
88
|
+
}, [Loaded]);
|
|
69
89
|
useEffect(() => {
|
|
70
90
|
if (!open || Loaded) {
|
|
71
91
|
return;
|
|
72
92
|
}
|
|
73
93
|
let active = true;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
setFailure(false);
|
|
95
|
+
preload().then(
|
|
96
|
+
(value) => {
|
|
97
|
+
if (active) {
|
|
98
|
+
setReady(() => value);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
() => {
|
|
102
|
+
if (active) {
|
|
103
|
+
setFailure(true);
|
|
104
|
+
}
|
|
77
105
|
}
|
|
78
|
-
|
|
106
|
+
);
|
|
79
107
|
return () => {
|
|
80
108
|
active = false;
|
|
81
109
|
};
|
|
82
|
-
}, [open, Loaded]);
|
|
110
|
+
}, [open, Loaded, retries]);
|
|
83
111
|
if (!(open || opened)) {
|
|
84
112
|
return null;
|
|
85
113
|
}
|
|
86
114
|
if (!Loaded) {
|
|
87
|
-
|
|
115
|
+
if (!open) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return /* @__PURE__ */ jsx(Fragment, { children: failure && failed ? failed(() => setRetries((count) => count + 1)) : fallback });
|
|
88
119
|
}
|
|
89
120
|
return /* @__PURE__ */ jsx(Loaded, { ...props });
|
|
90
121
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/deferred/index.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\nimport {\n Fragment,\n useEffect,\n useMemo,\n useState,\n type ComponentType,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\n/** Props for a deferred component: its own props plus `open`, which the helper reads and passes on. */\nexport type DeferredProps<P> = Omit<P, \"open\"> & {\n /**\n * Load the code if needed and render the component. Before the first open\n * it renders nothing; after it, the component stays mounted and receives\n * `open`, so it can animate out and return focus when it closes.\n */\n open: boolean;\n /** Shown while `open` is true and the code is still loading, for inline parts that should hold their place. */\n fallback?: ReactNode;\n};\n\n/** Options for `preloadWhenIdle`. */\nexport type DeferredIdleOptions = {\n /** Start the load after this many milliseconds even if the browser never goes idle. */\n timeout?: number;\n};\n\n/**\n * A component whose code loads on demand and renders without suspending.\n * Create it once at module scope with `deferred()`.\n */\nexport type Deferred<P> = {\n /**\n * Start loading the code. Repeated calls share one load. A failed load is\n * forgotten, so the next call tries again.\n * @returns The loaded component, or the load error.\n */\n preload(): Promise<ComponentType<P>>;\n /**\n * Load the code once the browser is idle. Use it only for small chunks.\n * Does nothing on the server.\n * @returns A function that cancels the scheduled load.\n */\n preloadWhenIdle(options?: DeferredIdleOptions): () => void;\n /**\n * Renders nothing until `open` is first true and the code is in. When\n * `open` turns true it loads the code and renders as soon as it arrives.
|
|
5
|
-
"mappings": ";;;AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;
|
|
4
|
+
"sourcesContent": ["\"use client\";\nimport {\n Fragment,\n useEffect,\n useMemo,\n useState,\n type ComponentType,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\n/** Props for a deferred component: its own props plus `open`, which the helper reads and passes on. */\nexport type DeferredProps<P> = Omit<P, \"open\"> & {\n /**\n * Load the code if needed and render the component. Before the first open\n * it renders nothing; after it, the component stays mounted and receives\n * `open`, so it can animate out and return focus when it closes.\n */\n open: boolean;\n /** Shown while `open` is true and the code is still loading, for inline parts that should hold their place. */\n fallback?: ReactNode;\n /**\n * Shown while `open` is true and the code failed to load. Call `retry` to load it again.\n * A later `preload()`, such as the next tap on the trigger, also retries and renders on success.\n */\n failed?: (retry: () => void) => ReactNode;\n};\n\n/** Options for `preloadWhenIdle`. */\nexport type DeferredIdleOptions = {\n /** Start the load after this many milliseconds even if the browser never goes idle. */\n timeout?: number;\n};\n\n/**\n * A component whose code loads on demand and renders without suspending.\n * Create it once at module scope with `deferred()`.\n */\nexport type Deferred<P> = {\n /**\n * Start loading the code. Repeated calls share one load. A failed load is\n * forgotten, so the next call tries again.\n * @returns The loaded component, or the load error.\n */\n preload(): Promise<ComponentType<P>>;\n /**\n * Load the code once the browser is idle. Use it only for small chunks.\n * Does nothing on the server.\n * @returns A function that cancels the scheduled load.\n */\n preloadWhenIdle(options?: DeferredIdleOptions): () => void;\n /**\n * Renders nothing until `open` is first true and the code is in. When\n * `open` turns true it loads the code and renders as soon as it arrives. If\n * the load fails it shows `failed` and renders once a retry or a later\n * `preload()` succeeds. It never suspends. After the first open the component stays mounted and\n * every prop passes through, `open` included, so it can run its own exit.\n */\n Component: (props: DeferredProps<P>) => ReactElement | null;\n};\n\n/** Event handlers that start loading a deferred component when a shopper reaches for its trigger. */\nexport type IntentPreloadHandlers = {\n onPointerEnter: () => void;\n onPointerDown: () => void;\n onFocus: () => void;\n};\n\n/** What a deferred load resolves to: a component, or a module whose default export is one. */\nexport type DeferredModule =\n ComponentType<never> | { default: ComponentType<never> };\n\n/** The props of the component a deferred load resolves to. */\nexport type DeferredModuleProps<T> = T extends {\n default: ComponentType<infer P>;\n}\n ? P\n : T extends ComponentType<infer P>\n ? P\n : never;\n\ntype AnyComponent = ComponentType<Record<string, unknown>>;\n\nfunction component(value: DeferredModule): AnyComponent {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"default\" in value &&\n !(\"$$typeof\" in value)\n ) {\n return value.default as AnyComponent;\n }\n return value as AnyComponent;\n}\n\nconst ignore = () => {};\n\n/**\n * Load a component's code on demand without `React.lazy` or `<Suspense>`.\n * React holds a suspended boundary's first reveal for about 300 ms, so a\n * lazy overlay opens late. A deferred one renders on the frame its code\n * arrives. Pass a module whose default export is the component, or resolve\n * to the component itself.\n *\n * @example\n * const Bag = deferred(() => import(\"./bag-sheet\"));\n * const Finder = deferred(() => import(\"./finder\").then((m) => m.Finder));\n * <Bag.Component open={open} onClose={close} />\n */\nexport function deferred<T extends DeferredModule>(\n load: () => Promise<T>,\n): Deferred<DeferredModuleProps<T>> {\n type P = DeferredModuleProps<T>;\n let loaded: AnyComponent | undefined;\n let pending: Promise<AnyComponent> | undefined;\n // Mounted instances that are waiting for the code, told when any load succeeds.\n const waiting = new Set<(value: AnyComponent) => void>();\n\n const preload = (): Promise<AnyComponent> => {\n if (loaded) {\n return Promise.resolve(loaded);\n }\n if (!pending) {\n // Starts the import now. A load that throws, or a module whose component\n // cannot be read, becomes a rejection the next call retries.\n const attempt = new Promise<T>((resolve) => resolve(load()))\n .then(component)\n .then(\n (result) => {\n loaded = result;\n for (const notify of waiting) {\n notify(result);\n }\n return result;\n },\n (error: unknown) => {\n // Forget the failure so the next open or preload tries again.\n if (pending === attempt) {\n pending = undefined;\n }\n throw error;\n },\n );\n // Callers may ignore the promise; the component reports nothing either.\n attempt.catch(ignore);\n pending = attempt;\n }\n return pending;\n };\n\n const preloadWhenIdle = (options: DeferredIdleOptions = {}) => {\n if (typeof window === \"undefined\" || loaded) {\n return ignore;\n }\n const start = () => {\n preload().catch(ignore);\n };\n if (typeof window.requestIdleCallback === \"function\") {\n const handle = window.requestIdleCallback(\n start,\n options.timeout === undefined\n ? undefined\n : { timeout: options.timeout },\n );\n return () => window.cancelIdleCallback(handle);\n }\n const handle = window.setTimeout(start, options.timeout ?? 1);\n return () => window.clearTimeout(handle);\n };\n\n function DeferredComponent({\n fallback = null,\n failed,\n ...props\n }: DeferredProps<P>) {\n const { open } = props;\n const [ready, setReady] = useState<AnyComponent | undefined>(() => loaded);\n const [opened, setOpened] = useState<boolean>(open);\n // A failed load shows `failed` until a retry or a new open starts another.\n const [failure, setFailure] = useState(false);\n const [retries, setRetries] = useState(0);\n if (open && !opened) {\n setOpened(true);\n }\n const Loaded = ready ?? loaded;\n useEffect(() => {\n if (Loaded) {\n return;\n }\n const notify = (value: AnyComponent) => setReady(() => value);\n waiting.add(notify);\n return () => {\n waiting.delete(notify);\n };\n }, [Loaded]);\n useEffect(() => {\n if (!open || Loaded) {\n return;\n }\n let active = true;\n setFailure(false);\n preload().then(\n (value) => {\n if (active) {\n setReady(() => value);\n }\n },\n () => {\n if (active) {\n setFailure(true);\n }\n },\n );\n return () => {\n active = false;\n };\n }, [open, Loaded, retries]);\n if (!(open || opened)) {\n return null;\n }\n if (!Loaded) {\n if (!open) {\n return null;\n }\n return (\n <Fragment>\n {failure && failed\n ? failed(() => setRetries((count) => count + 1))\n : fallback}\n </Fragment>\n );\n }\n return <Loaded {...(props as Record<string, unknown>)} />;\n }\n DeferredComponent.displayName = \"Deferred\";\n\n return {\n // The load resolved to the component typed by T.\n preload: preload as () => Promise<ComponentType<P>>,\n preloadWhenIdle,\n Component: DeferredComponent,\n };\n}\n\n/**\n * Start loading a deferred component when the shopper points at, presses or\n * focuses its trigger, so the code is usually in by the click. Spread the\n * result on the trigger.\n *\n * @example\n * const intent = useIntentPreload(Bag);\n * <button {...intent} onClick={openBag}>Bag</button>\n */\nexport function useIntentPreload(target: {\n preload(): Promise<unknown>;\n}): IntentPreloadHandlers {\n return useMemo(() => {\n const start = () => {\n target.preload().catch(ignore);\n };\n return { onPointerEnter: start, onPointerDown: start, onFocus: start };\n }, [target]);\n}\n"],
|
|
5
|
+
"mappings": ";;;AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAwNC;AA9IR,SAAS,UAAU,OAAqC;AACtD,MACE,OAAO,UAAU,YACjB,UAAU,QACV,aAAa,SACb,EAAE,cAAc,QAChB;AACA,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AAEA,IAAM,SAAS,MAAM;AAAC;AAcf,SAAS,SACd,MACkC;AAElC,MAAI;AACJ,MAAI;AAEJ,QAAM,UAAU,oBAAI,IAAmC;AAEvD,QAAM,UAAU,MAA6B;AAC3C,QAAI,QAAQ;AACV,aAAO,QAAQ,QAAQ,MAAM;AAAA,IAC/B;AACA,QAAI,CAAC,SAAS;AAGZ,YAAM,UAAU,IAAI,QAAW,CAAC,YAAY,QAAQ,KAAK,CAAC,CAAC,EACxD,KAAK,SAAS,EACd;AAAA,QACC,CAAC,WAAW;AACV,mBAAS;AACT,qBAAW,UAAU,SAAS;AAC5B,mBAAO,MAAM;AAAA,UACf;AACA,iBAAO;AAAA,QACT;AAAA,QACA,CAAC,UAAmB;AAElB,cAAI,YAAY,SAAS;AACvB,sBAAU;AAAA,UACZ;AACA,gBAAM;AAAA,QACR;AAAA,MACF;AAEF,cAAQ,MAAM,MAAM;AACpB,gBAAU;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,CAAC,UAA+B,CAAC,MAAM;AAC7D,QAAI,OAAO,WAAW,eAAe,QAAQ;AAC3C,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,MAAM;AAClB,cAAQ,EAAE,MAAM,MAAM;AAAA,IACxB;AACA,QAAI,OAAO,OAAO,wBAAwB,YAAY;AACpD,YAAMA,UAAS,OAAO;AAAA,QACpB;AAAA,QACA,QAAQ,YAAY,SAChB,SACA,EAAE,SAAS,QAAQ,QAAQ;AAAA,MACjC;AACA,aAAO,MAAM,OAAO,mBAAmBA,OAAM;AAAA,IAC/C;AACA,UAAM,SAAS,OAAO,WAAW,OAAO,QAAQ,WAAW,CAAC;AAC5D,WAAO,MAAM,OAAO,aAAa,MAAM;AAAA,EACzC;AAEA,WAAS,kBAAkB;AAAA,IACzB,WAAW;AAAA,IACX;AAAA,IACA,GAAG;AAAA,EACL,GAAqB;AACnB,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,CAAC,OAAO,QAAQ,IAAI,SAAmC,MAAM,MAAM;AACzE,UAAM,CAAC,QAAQ,SAAS,IAAI,SAAkB,IAAI;AAElD,UAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,UAAM,CAAC,SAAS,UAAU,IAAI,SAAS,CAAC;AACxC,QAAI,QAAQ,CAAC,QAAQ;AACnB,gBAAU,IAAI;AAAA,IAChB;AACA,UAAM,SAAS,SAAS;AACxB,cAAU,MAAM;AACd,UAAI,QAAQ;AACV;AAAA,MACF;AACA,YAAM,SAAS,CAAC,UAAwB,SAAS,MAAM,KAAK;AAC5D,cAAQ,IAAI,MAAM;AAClB,aAAO,MAAM;AACX,gBAAQ,OAAO,MAAM;AAAA,MACvB;AAAA,IACF,GAAG,CAAC,MAAM,CAAC;AACX,cAAU,MAAM;AACd,UAAI,CAAC,QAAQ,QAAQ;AACnB;AAAA,MACF;AACA,UAAI,SAAS;AACb,iBAAW,KAAK;AAChB,cAAQ,EAAE;AAAA,QACR,CAAC,UAAU;AACT,cAAI,QAAQ;AACV,qBAAS,MAAM,KAAK;AAAA,UACtB;AAAA,QACF;AAAA,QACA,MAAM;AACJ,cAAI,QAAQ;AACV,uBAAW,IAAI;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AACA,aAAO,MAAM;AACX,iBAAS;AAAA,MACX;AAAA,IACF,GAAG,CAAC,MAAM,QAAQ,OAAO,CAAC;AAC1B,QAAI,EAAE,QAAQ,SAAS;AACrB,aAAO;AAAA,IACT;AACA,QAAI,CAAC,QAAQ;AACX,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AACA,aACE,oBAAC,YACE,qBAAW,SACR,OAAO,MAAM,WAAW,CAAC,UAAU,QAAQ,CAAC,CAAC,IAC7C,UACN;AAAA,IAEJ;AACA,WAAO,oBAAC,UAAQ,GAAI,OAAmC;AAAA,EACzD;AACA,oBAAkB,cAAc;AAEhC,SAAO;AAAA;AAAA,IAEL;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb;AACF;AAWO,SAAS,iBAAiB,QAEP;AACxB,SAAO,QAAQ,MAAM;AACnB,UAAM,QAAQ,MAAM;AAClB,aAAO,QAAQ,EAAE,MAAM,MAAM;AAAA,IAC/B;AACA,WAAO,EAAE,gBAAgB,OAAO,eAAe,OAAO,SAAS,MAAM;AAAA,EACvE,GAAG,CAAC,MAAM,CAAC;AACb;",
|
|
6
6
|
"names": ["handle"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { AllHTMLAttributes, ReactNode, Ref } from 'react';
|
|
3
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
3
|
import { Dialog } from '@base-ui/react/dialog';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -41,7 +40,7 @@ type Parts = {
|
|
|
41
40
|
declare function useEngineParts(): Parts;
|
|
42
41
|
declare function Surface(props: SurfaceProps & {
|
|
43
42
|
children?: ReactNode;
|
|
44
|
-
}):
|
|
43
|
+
}): react.JSX.Element;
|
|
45
44
|
declare const EngineTitle: react.ForwardRefExoticComponent<Omit<react.AllHTMLAttributes<HTMLElement>, "children" | "defaultValue" | "value"> & {
|
|
46
45
|
asChild?: boolean;
|
|
47
46
|
children?: ReactNode | ((state: unknown) => ReactNode);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes, ReactNode, ComponentType, ReactElement, KeyboardEvent as KeyboardEvent$1, ImgHTMLAttributes, ChangeEvent, ClipboardEvent } from 'react';
|
|
3
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
3
|
import * as _zappie_sdk from '@zappie/sdk';
|
|
5
4
|
import { Branch as Branch$1, CartLine, CartLineInput, CartIssue, CartFix, Quote, DeliveryAddress, MenuSchedule, CartFulfilment, OptionGroup as OptionGroup$1, Item, Money as Money$1, Choice as Choice$1, MoneyFormatOptions, PaymentMethodKind, Category, Menu, OpeningTime } from '@zappie/sdk';
|
|
6
5
|
import { useCart } from '@zappie/sdk/react';
|
|
7
|
-
import { P as PartProps, a as Presentation, S as SwipeDirection } from './engine-
|
|
6
|
+
import { P as PartProps, a as Presentation, S as SwipeDirection } from './engine-Bfbv9M0D.js';
|
|
8
7
|
import { C as CloseOptions, O as OverlayQuery } from './history-Bqu12Vkz.js';
|
|
9
8
|
import '@base-ui/react/dialog';
|
|
10
9
|
|
|
@@ -105,7 +104,7 @@ type DeliveryMapProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
105
104
|
* container height with CSS. Colour the house marker with --map-accent and
|
|
106
105
|
* the line with --delivery-map-route.
|
|
107
106
|
*/
|
|
108
|
-
declare function DeliveryMap({ branch, shopper, route, browserKey, pinImageUrl, onLoadError, renderLoadError, ...props }: DeliveryMapProps):
|
|
107
|
+
declare function DeliveryMap({ branch, shopper, route, browserKey, pinImageUrl, onLoadError, renderLoadError, ...props }: DeliveryMapProps): react.JSX.Element | null;
|
|
109
108
|
|
|
110
109
|
/** What a template gets to render when the map fails to load. */
|
|
111
110
|
type BranchMapLoadErrorState = MapLoadErrorState;
|
|
@@ -153,7 +152,7 @@ type BranchMapProps = Omit<HTMLAttributes<HTMLDivElement>, "onSelect"> & {
|
|
|
153
152
|
* --branch-map-pin, --branch-map-pin-selected, --branch-map-pin-border and
|
|
154
153
|
* --branch-map-pin-size.
|
|
155
154
|
*/
|
|
156
|
-
declare function BranchMap({ branches, selectedBranchId, onSelect, shopperLocation, browserKey, maxZoom, pinImageUrl, mapTypeControl, pinLabel, compact, onLoadError, renderLoadError, ...props }: BranchMapProps):
|
|
155
|
+
declare function BranchMap({ branches, selectedBranchId, onSelect, shopperLocation, browserKey, maxZoom, pinImageUrl, mapTypeControl, pinLabel, compact, onLoadError, renderLoadError, ...props }: BranchMapProps): react.JSX.Element | null;
|
|
157
156
|
|
|
158
157
|
/**
|
|
159
158
|
* The current quantity, bounds, step, disabled state and value setter exposed by a quantity control.
|
|
@@ -178,7 +177,7 @@ type QuantityProps = PartProps<QuantityState> & {
|
|
|
178
177
|
step?: number;
|
|
179
178
|
disabled?: boolean;
|
|
180
179
|
};
|
|
181
|
-
declare function Root$5({ value, defaultValue, onValueChange, min, max, step, disabled, ...props }: QuantityProps):
|
|
180
|
+
declare function Root$5({ value, defaultValue, onValueChange, min, max, step, disabled, ...props }: QuantityProps): react.JSX.Element;
|
|
182
181
|
/**
|
|
183
182
|
* Composable quantity controls with bounded step changes and keyboard support.
|
|
184
183
|
* Wrap Value, Increment and Decrement in Quantity.Root.
|
|
@@ -209,7 +208,7 @@ declare const Quantity: {
|
|
|
209
208
|
};
|
|
210
209
|
|
|
211
210
|
type CartContext = ReturnType<typeof useCart>;
|
|
212
|
-
declare function Root$4(props: PartProps<CartContext>):
|
|
211
|
+
declare function Root$4(props: PartProps<CartContext>): react.JSX.Element;
|
|
213
212
|
type LineContext = {
|
|
214
213
|
line: CartLine;
|
|
215
214
|
item: _zappie_sdk.Item | undefined;
|
|
@@ -218,7 +217,7 @@ type LineContext = {
|
|
|
218
217
|
};
|
|
219
218
|
declare function CartQuantity({ lineId, ...props }: Omit<QuantityProps, "value" | "defaultValue" | "onValueChange"> & {
|
|
220
219
|
lineId: string;
|
|
221
|
-
}):
|
|
220
|
+
}): react.JSX.Element | null;
|
|
222
221
|
/**
|
|
223
222
|
* Composable cart parts for lines, quantity changes, removal, empty state and validation issues.
|
|
224
223
|
* Wrap the parts in Cart.Root inside your ZappieProvider.
|
|
@@ -276,6 +275,11 @@ type DeferredProps<P> = Omit<P, "open"> & {
|
|
|
276
275
|
open: boolean;
|
|
277
276
|
/** Shown while `open` is true and the code is still loading, for inline parts that should hold their place. */
|
|
278
277
|
fallback?: ReactNode;
|
|
278
|
+
/**
|
|
279
|
+
* Shown while `open` is true and the code failed to load. Call `retry` to load it again.
|
|
280
|
+
* A later `preload()`, such as the next tap on the trigger, also retries and renders on success.
|
|
281
|
+
*/
|
|
282
|
+
failed?: (retry: () => void) => ReactNode;
|
|
279
283
|
};
|
|
280
284
|
/** Options for `preloadWhenIdle`. */
|
|
281
285
|
type DeferredIdleOptions = {
|
|
@@ -301,8 +305,9 @@ type Deferred<P> = {
|
|
|
301
305
|
preloadWhenIdle(options?: DeferredIdleOptions): () => void;
|
|
302
306
|
/**
|
|
303
307
|
* Renders nothing until `open` is first true and the code is in. When
|
|
304
|
-
* `open` turns true it loads the code and renders as soon as it arrives.
|
|
305
|
-
*
|
|
308
|
+
* `open` turns true it loads the code and renders as soon as it arrives. If
|
|
309
|
+
* the load fails it shows `failed` and renders once a retry or a later
|
|
310
|
+
* `preload()` succeeds. It never suspends. After the first open the component stays mounted and
|
|
306
311
|
* every prop passes through, `open` included, so it can run its own exit.
|
|
307
312
|
*/
|
|
308
313
|
Component: (props: DeferredProps<P>) => ReactElement | null;
|
|
@@ -414,7 +419,7 @@ declare function Picker({ getSuggestions, onSelect, query, defaultQuery, onQuery
|
|
|
414
419
|
defaultQuery?: string;
|
|
415
420
|
onQueryChange?: (query: string) => void;
|
|
416
421
|
debounceMs?: number;
|
|
417
|
-
}):
|
|
422
|
+
}): react.JSX.Element;
|
|
418
423
|
/**
|
|
419
424
|
* Composable address picker parts with debounced suggestions and keyboard navigation.
|
|
420
425
|
* Supply getSuggestions and onSelect to Address.Picker. It cancels outdated requests.
|
|
@@ -601,7 +606,7 @@ type ItemFormProps = Omit<PartProps<ItemFormContext>, "onInvalid"> & {
|
|
|
601
606
|
*/
|
|
602
607
|
onInvalid?: (groups: ItemFormInvalidGroup[]) => void;
|
|
603
608
|
};
|
|
604
|
-
declare function Root$3({ item, value, defaultValue, onValueChange, defaultQuantity, onAdded, onCommit, onInvalid, ...props }: ItemFormProps):
|
|
609
|
+
declare function Root$3({ item, value, defaultValue, onValueChange, defaultQuantity, onAdded, onCommit, onInvalid, ...props }: ItemFormProps): react.JSX.Element;
|
|
605
610
|
|
|
606
611
|
type GroupState = {
|
|
607
612
|
group: OptionGroup$1;
|
|
@@ -677,7 +682,7 @@ type ImageProps = Omit<ImgHTMLAttributes<HTMLImageElement>, "src" | "srcSet"> &
|
|
|
677
682
|
mode?: "resize" | "direct";
|
|
678
683
|
};
|
|
679
684
|
/** Render an image through same-origin resizing, or directly when unavailable. */
|
|
680
|
-
declare function Image({ src, sizes, priority, quality, mode, alt, ...props }: ImageProps):
|
|
685
|
+
declare function Image({ src, sizes, priority, quality, mode, alt, ...props }: ImageProps): react.JSX.Element;
|
|
681
686
|
|
|
682
687
|
/**
|
|
683
688
|
* Render formatted SDK money in a data element, with the minor-unit amount as its value.
|
|
@@ -770,7 +775,7 @@ declare function Root$2({ param, id, presentation, swipeDirection, fallback, omi
|
|
|
770
775
|
presentation?: ResponsivePresentation;
|
|
771
776
|
/** Swipe direction to dismiss. Defaults to `down` for drawers and `right` for sheets. */
|
|
772
777
|
swipeDirection?: SwipeDirection;
|
|
773
|
-
} & CloseOptions):
|
|
778
|
+
} & CloseOptions): react.JSX.Element;
|
|
774
779
|
/**
|
|
775
780
|
* Composable dialog, drawer and sheet parts with URL-backed open state and a lazy modal engine.
|
|
776
781
|
* Use Root, Trigger, Content, Title and Close to connect history, focus handling and dismissal.
|
|
@@ -838,7 +843,7 @@ declare function Root$1({ methods, value, defaultValue, onValueChange, ...props
|
|
|
838
843
|
value?: PaymentMethodKind | null;
|
|
839
844
|
defaultValue?: PaymentMethodKind | null;
|
|
840
845
|
onValueChange?: (value: PaymentMethodKind | null) => void;
|
|
841
|
-
}):
|
|
846
|
+
}): react.JSX.Element;
|
|
842
847
|
/**
|
|
843
848
|
* Composable payment-method radio controls with keyboard navigation.
|
|
844
849
|
* Root manages the selection. Item renders each method and prevents selection when disabled.
|
|
@@ -906,7 +911,7 @@ type RootProps = Omit<PartProps<SearchState>, "onSelect"> & {
|
|
|
906
911
|
onSelect?: (result: SearchResult) => void;
|
|
907
912
|
source?: SearchSource;
|
|
908
913
|
};
|
|
909
|
-
declare function Root(props: RootProps):
|
|
914
|
+
declare function Root(props: RootProps): react.JSX.Element;
|
|
910
915
|
/**
|
|
911
916
|
* Composable menu search parts with combobox navigation and result announcements.
|
|
912
917
|
* Use Root with your own source or let it index the active branch menu through your ZappieProvider.
|
package/dist/overlay/engine.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import 'react';
|
|
2
|
-
import 'react/jsx-runtime';
|
|
3
2
|
import '@base-ui/react/dialog';
|
|
4
|
-
export { E as EngineClose, b as EngineTitle, a as Presentation, c as Surface, d as SurfaceProps, S as SwipeDirection, u as useEngineParts } from '../engine-
|
|
3
|
+
export { E as EngineClose, b as EngineTitle, a as Presentation, c as Surface, d as SurfaceProps, S as SwipeDirection, u as useEngineParts } from '../engine-Bfbv9M0D.js';
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zappie/foundations",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "UI-less React primitives for Zappie storefronts: behaviour, state and accessibility without styles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"CHANGELOG.md"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@base-ui/react": "^1.
|
|
34
|
+
"@base-ui/react": "^1.9.0",
|
|
35
35
|
"@googlemaps/markerclusterer": "^2.6.2",
|
|
36
|
-
"@zappie/sdk": "^0.1.
|
|
36
|
+
"@zappie/sdk": "^0.1.12"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": "^18.2.0 || ^19.0.0",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"directory": "packages/foundations"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"esbuild": "^0.
|
|
48
|
+
"esbuild": "^0.28.2"
|
|
49
49
|
},
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"homepage": "https://github.com/zappie/storefront#readme",
|