@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
package/README.md CHANGED
@@ -46,6 +46,88 @@ Entry point for React Page Designer integration. Exports only the minimal set of
46
46
 
47
47
  CSS stylesheet containing design layer styles for Page Designer integration. Provides visual overlays, selection indicators, and design-time UI elements. Can be imported and consumed in various ways depending on your bundler configuration and build setup.
48
48
 
49
+ ### `/data-store` MRT Data Store Access
50
+
51
+ Utilities and middleware for reading scoped entries from the MRT data access layer. This module intentionally exposes only key-specific helpers (initially site preferences).
52
+
53
+ **Environment Variables:**
54
+
55
+ - `AWS_REGION` (required): AWS region for the data store table (e.g., `us-east-1`)
56
+ - `MOBIFY_PROPERTY_ID` (required): MRT property identifier (e.g., `abcd1234`)
57
+ - `DEPLOY_TARGET` (required): MRT deploy target (e.g., `production`)
58
+
59
+ These are managed by Managed Runtime and are not typically set by SDK consumers directly.
60
+
61
+ **Provider Selection:**
62
+
63
+ The runtime auto-selects the MRT provider when all MRT environment variables are present.
64
+ If any are missing, it loads a local provider from `@salesforce/storefront-next-dev` in
65
+ development or when explicitly allowed.
66
+
67
+ Local provider opt-in outside development:
68
+
69
+ - `SFNEXT_DATA_STORE_ALLOW_LOCAL` (optional): set to `true` to allow local provider
70
+ - `CI` (optional): when set to `true`, allows the local provider
71
+
72
+ Local provider environment variables (development only):
73
+
74
+ - `SFNEXT_DATA_STORE_DEFAULTS` (optional): JSON map of keys to preference objects
75
+ - `SFNEXT_DATA_STORE_WARN_ON_MISSING` (optional): set to `false` to silence warnings
76
+
77
+ **Example Usage:**
78
+
79
+ ```typescript
80
+ import { customSitePreferencesMiddleware, getSitePreferences } from '@salesforce/storefront-next-runtime/data-store';
81
+
82
+ export const middleware = [
83
+ // Must run after the multi-site middleware to resolve site-specific keys.
84
+ customSitePreferencesMiddleware,
85
+ // ...other middleware
86
+ ];
87
+
88
+ export const loader = ({ context }) => {
89
+ const sitePreferences = getSitePreferences(context);
90
+ return { sitePreferences };
91
+ };
92
+ ```
93
+
94
+ **Custom Middleware Usage:**
95
+
96
+ If you want to read a different key or apply a custom transform, you can build your own
97
+ middleware with `createDataStoreMiddleware` and `createDataStoreContext`.
98
+
99
+ ```typescript
100
+ import {
101
+ createDataStoreContext,
102
+ createDataStoreMiddleware,
103
+ } from '@salesforce/storefront-next-runtime/data-store';
104
+
105
+ type CustomPreferences = {
106
+ featureFlags: Record<string, boolean>;
107
+ };
108
+
109
+ export const customPreferencesContext = createDataStoreContext<CustomPreferences>();
110
+
111
+ export const customPreferencesMiddleware = createDataStoreMiddleware({
112
+ entryKey: 'custom-preferences',
113
+ context: customPreferencesContext,
114
+ transform: (value) => ({
115
+ featureFlags: value.featureFlags as Record<string, boolean>,
116
+ }),
117
+ });
118
+
119
+ export const loader = ({ context }) => {
120
+ const customPreferences = context.get(customPreferencesContext);
121
+ return { customPreferences };
122
+ };
123
+ ```
124
+
125
+ The site preferences middleware reads data from a site-scoped key in the data store using this format:
126
+
127
+ ```
128
+ <siteid>-custom-site-preferences
129
+ ```
130
+
49
131
  ### `/scapi-client` SCAPI Client
50
132
 
51
133
  Type-safe, auto-generated API clients for Salesforce Commerce APIs with operation-based method names.
@@ -1,5 +1,5 @@
1
1
  import "./messaging-api.js";
2
- import { i as useDesignState, o as useComponentDiscovery } from "./DesignContext.js";
2
+ import { a as useDesignState, i as useThrottledCallback, r as useDesignContext, s as useComponentDiscovery } from "./DesignContext.js";
3
3
  import "./modeDetection.js";
