@salesforce/storefront-next-runtime 0.3.1-alpha.1 → 0.4.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +82 -0
  2. package/dist/DesignComponent.js +37 -12
  3. package/dist/DesignComponent.js.map +1 -1
  4. package/dist/DesignContext.js +47 -2
  5. package/dist/DesignContext.js.map +1 -1
  6. package/dist/DesignFrame.js +1 -1
  7. package/dist/DesignRegion.js +1 -1
  8. package/dist/config.d.ts +4 -4
  9. package/dist/custom-global-preferences.d.ts +20 -0
  10. package/dist/custom-global-preferences.d.ts.map +1 -0
  11. package/dist/custom-global-preferences.js +28 -0
  12. package/dist/custom-global-preferences.js.map +1 -0
  13. package/dist/custom-site-preferences.d.ts +20 -0
  14. package/dist/custom-site-preferences.d.ts.map +1 -0
  15. package/dist/custom-site-preferences.js +28 -0
  16. package/dist/custom-site-preferences.js.map +1 -0
  17. package/dist/data-store-custom-global-preferences.d.ts +2 -0
  18. package/dist/data-store-custom-global-preferences.js +6 -0
  19. package/dist/data-store-custom-site-preferences.d.ts +2 -0
  20. package/dist/data-store-custom-site-preferences.js +6 -0
  21. package/dist/data-store-gcp-preferences.d.ts +2 -0
  22. package/dist/data-store-gcp-preferences.js +6 -0
  23. package/dist/data-store.d.ts +97 -0
  24. package/dist/data-store.d.ts.map +1 -0
  25. package/dist/data-store.js +42 -0
  26. package/dist/data-store.js.map +1 -0
  27. package/dist/design-data.d.ts +82 -88
  28. package/dist/design-data.d.ts.map +1 -1
  29. package/dist/design-data.js +95 -57
  30. package/dist/design-data.js.map +1 -1
  31. package/dist/design-messaging.d.ts +2 -2
  32. package/dist/events.d.ts +34 -6
  33. package/dist/events.d.ts.map +1 -1
  34. package/dist/events.js +6 -6
  35. package/dist/events.js.map +1 -1
  36. package/dist/gcp-preferences.d.ts +52 -0
  37. package/dist/gcp-preferences.d.ts.map +1 -0
  38. package/dist/gcp-preferences.js +61 -0
  39. package/dist/gcp-preferences.js.map +1 -0
  40. package/dist/i18n-client.d.ts +38 -0
  41. package/dist/i18n-client.d.ts.map +1 -0
  42. package/dist/i18n-client.js +72 -0
  43. package/dist/i18n-client.js.map +1 -0
  44. package/dist/i18n.d.ts +63 -0
  45. package/dist/i18n.d.ts.map +1 -0
  46. package/dist/i18n.js +98 -0
  47. package/dist/i18n.js.map +1 -0
  48. package/dist/index.d.ts +60 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/messaging-api.js +3 -1
  51. package/dist/messaging-api.js.map +1 -1
  52. package/dist/scapi.d.ts +247 -2
  53. package/dist/scapi.d.ts.map +1 -1
  54. package/dist/scapi.js +1 -1
  55. package/dist/scapi.js.map +1 -1
  56. package/dist/site-context.d.ts +94 -18
  57. package/dist/site-context.d.ts.map +1 -1
  58. package/dist/site-context.js +2 -417
  59. package/dist/site-context2.js +513 -0
  60. package/dist/site-context2.js.map +1 -0
  61. package/dist/types2.d.ts +210 -0
  62. package/dist/types2.d.ts.map +1 -1
  63. package/dist/utils.js +179 -0
  64. package/dist/utils.js.map +1 -0
  65. package/package.json +63 -4
  66. package/dist/site-context.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DesignContext.js","names":["results: ComponentDiscoveryResult[]","rect","component: ComponentDiscoveryResult | null","region: ComponentDiscoveryResult | null","insertType: InsertionType"],"sources":["../src/design/react/hooks/useInteraction.ts","../src/design/react/hooks/useSelectInteraction.ts","../src/design/react/hooks/useHoverInteraction.ts","../src/design/react/hooks/useDeleteInteraction.ts","../src/design/react/hooks/useFocusInteraction.ts","../src/design/react/hooks/useScrollInteraction.ts","../src/design/react/hooks/useComponentDiscovery.ts","../src/design/react/utils/regionUtils.ts","../src/design/react/hooks/useDragInteraction.ts","../src/design/react/context/DesignStateContext.tsx","../src/design/react/hooks/useDesignState.ts","../src/design/react/hooks/useThrottledCallback.ts","../src/design/react/hooks/useDebouncedCallback.ts","../src/design/react/hooks/useGlobalListeners.ts","../src/design/react/hooks/useGlobalAnchorBlock.ts","../src/design/react/components/DesignApp.tsx","../src/design/react/context/DesignContext.tsx"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect, useState, type Dispatch, type SetStateAction } from 'react';\nimport type { ClientApi, ClientEventNameMapping } from '../../messaging-api';\nimport { useDesignContext } from '../context/DesignContext';\n\nexport interface EventHandler<TState, TName extends keyof ClientEventNameMapping> {\n handler: (event: ClientEventNameMapping[TName], setState: Dispatch<SetStateAction<TState>>) => void;\n}\n\nexport interface InteractionConfig<TState, TActions> {\n /** Initial state value */\n initialState: TState | (() => TState);\n /** Event handlers to register with the client API */\n eventHandlers?: {\n [TKey in keyof ClientEventNameMapping]?: EventHandler<TState, TKey>;\n };\n /** Action creators that return functions to interact with the client API */\n actions?: (state: TState, setState: Dispatch<SetStateAction<TState>>, clientApi: ClientApi | null) => TActions;\n}\n\n/**\n * Base hook that provides common interaction patterns for design-time functionality.\n * Reduces boilerplate by handling state management, event listeners, and cleanup.\n *\n * @param config - Configuration object defining the interaction behavior\n * @returns Object containing state and action methods\n */\nexport function useInteraction<\n TState,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n TActions extends Record<string, (...args: any[]) => any>,\n>(config: InteractionConfig<TState, TActions>): { state: TState } & TActions {\n const [state, setState] = useState<TState>(config.initialState);\n const { isDesignMode, clientApi } = useDesignContext();\n\n useEffect(() => {\n if (!isDesignMode || !clientApi) {\n return () => {\n // Return empty cleanup function for consistency\n };\n }\n\n const unsubscribeFunctions = Object.entries(config.eventHandlers ?? {}).map(([eventName, entry]) =>\n clientApi.on(eventName as keyof ClientEventNameMapping, (event) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n entry.handler(event as any, setState)\n )\n );\n\n return () => {\n unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n };\n }, [isDesignMode, clientApi, config.eventHandlers]);\n\n const actions = config.actions?.(state, setState, clientApi ?? null) ?? ({} as TActions);\n\n return { state, ...actions };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface SelectInteraction {\n selectedComponentId: string;\n setSelectedComponent: (componentId: string) => void;\n}\n\n/**\n * Custom hook that manages component selection state and handles\n * client-host communication for selection events.\n *\n * @param isDesignMode - Whether design mode is active\n * @param clientApi - Client API for host communication\n * @returns Selection state and interaction methods\n */\nexport function useSelectInteraction(): SelectInteraction {\n const { state: selectedComponentId, setSelectedComponent } = useInteraction({\n initialState: '',\n eventHandlers: {\n ComponentSelected: {\n handler: (event, setState) => {\n setState(event.componentId);\n },\n },\n ComponentDeselected: {\n handler: (_, setState) => {\n setState('');\n },\n },\n },\n actions: (_state, setState, clientApi) => ({\n setSelectedComponent: (componentId: string) => {\n setState(componentId);\n clientApi?.selectComponent({ componentId });\n },\n }),\n });\n\n return {\n selectedComponentId,\n setSelectedComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface HoverInteraction {\n hoveredComponentId: string | null;\n setHoveredComponent: (componentId: string | null) => void;\n}\n\n/**\n * Custom hook that manages component hover state and handles\n * client-host communication for hover events.\n *\n * @returns Hover state and interaction methods\n */\nexport function useHoverInteraction(): HoverInteraction {\n const { state: hoveredComponentId, setHoveredComponent } = useInteraction({\n initialState: null as string | null,\n eventHandlers: {\n ComponentHoveredIn: {\n handler: (event, setState) => setState(event.componentId),\n },\n ComponentHoveredOut: {\n handler: (_, setState) => setState(null),\n },\n },\n actions: (state, setState, clientApi) => ({\n setHoveredComponent: (componentId: string | null) => {\n if (state && componentId !== state) {\n // Use the current hovered component for hover out\n clientApi?.hoverOutOfComponent({\n componentId: state,\n });\n }\n\n if (componentId && componentId !== state) {\n clientApi?.hoverInToComponent({ componentId });\n }\n\n setState(componentId);\n },\n }),\n });\n\n return {\n hoveredComponentId,\n setHoveredComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\nimport type { ComponentDeletedEvent, EventPayload } from '../../messaging-api';\n\nexport interface DeleteInteraction {\n deleteComponent: (componentId: EventPayload<ComponentDeletedEvent>) => void;\n}\n\nexport function useDeleteInteraction({\n selectedComponentId,\n setSelectedComponent,\n}: {\n selectedComponentId: string | null;\n setSelectedComponent: (componentId: string) => void;\n}): DeleteInteraction {\n const { deleteComponent } = useInteraction({\n initialState: null,\n eventHandlers: {},\n actions: (_state, _setState, clientApi) => ({\n deleteComponent: (event: EventPayload<ComponentDeletedEvent>) => {\n clientApi?.deleteComponent(event);\n\n // When a component is deleted, we want to make sure it's no longer selected.\n if (selectedComponentId === event.componentId) {\n setSelectedComponent('');\n }\n },\n }),\n });\n\n return {\n deleteComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface FocusInteraction {\n focusedComponentId: string | null;\n focusComponent: (node: Element) => void;\n}\n\nexport function useFocusInteraction({\n setSelectedComponent,\n}: {\n setSelectedComponent: (componentId: string) => void;\n}): FocusInteraction {\n const { state: focusedComponentId, focusComponent } = useInteraction({\n initialState: null as string | null,\n eventHandlers: {\n ComponentFocused: {\n handler: (event, setState) => {\n setSelectedComponent('');\n setState(event.componentId);\n },\n },\n },\n actions: (_state, setState) => ({\n focusComponent: (node: Element) => {\n node.scrollIntoView();\n setState(null);\n },\n }),\n });\n\n return {\n focusedComponentId,\n focusComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface ScrollInteraction {\n notifyWindowScrollChange: (x: number, y: number) => void;\n}\n\n/**\n * Custom hook that manages component hover state and handles\n * client-host communication for hover events.\n *\n * @returns Hover state and interaction methods\n */\nexport function useScrollInteraction(): ScrollInteraction {\n const { notifyWindowScrollChange } = useInteraction({\n initialState: null,\n eventHandlers: {\n WindowScrollChanged: {\n handler: (event) => {\n if (event.scrollY != null) {\n window.scrollTo({\n behavior: 'instant',\n top: event.scrollY,\n });\n }\n },\n },\n },\n actions: (_state, _setState, clientApi) => ({\n notifyWindowScrollChange: (x: number, y: number) => {\n clientApi?.notifyWindowScrollChanged({\n scrollX: x,\n scrollY: y,\n });\n },\n }),\n });\n\n return { notifyWindowScrollChange };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback } from 'react';\nimport type { NodeToTargetMapEntry } from '../context/DesignStateContext';\n\nexport type ComponentDiscoveryResult = NodeToTargetMapEntry & { node: Element };\n\n/**\n * Returns a utility for discovering components and regions at a given\n * x, y coordinates.\n * @param nodeToTargetMap - The map of nodes to target entries.\n */\nexport function useComponentDiscovery({\n nodeToTargetMap,\n}: {\n nodeToTargetMap: WeakMap<Element, NodeToTargetMapEntry>;\n}): (query: { x: number; y: number; filter?: (entry: NodeToTargetMapEntry) => boolean }) => ComponentDiscoveryResult[] {\n return useCallback(\n ({ x, y, filter = () => true }) => {\n const nodeStack = document.elementsFromPoint(x, y);\n const results: ComponentDiscoveryResult[] = [];\n\n for (let i = 0; i < nodeStack.length; i += 1) {\n const node = nodeStack[i];\n const entry = nodeToTargetMap.get(node);\n\n if (entry && filter(entry)) {\n results.push({ ...entry, node });\n }\n }\n\n return results;\n },\n [nodeToTargetMap]\n );\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Checks if a component type is allowed in a region based on inclusion and exclusion rules.\n *\n * @param componentType - The type of component being checked\n * @param componentTypeInclusions - Array of allowed component types (if empty, all types are allowed by default)\n * @param componentTypeExclusions - Array of forbidden component types\n * @returns true if the component type is allowed, false otherwise\n */\nexport function isComponentTypeAllowedInRegion(\n componentType: string | undefined,\n componentTypeInclusions: string[],\n componentTypeExclusions: string[]\n): boolean {\n if (!componentType) {\n return false;\n }\n\n if (componentTypeExclusions?.includes(componentType)) {\n return false;\n }\n\n // If there are inclusions specified, the component type must be in the list\n if (componentTypeInclusions?.length > 0) {\n return componentTypeInclusions.includes(componentType);\n }\n\n return true;\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { useInteraction } from './useInteraction';\nimport type { NodeToTargetMapEntry } from '../context/DesignStateContext';\nimport { useComponentDiscovery, type ComponentDiscoveryResult } from './useComponentDiscovery';\nimport { isComponentTypeAllowedInRegion } from '../utils/regionUtils';\n\n// The height of the scroll buffer on the top and bottom of the window\n// as a percentage of the window height.\nconst SCROLL_BUFFER_HEIGHT_PERCENTAGE = 15;\nconst SCROLL_BUFFER_MIN_HEIGHT_IN_PIXELS = 50;\n// The interval at which the window will scroll within the buffer.\n// More often means a smoother experience.\nconst SCROLL_INTERVAL_IN_MS = 1000 / 60; // 60fps\n// The multiplier applied to the scroll factor.\n// The scroll factor is a value between 0 and 1 that determines how much to scroll.\n// This value will be the maximum amount of pixels that will be scrolled in a single frame.\nconst SCROLL_BASE_AMOUNT_IN_PIXELS = 50;\n\ninterface InsertionType {\n axis: 'x' | 'y';\n type: 'before' | 'after';\n}\n\nexport interface DropTarget extends NodeToTargetMapEntry {\n beforeComponentId?: string;\n afterComponentId?: string;\n insertType: InsertionType;\n insertComponentId?: string;\n regionId: string;\n}\n\nexport interface DragInteraction {\n dragState: {\n isDragging: boolean;\n x: number;\n y: number;\n currentDropTarget: DropTarget | null;\n pendingTargetCommit: boolean;\n componentType?: string;\n sourceComponentId?: string;\n sourceRegionId?: string;\n rectCache: WeakMap<Element, DOMRect>;\n scrollDirection: 0 | 1 | -1;\n pendingComponentDragId: string | null;\n };\n commitCurrentDropTarget: () => void;\n startComponentMove: (componentId: string, regionId: string, componentType: string) => void;\n updateComponentMove: (params: { x: number; y: number }) => void;\n setPendingComponentDragId: (componentId: string) => void;\n dropComponent: () => void;\n cancelDrag: () => void;\n}\n\nfunction getInsertionType({\n cache,\n node,\n x,\n y,\n}: {\n cache: WeakMap<Element, DOMRect>;\n node: Element;\n x: number;\n y: number;\n}): InsertionType {\n if (!cache.has(node)) {\n const rect = node.getBoundingClientRect();\n const screenLeft = rect.left - window.scrollX;\n const screenTop = rect.top + window.scrollY;\n\n // A bounding box is relative to the viewport.\n // We need to know the absolute position, taking into account the scroll position.\n cache.set(node, new DOMRect(screenLeft, screenTop, rect.width, rect.height));\n }\n\n const rect = cache.get(node) as DOMRect;\n const screenX = x + window.scrollX;\n const screenY = y + window.scrollY;\n const midX = rect.left + rect.width / 2;\n const midY = rect.top + rect.height / 2;\n const deltaX = screenX - midX;\n const deltaY = screenY - midY;\n // Use the relative delta for boxes that are not square.\n const relativeDeltaX = deltaX / (rect.width / 2);\n const relativeDeltaY = deltaY / (rect.height / 2);\n\n if (Math.abs(relativeDeltaX) > Math.abs(relativeDeltaY)) {\n return { axis: 'x', type: relativeDeltaX < 0 ? 'before' : 'after' };\n }\n\n return { axis: 'y', type: relativeDeltaY < 0 ? 'before' : 'after' };\n}\n\n// Determines whether a source component is being dropped on itself.\nfunction isOnSelfDropTarget({\n sourceComponentId,\n beforeComponentId,\n afterComponentId,\n insertType,\n componentId,\n}: {\n sourceComponentId: string | undefined;\n beforeComponentId: string | undefined;\n afterComponentId: string | undefined;\n insertType: InsertionType;\n componentId: string;\n}) {\n const isOnSource = sourceComponentId && componentId === sourceComponentId;\n const isOnSameRegionBefore =\n sourceComponentId && insertType.type === 'before' && beforeComponentId === sourceComponentId;\n const isOnSameRegionAfter =\n sourceComponentId && insertType.type === 'after' && afterComponentId === sourceComponentId;\n\n return isOnSource || isOnSameRegionBefore || isOnSameRegionAfter;\n}\n\nexport function useDragInteraction({\n nodeToTargetMap,\n}: {\n nodeToTargetMap: WeakMap<Element, NodeToTargetMapEntry>;\n}): DragInteraction {\n const discoverComponents = useComponentDiscovery({\n nodeToTargetMap,\n });\n const getNearestComponentAndRegion = useCallback(\n (\n x: number,\n y: number\n ): {\n component: ComponentDiscoveryResult | null;\n region: ComponentDiscoveryResult | null;\n } => {\n const stack = discoverComponents({ x, y });\n let component: ComponentDiscoveryResult | null = null;\n let region: ComponentDiscoveryResult | null = null;\n\n for (let i = 0; i < stack.length; i += 1) {\n const entry = stack[i];\n\n // We need a region id and direction for this to be a target.\n if (entry.regionId) {\n if (entry.type === 'component') {\n component = entry;\n } else if (entry.type === 'region') {\n region = entry;\n // Once we find a region we need to exit.\n break;\n }\n }\n }\n\n return { component, region };\n },\n [discoverComponents]\n );\n\n const getInsertionComponentIds = (\n componentId: string,\n region: NodeToTargetMapEntry & { node: Element }\n ): [string | undefined, string | undefined] => {\n const componentIndex = region.componentIds.indexOf(componentId);\n\n return [region.componentIds[componentIndex - 1], region.componentIds[componentIndex + 1]];\n };\n\n const getCurrentDropTarget = useCallback(\n ({\n x,\n y,\n rectCache,\n componentType,\n }: {\n x: number;\n y: number;\n rectCache: WeakMap<Element, DOMRect>;\n componentType?: string;\n }): DropTarget | null => {\n const { component, region } = getNearestComponentAndRegion(x, y);\n\n if (region) {\n // If component type is not allowed, don't return a drop target\n if (\n !isComponentTypeAllowedInRegion(\n componentType,\n region.componentTypeInclusions || [],\n region.componentTypeExclusions || []\n )\n ) {\n return null;\n }\n\n const insertType: InsertionType = component\n ? getInsertionType({\n cache: rectCache,\n node: component.node,\n x,\n y,\n })\n : { axis: 'y', type: 'after' };\n\n const [beforeComponentId, afterComponentId] = component\n ? getInsertionComponentIds(component.componentId, region)\n : [];\n\n // If we find a component before a region, it means we are dropping over a component.\n // If no component is found before a region, it means we are dropping over an empty region.\n return {\n type: component ? 'component' : 'region',\n regionId: region.regionId,\n componentIds: region.componentIds,\n componentId: component?.componentId ?? '',\n parentId: region.parentId,\n beforeComponentId,\n afterComponentId,\n insertComponentId: component?.componentId,\n insertType,\n componentTypeInclusions: region.componentTypeInclusions,\n componentTypeExclusions: region.componentTypeExclusions,\n };\n }\n\n return null;\n },\n [getNearestComponentAndRegion]\n );\n\n const computeScrollFactor = ({ y, windowHeight }: { y: number; windowHeight: number }) => {\n const bufferHeight = Math.max(\n windowHeight * (SCROLL_BUFFER_HEIGHT_PERCENTAGE / 100),\n SCROLL_BUFFER_MIN_HEIGHT_IN_PIXELS\n );\n const bottomBufferStart = windowHeight - bufferHeight;\n\n if (y > bottomBufferStart) {\n return (y - bottomBufferStart) / bufferHeight;\n }\n\n if (y < bufferHeight) {\n return (y - bufferHeight) / bufferHeight;\n }\n\n return 0;\n };\n\n const computeScrollDirection = (factor: number): 0 | 1 | -1 => {\n if (factor > 0) {\n return 1;\n }\n\n if (factor < 0) {\n return -1;\n }\n\n return 0;\n };\n\n const scrollFactorRef = useRef(0);\n\n const {\n state: dragState,\n commitCurrentDropTarget,\n updateComponentMove,\n startComponentMove,\n dropComponent,\n cancelDrag,\n setPendingComponentDragId,\n } = useInteraction({\n initialState: {\n isDragging: false,\n componentType: '',\n sourceComponentId: undefined as string | undefined,\n sourceRegionId: undefined as string | undefined,\n x: 0,\n y: 0,\n currentDropTarget: null as DropTarget | null,\n pendingTargetCommit: false,\n rectCache: new WeakMap<Element, DOMRect>(),\n pendingComponentDragId: null,\n } as DragInteraction['dragState'],\n eventHandlers: {\n ComponentDragStarted: {\n handler: (event, setState) => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n componentType: event.componentType,\n sourceComponentId: undefined,\n sourceRegionId: undefined,\n x: 0,\n y: 0,\n isDragging: true,\n currentDropTarget: null,\n pendingTargetCommit: false,\n scrollDirection: 0,\n rectCache: new WeakMap<Element, DOMRect>(),\n }));\n },\n },\n ClientWindowDragExited: {\n handler: (_, setState) => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n componentType: '',\n x: 0,\n y: 0,\n isDragging: false,\n currentDropTarget: null,\n scrollDirection: 0,\n pendingTargetCommit: false,\n }));\n },\n },\n ClientWindowDragMoved: {\n handler: (event, setState) => {\n scrollFactorRef.current = computeScrollFactor({\n y: event.y,\n windowHeight: window.innerHeight,\n });\n\n setState((prevState) => ({\n ...prevState,\n x: event.x,\n y: event.y,\n isDragging: true,\n scrollDirection: computeScrollDirection(scrollFactorRef.current),\n currentDropTarget: getCurrentDropTarget({\n x: event.x,\n y: event.y,\n rectCache: dragState.rectCache,\n componentType: prevState.componentType,\n }),\n }));\n },\n },\n ClientWindowDragDropped: {\n handler: (_, setState) => {\n setState((prevState) => ({\n ...prevState,\n isDragging: false,\n pendingTargetCommit: true,\n }));\n },\n },\n },\n actions: (state, setState, clientApi) => ({\n cancelDrag: () => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n x: 0,\n y: 0,\n scrollDirection: 0,\n isDragging: false,\n pendingComponentDragId: null,\n }));\n },\n updateComponentMove: ({ x, y }: { x: number; y: number }) => {\n scrollFactorRef.current = computeScrollFactor({\n y,\n windowHeight: window.innerHeight,\n });\n\n setState((prevState) => ({\n ...prevState,\n x,\n y,\n scrollDirection: computeScrollDirection(scrollFactorRef.current),\n currentDropTarget: getCurrentDropTarget({\n x,\n y,\n rectCache: state.rectCache,\n componentType: state.componentType,\n }),\n }));\n },\n setPendingComponentDragId: (componentId: string) => {\n setState((prevState) => ({\n ...prevState,\n pendingComponentDragId: componentId,\n }));\n },\n dropComponent: () => {\n setState((prevState) => ({\n ...prevState,\n isDragging: false,\n pendingTargetCommit: true,\n }));\n },\n startComponentMove: (componentId: string, regionId: string, componentType: string) => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n x: 0,\n y: 0,\n componentType,\n sourceComponentId: componentId,\n sourceRegionId: regionId,\n isDragging: true,\n scrollDirection: 0,\n rectCache: new WeakMap<Element, DOMRect>(),\n }));\n },\n commitCurrentDropTarget: () => {\n // Don't do anything if we don't have a drop target.\n if (state.currentDropTarget) {\n // If we have a source component id, then we are moving a component to a different region.\n if (state.sourceComponentId) {\n if (\n !isOnSelfDropTarget({\n sourceComponentId: state.sourceComponentId,\n beforeComponentId: state.currentDropTarget.beforeComponentId,\n afterComponentId: state.currentDropTarget.afterComponentId,\n insertType: state.currentDropTarget.insertType,\n componentId: state.currentDropTarget.componentId,\n })\n ) {\n clientApi?.moveComponentToRegion({\n componentId: state.sourceComponentId,\n sourceRegionId: state.sourceRegionId ?? '',\n insertType: state.currentDropTarget.insertType?.type,\n insertComponentId: state.currentDropTarget.insertComponentId,\n beforeComponentId: state.currentDropTarget.beforeComponentId,\n afterComponentId: state.currentDropTarget.afterComponentId,\n targetRegionId: state.currentDropTarget.regionId,\n targetComponentId: state.currentDropTarget.parentId ?? '',\n });\n }\n // If we don't have a source component id, then we are adding a new component to a region.\n } else if (state.componentType) {\n clientApi?.addComponentToRegion({\n insertType: state.currentDropTarget.insertType?.type,\n insertComponentId: state.currentDropTarget.insertComponentId,\n componentProperties: {},\n componentType: state.componentType,\n targetComponentId: state.currentDropTarget.parentId ?? '',\n beforeComponentId: state.currentDropTarget.beforeComponentId,\n afterComponentId: state.currentDropTarget.afterComponentId,\n targetRegionId: state.currentDropTarget.regionId,\n });\n }\n }\n\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n x: 0,\n y: 0,\n componentType: '',\n scrollDirection: 0,\n sourceComponentId: undefined,\n sourceRegionId: undefined,\n pendingComponentDragId: null,\n currentDropTarget: null,\n pendingTargetCommit: false,\n }));\n },\n }),\n });\n\n // Commits the current drop target if we are pending a target commit.\n useEffect(() => {\n if (dragState.pendingTargetCommit) {\n commitCurrentDropTarget();\n }\n }, [dragState.pendingTargetCommit, commitCurrentDropTarget]);\n\n // Starts scrolling the window when the drag state scroll factor is not 0.\n useEffect(() => {\n if (dragState.scrollDirection !== 0) {\n const interval = setInterval(() => {\n window.scrollBy(0, scrollFactorRef.current * SCROLL_BASE_AMOUNT_IN_PIXELS);\n }, SCROLL_INTERVAL_IN_MS);\n\n return () => clearInterval(interval);\n }\n\n return () => {\n // noop\n };\n }, [dragState.scrollDirection, scrollFactorRef]);\n\n return {\n dragState,\n setPendingComponentDragId,\n commitCurrentDropTarget,\n startComponentMove,\n updateComponentMove,\n dropComponent,\n cancelDrag,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { useSelectInteraction } from '../hooks/useSelectInteraction';\nimport { useHoverInteraction } from '../hooks/useHoverInteraction';\nimport { useDeleteInteraction } from '../hooks/useDeleteInteraction';\nimport { useFocusInteraction } from '../hooks/useFocusInteraction';\nimport { useScrollInteraction, type ScrollInteraction } from '../hooks/useScrollInteraction';\nimport { useDragInteraction, type DragInteraction } from '../hooks/useDragInteraction';\nimport type { ComponentDeletedEvent, EventPayload } from '../../messaging-api';\n\nexport interface NodeToTargetMapEntry {\n type: 'region' | 'component';\n parentId?: string;\n componentId: string;\n regionId: string;\n componentIds: string[];\n componentTypeInclusions?: string[];\n componentTypeExclusions?: string[];\n}\n\nexport interface DesignState extends DragInteraction, ScrollInteraction {\n selectedComponentId: string | null;\n hoveredComponentId: string | null;\n setSelectedComponent: (componentId: string) => void;\n setHoveredComponent: (componentId: string | null) => void;\n deleteComponent: (event: EventPayload<ComponentDeletedEvent>) => void;\n focusComponent: (node: Element) => void;\n focusedComponentId: string | null;\n nodeToTargetMap: WeakMap<Element, NodeToTargetMapEntry>;\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const DesignStateContext = React.createContext<DesignState>(null as unknown as DesignState);\n\nexport const DesignStateProvider = ({ children }: { children: React.ReactNode }): React.JSX.Element => {\n const selectInteraction = useSelectInteraction();\n const hoverInteraction = useHoverInteraction();\n const deleteInteraction = useDeleteInteraction({\n selectedComponentId: selectInteraction.selectedComponentId,\n setSelectedComponent: selectInteraction.setSelectedComponent,\n });\n const focusInteraction = useFocusInteraction({\n setSelectedComponent: selectInteraction.setSelectedComponent,\n });\n const scrollInteraction = useScrollInteraction();\n const nodeToTargetMap = React.useMemo(() => new WeakMap(), []);\n const dragInteraction = useDragInteraction({ nodeToTargetMap });\n\n const state = React.useMemo(\n () => ({\n ...deleteInteraction,\n ...selectInteraction,\n ...hoverInteraction,\n ...focusInteraction,\n ...dragInteraction,\n ...scrollInteraction,\n nodeToTargetMap,\n }),\n [\n deleteInteraction,\n selectInteraction,\n hoverInteraction,\n focusInteraction,\n dragInteraction,\n nodeToTargetMap,\n scrollInteraction,\n ]\n );\n\n return <DesignStateContext.Provider value={state}>{children}</DesignStateContext.Provider>;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { DesignStateContext, type DesignState } from '../context/DesignStateContext';\n\n/**\n * Custom hook that manages design-time component state by composing\n * individual interaction hooks for better maintainability and testability.\n *\n * @returns Combined design state from all interactions\n */\nexport const useDesignState = (): DesignState => {\n const context = React.useContext(DesignStateContext);\n\n if (!context) {\n throw new Error('useDesignState must be used within a DesignStateProvider');\n }\n\n return context;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useRef, useCallback } from 'react';\n\nexport function useThrottledCallback<TArgs extends unknown[], TReturn>(\n callback: (...args: TArgs) => TReturn,\n interval: number,\n deps: unknown[] = []\n): (...args: TArgs) => TReturn | void {\n const lastCallTime = useRef<number>(0);\n\n return useCallback(\n (...args: TArgs): TReturn | void => {\n const now = Date.now();\n\n if (now >= lastCallTime.current + interval) {\n lastCallTime.current = now;\n\n callback(...args);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [callback, interval, ...deps]\n );\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useRef, useCallback } from 'react';\n\nexport function useDebouncedCallback<TArgs extends unknown[], TReturn>(\n callback: (...args: TArgs) => TReturn,\n interval: number,\n deps: unknown[] = []\n): (...args: TArgs) => TReturn | void {\n const timeoutRef = useRef<number | null>(null);\n\n return useCallback(\n (...args: TArgs): TReturn | void => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n\n timeoutRef.current = setTimeout(() => {\n callback(...args);\n timeoutRef.current = null;\n }, interval) as unknown as number;\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [callback, interval, ...deps]\n );\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect } from 'react';\nimport { useDesignState } from './useDesignState';\nimport { useThrottledCallback } from './useThrottledCallback';\nimport { useDebouncedCallback } from './useDebouncedCallback';\n\nconst FPS_60 = 1000 / 60;\n\nexport function useGlobalListeners(): void {\n const { dropComponent, updateComponentMove, cancelDrag, notifyWindowScrollChange } = useDesignState();\n const dragListener = useThrottledCallback(\n (event: DragEvent) => updateComponentMove({ x: event.clientX, y: event.clientY }),\n FPS_60,\n [updateComponentMove]\n );\n const scrollListener = useDebouncedCallback(() => notifyWindowScrollChange(window.scrollX, window.scrollY), 100, [\n notifyWindowScrollChange,\n ]);\n\n useEffect(() => {\n const dragEndListener = () => dropComponent();\n const mouseUpListener = () => cancelDrag();\n\n window.addEventListener('dragover', dragListener);\n window.addEventListener('dragend', dragEndListener);\n window.addEventListener('scroll', scrollListener);\n // We need to make sure we cancel dragging on mouseup since we\n // we are using mousedown to start dragging or else it would stay in a dragging\n // state from regular click events.\n window.addEventListener('mouseup', mouseUpListener);\n\n return () => {\n window.removeEventListener('dragover', dragListener);\n window.removeEventListener('dragend', dragEndListener);\n window.removeEventListener('mouseup', mouseUpListener);\n window.removeEventListener('scroll', scrollListener);\n };\n }, [dropComponent, cancelDrag, dragListener, scrollListener]);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect } from 'react';\n\n/**\n * React hook that prevents all <a> (anchor) navigation by default in the document,\n * unless the anchor has the attribute `data-pd-allow-link`.\n */\nexport function useGlobalAnchorBlock(): void {\n useEffect(() => {\n function preventAnchorClicks(event: MouseEvent) {\n const target = event.target as HTMLElement;\n const anchor = target.closest('a');\n\n // This data attribute acts as a workaround in the event we do\n // want to have an anchor tag navigate in design mode.\n if (anchor && !anchor.hasAttribute('data-pd-allow-link')) {\n event.preventDefault();\n }\n }\n\n document.addEventListener('click', preventAnchorClicks);\n\n return () => document.removeEventListener('click', preventAnchorClicks);\n }, []);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useGlobalListeners } from '../hooks/useGlobalListeners';\nimport { useGlobalAnchorBlock } from '../hooks/useGlobalAnchorBlock';\n\n/**\n * Containes any global setup logic for the design layer.\n */\nexport const DesignApp = ({ children }: React.PropsWithChildren<unknown>): React.JSX.Element => {\n useGlobalListeners();\n useGlobalAnchorBlock();\n\n return <>{children}</>;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport {\n createClientApi,\n type ClientApi,\n type IsomorphicConfiguration,\n type ClientAcknowledgedEvent,\n type EventPayload,\n type HostToClientConfiguration,\n} from '../../messaging-api';\nimport type { ShopperExperience } from '@/scapi-client/types';\nimport { DesignStateProvider } from './DesignStateContext';\nimport { DesignApp } from '../components/DesignApp';\nimport { usePageDesignerMode } from '../core/PageDesignerProvider';\n\nconst noop = () => {\n /* noop */\n};\n\n/**\n * Type definition for the Design Context\n * Extends DesignState with additional design-time properties\n */\nexport interface DesignContextType {\n /** Whether design mode is currently active */\n isDesignMode: boolean;\n /** Client API for host communication */\n clientApi?: ClientApi;\n /** Whether the client is connected to the host */\n isConnected: boolean;\n /** The page designer config */\n pageDesignerConfig: EventPayload<ClientAcknowledgedEvent> | null;\n /** Page data that the client has retrieved */\n clientPage: ShopperExperience.schemas['Page'] | null;\n /** Sets the client page data */\n setClientPage: (page: ShopperExperience.schemas['Page']) => void;\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const DesignContext = React.createContext<DesignContextType>({\n isDesignMode: false,\n isConnected: false,\n pageDesignerConfig: null,\n clientPage: null,\n setClientPage: noop,\n});\n\n/**\n * Provider component that enables design-time functionality for child components.\n * Sets up client-host communication and manages component selection state.\n *\n * @param children - Child components to wrap with design functionality\n * @param targetOrigin - Target origin for postMessage communication\n * @param clientId - Id for the client API\n * @returns JSX element wrapping children with design context\n */\nexport const DesignProvider = ({\n children,\n targetOrigin,\n clientId,\n usid,\n clientConnectionTimeout,\n clientConnectionInterval,\n clientLogger = noop,\n}: React.PropsWithChildren<{\n targetOrigin: string;\n clientId: string;\n usid?: string;\n clientConnectionTimeout?: number;\n clientConnectionInterval?: number;\n clientLogger?: IsomorphicConfiguration['logger'];\n}>): React.JSX.Element => {\n const { isDesignMode } = usePageDesignerMode();\n const [isConnected, setIsConnected] = React.useState(false);\n const [pageDesignerConfig, setPageDesignerConfig] = React.useState<HostToClientConfiguration | null>(null);\n const [clientPage, setClientPage] = React.useState<ShopperExperience.schemas['Page'] | null>(null);\n const clientPageRef = React.useRef<ShopperExperience.schemas['Page'] | null>(null);\n\n const clientApi = React.useMemo(\n () =>\n createClientApi({\n logger: clientLogger,\n emitter: {\n postMessage: (message) => window.parent.postMessage(message, targetOrigin),\n addEventListener: (handler) => {\n const listener = (event: MessageEvent) => handler(event.data);\n\n window.addEventListener('message', listener);\n\n return () => window.removeEventListener('message', listener);\n },\n },\n id: clientId,\n }),\n [targetOrigin, clientId, clientLogger]\n );\n\n React.useEffect(() => {\n // This will poll the host for a connection until the client is acknowledged.\n clientApi.connect({\n timeout: clientConnectionTimeout,\n interval: clientConnectionInterval,\n onHostConnected: (event) => {\n setPageDesignerConfig(event);\n setIsConnected(true);\n },\n onHostDisconnected: (reconnect) => {\n setPageDesignerConfig(null);\n setIsConnected(false);\n reconnect();\n },\n onError: () => {\n // TODO: Figure out how to handle this.\n },\n usid,\n });\n\n return () => {\n clientApi.disconnect();\n setPageDesignerConfig(null);\n setIsConnected(false);\n };\n }, [clientApi, clientConnectionTimeout, clientConnectionInterval, usid]);\n\n // Use the extracted state management hook\n const contextValue = React.useMemo<DesignContextType>(\n () => ({\n isDesignMode,\n clientApi,\n isConnected,\n pageDesignerConfig,\n clientPage,\n setClientPage: (page: ShopperExperience.schemas['Page']) => {\n if (page !== clientPageRef.current) {\n clientPageRef.current = page;\n setClientPage(page);\n clientApi?.notifyClientPageChanged({ page });\n }\n },\n }),\n [isDesignMode, clientApi, isConnected, pageDesignerConfig, clientPage, setClientPage]\n );\n\n return (\n <DesignContext.Provider value={contextValue}>\n <DesignStateProvider>\n <DesignApp>{children}</DesignApp>\n </DesignStateProvider>\n </DesignContext.Provider>\n );\n};\n\nDesignProvider.defaultProps = {\n clientLogger: noop,\n clientConnectionTimeout: 60_000,\n clientConnectionInterval: 1_000,\n};\n\n/**\n * Custom hook to access the design context\n * Provides access to design mode state and component selection functionality\n *\n * @returns The current design context\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport const useDesignContext = (): DesignContextType => React.useContext(DesignContext);\n"],"mappings":"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"}
