@zappie/foundations 0.1.1 → 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.
Files changed (72) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/account/index.js +49 -0
  3. package/dist/account/index.js.map +7 -0
  4. package/dist/cart/index.js +168 -0
  5. package/dist/cart/index.js.map +7 -0
  6. package/dist/fulfilment/address-picker.js +168 -0
  7. package/dist/fulfilment/address-picker.js.map +7 -0
  8. package/dist/fulfilment/branch-picker.js +54 -0
  9. package/dist/fulfilment/branch-picker.js.map +7 -0
  10. package/dist/fulfilment/schedule.js +146 -0
  11. package/dist/fulfilment/schedule.js.map +7 -0
  12. package/dist/fulfilment/switch.js +54 -0
  13. package/dist/fulfilment/switch.js.map +7 -0
  14. package/dist/index.js +48 -2114
  15. package/dist/index.js.map +7 -1
  16. package/dist/internal/combobox.js +131 -0
  17. package/dist/internal/combobox.js.map +7 -0
  18. package/dist/internal/data-attrs.js +8 -0
  19. package/dist/internal/data-attrs.js.map +7 -0
  20. package/dist/internal/ids.js +10 -0
  21. package/dist/internal/ids.js.map +7 -0
  22. package/dist/{chunk-D3J7S33L.js → internal/slot.js} +13 -6
  23. package/dist/internal/slot.js.map +7 -0
  24. package/dist/internal/use-controllable-state.js +29 -0
  25. package/dist/internal/use-controllable-state.js.map +7 -0
  26. package/dist/item-form/index.js +13 -0
  27. package/dist/item-form/index.js.map +7 -0
  28. package/dist/item-form/option-group.js +268 -0
  29. package/dist/item-form/option-group.js.map +7 -0
  30. package/dist/item-form/options.js +30 -0
  31. package/dist/item-form/options.js.map +7 -0
  32. package/dist/item-form/quantity.js +131 -0
  33. package/dist/item-form/quantity.js.map +7 -0
  34. package/dist/item-form/root.js +151 -0
  35. package/dist/item-form/root.js.map +7 -0
  36. package/dist/media/image.js +30 -0
  37. package/dist/media/image.js.map +7 -0
  38. package/dist/money.js +20 -0
  39. package/dist/money.js.map +7 -0
  40. package/dist/next.js +8 -6
  41. package/dist/next.js.map +7 -1
  42. package/dist/otp/input.js +110 -0
  43. package/dist/otp/input.js.map +7 -0
  44. package/dist/overlay/engine.js +16 -8
  45. package/dist/overlay/engine.js.map +7 -1
  46. package/dist/{chunk-BY2WQGLO.js → overlay/history.js} +9 -4
  47. package/dist/overlay/history.js.map +7 -0
  48. package/dist/overlay/react.js +261 -0
  49. package/dist/overlay/react.js.map +7 -0
  50. package/dist/payment/methods.js +103 -0
  51. package/dist/payment/methods.js.map +7 -0
  52. package/dist/rich-text/banners.js +9 -0
  53. package/dist/rich-text/banners.js.map +7 -0
  54. package/dist/rich-text/browser.js +3 -3
  55. package/dist/rich-text/browser.js.map +7 -1
  56. package/dist/rich-text/core.js +75 -0
  57. package/dist/rich-text/core.js.map +7 -0
  58. package/dist/rich-text/index.js +3 -79
  59. package/dist/rich-text/index.js.map +7 -1
  60. package/dist/search/engine.js +93 -0
  61. package/dist/search/engine.js.map +7 -0
  62. package/dist/search/index.js +175 -0
  63. package/dist/search/index.js.map +7 -0
  64. package/dist/status/hours.js +177 -0
  65. package/dist/status/hours.js.map +7 -0
  66. package/dist/status/open-status.js +45 -0
  67. package/dist/status/open-status.js.map +7 -0
  68. package/dist/version.js +6 -0
  69. package/dist/version.js.map +7 -0
  70. package/package.json +3 -3
  71. package/dist/chunk-BY2WQGLO.js.map +0 -1
  72. package/dist/chunk-D3J7S33L.js.map +0 -1