4
4
  import "./PageDesignerProvider.js";
5
5
  import { i as useRegionContext, n as useComponentContext, t as ComponentContext } from "./ComponentContext.js";
@@ -48,6 +48,27 @@ function useFocusedComponentHandler(componentId, nodeRef) {
48
48
  ]);
49
49
  }
50
50
 
51
+ //#endregion
52
+ //#region src/design/react/hooks/useComponentInfo.ts
53
+ /**
54
+ * Hook that returns the current ComponentInfo for a given component ID,
55
+ * merging the base config with any runtime updates.
56
+ *
57
+ * @param componentId - The ID of the component to get info for
58
+ * @returns The merged ComponentInfo or null if the component doesn't exist
59
+ */
60
+ function useComponentInfo(componentId) {
61
+ const { pageDesignerConfig } = useDesignContext();
62
+ const { componentUpdates } = useDesignState();
63
+ const baseComponentInfo = pageDesignerConfig?.components?.[componentId];
64
+ const updates = componentUpdates?.[componentId] ?? {};
65
+ if (!baseComponentInfo) return null;
66
+ return {
67
+ ...baseComponentInfo,
68
+ ...updates
69
+ };
70
+ }
71
+
51
72
  //#endregion
52
73
  //#region src/design/react/components/DesignComponent.tsx
