@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.
- package/README.md +82 -0
- package/dist/DesignComponent.js +37 -12
- package/dist/DesignComponent.js.map +1 -1
- package/dist/DesignContext.js +47 -2
- package/dist/DesignContext.js.map +1 -1
- package/dist/DesignFrame.js +1 -1
- package/dist/DesignRegion.js +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/custom-global-preferences.d.ts +20 -0
- package/dist/custom-global-preferences.d.ts.map +1 -0
- package/dist/custom-global-preferences.js +28 -0
- package/dist/custom-global-preferences.js.map +1 -0
- package/dist/custom-site-preferences.d.ts +20 -0
- package/dist/custom-site-preferences.d.ts.map +1 -0
- package/dist/custom-site-preferences.js +28 -0
- package/dist/custom-site-preferences.js.map +1 -0
- package/dist/data-store-custom-global-preferences.d.ts +2 -0
- package/dist/data-store-custom-global-preferences.js +6 -0
- package/dist/data-store-custom-site-preferences.d.ts +2 -0
- package/dist/data-store-custom-site-preferences.js +6 -0
- package/dist/data-store-gcp-preferences.d.ts +2 -0
- package/dist/data-store-gcp-preferences.js +6 -0
- package/dist/data-store.d.ts +97 -0
- package/dist/data-store.d.ts.map +1 -0
- package/dist/data-store.js +42 -0
- package/dist/data-store.js.map +1 -0
- package/dist/design-data.d.ts +82 -88
- package/dist/design-data.d.ts.map +1 -1
- package/dist/design-data.js +95 -57
- package/dist/design-data.js.map +1 -1
- package/dist/design-messaging.d.ts +2 -2
- package/dist/events.d.ts +34 -6
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +6 -6
- package/dist/events.js.map +1 -1
- package/dist/gcp-preferences.d.ts +52 -0
- package/dist/gcp-preferences.d.ts.map +1 -0
- package/dist/gcp-preferences.js +61 -0
- package/dist/gcp-preferences.js.map +1 -0
- package/dist/i18n-client.d.ts +38 -0
- package/dist/i18n-client.d.ts.map +1 -0
- package/dist/i18n-client.js +72 -0
- package/dist/i18n-client.js.map +1 -0
- package/dist/i18n.d.ts +63 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +98 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +60 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/messaging-api.js +3 -1
- package/dist/messaging-api.js.map +1 -1
- package/dist/scapi.d.ts +247 -2
- package/dist/scapi.d.ts.map +1 -1
- package/dist/scapi.js +1 -1
- package/dist/scapi.js.map +1 -1
- package/dist/site-context.d.ts +94 -18
- package/dist/site-context.d.ts.map +1 -1
- package/dist/site-context.js +2 -417
- package/dist/site-context2.js +513 -0
- package/dist/site-context2.js.map +1 -0
- package/dist/types2.d.ts +210 -0
- package/dist/types2.d.ts.map +1 -1
- package/dist/utils.js +179 -0
- package/dist/utils.js.map +1 -0
- package/package.json +63 -4
- 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.
|
package/dist/DesignComponent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./messaging-api.js";
|
|
2
|
-
import {
|
|
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
|
|
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
|
|
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
|
|
82
|
-
y
|
|
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
|
-
|
|
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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"}
|
package/dist/DesignContext.js
CHANGED
|
@@ -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 {
|
|
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
|