@@ -0,0 +1,151 @@
1
+ "use client";
2
+
3
+ // src/item-form/root.tsx
4
+ import {
5
+ previewItem,
6
+ ZappieCartError
7
+ } from "@zappie/sdk";
8
+ import { useCartCatalogue, useZappie } from "@zappie/sdk/react";
9
+ import {
10
+ createContext,
11
+ useCallback,
12
+ useContext,
13
+ useMemo,
14
+ useRef,
15
+ useState
16
+ } from "react";
17
+ import { part } from "../internal/slot.js";
18
+ import { useControllableState } from "../internal/use-controllable-state.js";
19
+ import { jsx } from "react/jsx-runtime";
20
+ var ItemFormStateContext = createContext(null);
21
+ function useItemForm() {
22
+ const value = useContext(ItemFormStateContext);
23
+ if (!value) {
24
+ throw new Error("ItemForm parts require ItemForm.Root");
25
+ }
26
+ return value;
27
+ }
28
+ var GroupRegistry = createContext(
29
+ null
30
+ );
31
+ function Root({
32
+ item,
33
+ value,
34
+ defaultValue,
35
+ onValueChange,
36
+ defaultQuantity,
37
+ onAdded,
38
+ onCommit,
39
+ ...props
40
+ }) {
41
+ const client = useZappie();
42
+ const menu = useCartCatalogue();
43
+ const [input, setInput] = useControllableState({
44
+ value,
45
+ defaultValue: {
46
+ ...defaultValue,
47
+ itemId: item.id,
48
+ quantity: defaultQuantity ?? defaultValue?.quantity ?? item.quantity.min
49
+ },
50
+ onChange: onValueChange
51
+ });
52
+ const registry = useRef(/* @__PURE__ */ new Map());
53
+ const [added, setAdded] = useState(false);
54
+ const [attempted, setAttempted] = useState(false);
55
+ const [failure, setFailure] = useState(null);
56
+ const normalized = useMemo(
57
+ () => ({ ...input, itemId: item.id }),
58
+ [input, item.id]
59
+ );
60
+ const preview = useMemo(
61
+ () => previewItem(item, normalized),
62
+ [item, normalized]
63
+ );
64
+ const validation = useMemo(
65
+ () => client.cart.validate(normalized),
66
+ [client, normalized, menu]
67
+ );
68
+ const issues = failure ?? (attempted && !validation.ok ? validation.issues : []);
69
+ const setValue = useCallback(
70
+ (next) => {
71
+ setAdded(false);
72
+ setFailure(null);
73
+ setInput({ ...next, itemId: item.id });
74
+ },
75
+ [setInput, item.id]
76
+ );
77
+ const setQuantity = useCallback(
78
+ (quantity) => setValue({ ...normalized, quantity }),
79
+ [setValue, normalized]
80
+ );
81
+ const focusIssue = useCallback((errors) => {
82
+ for (const [groupId, element] of registry.current) {
83
+ if (errors.some((issue) => issue.groupId === groupId)) {
84
+ element.focus();
85
+ break;
86
+ }
87
+ }
88
+ }, []);
89
+ const add = useCallback(() => {
90
+ const result = client.cart.validate(normalized);
91
+ if (!result.ok) {
92
+ setAttempted(true);
93
+ setFailure(result.issues);
94
+ focusIssue(result.issues);
95
+ return null;
96
+ }
97
+ try {
98
+ const line = onCommit ? onCommit(normalized) : client.cart.add(item, normalized);
99
+ setAttempted(false);
100
+ setAdded(true);
101
+ onAdded?.(line);
102
+ return line;
103
+ } catch (error) {
104
+ if (error instanceof ZappieCartError) {
105
+ setAttempted(true);
106
+ setFailure([...error.issues]);
107
+ focusIssue([...error.issues]);
108
+ return null;
109
+ }
110
+ throw error;
111
+ }
112
+ }, [client, normalized, item, onAdded, onCommit, focusIssue]);
113
+ const context = useMemo(
114
+ () => ({
115
+ item,
116
+ ...preview,
117
+ quantity: normalized.quantity ?? item.quantity.min,
118
+ setQuantity,
119
+ issues,
120
+ canAdd: validation.ok && !failure,
121
+ add,
122
+ status: added ? "added" : validation.ok ? "valid" : "incomplete",
123
+ value: normalized,
124
+ setValue
125
+ }),
126
+ [
127
+ item,
128
+ preview,
129
+ normalized,
130
+ setQuantity,
131
+ issues,
132
+ validation.ok,
133
+ failure,
134
+ add,
135
+ added,
136
+ setValue
137
+ ]
138
+ );
139
+ return /* @__PURE__ */ jsx(ItemFormStateContext.Provider, { value: context, children: /* @__PURE__ */ jsx(GroupRegistry.Provider, { value: registry.current, children: part("div", props, context, {
140
+ "data-zappie-item": item.id,
141
+ "data-state": issues.length ? "invalid" : "valid",
142
+ "data-sold-out": item.isAvailable ? void 0 : ""
143
+ }) }) });
144
+ }
145
+ export {
146
+ GroupRegistry,
147
+ ItemFormStateContext,
148
+ Root,
149
+ useItemForm
150
+ };
151
+ //# sourceMappingURL=root.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/item-form/root.tsx"],
4
+ "sourcesContent": ["\"use client\";\nimport {\n previewItem,\n ZappieCartError,\n type CartIssue,\n type CartLine,\n type CartLineInput,\n type Item,\n type Money,\n type OptionGroup,\n} from \"@zappie/sdk\";\nimport { useCartCatalogue, useZappie } from \"@zappie/sdk/react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { part, type PartProps } from \"../internal/slot\";\nimport { useControllableState } from \"../internal/use-controllable-state\";\n/**\n * An SDK option group with the effective rules exposed by the item preview.\n */\nexport type ActiveGroup = OptionGroup;\n/**\n * The current item selection, preview prices, validation issues and actions supplied to item form parts.\n */\nexport type ItemFormContext = {\n item: Item;\n groups: ActiveGroup[];\n quantity: number;\n setQuantity: (quantity: number) => void;\n unitPrice: Money;\n total: Money;\n issues: CartIssue[];\n canAdd: boolean;\n add: () => CartLine | null;\n status: \"incomplete\" | \"valid\" | \"added\";\n value: CartLineInput;\n setValue: (value: CartLineInput) => void;\n};\nexport const ItemFormStateContext = createContext<ItemFormContext | null>(null);\nexport function useItemForm() {\n const value = useContext(ItemFormStateContext);\n if (!value) {\n throw new Error(\"ItemForm parts require ItemForm.Root\");\n }\n return value;\n}\nexport const GroupRegistry = createContext<Map<string, HTMLElement> | null>(\n null,\n);\n/**\n * Item form configuration with controlled or default selections and cart commit callbacks.\n * Supply onCommit to update an existing line instead of adding a new one.\n */\nexport type ItemFormProps = PartProps<ItemFormContext> & {\n item: Item;\n value?: CartLineInput;\n defaultValue?: Partial<CartLineInput>;\n onValueChange?: (value: CartLineInput) => void;\n defaultQuantity?: number;\n onAdded?: (line: CartLine) => void;\n /** Update an existing line through the same validation and focus workflow. */\n onCommit?: (input: CartLineInput) => CartLine;\n};\nexport function Root({\n item,\n value,\n defaultValue,\n onValueChange,\n defaultQuantity,\n onAdded,\n onCommit,\n ...props\n}: ItemFormProps) {\n const client = useZappie();\n const menu = useCartCatalogue();\n const [input, setInput] = useControllableState({\n value,\n defaultValue: {\n ...defaultValue,\n itemId: item.id,\n quantity: defaultQuantity ?? defaultValue?.quantity ?? item.quantity.min,\n },\n onChange: onValueChange,\n });\n const registry = useRef(new Map<string, HTMLElement>());\n const [added, setAdded] = useState(false);\n // Errors show only after the shopper tries to add (PRD 05 5.3), then track live validation.\n const [attempted, setAttempted] = useState(false);\n const [failure, setFailure] = useState<CartIssue[] | null>(null);\n const normalized = useMemo(\n () => ({ ...input, itemId: item.id }),\n [input, item.id],\n );\n const preview = useMemo(\n () => previewItem(item, normalized),\n [item, normalized],\n );\n const validation = useMemo(\n () => client.cart.validate(normalized),\n [client, normalized, menu],\n );\n const issues =\n failure ?? (attempted && !validation.ok ? validation.issues : []);\n const setValue = useCallback(\n (next: CartLineInput) => {\n setAdded(false);\n setFailure(null);\n setInput({ ...next, itemId: item.id });\n },\n [setInput, item.id],\n );\n const setQuantity = useCallback(\n (quantity: number) => setValue({ ...normalized, quantity }),\n [setValue, normalized],\n );\n const focusIssue = useCallback((errors: CartIssue[]) => {\n for (const [groupId, element] of registry.current) {\n if (errors.some((issue) => issue.groupId === groupId)) {\n element.focus();\n break;\n }\n }\n }, []);\n const add = useCallback(() => {\n const result = client.cart.validate(normalized);\n if (!result.ok) {\n setAttempted(true);\n setFailure(result.issues);\n focusIssue(result.issues);\n return null;\n }\n try {\n const line = onCommit\n ? onCommit(normalized)\n : client.cart.add(item, normalized);\n setAttempted(false);\n setAdded(true);\n onAdded?.(line);\n return line;\n } catch (error) {\n if (error instanceof ZappieCartError) {\n setAttempted(true);\n setFailure([...error.issues]);\n focusIssue([...error.issues]);\n return null;\n }\n throw error;\n }\n }, [client, normalized, item, onAdded, onCommit, focusIssue]);\n const context: ItemFormContext = useMemo(\n () => ({\n item,\n ...preview,\n quantity: normalized.quantity ?? item.quantity.min,\n setQuantity,\n issues,\n canAdd: validation.ok && !failure,\n add,\n status: added ? \"added\" : validation.ok ? \"valid\" : \"incomplete\",\n value: normalized,\n setValue,\n }),\n [\n item,\n preview,\n normalized,\n setQuantity,\n issues,\n validation.ok,\n failure,\n add,\n added,\n setValue,\n ],\n );\n return (\n <ItemFormStateContext.Provider value={context}>\n <GroupRegistry.Provider value={registry.current}>\n {part(\"div\", props, context, {\n \"data-zappie-item\": item.id,\n \"data-state\": issues.length ? \"invalid\" : \"valid\",\n \"data-sold-out\": item.isAvailable ? undefined : \"\",\n })}\n </GroupRegistry.Provider>\n </ItemFormStateContext.Provider>\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,30 @@
1
+ // src/media/image.tsx
2
+ import { resized, srcSet } from "@zappie/sdk/template";
3
+ import { jsx } from "react/jsx-runtime";
4
+ function Image({
5
+ src,
6
+ sizes = "100vw",
7
+ priority = false,
8
+ quality,
9
+ mode = "resize",
10
+ alt,
11
+ ...props
12
+ }) {
13
+ const responsive = mode === "resize" && /^https?:\/\//.test(src);
14
+ return /* @__PURE__ */ jsx(
15
+ "img",
16
+ {
17
+ ...props,
18
+ alt,
19
+ src: responsive ? resized(src, 960, quality) : src,
20
+ ...responsive ? { srcSet: srcSet(src, quality), sizes } : {},
21
+ loading: priority ? "eager" : "lazy",
22
+ decoding: priority ? "sync" : "async",
23
+ ...priority ? { fetchPriority: "high" } : {}
24
+ }
25
+ );
26
+ }
27
+ export {
28
+ Image
29
+ };
30
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/media/image.tsx"],
4
+ "sourcesContent": ["import { resized, srcSet } from \"@zappie/sdk/template\";\nimport type { ImgHTMLAttributes } from \"react\";\n\n/** Props for a responsive storefront image. */\nexport type ImageProps = Omit<\n ImgHTMLAttributes<HTMLImageElement>,\n \"src\" | \"srcSet\"\n> & {\n src: string;\n alt: string;\n sizes?: string;\n priority?: boolean;\n quality?: number;\n mode?: \"resize\" | \"direct\";\n};\n\n/** Render an image through same-origin resizing, or directly when unavailable. */\nexport function Image({\n src,\n sizes = \"100vw\",\n priority = false,\n quality,\n mode = \"resize\",\n alt,\n ...props\n}: ImageProps) {\n const responsive = mode === \"resize\" && /^https?:\\/\\//.test(src);\n return (\n <img\n {...props}\n alt={alt}\n src={responsive ? resized(src, 960, quality) : src}\n {...(responsive ? { srcSet: srcSet(src, quality), sizes } : {})}\n loading={priority ? \"eager\" : \"lazy\"}\n decoding={priority ? \"sync\" : \"async\"}\n {...(priority ? { fetchPriority: \"high\" as const } : {})}\n />\n );\n}\n"],
5
+ "mappings": ";AAAA,SAAS,SAAS,cAAc;AA4B5B;AAXG,SAAS,MAAM;AAAA,EACpB;AAAA,EACA,QAAQ;AAAA,EACR,WAAW;AAAA,EACX;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA,GAAG;AACL,GAAe;AACb,QAAM,aAAa,SAAS,YAAY,eAAe,KAAK,GAAG;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,KAAK,aAAa,QAAQ,KAAK,KAAK,OAAO,IAAI;AAAA,MAC9C,GAAI,aAAa,EAAE,QAAQ,OAAO,KAAK,OAAO,GAAG,MAAM,IAAI,CAAC;AAAA,MAC7D,SAAS,WAAW,UAAU;AAAA,MAC9B,UAAU,WAAW,SAAS;AAAA,MAC7B,GAAI,WAAW,EAAE,eAAe,OAAgB,IAAI,CAAC;AAAA;AAAA,EACxD;AAEJ;",
6
+ "names": []
7
+ }
package/dist/money.js ADDED
@@ -0,0 +1,20 @@
1
+ // src/money.tsx
2
+ import {
3
+ format
4
+ } from "@zappie/sdk";
5
+ import { forwardRef } from "react";
6
+ import { part } from "./internal/slot.js";
7
+ var Money = forwardRef(function Money2({ value, formatOptions, ...props }, ref) {
8
+ const formatted = format.money(value, formatOptions);
9
+ return part(
10
+ "data",
11
+ { ...props, children: props.children ?? formatted },
12
+ { formatted },
13
+ { value: String(value.amountMinor) },
14
+ ref
15
+ );
16
+ });
17
+ export {
18
+ Money
19
+ };
20
+ //# sourceMappingURL=money.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/money.tsx"],
4
+ "sourcesContent": ["import {\n format,\n type MoneyFormatOptions,\n type Money as MoneyValue,\n} from \"@zappie/sdk\";\nimport { forwardRef } from \"react\";\nimport { part, type PartProps } from \"./internal/slot\";\n/**\n * Render formatted SDK money in a data element, with the minor-unit amount as its value.\n * You can override the content with children or a render function receiving the formatted string.\n */\nexport const Money = forwardRef<\n HTMLElement,\n PartProps<{ formatted: string }> & {\n value: MoneyValue;\n formatOptions?: MoneyFormatOptions;\n }\n>(function Money({ value, formatOptions, ...props }, ref) {\n const formatted = format.money(value, formatOptions);\n return part(\n \"data\",\n { ...props, children: props.children ?? formatted },\n { formatted },\n { value: String(value.amountMinor) },\n ref,\n );\n});\n"],
5
+ "mappings": ";AAAA;AAAA,EACE;AAAA,OAGK;AACP,SAAS,kBAAkB;AAC3B,SAAS,YAA4B;AAK9B,IAAM,QAAQ,WAMnB,SAASA,OAAM,EAAE,OAAO,eAAe,GAAG,MAAM,GAAG,KAAK;AACxD,QAAM,YAAY,OAAO,MAAM,OAAO,aAAa;AACnD,SAAO;AAAA,IACL;AAAA,IACA,EAAE,GAAG,OAAO,UAAU,MAAM,YAAY,UAAU;AAAA,IAClD,EAAE,UAAU;AAAA,IACZ,EAAE,OAAO,OAAO,MAAM,WAAW,EAAE;AAAA,IACnC;AAAA,EACF;AACF,CAAC;",
6
+ "names": ["Money"]
7
+ }
package/dist/next.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { LOCATION_EVENT } from './chunk-BY2WQGLO.js';
3
- export { LOCATION_EVENT as OVERLAY_LOCATION_EVENT } from './chunk-BY2WQGLO.js';
4
- import { useEffect } from 'react';
5
2
 