53
74
  function DesignComponent(props) {
@@ -55,11 +76,12 @@ function DesignComponent(props) {
55
76
  const { id = "", name, isFragment = false, isVisible = true, isLocalized = false } = designMetadata ?? {};
56
77
  const componentId = id;
57
78
  const componentType = useComponentType(componentId);
58
- const componentName = componentType?.label || name || "Component";
79
+ const componentInfo = useComponentInfo(componentId);
80
+ const { nodeToTargetMap } = useDesignState();
81
+ const componentName = componentInfo?.name || componentType?.label || name || "Component";
59
82
  const dragRef = useRef(null);
60
83
  const { regionId } = useRegionContext() ?? {};
61
84
  const { componentId: parentComponentId } = useComponentContext() ?? {};
62
- const { nodeToTargetMap } = useDesignState();
63
85
  const { selectedComponentId, hoveredComponentId, setSelectedComponent, setHoveredComponent, startComponentMove, setPendingComponentDragId, dragState: { pendingComponentDragId, isDragging, sourceComponentId: draggingSourceComponentId } } = useDesignState();
64
86
  useFocusedComponentHandler(componentId, dragRef);
65
87
  useNodeToTargetStore({
@@ -71,18 +93,21 @@ function DesignComponent(props) {
71
93
  });
72
94
  const discoverComponents = useComponentDiscovery({ nodeToTargetMap });
73
95
  const isPendingDrag = pendingComponentDragId === componentId;
74
- const handleMouseEnter = useCallback((event) => {
75
- event.stopPropagation();
76
- setHoveredComponent(componentId);
77
- }, [setHoveredComponent, componentId]);
78
- const handleMouseLeave = useCallback((event) => {
79
- event.stopPropagation();
96
+ const findAndSetHoveredComponent = useCallback((x, y) => {
80
97
  setHoveredComponent(discoverComponents({
81
- x: event.clientX,
82
- y: event.clientY,
98
+ x,
99
+ y,
83
100
  filter: (entry) => entry.type === "component"
84
101
  })[0]?.componentId ?? null);
85
102
  }, [setHoveredComponent, discoverComponents]);
103
+ const handleMouseMove = useThrottledCallback((event) => {
104
+ event.stopPropagation();
105
+ findAndSetHoveredComponent(event.clientX, event.clientY);
106
+ }, 1e3 / 60, [findAndSetHoveredComponent]);
107
+ const handleMouseLeave = useCallback((event) => {
108
+ event.stopPropagation();
109
+ findAndSetHoveredComponent(event.clientX, event.clientY);
110
+ }, [findAndSetHoveredComponent]);
86
111
  const handleClick = useCallback((e) => {
87
112
  e.stopPropagation();
88
113
  setSelectedComponent(componentId);
@@ -124,7 +149,7 @@ function DesignComponent(props) {
124
149
  onClick: handleClick,
125
150
  onDragOver: handleDragOver,
126
151
  onDragStart: handleDragStart,
127
- onMouseEnter: handleMouseEnter,
152
+ onMouseMove: handleMouseMove,
128
153
  onMouseLeave: handleMouseLeave,
129
154
  onMouseDown: handleMouseDown,
130
155
  "data-component-type": componentType?.id,
@@ -1 +1 @@
1
- {"version":3,"file":"DesignComponent.js","names":[],"sources":["../src/design/react/hooks/useComponentDecoratorClasses.ts","../src/design/react/hooks/useFocusedComponentHandler.ts","../src/design/react/components/DesignComponent.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 { useDesignState } from './useDesignState';\n\nexport function useComponentDecoratorClasses({\n componentId,\n isFragment,\n isLocalized,\n}: {\n componentId: string;\n isFragment: boolean;\n isLocalized: boolean;\n}): string {\n const { selectedComponentId, hoveredComponentId, dragState } = useDesignState();\n\n const isSelected = selectedComponentId === componentId;\n const isHovered = !dragState.isDragging && hoveredComponentId === componentId;\n const showFrame = (isSelected || isHovered) && !dragState.isDragging;\n const isMoving = dragState.isDragging && dragState.sourceComponentId === componentId;\n const isDropTarget = dragState.currentDropTarget?.componentId === componentId;\n const dropTargetInsertType = dragState.currentDropTarget?.insertType;\n const dropTargetAxis = dropTargetInsertType?.axis;\n\n return [\n 'pd-design__decorator',\n isFragment ? 'pd-design__fragment' : 'pd-design__component',\n showFrame && 'pd-design__frame--visible',\n isSelected && 'pd-design__decorator--selected',\n isHovered && 'pd-design__decorator--hovered',\n isMoving && 'pd-design__decorator--moving',\n !isLocalized && 'pd-design__component--unlocalized',\n isDropTarget &&\n dropTargetAxis &&\n dropTargetInsertType &&\n `pd-design__drop-target__${dropTargetAxis}-${dropTargetInsertType.type}`,\n ]\n .filter(Boolean)\n .join(' ');\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 { useDesignState } from './useDesignState';\n\n/**\n * Focuses a component when the focused component id matches the component id.\n * @param componentId - The id of the component to focus.\n * @param nodeRef - The ref object to the node to focus.\n */\nexport function useFocusedComponentHandler(componentId: string, nodeRef: React.RefObject<Element | null>): void {\n const { focusedComponentId, focusComponent } = useDesignState();\n\n React.useEffect(() => {\n if (focusedComponentId === componentId && nodeRef.current) {\n focusComponent(nodeRef.current);\n }\n }, [focusedComponentId, componentId, focusComponent, nodeRef]);\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, { useRef, useCallback } from 'react';\nimport type { ComponentDecoratorProps } from '../core/component.types';\nimport { useComponentDecoratorClasses } from '../hooks/useComponentDecoratorClasses';\nimport { useDesignState } from '../hooks/useDesignState';\nimport { useFocusedComponentHandler } from '../hooks/useFocusedComponentHandler';\nimport { useNodeToTargetStore } from '../hooks/useNodeToTargetStore';\nimport { DesignFrame } from './DesignFrame';\nimport { useRegionContext } from '../core/RegionContext';\nimport { ComponentContext, useComponentContext, type ComponentContextType } from '../core/ComponentContext';\nimport { useComponentDiscovery } from '../hooks/useComponentDiscovery';\nimport { useComponentType } from '../hooks/useComponentType';\n\nexport function DesignComponent(props: ComponentDecoratorProps<unknown>): React.JSX.Element {\n const { designMetadata, children } = props;\n const { id = '', name, isFragment = false, isVisible = true, isLocalized = false } = designMetadata ?? {};\n const componentId = id;\n const componentType = useComponentType(componentId);\n const componentName = componentType?.label || name || 'Component';\n const dragRef = useRef<HTMLDivElement>(null);\n const { regionId } = useRegionContext() ?? {};\n const { componentId: parentComponentId } = useComponentContext() ?? {};\n const { nodeToTargetMap } = useDesignState();\n\n const {\n selectedComponentId,\n hoveredComponentId,\n setSelectedComponent,\n setHoveredComponent,\n startComponentMove,\n setPendingComponentDragId,\n dragState: { pendingComponentDragId, isDragging, sourceComponentId: draggingSourceComponentId },\n } = useDesignState();\n\n useFocusedComponentHandler(componentId, dragRef);\n useNodeToTargetStore({\n type: 'component',\n nodeRef: dragRef,\n parentId: parentComponentId,\n regionId,\n componentId,\n });\n\n const discoverComponents = useComponentDiscovery({\n nodeToTargetMap,\n });\n\n const isPendingDrag = pendingComponentDragId === componentId;\n\n const handleMouseEnter = useCallback(\n (event: React.MouseEvent) => {\n event.stopPropagation();\n setHoveredComponent(componentId);\n },\n [setHoveredComponent, componentId]\n );\n\n const handleMouseLeave = useCallback(\n (event: React.MouseEvent) => {\n event.stopPropagation();\n\n // If we hover off a component, we could still be hovering over a parent component\n // that contains that child. In this instance, the mouse enter doesn't fire and that parent\n // would not be highlighted. Everytime we leave a component, we check\n // if we are hovering over a component at those coordinates. If we are,\n // we set the hovered component to that component.\n const components = discoverComponents({\n x: event.clientX,\n y: event.clientY,\n filter: (entry) => entry.type === 'component',\n });\n\n setHoveredComponent(components[0]?.componentId ?? null);\n },\n [setHoveredComponent, discoverComponents]\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n setSelectedComponent(componentId);\n },\n [setSelectedComponent, componentId]\n );\n\n const showFrame = [selectedComponentId, hoveredComponentId].includes(componentId) && !isDragging;\n const isDraggable = Boolean(componentId && regionId && componentType?.id);\n\n const classes = useComponentDecoratorClasses({\n componentId,\n isLocalized,\n isFragment: Boolean(isFragment),\n });\n\n const context = React.useMemo<ComponentContextType>(() => ({ componentId: id, name }), [id, name]);\n\n // Makes the component a drop target.\n const handleDragOver = React.useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n // Don't prevent propagation here.\n // We depend on the global listener to handle the drag over event.\n // If we are moving a component, don't let it be droppable on itself.\n if (draggingSourceComponentId !== componentId) {\n event.preventDefault();\n }\n },\n [draggingSourceComponentId, componentId]\n );\n\n // When dragging, we don't consider the component as dragging until the drag start event\n // is triggered. However, we need to mark the component as draggable on mouse down so that\n // it can even be dragged via the native drag and drop API.\n //\n // If we were to mark the components as dragging on mouse down instead, a selection of a component\n // would first remove the frame because this thinks we are dragging the component instead of selecting it.\n // This is why it is split up into two events.\n const handleMouseDown = React.useCallback(\n (event: React.MouseEvent) => {\n if (componentId) {\n event.stopPropagation();\n setPendingComponentDragId(componentId);\n }\n },\n [componentId, setPendingComponentDragId]\n );\n\n const handleDragStart = React.useCallback(\n (event: React.DragEvent) => {\n event.stopPropagation();\n\n if (componentId && regionId && componentType?.id) {\n startComponentMove(componentId, regionId, componentType.id);\n }\n },\n [componentId, regionId, componentType?.id, startComponentMove]\n );\n\n // Don't render anything if the components is hidden via visibility rules.\n // We still want the component to be reactive in case the use changes the\n // visibility rules or the render context.\n if (!isVisible) {\n return <></>;\n }\n\n return (\n <div\n ref={dragRef}\n className={classes}\n draggable={isPendingDrag && isDraggable}\n onClick={handleClick}\n onDragOver={handleDragOver}\n onDragStart={handleDragStart}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onMouseDown={handleMouseDown}\n data-component-type={componentType?.id}\n data-testid={`design-component-${componentId}`}>\n <div className=\"pd-design__component__drop-target\" />\n <DesignFrame\n showFrame={showFrame}\n componentId={componentId}\n localized={isLocalized}\n name={componentName}\n parentId={parentComponentId}\n isMoveable={isDraggable}\n regionId={regionId}>\n <ComponentContext.Provider value={context}>{children}</ComponentContext.Provider>\n </DesignFrame>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DesignComponent.js","names":[],"sources":["../src/design/react/hooks/useComponentDecoratorClasses.ts","../src/design/react/hooks/useFocusedComponentHandler.ts","../src/design/react/hooks/useComponentInfo.ts","../src/design/react/components/DesignComponent.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 { useDesignState } from './useDesignState';\n\nexport function useComponentDecoratorClasses({\n componentId,\n isFragment,\n isLocalized,\n}: {\n componentId: string;\n isFragment: boolean;\n isLocalized: boolean;\n}): string {\n const { selectedComponentId, hoveredComponentId, dragState } = useDesignState();\n\n const isSelected = selectedComponentId === componentId;\n const isHovered = !dragState.isDragging && hoveredComponentId === componentId;\n const showFrame = (isSelected || isHovered) && !dragState.isDragging;\n const isMoving = dragState.isDragging && dragState.sourceComponentId === componentId;\n const isDropTarget = dragState.currentDropTarget?.componentId === componentId;\n const dropTargetInsertType = dragState.currentDropTarget?.insertType;\n const dropTargetAxis = dropTargetInsertType?.axis;\n\n return [\n 'pd-design__decorator',\n isFragment ? 'pd-design__fragment' : 'pd-design__component',\n showFrame && 'pd-design__frame--visible',\n isSelected && 'pd-design__decorator--selected',\n isHovered && 'pd-design__decorator--hovered',\n isMoving && 'pd-design__decorator--moving',\n !isLocalized && 'pd-design__component--unlocalized',\n isDropTarget &&\n dropTargetAxis &&\n dropTargetInsertType &&\n `pd-design__drop-target__${dropTargetAxis}-${dropTargetInsertType.type}`,\n ]\n .filter(Boolean)\n .join(' ');\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 { useDesignState } from './useDesignState';\n\n/**\n * Focuses a component when the focused component id matches the component id.\n * @param componentId - The id of the component to focus.\n * @param nodeRef - The ref object to the node to focus.\n */\nexport function useFocusedComponentHandler(componentId: string, nodeRef: React.RefObject<Element | null>): void {\n const { focusedComponentId, focusComponent } = useDesignState();\n\n React.useEffect(() => {\n if (focusedComponentId === componentId && nodeRef.current) {\n focusComponent(nodeRef.current);\n }\n }, [focusedComponentId, componentId, focusComponent, nodeRef]);\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 type { ComponentInfo } from '../../messaging-api';\nimport { useDesignContext } from '../context/DesignContext';\nimport { useDesignState } from './useDesignState';\n\n/**\n * Hook that returns the current ComponentInfo for a given component ID,\n * merging the base config with any runtime updates.\n *\n * @param componentId - The ID of the component to get info for\n * @returns The merged ComponentInfo or null if the component doesn't exist\n */\nexport function useComponentInfo(componentId: string): ComponentInfo | null {\n const { pageDesignerConfig } = useDesignContext();\n const { componentUpdates } = useDesignState();\n const baseComponentInfo = pageDesignerConfig?.components?.[componentId];\n const updates = componentUpdates?.[componentId] ?? {};\n\n if (!baseComponentInfo) {\n return null;\n }\n\n return { ...baseComponentInfo, ...updates };\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, { useRef, useCallback } from 'react';\nimport type { ComponentDecoratorProps } from '../core/component.types';\nimport { useComponentDecoratorClasses } from '../hooks/useComponentDecoratorClasses';\nimport { useDesignState } from '../hooks/useDesignState';\nimport { useFocusedComponentHandler } from '../hooks/useFocusedComponentHandler';\nimport { useNodeToTargetStore } from '../hooks/useNodeToTargetStore';\nimport { DesignFrame } from './DesignFrame';\nimport { useRegionContext } from '../core/RegionContext';\nimport { ComponentContext, useComponentContext, type ComponentContextType } from '../core/ComponentContext';\nimport { useComponentDiscovery } from '../hooks/useComponentDiscovery';\nimport { useComponentType } from '../hooks/useComponentType';\nimport { useThrottledCallback } from '../hooks/useThrottledCallback';\nimport { useComponentInfo } from '../hooks/useComponentInfo';\n\nexport function DesignComponent(props: ComponentDecoratorProps<unknown>): React.JSX.Element {\n const { designMetadata, children } = props;\n const { id = '', name, isFragment = false, isVisible = true, isLocalized = false } = designMetadata ?? {};\n const componentId = id;\n const componentType = useComponentType(componentId);\n const componentInfo = useComponentInfo(componentId);\n const { nodeToTargetMap } = useDesignState();\n\n const componentName = componentInfo?.name || componentType?.label || name || 'Component';\n const dragRef = useRef<HTMLDivElement>(null);\n const { regionId } = useRegionContext() ?? {};\n const { componentId: parentComponentId } = useComponentContext() ?? {};\n\n const {\n selectedComponentId,\n hoveredComponentId,\n setSelectedComponent,\n setHoveredComponent,\n startComponentMove,\n setPendingComponentDragId,\n dragState: { pendingComponentDragId, isDragging, sourceComponentId: draggingSourceComponentId },\n } = useDesignState();\n\n useFocusedComponentHandler(componentId, dragRef);\n useNodeToTargetStore({\n type: 'component',\n nodeRef: dragRef,\n parentId: parentComponentId,\n regionId,\n componentId,\n });\n\n const discoverComponents = useComponentDiscovery({\n nodeToTargetMap,\n });\n\n const isPendingDrag = pendingComponentDragId === componentId;\n const findAndSetHoveredComponent = useCallback(\n (x: number, y: number) => {\n // If we hover off a component, we could still be hovering over a parent component\n // that contains that child. In this instance, the mouse enter doesn't fire and that parent\n // would not be highlighted. Everytime we leave a component, we check\n // if we are hovering over a component at those coordinates. If we are,\n // we set the hovered component to that component.\n const components = discoverComponents({\n x,\n y,\n filter: (entry) => entry.type === 'component',\n });\n\n setHoveredComponent(components[0]?.componentId ?? null);\n },\n [setHoveredComponent, discoverComponents]\n );\n\n const handleMouseMove = useThrottledCallback(\n (event: React.MouseEvent) => {\n event.stopPropagation();\n findAndSetHoveredComponent(event.clientX, event.clientY);\n },\n 1000 / 60, // 60 FPS\n [findAndSetHoveredComponent]\n );\n\n const handleMouseLeave = useCallback(\n (event: React.MouseEvent) => {\n event.stopPropagation();\n findAndSetHoveredComponent(event.clientX, event.clientY);\n },\n [findAndSetHoveredComponent]\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n setSelectedComponent(componentId);\n },\n [setSelectedComponent, componentId]\n );\n\n const showFrame = [selectedComponentId, hoveredComponentId].includes(componentId) && !isDragging;\n const isDraggable = Boolean(componentId && regionId && componentType?.id);\n\n const classes = useComponentDecoratorClasses({\n componentId,\n isLocalized,\n isFragment: Boolean(isFragment),\n });\n\n const context = React.useMemo<ComponentContextType>(() => ({ componentId: id, name }), [id, name]);\n\n // Makes the component a drop target.\n const handleDragOver = React.useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n // Don't prevent propagation here.\n // We depend on the global listener to handle the drag over event.\n // If we are moving a component, don't let it be droppable on itself.\n if (draggingSourceComponentId !== componentId) {\n event.preventDefault();\n }\n },\n [draggingSourceComponentId, componentId]\n );\n\n // When dragging, we don't consider the component as dragging until the drag start event\n // is triggered. However, we need to mark the component as draggable on mouse down so that\n // it can even be dragged via the native drag and drop API.\n //\n // If we were to mark the components as dragging on mouse down instead, a selection of a component\n // would first remove the frame because this thinks we are dragging the component instead of selecting it.\n // This is why it is split up into two events.\n const handleMouseDown = React.useCallback(\n (event: React.MouseEvent) => {\n if (componentId) {\n event.stopPropagation();\n setPendingComponentDragId(componentId);\n }\n },\n [componentId, setPendingComponentDragId]\n );\n\n const handleDragStart = React.useCallback(\n (event: React.DragEvent) => {\n event.stopPropagation();\n\n if (componentId && regionId && componentType?.id) {\n startComponentMove(componentId, regionId, componentType.id);\n }\n },\n [componentId, regionId, componentType?.id, startComponentMove]\n );\n\n // Don't render anything if the components is hidden via visibility rules.\n // We still want the component to be reactive in case the use changes the\n // visibility rules or the render context.\n if (!isVisible) {\n return <></>;\n }\n\n return (\n <div\n ref={dragRef}\n className={classes}\n draggable={isPendingDrag && isDraggable}\n onClick={handleClick}\n onDragOver={handleDragOver}\n onDragStart={handleDragStart}\n onMouseMove={handleMouseMove}\n onMouseLeave={handleMouseLeave}\n onMouseDown={handleMouseDown}\n data-component-type={componentType?.id}\n data-testid={`design-component-${componentId}`}>\n <div className=\"pd-design__component__drop-target\" />\n <DesignFrame\n showFrame={showFrame}\n componentId={componentId}\n localized={isLocalized}\n name={componentName}\n parentId={parentComponentId}\n isMoveable={isDraggable}\n regionId={regionId}>\n <ComponentContext.Provider value={context}>{children}</ComponentContext.Provider>\n </DesignFrame>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -510,6 +510,48 @@ function useDragInteraction({ nodeToTargetMap }) {
510
510
  };
511
511
  }
512
512
 
513
+ //#endregion
514
+ //#region src/design/react/hooks/useComponentUpdateInteraction.ts
515
+ /**
516
+ * Custom hook that manages component update state and handles
517
+ * client-host communication for component update events.
518
+ *
519
+ * Listens for ComponentUpdated events from the host and maintains
520
+ * a map of component IDs to their updated data.
521
+ *
522
+ * @returns Component update state
523
+ */
524
+ function useComponentUpdateInteraction() {
525
+ const { state: componentUpdates } = useInteraction({
526
+ initialState: {},
527
+ eventHandlers: {
528
+ ClientAcknowledged: { handler: (event, setState) => {
529
+ const initialUpdates = {};
530
+ Object.entries(event.components).forEach(([id, componentInfo]) => {
531
+ if (componentInfo.name) initialUpdates[id] = { name: componentInfo.name };
532
+ });
533
+ if (Object.keys(initialUpdates).length > 0) setState((prev) => ({
534
+ ...prev,
535
+ ...initialUpdates
536
+ }));
537
+ } },
538
+ ComponentUpdated: { handler: (event, setState) => {
539
+ setState((prev) => {
540
+ const componentId = event.componentId;
541
+ const updated = { ...prev[componentId] || {} };
542
+ if (event.changeType === "name") updated.name = event.newValue;
543
+ else if (event.changeType === "visibility") updated.visibility = event.newValue;
544
+ return {
545
+ ...prev,
546
+ [componentId]: updated
547
+ };
548
+ });
549
+ } }
550
+ }
551
+ });
552
+ return { componentUpdates };
553
+ }
554
+
513
555
  //#endregion
514
556
  //#region src/design/react/context/DesignStateContext.tsx
515
557
  const DesignStateContext = React.createContext(null);
@@ -522,6 +564,7 @@ const DesignStateProvider = ({ children }) => {
522
564
  });
523
565
  const focusInteraction = useFocusInteraction({ setSelectedComponent: selectInteraction.setSelectedComponent });
524
566
  const scrollInteraction = useScrollInteraction();
567
+ const componentUpdateInteraction = useComponentUpdateInteraction();
525
568
  const nodeToTargetMap = React.useMemo(() => /* @__PURE__ */ new WeakMap(), []);
526
569
  const dragInteraction = useDragInteraction({ nodeToTargetMap });
527
570
  const state = React.useMemo(() => ({
@@ -531,6 +574,7 @@ const DesignStateProvider = ({ children }) => {
531
574
  ...focusInteraction,
532
575
  ...dragInteraction,
533
576
  ...scrollInteraction,
577
+ ...componentUpdateInteraction,
534
578
  nodeToTargetMap
535
579
  }), [
536
580
  deleteInteraction,
@@ -539,7 +583,8 @@ const DesignStateProvider = ({ children }) => {
539
583
  focusInteraction,
540
584
  dragInteraction,
541
585
  nodeToTargetMap,
542
- scrollInteraction
586
+ scrollInteraction,
587
+ componentUpdateInteraction
543
588
  ]);
544
589
  return /* @__PURE__ */ jsx(DesignStateContext.Provider, {
545
590
  value: state,
@@ -765,5 +810,5 @@ DesignProvider.defaultProps = {
765
810
  const useDesignContext = () => React.useContext(DesignContext);
766
811
 
767
812
  //#endregion
768
- export { isComponentTypeAllowedInRegion as a, useDesignState as i, DesignProvider as n, useComponentDiscovery as o, useDesignContext as r, DesignContext as t };
813
+ export { useDesignState as a, useThrottledCallback as i, DesignProvider as n, isComponentTypeAllowedInRegion as o, useDesignContext as r, useComponentDiscovery as s, DesignContext as t };
769
814
  //# sourceMappingURL=DesignContext.js.map