@zappie/foundations 0.1.9 → 0.1.12
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 +23 -0
- package/dist/account/index.js.map +0 -1
- package/dist/branch-map/colors.js.map +0 -1
- package/dist/branch-map/delivery-map.js.map +0 -1
- package/dist/branch-map/delivery-runtime.js.map +0 -1
- package/dist/branch-map/fit.js.map +0 -1
- package/dist/branch-map/geometry.js.map +0 -1
- package/dist/branch-map/index.js.map +0 -1
- package/dist/branch-map/loader.js.map +0 -1
- package/dist/branch-map/markers.js.map +0 -1
- package/dist/branch-map/runtime.js.map +0 -1
- package/dist/branch-map/use-map-runtime.js.map +0 -1
- package/dist/cart/index.js.map +0 -1
- package/dist/{core-DdojsUzR.d.ts → core-Cd-_zlQx.d.ts} +2 -1
- package/dist/deferred/index.js.map +0 -1
- package/dist/{engine-Bfbv9M0D.d.ts → engine-D2iRshfW.d.ts} +6 -4
- package/dist/fulfilment/address-picker.js.map +0 -1
- package/dist/fulfilment/branch-picker.js.map +0 -1
- package/dist/fulfilment/schedule.js.map +0 -1
- package/dist/fulfilment/switch.js.map +0 -1
- package/dist/{history-Bqu12Vkz.d.ts → history-BlytQinP.d.ts} +2 -1
- package/dist/index.d.ts +38 -36
- package/dist/index.js.map +0 -1
- package/dist/internal/combobox.js.map +0 -1
- package/dist/internal/data-attrs.js.map +0 -1
- package/dist/internal/ids.js.map +0 -1
- package/dist/internal/slot.js.map +1 -2
- package/dist/internal/use-controllable-state.js.map +0 -1
- package/dist/item-form/index.js.map +0 -1
- package/dist/item-form/option-group.js.map +0 -1
- package/dist/item-form/options.js.map +0 -1
- package/dist/item-form/quantity.js.map +0 -1
- package/dist/item-form/root.js.map +0 -1
- package/dist/media/image.js.map +0 -1
- package/dist/money.js.map +0 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js.map +0 -1
- package/dist/otp/input.js.map +0 -1
- package/dist/overlay/engine.d.ts +1 -1
- package/dist/overlay/engine.js.map +0 -1
- package/dist/overlay/history.js.map +0 -1
- package/dist/overlay/react.js.map +0 -1
- package/dist/payment/methods.js.map +0 -1
- package/dist/rich-text/banners.js.map +0 -1
- package/dist/rich-text/browser.d.ts +1 -1
- package/dist/rich-text/browser.js.map +0 -1
- package/dist/rich-text/core.js.map +0 -1
- package/dist/rich-text/index.d.ts +1 -1
- package/dist/rich-text/index.js.map +0 -1
- package/dist/search/engine.js.map +0 -1
- package/dist/search/index.js.map +0 -1
- package/dist/status/hours.js.map +0 -1
- package/dist/status/open-status.js.map +0 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -2
- package/package.json +3 -3
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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
4
|
"mappings": "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",
|
|
6
5
|
"names": ["EngineTitle", "EngineClose"]
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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
4
|
"mappings": "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",
|
|
6
5
|
"names": ["index"]
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/overlay/react.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type Ref,\n} from \"react\";\nimport { createPortal, flushSync } from \"react-dom\";\nimport { composeRefs, part, partId, type PartProps } from \"../internal/slot\";\nimport type { Presentation, SwipeDirection } from \"./engine\";\nimport {\n closeOverlay,\n locationSnapshot,\n openOverlay,\n subscribeLocation,\n type CloseOptions,\n type OverlayQuery,\n} from \"./history\";\n\ntype EngineModule = typeof import(\"./engine\");\nlet engineModule: EngineModule | undefined;\nlet enginePromise: Promise<EngineModule> | undefined;\n/**\n * Load the overlay engine (Base UI dialog and drawer). It is a separate chunk, prefetched once\n * the page has loaded and the browser is idle, and on trigger hover/focus, so it is ready by\n * the first open.\n */\nexport function loadOverlayEngine(): Promise<EngineModule> {\n enginePromise ??= import(\"./engine\").then(\n (module) => (engineModule = module),\n (error: unknown) => {\n // A failed chunk load (e.g. offline) must not poison later opens.\n enginePromise = undefined;\n throw error;\n },\n );\n return enginePromise;\n}\n\n/**\n * Control an overlay whose open state is stored in a URL query parameter.\n *\n * @param param - The query parameter to read and update.\n * @param id - The value that identifies this overlay as open.\n * @param options - Fallback query values and query parameters to omit when closing.\n * @returns Reactive open state and history-backed open and close actions.\n */\nexport function useOverlay(param: string, id: string, options?: CloseOptions) {\n const search = useSyncExternalStore(\n subscribeLocation,\n locationSnapshot,\n () => \"\",\n );\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const open = useCallback(\n (query?: OverlayQuery) => openOverlay(param, id, query),\n [param, id],\n );\n const close = useCallback(\n () => closeOverlay(param, id, optionsRef.current),\n [param, id],\n );\n return useMemo(\n () => ({\n isOpen: new URLSearchParams(search).get(param) === id,\n open,\n close,\n }),\n [search, param, id, open, close],\n );\n}\n\n/** Tailwind's default min-width breakpoints. */\nconst BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280 } as const;\nexport type ResponsivePresentation =\n | Presentation\n | ({ base: Presentation } & Partial<\n Record<keyof typeof BREAKPOINTS, Presentation>\n >);\n/** Choose a presentation using media queries. The server renders `base`. */\nfunction usePresentation(value: ResponsivePresentation): Presentation {\n // Serialise so inline objects don't resubscribe on every render.\n const key = typeof value === \"string\" ? value : JSON.stringify(value);\n const resolve = useCallback((): Presentation => {\n const parsed = (\n key.startsWith(\"{\") ? JSON.parse(key) : key\n ) as ResponsivePresentation;\n if (typeof parsed === \"string\") {\n return parsed;\n }\n let current = parsed.base;\n for (const [name, width] of Object.entries(BREAKPOINTS)) {\n const at = parsed[name as keyof typeof BREAKPOINTS];\n if (at && window.matchMedia(`(min-width: ${width}px)`).matches) {\n current = at;\n }\n }\n return current;\n }, [key]);\n const subscribe = useCallback(\n (onChange: () => void) => {\n if (!key.startsWith(\"{\")) {\n return () => {};\n }\n const queries = Object.values(BREAKPOINTS).map((width) =>\n window.matchMedia(`(min-width: ${width}px)`),\n );\n queries.forEach((query) => query.addEventListener(\"change\", onChange));\n return () =>\n queries.forEach((query) =>\n query.removeEventListener(\"change\", onChange),\n );\n },\n [key],\n );\n return useSyncExternalStore(subscribe, resolve, () =>\n typeof value === \"string\" ? value : value.base,\n );\n}\n\ntype OverlayState = ReturnType<typeof useOverlay>;\ntype OverlayContext = OverlayState & {\n presentation: Presentation;\n swipeDirection: SwipeDirection;\n contentId: string;\n setContentId: (id: string) => void;\n trigger: { current: HTMLElement | null };\n};\nconst Context = createContext<OverlayContext | null>(null);\nfunction useContextValue() {\n const value = useContext(Context);\n if (!value) {\n throw new Error(\"Overlay parts require Overlay.Root\");\n }\n return value;\n}\nconst prefetch = () => void loadOverlayEngine().catch(() => {});\n\n// The prefetch is scheduled when this module loads, not when an Overlay.Root mounts: a template\n// that loads its overlay with deferred() mounts the Root only on the tap, which would leave the\n// engine's download inside the open. Waiting for the load event keeps it out of the page load.\nfunction prefetchWhenIdle() {\n if (typeof window === \"undefined\") {\n return;\n }\n const schedule = () => {\n if (engineModule) {\n return;\n }\n if (typeof window.requestIdleCallback === \"function\") {\n window.requestIdleCallback(prefetch);\n } else {\n window.setTimeout(prefetch, 1500);\n }\n };\n if (document.readyState === \"complete\") {\n schedule();\n } else {\n window.addEventListener(\"load\", schedule, { once: true });\n }\n}\nprefetchWhenIdle();\n\n/**\n * The URL is the only open state. The engine (Base UI) supplies the modal mechanics: portal,\n * focus scope, scroll lock, outside and Escape dismissal, exit presence and, for drawers and\n * sheets, swipe-to-dismiss. Every open or close it requests goes through the history core.\n */\nfunction Root({\n param,\n id,\n presentation = \"dialog\",\n swipeDirection,\n fallback,\n omitParams,\n navigation,\n ...props\n}: PartProps<OverlayState> & {\n param: string;\n id: string;\n /** Your URL adapter for overlays whose open state lives in the path. */\n navigation?: OverlayState;\n /** A `dialog`, swipeable `drawer` or `sheet`. Use `{ base, sm, md, lg, xl }` for responsive layouts. */\n presentation?: ResponsivePresentation;\n /** Swipe direction to dismiss. Defaults to `down` for drawers and `right` for sheets. */\n swipeDirection?: SwipeDirection;\n} & CloseOptions) {\n const queryOverlay = useOverlay(param, id, { fallback, omitParams });\n const overlay = navigation ?? queryOverlay;\n const resolved = usePresentation(presentation);\n const generated = useId();\n const [contentId, setContentId] = useState(`zappie-overlay-${generated}`);\n const trigger = useRef<HTMLElement | null>(null);\n const context = useMemo(\n () => ({\n ...overlay,\n presentation: resolved,\n swipeDirection:\n swipeDirection ?? (resolved === \"sheet\" ? \"right\" : \"down\"),\n contentId,\n setContentId,\n trigger,\n }),\n [overlay, resolved, swipeDirection, contentId],\n );\n return (\n <Context.Provider value={context}>\n {part(\"div\", props, overlay, {\n \"data-state\": overlay.isOpen ? \"open\" : \"closed\",\n \"data-presentation\": resolved,\n })}\n </Context.Provider>\n );\n}\nconst Trigger = forwardRef<HTMLElement, PartProps<OverlayState>>(\n function Trigger(props, ref) {\n const ctx = useContextValue();\n return part(\n \"button\",\n props,\n ctx,\n {\n type: \"button\",\n \"aria-haspopup\": \"dialog\",\n \"aria-expanded\": ctx.isOpen,\n \"aria-controls\": ctx.contentId,\n \"data-state\": ctx.isOpen ? \"open\" : \"closed\",\n onPointerEnter: prefetch,\n onFocus: prefetch,\n onClick: () => ctx.open(),\n },\n composeRefs(ref, (node: HTMLElement | null) => {\n ctx.trigger.current = node;\n }),\n );\n },\n);\nexport type OverlayContentProps = PartProps<OverlayState> & {\n /** Runs on Escape. Call `event.preventDefault()` to keep the overlay open. */\n onEscape?: (event: KeyboardEvent) => void;\n /** Runs on an outside pointer press or focus. Call `event.preventDefault()` to keep the overlay open. */\n onInteractOutside?: (event: Event) => void;\n /** Keep the content mounted while closed, for exit animations driven by `data-state`. */\n forceMount?: true;\n /** Where to mount the content. Defaults to `document.body`. */\n container?: HTMLElement | null;\n};\n\ntype EngineKind = \"dialog\" | \"drawer\";\nconst engineKind = (presentation: Presentation): EngineKind =>\n presentation === \"dialog\" ? \"dialog\" : \"drawer\";\n/** The engine paths (Base UI's dialog, or its drawer) that have opened on this page. */\nconst warmed = new Set<EngineKind>();\n/** Whether the engine owns the content around a nested Root yet. */\nconst ContentContext = createContext<{ attached: boolean } | null>(null);\n// Everything a shopper can do to the page while the frame waits for the engine.\nconst HELD_EVENTS = [\n \"pointerdown\",\n \"mousedown\",\n \"touchstart\",\n \"click\",\n \"keydown\",\n \"wheel\",\n \"touchmove\",\n] as const;\ntype StartTimes = Map<string, CSSNumberish | null>;\nconst animationsOf = (node: Element | null | undefined) =>\n typeof node?.getAnimations === \"function\" ? node.getAnimations() : [];\n/** The start time of each CSS animation running on a node, by animation name. */\nfunction startTimes(node: Element | null | undefined): StartTimes {\n const times: StartTimes = new Map();\n for (const animation of animationsOf(node)) {\n if (\"animationName\" in animation) {\n times.set((animation as CSSAnimation).animationName, animation.startTime);\n }\n }\n return times;\n}\n/** Carry the frame's running animations over to the engine's nodes, so they don't restart. */\nfunction resume(node: Element | null | undefined, times: StartTimes) {\n for (const animation of animationsOf(node)) {\n const start =\n \"animationName\" in animation\n ? times.get((animation as CSSAnimation).animationName)\n : undefined;\n if (start !== undefined && start !== null) {\n animation.startTime = start;\n }\n }\n}\n\ntype FrameProps = {\n ctx: OverlayContext;\n contentProps: PartProps<never>;\n contentRef: Ref<HTMLElement>;\n container: HTMLElement | null | undefined;\n onEscape: ((event: KeyboardEvent) => void) | undefined;\n onInteractOutside: ((event: Event) => void) | undefined;\n onAttach: (times: [StartTimes, StartTimes]) => void;\n};\n/**\n * The overlay's first frame on a page: its backdrop and its panel with the content, in the\n * engine's markup, painted without the engine. The first open on a page runs Base UI's and\n * React DOM's modal code for the first time, and V8 compiles it then, which takes several\n * frames on a slow phone. The frame paints on the tap and the engine replaces it at the start\n * of the next frame, so that work lands after the overlay is on screen.\n *\n * Until the engine is in, the frame is hidden from assistive technology and takes no input:\n * every key, press and scroll is held, so focus stays on the trigger and nothing on the page\n * can be reached. Escape and an outside press still close it, through the same callbacks.\n */\nfunction Frame({\n ctx,\n contentProps,\n contentRef,\n container,\n onEscape,\n onInteractOutside,\n onAttach,\n}: FrameProps) {\n const backdrop = useRef<HTMLDivElement>(null);\n const popup = useRef<HTMLElement | null>(null);\n const latest = useRef({ onEscape, onInteractOutside, onAttach, ctx });\n latest.current = { onEscape, onInteractOutside, onAttach, ctx };\n useLayoutEffect(() => {\n const dismiss = (\n callback: ((event: never) => void) | undefined,\n event: Event,\n ) => {\n callback?.(event as never);\n if (!(callback && event.defaultPrevented)) {\n latest.current.ctx.close();\n }\n };\n const hold = (event: Event) => {\n const inside =\n event.target instanceof Node && popup.current?.contains(event.target);\n if (\n event.type === \"keydown\" &&\n (event as KeyboardEvent).key === \"Escape\"\n ) {\n dismiss(latest.current.onEscape, event);\n } else if (event.type === \"pointerdown\" && !inside) {\n dismiss(latest.current.onInteractOutside, event);\n }\n if (event.cancelable) {\n event.preventDefault();\n }\n event.stopImmediatePropagation();\n };\n for (const type of HELD_EVENTS) {\n window.addEventListener(type, hold, { capture: true, passive: false });\n }\n // The first callback runs before this frame paints; the second starts the next frame.\n let live = true;\n let frame = requestAnimationFrame(() => {\n frame = requestAnimationFrame(() => {\n if (live) {\n latest.current.onAttach([\n startTimes(backdrop.current),\n startTimes(popup.current),\n ]);\n }\n });\n });\n return () => {\n live = false;\n cancelAnimationFrame(frame);\n for (const type of HELD_EVENTS) {\n window.removeEventListener(type, hold, { capture: true });\n }\n };\n }, []);\n const { presentation, swipeDirection } = ctx;\n const drawer = presentation !== \"dialog\";\n const { id: _ownId, ...rest } = contentProps as PartProps<never> & {\n id?: string;\n };\n const id = partId(contentProps as Parameters<typeof partId>[0]);\n const panel = part(\n \"div\",\n rest as PartProps<unknown>,\n ctx,\n {\n \"data-open\": \"\",\n ...(drawer ? { \"data-swipe-direction\": swipeDirection } : {}),\n id: id ?? ctx.contentId,\n role: \"dialog\",\n tabIndex: -1,\n style: drawer\n ? {\n \"--drawer-swipe-movement-x\": \"0px\",\n \"--drawer-swipe-movement-y\": \"0px\",\n \"--drawer-swipe-progress\": 0,\n \"--nested-drawers\": 0,\n \"--drawer-snap-point-offset\": \"0px\",\n \"--drawer-swipe-strength\": 1,\n }\n : { \"--nested-dialogs\": 0 },\n \"aria-modal\": true,\n \"data-presentation\": presentation,\n \"data-state\": \"open\",\n // The engine's panel replaces this one on the next frame and is the one announced.\n \"aria-hidden\": true,\n },\n composeRefs(contentRef, (node: HTMLElement | null) => {\n popup.current = node;\n }),\n );\n return createPortal(\n <div data-zappie-overlay-frame=\"\">\n <div\n role=\"presentation\"\n aria-hidden=\"true\"\n style={{ position: \"fixed\", inset: 0, userSelect: \"none\" }}\n />\n <div\n ref={backdrop}\n data-open=\"\"\n role=\"presentation\"\n style={\n {\n userSelect: \"none\",\n ...(drawer\n ? { \"--drawer-swipe-progress\": 0, \"--drawer-swipe-strength\": 1 }\n : {}),\n } as CSSProperties\n }\n data-zappie-backdrop=\"\"\n data-presentation={presentation}\n data-state=\"open\"\n aria-hidden=\"true\"\n />\n {drawer ? (\n <div\n data-open=\"\"\n role=\"presentation\"\n style={{ \"--drawer-keyboard-inset\": \"0px\" } as CSSProperties}\n >\n {panel}\n </div>\n ) : (\n panel\n )}\n </div>,\n container ?? document.body,\n );\n}\n\ntype Phase = \"closed\" | \"frame\" | \"engine\";\nconst Content = forwardRef<HTMLElement, OverlayContentProps>(function Content(\n { onEscape, onInteractOutside, forceMount, container, ...props },\n ref,\n) {\n const ctx = useContextValue();\n const parent = useContext(ContentContext);\n const [loaded, setEngine] = useState(engineModule);\n // Content that mounted before the idle prefetch finished still sees the engine once it is in.\n const engine = loaded ?? engineModule;\n // A page's first open of each engine path paints a frame first; see Frame. Nested overlays\n // open inside an engine that is already running, and a forced mount has no tap to answer.\n const firstPhase = (): Phase =>\n !forceMount &&\n ctx.isOpen &&\n !parent &&\n !warmed.has(engineKind(ctx.presentation))\n ? \"frame\"\n : \"engine\";\n // Once the engine is in, the surface stays mounted so it can play exit transitions.\n const [phase, setPhase] = useState<Phase>(() =>\n engine && (ctx.isOpen || forceMount) ? firstPhase() : \"closed\",\n );\n if (phase === \"closed\" && engine && (ctx.isOpen || forceMount)) {\n setPhase(firstPhase());\n }\n if (phase === \"frame\" && !ctx.isOpen) {\n setPhase(\"closed\");\n }\n const customId = partId(props as Parameters<typeof partId>[0]);\n const { setContentId } = ctx;\n useEffect(() => {\n if (customId) {\n setContentId(customId);\n }\n }, [customId, setContentId]);\n useEffect(() => {\n if (engine || !(ctx.isOpen || forceMount)) {\n return undefined;\n }\n let live = true;\n void loadOverlayEngine().then(\n (module) => {\n if (live) {\n // The engine arrived after the open, so it paints the overlay itself.\n setEngine(module);\n setPhase((current) => (current === \"closed\" ? \"engine\" : current));\n }\n },\n () => {},\n );\n return () => {\n live = false;\n };\n }, [engine, ctx.isOpen, forceMount]);\n const kind = engineKind(ctx.presentation);\n useEffect(() => {\n if (phase === \"engine\" && ctx.isOpen) {\n warmed.add(kind);\n }\n }, [phase, ctx.isOpen, kind]);\n const panel = useRef<HTMLElement | null>(null);\n const engineRef = useMemo(\n () =>\n composeRefs(ref, (node: HTMLElement | null) => {\n panel.current = node;\n }),\n [ref],\n );\n const attach = useCallback(([backdrop, popup]: [StartTimes, StartTimes]) => {\n flushSync(() => setPhase(\"engine\"));\n const node = panel.current;\n resume(node, popup);\n resume(\n node\n ?.closest(\"[data-base-ui-portal]\")\n ?.querySelector(\"[data-zappie-backdrop]\"),\n backdrop,\n );\n }, []);\n const attached = useMemo(() => ({ attached: phase === \"engine\" }), [phase]);\n if (!engine || phase === \"closed\" || (parent && !parent.attached)) {\n return null;\n }\n if (phase === \"frame\") {\n return (\n <ContentContext.Provider value={attached}>\n <PartsContext.Provider value={frameParts}>\n <Frame\n ctx={ctx}\n contentProps={props as PartProps<never>}\n contentRef={ref}\n container={container}\n onEscape={onEscape}\n onInteractOutside={onInteractOutside}\n onAttach={attach}\n />\n </PartsContext.Provider>\n </ContentContext.Provider>\n );\n }\n return (\n <ContentContext.Provider value={attached}>\n <PartsContext.Provider value={engine}>\n <engine.Surface\n open={ctx.isOpen}\n presentation={ctx.presentation}\n swipeDirection={ctx.swipeDirection}\n contentId={ctx.contentId}\n trigger={ctx.trigger}\n onOpen={() => ctx.open()}\n onClose={ctx.close}\n onEscape={onEscape}\n onInteractOutside={onInteractOutside}\n forceMount={forceMount}\n container={container}\n state={ctx}\n contentProps={props as PartProps<never>}\n contentRef={engineRef}\n />\n </PartsContext.Provider>\n </ContentContext.Provider>\n );\n});\n\ntype PartComponent = EngineModule[\"EngineTitle\"];\ntype Parts = { EngineTitle: PartComponent; EngineClose: PartComponent };\ntype FramePartProps = PartProps<unknown> & { state: unknown };\n/** Title and Close for the content: the engine's, or the frame's inert stand-ins. */\nconst PartsContext = createContext<Parts | null>(null);\nconst frameParts: Parts = {\n EngineTitle: forwardRef<HTMLElement, FramePartProps>(function FrameTitle(\n { state, ...props },\n ref,\n ) {\n return part(\"h2\", props, state, {}, ref);\n }),\n EngineClose: forwardRef<HTMLElement, FramePartProps>(function FrameClose(\n { state, ...props },\n ref,\n ) {\n return part(\"button\", props, state, { type: \"button\" }, ref);\n }),\n};\nfunction useEngine() {\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}\nconst Title = forwardRef<HTMLElement, PartProps<OverlayState>>(\n function Title(props, ref) {\n const ctx = useContextValue();\n const { EngineTitle } = useEngine();\n return (\n <EngineTitle {...(props as PartProps<unknown>)} state={ctx} ref={ref} />\n );\n },\n);\nconst Close = forwardRef<HTMLElement, PartProps<OverlayState>>(\n function Close(props, ref) {\n const ctx = useContextValue();\n const { EngineClose } = useEngine();\n return (\n <EngineClose {...(props as PartProps<unknown>)} state={ctx} ref={ref} />\n );\n },\n);\n/**\n * Composable dialog, drawer and sheet parts with URL-backed open state and a lazy modal engine.\n * Use Root, Trigger, Content, Title and Close to connect history, focus handling and dismissal.\n */\nexport const Overlay = { Root, Trigger, Content, Title, Close };\n"],
|
|
5
4
|
"mappings": "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",
|
|
6
5
|
"names": ["Trigger", "Content", "Title", "Close"]
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/payment/methods.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\nimport type { PaymentMethodKind } from \"@zappie/sdk\";\nimport {\n createContext,\n forwardRef,\n useContext,\n type KeyboardEvent,\n} from \"react\";\nimport { usePartId } from \"../internal/ids\";\nimport { part, type PartProps } from \"../internal/slot\";\nimport { useControllableState } from \"../internal/use-controllable-state\";\n/**\n * A payment-method choice with optional disabled state and an explanatory reason.\n */\nexport type PaymentMethod = {\n value: PaymentMethodKind;\n disabled?: boolean;\n reason?: string;\n};\ntype PaymentState = {\n methods: PaymentMethod[];\n value: PaymentMethodKind | null;\n setValue: (value: PaymentMethodKind) => void;\n};\nconst Context = createContext<PaymentState | null>(null);\nfunction Root({\n methods,\n value,\n defaultValue = null,\n onValueChange,\n ...props\n}: PartProps<PaymentState> & {\n methods: (PaymentMethod | PaymentMethodKind)[];\n value?: PaymentMethodKind | null;\n defaultValue?: PaymentMethodKind | null;\n onValueChange?: (value: PaymentMethodKind | null) => void;\n}) {\n const [selected, set] = useControllableState({\n value,\n defaultValue,\n onChange: onValueChange,\n });\n const normalized = methods.map((method) =>\n typeof method === \"string\" ? { value: method } : method,\n );\n const setValue = (next: PaymentMethodKind) => {\n if (\n normalized.some((method) => method.value === next && !method.disabled)\n ) {\n set(next);\n }\n };\n const state = { methods: normalized, value: selected, setValue };\n return (\n <Context.Provider value={state}>\n {part(\"div\", props, state, {\n role: \"radiogroup\",\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => {\n if (\n ![\n \"ArrowRight\",\n \"ArrowDown\",\n \"ArrowLeft\",\n \"ArrowUp\",\n \"Home\",\n \"End\",\n ].includes(event.key)\n ) {\n return;\n }\n const buttons = Array.from(\n event.currentTarget.querySelectorAll<HTMLElement>(\n '[role=\"radio\"]:not([aria-disabled=\"true\"])',\n ),\n );\n if (!buttons.length) {\n return;\n }\n event.preventDefault();\n const current = buttons.indexOf(\n document.activeElement as HTMLElement,\n );\n const index =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? buttons.length - 1\n : (current +\n ([\"ArrowLeft\", \"ArrowUp\"].includes(event.key) ? -1 : 1) +\n buttons.length) %\n buttons.length;\n buttons[index]?.focus();\n buttons[index]?.click();\n },\n })}\n </Context.Provider>\n );\n}\nconst Item = forwardRef<\n HTMLElement,\n PartProps<PaymentMethod & { selected: boolean }> & {\n value: PaymentMethodKind;\n }\n>(function Item({ value, ...props }, ref) {\n const ctx = useContext(Context);\n const id = usePartId();\n if (!ctx) {\n throw new Error(\"PaymentMethods.Item requires PaymentMethods.Root\");\n }\n const method = ctx.methods.find((method) => method.value === value);\n if (!method) {\n return null;\n }\n const selected = ctx.value === value;\n const first = ctx.methods.find((method) => !method.disabled)?.value;\n return part(\n \"button\",\n props,\n { ...method, selected },\n {\n id,\n type: \"button\",\n role: \"radio\",\n \"aria-checked\": selected,\n \"aria-disabled\": method.disabled || undefined,\n \"aria-description\": method.reason,\n disabled: method.disabled,\n tabIndex: selected || (!ctx.value && first === value) ? 0 : -1,\n \"data-disabled\": method.disabled ? \"\" : undefined,\n \"data-selected\": selected ? \"\" : undefined,\n \"data-state\": selected ? \"checked\" : \"unchecked\",\n onClick: () => ctx.setValue(value),\n },\n ref,\n );\n});\n/**\n * Composable payment-method radio controls with keyboard navigation.\n * Root manages the selection. Item renders each method and prevents selection when disabled.\n */\nexport const PaymentMethods = { Root, Item };\n"],
|
|
5
4
|
"mappings": "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",
|
|
6
5
|
"names": ["Item", "method"]
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rich-text/banners.ts"],
|
|
4
|
-
"sourcesContent": ["// Multiple menu info banners are stored as one string joined by this delimiter\n// (the dashboard editor joins on it; here we split it back out for display).\n/**\n * The separator used to store multiple menu info banners in a single string.\n */\nexport const BANNER_DELIMITER = \"<::>\";\n\n// The delimiter looks like an HTML tag, so once it lands inside the dashboard's\n// rich-text editor as content it gets serialised as escaped text \u2014 `<::>`,\n// usually on its own `<p>` line. Splitting on the literal `<::>` then finds\n// nothing and every banner collapses into one. Convert the escaped form (and its\n// `<p>` wrapper) back to the real delimiter before splitting.\nconst normalizeBannerDelimiters = (html: string): string =>\n html\n .replace(/<p>\\s*(?:<::>|<::>)\\s*<\\/p>/gi, BANNER_DELIMITER)\n .replaceAll(\"<::>\", BANNER_DELIMITER);\n\n/** Split a stored info-banner value into individual banner HTML fragments. */\nexport const splitInfoBanner = (infoBanner?: string | null): string[] =>\n normalizeBannerDelimiters(infoBanner ?? \"\").split(BANNER_DELIMITER);\n"],
|
|
5
4
|
"mappings": ";AAKO,IAAM,mBAAmB;AAOhC,IAAM,4BAA4B,CAAC,SACjC,KACG,QAAQ,uCAAuC,gBAAgB,EAC/D,WAAW,cAAc,gBAAgB;AAGvC,IAAM,kBAAkB,CAAC,eAC9B,0BAA0B,cAAc,EAAE,EAAE,MAAM,gBAAgB;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rich-text/browser.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ParsedRichTextNode } from \"./core\";\n\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\n\nconst convertNode = (node: Node): ParsedRichTextNode => {\n if (node.nodeType === TEXT_NODE) {\n return { type: \"text\", data: node.nodeValue || \"\" };\n }\n\n if (node.nodeType === COMMENT_NODE) {\n return { type: \"comment\" };\n }\n\n return {\n type: \"tag\",\n name: node.nodeName.toLowerCase(),\n children: Array.from(node.childNodes).map(convertNode),\n };\n};\n\n/**\n * Parse HTML with the browser DOMParser and convert body children to the shared rich-text node format.\n * Requires a DOM environment. Pair with createSanitizeRichText to remove unsupported content.\n */\nexport const parseRichText = (html: string): ParsedRichTextNode[] => {\n const document = new DOMParser().parseFromString(html, \"text/html\");\n return Array.from(document.body.childNodes).map(convertNode);\n};\n"],
|
|
5
4
|
"mappings": ";AAEA,IAAM,YAAY;AAClB,IAAM,eAAe;AAErB,IAAM,cAAc,CAAC,SAAmC;AACtD,MAAI,KAAK,aAAa,WAAW;AAC/B,WAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,aAAa,GAAG;AAAA,EACpD;AAEA,MAAI,KAAK,aAAa,cAAc;AAClC,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,KAAK,SAAS,YAAY;AAAA,IAChC,UAAU,MAAM,KAAK,KAAK,UAAU,EAAE,IAAI,WAAW;AAAA,EACvD;AACF;AAMO,IAAM,gBAAgB,CAAC,SAAuC;AACnE,QAAM,WAAW,IAAI,UAAU,EAAE,gBAAgB,MAAM,WAAW;AAClE,SAAO,MAAM,KAAK,SAAS,KAAK,UAAU,EAAE,IAAI,WAAW;AAC7D;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rich-text/core.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * A parser-neutral rich-text node containing its type, optional tag name, text and children.\n */\nexport type ParsedRichTextNode = {\n type: string;\n name?: string;\n data?: string;\n children?: ParsedRichTextNode[];\n};\n\n/**\n * A parser adapter that converts HTML into the node tree consumed by the rich-text sanitizer.\n */\nexport type ParseRichText = (html: string) => ParsedRichTextNode[];\n\nconst ALLOWED_TAGS = new Set([\n \"b\",\n \"blockquote\",\n \"br\",\n \"code\",\n \"del\",\n \"em\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"hr\",\n \"i\",\n \"li\",\n \"ol\",\n \"p\",\n \"pre\",\n \"s\",\n \"span\",\n \"strike\",\n \"strong\",\n \"sub\",\n \"sup\",\n \"u\",\n \"ul\",\n]);\n\nconst DROP_CONTENT_TAGS = new Set([\n \"audio\",\n \"canvas\",\n \"embed\",\n \"iframe\",\n \"math\",\n \"noscript\",\n \"object\",\n \"script\",\n \"style\",\n \"svg\",\n \"template\",\n \"video\",\n]);\n\nconst VOID_TAGS = new Set([\"br\", \"hr\"]);\n\nconst escapeText = (value: string): string =>\n value\n .replaceAll(\"\\r\\n\", \"\\n\")\n .replaceAll(\"\\r\", \"\\n\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"\\u00a0\", \" \")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\");\n\nconst serializeNode = (node: ParsedRichTextNode): string => {\n if (node.type === \"text\") {\n return escapeText(node.data || \"\");\n }\n\n if (node.type === \"comment\" || node.type === \"directive\") {\n return \"\";\n }\n\n const tagName = node.name?.toLowerCase();\n if (tagName && DROP_CONTENT_TAGS.has(tagName)) {\n return \"\";\n }\n\n const children = (node.children || []).map(serializeNode).join(\"\");\n if (!tagName || !ALLOWED_TAGS.has(tagName)) {\n return children;\n }\n\n if (VOID_TAGS.has(tagName)) {\n return `<${tagName}>`;\n }\n\n return `<${tagName}>${children}</${tagName}>`;\n};\n\n/**\n * Create a sanitizer using your HTML parser adapter.\n * Keeps supported formatting tags without attributes, escapes text and removes unsafe element content.\n *\n * @param parseRichText - A parser that returns the shared rich-text node format.\n * @returns A sanitizer that accepts HTML and returns sanitized HTML, or an empty string for empty input.\n */\nexport const createSanitizeRichText =\n (parseRichText: ParseRichText) =>\n (html?: string | null): string => {\n if (!html) {\n return \"\";\n }\n\n return parseRichText(html).map(serializeNode).join(\"\");\n };\n"],
|
|
5
4
|
"mappings": ";AAeA,IAAM,eAAe,oBAAI,IAAI;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,YAAY,oBAAI,IAAI,CAAC,MAAM,IAAI,CAAC;AAEtC,IAAM,aAAa,CAAC,UAClB,MACG,WAAW,QAAQ,IAAI,EACvB,WAAW,MAAM,IAAI,EACrB,WAAW,KAAK,OAAO,EACvB,WAAW,QAAU,QAAQ,EAC7B,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,MAAM;AAE3B,IAAM,gBAAgB,CAAC,SAAqC;AAC1D,MAAI,KAAK,SAAS,QAAQ;AACxB,WAAO,WAAW,KAAK,QAAQ,EAAE;AAAA,EACnC;AAEA,MAAI,KAAK,SAAS,aAAa,KAAK,SAAS,aAAa;AACxD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,KAAK,MAAM,YAAY;AACvC,MAAI,WAAW,kBAAkB,IAAI,OAAO,GAAG;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,KAAK,YAAY,CAAC,GAAG,IAAI,aAAa,EAAE,KAAK,EAAE;AACjE,MAAI,CAAC,WAAW,CAAC,aAAa,IAAI,OAAO,GAAG;AAC1C,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,IAAI,OAAO,GAAG;AAC1B,WAAO,IAAI,OAAO;AAAA,EACpB;AAEA,SAAO,IAAI,OAAO,IAAI,QAAQ,KAAK,OAAO;AAC5C;AASO,IAAM,yBACX,CAAC,kBACD,CAAC,SAAiC;AAChC,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,IAAI,EAAE,IAAI,aAAa,EAAE,KAAK,EAAE;AACvD;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as ParseRichText, P as ParsedRichTextNode, c as createSanitizeRichText } from '../core-
|
|
1
|
+
export { a as ParseRichText, P as ParsedRichTextNode, c as createSanitizeRichText } from '../core-Cd-_zlQx.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The separator used to store multiple menu info banners in a single string.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/search/engine.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Category, Item, Menu } from \"@zappie/sdk\";\n/**\n * A scored item or category returned by menu search, ordered by descending score.\n */\nexport type SearchResult =\n | { type: \"item\"; item: Item; score: number }\n | { type: \"category\"; category: Category; score: number };\nexport function normalizeSearch(text: string) {\n return text\n .normalize(\"NFD\")\n .replace(/\\p{M}/gu, \"\")\n .toLowerCase()\n .split(/[^\\p{L}\\p{N}]+/u)\n .filter(Boolean);\n}\nfunction near(a: string, b: string) {\n if (Math.abs(a.length - b.length) > 1) {\n return false;\n }\n let i = 0;\n let j = 0;\n let edits = 0;\n while (i < a.length && j < b.length) {\n if (a[i] === b[j]) {\n i++;\n j++;\n continue;\n }\n if (++edits > 1) {\n return false;\n }\n if (a.length === b.length) {\n if (a[i] === b[j + 1] && a[i + 1] === b[j]) {\n i += 2;\n j += 2;\n } else {\n i++;\n j++;\n }\n } else if (a.length > b.length) {\n i++;\n } else {\n j++;\n }\n }\n return edits + (a.length - i) + (b.length - j) <= 1;\n}\n/**\n * Index item names, tags and descriptions plus category names and descriptions for local search.\n * Matches case- and accent-insensitive prefixes and allows a single edit for query tokens of at least four characters.\n *\n * @param menu - The menu snapshot you want to search.\n * @returns A search function that requires every query token to match and sorts results by descending score.\n */\nexport function createSearchIndex(menu: Menu) {\n const entries = [\n ...Object.values(menu.items).map((item) => ({\n result: { type: \"item\" as const, item },\n fields: [\n normalizeSearch(item.name),\n normalizeSearch(item.tags.join(\" \")),\n normalizeSearch(item.description ?? \"\"),\n ],\n })),\n ...menu.categories.map((category) => ({\n result: { type: \"category\" as const, category },\n fields: [\n normalizeSearch(category.name),\n [],\n normalizeSearch(category.description ?? \"\"),\n ],\n })),\n ];\n return (query: string): SearchResult[] => {\n const tokens = normalizeSearch(query);\n if (!tokens.length) {\n return [];\n }\n const results: SearchResult[] = [];\n for (const entry of entries) {\n let score = 0;\n for (const token of tokens) {\n let best = 0;\n for (let field = 0; field < entry.fields.length; field++) {\n const weight = [30, 20, 10][field]!;\n for (const word of entry.fields[field]!) {\n if (word.startsWith(token)) {\n best = Math.max(best, weight + (word === token ? 3 : 2));\n } else if (token.length >= 4 && near(token, word)) {\n best = Math.max(best, weight);\n }\n }\n }\n if (!best) {\n score = 0;\n break;\n }\n score += best;\n }\n if (score) {\n results.push({ ...entry.result, score });\n }\n }\n return results.sort((a, b) => b.score - a.score);\n };\n}\n"],
|
|
5
4
|
"mappings": ";AAOO,SAAS,gBAAgB,MAAc;AAC5C,SAAO,KACJ,UAAU,KAAK,EACf,QAAQ,WAAW,EAAE,EACrB,YAAY,EACZ,MAAM,iBAAiB,EACvB,OAAO,OAAO;AACnB;AACA,SAAS,KAAK,GAAW,GAAW;AAClC,MAAI,KAAK,IAAI,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG;AACrC,WAAO;AAAA,EACT;AACA,MAAI,IAAI;AACR,MAAI,IAAI;AACR,MAAI,QAAQ;AACZ,SAAO,IAAI,EAAE,UAAU,IAAI,EAAE,QAAQ;AACnC,QAAI,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG;AACjB;AACA;AACA;AAAA,IACF;AACA,QAAI,EAAE,QAAQ,GAAG;AACf,aAAO;AAAA,IACT;AACA,QAAI,EAAE,WAAW,EAAE,QAAQ;AACzB,UAAI,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG;AAC1C,aAAK;AACL,aAAK;AAAA,MACP,OAAO;AACL;AACA;AAAA,MACF;AAAA,IACF,WAAW,EAAE,SAAS,EAAE,QAAQ;AAC9B;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAAA,EACF;AACA,SAAO,SAAS,EAAE,SAAS,MAAM,EAAE,SAAS,MAAM;AACpD;AAQO,SAAS,kBAAkB,MAAY;AAC5C,QAAM,UAAU;AAAA,IACd,GAAG,OAAO,OAAO,KAAK,KAAK,EAAE,IAAI,CAAC,UAAU;AAAA,MAC1C,QAAQ,EAAE,MAAM,QAAiB,KAAK;AAAA,MACtC,QAAQ;AAAA,QACN,gBAAgB,KAAK,IAAI;AAAA,QACzB,gBAAgB,KAAK,KAAK,KAAK,GAAG,CAAC;AAAA,QACnC,gBAAgB,KAAK,eAAe,EAAE;AAAA,MACxC;AAAA,IACF,EAAE;AAAA,IACF,GAAG,KAAK,WAAW,IAAI,CAAC,cAAc;AAAA,MACpC,QAAQ,EAAE,MAAM,YAAqB,SAAS;AAAA,MAC9C,QAAQ;AAAA,QACN,gBAAgB,SAAS,IAAI;AAAA,QAC7B,CAAC;AAAA,QACD,gBAAgB,SAAS,eAAe,EAAE;AAAA,MAC5C;AAAA,IACF,EAAE;AAAA,EACJ;AACA,SAAO,CAAC,UAAkC;AACxC,UAAM,SAAS,gBAAgB,KAAK;AACpC,QAAI,CAAC,OAAO,QAAQ;AAClB,aAAO,CAAC;AAAA,IACV;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,SAAS;AAC3B,UAAI,QAAQ;AACZ,iBAAW,SAAS,QAAQ;AAC1B,YAAI,OAAO;AACX,iBAAS,QAAQ,GAAG,QAAQ,MAAM,OAAO,QAAQ,SAAS;AACxD,gBAAM,SAAS,CAAC,IAAI,IAAI,EAAE,EAAE,KAAK;AACjC,qBAAW,QAAQ,MAAM,OAAO,KAAK,GAAI;AACvC,gBAAI,KAAK,WAAW,KAAK,GAAG;AAC1B,qBAAO,KAAK,IAAI,MAAM,UAAU,SAAS,QAAQ,IAAI,EAAE;AAAA,YACzD,WAAW,MAAM,UAAU,KAAK,KAAK,OAAO,IAAI,GAAG;AACjD,qBAAO,KAAK,IAAI,MAAM,MAAM;AAAA,YAC9B;AAAA,UACF;AAAA,QACF;AACA,YAAI,CAAC,MAAM;AACT,kBAAQ;AACR;AAAA,QACF;AACA,iBAAS;AAAA,MACX;AACA,UAAI,OAAO;AACT,gBAAQ,KAAK,EAAE,GAAG,MAAM,QAAQ,MAAM,CAAC;AAAA,MACzC;AAAA,IACF;AACA,WAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,EACjD;AACF;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/dist/search/index.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/search/index.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\nimport { useCart, useMenu, useZappie } from \"@zappie/sdk/react\";\nimport {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useMemo,\n type ChangeEvent,\n} from \"react\";\nimport {\n countAnnouncement,\n useCombobox,\n withLiveRegion,\n} from \"../internal/combobox\";\nimport { composeRefs, part, type PartProps } from \"../internal/slot\";\nimport { useControllableState } from \"../internal/use-controllable-state\";\nimport { createSearchIndex, type SearchResult } from \"./engine\";\n/**\n * Search query, results and combobox navigation exposed to search parts and render functions.\n */\nexport type SearchState = ReturnType<typeof useCombobox<SearchResult>> & {\n query: string;\n setQuery: (query: string) => void;\n results: SearchResult[];\n setComposing: (value: boolean) => void;\n error?: string;\n retry?: () => void;\n};\nconst Context = createContext<SearchState | null>(null);\nfunction useSearch() {\n const ctx = useContext(Context);\n if (!ctx) {\n throw new Error(\"Search parts require Search.Root\");\n }\n return ctx;\n}\n/**\n * Externally supplied search results and optional loading, error, retry and composition controls.\n */\nexport type SearchSource = {\n results: SearchResult[];\n isLoading?: boolean;\n isStale?: boolean;\n error?: string;\n retry?: () => void;\n onCompositionChange?: (composing: boolean) => void;\n};\ntype RootProps = Omit<PartProps<SearchState>, \"onSelect\"> & {\n announcement?: (count: number) => string;\n query?: string;\n defaultQuery?: string;\n onQueryChange?: (query: string) => void;\n onSelect?: (result: SearchResult) => void;\n source?: SearchSource;\n};\nfunction Root(props: RootProps) {\n if (props.source) {\n return <ControlledRoot {...props} source={props.source} />;\n }\n return <UncontrolledRoot {...props} />;\n}\nfunction UncontrolledRoot(props: RootProps) {\n const cart = useCart();\n const menu = useMenu(cart.branchId ?? undefined);\n const [query, setQuery] = useControllableState({\n value: props.query,\n defaultValue: props.defaultQuery ?? \"\",\n onChange: props.onQueryChange,\n });\n const index = useMemo(\n () => (menu.data ? createSearchIndex(menu.data) : () => []),\n [menu.data],\n );\n const results = useMemo(() => index(query), [index, query]);\n return (\n <ControlledRoot\n {...props}\n query={query}\n onQueryChange={setQuery}\n source={{ results, isLoading: menu.isLoading, isStale: menu.isStale }}\n />\n );\n}\nfunction ControlledRoot({\n query,\n defaultQuery = \"\",\n onQueryChange,\n onSelect = () => {},\n announcement = countAnnouncement,\n source,\n ...props\n}: RootProps & { source: SearchSource }) {\n const client = useZappie();\n const [value, setValue] = useControllableState({\n value: query,\n defaultValue: defaultQuery,\n onChange: onQueryChange,\n });\n const results = source.results;\n const combo = useCombobox(results, onSelect);\n const setQuery = (next: string) => {\n setValue(next);\n combo.setActiveIndex(-1);\n combo.setOpen(true);\n };\n useEffect(() => {\n if (!value.trim()) {\n return;\n }\n const timer = setTimeout(\n () =>\n client._internal.emit(\"search\", {\n query: value,\n resultCount: results.length,\n }),\n 600,\n );\n return () => clearTimeout(timer);\n }, [client, value, results.length]);\n const state = {\n ...combo,\n query: value,\n setQuery,\n results,\n setComposing: (value: boolean) => source.onCompositionChange?.(value),\n ...(source.error ? { error: source.error } : {}),\n ...(source.retry ? { retry: source.retry } : {}),\n };\n return (\n <Context.Provider value={state}>\n {part(\n \"div\",\n withLiveRegion(\n props,\n combo.isOpen && value.trim() ? announcement(results.length) : \"\",\n ) as typeof props,\n state,\n {\n \"data-state\": source.error\n ? \"error\"\n : source.isLoading\n ? \"loading\"\n : source.isStale\n ? \"stale\"\n : \"valid\",\n onBlur: (event: {\n currentTarget: HTMLElement;\n relatedTarget: Node | null;\n }) => {\n if (!event.currentTarget.contains(event.relatedTarget)) {\n combo.setOpen(false);\n }\n },\n },\n )}\n </Context.Provider>\n );\n}\nconst Input = forwardRef<HTMLElement, PartProps<SearchState>>(\n function Input(props, ref) {\n const state = useSearch();\n return part(\n \"input\",\n props,\n state,\n {\n ...state.inputProps,\n type: \"search\",\n onCompositionStart: () => state.setComposing(true),\n onCompositionEnd: () => state.setComposing(false),\n value: state.query,\n onChange: (event: ChangeEvent<HTMLInputElement>) =>\n state.setQuery(event.target.value),\n },\n ref,\n );\n },\n);\nconst Results = forwardRef<HTMLElement, PartProps<SearchState>>(\n function Results(props, ref) {\n const state = useSearch();\n return part(\n \"div\",\n props,\n state,\n state.listProps,\n composeRefs(ref, (node) => {\n if (node?.id && node.id !== state.listProps.id) {\n state.setListId(node.id);\n }\n }),\n );\n },\n);\nconst Result = forwardRef<\n HTMLElement,\n PartProps<SearchState> & { index: number }\n>(function Result({ index, ...props }, ref) {\n const state = useSearch();\n return part(\n \"div\",\n props,\n state,\n state.getOptionProps(index),\n composeRefs(ref, (node) => {\n if (node?.id && node.id !== state.getOptionProps(index).id) {\n state.registerOption(index, node.id);\n }\n }),\n );\n});\n/**\n * Composable menu search parts with combobox navigation and result announcements.\n * Use Root with your own source or let it index the active branch menu through your ZappieProvider.\n */\nexport const Search = { Root, Input, Results, Result };\nexport { createSearchIndex } from \"./engine\";\nexport type { SearchResult } from \"./engine\";\n"],
|
|
5
4
|
"mappings": ";;;AACA,SAAS,SAAS,SAAS,iBAAiB;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa,YAA4B;AAClD,SAAS,4BAA4B;AACrC,SAAS,yBAA4C;AAwMrD,SAAS,qBAAAA,0BAAyB;AA/JvB;AA7BX,IAAM,UAAU,cAAkC,IAAI;AACtD,SAAS,YAAY;AACnB,QAAM,MAAM,WAAW,OAAO;AAC9B,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AACA,SAAO;AACT;AAoBA,SAAS,KAAK,OAAkB;AAC9B,MAAI,MAAM,QAAQ;AAChB,WAAO,oBAAC,kBAAgB,GAAG,OAAO,QAAQ,MAAM,QAAQ;AAAA,EAC1D;AACA,SAAO,oBAAC,oBAAkB,GAAG,OAAO;AACtC;AACA,SAAS,iBAAiB,OAAkB;AAC1C,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,QAAQ,KAAK,YAAY,MAAS;AAC/C,QAAM,CAAC,OAAO,QAAQ,IAAI,qBAAqB;AAAA,IAC7C,OAAO,MAAM;AAAA,IACb,cAAc,MAAM,gBAAgB;AAAA,IACpC,UAAU,MAAM;AAAA,EAClB,CAAC;AACD,QAAM,QAAQ;AAAA,IACZ,MAAO,KAAK,OAAO,kBAAkB,KAAK,IAAI,IAAI,MAAM,CAAC;AAAA,IACzD,CAAC,KAAK,IAAI;AAAA,EACZ;AACA,QAAM,UAAU,QAAQ,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,KAAK,CAAC;AAC1D,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,eAAe;AAAA,MACf,QAAQ,EAAE,SAAS,WAAW,KAAK,WAAW,SAAS,KAAK,QAAQ;AAAA;AAAA,EACtE;AAEJ;AACA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,WAAW,MAAM;AAAA,EAAC;AAAA,EAClB,eAAe;AAAA,EACf;AAAA,EACA,GAAG;AACL,GAAyC;AACvC,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,OAAO,QAAQ,IAAI,qBAAqB;AAAA,IAC7C,OAAO;AAAA,IACP,cAAc;AAAA,IACd,UAAU;AAAA,EACZ,CAAC;AACD,QAAM,UAAU,OAAO;AACvB,QAAM,QAAQ,YAAY,SAAS,QAAQ;AAC3C,QAAM,WAAW,CAAC,SAAiB;AACjC,aAAS,IAAI;AACb,UAAM,eAAe,EAAE;AACvB,UAAM,QAAQ,IAAI;AAAA,EACpB;AACA,YAAU,MAAM;AACd,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,MACZ,MACE,OAAO,UAAU,KAAK,UAAU;AAAA,QAC9B,OAAO;AAAA,QACP,aAAa,QAAQ;AAAA,MACvB,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,QAAQ,OAAO,QAAQ,MAAM,CAAC;AAClC,QAAM,QAAQ;AAAA,IACZ,GAAG;AAAA,IACH,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,cAAc,CAACC,WAAmB,OAAO,sBAAsBA,MAAK;AAAA,IACpE,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAC9C,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,EAChD;AACA,SACE,oBAAC,QAAQ,UAAR,EAAiB,OAAO,OACtB;AAAA,IACC;AAAA,IACA;AAAA,MACE;AAAA,MACA,MAAM,UAAU,MAAM,KAAK,IAAI,aAAa,QAAQ,MAAM,IAAI;AAAA,IAChE;AAAA,IACA;AAAA,IACA;AAAA,MACE,cAAc,OAAO,QACjB,UACA,OAAO,YACL,YACA,OAAO,UACL,UACA;AAAA,MACR,QAAQ,CAAC,UAGH;AACJ,YAAI,CAAC,MAAM,cAAc,SAAS,MAAM,aAAa,GAAG;AACtD,gBAAM,QAAQ,KAAK;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF,GACF;AAEJ;AACA,IAAM,QAAQ;AAAA,EACZ,SAASC,OAAM,OAAO,KAAK;AACzB,UAAM,QAAQ,UAAU;AACxB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,GAAG,MAAM;AAAA,QACT,MAAM;AAAA,QACN,oBAAoB,MAAM,MAAM,aAAa,IAAI;AAAA,QACjD,kBAAkB,MAAM,MAAM,aAAa,KAAK;AAAA,QAChD,OAAO,MAAM;AAAA,QACb,UAAU,CAAC,UACT,MAAM,SAAS,MAAM,OAAO,KAAK;AAAA,MACrC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AACA,IAAM,UAAU;AAAA,EACd,SAASC,SAAQ,OAAO,KAAK;AAC3B,UAAM,QAAQ,UAAU;AACxB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,YAAY,KAAK,CAAC,SAAS;AACzB,YAAI,MAAM,MAAM,KAAK,OAAO,MAAM,UAAU,IAAI;AAC9C,gBAAM,UAAU,KAAK,EAAE;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AACA,IAAM,SAAS,WAGb,SAASC,QAAO,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK;AAC1C,QAAM,QAAQ,UAAU;AACxB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,eAAe,KAAK;AAAA,IAC1B,YAAY,KAAK,CAAC,SAAS;AACzB,UAAI,MAAM,MAAM,KAAK,OAAO,MAAM,eAAe,KAAK,EAAE,IAAI;AAC1D,cAAM,eAAe,OAAO,KAAK,EAAE;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;AAKM,IAAM,SAAS,EAAE,MAAM,OAAO,SAAS,OAAO;",
|
|
6
5
|
"names": ["createSearchIndex", "value", "Input", "Results", "Result"]
|
|
7
6
|
}
|
package/dist/status/hours.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/status/hours.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Branch, OpeningTime } from \"@zappie/sdk\";\nconst DAY = 86400000;\nconst formatters = new Map<string, Intl.DateTimeFormat>();\nfunction formatter(timezone: string) {\n let value = formatters.get(timezone);\n if (!value) {\n value = new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hourCycle: \"h23\",\n });\n formatters.set(timezone, value);\n }\n return value;\n}\nexport function localParts(date: Date, timezone: string) {\n const parts = Object.fromEntries(\n formatter(timezone)\n .formatToParts(date)\n .map(({ type, value }) => [type, value]),\n );\n return {\n date: `${parts.year}-${parts.month}-${parts.day}`,\n hour: Number(parts.hour),\n minute: Number(parts.minute),\n second: Number(parts.second),\n };\n}\n/**\n * Parse a zero-padded HH:mm or HH:mm:ss wall-clock value without applying a time zone.\n *\n * @returns Clock parts with 12-hour and 24-hour values, or undefined for an invalid time.\n * @example\n * ```ts\n * parseWallClock(\"14:30\"); // { hour24: 14, hour12: 2, minute: 30, second: 0, period: \"PM\" }\n * ```\n */\nexport function parseWallClock(value: string) {\n const match = /^(\\d{2}):(\\d{2})(?::(\\d{2}))?$/.exec(value);\n if (\n !match ||\n Number(match[1]) > 23 ||\n Number(match[2]) > 59 ||\n Number(match[3] ?? 0) > 59\n ) {\n return undefined;\n }\n const hour24 = Number(match[1]);\n return {\n hour24,\n hour12: hour24 % 12 || 12,\n minute: Number(match[2]),\n second: Number(match[3] ?? 0),\n period: hour24 >= 12 ? \"PM\" : \"AM\",\n };\n}\n/**\n * Format a valid wall-clock time as a 12-hour label with AM or PM.\n * Omits zero minutes and all seconds. Returns invalid input unchanged.\n *\n * @example\n * ```ts\n * formatWallClock(\"14:00\"); // \"2 PM\"\n * formatWallClock(\"09:30:15\"); // \"9:30 AM\"\n * ```\n */\nexport function formatWallClock(value: string) {\n const time = parseWallClock(value);\n return time\n ? `${time.hour12}${time.minute ? `:${String(time.minute).padStart(2, \"0\")}` : \"\"} ${time.period}`\n : value;\n}\n/**\n * Group consecutive days with identical opening intervals into display labels.\n * Skips disabled intervals and days with no enabled hours, and orders the groups from Sunday to Saturday.\n */\nexport function formatOpeningHours(times: OpeningTime[]) {\n const names = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n ];\n const groups: { days: number[]; dayLabel: string; hoursLabel: string }[] = [];\n for (let day = 0; day < 7; day++) {\n const intervals = times\n .filter((time) => !time.disabled && time.day === day)\n .sort((a, b) => a.opens.localeCompare(b.opens));\n if (!intervals.length) {\n continue;\n }\n const hoursLabel = intervals\n .map(\n (time) =>\n `${formatWallClock(time.opens)} \u2013 ${formatWallClock(time.closes)}`,\n )\n .join(\", \");\n const last = groups[groups.length - 1];\n if (\n last &&\n last.days[last.days.length - 1] === day - 1 &&\n last.hoursLabel === hoursLabel\n ) {\n last.days.push(day);\n last.dayLabel = `${names[last.days[0]!]} \u2013 ${names[day]}`;\n } else {\n groups.push({ days: [day], dayLabel: names[day]!, hoursLabel });\n }\n }\n return groups;\n}\nexport function dateOffset(date: string, days: number) {\n return new Date(Date.parse(`${date}T00:00:00Z`) + days * DAY)\n .toISOString()\n .slice(0, 10);\n}\n/** Return all matching instants (two at a DST fold, none in a DST gap). */\nexport function wallInstants(date: string, clock: string, timezone: string) {\n const time = parseWallClock(clock);\n if (!time) {\n return [];\n }\n const wall =\n Date.parse(`${date}T00:00:00Z`) +\n ((time.hour24 * 60 + time.minute) * 60 + time.second) * 1000;\n const offsets = new Set<number>();\n for (const shift of [-DAY, 0, DAY]) {\n const sample = wall + shift;\n const local = localParts(new Date(sample), timezone);\n const asUTC =\n Date.parse(`${local.date}T00:00:00Z`) +\n ((local.hour * 60 + local.minute) * 60 + local.second) * 1000;\n offsets.add(asUTC - sample);\n }\n const matches = [];\n for (const offset of offsets) {\n const instant = wall - offset;\n const local = localParts(new Date(instant), timezone);\n if (\n local.date === date &&\n local.hour === time.hour24 &&\n local.minute === time.minute &&\n local.second === time.second\n ) {\n matches.push(instant);\n }\n }\n return matches.sort((a, b) => a - b);\n}\nexport type OpeningInterval = { start: number; end: number };\nexport function openingIntervals(\n branch: Branch,\n timezone: string,\n now: Date,\n days = 8,\n): OpeningInterval[] {\n const today = localParts(now, timezone).date;\n const intervals: OpeningInterval[] = [];\n for (let offset = -1; offset < days; offset++) {\n const date = dateOffset(today, offset);\n const day = new Date(`${date}T00:00:00Z`).getUTCDay();\n const special = branch.specialHours?.find((hours) => hours.date === date);\n const times = special\n ? special.closed || !special.opens || !special.closes\n ? []\n : [{ opens: special.opens, closes: special.closes }]\n : branch.openingTimes.filter(\n (hours) => hours.day === day && !hours.disabled,\n );\n for (const hours of times) {\n const starts = wallInstants(date, hours.opens, timezone);\n const overnight = hours.closes <= hours.opens;\n const endDate = overnight ? dateOffset(date, 1) : date;\n const ends = wallInstants(endDate, hours.closes, timezone);\n const start = starts[0];\n let end = ends[ends.length - 1];\n if (\n overnight &&\n branch.specialHours?.some(\n (hours) => hours.date === endDate && hours.closed,\n )\n ) {\n end = wallInstants(endDate, \"00:00\", timezone)[0];\n }\n if (start !== undefined && end !== undefined && start < end) {\n intervals.push({ start, end });\n }\n }\n }\n const closedUntil = branch.closedUntil\n ? Date.parse(branch.closedUntil)\n : -Infinity;\n const sorted = intervals\n .map(({ start, end }) => ({ start: Math.max(start, closedUntil), end }))\n .filter(({ start, end }) => start < end)\n .sort((a, b) => a.start - b.start);\n const merged: OpeningInterval[] = [];\n for (const interval of sorted) {\n const last = merged[merged.length - 1];\n if (last && interval.start <= last.end) {\n last.end = Math.max(last.end, interval.end);\n } else {\n merged.push({ ...interval });\n }\n }\n return merged;\n}\nexport type OpenStatusState = {\n isOpen: boolean;\n label: string;\n nextChange?: Date;\n};\n/**\n * Calculate whether a branch is open and provide its next opening or closing label.\n * Accounts for weekly hours, special hours, overnight intervals and closedUntil.\n *\n * @param branch - The branch whose opening rules apply.\n * @param timezone - The time zone used to interpret and display its hours.\n * @param now - The instant to check. Defaults to the current time.\n * @returns Open state, a display label and the next boundary found in the opening-hours window.\n */\nexport function getOpenStatus(\n branch: Branch,\n timezone: string,\n now = new Date(),\n): OpenStatusState {\n const intervals = openingIntervals(branch, timezone, now);\n const current = intervals.find(\n ({ start, end }) => start <= now.getTime() && end > now.getTime(),\n );\n const next =\n current?.end ?? intervals.find(({ start }) => start > now.getTime())?.start;\n if (next === undefined) {\n return { isOpen: false, label: \"Closed\" };\n }\n const nextChange = new Date(next);\n const local = localParts(nextChange, timezone);\n const clock = formatWallClock(\n `${String(local.hour).padStart(2, \"0\")}:${String(local.minute).padStart(2, \"0\")}`,\n )\n .toLowerCase()\n .replace(\" \", \"\");\n const today = localParts(now, timezone).date;\n const suffix =\n local.date === today\n ? \"\"\n : local.date === dateOffset(today, 1)\n ? \" tomorrow\"\n : ` ${new Intl.DateTimeFormat(\"en\", { timeZone: timezone, weekday: \"long\" }).format(nextChange)}`;\n return {\n isOpen: Boolean(current),\n label: current ? `Open until ${clock}` : `Opens ${clock}${suffix}`,\n nextChange,\n };\n}\n"],
|
|
5
4
|
"mappings": ";AACA,IAAM,MAAM;AACZ,IAAM,aAAa,oBAAI,IAAiC;AACxD,SAAS,UAAU,UAAkB;AACnC,MAAI,QAAQ,WAAW,IAAI,QAAQ;AACnC,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,KAAK,eAAe,SAAS;AAAA,MACvC,UAAU;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW;AAAA,IACb,CAAC;AACD,eAAW,IAAI,UAAU,KAAK;AAAA,EAChC;AACA,SAAO;AACT;AACO,SAAS,WAAW,MAAY,UAAkB;AACvD,QAAM,QAAQ,OAAO;AAAA,IACnB,UAAU,QAAQ,EACf,cAAc,IAAI,EAClB,IAAI,CAAC,EAAE,MAAM,MAAM,MAAM,CAAC,MAAM,KAAK,CAAC;AAAA,EAC3C;AACA,SAAO;AAAA,IACL,MAAM,GAAG,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG;AAAA,IAC/C,MAAM,OAAO,MAAM,IAAI;AAAA,IACvB,QAAQ,OAAO,MAAM,MAAM;AAAA,IAC3B,QAAQ,OAAO,MAAM,MAAM;AAAA,EAC7B;AACF;AAUO,SAAS,eAAe,OAAe;AAC5C,QAAM,QAAQ,iCAAiC,KAAK,KAAK;AACzD,MACE,CAAC,SACD,OAAO,MAAM,CAAC,CAAC,IAAI,MACnB,OAAO,MAAM,CAAC,CAAC,IAAI,MACnB,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,IACxB;AACA,WAAO;AAAA,EACT;AACA,QAAM,SAAS,OAAO,MAAM,CAAC,CAAC;AAC9B,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,SAAS,MAAM;AAAA,IACvB,QAAQ,OAAO,MAAM,CAAC,CAAC;AAAA,IACvB,QAAQ,OAAO,MAAM,CAAC,KAAK,CAAC;AAAA,IAC5B,QAAQ,UAAU,KAAK,OAAO;AAAA,EAChC;AACF;AAWO,SAAS,gBAAgB,OAAe;AAC7C,QAAM,OAAO,eAAe,KAAK;AACjC,SAAO,OACH,GAAG,KAAK,MAAM,GAAG,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG,GAAG,CAAC,KAAK,EAAE,IAAI,KAAK,MAAM,KAC7F;AACN;AAKO,SAAS,mBAAmB,OAAsB;AACvD,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,SAAqE,CAAC;AAC5E,WAAS,MAAM,GAAG,MAAM,GAAG,OAAO;AAChC,UAAM,YAAY,MACf,OAAO,CAAC,SAAS,CAAC,KAAK,YAAY,KAAK,QAAQ,GAAG,EACnD,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAChD,QAAI,CAAC,UAAU,QAAQ;AACrB;AAAA,IACF;AACA,UAAM,aAAa,UAChB;AAAA,MACC,CAAC,SACC,GAAG,gBAAgB,KAAK,KAAK,CAAC,WAAM,gBAAgB,KAAK,MAAM,CAAC;AAAA,IACpE,EACC,KAAK,IAAI;AACZ,UAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,QACE,QACA,KAAK,KAAK,KAAK,KAAK,SAAS,CAAC,MAAM,MAAM,KAC1C,KAAK,eAAe,YACpB;AACA,WAAK,KAAK,KAAK,GAAG;AAClB,WAAK,WAAW,GAAG,MAAM,KAAK,KAAK,CAAC,CAAE,CAAC,WAAM,MAAM,GAAG,CAAC;AAAA,IACzD,OAAO;AACL,aAAO,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,UAAU,MAAM,GAAG,GAAI,WAAW,CAAC;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;AACO,SAAS,WAAW,MAAc,MAAc;AACrD,SAAO,IAAI,KAAK,KAAK,MAAM,GAAG,IAAI,YAAY,IAAI,OAAO,GAAG,EACzD,YAAY,EACZ,MAAM,GAAG,EAAE;AAChB;AAEO,SAAS,aAAa,MAAc,OAAe,UAAkB;AAC1E,QAAM,OAAO,eAAe,KAAK;AACjC,MAAI,CAAC,MAAM;AACT,WAAO,CAAC;AAAA,EACV;AACA,QAAM,OACJ,KAAK,MAAM,GAAG,IAAI,YAAY,MAC5B,KAAK,SAAS,KAAK,KAAK,UAAU,KAAK,KAAK,UAAU;AAC1D,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,SAAS,CAAC,CAAC,KAAK,GAAG,GAAG,GAAG;AAClC,UAAM,SAAS,OAAO;AACtB,UAAM,QAAQ,WAAW,IAAI,KAAK,MAAM,GAAG,QAAQ;AACnD,UAAM,QACJ,KAAK,MAAM,GAAG,MAAM,IAAI,YAAY,MAClC,MAAM,OAAO,KAAK,MAAM,UAAU,KAAK,MAAM,UAAU;AAC3D,YAAQ,IAAI,QAAQ,MAAM;AAAA,EAC5B;AACA,QAAM,UAAU,CAAC;AACjB,aAAW,UAAU,SAAS;AAC5B,UAAM,UAAU,OAAO;AACvB,UAAM,QAAQ,WAAW,IAAI,KAAK,OAAO,GAAG,QAAQ;AACpD,QACE,MAAM,SAAS,QACf,MAAM,SAAS,KAAK,UACpB,MAAM,WAAW,KAAK,UACtB,MAAM,WAAW,KAAK,QACtB;AACA,cAAQ,KAAK,OAAO;AAAA,IACtB;AAAA,EACF;AACA,SAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACrC;AAEO,SAAS,iBACd,QACA,UACA,KACA,OAAO,GACY;AACnB,QAAM,QAAQ,WAAW,KAAK,QAAQ,EAAE;AACxC,QAAM,YAA+B,CAAC;AACtC,WAAS,SAAS,IAAI,SAAS,MAAM,UAAU;AAC7C,UAAM,OAAO,WAAW,OAAO,MAAM;AACrC,UAAM,OAAM,oBAAI,KAAK,GAAG,IAAI,YAAY,GAAE,UAAU;AACpD,UAAM,UAAU,OAAO,cAAc,KAAK,CAAC,UAAU,MAAM,SAAS,IAAI;AACxE,UAAM,QAAQ,UACV,QAAQ,UAAU,CAAC,QAAQ,SAAS,CAAC,QAAQ,SAC3C,CAAC,IACD,CAAC,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC,IACnD,OAAO,aAAa;AAAA,MAClB,CAAC,UAAU,MAAM,QAAQ,OAAO,CAAC,MAAM;AAAA,IACzC;AACJ,eAAW,SAAS,OAAO;AACzB,YAAM,SAAS,aAAa,MAAM,MAAM,OAAO,QAAQ;AACvD,YAAM,YAAY,MAAM,UAAU,MAAM;AACxC,YAAM,UAAU,YAAY,WAAW,MAAM,CAAC,IAAI;AAClD,YAAM,OAAO,aAAa,SAAS,MAAM,QAAQ,QAAQ;AACzD,YAAM,QAAQ,OAAO,CAAC;AACtB,UAAI,MAAM,KAAK,KAAK,SAAS,CAAC;AAC9B,UACE,aACA,OAAO,cAAc;AAAA,QACnB,CAACA,WAAUA,OAAM,SAAS,WAAWA,OAAM;AAAA,MAC7C,GACA;AACA,cAAM,aAAa,SAAS,SAAS,QAAQ,EAAE,CAAC;AAAA,MAClD;AACA,UAAI,UAAU,UAAa,QAAQ,UAAa,QAAQ,KAAK;AAC3D,kBAAU,KAAK,EAAE,OAAO,IAAI,CAAC;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AACA,QAAM,cAAc,OAAO,cACvB,KAAK,MAAM,OAAO,WAAW,IAC7B;AACJ,QAAM,SAAS,UACZ,IAAI,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,KAAK,IAAI,OAAO,WAAW,GAAG,IAAI,EAAE,EACtE,OAAO,CAAC,EAAE,OAAO,IAAI,MAAM,QAAQ,GAAG,EACtC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACnC,QAAM,SAA4B,CAAC;AACnC,aAAW,YAAY,QAAQ;AAC7B,UAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,QAAI,QAAQ,SAAS,SAAS,KAAK,KAAK;AACtC,WAAK,MAAM,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG;AAAA,IAC5C,OAAO;AACL,aAAO,KAAK,EAAE,GAAG,SAAS,CAAC;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;AAeO,SAAS,cACd,QACA,UACA,MAAM,oBAAI,KAAK,GACE;AACjB,QAAM,YAAY,iBAAiB,QAAQ,UAAU,GAAG;AACxD,QAAM,UAAU,UAAU;AAAA,IACxB,CAAC,EAAE,OAAO,IAAI,MAAM,SAAS,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ;AAAA,EAClE;AACA,QAAM,OACJ,SAAS,OAAO,UAAU,KAAK,CAAC,EAAE,MAAM,MAAM,QAAQ,IAAI,QAAQ,CAAC,GAAG;AACxE,MAAI,SAAS,QAAW;AACtB,WAAO,EAAE,QAAQ,OAAO,OAAO,SAAS;AAAA,EAC1C;AACA,QAAM,aAAa,IAAI,KAAK,IAAI;AAChC,QAAM,QAAQ,WAAW,YAAY,QAAQ;AAC7C,QAAM,QAAQ;AAAA,IACZ,GAAG,OAAO,MAAM,IAAI,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,MAAM,MAAM,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,EACjF,EACG,YAAY,EACZ,QAAQ,KAAK,EAAE;AAClB,QAAM,QAAQ,WAAW,KAAK,QAAQ,EAAE;AACxC,QAAM,SACJ,MAAM,SAAS,QACX,KACA,MAAM,SAAS,WAAW,OAAO,CAAC,IAChC,cACA,IAAI,IAAI,KAAK,eAAe,MAAM,EAAE,UAAU,UAAU,SAAS,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC;AACrG,SAAO;AAAA,IACL,QAAQ,QAAQ,OAAO;AAAA,IACvB,OAAO,UAAU,cAAc,KAAK,KAAK,SAAS,KAAK,GAAG,MAAM;AAAA,IAChE;AAAA,EACF;AACF;",
|
|
6
5
|
"names": ["hours"]
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/status/open-status.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\";\nimport type { Branch } from \"@zappie/sdk\";\nimport { useStore } from \"@zappie/sdk/react\";\nimport { forwardRef, useEffect, useState } from \"react\";\nimport { part, type PartProps } from \"../internal/slot\";\nimport { getOpenStatus, type OpenStatusState } from \"./hours\";\nexport function useOpenStatus(branch: Branch, timezone: string) {\n const [now, setNow] = useState(() => new Date());\n const state = getOpenStatus(branch, timezone, now);\n const boundary = state.nextChange?.getTime();\n useEffect(() => {\n // With no weekly boundary, retry at the next day for future calendar exceptions.\n const delay = boundary !== undefined ? boundary - Date.now() : 86400000;\n const timeout = setTimeout(\n () => setNow(new Date()),\n Math.max(1, Math.min(2147483647, delay)),\n );\n const refresh = () => setNow(new Date());\n window.addEventListener(\"focus\", refresh);\n return () => {\n clearTimeout(timeout);\n window.removeEventListener(\"focus\", refresh);\n };\n }, [branch, timezone, boundary]);\n return state;\n}\n/**\n * Expose a branch opening label and open/closed state in a span or your render function.\n * Uses your time zone override, then the branch, store or UTC, and refreshes at boundaries and window focus.\n */\nexport const OpenStatus = forwardRef<\n HTMLElement,\n PartProps<OpenStatusState> & { branch: Branch; timezone?: string }\n>(function OpenStatus({ branch, timezone, ...props }, ref) {\n const store = useStore();\n const state = useOpenStatus(\n branch,\n timezone ?? branch.timezone ?? store.data?.timezone ?? \"UTC\",\n );\n return part(\n \"span\",\n props,\n state,\n { \"data-state\": state.isOpen ? \"open\" : \"closed\" },\n ref,\n );\n});\n"],
|
|
5
4
|
"mappings": ";;;AAEA,SAAS,gBAAgB;AACzB,SAAS,YAAY,WAAW,gBAAgB;AAChD,SAAS,YAA4B;AACrC,SAAS,qBAA2C;AAC7C,SAAS,cAAc,QAAgB,UAAkB;AAC9D,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,MAAM,oBAAI,KAAK,CAAC;AAC/C,QAAM,QAAQ,cAAc,QAAQ,UAAU,GAAG;AACjD,QAAM,WAAW,MAAM,YAAY,QAAQ;AAC3C,YAAU,MAAM;AAEd,UAAM,QAAQ,aAAa,SAAY,WAAW,KAAK,IAAI,IAAI;AAC/D,UAAM,UAAU;AAAA,MACd,MAAM,OAAO,oBAAI,KAAK,CAAC;AAAA,MACvB,KAAK,IAAI,GAAG,KAAK,IAAI,YAAY,KAAK,CAAC;AAAA,IACzC;AACA,UAAM,UAAU,MAAM,OAAO,oBAAI,KAAK,CAAC;AACvC,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,MAAM;AACX,mBAAa,OAAO;AACpB,aAAO,oBAAoB,SAAS,OAAO;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,QAAQ,UAAU,QAAQ,CAAC;AAC/B,SAAO;AACT;AAKO,IAAM,aAAa,WAGxB,SAASA,YAAW,EAAE,QAAQ,UAAU,GAAG,MAAM,GAAG,KAAK;AACzD,QAAM,QAAQ,SAAS;AACvB,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,YAAY,OAAO,YAAY,MAAM,MAAM,YAAY;AAAA,EACzD;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,cAAc,MAAM,SAAS,SAAS,SAAS;AAAA,IACjD;AAAA,EACF;AACF,CAAC;",
|
|
6
5
|
"names": ["OpenStatus"]
|
|
7
6
|
}
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"
|
|
5
|
-
"mappings": ";AAMO,IAAM,kBACX,OACI,UACA;",
|
|
4
|
+
"mappings": ";AAMO,IAAM,kBACX,OACI,WACA;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zappie/foundations",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "UI-less React primitives for Zappie storefronts: behaviour, state and accessibility without styles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@base-ui/react": "^1.9.0",
|
|
35
35
|
"@googlemaps/markerclusterer": "^2.6.2",
|
|
36
|
-
"@zappie/sdk": "^0.
|
|
36
|
+
"@zappie/sdk": "^0.2.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": "^18.2.0 || ^19.0.0",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"url": "https://github.com/zappie/storefront-packages/issues"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
|
-
"build": "tsup && node ../../scripts/release-packages/build-modules.mjs",
|
|
57
|
+
"build": "tsup && node ../../scripts/release-packages/build-modules.mjs --no-sources-content",
|
|
58
58
|
"size": "node scripts/check-size.mjs"
|
|
59
59
|
}
|
|
60
60
|
}
|