3
+ // src/overlay/next.ts
4
+ import { useEffect } from "react";
5
+ import { LOCATION_EVENT } from "./overlay/history.js";
6
6
  var subscribers = 0;
7
7
  var uninstall;
8
8
  function installShallowHistory() {
@@ -50,7 +50,9 @@ function installShallowHistory() {
50
50
  function useNextOverlayBridge() {
51
51
  useEffect(installShallowHistory, []);
52
52
  }
53
-
54
- export { installShallowHistory, useNextOverlayBridge };
53
+ export {
54
+ LOCATION_EVENT as OVERLAY_LOCATION_EVENT,
55
+ installShallowHistory,
56
+ useNextOverlayBridge
57
+ };
55
58
  //# sourceMappingURL=next.js.map
56
- //# sourceMappingURL=next.js.map
package/dist/next.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../src/overlay/next.ts"],"names":[],"mappings":";;;;AASA,IAAI,WAAA,GAAc,CAAA;AAClB,IAAI,SAAA;AAEG,SAAS,qBAAA,GAAwB;AACtC,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,OAAO,MAAM;AAAA,IAAC,CAAA;AAAA,EAChB;AACA,EAAA,IAAI,kBAAkB,CAAA,EAAG;AACvB,IAAA,IAAI,WAAW,EAAE,IAAA,EAAM,IAAI,QAAA,EAAU,EAAA,EAAI,SAAS,KAAA,EAAM;AACxD,IAAA,MAAM,SAAS,MAAM;AACnB,MAAA,QAAA,GAAW;AAAA,QACT,MAAM,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,YAAA,IAAgB,OAAO,QAAA,CAAS,QAAA;AAAA,QAC5D,QAAA,EAAU,OAAO,QAAA,CAAS,QAAA;AAAA,QAC1B,OAAA,EAAS,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,OAAO,YAAY;AAAA,OACrD;AAAA,IACF,CAAA;AACA,IAAA,MAAA,EAAO;AACP,IAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,KAAyB;AACtC,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,EAAO,YAAA,IAAgB,OAAO,QAAA,CAAS,QAAA;AAC1D,MAAA,IAAA,CACG,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,YAAY,KAAK,QAAA,CAAS,OAAA,KAChD,IAAA,KAAS,QAAA,CAAS,IAAA,IAClB,MAAA,CAAO,QAAA,CAAS,QAAA,KAAa,SAAS,QAAA,EACtC;AACA,QAAA,KAAA,CAAM,wBAAA,EAAyB;AAC/B,QAAA,MAAA,EAAO;AACP,QAAA,MAAA,CAAO,aAAA,CAAc,IAAI,KAAA,CAAM,cAAc,CAAC,CAAA;AAC9C,QAAA;AAAA,MACF;AACA,MAAA,MAAA,EAAO;AAAA,IACT,CAAA;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAA,EAAY,KAAA,EAAO,IAAI,CAAA;AAC/C,IAAA,MAAA,CAAO,gBAAA,CAAiB,gBAAgB,MAAM,CAAA;AAC9C,IAAA,SAAA,GAAY,MAAM;AAChB,MAAA,MAAA,CAAO,mBAAA,CAAoB,UAAA,EAAY,KAAA,EAAO,IAAI,CAAA;AAClD,MAAA,MAAA,CAAO,mBAAA,CAAoB,gBAAgB,MAAM,CAAA;AAAA,IACnD,CAAA;AAAA,EACF;AACA,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,OAAO,MAAM;AACX,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,IAAI,EAAE,gBAAgB,CAAA,EAAG;AACvB,QAAA,SAAA,IAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAA;AACF;AAKO,SAAS,oBAAA,GAAuB;AACrC,EAAA,SAAA,CAAU,qBAAA,EAAuB,EAAE,CAAA;AACrC","file":"next.js","sourcesContent":["\"use client\";\nimport { useEffect } from \"react\";\nimport { LOCATION_EVENT } from \"./history\";\n/**\n * The event overlays re-read the URL on. A host that intercepts `popstate`\n * for its own shallow history (and stops it) must dispatch this too, or open\n * overlays never see Back.\n */\nexport { LOCATION_EVENT as OVERLAY_LOCATION_EVENT };\nlet subscribers = 0;\nlet uninstall: (() => void) | undefined;\n/** Capture same-page shallow moves before Next attempts a server navigation. */\nexport function installShallowHistory() {\n if (typeof window === \"undefined\") {\n return () => {};\n }\n if (subscribers++ === 0) {\n let previous = { base: \"\", pathname: \"\", shallow: false };\n const record = () => {\n previous = {\n base: window.history.state?.__zappieBase ?? window.location.pathname,\n pathname: window.location.pathname,\n shallow: Boolean(window.history.state?.__zappieBase),\n };\n };\n record();\n const onPop = (event: PopStateEvent) => {\n const base = event.state?.__zappieBase ?? window.location.pathname;\n if (\n (Boolean(event.state?.__zappieBase) || previous.shallow) &&\n base === previous.base &&\n window.location.pathname === previous.pathname\n ) {\n event.stopImmediatePropagation();\n record();\n window.dispatchEvent(new Event(LOCATION_EVENT));\n return;\n }\n record();\n };\n window.addEventListener(\"popstate\", onPop, true);\n window.addEventListener(LOCATION_EVENT, record);\n uninstall = () => {\n window.removeEventListener(\"popstate\", onPop, true);\n window.removeEventListener(LOCATION_EVENT, record);\n };\n }\n let released = false;\n return () => {\n if (!released) {\n released = true;\n if (--subscribers === 0) {\n uninstall?.();\n }\n }\n };\n}\n/**\n * Install the shared shallow-history bridge on mount and release it on unmount.\n * Keeps same-page overlay history changes from triggering Next server navigation.\n */\nexport function useNextOverlayBridge() {\n useEffect(installShallowHistory, []);\n}\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/overlay/next.ts"],
4
+ "sourcesContent": ["\"use client\";\nimport { useEffect } from \"react\";\nimport { LOCATION_EVENT } from \"./history\";\n/**\n * The event overlays re-read the URL on. A host that intercepts `popstate`\n * for its own shallow history (and stops it) must dispatch this too, or open\n * overlays never see Back.\n */\nexport { LOCATION_EVENT as OVERLAY_LOCATION_EVENT };\nlet subscribers = 0;\nlet uninstall: (() => void) | undefined;\n/** Capture same-page shallow moves before Next attempts a server navigation. */\nexport function installShallowHistory() {\n if (typeof window === \"undefined\") {\n return () => {};\n }\n if (subscribers++ === 0) {\n let previous = { base: \"\", pathname: \"\", shallow: false };\n const record = () => {\n previous = {\n base: window.history.state?.__zappieBase ?? window.location.pathname,\n pathname: window.location.pathname,\n shallow: Boolean(window.history.state?.__zappieBase),\n };\n };\n record();\n const onPop = (event: PopStateEvent) => {\n const base = event.state?.__zappieBase ?? window.location.pathname;\n if (\n (Boolean(event.state?.__zappieBase) || previous.shallow) &&\n base === previous.base &&\n window.location.pathname === previous.pathname\n ) {\n event.stopImmediatePropagation();\n record();\n window.dispatchEvent(new Event(LOCATION_EVENT));\n return;\n }\n record();\n };\n window.addEventListener(\"popstate\", onPop, true);\n window.addEventListener(LOCATION_EVENT, record);\n uninstall = () => {\n window.removeEventListener(\"popstate\", onPop, true);\n window.removeEventListener(LOCATION_EVENT, record);\n };\n }\n let released = false;\n return () => {\n if (!released) {\n released = true;\n if (--subscribers === 0) {\n uninstall?.();\n }\n }\n };\n}\n/**\n * Install the shared shallow-history bridge on mount and release it on unmount.\n * Keeps same-page overlay history changes from triggering Next server navigation.\n */\nexport function useNextOverlayBridge() {\n useEffect(installShallowHistory, []);\n}\n"],
5
+ "mappings": ";;;AACA,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAO/B,IAAI,cAAc;AAClB,IAAI;AAEG,SAAS,wBAAwB;AACtC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AACA,MAAI,kBAAkB,GAAG;AACvB,QAAI,WAAW,EAAE,MAAM,IAAI,UAAU,IAAI,SAAS,MAAM;AACxD,UAAM,SAAS,MAAM;AACnB,iBAAW;AAAA,QACT,MAAM,OAAO,QAAQ,OAAO,gBAAgB,OAAO,SAAS;AAAA,QAC5D,UAAU,OAAO,SAAS;AAAA,QAC1B,SAAS,QAAQ,OAAO,QAAQ,OAAO,YAAY;AAAA,MACrD;AAAA,IACF;AACA,WAAO;AACP,UAAM,QAAQ,CAAC,UAAyB;AACtC,YAAM,OAAO,MAAM,OAAO,gBAAgB,OAAO,SAAS;AAC1D,WACG,QAAQ,MAAM,OAAO,YAAY,KAAK,SAAS,YAChD,SAAS,SAAS,QAClB,OAAO,SAAS,aAAa,SAAS,UACtC;AACA,cAAM,yBAAyB;AAC/B,eAAO;AACP,eAAO,cAAc,IAAI,MAAM,cAAc,CAAC;AAC9C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AACA,WAAO,iBAAiB,YAAY,OAAO,IAAI;AAC/C,WAAO,iBAAiB,gBAAgB,MAAM;AAC9C,gBAAY,MAAM;AAChB,aAAO,oBAAoB,YAAY,OAAO,IAAI;AAClD,aAAO,oBAAoB,gBAAgB,MAAM;AAAA,IACnD;AAAA,EACF;AACA,MAAI,WAAW;AACf,SAAO,MAAM;AACX,QAAI,CAAC,UAAU;AACb,iBAAW;AACX,UAAI,EAAE,gBAAgB,GAAG;AACvB,oBAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,uBAAuB;AACrC,YAAU,uBAAuB,CAAC,CAAC;AACrC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ // src/otp/input.tsx
4
+ import {
5
+ forwardRef,
6
+ useEffect,
7
+ useRef
8
+ } from "react";
9
+ import { composeRefs, part } from "../internal/slot.js";
10
+ import { useControllableState } from "../internal/use-controllable-state.js";
11
+ import { jsx } from "react/jsx-runtime";
12
+ function slotAttributes(index, length, value, disabled, update, focus) {
13
+ return {
14
+ type: "text",
15
+ inputMode: "numeric",
16
+ autoComplete: index === 0 ? "one-time-code" : "off",
17
+ "aria-label": `Digit ${index + 1} of ${length}`,
18
+ "data-otp-slot": index,
19
+ value: value[index] ?? "",
20
+ disabled,
21
+ onChange: (event) => update(index, event.target.value),
22
+ onPaste: (event) => {
23
+ event.preventDefault();
24
+ update(index, event.clipboardData.getData("text"));
25
+ },
26
+ onKeyDown: (event) => {
27
+ if (event.key === "Backspace") {
28
+ event.preventDefault();
29
+ const target = value[index] ? index : Math.max(0, index - 1);
30
+ update(target, "");
31
+ focus(target);
32
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
33
+ event.preventDefault();
34
+ focus(index + (event.key === "ArrowLeft" ? -1 : 1));
35
+ }
36
+ },
37
+ onFocus: (event) => event.currentTarget.select()
38
+ };
39
+ }
40
+ var Input = forwardRef(function Input2({
41
+ length = 6,
42
+ value,
43
+ defaultValue = "",
44
+ onValueChange,
45
+ onComplete,
46
+ disabled = false,
47
+ ...props
48
+ }, ref) {
49
+ if (!Number.isInteger(length) || length < 1 || length > 12) {
50
+ throw new RangeError("OTP length must be 1\u201312");
51
+ }
52
+ const [current, setValue] = useControllableState({
53
+ value,
54
+ defaultValue,
55
+ onChange: onValueChange
56
+ });
57
+ const element = useRef(null);
58
+ const previous = useRef("");
59
+ const callback = useRef(onComplete);
60
+ callback.current = onComplete;
61
+ useEffect(() => {
62
+ if (current.length === length && /^\d+$/.test(current) && previous.current !== current) {
63
+ callback.current?.(current);
64
+ }
65
+ previous.current = current;
66
+ }, [current, length]);
67
+ const focus = (index) => element.current?.querySelector(
68
+ `[data-otp-slot="${Math.max(0, Math.min(length - 1, index))}"]`
69
+ )?.focus();
70
+ const update = (index, text) => {
71
+ if (disabled) {
72
+ return;
73
+ }
74
+ const digits = text.replace(/\D/g, "");
75
+ const start = digits.length >= length ? 0 : index;
76
+ const next = (current.slice(0, start) + digits + current.slice(start + Math.max(1, digits.length))).slice(0, length);
77
+ setValue(next);
78
+ if (digits) {
79
+ focus(start + digits.length);
80
+ }
81
+ };
82
+ const adopt = useRef(update);
83
+ adopt.current = update;
84
+ useEffect(() => {
85
+ const typed = Array.from(
86
+ element.current?.querySelectorAll("[data-otp-slot]") ?? [],
87
+ (input) => input.value
88
+ ).join("");
89
+ if (typed && typed !== current) {
90
+ adopt.current(0, typed);
91
+ }
92
+ }, []);
93
+ const getSlotProps = (index) => slotAttributes(index, length, current, disabled, update, focus);
94
+ const slots = Array.from({ length }, (_, index) => current[index] ?? "");
95
+ return part(
96
+ "div",
97
+ {
98
+ ...props,
99
+ children: props.children ?? slots.map((_, index) => /* @__PURE__ */ jsx("input", { ...getSlotProps(index) }, index))
100
+ },
101
+ { value: current, slots, getSlotProps },
102
+ { role: "group", "data-disabled": disabled ? "" : void 0 },
103
+ composeRefs(ref, element)
104
+ );
105
+ });
106
+ var Otp = { Input };
107
+ export {
108
+ Otp
109
+ };
110
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/otp/input.tsx"],
4
+ "sourcesContent": ["\"use client\";\nimport {\n forwardRef,\n useEffect,\n useRef,\n type ChangeEvent,\n type ClipboardEvent,\n type KeyboardEvent,\n} from \"react\";\nimport { composeRefs, part, type PartProps } from \"../internal/slot\";\nimport { useControllableState } from \"../internal/use-controllable-state\";\nexport type OtpState = {\n value: string;\n slots: string[];\n getSlotProps: (index: number) => ReturnType<typeof slotAttributes>;\n};\nfunction slotAttributes(\n index: number,\n length: number,\n value: string,\n disabled: boolean,\n update: (index: number, text: string) => void,\n focus: (index: number) => void,\n) {\n return {\n type: \"text\",\n inputMode: \"numeric\" as const,\n autoComplete: index === 0 ? \"one-time-code\" : \"off\",\n \"aria-label\": `Digit ${index + 1} of ${length}`,\n \"data-otp-slot\": index,\n value: value[index] ?? \"\",\n disabled,\n onChange: (event: ChangeEvent<HTMLInputElement>) =>\n update(index, event.target.value),\n onPaste: (event: ClipboardEvent<HTMLInputElement>) => {\n event.preventDefault();\n update(index, event.clipboardData.getData(\"text\"));\n },\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Backspace\") {\n event.preventDefault();\n const target = value[index] ? index : Math.max(0, index - 1);\n update(target, \"\");\n focus(target);\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n event.preventDefault();\n focus(index + (event.key === \"ArrowLeft\" ? -1 : 1));\n }\n },\n onFocus: (event: { currentTarget: HTMLInputElement }) =>\n event.currentTarget.select(),\n };\n}\nconst Input = forwardRef<\n HTMLElement,\n PartProps<OtpState> & {\n length?: number;\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n onComplete?: (value: string) => void;\n disabled?: boolean;\n }\n>(function Input(\n {\n length = 6,\n value,\n defaultValue = \"\",\n onValueChange,\n onComplete,\n disabled = false,\n ...props\n },\n ref,\n) {\n if (!Number.isInteger(length) || length < 1 || length > 12) {\n throw new RangeError(\"OTP length must be 1\u201312\");\n }\n const [current, setValue] = useControllableState({\n value,\n defaultValue,\n onChange: onValueChange,\n });\n const element = useRef<HTMLElement>(null);\n const previous = useRef(\"\");\n const callback = useRef(onComplete);\n callback.current = onComplete;\n useEffect(() => {\n if (\n current.length === length &&\n /^\\d+$/.test(current) &&\n previous.current !== current\n ) {\n callback.current?.(current);\n }\n previous.current = current;\n }, [current, length]);\n const focus = (index: number) =>\n element.current\n ?.querySelector<HTMLInputElement>(\n `[data-otp-slot=\"${Math.max(0, Math.min(length - 1, index))}\"]`,\n )\n ?.focus();\n const update = (index: number, text: string) => {\n if (disabled) {\n return;\n }\n const digits = text.replace(/\\D/g, \"\");\n const start = digits.length >= length ? 0 : index;\n const next = (\n current.slice(0, start) +\n digits +\n current.slice(start + Math.max(1, digits.length))\n ).slice(0, length);\n setValue(next);\n if (digits) {\n focus(start + digits.length);\n }\n };\n // An SMS code can be autofilled (or typed) before hydration: it sits in the\n // DOM with no change event. Adopt it once the component mounts.\n const adopt = useRef(update);\n adopt.current = update;\n useEffect(() => {\n const typed = Array.from(\n element.current?.querySelectorAll<HTMLInputElement>(\"[data-otp-slot]\") ??\n [],\n (input) => input.value,\n ).join(\"\");\n if (typed && typed !== current) {\n adopt.current(0, typed);\n }\n // Mount only: later edits arrive as change events.\n }, []);\n const getSlotProps = (index: number) =>\n slotAttributes(index, length, current, disabled, update, focus);\n const slots = Array.from({ length }, (_, index) => current[index] ?? \"\");\n return part(\n \"div\",\n {\n ...props,\n children:\n props.children ??\n slots.map((_, index) => <input key={index} {...getSlotProps(index)} />),\n },\n { value: current, slots, getSlotProps },\n { role: \"group\", \"data-disabled\": disabled ? \"\" : undefined },\n composeRefs(ref, element),\n );\n});\n/**\n * A numeric one-time-code input with paste, autofill and keyboard focus handling.\n * Otp.Input defaults to six digits and calls onComplete when a new complete code is entered.\n * You supply code verification.\n */\nexport const Otp = { Input };\n"],
5
+ "mappings": "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",
6
+ "names": ["Input"]
7
+ }
@@ -1,10 +1,15 @@
1
1
  "use client";