1
+ {"version":3,"file":"DesignContext.js","names":["results: ComponentDiscoveryResult[]","rect","component: ComponentDiscoveryResult | null","region: ComponentDiscoveryResult | null","insertType: InsertionType","initialUpdates: Record<string, ComponentUpdate>"],"sources":["../src/design/react/hooks/useInteraction.ts","../src/design/react/hooks/useSelectInteraction.ts","../src/design/react/hooks/useHoverInteraction.ts","../src/design/react/hooks/useDeleteInteraction.ts","../src/design/react/hooks/useFocusInteraction.ts","../src/design/react/hooks/useScrollInteraction.ts","../src/design/react/hooks/useComponentDiscovery.ts","../src/design/react/utils/regionUtils.ts","../src/design/react/hooks/useDragInteraction.ts","../src/design/react/hooks/useComponentUpdateInteraction.ts","../src/design/react/context/DesignStateContext.tsx","../src/design/react/hooks/useDesignState.ts","../src/design/react/hooks/useThrottledCallback.ts","../src/design/react/hooks/useDebouncedCallback.ts","../src/design/react/hooks/useGlobalListeners.ts","../src/design/react/hooks/useGlobalAnchorBlock.ts","../src/design/react/components/DesignApp.tsx","../src/design/react/context/DesignContext.tsx"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect, useState, type Dispatch, type SetStateAction } from 'react';\nimport type { ClientApi, ClientEventNameMapping } from '../../messaging-api';\nimport { useDesignContext } from '../context/DesignContext';\n\nexport interface EventHandler<TState, TName extends keyof ClientEventNameMapping> {\n handler: (event: ClientEventNameMapping[TName], setState: Dispatch<SetStateAction<TState>>) => void;\n}\n\nexport interface InteractionConfig<TState, TActions> {\n /** Initial state value */\n initialState: TState | (() => TState);\n /** Event handlers to register with the client API */\n eventHandlers?: {\n [TKey in keyof ClientEventNameMapping]?: EventHandler<TState, TKey>;\n };\n /** Action creators that return functions to interact with the client API */\n actions?: (state: TState, setState: Dispatch<SetStateAction<TState>>, clientApi: ClientApi | null) => TActions;\n}\n\n/**\n * Base hook that provides common interaction patterns for design-time functionality.\n * Reduces boilerplate by handling state management, event listeners, and cleanup.\n *\n * @param config - Configuration object defining the interaction behavior\n * @returns Object containing state and action methods\n */\nexport function useInteraction<\n TState,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n TActions extends Record<string, (...args: any[]) => any>,\n>(config: InteractionConfig<TState, TActions>): { state: TState } & TActions {\n const [state, setState] = useState<TState>(config.initialState);\n const { isDesignMode, clientApi } = useDesignContext();\n\n useEffect(() => {\n if (!isDesignMode || !clientApi) {\n return () => {\n // Return empty cleanup function for consistency\n };\n }\n\n const unsubscribeFunctions = Object.entries(config.eventHandlers ?? {}).map(([eventName, entry]) =>\n clientApi.on(eventName as keyof ClientEventNameMapping, (event) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n entry.handler(event as any, setState)\n )\n );\n\n return () => {\n unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n };\n }, [isDesignMode, clientApi, config.eventHandlers]);\n\n const actions = config.actions?.(state, setState, clientApi ?? null) ?? ({} as TActions);\n\n return { state, ...actions };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface SelectInteraction {\n selectedComponentId: string;\n setSelectedComponent: (componentId: string) => void;\n}\n\n/**\n * Custom hook that manages component selection state and handles\n * client-host communication for selection events.\n *\n * @param isDesignMode - Whether design mode is active\n * @param clientApi - Client API for host communication\n * @returns Selection state and interaction methods\n */\nexport function useSelectInteraction(): SelectInteraction {\n const { state: selectedComponentId, setSelectedComponent } = useInteraction({\n initialState: '',\n eventHandlers: {\n ComponentSelected: {\n handler: (event, setState) => {\n setState(event.componentId);\n },\n },\n ComponentDeselected: {\n handler: (_, setState) => {\n setState('');\n },\n },\n },\n actions: (_state, setState, clientApi) => ({\n setSelectedComponent: (componentId: string) => {\n setState(componentId);\n clientApi?.selectComponent({ componentId });\n },\n }),\n });\n\n return {\n selectedComponentId,\n setSelectedComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface HoverInteraction {\n hoveredComponentId: string | null;\n setHoveredComponent: (componentId: string | null) => void;\n}\n\n/**\n * Custom hook that manages component hover state and handles\n * client-host communication for hover events.\n *\n * @returns Hover state and interaction methods\n */\nexport function useHoverInteraction(): HoverInteraction {\n const { state: hoveredComponentId, setHoveredComponent } = useInteraction({\n initialState: null as string | null,\n eventHandlers: {\n ComponentHoveredIn: {\n handler: (event, setState) => setState(event.componentId),\n },\n ComponentHoveredOut: {\n handler: (_, setState) => setState(null),\n },\n },\n actions: (state, setState, clientApi) => ({\n setHoveredComponent: (componentId: string | null) => {\n if (state && componentId !== state) {\n // Use the current hovered component for hover out\n clientApi?.hoverOutOfComponent({\n componentId: state,\n });\n }\n\n if (componentId && componentId !== state) {\n clientApi?.hoverInToComponent({ componentId });\n }\n\n setState(componentId);\n },\n }),\n });\n\n return {\n hoveredComponentId,\n setHoveredComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\nimport type { ComponentDeletedEvent, EventPayload } from '../../messaging-api';\n\nexport interface DeleteInteraction {\n deleteComponent: (componentId: EventPayload<ComponentDeletedEvent>) => void;\n}\n\nexport function useDeleteInteraction({\n selectedComponentId,\n setSelectedComponent,\n}: {\n selectedComponentId: string | null;\n setSelectedComponent: (componentId: string) => void;\n}): DeleteInteraction {\n const { deleteComponent } = useInteraction({\n initialState: null,\n eventHandlers: {},\n actions: (_state, _setState, clientApi) => ({\n deleteComponent: (event: EventPayload<ComponentDeletedEvent>) => {\n clientApi?.deleteComponent(event);\n\n // When a component is deleted, we want to make sure it's no longer selected.\n if (selectedComponentId === event.componentId) {\n setSelectedComponent('');\n }\n },\n }),\n });\n\n return {\n deleteComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface FocusInteraction {\n focusedComponentId: string | null;\n focusComponent: (node: Element) => void;\n}\n\nexport function useFocusInteraction({\n setSelectedComponent,\n}: {\n setSelectedComponent: (componentId: string) => void;\n}): FocusInteraction {\n const { state: focusedComponentId, focusComponent } = useInteraction({\n initialState: null as string | null,\n eventHandlers: {\n ComponentFocused: {\n handler: (event, setState) => {\n setSelectedComponent('');\n setState(event.componentId);\n },\n },\n },\n actions: (_state, setState) => ({\n focusComponent: (node: Element) => {\n node.scrollIntoView();\n setState(null);\n },\n }),\n });\n\n return {\n focusedComponentId,\n focusComponent,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface ScrollInteraction {\n notifyWindowScrollChange: (x: number, y: number) => void;\n}\n\n/**\n * Custom hook that manages component hover state and handles\n * client-host communication for hover events.\n *\n * @returns Hover state and interaction methods\n */\nexport function useScrollInteraction(): ScrollInteraction {\n const { notifyWindowScrollChange } = useInteraction({\n initialState: null,\n eventHandlers: {\n WindowScrollChanged: {\n handler: (event) => {\n if (event.scrollY != null) {\n window.scrollTo({\n behavior: 'instant',\n top: event.scrollY,\n });\n }\n },\n },\n },\n actions: (_state, _setState, clientApi) => ({\n notifyWindowScrollChange: (x: number, y: number) => {\n clientApi?.notifyWindowScrollChanged({\n scrollX: x,\n scrollY: y,\n });\n },\n }),\n });\n\n return { notifyWindowScrollChange };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback } from 'react';\nimport type { NodeToTargetMapEntry } from '../context/DesignStateContext';\n\nexport type ComponentDiscoveryResult = NodeToTargetMapEntry & { node: Element };\n\n/**\n * Returns a utility for discovering components and regions at a given\n * x, y coordinates.\n * @param nodeToTargetMap - The map of nodes to target entries.\n */\nexport function useComponentDiscovery({\n nodeToTargetMap,\n}: {\n nodeToTargetMap: WeakMap<Element, NodeToTargetMapEntry>;\n}): (query: { x: number; y: number; filter?: (entry: NodeToTargetMapEntry) => boolean }) => ComponentDiscoveryResult[] {\n return useCallback(\n ({ x, y, filter = () => true }) => {\n const nodeStack = document.elementsFromPoint(x, y);\n const results: ComponentDiscoveryResult[] = [];\n\n for (let i = 0; i < nodeStack.length; i += 1) {\n const node = nodeStack[i];\n const entry = nodeToTargetMap.get(node);\n\n if (entry && filter(entry)) {\n results.push({ ...entry, node });\n }\n }\n\n return results;\n },\n [nodeToTargetMap]\n );\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Checks if a component type is allowed in a region based on inclusion and exclusion rules.\n *\n * @param componentType - The type of component being checked\n * @param componentTypeInclusions - Array of allowed component types (if empty, all types are allowed by default)\n * @param componentTypeExclusions - Array of forbidden component types\n * @returns true if the component type is allowed, false otherwise\n */\nexport function isComponentTypeAllowedInRegion(\n componentType: string | undefined,\n componentTypeInclusions: string[],\n componentTypeExclusions: string[]\n): boolean {\n if (!componentType) {\n return false;\n }\n\n if (componentTypeExclusions?.includes(componentType)) {\n return false;\n }\n\n // If there are inclusions specified, the component type must be in the list\n if (componentTypeInclusions?.length > 0) {\n return componentTypeInclusions.includes(componentType);\n }\n\n return true;\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { useInteraction } from './useInteraction';\nimport type { NodeToTargetMapEntry } from '../context/DesignStateContext';\nimport { useComponentDiscovery, type ComponentDiscoveryResult } from './useComponentDiscovery';\nimport { isComponentTypeAllowedInRegion } from '../utils/regionUtils';\n\n// The height of the scroll buffer on the top and bottom of the window\n// as a percentage of the window height.\nconst SCROLL_BUFFER_HEIGHT_PERCENTAGE = 15;\nconst SCROLL_BUFFER_MIN_HEIGHT_IN_PIXELS = 50;\n// The interval at which the window will scroll within the buffer.\n// More often means a smoother experience.\nconst SCROLL_INTERVAL_IN_MS = 1000 / 60; // 60fps\n// The multiplier applied to the scroll factor.\n// The scroll factor is a value between 0 and 1 that determines how much to scroll.\n// This value will be the maximum amount of pixels that will be scrolled in a single frame.\nconst SCROLL_BASE_AMOUNT_IN_PIXELS = 50;\n\ninterface InsertionType {\n axis: 'x' | 'y';\n type: 'before' | 'after';\n}\n\nexport interface DropTarget extends NodeToTargetMapEntry {\n beforeComponentId?: string;\n afterComponentId?: string;\n insertType: InsertionType;\n insertComponentId?: string;\n regionId: string;\n}\n\nexport interface DragInteraction {\n dragState: {\n isDragging: boolean;\n x: number;\n y: number;\n currentDropTarget: DropTarget | null;\n pendingTargetCommit: boolean;\n componentType?: string;\n sourceComponentId?: string;\n sourceRegionId?: string;\n rectCache: WeakMap<Element, DOMRect>;\n scrollDirection: 0 | 1 | -1;\n pendingComponentDragId: string | null;\n };\n commitCurrentDropTarget: () => void;\n startComponentMove: (componentId: string, regionId: string, componentType: string) => void;\n updateComponentMove: (params: { x: number; y: number }) => void;\n setPendingComponentDragId: (componentId: string) => void;\n dropComponent: () => void;\n cancelDrag: () => void;\n}\n\nfunction getInsertionType({\n cache,\n node,\n x,\n y,\n}: {\n cache: WeakMap<Element, DOMRect>;\n node: Element;\n x: number;\n y: number;\n}): InsertionType {\n if (!cache.has(node)) {\n const rect = node.getBoundingClientRect();\n const screenLeft = rect.left - window.scrollX;\n const screenTop = rect.top + window.scrollY;\n\n // A bounding box is relative to the viewport.\n // We need to know the absolute position, taking into account the scroll position.\n cache.set(node, new DOMRect(screenLeft, screenTop, rect.width, rect.height));\n }\n\n const rect = cache.get(node) as DOMRect;\n const screenX = x + window.scrollX;\n const screenY = y + window.scrollY;\n const midX = rect.left + rect.width / 2;\n const midY = rect.top + rect.height / 2;\n const deltaX = screenX - midX;\n const deltaY = screenY - midY;\n // Use the relative delta for boxes that are not square.\n const relativeDeltaX = deltaX / (rect.width / 2);\n const relativeDeltaY = deltaY / (rect.height / 2);\n\n if (Math.abs(relativeDeltaX) > Math.abs(relativeDeltaY)) {\n return { axis: 'x', type: relativeDeltaX < 0 ? 'before' : 'after' };\n }\n\n return { axis: 'y', type: relativeDeltaY < 0 ? 'before' : 'after' };\n}\n\n// Determines whether a source component is being dropped on itself.\nfunction isOnSelfDropTarget({\n sourceComponentId,\n beforeComponentId,\n afterComponentId,\n insertType,\n componentId,\n}: {\n sourceComponentId: string | undefined;\n beforeComponentId: string | undefined;\n afterComponentId: string | undefined;\n insertType: InsertionType;\n componentId: string;\n}) {\n const isOnSource = sourceComponentId && componentId === sourceComponentId;\n const isOnSameRegionBefore =\n sourceComponentId && insertType.type === 'before' && beforeComponentId === sourceComponentId;\n const isOnSameRegionAfter =\n sourceComponentId && insertType.type === 'after' && afterComponentId === sourceComponentId;\n\n return isOnSource || isOnSameRegionBefore || isOnSameRegionAfter;\n}\n\nexport function useDragInteraction({\n nodeToTargetMap,\n}: {\n nodeToTargetMap: WeakMap<Element, NodeToTargetMapEntry>;\n}): DragInteraction {\n const discoverComponents = useComponentDiscovery({\n nodeToTargetMap,\n });\n const getNearestComponentAndRegion = useCallback(\n (\n x: number,\n y: number\n ): {\n component: ComponentDiscoveryResult | null;\n region: ComponentDiscoveryResult | null;\n } => {\n const stack = discoverComponents({ x, y });\n let component: ComponentDiscoveryResult | null = null;\n let region: ComponentDiscoveryResult | null = null;\n\n for (let i = 0; i < stack.length; i += 1) {\n const entry = stack[i];\n\n // We need a region id and direction for this to be a target.\n if (entry.regionId) {\n if (entry.type === 'component') {\n component = entry;\n } else if (entry.type === 'region') {\n region = entry;\n // Once we find a region we need to exit.\n break;\n }\n }\n }\n\n return { component, region };\n },\n [discoverComponents]\n );\n\n const getInsertionComponentIds = (\n componentId: string,\n region: NodeToTargetMapEntry & { node: Element }\n ): [string | undefined, string | undefined] => {\n const componentIndex = region.componentIds.indexOf(componentId);\n\n return [region.componentIds[componentIndex - 1], region.componentIds[componentIndex + 1]];\n };\n\n const getCurrentDropTarget = useCallback(\n ({\n x,\n y,\n rectCache,\n componentType,\n }: {\n x: number;\n y: number;\n rectCache: WeakMap<Element, DOMRect>;\n componentType?: string;\n }): DropTarget | null => {\n const { component, region } = getNearestComponentAndRegion(x, y);\n\n if (region) {\n // If component type is not allowed, don't return a drop target\n if (\n !isComponentTypeAllowedInRegion(\n componentType,\n region.componentTypeInclusions || [],\n region.componentTypeExclusions || []\n )\n ) {\n return null;\n }\n\n const insertType: InsertionType = component\n ? getInsertionType({\n cache: rectCache,\n node: component.node,\n x,\n y,\n })\n : { axis: 'y', type: 'after' };\n\n const [beforeComponentId, afterComponentId] = component\n ? getInsertionComponentIds(component.componentId, region)\n : [];\n\n // If we find a component before a region, it means we are dropping over a component.\n // If no component is found before a region, it means we are dropping over an empty region.\n return {\n type: component ? 'component' : 'region',\n regionId: region.regionId,\n componentIds: region.componentIds,\n componentId: component?.componentId ?? '',\n parentId: region.parentId,\n beforeComponentId,\n afterComponentId,\n insertComponentId: component?.componentId,\n insertType,\n componentTypeInclusions: region.componentTypeInclusions,\n componentTypeExclusions: region.componentTypeExclusions,\n };\n }\n\n return null;\n },\n [getNearestComponentAndRegion]\n );\n\n const computeScrollFactor = ({ y, windowHeight }: { y: number; windowHeight: number }) => {\n const bufferHeight = Math.max(\n windowHeight * (SCROLL_BUFFER_HEIGHT_PERCENTAGE / 100),\n SCROLL_BUFFER_MIN_HEIGHT_IN_PIXELS\n );\n const bottomBufferStart = windowHeight - bufferHeight;\n\n if (y > bottomBufferStart) {\n return (y - bottomBufferStart) / bufferHeight;\n }\n\n if (y < bufferHeight) {\n return (y - bufferHeight) / bufferHeight;\n }\n\n return 0;\n };\n\n const computeScrollDirection = (factor: number): 0 | 1 | -1 => {\n if (factor > 0) {\n return 1;\n }\n\n if (factor < 0) {\n return -1;\n }\n\n return 0;\n };\n\n const scrollFactorRef = useRef(0);\n\n const {\n state: dragState,\n commitCurrentDropTarget,\n updateComponentMove,\n startComponentMove,\n dropComponent,\n cancelDrag,\n setPendingComponentDragId,\n } = useInteraction({\n initialState: {\n isDragging: false,\n componentType: '',\n sourceComponentId: undefined as string | undefined,\n sourceRegionId: undefined as string | undefined,\n x: 0,\n y: 0,\n currentDropTarget: null as DropTarget | null,\n pendingTargetCommit: false,\n rectCache: new WeakMap<Element, DOMRect>(),\n pendingComponentDragId: null,\n } as DragInteraction['dragState'],\n eventHandlers: {\n ComponentDragStarted: {\n handler: (event, setState) => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n componentType: event.componentType,\n sourceComponentId: undefined,\n sourceRegionId: undefined,\n x: 0,\n y: 0,\n isDragging: true,\n currentDropTarget: null,\n pendingTargetCommit: false,\n scrollDirection: 0,\n rectCache: new WeakMap<Element, DOMRect>(),\n }));\n },\n },\n ClientWindowDragExited: {\n handler: (_, setState) => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n componentType: '',\n x: 0,\n y: 0,\n isDragging: false,\n currentDropTarget: null,\n scrollDirection: 0,\n pendingTargetCommit: false,\n }));\n },\n },\n ClientWindowDragMoved: {\n handler: (event, setState) => {\n scrollFactorRef.current = computeScrollFactor({\n y: event.y,\n windowHeight: window.innerHeight,\n });\n\n setState((prevState) => ({\n ...prevState,\n x: event.x,\n y: event.y,\n isDragging: true,\n scrollDirection: computeScrollDirection(scrollFactorRef.current),\n currentDropTarget: getCurrentDropTarget({\n x: event.x,\n y: event.y,\n rectCache: dragState.rectCache,\n componentType: prevState.componentType,\n }),\n }));\n },\n },\n ClientWindowDragDropped: {\n handler: (_, setState) => {\n setState((prevState) => ({\n ...prevState,\n isDragging: false,\n pendingTargetCommit: true,\n }));\n },\n },\n },\n actions: (state, setState, clientApi) => ({\n cancelDrag: () => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n x: 0,\n y: 0,\n scrollDirection: 0,\n isDragging: false,\n pendingComponentDragId: null,\n }));\n },\n updateComponentMove: ({ x, y }: { x: number; y: number }) => {\n scrollFactorRef.current = computeScrollFactor({\n y,\n windowHeight: window.innerHeight,\n });\n\n setState((prevState) => ({\n ...prevState,\n x,\n y,\n scrollDirection: computeScrollDirection(scrollFactorRef.current),\n currentDropTarget: getCurrentDropTarget({\n x,\n y,\n rectCache: state.rectCache,\n componentType: state.componentType,\n }),\n }));\n },\n setPendingComponentDragId: (componentId: string) => {\n setState((prevState) => ({\n ...prevState,\n pendingComponentDragId: componentId,\n }));\n },\n dropComponent: () => {\n setState((prevState) => ({\n ...prevState,\n isDragging: false,\n pendingTargetCommit: true,\n }));\n },\n startComponentMove: (componentId: string, regionId: string, componentType: string) => {\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n x: 0,\n y: 0,\n componentType,\n sourceComponentId: componentId,\n sourceRegionId: regionId,\n isDragging: true,\n scrollDirection: 0,\n rectCache: new WeakMap<Element, DOMRect>(),\n }));\n },\n commitCurrentDropTarget: () => {\n // Don't do anything if we don't have a drop target.\n if (state.currentDropTarget) {\n // If we have a source component id, then we are moving a component to a different region.\n if (state.sourceComponentId) {\n if (\n !isOnSelfDropTarget({\n sourceComponentId: state.sourceComponentId,\n beforeComponentId: state.currentDropTarget.beforeComponentId,\n afterComponentId: state.currentDropTarget.afterComponentId,\n insertType: state.currentDropTarget.insertType,\n componentId: state.currentDropTarget.componentId,\n })\n ) {\n clientApi?.moveComponentToRegion({\n componentId: state.sourceComponentId,\n sourceRegionId: state.sourceRegionId ?? '',\n insertType: state.currentDropTarget.insertType?.type,\n insertComponentId: state.currentDropTarget.insertComponentId,\n beforeComponentId: state.currentDropTarget.beforeComponentId,\n afterComponentId: state.currentDropTarget.afterComponentId,\n targetRegionId: state.currentDropTarget.regionId,\n targetComponentId: state.currentDropTarget.parentId ?? '',\n });\n }\n // If we don't have a source component id, then we are adding a new component to a region.\n } else if (state.componentType) {\n clientApi?.addComponentToRegion({\n insertType: state.currentDropTarget.insertType?.type,\n insertComponentId: state.currentDropTarget.insertComponentId,\n componentProperties: {},\n componentType: state.componentType,\n targetComponentId: state.currentDropTarget.parentId ?? '',\n beforeComponentId: state.currentDropTarget.beforeComponentId,\n afterComponentId: state.currentDropTarget.afterComponentId,\n targetRegionId: state.currentDropTarget.regionId,\n });\n }\n }\n\n scrollFactorRef.current = 0;\n\n setState((prevState) => ({\n ...prevState,\n x: 0,\n y: 0,\n componentType: '',\n scrollDirection: 0,\n sourceComponentId: undefined,\n sourceRegionId: undefined,\n pendingComponentDragId: null,\n currentDropTarget: null,\n pendingTargetCommit: false,\n }));\n },\n }),\n });\n\n // Commits the current drop target if we are pending a target commit.\n useEffect(() => {\n if (dragState.pendingTargetCommit) {\n commitCurrentDropTarget();\n }\n }, [dragState.pendingTargetCommit, commitCurrentDropTarget]);\n\n // Starts scrolling the window when the drag state scroll factor is not 0.\n useEffect(() => {\n if (dragState.scrollDirection !== 0) {\n const interval = setInterval(() => {\n window.scrollBy(0, scrollFactorRef.current * SCROLL_BASE_AMOUNT_IN_PIXELS);\n }, SCROLL_INTERVAL_IN_MS);\n\n return () => clearInterval(interval);\n }\n\n return () => {\n // noop\n };\n }, [dragState.scrollDirection, scrollFactorRef]);\n\n return {\n dragState,\n setPendingComponentDragId,\n commitCurrentDropTarget,\n startComponentMove,\n updateComponentMove,\n dropComponent,\n cancelDrag,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useInteraction } from './useInteraction';\n\nexport interface ComponentUpdate {\n name?: string;\n [key: string]: unknown;\n}\n\nexport interface ComponentUpdateInteraction {\n componentUpdates: Record<string, ComponentUpdate>;\n}\n\n/**\n * Custom hook that manages component update state and handles\n * client-host communication for component update events.\n *\n * Listens for ComponentUpdated events from the host and maintains\n * a map of component IDs to their updated data.\n *\n * @returns Component update state\n */\nexport function useComponentUpdateInteraction(): ComponentUpdateInteraction {\n const { state: componentUpdates } = useInteraction<Record<string, ComponentUpdate>, Record<string, never>>({\n initialState: {},\n eventHandlers: {\n // Handle initial component names from page-init\n ClientAcknowledged: {\n handler: (event, setState) => {\n const initialUpdates: Record<string, ComponentUpdate> = {};\n Object.entries(event.components).forEach(([id, componentInfo]) => {\n if (componentInfo.name) {\n initialUpdates[id] = { name: componentInfo.name };\n }\n });\n // Merge to preserve ComponentUpdated changes\n if (Object.keys(initialUpdates).length > 0) {\n setState((prev) => ({ ...prev, ...initialUpdates }));\n }\n },\n },\n // Handle runtime component updates\n ComponentUpdated: {\n handler: (event, setState) => {\n setState((prev) => {\n const componentId = event.componentId;\n const existing = prev[componentId] || {};\n\n // Update the specific field based on changeType\n const updated = { ...existing };\n if (event.changeType === 'name') {\n updated.name = event.newValue as string;\n } else if (event.changeType === 'visibility') {\n updated.visibility = event.newValue;\n }\n\n return {\n ...prev,\n [componentId]: updated,\n };\n });\n },\n },\n },\n });\n\n return {\n componentUpdates,\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { useSelectInteraction } from '../hooks/useSelectInteraction';\nimport { useHoverInteraction } from '../hooks/useHoverInteraction';\nimport { useDeleteInteraction } from '../hooks/useDeleteInteraction';\nimport { useFocusInteraction } from '../hooks/useFocusInteraction';\nimport { useScrollInteraction, type ScrollInteraction } from '../hooks/useScrollInteraction';\nimport { useDragInteraction, type DragInteraction } from '../hooks/useDragInteraction';\nimport { useComponentUpdateInteraction, type ComponentUpdateInteraction } from '../hooks/useComponentUpdateInteraction';\nimport type { ComponentDeletedEvent, EventPayload } from '../../messaging-api';\n\nexport interface NodeToTargetMapEntry {\n type: 'region' | 'component';\n parentId?: string;\n componentId: string;\n regionId: string;\n componentIds: string[];\n componentTypeInclusions?: string[];\n componentTypeExclusions?: string[];\n}\n\nexport interface DesignState extends DragInteraction, ScrollInteraction, ComponentUpdateInteraction {\n selectedComponentId: string | null;\n hoveredComponentId: string | null;\n setSelectedComponent: (componentId: string) => void;\n setHoveredComponent: (componentId: string | null) => void;\n deleteComponent: (event: EventPayload<ComponentDeletedEvent>) => void;\n focusComponent: (node: Element) => void;\n focusedComponentId: string | null;\n nodeToTargetMap: WeakMap<Element, NodeToTargetMapEntry>;\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const DesignStateContext = React.createContext<DesignState>(null as unknown as DesignState);\n\nexport const DesignStateProvider = ({ children }: { children: React.ReactNode }): React.JSX.Element => {\n const selectInteraction = useSelectInteraction();\n const hoverInteraction = useHoverInteraction();\n const deleteInteraction = useDeleteInteraction({\n selectedComponentId: selectInteraction.selectedComponentId,\n setSelectedComponent: selectInteraction.setSelectedComponent,\n });\n const focusInteraction = useFocusInteraction({\n setSelectedComponent: selectInteraction.setSelectedComponent,\n });\n const scrollInteraction = useScrollInteraction();\n const componentUpdateInteraction = useComponentUpdateInteraction();\n const nodeToTargetMap = React.useMemo(() => new WeakMap(), []);\n const dragInteraction = useDragInteraction({ nodeToTargetMap });\n\n const state = React.useMemo(\n () => ({\n ...deleteInteraction,\n ...selectInteraction,\n ...hoverInteraction,\n ...focusInteraction,\n ...dragInteraction,\n ...scrollInteraction,\n ...componentUpdateInteraction,\n nodeToTargetMap,\n }),\n [\n deleteInteraction,\n selectInteraction,\n hoverInteraction,\n focusInteraction,\n dragInteraction,\n nodeToTargetMap,\n scrollInteraction,\n componentUpdateInteraction,\n ]\n );\n\n return <DesignStateContext.Provider value={state}>{children}</DesignStateContext.Provider>;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { DesignStateContext, type DesignState } from '../context/DesignStateContext';\n\n/**\n * Custom hook that manages design-time component state by composing\n * individual interaction hooks for better maintainability and testability.\n *\n * @returns Combined design state from all interactions\n */\nexport const useDesignState = (): DesignState => {\n const context = React.useContext(DesignStateContext);\n\n if (!context) {\n throw new Error('useDesignState must be used within a DesignStateProvider');\n }\n\n return context;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useRef, useCallback } from 'react';\n\nexport function useThrottledCallback<TArgs extends unknown[], TReturn>(\n callback: (...args: TArgs) => TReturn,\n interval: number,\n deps: unknown[] = []\n): (...args: TArgs) => TReturn | void {\n const lastCallTime = useRef<number>(0);\n\n return useCallback(\n (...args: TArgs): TReturn | void => {\n const now = Date.now();\n\n if (now >= lastCallTime.current + interval) {\n lastCallTime.current = now;\n\n callback(...args);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [callback, interval, ...deps]\n );\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useRef, useCallback } from 'react';\n\nexport function useDebouncedCallback<TArgs extends unknown[], TReturn>(\n callback: (...args: TArgs) => TReturn,\n interval: number,\n deps: unknown[] = []\n): (...args: TArgs) => TReturn | void {\n const timeoutRef = useRef<number | null>(null);\n\n return useCallback(\n (...args: TArgs): TReturn | void => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n\n timeoutRef.current = setTimeout(() => {\n callback(...args);\n timeoutRef.current = null;\n }, interval) as unknown as number;\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [callback, interval, ...deps]\n );\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect } from 'react';\nimport { useDesignState } from './useDesignState';\nimport { useThrottledCallback } from './useThrottledCallback';\nimport { useDebouncedCallback } from './useDebouncedCallback';\n\nconst FPS_60 = 1000 / 60;\n\nexport function useGlobalListeners(): void {\n const { dropComponent, updateComponentMove, cancelDrag, notifyWindowScrollChange } = useDesignState();\n const dragListener = useThrottledCallback(\n (event: DragEvent) => updateComponentMove({ x: event.clientX, y: event.clientY }),\n FPS_60,\n [updateComponentMove]\n );\n const scrollListener = useDebouncedCallback(() => notifyWindowScrollChange(window.scrollX, window.scrollY), 100, [\n notifyWindowScrollChange,\n ]);\n\n useEffect(() => {\n const dragEndListener = () => dropComponent();\n const mouseUpListener = () => cancelDrag();\n\n window.addEventListener('dragover', dragListener);\n window.addEventListener('dragend', dragEndListener);\n window.addEventListener('scroll', scrollListener);\n // We need to make sure we cancel dragging on mouseup since we\n // we are using mousedown to start dragging or else it would stay in a dragging\n // state from regular click events.\n window.addEventListener('mouseup', mouseUpListener);\n\n return () => {\n window.removeEventListener('dragover', dragListener);\n window.removeEventListener('dragend', dragEndListener);\n window.removeEventListener('mouseup', mouseUpListener);\n window.removeEventListener('scroll', scrollListener);\n };\n }, [dropComponent, cancelDrag, dragListener, scrollListener]);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect } from 'react';\n\n/**\n * React hook that prevents all <a> (anchor) navigation by default in the document,\n * unless the anchor has the attribute `data-pd-allow-link`.\n */\nexport function useGlobalAnchorBlock(): void {\n useEffect(() => {\n function preventAnchorClicks(event: MouseEvent) {\n const target = event.target as HTMLElement;\n const anchor = target.closest('a');\n\n // This data attribute acts as a workaround in the event we do\n // want to have an anchor tag navigate in design mode.\n if (anchor && !anchor.hasAttribute('data-pd-allow-link')) {\n event.preventDefault();\n }\n }\n\n document.addEventListener('click', preventAnchorClicks);\n\n return () => document.removeEventListener('click', preventAnchorClicks);\n }, []);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useGlobalListeners } from '../hooks/useGlobalListeners';\nimport { useGlobalAnchorBlock } from '../hooks/useGlobalAnchorBlock';\n\n/**\n * Containes any global setup logic for the design layer.\n */\nexport const DesignApp = ({ children }: React.PropsWithChildren<unknown>): React.JSX.Element => {\n useGlobalListeners();\n useGlobalAnchorBlock();\n\n return <>{children}</>;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport {\n createClientApi,\n type ClientApi,\n type IsomorphicConfiguration,\n type ClientAcknowledgedEvent,\n type EventPayload,\n type HostToClientConfiguration,\n} from '../../messaging-api';\nimport type { ShopperExperience } from '@/scapi-client/types';\nimport { DesignStateProvider } from './DesignStateContext';\nimport { DesignApp } from '../components/DesignApp';\nimport { usePageDesignerMode } from '../core/PageDesignerProvider';\n\nconst noop = () => {\n /* noop */\n};\n\n/**\n * Type definition for the Design Context\n * Extends DesignState with additional design-time properties\n */\nexport interface DesignContextType {\n /** Whether design mode is currently active */\n isDesignMode: boolean;\n /** Client API for host communication */\n clientApi?: ClientApi;\n /** Whether the client is connected to the host */\n isConnected: boolean;\n /** The page designer config */\n pageDesignerConfig: EventPayload<ClientAcknowledgedEvent> | null;\n /** Page data that the client has retrieved */\n clientPage: ShopperExperience.schemas['Page'] | null;\n /** Sets the client page data */\n setClientPage: (page: ShopperExperience.schemas['Page']) => void;\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const DesignContext = React.createContext<DesignContextType>({\n isDesignMode: false,\n isConnected: false,\n pageDesignerConfig: null,\n clientPage: null,\n setClientPage: noop,\n});\n\n/**\n * Provider component that enables design-time functionality for child components.\n * Sets up client-host communication and manages component selection state.\n *\n * @param children - Child components to wrap with design functionality\n * @param targetOrigin - Target origin for postMessage communication\n * @param clientId - Id for the client API\n * @returns JSX element wrapping children with design context\n */\nexport const DesignProvider = ({\n children,\n targetOrigin,\n clientId,\n usid,\n clientConnectionTimeout,\n clientConnectionInterval,\n clientLogger = noop,\n}: React.PropsWithChildren<{\n targetOrigin: string;\n clientId: string;\n usid?: string;\n clientConnectionTimeout?: number;\n clientConnectionInterval?: number;\n clientLogger?: IsomorphicConfiguration['logger'];\n}>): React.JSX.Element => {\n const { isDesignMode } = usePageDesignerMode();\n const [isConnected, setIsConnected] = React.useState(false);\n const [pageDesignerConfig, setPageDesignerConfig] = React.useState<HostToClientConfiguration | null>(null);\n const [clientPage, setClientPage] = React.useState<ShopperExperience.schemas['Page'] | null>(null);\n const clientPageRef = React.useRef<ShopperExperience.schemas['Page'] | null>(null);\n\n const clientApi = React.useMemo(\n () =>\n createClientApi({\n logger: clientLogger,\n emitter: {\n postMessage: (message) => window.parent.postMessage(message, targetOrigin),\n addEventListener: (handler) => {\n const listener = (event: MessageEvent) => handler(event.data);\n\n window.addEventListener('message', listener);\n\n return () => window.removeEventListener('message', listener);\n },\n },\n id: clientId,\n }),\n [targetOrigin, clientId, clientLogger]\n );\n\n React.useEffect(() => {\n // This will poll the host for a connection until the client is acknowledged.\n clientApi.connect({\n timeout: clientConnectionTimeout,\n interval: clientConnectionInterval,\n onHostConnected: (event) => {\n setPageDesignerConfig(event);\n setIsConnected(true);\n },\n onHostDisconnected: (reconnect) => {\n setPageDesignerConfig(null);\n setIsConnected(false);\n reconnect();\n },\n onError: () => {\n // TODO: Figure out how to handle this.\n },\n usid,\n });\n\n return () => {\n clientApi.disconnect();\n setPageDesignerConfig(null);\n setIsConnected(false);\n };\n }, [clientApi, clientConnectionTimeout, clientConnectionInterval, usid]);\n\n // Use the extracted state management hook\n const contextValue = React.useMemo<DesignContextType>(\n () => ({\n isDesignMode,\n clientApi,\n isConnected,\n pageDesignerConfig,\n clientPage,\n setClientPage: (page: ShopperExperience.schemas['Page']) => {\n if (page !== clientPageRef.current) {\n clientPageRef.current = page;\n setClientPage(page);\n clientApi?.notifyClientPageChanged({ page });\n }\n },\n }),\n [isDesignMode, clientApi, isConnected, pageDesignerConfig, clientPage, setClientPage]\n );\n\n return (\n <DesignContext.Provider value={contextValue}>\n <DesignStateProvider>\n <DesignApp>{children}</DesignApp>\n </DesignStateProvider>\n </DesignContext.Provider>\n );\n};\n\nDesignProvider.defaultProps = {\n clientLogger: noop,\n clientConnectionTimeout: 60_000,\n clientConnectionInterval: 1_000,\n};\n\n/**\n * Custom hook to access the design context\n * Provides access to design mode state and component selection functionality\n *\n * @returns The current design context\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport const useDesignContext = (): DesignContextType => React.useContext(DesignContext);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { i as useDesignState, r as useDesignContext } from "./DesignContext.js";
1
+ import { a as useDesignState, r as useDesignContext } from "./DesignContext.js";
2
2
  import React from "react";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
 
@@ -1,5 +1,5 @@
1
1
  import "./messaging-api.js";
2
- import { a as isComponentTypeAllowedInRegion, i as useDesignState } from "./DesignContext.js";
2
+ import { a as useDesignState, o as isComponentTypeAllowedInRegion } from "./DesignContext.js";
3
3
  import "./modeDetection.js";
4
4
  import "./PageDesignerProvider.js";
5
5
  import { n as useComponentContext, r as RegionContext } from "./ComponentContext.js";
package/dist/config.d.ts CHANGED
@@ -2,8 +2,8 @@ import { n as Site, r as Url, t as Locale } from "./types.js";
2
2
  import { n as DefineConfigOptions, r as defineConfig, t as BaseConfig } from "./schema.js";
3
3
  import * as react0 from "react";
4
4
  import { ReactNode } from "react";
5
- import * as react_jsx_runtime2 from "react/jsx-runtime";
6
- import * as react_router2 from "react-router";
5
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
6
+ import * as react_router9 from "react-router";
7
7
  import { MiddlewareFunction, RouterContextProvider } from "react-router";
8
8
 
9
9
  //#region src/config/get-config.d.ts
@@ -39,7 +39,7 @@ declare function useConfig<T extends Record<string, unknown> = Record<string, un
39
39
  * Populated by `createAppConfigMiddleware` with the `app` section of config.
40
40
  * Accessible in loaders, actions, and middleware via `context.get(appConfigContext)`.
41
41
  */
42
- declare const appConfigContext: react_router2.RouterContext<Record<string, unknown>>;
42
+ declare const appConfigContext: react_router9.RouterContext<Record<string, unknown>>;
43
43
  /**
44
44
  * React context for application configuration.
45
45
  *
@@ -67,7 +67,7 @@ interface ConfigProviderProps {
67
67
  declare function ConfigProvider({
68
68
  config,
69
69
  children
70
- }: ConfigProviderProps): react_jsx_runtime2.JSX.Element;
70
+ }: ConfigProviderProps): react_jsx_runtime0.JSX.Element;
71
71
  //#endregion
72
72
  //#region src/config/middleware.d.ts
73
73
  /**
@@ -0,0 +1,20 @@
1
+ import * as react_router3 from "react-router";
2
+ import { RouterContextProvider } from "react-router";
3
+
4
+ //#region src/data-store/middleware/custom-global-preferences.d.ts
5
+
6
+ type CustomGlobalPreferences = Record<string, unknown>;
7
+ declare const DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY = "custom-global-preferences";
8
+ declare const customGlobalPreferencesContext: react_router3.RouterContext<CustomGlobalPreferences | null>;
9
+ /**
10
+ * Read custom global preferences from router context.
11
+ *
12
+ * @param context - Router context provider
13
+ * @returns Custom global preferences data stored by data-store middleware
14
+ * @throws Error when the data-store context is not available
15
+ */
16
+ declare function getCustomGlobalPreferences(context: Readonly<RouterContextProvider>): CustomGlobalPreferences;
17
+ declare const customGlobalPreferencesMiddleware: react_router3.MiddlewareFunction<Response>;
18
+ //#endregion
19
+ export { getCustomGlobalPreferences as a, customGlobalPreferencesMiddleware as i, DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY as n, customGlobalPreferencesContext as r, CustomGlobalPreferences as t };
20
+ //# sourceMappingURL=custom-global-preferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-global-preferences.d.ts","names":[],"sources":["../src/data-store/middleware/custom-global-preferences.ts"],"sourcesContent":[],"mappings":";;;;;KAmBY,uBAAA,GAA0B;cAEzB,qCAAA;cACA,gCAA8B,aAAA,CAAA,cAAA;;;;;;;;iBAS3B,0BAAA,UAAoC,SAAS,yBAAyB;cAYzE,mCAAiC,aAAA,CAAA,mBAAA"}
@@ -0,0 +1,28 @@
1
+ import { n as createDataStoreMiddleware, t as createDataStoreContext } from "./utils.js";
2
+
3
+ //#region src/data-store/middleware/custom-global-preferences.ts
4
+ const DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY = "custom-global-preferences";
5
+ const customGlobalPreferencesContext = createDataStoreContext();
6
+ /**
7
+ * Read custom global preferences from router context.
8
+ *
9
+ * @param context - Router context provider
10
+ * @returns Custom global preferences data stored by data-store middleware
11
+ * @throws Error when the data-store context is not available
12
+ */
13
+ function getCustomGlobalPreferences(context) {
14
+ const data = context.get(customGlobalPreferencesContext);
15
+ if (!data) {
16
+ console.warn("Custom global preferences context not found. Ensure data-store middleware runs before loaders and the required env vars are set.");
17
+ return {};
18
+ }
19
+ return data;
20
+ }
21
+ const customGlobalPreferencesMiddleware = createDataStoreMiddleware({
22
+ entryKey: DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY,
23
+ context: customGlobalPreferencesContext
24
+ });
25
+
26
+ //#endregion
27
+ export { getCustomGlobalPreferences as i, customGlobalPreferencesContext as n, customGlobalPreferencesMiddleware as r, DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY as t };
28
+ //# sourceMappingURL=custom-global-preferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-global-preferences.js","names":[],"sources":["../src/data-store/middleware/custom-global-preferences.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { RouterContextProvider } from 'react-router';\nimport { createDataStoreContext, createDataStoreMiddleware } from '../utils';\n\nexport type CustomGlobalPreferences = Record<string, unknown>;\n\nexport const DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY = 'custom-global-preferences';\nexport const customGlobalPreferencesContext = createDataStoreContext<CustomGlobalPreferences>();\n\n/**\n * Read custom global preferences from router context.\n *\n * @param context - Router context provider\n * @returns Custom global preferences data stored by data-store middleware\n * @throws Error when the data-store context is not available\n */\nexport function getCustomGlobalPreferences(context: Readonly<RouterContextProvider>): CustomGlobalPreferences {\n const data = context.get(customGlobalPreferencesContext);\n if (!data) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Custom global preferences context not found. Ensure data-store middleware runs before loaders and the required env vars are set.'\n );\n return {};\n }\n return data;\n}\n\nexport const customGlobalPreferencesMiddleware = createDataStoreMiddleware({\n entryKey: DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY,\n context: customGlobalPreferencesContext,\n});\n"],"mappings":";;;AAqBA,MAAa,wCAAwC;AACrD,MAAa,iCAAiC,wBAAiD;;;;;;;;AAS/F,SAAgB,2BAA2B,SAAmE;CAC1G,MAAM,OAAO,QAAQ,IAAI,+BAA+B;AACxD,KAAI,CAAC,MAAM;AAEP,UAAQ,KACJ,mIACH;AACD,SAAO,EAAE;;AAEb,QAAO;;AAGX,MAAa,oCAAoC,0BAA0B;CACvE,UAAU;CACV,SAAS;CACZ,CAAC"}
@@ -0,0 +1,20 @@
1
+ import * as react_router0 from "react-router";
2
+ import { RouterContextProvider } from "react-router";
3
+
4
+ //#region src/data-store/middleware/custom-site-preferences.d.ts
5
+
6
+ type SitePreferences = Record<string, unknown>;
7
+ declare const DEFAULT_SITE_PREFERENCES_KEY = "site-preferences";
8
+ declare const sitePreferencesContext: react_router0.RouterContext<SitePreferences | null>;
9
+ /**
10
+ * Read site preferences from router context.
11
+ *
12
+ * @param context - Router context provider
13
+ * @returns Site preferences data stored by data-store middleware
14
+ * @throws Error when the data-store context is not available
15
+ */
16
+ declare function getSitePreferences(context: Readonly<RouterContextProvider>): SitePreferences;
17
+ declare const customSitePreferencesMiddleware: react_router0.MiddlewareFunction<Response>;
18
+ //#endregion
19
+ export { sitePreferencesContext as a, getSitePreferences as i, SitePreferences as n, customSitePreferencesMiddleware as r, DEFAULT_SITE_PREFERENCES_KEY as t };
20
+ //# sourceMappingURL=custom-site-preferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-site-preferences.d.ts","names":[],"sources":["../src/data-store/middleware/custom-site-preferences.ts"],"sourcesContent":[],"mappings":";;;;;KAmBY,eAAA,GAAkB;cAEjB,4BAAA;cACA,wBAAsB,aAAA,CAAA,cAAA;;;;;;;;iBASnB,kBAAA,UAA4B,SAAS,yBAAyB;cAYjE,iCAA+B,aAAA,CAAA,mBAAA"}
@@ -0,0 +1,28 @@
1
+ import { n as createDataStoreMiddleware, r as prefixWithSiteId, t as createDataStoreContext } from "./utils.js";
2
+
3
+ //#region src/data-store/middleware/custom-site-preferences.ts
4
+ const DEFAULT_SITE_PREFERENCES_KEY = "site-preferences";
5
+ const sitePreferencesContext = createDataStoreContext();
6
+ /**
7
+ * Read site preferences from router context.
8
+ *
9
+ * @param context - Router context provider
10
+ * @returns Site preferences data stored by data-store middleware
11
+ * @throws Error when the data-store context is not available
12
+ */
13
+ function getSitePreferences(context) {
14
+ const data = context.get(sitePreferencesContext);
15
+ if (!data) {
16
+ console.warn("Data store context not found. Ensure data-store middleware runs before loaders and the required env vars are set.");
17
+ return {};
18
+ }
19
+ return data;
20
+ }
21
+ const customSitePreferencesMiddleware = createDataStoreMiddleware({
22
+ entryKey: prefixWithSiteId("custom-site-preferences"),
23
+ context: sitePreferencesContext
24
+ });
25
+
26
+ //#endregion
27
+ export { sitePreferencesContext as i, customSitePreferencesMiddleware as n, getSitePreferences as r, DEFAULT_SITE_PREFERENCES_KEY as t };
28
+ //# sourceMappingURL=custom-site-preferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-site-preferences.js","names":[],"sources":["../src/data-store/middleware/custom-site-preferences.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { RouterContextProvider } from 'react-router';\nimport { createDataStoreContext, createDataStoreMiddleware, prefixWithSiteId } from '../utils';\n\nexport type SitePreferences = Record<string, unknown>;\n\nexport const DEFAULT_SITE_PREFERENCES_KEY = 'site-preferences';\nexport const sitePreferencesContext = createDataStoreContext<SitePreferences>();\n\n/**\n * Read site preferences from router context.\n *\n * @param context - Router context provider\n * @returns Site preferences data stored by data-store middleware\n * @throws Error when the data-store context is not available\n */\nexport function getSitePreferences(context: Readonly<RouterContextProvider>): SitePreferences {\n const data = context.get(sitePreferencesContext);\n if (!data) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Data store context not found. Ensure data-store middleware runs before loaders and the required env vars are set.'\n );\n return {};\n }\n return data;\n}\n\nexport const customSitePreferencesMiddleware = createDataStoreMiddleware({\n entryKey: prefixWithSiteId('custom-site-preferences'),\n context: sitePreferencesContext,\n});\n"],"mappings":";;;AAqBA,MAAa,+BAA+B;AAC5C,MAAa,yBAAyB,wBAAyC;;;;;;;;AAS/E,SAAgB,mBAAmB,SAA2D;CAC1F,MAAM,OAAO,QAAQ,IAAI,uBAAuB;AAChD,KAAI,CAAC,MAAM;AAEP,UAAQ,KACJ,oHACH;AACD,SAAO,EAAE;;AAEb,QAAO;;AAGX,MAAa,kCAAkC,0BAA0B;CACrE,UAAU,iBAAiB,0BAA0B;CACrD,SAAS;CACZ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { a as getCustomGlobalPreferences, i as customGlobalPreferencesMiddleware, n as DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY, r as customGlobalPreferencesContext, t as CustomGlobalPreferences } from "./custom-global-preferences.js";
2
+ export { CustomGlobalPreferences, DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY, customGlobalPreferencesContext, customGlobalPreferencesMiddleware, getCustomGlobalPreferences };
@@ -0,0 +1,6 @@
1
+ import "./utils.js";
2
+ import "./site-context2.js";
3
+ import "./apply-url-config.js";
4
+ import { i as getCustomGlobalPreferences, n as customGlobalPreferencesContext, r as customGlobalPreferencesMiddleware, t as DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY } from "./custom-global-preferences.js";
5
+
6
+ export { DEFAULT_CUSTOM_GLOBAL_PREFERENCES_KEY, customGlobalPreferencesContext, customGlobalPreferencesMiddleware, getCustomGlobalPreferences };
@@ -0,0 +1,2 @@
1
+ import { a as sitePreferencesContext, i as getSitePreferences, n as SitePreferences, r as customSitePreferencesMiddleware, t as DEFAULT_SITE_PREFERENCES_KEY } from "./custom-site-preferences.js";
2
+ export { DEFAULT_SITE_PREFERENCES_KEY, SitePreferences, customSitePreferencesMiddleware, getSitePreferences, sitePreferencesContext };
@@ -0,0 +1,6 @@
1
+ import "./utils.js";
2
+ import "./site-context2.js";
3
+ import "./apply-url-config.js";
4
+ import { i as sitePreferencesContext, n as customSitePreferencesMiddleware, r as getSitePreferences, t as DEFAULT_SITE_PREFERENCES_KEY } from "./custom-site-preferences.js";
5
+
6
+ export { DEFAULT_SITE_PREFERENCES_KEY, customSitePreferencesMiddleware, getSitePreferences, sitePreferencesContext };
@@ -0,0 +1,2 @@
1
+ import { a as getGcpApiKey, i as gcpPreferencesMiddleware, n as GcpPreferences, o as getGcpPreferences, r as gcpPreferencesContext, t as DEFAULT_GCP_PREFERENCES_KEY } from "./gcp-preferences.js";
2
+ export { DEFAULT_GCP_PREFERENCES_KEY, GcpPreferences, gcpPreferencesContext, gcpPreferencesMiddleware, getGcpApiKey, getGcpPreferences };
@@ -0,0 +1,6 @@
1
+ import "./utils.js";
2
+ import "./site-context2.js";
3
+ import "./apply-url-config.js";
4
+ import { a as getGcpPreferences, i as getGcpApiKey, n as gcpPreferencesContext, r as gcpPreferencesMiddleware, t as DEFAULT_GCP_PREFERENCES_KEY } from "./gcp-preferences.js";
5
+
6
+ export { DEFAULT_GCP_PREFERENCES_KEY, gcpPreferencesContext, gcpPreferencesMiddleware, getGcpApiKey, getGcpPreferences };