2
- import { partId, part, composeRefs } from '../chunk-D3J7S33L.js';
3
- import { Dialog } from '@base-ui/react/dialog';
4
- import { Drawer } from '@base-ui/react/drawer';
5
- import { createContext, forwardRef, useContext } from 'react';
6
- import { jsx, jsxs } from 'react/jsx-runtime';
7
2
 
3
+ // src/overlay/engine.tsx
4
+ import { Dialog } from "@base-ui/react/dialog";
5
+ import { Drawer } from "@base-ui/react/drawer";
6
+ import {
7
+ createContext,
8
+ forwardRef,
9
+ useContext
10
+ } from "react";
11
+ import { composeRefs, part, partId } from "../internal/slot.js";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
8
13
  var PartsContext = createContext(null);
9
14
  function useEngineParts() {
10
15
  const parts = useContext(PartsContext);
@@ -166,7 +171,10 @@ var EngineClose = forwardRef(
166
171
  );
167
172
  }
168
173
  );
169
-
170
- export { EngineClose, EngineTitle, Surface, useEngineParts };
174
+ export {
175
+ EngineClose,
176
+ EngineTitle,
177
+ Surface,
178
+ useEngineParts
179
+ };
171
180
  //# sourceMappingURL=engine.js.map
172
- //# sourceMappingURL=engine.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../../src/overlay/engine.tsx"],"names":["EngineTitle","EngineClose"],"mappings":"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","file":"engine.js","sourcesContent":["\"use client\";\n// The overlay engine: the only module that imports Base UI. It loads on first open (or an\n// idle prefetch) so dialog and drawer mechanics stay out of the initial bundle.\nimport { Dialog } from \"@base-ui/react/dialog\";\nimport { Drawer } from \"@base-ui/react/drawer\";\nimport {\n createContext,\n forwardRef,\n useContext,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { composeRefs, part, partId, type PartProps } from \"../internal/slot\";\n\nexport type Presentation = \"dialog\" | \"drawer\" | \"sheet\";\nexport type SwipeDirection = \"up\" | \"down\" | \"left\" | \"right\";\ntype ChangeDetails = {\n reason: string;\n event: Event;\n cancel: () => void;\n};\nexport type SurfaceProps = {\n open: boolean;\n presentation: Presentation;\n swipeDirection: SwipeDirection;\n /** Ids the trigger points at; caller-supplied ids win. */\n contentId: string;\n titleId?: string | undefined;\n trigger: { current: HTMLElement | null };\n onOpen: () => void;\n onClose: () => void;\n onEscape?: ((event: KeyboardEvent) => void) | undefined;\n onInteractOutside?: ((event: Event) => void) | undefined;\n forceMount?: true | undefined;\n container?: HTMLElement | null | undefined;\n state: unknown;\n contentProps: PartProps<never>;\n contentRef: Ref<HTMLElement>;\n};\ntype Parts = { Title: typeof Dialog.Title; Close: typeof Dialog.Close };\nconst PartsContext = createContext<Parts | null>(null);\nexport function useEngineParts() {\n const parts = useContext(PartsContext);\n if (!parts) {\n throw new Error(\n \"Overlay.Title and Overlay.Close must be inside Overlay.Content\",\n );\n }\n return parts;\n}\n/** Route Base UI's open changes through the URL, letting callbacks cancel a dismissal. */\nfunction changeHandler(props: SurfaceProps) {\n return (open: boolean, details: ChangeDetails) => {\n if (open) {\n props.onOpen();\n return;\n }\n const callback =\n details.reason === \"escape-key\"\n ? (props.onEscape as ((event: Event) => void) | undefined)\n : details.reason === \"outside-press\" || details.reason === \"focus-out\"\n ? props.onInteractOutside\n : undefined;\n callback?.(details.event);\n if (details.event?.defaultPrevented && callback) {\n details.cancel();\n return;\n }\n props.onClose();\n };\n}\nfunction Popup({\n props,\n Component,\n children,\n}: {\n props: SurfaceProps;\n Component: typeof Dialog.Popup;\n children?: ReactNode;\n}) {\n const { contentProps, contentRef, presentation, state } = props;\n const { id: _ownId, ...rest } = contentProps as PartProps<never> & {\n id?: string;\n };\n const id = partId(contentProps as Parameters<typeof partId>[0]);\n return (\n <Component\n id={id ?? props.contentId}\n // Prefer an explicit [data-autofocus] target, else Base UI's first tabbable.\n initialFocus={() =>\n document\n .getElementById(id ?? props.contentId)\n ?.querySelector<HTMLElement>(\"[data-autofocus]\") ?? true\n }\n finalFocus={() => props.trigger.current ?? true}\n render={(baseProps) => {\n const { ref: baseRef, ...base } = baseProps as unknown as Record<\n string,\n unknown\n > & {\n ref?: Ref<HTMLElement>;\n };\n return part(\n \"div\",\n (children === undefined\n ? rest\n : { ...rest, children }) as PartProps<unknown>,\n state,\n {\n ...base,\n \"aria-modal\": true,\n \"data-presentation\": presentation,\n \"data-state\": props.open ? \"open\" : \"closed\",\n },\n composeRefs(baseRef, contentRef),\n );\n }}\n />\n );\n}\nexport function Surface(props: SurfaceProps & { children?: ReactNode }) {\n const { children, forceMount, container, presentation } = props;\n const portal = {\n ...(forceMount ? { keepMounted: true } : {}),\n ...(container !== undefined ? { container } : {}),\n };\n if (presentation === \"dialog\") {\n return (\n <Dialog.Root\n open={props.open}\n onOpenChange={changeHandler(props) as never}\n >\n <PartsContext.Provider\n value={{ Title: Dialog.Title, Close: Dialog.Close }}\n >\n <Dialog.Portal {...portal}>\n {/* Unstyled; templates style [data-zappie-backdrop] with data-state/data-presentation. */}\n <Dialog.Backdrop\n data-zappie-backdrop=\"\"\n data-presentation={presentation}\n data-state={props.open ? \"open\" : \"closed\"}\n />\n <Popup props={props} Component={Dialog.Popup}>\n {children}\n </Popup>\n </Dialog.Portal>\n </PartsContext.Provider>\n </Dialog.Root>\n );\n }\n return (\n <Drawer.Root\n open={props.open}\n onOpenChange={changeHandler(props) as never}\n swipeDirection={props.swipeDirection}\n >\n <PartsContext.Provider\n value={{\n Title: Drawer.Title as typeof Dialog.Title,\n Close: Drawer.Close as typeof Dialog.Close,\n }}\n >\n <Drawer.Portal {...portal}>\n <Drawer.Backdrop\n data-zappie-backdrop=\"\"\n data-presentation={presentation}\n data-state={props.open ? \"open\" : \"closed\"}\n />\n {/* Keeps focused fields visible above the on-screen keyboard in bottom sheets. */}\n <Drawer.VirtualKeyboardProvider>\n <Drawer.Viewport>\n <Popup\n props={props}\n Component={Drawer.Popup as typeof Dialog.Popup}\n >\n {children}\n </Popup>\n </Drawer.Viewport>\n </Drawer.VirtualKeyboardProvider>\n </Drawer.Portal>\n </PartsContext.Provider>\n </Drawer.Root>\n );\n}\n/** Title and Close rendered with whichever engine (dialog or drawer) owns the content. */\ntype EnginePartProps = PartProps<unknown> & {\n id?: string | undefined;\n state: unknown;\n};\nexport const EngineTitle = forwardRef<HTMLElement, EnginePartProps>(\n function EngineTitle({ state, ...props }, ref) {\n const { Title } = useEngineParts();\n const id = partId(props as Parameters<typeof partId>[0]);\n return (\n <Title\n {...(id ? { id } : {})}\n render={(base) => {\n const { ref: baseRef, ...rest } = base as unknown as Record<\n string,\n unknown\n > & {\n ref?: Ref<HTMLElement>;\n };\n return part(\"h2\", props, state, rest, composeRefs(baseRef, ref));\n }}\n />\n );\n },\n);\nexport const EngineClose = forwardRef<HTMLElement, EnginePartProps>(\n function EngineClose({ state, ...props }, ref) {\n const { Close } = useEngineParts();\n return (\n <Close\n render={(base) => {\n const { ref: baseRef, ...rest } = base as unknown as Record<\n string,\n unknown\n > & {\n ref?: Ref<HTMLElement>;\n };\n return part(\n \"button\",\n props,\n state,\n { type: \"button\", ...rest },\n composeRefs(baseRef, ref),\n );\n }}\n />\n );\n },\n);\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/overlay/engine.tsx"],
4
+ "sourcesContent": ["\"use client\";\n// The overlay engine: the only module that imports Base UI. It loads on first open (or an\n// idle prefetch) so dialog and drawer mechanics stay out of the initial bundle.\nimport { Dialog } from \"@base-ui/react/dialog\";\nimport { Drawer } from \"@base-ui/react/drawer\";\nimport {\n createContext,\n forwardRef,\n useContext,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { composeRefs, part, partId, type PartProps } from \"../internal/slot\";\n\nexport type Presentation = \"dialog\" | \"drawer\" | \"sheet\";\nexport type SwipeDirection = \"up\" | \"down\" | \"left\" | \"right\";\ntype ChangeDetails = {\n reason: string;\n event: Event;\n cancel: () => void;\n};\nexport type SurfaceProps = {\n open: boolean;\n presentation: Presentation;\n swipeDirection: SwipeDirection;\n /** Ids the trigger points at; caller-supplied ids win. */\n contentId: string;\n titleId?: string | undefined;\n trigger: { current: HTMLElement | null };\n onOpen: () => void;\n onClose: () => void;\n onEscape?: ((event: KeyboardEvent) => void) | undefined;\n onInteractOutside?: ((event: Event) => void) | undefined;\n forceMount?: true | undefined;\n container?: HTMLElement | null | undefined;\n state: unknown;\n contentProps: PartProps<never>;\n contentRef: Ref<HTMLElement>;\n};\ntype Parts = { Title: typeof Dialog.Title; Close: typeof Dialog.Close };\nconst PartsContext = createContext<Parts | null>(null);\nexport function useEngineParts() {\n const parts = useContext(PartsContext);\n if (!parts) {\n throw new Error(\n \"Overlay.Title and Overlay.Close must be inside Overlay.Content\",\n );\n }\n return parts;\n}\n/** Route Base UI's open changes through the URL, letting callbacks cancel a dismissal. */\nfunction changeHandler(props: SurfaceProps) {\n return (open: boolean, details: ChangeDetails) => {\n if (open) {\n props.onOpen();\n return;\n }\n const callback =\n details.reason === \"escape-key\"\n ? (props.onEscape as ((event: Event) => void) | undefined)\n : details.reason === \"outside-press\" || details.reason === \"focus-out\"\n ? props.onInteractOutside\n : undefined;\n callback?.(details.event);\n if (details.event?.defaultPrevented && callback) {\n details.cancel();\n return;\n }\n props.onClose();\n };\n}\nfunction Popup({\n props,\n Component,\n children,\n}: {\n props: SurfaceProps;\n Component: typeof Dialog.Popup;\n children?: ReactNode;\n}) {\n const { contentProps, contentRef, presentation, state } = props;\n const { id: _ownId, ...rest } = contentProps as PartProps<never> & {\n id?: string;\n };\n const id = partId(contentProps as Parameters<typeof partId>[0]);\n return (\n <Component\n id={id ?? props.contentId}\n // Prefer an explicit [data-autofocus] target, else Base UI's first tabbable.\n initialFocus={() =>\n document\n .getElementById(id ?? props.contentId)\n ?.querySelector<HTMLElement>(\"[data-autofocus]\") ?? true\n }\n finalFocus={() => props.trigger.current ?? true}\n render={(baseProps) => {\n const { ref: baseRef, ...base } = baseProps as unknown as Record<\n string,\n unknown\n > & {\n ref?: Ref<HTMLElement>;\n };\n return part(\n \"div\",\n (children === undefined\n ? rest\n : { ...rest, children }) as PartProps<unknown>,\n state,\n {\n ...base,\n \"aria-modal\": true,\n \"data-presentation\": presentation,\n \"data-state\": props.open ? \"open\" : \"closed\",\n },\n composeRefs(baseRef, contentRef),\n );\n }}\n />\n );\n}\nexport function Surface(props: SurfaceProps & { children?: ReactNode }) {\n const { children, forceMount, container, presentation } = props;\n const portal = {\n ...(forceMount ? { keepMounted: true } : {}),\n ...(container !== undefined ? { container } : {}),\n };\n if (presentation === \"dialog\") {\n return (\n <Dialog.Root\n open={props.open}\n onOpenChange={changeHandler(props) as never}\n >\n <PartsContext.Provider\n value={{ Title: Dialog.Title, Close: Dialog.Close }}\n >\n <Dialog.Portal {...portal}>\n {/* Unstyled; templates style [data-zappie-backdrop] with data-state/data-presentation. */}\n <Dialog.Backdrop\n data-zappie-backdrop=\"\"\n data-presentation={presentation}\n data-state={props.open ? \"open\" : \"closed\"}\n />\n <Popup props={props} Component={Dialog.Popup}>\n {children}\n </Popup>\n </Dialog.Portal>\n </PartsContext.Provider>\n </Dialog.Root>\n );\n }\n return (\n <Drawer.Root\n open={props.open}\n onOpenChange={changeHandler(props) as never}\n swipeDirection={props.swipeDirection}\n >\n <PartsContext.Provider\n value={{\n Title: Drawer.Title as typeof Dialog.Title,\n Close: Drawer.Close as typeof Dialog.Close,\n }}\n >\n <Drawer.Portal {...portal}>\n <Drawer.Backdrop\n data-zappie-backdrop=\"\"\n data-presentation={presentation}\n data-state={props.open ? \"open\" : \"closed\"}\n />\n {/* Keeps focused fields visible above the on-screen keyboard in bottom sheets. */}\n <Drawer.VirtualKeyboardProvider>\n <Drawer.Viewport>\n <Popup\n props={props}\n Component={Drawer.Popup as typeof Dialog.Popup}\n >\n {children}\n </Popup>\n </Drawer.Viewport>\n </Drawer.VirtualKeyboardProvider>\n </Drawer.Portal>\n </PartsContext.Provider>\n </Drawer.Root>\n );\n}\n/** Title and Close rendered with whichever engine (dialog or drawer) owns the content. */\ntype EnginePartProps = PartProps<unknown> & {\n id?: string | undefined;\n state: unknown;\n};\nexport const EngineTitle = forwardRef<HTMLElement, EnginePartProps>(\n function EngineTitle({ state, ...props }, ref) {\n const { Title } = useEngineParts();\n const id = partId(props as Parameters<typeof partId>[0]);\n return (\n <Title\n {...(id ? { id } : {})}\n render={(base) => {\n const { ref: baseRef, ...rest } = base as unknown as Record<\n string,\n unknown\n > & {\n ref?: Ref<HTMLElement>;\n };\n return part(\"h2\", props, state, rest, composeRefs(baseRef, ref));\n }}\n />\n );\n },\n);\nexport const EngineClose = forwardRef<HTMLElement, EnginePartProps>(\n function EngineClose({ state, ...props }, ref) {\n const { Close } = useEngineParts();\n return (\n <Close\n render={(base) => {\n const { ref: baseRef, ...rest } = base as unknown as Record<\n string,\n unknown\n > & {\n ref?: Ref<HTMLElement>;\n };\n return part(\n \"button\",\n props,\n state,\n { type: \"button\", ...rest },\n composeRefs(baseRef, ref),\n );\n }}\n />\n );\n },\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["EngineTitle", "EngineClose"]
7
+ }
@@ -91,7 +91,12 @@ function closeOverlay(param, id, options = {}) {
91
91
  entry && url.searchParams.get(entry.param) === entry.id ? entry : null
92
92
  );
93
93
  }
94
-
95
- export { LOCATION_EVENT, closeOverlay, locationSnapshot, openOverlay, subscribeLocation };
96
- //# sourceMappingURL=chunk-BY2WQGLO.js.map
97
- //# sourceMappingURL=chunk-BY2WQGLO.js.map
94
+ export {
95
+ LOCATION_EVENT,
96
+ closeOverlay,
97
+ getCurrentOverlayEntry,
98
+ locationSnapshot,
99
+ openOverlay,
100
+ subscribeLocation
101
+ };
102
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/overlay/history.ts"],
4
+ "sourcesContent": ["export type OverlayEntry = { param: string; id: string; stack: string[] };\nexport type OverlayQuery = Record<string, string | null | undefined>;\nexport type CloseOptions = {\n fallback?: OverlayQuery | undefined;\n omitParams?: string[] | undefined;\n};\nexport const LOCATION_EVENT = \"zappie:location\";\nexport function getCurrentOverlayEntry(): OverlayEntry | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n const entry = window.history.state?.__zappieOverlay;\n if (\n !entry ||\n typeof entry.param !== \"string\" ||\n typeof entry.id !== \"string\"\n ) {\n return null;\n }\n return {\n param: entry.param,\n id: entry.id,\n stack: Array.isArray(entry.stack)\n ? entry.stack.filter((key: unknown) => typeof key === \"string\")\n : [],\n };\n}\nexport function subscribeLocation(listener: () => void) {\n window.addEventListener(\"popstate\", listener);\n window.addEventListener(LOCATION_EVENT, listener);\n return () => {\n window.removeEventListener(\"popstate\", listener);\n window.removeEventListener(LOCATION_EVENT, listener);\n };\n}\nexport function locationSnapshot() {\n return window.location.search;\n}\nfunction applyQuery(url: URL, query: OverlayQuery) {\n for (const [key, value] of Object.entries(query)) {\n if (value == null) {\n url.searchParams.delete(key);\n } else {\n url.searchParams.set(key, value);\n }\n }\n}\nfunction write(\n type: \"pushState\" | \"replaceState\",\n url: URL,\n overlay: OverlayEntry | null,\n) {\n const state = { ...window.history.state };\n delete state.__zappieOverlay;\n if (overlay) {\n state.__zappieOverlay = overlay;\n }\n state.__zappieBase ??= window.location.pathname;\n if (url.pathname !== window.location.pathname) {\n delete state.__NA;\n delete state.__PRIVATE_NEXTJS_INTERNALS_TREE;\n }\n // Bypass Next's wrapper: shallow overlay writes must not remount the page.\n const prototype = Object.getPrototypeOf(window.history) as History;\n prototype[type].call(window.history, state, \"\", url.href);\n window.dispatchEvent(new Event(LOCATION_EVENT));\n}\nexport function openOverlay(\n param: string,\n id: string,\n query: OverlayQuery = {},\n) {\n const url = new URL(window.location.href);\n applyQuery(url, query);\n url.searchParams.set(param, id);\n if (url.href === window.location.href) {\n return;\n }\n const previous = getCurrentOverlayEntry();\n write(\"pushState\", url, {\n param,\n id,\n stack: [...(previous?.stack ?? []), `${param}:${id}`],\n });\n}\nexport function closeOverlay(\n param: string,\n id?: string,\n options: CloseOptions = {},\n) {\n const url = new URL(window.location.href);\n if (!url.searchParams.has(param)) {\n return;\n }\n const entry = getCurrentOverlayEntry();\n const stack = entry?.stack ?? [];\n const index = id\n ? stack.lastIndexOf(`${param}:${id}`)\n : stack.reduce(\n (found, key, index) => (key.startsWith(`${param}:`) ? index : found),\n -1,\n );\n if (index >= 0) {\n window.history.go(-(stack.length - index));\n return;\n }\n applyQuery(url, options.fallback ?? {});\n if (!options.fallback || !(param in options.fallback)) {\n url.searchParams.delete(param);\n }\n for (const omitted of options.omitParams ?? []) {\n url.searchParams.delete(omitted);\n }\n write(\n \"replaceState\",\n url,\n entry && url.searchParams.get(entry.param) === entry.id ? entry : null,\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["index"]
7
+ }