@salesforce/storefront-next-runtime 0.2.0 → 0.3.0-alpha.1
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/dist/DesignFrame.js +6 -2
- package/dist/DesignFrame.js.map +1 -1
- package/dist/DesignRegion.js +2 -1
- package/dist/DesignRegion.js.map +1 -1
- package/dist/apply-url-config.js +4 -4
- package/dist/apply-url-config.js.map +1 -1
- package/dist/component.types.d.ts +6 -0
- package/dist/component.types.d.ts.map +1 -1
- package/dist/config-load.d.ts +27 -0
- package/dist/config-load.d.ts.map +1 -0
- package/dist/config-load.js +3 -0
- package/dist/config.d.ts +248 -1
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +432 -0
- package/dist/config.js.map +1 -0
- package/dist/design-data.d.ts +40 -27
- package/dist/design-data.d.ts.map +1 -1
- package/dist/design-data.js +50 -26
- package/dist/design-data.js.map +1 -1
- package/dist/design-react-core.d.ts +2 -2
- package/dist/design-react-core.js +3 -1
- package/dist/design-react-core.js.map +1 -1
- package/dist/events.d.ts +9 -4
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +6 -6
- package/dist/events.js.map +1 -1
- package/dist/load-config.js +42 -0
- package/dist/load-config.js.map +1 -0
- package/dist/routing.d.ts +1 -1
- package/dist/routing.d.ts.map +1 -1
- package/dist/routing.js +5 -38
- package/dist/routing.js.map +1 -1
- package/dist/scapi.d.ts +8 -0
- package/dist/scapi.d.ts.map +1 -1
- package/dist/scapi.js +1 -1
- package/dist/scapi.js.map +1 -1
- package/dist/schema.d.ts +78 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/{multi-site.d.ts → site-context.d.ts} +85 -60
- package/dist/site-context.d.ts.map +1 -0
- package/dist/{multi-site.js → site-context.js} +67 -41
- package/dist/site-context.js.map +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -4
- package/dist/multi-site.d.ts.map +0 -1
- package/dist/multi-site.js.map +0 -1
package/dist/DesignFrame.js
CHANGED
|
@@ -125,7 +125,7 @@ const DesignOverlay = () => {
|
|
|
125
125
|
|
|
126
126
|
//#endregion
|
|
127
127
|
//#region src/design/react/components/DesignFrame.tsx
|
|
128
|
-
const DesignFrame = ({ componentId, children, name, parentId, regionId, localized = false, showFrame = false, showToolbox = true, isMoveable = true }) => {
|
|
128
|
+
const DesignFrame = ({ componentId, children, name, parentId, regionId, localized = false, showFrame = false, showToolbox = true, isMoveable = true, className }) => {
|
|
129
129
|
const componentType = useComponentType(componentId ?? "");
|
|
130
130
|
const { deleteComponent } = useDesignState();
|
|
131
131
|
const labels = useLabels();
|
|
@@ -145,7 +145,11 @@ const DesignFrame = ({ componentId, children, name, parentId, regionId, localize
|
|
|
145
145
|
]);
|
|
146
146
|
const stopPropagation = (event) => event.stopPropagation();
|
|
147
147
|
return /* @__PURE__ */ jsxs("div", {
|
|
148
|
-
className: [
|
|
148
|
+
className: [
|
|
149
|
+
"pd-design__frame",
|
|
150
|
+
showFrame && "pd-design__frame--visible",
|
|
151
|
+
className
|
|
152
|
+
].filter(Boolean).join(" "),
|
|
149
153
|
ref: nodeRef,
|
|
150
154
|
children: [
|
|
151
155
|
showFrame && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", { className: "pd-design__frame--x" }), /* @__PURE__ */ jsx("div", { className: "pd-design__frame--y" })] }),
|
package/dist/DesignFrame.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DesignFrame.js","names":[],"sources":["../src/design/react/hooks/useNodeToTargetStore.ts","../src/design/react/hooks/useComponentType.ts","../src/design/react/components/DeleteToolboxButton.tsx","../src/design/react/components/MoveToolboxButton.tsx","../src/design/react/hooks/useLabels.ts","../src/design/react/components/DesignOverlay.tsx","../src/design/react/components/DesignFrame.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 React from 'react';\nimport { useDesignState } from './useDesignState';\nimport type { NodeToTargetMapEntry } from '../context/DesignStateContext';\n\nexport function useNodeToTargetStore({\n parentId,\n componentId,\n regionId,\n nodeRef,\n type,\n componentIds,\n componentTypeInclusions,\n componentTypeExclusions,\n}: Partial<NodeToTargetMapEntry> & {\n nodeRef: React.RefObject<Element | null>;\n}): void {\n const { nodeToTargetMap } = useDesignState();\n\n React.useEffect(() => {\n if (nodeRef.current) {\n nodeToTargetMap.set(nodeRef.current, {\n parentId,\n componentId,\n regionId,\n type,\n componentIds,\n componentTypeInclusions,\n componentTypeExclusions,\n } as NodeToTargetMapEntry);\n }\n }, [\n nodeRef,\n parentId,\n componentId,\n regionId,\n type,\n componentIds,\n nodeToTargetMap,\n componentTypeInclusions,\n componentTypeExclusions,\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 { useDesignContext } from '../context/DesignContext';\nimport type { ComponentType } from '../../messaging-api/domain-types';\n\nexport function useComponentType(componentId: string): ComponentType | null {\n const { pageDesignerConfig } = useDesignContext();\n const { type = '' } = pageDesignerConfig?.components[componentId] ?? {};\n\n return pageDesignerConfig?.componentTypes[type] ?? null;\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 React from 'react';\n\nexport const DeleteToolboxButton = ({\n title,\n onClick,\n onMouseDown = () => {\n /* noop */\n },\n}: {\n title: string;\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;\n onMouseDown?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n}): React.JSX.Element => (\n <button\n className=\"pd-design__frame__toolbox-button\"\n title={title}\n type=\"button\"\n onMouseDown={onMouseDown}\n onClick={onClick}>\n <svg\n className=\"pd-design__frame__delete-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M18 6L6 18M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\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 React from 'react';\n\nexport const MoveToolboxButton = ({ title }: { title: string }): React.JSX.Element => (\n <button className=\"pd-design__frame__toolbox-button\" title={title} type=\"button\">\n <svg className=\"pd-design__frame__move-icon\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M22.9 11.7l-3.8-4.2c-.3-.3-.6 0-.6.4v2.7h-4.7c-.2 0-.4-.2-.4-.4V5.5h2.7c.5 0 .7-.4.4-.6l-4.1-3.8c-.2-.2-.5-.2-.7 0L7.6 4.9c-.3.3-.1.6.4.6h2.6v4.7c0 .2-.2.4-.4.4H5.5V7.9c0-.5-.4-.7-.6-.4l-3.8 4.1c-.2.2-.2.5 0 .7l3.8 4.1c.3.3.6.1.6-.4v-2.6h4.7c.2 0 .4.2.4.4v4.7H7.9c-.5 0-.7.4-.4.6l4.1 3.8c.2.2.5.2.7 0l4.1-3.8c.3-.3.1-.6-.4-.6h-2.6v-4.7c0-.2.2-.4.4-.4h4.7v2.7c0 .5.4.7.6.4l3.8-4.1c.2-.3.2-.5 0-.7z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\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 { useDesignContext } from '../context/DesignContext';\n\nexport function useLabels(): Record<string, string> {\n const { pageDesignerConfig } = useDesignContext();\n\n return pageDesignerConfig?.labels ?? {};\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 */\nexport const DesignOverlay = () => {\n return (\n <div className=\"pd-design__frame__overlay\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n x=\"0px\"\n y=\"0px\"\n width=\"52px\"\n height=\"52px\"\n viewBox=\"0 0 52 52\"\n enableBackground=\"new 0 0 52 52\"\n xmlSpace=\"preserve\">\n <path\n fill=\"#FFFFFF\"\n d=\"M26,2C12.7,2,2,12.7,2,26s10.7,24,24,24s24-10.7,24-24S39.3,2,26,2z M26,7C26,7,26,7,26,7C26,7,26,7,26,7\n\tC26,7,26,7,26,7z M28,7.1c-0.1,0-0.1,0-0.2,0C27.9,7.1,28,7.1,28,7.1z M26,45C15.5,45,7,36.5,7,26c0-1,0.1-2.1,0.3-3\n\tc1.3,0.2,2.9,0.7,3.7,1.5c1.7,1.8,3.6,3.9,5.4,4.3c0,0-0.2,0.1-0.4,0.4c-0.2,0.3-0.4,0.9-0.4,1.9c0,4.7,4.4,1.9,4.4,6.6\n\tc0,4.7,5.3,6.6,5.3,2.8s3.5-5.6,3.5-8.5s-2.7-2.8-4.4-3.8c-1.8-0.9-2.7-2.4-6.1-1.9c-1.8-1.7-2.8-3.1-2-4.7c0.9-1.7,4.6-2,4.6-4.6\n\ts-2.5-3.1-4.3-3.1c-0.8,0-2.5-0.6-3.9-1.3c1.7-1.7,3.8-3.1,6-4.1c1.6,0.7,4.3,1.8,6.6,1.8c2.7,0,4.1-1.9,3.7-3.1\n\tc4.5,0.7,8.5,3,11.4,6.2c-1.5,0.9-3.5,1.9-7,1.9c-4.6,0-4.6,4.7-1.9,5.6c2.8,0.9,5.6-1.8,6.5,0c0.9,1.8-6.5,1.8-4.6,6.4\n\tc1.9,4.6,3.7-0.1,5.6,4.5c1.9,4.6,5.6-0.7,2.8-4.3c-1.2-1.6-0.9-6.5,1.9-6.5h0.9c0.4,1.6,0.7,3.3,0.7,5C45,36.5,36.5,45,26,45z\"\n />\n </svg>\n </div>\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 { useComponentType } from '../hooks/useComponentType';\nimport { DeleteToolboxButton } from './DeleteToolboxButton';\nimport { MoveToolboxButton } from './MoveToolboxButton';\nimport { useDesignState } from '../hooks/useDesignState';\nimport { useLabels } from '../hooks/useLabels';\nimport { DesignOverlay } from './DesignOverlay';\n\nexport const DesignFrame = ({\n componentId,\n children,\n name,\n parentId,\n regionId,\n localized = false,\n showFrame = false,\n showToolbox = true,\n isMoveable = true,\n}: React.PropsWithChildren<{\n componentId?: string;\n name: string;\n localized?: boolean;\n parentId?: string;\n regionId?: string;\n showToolbox?: boolean;\n showFrame?: boolean;\n isMoveable?: boolean;\n}>): React.JSX.Element => {\n const componentType = useComponentType(componentId ?? '');\n const { deleteComponent } = useDesignState();\n const labels = useLabels();\n const nodeRef = React.useRef<HTMLDivElement>(null);\n\n const handleDelete = React.useCallback(\n (event: React.MouseEvent) => {\n // Stop propagation so we don't select the component as well when\n // this bubbles up.\n event.stopPropagation();\n\n if (componentId) {\n deleteComponent({\n componentId,\n sourceComponentId: parentId ?? '',\n sourceRegionId: regionId ?? '',\n });\n }\n },\n [deleteComponent, componentId, parentId, regionId]\n );\n\n const stopPropagation = (event: React.MouseEvent) => event.stopPropagation();\n\n const classes = ['pd-design__frame', showFrame && 'pd-design__frame--visible'].filter(Boolean).join(' ');\n\n // TODO: For the frame label, when there is not enough space above the component to display it, we\n // need to display it inside the container instead.\n return (\n <div className={classes} ref={nodeRef}>\n {showFrame && (\n <>\n <div className=\"pd-design__frame--x\" />\n <div className=\"pd-design__frame--y\" />\n </>\n )}\n <div className=\"pd-design__frame__label\" onMouseDown={stopPropagation}>\n {componentType?.image && (\n <span className=\"pd-design__icon\">\n <img src={componentType.image} alt=\"\" />\n </span>\n )}\n <span className=\"pd-design__frame__name\">{name}</span>\n {!localized && (\n <span className=\"pd-design__frame__fallback-badge\">{labels.fallback ?? 'Fallback'}</span>\n )}\n </div>\n {showToolbox && (\n <div className=\"pd-design__frame__toolbox\">\n {isMoveable && <MoveToolboxButton title={labels.moveComponent ?? 'Move component'} />}\n <DeleteToolboxButton\n title={labels.deleteComponent ?? 'Delete component'}\n onMouseDown={stopPropagation}\n onClick={handleDelete}\n />\n </div>\n )}\n <DesignOverlay />\n {children}\n </div>\n );\n};\n\nDesignFrame.defaultProps = {\n parentId: undefined,\n componentId: undefined,\n showToolbox: true,\n regionId: undefined,\n showFrame: false,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DesignFrame.js","names":[],"sources":["../src/design/react/hooks/useNodeToTargetStore.ts","../src/design/react/hooks/useComponentType.ts","../src/design/react/components/DeleteToolboxButton.tsx","../src/design/react/components/MoveToolboxButton.tsx","../src/design/react/hooks/useLabels.ts","../src/design/react/components/DesignOverlay.tsx","../src/design/react/components/DesignFrame.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 React from 'react';\nimport { useDesignState } from './useDesignState';\nimport type { NodeToTargetMapEntry } from '../context/DesignStateContext';\n\nexport function useNodeToTargetStore({\n parentId,\n componentId,\n regionId,\n nodeRef,\n type,\n componentIds,\n componentTypeInclusions,\n componentTypeExclusions,\n}: Partial<NodeToTargetMapEntry> & {\n nodeRef: React.RefObject<Element | null>;\n}): void {\n const { nodeToTargetMap } = useDesignState();\n\n React.useEffect(() => {\n if (nodeRef.current) {\n nodeToTargetMap.set(nodeRef.current, {\n parentId,\n componentId,\n regionId,\n type,\n componentIds,\n componentTypeInclusions,\n componentTypeExclusions,\n } as NodeToTargetMapEntry);\n }\n }, [\n nodeRef,\n parentId,\n componentId,\n regionId,\n type,\n componentIds,\n nodeToTargetMap,\n componentTypeInclusions,\n componentTypeExclusions,\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 { useDesignContext } from '../context/DesignContext';\nimport type { ComponentType } from '../../messaging-api/domain-types';\n\nexport function useComponentType(componentId: string): ComponentType | null {\n const { pageDesignerConfig } = useDesignContext();\n const { type = '' } = pageDesignerConfig?.components[componentId] ?? {};\n\n return pageDesignerConfig?.componentTypes[type] ?? null;\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 React from 'react';\n\nexport const DeleteToolboxButton = ({\n title,\n onClick,\n onMouseDown = () => {\n /* noop */\n },\n}: {\n title: string;\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;\n onMouseDown?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n}): React.JSX.Element => (\n <button\n className=\"pd-design__frame__toolbox-button\"\n title={title}\n type=\"button\"\n onMouseDown={onMouseDown}\n onClick={onClick}>\n <svg\n className=\"pd-design__frame__delete-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M18 6L6 18M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\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 React from 'react';\n\nexport const MoveToolboxButton = ({ title }: { title: string }): React.JSX.Element => (\n <button className=\"pd-design__frame__toolbox-button\" title={title} type=\"button\">\n <svg className=\"pd-design__frame__move-icon\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M22.9 11.7l-3.8-4.2c-.3-.3-.6 0-.6.4v2.7h-4.7c-.2 0-.4-.2-.4-.4V5.5h2.7c.5 0 .7-.4.4-.6l-4.1-3.8c-.2-.2-.5-.2-.7 0L7.6 4.9c-.3.3-.1.6.4.6h2.6v4.7c0 .2-.2.4-.4.4H5.5V7.9c0-.5-.4-.7-.6-.4l-3.8 4.1c-.2.2-.2.5 0 .7l3.8 4.1c.3.3.6.1.6-.4v-2.6h4.7c.2 0 .4.2.4.4v4.7H7.9c-.5 0-.7.4-.4.6l4.1 3.8c.2.2.5.2.7 0l4.1-3.8c.3-.3.1-.6-.4-.6h-2.6v-4.7c0-.2.2-.4.4-.4h4.7v2.7c0 .5.4.7.6.4l3.8-4.1c.2-.3.2-.5 0-.7z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\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 { useDesignContext } from '../context/DesignContext';\n\nexport function useLabels(): Record<string, string> {\n const { pageDesignerConfig } = useDesignContext();\n\n return pageDesignerConfig?.labels ?? {};\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 */\nexport const DesignOverlay = () => {\n return (\n <div className=\"pd-design__frame__overlay\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n x=\"0px\"\n y=\"0px\"\n width=\"52px\"\n height=\"52px\"\n viewBox=\"0 0 52 52\"\n enableBackground=\"new 0 0 52 52\"\n xmlSpace=\"preserve\">\n <path\n fill=\"#FFFFFF\"\n d=\"M26,2C12.7,2,2,12.7,2,26s10.7,24,24,24s24-10.7,24-24S39.3,2,26,2z M26,7C26,7,26,7,26,7C26,7,26,7,26,7\n\tC26,7,26,7,26,7z M28,7.1c-0.1,0-0.1,0-0.2,0C27.9,7.1,28,7.1,28,7.1z M26,45C15.5,45,7,36.5,7,26c0-1,0.1-2.1,0.3-3\n\tc1.3,0.2,2.9,0.7,3.7,1.5c1.7,1.8,3.6,3.9,5.4,4.3c0,0-0.2,0.1-0.4,0.4c-0.2,0.3-0.4,0.9-0.4,1.9c0,4.7,4.4,1.9,4.4,6.6\n\tc0,4.7,5.3,6.6,5.3,2.8s3.5-5.6,3.5-8.5s-2.7-2.8-4.4-3.8c-1.8-0.9-2.7-2.4-6.1-1.9c-1.8-1.7-2.8-3.1-2-4.7c0.9-1.7,4.6-2,4.6-4.6\n\ts-2.5-3.1-4.3-3.1c-0.8,0-2.5-0.6-3.9-1.3c1.7-1.7,3.8-3.1,6-4.1c1.6,0.7,4.3,1.8,6.6,1.8c2.7,0,4.1-1.9,3.7-3.1\n\tc4.5,0.7,8.5,3,11.4,6.2c-1.5,0.9-3.5,1.9-7,1.9c-4.6,0-4.6,4.7-1.9,5.6c2.8,0.9,5.6-1.8,6.5,0c0.9,1.8-6.5,1.8-4.6,6.4\n\tc1.9,4.6,3.7-0.1,5.6,4.5c1.9,4.6,5.6-0.7,2.8-4.3c-1.2-1.6-0.9-6.5,1.9-6.5h0.9c0.4,1.6,0.7,3.3,0.7,5C45,36.5,36.5,45,26,45z\"\n />\n </svg>\n </div>\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 { useComponentType } from '../hooks/useComponentType';\nimport { DeleteToolboxButton } from './DeleteToolboxButton';\nimport { MoveToolboxButton } from './MoveToolboxButton';\nimport { useDesignState } from '../hooks/useDesignState';\nimport { useLabels } from '../hooks/useLabels';\nimport { DesignOverlay } from './DesignOverlay';\n\nexport const DesignFrame = ({\n componentId,\n children,\n name,\n parentId,\n regionId,\n localized = false,\n showFrame = false,\n showToolbox = true,\n isMoveable = true,\n className,\n}: React.PropsWithChildren<{\n componentId?: string;\n name: string;\n localized?: boolean;\n parentId?: string;\n regionId?: string;\n showToolbox?: boolean;\n showFrame?: boolean;\n isMoveable?: boolean;\n className?: string;\n}>): React.JSX.Element => {\n const componentType = useComponentType(componentId ?? '');\n const { deleteComponent } = useDesignState();\n const labels = useLabels();\n const nodeRef = React.useRef<HTMLDivElement>(null);\n\n const handleDelete = React.useCallback(\n (event: React.MouseEvent) => {\n // Stop propagation so we don't select the component as well when\n // this bubbles up.\n event.stopPropagation();\n\n if (componentId) {\n deleteComponent({\n componentId,\n sourceComponentId: parentId ?? '',\n sourceRegionId: regionId ?? '',\n });\n }\n },\n [deleteComponent, componentId, parentId, regionId]\n );\n\n const stopPropagation = (event: React.MouseEvent) => event.stopPropagation();\n\n const classes = ['pd-design__frame', showFrame && 'pd-design__frame--visible', className].filter(Boolean).join(' ');\n\n // TODO: For the frame label, when there is not enough space above the component to display it, we\n // need to display it inside the container instead.\n return (\n <div className={classes} ref={nodeRef}>\n {showFrame && (\n <>\n <div className=\"pd-design__frame--x\" />\n <div className=\"pd-design__frame--y\" />\n </>\n )}\n <div className=\"pd-design__frame__label\" onMouseDown={stopPropagation}>\n {componentType?.image && (\n <span className=\"pd-design__icon\">\n <img src={componentType.image} alt=\"\" />\n </span>\n )}\n <span className=\"pd-design__frame__name\">{name}</span>\n {!localized && (\n <span className=\"pd-design__frame__fallback-badge\">{labels.fallback ?? 'Fallback'}</span>\n )}\n </div>\n {showToolbox && (\n <div className=\"pd-design__frame__toolbox\">\n {isMoveable && <MoveToolboxButton title={labels.moveComponent ?? 'Move component'} />}\n <DeleteToolboxButton\n title={labels.deleteComponent ?? 'Delete component'}\n onMouseDown={stopPropagation}\n onClick={handleDelete}\n />\n </div>\n )}\n <DesignOverlay />\n {children}\n </div>\n );\n};\n\nDesignFrame.defaultProps = {\n parentId: undefined,\n componentId: undefined,\n showToolbox: true,\n regionId: undefined,\n showFrame: false,\n};\n"],"mappings":"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"}
|
package/dist/DesignRegion.js
CHANGED
|
@@ -26,7 +26,7 @@ function useRegionDecoratorClasses({ regionId, componentTypeInclusions, componen
|
|
|
26
26
|
//#endregion
|
|
27
27
|
//#region src/design/react/components/DesignRegion.tsx
|
|
28
28
|
function DesignRegion(props) {
|
|
29
|
-
const { designMetadata, children } = props;
|
|
29
|
+
const { designMetadata, children, className } = props;
|
|
30
30
|
const { name, id = "", componentIds = [], componentTypeInclusions = [], componentTypeExclusions = [] } = designMetadata ?? {};
|
|
31
31
|
const nodeRef = React.useRef(null);
|
|
32
32
|
const classes = useRegionDecoratorClasses({
|
|
@@ -70,6 +70,7 @@ function DesignRegion(props) {
|
|
|
70
70
|
localized: true,
|
|
71
71
|
showFrame,
|
|
72
72
|
showToolbox: false,
|
|
73
|
+
className,
|
|
73
74
|
children: /* @__PURE__ */ jsx(RegionContext.Provider, {
|
|
74
75
|
value: context,
|
|
75
76
|
children
|
package/dist/DesignRegion.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DesignRegion.js","names":[],"sources":["../src/design/react/hooks/useRegionDecoratorClasses.ts","../src/design/react/components/DesignRegion.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 { useMemo } from 'react';\nimport { useDesignState } from './useDesignState';\nimport { isComponentTypeAllowedInRegion } from '../utils/regionUtils';\n\nexport function useRegionDecoratorClasses({\n regionId,\n componentTypeInclusions,\n componentTypeExclusions,\n}: {\n regionId: string;\n componentTypeInclusions: string[];\n componentTypeExclusions: string[];\n}): string {\n const {\n dragState: { currentDropTarget, componentType },\n } = useDesignState();\n\n const isHovered = regionId && currentDropTarget?.regionId === regionId;\n\n const isComponentAllowed = useMemo(\n () => isComponentTypeAllowedInRegion(componentType, componentTypeInclusions, componentTypeExclusions),\n [componentType, componentTypeInclusions, componentTypeExclusions]\n );\n\n // Only show hover state if the region is hovered and the component is allowed\n const shouldShowHover = isHovered && isComponentAllowed;\n\n return [\n 'pd-design__decorator',\n 'pd-design__region',\n shouldShowHover && 'pd-design__region--hovered pd-design__frame--visible',\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, { useCallback } from 'react';\nimport type { RegionDecoratorProps } from '../core/component.types';\nimport { useRegionDecoratorClasses } from '../hooks/useRegionDecoratorClasses';\nimport { useNodeToTargetStore } from '../hooks/useNodeToTargetStore';\nimport { DesignFrame } from './DesignFrame';\nimport { useLabels } from '../hooks/useLabels';\nimport { RegionContext, type RegionContextType } from '../core/RegionContext';\nimport { useComponentContext } from '../core/ComponentContext';\nimport { useDesignState } from '../hooks/useDesignState';\nimport { isComponentTypeAllowedInRegion } from '../utils/regionUtils';\n\nexport function DesignRegion(props: RegionDecoratorProps<unknown>): React.JSX.Element {\n const { designMetadata, children } = props;\n const {\n name,\n id = '',\n componentIds = [],\n componentTypeInclusions = [],\n componentTypeExclusions = [],\n } = designMetadata ?? {};\n const nodeRef = React.useRef<HTMLDivElement>(null);\n const classes = useRegionDecoratorClasses({\n regionId: id,\n componentTypeInclusions,\n componentTypeExclusions,\n });\n const { dragState } = useDesignState();\n const labels = useLabels();\n const showFrame = Boolean(id && dragState.currentDropTarget?.regionId === id);\n const { componentId: parentComponentId } = useComponentContext() ?? {};\n\n useNodeToTargetStore({\n type: 'region',\n nodeRef,\n parentId: parentComponentId,\n componentIds,\n componentId: parentComponentId ?? '',\n regionId: id,\n componentTypeInclusions,\n componentTypeExclusions,\n });\n\n const context = React.useMemo<RegionContextType>(() => ({ regionId: id, componentIds }), [id, componentIds]);\n\n const handleDragOver = useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n const isComponentAllowed = isComponentTypeAllowedInRegion(\n dragState.componentType,\n componentTypeInclusions,\n componentTypeExclusions\n );\n\n if (isComponentAllowed) {\n event.preventDefault();\n }\n },\n [dragState.componentType, componentTypeInclusions, componentTypeExclusions]\n );\n\n return (\n <div className={classes} ref={nodeRef} onDragOver={handleDragOver} data-region-id={id}>\n <DesignFrame\n name={name ?? labels.defaultRegionName ?? 'Region'}\n parentId={parentComponentId}\n regionId={id}\n localized\n showFrame={showFrame}\n showToolbox={false}>\n <RegionContext.Provider value={context}>{children}</RegionContext.Provider>\n </DesignFrame>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAmBA,SAAgB,0BAA0B,EACtC,UACA,yBACA,2BAKO;CACP,MAAM,EACF,WAAW,EAAE,mBAAmB,oBAChC,gBAAgB;CAEpB,MAAM,YAAY,YAAY,mBAAmB,aAAa;CAE9D,MAAM,qBAAqB,cACjB,+BAA+B,eAAe,yBAAyB,wBAAwB,EACrG;EAAC;EAAe;EAAyB;EAAwB,CACpE;AAKD,QAAO;EACH;EACA;EAJoB,aAAa,sBAKd;EACtB,CACI,OAAO,QAAQ,CACf,KAAK,IAAI;;;;;ACtBlB,SAAgB,aAAa,OAAyD;CAClF,MAAM,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"DesignRegion.js","names":[],"sources":["../src/design/react/hooks/useRegionDecoratorClasses.ts","../src/design/react/components/DesignRegion.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 { useMemo } from 'react';\nimport { useDesignState } from './useDesignState';\nimport { isComponentTypeAllowedInRegion } from '../utils/regionUtils';\n\nexport function useRegionDecoratorClasses({\n regionId,\n componentTypeInclusions,\n componentTypeExclusions,\n}: {\n regionId: string;\n componentTypeInclusions: string[];\n componentTypeExclusions: string[];\n}): string {\n const {\n dragState: { currentDropTarget, componentType },\n } = useDesignState();\n\n const isHovered = regionId && currentDropTarget?.regionId === regionId;\n\n const isComponentAllowed = useMemo(\n () => isComponentTypeAllowedInRegion(componentType, componentTypeInclusions, componentTypeExclusions),\n [componentType, componentTypeInclusions, componentTypeExclusions]\n );\n\n // Only show hover state if the region is hovered and the component is allowed\n const shouldShowHover = isHovered && isComponentAllowed;\n\n return [\n 'pd-design__decorator',\n 'pd-design__region',\n shouldShowHover && 'pd-design__region--hovered pd-design__frame--visible',\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, { useCallback } from 'react';\nimport type { RegionDecoratorProps } from '../core/component.types';\nimport { useRegionDecoratorClasses } from '../hooks/useRegionDecoratorClasses';\nimport { useNodeToTargetStore } from '../hooks/useNodeToTargetStore';\nimport { DesignFrame } from './DesignFrame';\nimport { useLabels } from '../hooks/useLabels';\nimport { RegionContext, type RegionContextType } from '../core/RegionContext';\nimport { useComponentContext } from '../core/ComponentContext';\nimport { useDesignState } from '../hooks/useDesignState';\nimport { isComponentTypeAllowedInRegion } from '../utils/regionUtils';\n\nexport function DesignRegion(props: RegionDecoratorProps<unknown>): React.JSX.Element {\n const { designMetadata, children, className } = props;\n const {\n name,\n id = '',\n componentIds = [],\n componentTypeInclusions = [],\n componentTypeExclusions = [],\n } = designMetadata ?? {};\n const nodeRef = React.useRef<HTMLDivElement>(null);\n const classes = useRegionDecoratorClasses({\n regionId: id,\n componentTypeInclusions,\n componentTypeExclusions,\n });\n const { dragState } = useDesignState();\n const labels = useLabels();\n const showFrame = Boolean(id && dragState.currentDropTarget?.regionId === id);\n const { componentId: parentComponentId } = useComponentContext() ?? {};\n\n useNodeToTargetStore({\n type: 'region',\n nodeRef,\n parentId: parentComponentId,\n componentIds,\n componentId: parentComponentId ?? '',\n regionId: id,\n componentTypeInclusions,\n componentTypeExclusions,\n });\n\n const context = React.useMemo<RegionContextType>(() => ({ regionId: id, componentIds }), [id, componentIds]);\n\n const handleDragOver = useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n const isComponentAllowed = isComponentTypeAllowedInRegion(\n dragState.componentType,\n componentTypeInclusions,\n componentTypeExclusions\n );\n\n if (isComponentAllowed) {\n event.preventDefault();\n }\n },\n [dragState.componentType, componentTypeInclusions, componentTypeExclusions]\n );\n\n return (\n <div className={classes} ref={nodeRef} onDragOver={handleDragOver} data-region-id={id}>\n <DesignFrame\n name={name ?? labels.defaultRegionName ?? 'Region'}\n parentId={parentComponentId}\n regionId={id}\n localized\n showFrame={showFrame}\n showToolbox={false}\n className={className}>\n <RegionContext.Provider value={context}>{children}</RegionContext.Provider>\n </DesignFrame>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAmBA,SAAgB,0BAA0B,EACtC,UACA,yBACA,2BAKO;CACP,MAAM,EACF,WAAW,EAAE,mBAAmB,oBAChC,gBAAgB;CAEpB,MAAM,YAAY,YAAY,mBAAmB,aAAa;CAE9D,MAAM,qBAAqB,cACjB,+BAA+B,eAAe,yBAAyB,wBAAwB,EACrG;EAAC;EAAe;EAAyB;EAAwB,CACpE;AAKD,QAAO;EACH;EACA;EAJoB,aAAa,sBAKd;EACtB,CACI,OAAO,QAAQ,CACf,KAAK,IAAI;;;;;ACtBlB,SAAgB,aAAa,OAAyD;CAClF,MAAM,EAAE,gBAAgB,UAAU,cAAc;CAChD,MAAM,EACF,MACA,KAAK,IACL,eAAe,EAAE,EACjB,0BAA0B,EAAE,EAC5B,0BAA0B,EAAE,KAC5B,kBAAkB,EAAE;CACxB,MAAM,UAAU,MAAM,OAAuB,KAAK;CAClD,MAAM,UAAU,0BAA0B;EACtC,UAAU;EACV;EACA;EACH,CAAC;CACF,MAAM,EAAE,cAAc,gBAAgB;CACtC,MAAM,SAAS,WAAW;CAC1B,MAAM,YAAY,QAAQ,MAAM,UAAU,mBAAmB,aAAa,GAAG;CAC7E,MAAM,EAAE,aAAa,sBAAsB,qBAAqB,IAAI,EAAE;AAEtE,sBAAqB;EACjB,MAAM;EACN;EACA,UAAU;EACV;EACA,aAAa,qBAAqB;EAClC,UAAU;EACV;EACA;EACH,CAAC;CAEF,MAAM,UAAU,MAAM,eAAkC;EAAE,UAAU;EAAI;EAAc,GAAG,CAAC,IAAI,aAAa,CAAC;AAiB5G,QACI,oBAAC;EAAI,WAAW;EAAS,KAAK;EAAS,YAhBpB,aAClB,UAA2C;AAOxC,OAN2B,+BACvB,UAAU,eACV,yBACA,wBACH,CAGG,OAAM,gBAAgB;KAG9B;GAAC,UAAU;GAAe;GAAyB;GAAwB,CAC9E;EAGsE,kBAAgB;YAC/E,oBAAC;GACG,MAAM,QAAQ,OAAO,qBAAqB;GAC1C,UAAU;GACV,UAAU;GACV;GACW;GACX,aAAa;GACF;aACX,oBAAC,cAAc;IAAS,OAAO;IAAU;KAAkC;IACjE;GACZ"}
|
package/dist/apply-url-config.js
CHANGED
|
@@ -31,7 +31,7 @@ function createPatternMatcher(patterns) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
//#endregion
|
|
34
|
-
//#region src/
|
|
34
|
+
//#region src/site-context/apply-url-config.ts
|
|
35
35
|
const DEFAULT_EXCLUDED_ROUTES = ["/resource/**", "/action/**"];
|
|
36
36
|
/**
|
|
37
37
|
* Separates routes into excluded (stay at root) and included (go under prefix).
|
|
@@ -61,11 +61,11 @@ function normalizeRoutePaths(routes) {
|
|
|
61
61
|
}));
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
* Creates the `
|
|
64
|
+
* Creates the `site-context-wrapper` parent route entry with the given prefix.
|
|
65
65
|
*/
|
|
66
66
|
function createPrefixWrapper(prefix, children, wrapperFile) {
|
|
67
67
|
return {
|
|
68
|
-
id: "
|
|
68
|
+
id: "site-context-wrapper",
|
|
69
69
|
file: wrapperFile,
|
|
70
70
|
path: prefix.slice(1),
|
|
71
71
|
children
|
|
@@ -97,7 +97,7 @@ function cloneRootIndexRoutes(routes) {
|
|
|
97
97
|
return duplicates;
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
100
|
-
* Applies
|
|
100
|
+
* Applies site context URL configuration to a set of route entries.
|
|
101
101
|
*
|
|
102
102
|
* Wraps non-excluded routes under a parent route with the configured URL prefix
|
|
103
103
|
* (e.g. `/:siteId/:localeId`), while keeping excluded routes (action/resource by default)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-url-config.js","names":["prefixPatterns: string[]","excludedRoutes: RouteConfigEntry[]","includedRoutes: RouteConfigEntry[]","duplicates: RouteConfigEntry[]"],"sources":["../src/utils/index.ts","../src/
|
|
1
|
+
{"version":3,"file":"apply-url-config.js","names":["prefixPatterns: string[]","excludedRoutes: RouteConfigEntry[]","includedRoutes: RouteConfigEntry[]","duplicates: RouteConfigEntry[]"],"sources":["../src/utils/index.ts","../src/site-context/apply-url-config.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\n/**\n * Creates a matcher function from an array of path patterns.\n * Supports `/**` suffix wildcards (e.g. '/resource/**', '/action/**').\n * Exact paths without wildcards are matched literally.\n */\nexport function createPatternMatcher(patterns: string[]): (path: string) => boolean {\n const exactMatches = new Set<string>();\n const prefixPatterns: string[] = [];\n\n for (const pattern of patterns) {\n if (pattern.endsWith('/**')) {\n prefixPatterns.push(pattern.slice(0, -3));\n } else {\n exactMatches.add(pattern);\n }\n }\n\n return (path: string) => {\n if (exactMatches.has(path)) return true;\n return prefixPatterns.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));\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 type { RouteConfigEntry } from '@react-router/dev/routes';\nimport { createPatternMatcher } from '../utils';\nimport type { Url } from '../config/types';\n\nconst DEFAULT_EXCLUDED_ROUTES = ['/resource/**', '/action/**'];\n\n/**\n * Separates routes into excluded (stay at root) and included (go under prefix).\n */\nexport function partitionRoutes(\n routes: RouteConfigEntry[],\n excludePatterns: string[]\n): { excludedRoutes: RouteConfigEntry[]; includedRoutes: RouteConfigEntry[] } {\n const isExcluded = createPatternMatcher(excludePatterns);\n const excludedRoutes: RouteConfigEntry[] = [];\n const includedRoutes: RouteConfigEntry[] = [];\n\n for (const route of routes) {\n // Normalize path for matching — ensure leading slash so patterns like '/resource/**' work\n // regardless of whether the route path comes with or without a leading slash.\n // E.g Some routes comes from React Router flatRoutes objects where the path has no leading splash\n const matchPath = route.path?.startsWith('/') ? route.path : `/${route.path}`;\n if (route.path && isExcluded(matchPath)) {\n excludedRoutes.push(route);\n } else {\n includedRoutes.push(route);\n }\n }\n\n return { excludedRoutes, includedRoutes };\n}\n\n/**\n * Normalizes route paths by stripping leading `/` so they're relative under a\n * parent route (React Router requirement).\n */\nexport function normalizeRoutePaths(routes: RouteConfigEntry[]): RouteConfigEntry[] {\n return routes.map((route) => ({\n ...route,\n // Check for leading splash because React Router route object can contain no leading splash for a child route\n // E.g Some routes comes from React Router flatRoutes objects where the path has no leading splash\n path: route.path?.startsWith('/') ? route.path.slice(1) : route.path,\n }));\n}\n\n/**\n * Creates the `site-context-wrapper` parent route entry with the given prefix.\n */\nexport function createPrefixWrapper(\n prefix: string,\n children: RouteConfigEntry[],\n wrapperFile: string\n): RouteConfigEntry {\n return {\n id: 'site-context-wrapper',\n file: wrapperFile,\n path: prefix.slice(1),\n children,\n };\n}\n\n/**\n * Finds the root index route (`/`) and duplicates it with its parent layout.\n * Looks at the top level for pathless layouts whose direct children include an index route.\n * e.g. _app (pathless) → _app._index (index: true)\n * Returns: _app--root-duplicate → _app._index--root-duplicate\n */\nexport function cloneRootIndexRoutes(routes: RouteConfigEntry[]): RouteConfigEntry[] {\n const duplicates: RouteConfigEntry[] = [];\n\n for (const route of routes) {\n if (route.index === true) {\n duplicates.push({\n ...route,\n id: `${route.id}--root-duplicate`,\n });\n } else if (!route.path && route.children) {\n const indexChild = route.children.find((child) => child.index === true);\n if (indexChild) {\n duplicates.push({\n ...route,\n id: `${route.id}--root-duplicate`,\n children: [{ ...indexChild, id: `${indexChild.id}--root-duplicate` }],\n });\n }\n }\n }\n\n return duplicates;\n}\n\n/**\n * Applies site context URL configuration to a set of route entries.\n *\n * Wraps non-excluded routes under a parent route with the configured URL prefix\n * (e.g. `/:siteId/:localeId`), while keeping excluded routes (action/resource by default)\n * at the root level. The homepage index route (and its parent layout) is always\n * duplicated at `/` so the root URL still serves content.\n *\n * @param options - Configuration for URL customisation.\n * @param options.routes - The flat route entries discovered from the filesystem.\n * @param options.urlConfig - URL customisation configuration (prefix, excludeRoutes).\n * @param options.wrapperFile - Path to the wrapper component file, relative to appDirectory.\n * @returns The transformed route entries with prefix wrapping applied.\n */\nexport function applyUrlConfig(options: {\n routes: RouteConfigEntry[];\n urlConfig?: Url;\n wrapperFile: string;\n}): RouteConfigEntry[] {\n const { routes, urlConfig, wrapperFile } = options;\n if (!urlConfig) return routes;\n if (!urlConfig.prefix?.startsWith('/')) {\n throw new Error(`urlConfig.prefix must start with a leading slash (\"/\"). Received: \"${urlConfig.prefix}\"`);\n }\n if (urlConfig.prefix === '/') return routes;\n\n const excludePatterns = urlConfig.excludeRoutes ?? DEFAULT_EXCLUDED_ROUTES;\n\n const { excludedRoutes, includedRoutes } = partitionRoutes(routes, excludePatterns);\n\n const wrappableRoutes = normalizeRoutePaths(includedRoutes);\n // the route that wraps the included routes under prefix\n const wrapperRoute = createPrefixWrapper(urlConfig.prefix, wrappableRoutes, wrapperFile);\n\n // duplicate the app root index to keep app homepage to server at '/'\n const rootDuplicates = cloneRootIndexRoutes(includedRoutes);\n\n return [...rootDuplicates, wrapperRoute, ...excludedRoutes];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,qBAAqB,UAA+C;CAChF,MAAM,+BAAe,IAAI,KAAa;CACtC,MAAMA,iBAA2B,EAAE;AAEnC,MAAK,MAAM,WAAW,SAClB,KAAI,QAAQ,SAAS,MAAM,CACvB,gBAAe,KAAK,QAAQ,MAAM,GAAG,GAAG,CAAC;KAEzC,cAAa,IAAI,QAAQ;AAIjC,SAAQ,SAAiB;AACrB,MAAI,aAAa,IAAI,KAAK,CAAE,QAAO;AACnC,SAAO,eAAe,MAAM,WAAW,SAAS,UAAU,KAAK,WAAW,GAAG,OAAO,GAAG,CAAC;;;;;;AChBhG,MAAM,0BAA0B,CAAC,gBAAgB,aAAa;;;;AAK9D,SAAgB,gBACZ,QACA,iBAC0E;CAC1E,MAAM,aAAa,qBAAqB,gBAAgB;CACxD,MAAMC,iBAAqC,EAAE;CAC7C,MAAMC,iBAAqC,EAAE;AAE7C,MAAK,MAAM,SAAS,QAAQ;EAIxB,MAAM,YAAY,MAAM,MAAM,WAAW,IAAI,GAAG,MAAM,OAAO,IAAI,MAAM;AACvE,MAAI,MAAM,QAAQ,WAAW,UAAU,CACnC,gBAAe,KAAK,MAAM;MAE1B,gBAAe,KAAK,MAAM;;AAIlC,QAAO;EAAE;EAAgB;EAAgB;;;;;;AAO7C,SAAgB,oBAAoB,QAAgD;AAChF,QAAO,OAAO,KAAK,WAAW;EAC1B,GAAG;EAGH,MAAM,MAAM,MAAM,WAAW,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,GAAG,MAAM;EACnE,EAAE;;;;;AAMP,SAAgB,oBACZ,QACA,UACA,aACgB;AAChB,QAAO;EACH,IAAI;EACJ,MAAM;EACN,MAAM,OAAO,MAAM,EAAE;EACrB;EACH;;;;;;;;AASL,SAAgB,qBAAqB,QAAgD;CACjF,MAAMC,aAAiC,EAAE;AAEzC,MAAK,MAAM,SAAS,OAChB,KAAI,MAAM,UAAU,KAChB,YAAW,KAAK;EACZ,GAAG;EACH,IAAI,GAAG,MAAM,GAAG;EACnB,CAAC;UACK,CAAC,MAAM,QAAQ,MAAM,UAAU;EACtC,MAAM,aAAa,MAAM,SAAS,MAAM,UAAU,MAAM,UAAU,KAAK;AACvE,MAAI,WACA,YAAW,KAAK;GACZ,GAAG;GACH,IAAI,GAAG,MAAM,GAAG;GAChB,UAAU,CAAC;IAAE,GAAG;IAAY,IAAI,GAAG,WAAW,GAAG;IAAmB,CAAC;GACxE,CAAC;;AAKd,QAAO;;;;;;;;;;;;;;;;AAiBX,SAAgB,eAAe,SAIR;CACnB,MAAM,EAAE,QAAQ,WAAW,gBAAgB;AAC3C,KAAI,CAAC,UAAW,QAAO;AACvB,KAAI,CAAC,UAAU,QAAQ,WAAW,IAAI,CAClC,OAAM,IAAI,MAAM,sEAAsE,UAAU,OAAO,GAAG;AAE9G,KAAI,UAAU,WAAW,IAAK,QAAO;CAIrC,MAAM,EAAE,gBAAgB,mBAAmB,gBAAgB,QAFnC,UAAU,iBAAiB,wBAEgC;CAEnF,MAAM,kBAAkB,oBAAoB,eAAe;CAE3D,MAAM,eAAe,oBAAoB,UAAU,QAAQ,iBAAiB,YAAY;AAKxF,QAAO;EAAC,GAFe,qBAAqB,eAAe;EAEhC;EAAc,GAAG;EAAe"}
|
|
@@ -53,6 +53,11 @@ interface ComponentDesignMetadata {
|
|
|
53
53
|
* The id of the component or region.
|
|
54
54
|
*/
|
|
55
55
|
id: string;
|
|
56
|
+
/**
|
|
57
|
+
* The unique identifier for the content link between this component
|
|
58
|
+
* and its parent.
|
|
59
|
+
*/
|
|
60
|
+
contentLinkUuid?: string;
|
|
56
61
|
/**
|
|
57
62
|
* Whether the component is a fragment.
|
|
58
63
|
*/
|
|
@@ -81,6 +86,7 @@ type ComponentDecoratorProps<TProps> = React.PropsWithChildren<{
|
|
|
81
86
|
} & TProps>;
|
|
82
87
|
type RegionDecoratorProps<TProps> = React.PropsWithChildren<{
|
|
83
88
|
designMetadata?: RegionDesignMetadata;
|
|
89
|
+
className?: string;
|
|
84
90
|
} & TProps>;
|
|
85
91
|
//#endregion
|
|
86
92
|
export { RegionDesignMetadata as a, RegionDecoratorProps as i, ComponentDesignMetadata as n, DefaultComponentConstructor as r, ComponentDecoratorProps as t };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.types.d.ts","names":[],"sources":["../src/design/react/core/component.types.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAqBiB,2BAAA;;;;;;QAMP;;UAGO,oBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAgCkB;;UAGlB,uBAAA
|
|
1
|
+
{"version":3,"file":"component.types.d.ts","names":[],"sources":["../src/design/react/core/component.types.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAqBiB,2BAAA;;;;;;QAMP;;UAGO,oBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAgCkB;;UAGlB,uBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA6BO;;KAGZ,kCAAkC,KAAA,CAAM;mBAE3B;;;IAGjB;KAGI,+BAA+B,KAAA,CAAM;mBAExB;;IAEjB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { t as BaseConfig } from "./schema.js";
|
|
2
|
+
|
|
3
|
+
//#region src/config/load-config.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Dynamically imports `config.server.ts` from the project root (CWD) and returns
|
|
7
|
+
* the full configuration object. This runs at route discovery time under vite-node
|
|
8
|
+
* (typegen, dev, build), which handles the TS transformation.
|
|
9
|
+
*
|
|
10
|
+
* Uses jiti to transpile TypeScript on the fly, which works regardless of whether
|
|
11
|
+
* the caller runs under vite-node, a plain Node process, or any other runtime.
|
|
12
|
+
* This avoids the fragile assumption that vite-node will intercept dynamic imports
|
|
13
|
+
* from pre-compiled npm packages (it won't — Vite externalizes node_modules).
|
|
14
|
+
*
|
|
15
|
+
* Returns the full config including `metadata`, `runtime`, and `app` sections.
|
|
16
|
+
* Callers that only need `app` can destructure: `const { app } = await loadConfig()`.
|
|
17
|
+
*
|
|
18
|
+
* - If the config file is missing, throws with a clear message.
|
|
19
|
+
* - If the config file exists but fails to import, throws with the original error as cause.
|
|
20
|
+
*
|
|
21
|
+
* @returns The full configuration object.
|
|
22
|
+
* @throws If `config.server.ts` is not found or fails to import.
|
|
23
|
+
*/
|
|
24
|
+
declare function loadConfig<T extends BaseConfig = BaseConfig>(): Promise<T>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { loadConfig };
|
|
27
|
+
//# sourceMappingURL=config-load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-load.d.ts","names":[],"sources":["../src/config/load-config.ts"],"sourcesContent":[],"mappings":";;;;;;AAsCA;;;;;;;;;;;;;;;;;iBAAsB,qBAAqB,aAAa,eAAe,QAAQ"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,249 @@
|
|
|
1
1
|
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
|
+
import * as react0 from "react";
|
|
4
|
+
import { ReactNode } from "react";
|
|
5
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
6
|
+
import * as react_router0 from "react-router";
|
|
7
|
+
import { MiddlewareFunction, RouterContextProvider } from "react-router";
|
|
8
|
+
|
|
9
|
+
//#region src/config/get-config.d.ts
|
|
10
|
+
|
|
11
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
__APP_CONFIG__?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get configuration in loaders, actions, and utilities.
|
|
18
|
+
*
|
|
19
|
+
* Pass context parameter in server loaders/actions.
|
|
20
|
+
* Omit context parameter in client loaders (uses window.__APP_CONFIG__).
|
|
21
|
+
*
|
|
22
|
+
* @param context - Router context for server loaders/actions
|
|
23
|
+
* @returns App configuration
|
|
24
|
+
*/
|
|
25
|
+
declare function getConfig<T extends Record<string, unknown> = Record<string, unknown>>(context?: Readonly<RouterContextProvider>): T;
|
|
26
|
+
/**
|
|
27
|
+
* Get configuration in React components.
|
|
28
|
+
*
|
|
29
|
+
* Must use this hook (not getConfig) because React Context requires useContext().
|
|
30
|
+
*
|
|
31
|
+
* @returns App configuration
|
|
32
|
+
*/
|
|
33
|
+
declare function useConfig<T extends Record<string, unknown> = Record<string, unknown>>(): T;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/config/context.d.ts
|
|
36
|
+
/**
|
|
37
|
+
* Router context for application configuration.
|
|
38
|
+
*
|
|
39
|
+
* Populated by `createAppConfigMiddleware` with the `app` section of config.
|
|
40
|
+
* Accessible in loaders, actions, and middleware via `context.get(appConfigContext)`.
|
|
41
|
+
*/
|
|
42
|
+
declare const appConfigContext: react_router0.RouterContext<Record<string, unknown>>;
|
|
43
|
+
/**
|
|
44
|
+
* React context for application configuration.
|
|
45
|
+
*
|
|
46
|
+
* Used by the `useConfig()` hook in React components.
|
|
47
|
+
* Populated by `ConfigProvider` in the component tree.
|
|
48
|
+
*/
|
|
49
|
+
declare const ConfigContext: react0.Context<Record<string, unknown> | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Extract the `app` section from a full config object.
|
|
52
|
+
*
|
|
53
|
+
* @param staticConfig - The full config object (output of `defineConfig()`)
|
|
54
|
+
* @returns The `app` section of the config
|
|
55
|
+
*/
|
|
56
|
+
declare function createAppConfig<T extends BaseConfig>(staticConfig: T): T['app'];
|
|
57
|
+
interface ConfigProviderProps {
|
|
58
|
+
config: Record<string, unknown>;
|
|
59
|
+
children: ReactNode;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* React context provider for application configuration.
|
|
63
|
+
*
|
|
64
|
+
* Wrap your component tree with this to enable `useConfig()` in child components.
|
|
65
|
+
* Typically placed in the root layout component.
|
|
66
|
+
*/
|
|
67
|
+
declare function ConfigProvider({
|
|
68
|
+
config,
|
|
69
|
+
children
|
|
70
|
+
}: ConfigProviderProps): react_jsx_runtime1.JSX.Element;
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/config/middleware.d.ts
|
|
73
|
+
/**
|
|
74
|
+
* Create app config middleware for both server and client.
|
|
75
|
+
*
|
|
76
|
+
* Follows the same factory pattern as `createSiteContextMiddleware`.
|
|
77
|
+
*
|
|
78
|
+
* The server middleware:
|
|
79
|
+
* - Validates required Commerce API fields on first request (one-time)
|
|
80
|
+
* - Sets `appConfigContext` in router context with `config.app`
|
|
81
|
+
*
|
|
82
|
+
* The client middleware:
|
|
83
|
+
* - Reads `window.__APP_CONFIG__` (injected during SSR)
|
|
84
|
+
* - Sets `appConfigContext` in router context
|
|
85
|
+
*
|
|
86
|
+
* Environment variables:
|
|
87
|
+
* - `SCAPI_PROXY_HOST` (optional): When set, skips `shortCode` validation
|
|
88
|
+
* (workspace environments route through a proxy that doesn't require shortCode)
|
|
89
|
+
* - `NODE_ENV` (optional): When set to 'test', skips validation entirely
|
|
90
|
+
*
|
|
91
|
+
* @param config - The full config object (output of `defineConfig()`)
|
|
92
|
+
* @returns Object with `server` and `client` middleware functions
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* import { createAppConfigMiddleware } from '@salesforce/storefront-next-runtime/config';
|
|
96
|
+
* import config from '@/config/server';
|
|
97
|
+
*
|
|
98
|
+
* const appConfigMiddleware = createAppConfigMiddleware(config);
|
|
99
|
+
*
|
|
100
|
+
* export const middleware = [appConfigMiddleware.server, ...otherMiddleware];
|
|
101
|
+
* export const clientMiddleware = [appConfigMiddleware.client, ...otherClientMiddleware];
|
|
102
|
+
*/
|
|
103
|
+
declare function createAppConfigMiddleware<T extends BaseConfig>(config: T): {
|
|
104
|
+
server: MiddlewareFunction<Response>;
|
|
105
|
+
client: MiddlewareFunction<Record<string, unknown>>;
|
|
106
|
+
};
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/config/utils.d.ts
|
|
109
|
+
/**
|
|
110
|
+
* Copyright 2026 Salesforce, Inc.
|
|
111
|
+
*
|
|
112
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
113
|
+
* you may not use this file except in compliance with the License.
|
|
114
|
+
* You may obtain a copy of the License at
|
|
115
|
+
*
|
|
116
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
117
|
+
*
|
|
118
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
119
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
120
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
121
|
+
* See the License for the specific language governing permissions and
|
|
122
|
+
* limitations under the License.
|
|
123
|
+
*/
|
|
124
|
+
/**
|
|
125
|
+
* Deep merge two objects, with source values overriding target values
|
|
126
|
+
* Arrays are replaced, not merged
|
|
127
|
+
*
|
|
128
|
+
* @param target - The base object
|
|
129
|
+
* @param source - The object with values to merge in
|
|
130
|
+
* @returns A new merged object
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* deepMerge(
|
|
134
|
+
* { a: { b: 1, c: 2 } },
|
|
135
|
+
* { a: { b: 3, d: 4 } }
|
|
136
|
+
* )
|
|
137
|
+
* // Returns: { a: { b: 3, c: 2, d: 4 } }
|
|
138
|
+
*/
|
|
139
|
+
declare const deepMerge: <T extends Record<string, unknown>>(target: T, source: Record<string, unknown>) => T;
|
|
140
|
+
/**
|
|
141
|
+
* Convert a path string with double underscore separators to a nested object
|
|
142
|
+
* Normalizes keys to match baseConfig casing (case-insensitive lookup, preserves baseConfig case)
|
|
143
|
+
*
|
|
144
|
+
* @param path - The path string (e.g., 'app__pages__cart__quantityUpdateDebounce')
|
|
145
|
+
* @param value - The value to set at the path
|
|
146
|
+
* @param baseConfig - Optional base config for case normalization
|
|
147
|
+
* @returns A nested object
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* pathToObject('app__pages__cart__maxQuantity', 999)
|
|
151
|
+
* // Returns: { app: { pages: { cart: { maxQuantity: 999 } } } }
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* // With baseConfig normalization:
|
|
155
|
+
* pathToObject('APP__SITE__LOCALE', 'en-GB', { app: { site: { locale: 'en-GB' } } })
|
|
156
|
+
* // Returns: { app: { site: { locale: 'en-GB' } } } (normalized to baseConfig casing)
|
|
157
|
+
*/
|
|
158
|
+
declare const pathToObject: (path: string, value: unknown, baseConfig?: Record<string, unknown>) => Record<string, unknown>;
|
|
159
|
+
/**
|
|
160
|
+
* Parse environment variable value with optimistic JSON parsing
|
|
161
|
+
* Tries to parse as JSON first, falls back to string if invalid
|
|
162
|
+
* Supports multi-line formatted JSON by normalizing whitespace before parsing
|
|
163
|
+
*
|
|
164
|
+
* @param varValue - The environment variable value
|
|
165
|
+
* @param varName - Optional variable name for better error messages
|
|
166
|
+
* @returns The parsed value (JSON type if valid JSON, otherwise string)
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* // Primitives
|
|
170
|
+
* parseEnvValue('42') // → 42 (number)
|
|
171
|
+
* parseEnvValue('true') // → true (boolean)
|
|
172
|
+
* parseEnvValue('hello') // → 'hello' (string)
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* // Single-line JSON
|
|
176
|
+
* parseEnvValue('["Apple","Google"]') // → ['Apple', 'Google'] (array)
|
|
177
|
+
* parseEnvValue('{"key":"value"}') // → {key: 'value'} (object)
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* // Multi-line formatted JSON (whitespace normalized automatically)
|
|
181
|
+
* parseEnvValue('[
|
|
182
|
+
* {"id": "en-GB"},
|
|
183
|
+
* {"id": "fr-FR"}
|
|
184
|
+
* ]') // → [{id: 'en-GB'}, {id: 'fr-FR'}] (array)
|
|
185
|
+
*/
|
|
186
|
+
declare const parseEnvValue: (varValue: string, varName?: string) => unknown;
|
|
187
|
+
/**
|
|
188
|
+
* Extract all valid paths from a config object (recursively traverses the object structure)
|
|
189
|
+
* Returns paths in lowercase with double underscore separators
|
|
190
|
+
*
|
|
191
|
+
* @param obj - The config object to extract paths from
|
|
192
|
+
* @param prefix - Current path prefix (used for recursion)
|
|
193
|
+
* @returns Array of valid config paths
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* extractValidPaths({ app: { site: { locale: 'en-GB' } } })
|
|
197
|
+
* // Returns: ['app__site__locale']
|
|
198
|
+
*/
|
|
199
|
+
declare const extractValidPaths: (obj: unknown, prefix?: string) => string[];
|
|
200
|
+
/**
|
|
201
|
+
* Options for mergeEnvConfig
|
|
202
|
+
*/
|
|
203
|
+
interface MergeEnvConfigOptions {
|
|
204
|
+
/**
|
|
205
|
+
* Config paths that cannot be overridden by environment variables.
|
|
206
|
+
* Paths are matched case-insensitively with double underscore separators.
|
|
207
|
+
* Any env var targeting a protected path or a sub-path of it will throw an error.
|
|
208
|
+
*
|
|
209
|
+
* @example ['app__engagement'] — prevents PUBLIC__app__engagement__* from being set via env
|
|
210
|
+
*/
|
|
211
|
+
protectedPaths?: string[];
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Merge environment variables with PUBLIC__ prefix into config.
|
|
215
|
+
*
|
|
216
|
+
* Uses double underscore (__) to target nested config paths.
|
|
217
|
+
* All PUBLIC__ prefixed variables are exposed to the client (bundled into window.__APP_CONFIG__).
|
|
218
|
+
*
|
|
219
|
+
* Server-only secrets should NEVER use this — read them directly from process.env in server code.
|
|
220
|
+
*
|
|
221
|
+
* Environment variables:
|
|
222
|
+
* - `PUBLIC__<path>` (optional): Override any config path. e.g. `PUBLIC__app__commerce__api__clientId=abc123`
|
|
223
|
+
* - `NODE_ENV` (optional): When set to 'development', enables conflict warnings for overlapping paths
|
|
224
|
+
*
|
|
225
|
+
* @param env - Environment variables object (defaults to process.env)
|
|
226
|
+
* @param baseConfig - Optional base config for strict path validation and case normalization
|
|
227
|
+
* @param options - Optional configuration including protected paths
|
|
228
|
+
* @returns Object with overrides to merge into base config
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* // Environment variables:
|
|
232
|
+
* // PUBLIC__app__commerce__api__clientId=abc123
|
|
233
|
+
* // PUBLIC__app__pages__cart__quantityUpdateDebounce=1000
|
|
234
|
+
* // PUBLIC__app__features__socialLogin__providers=["Apple","Google"]
|
|
235
|
+
*
|
|
236
|
+
* mergeEnvConfig()
|
|
237
|
+
* // Returns:
|
|
238
|
+
* // {
|
|
239
|
+
* // app: {
|
|
240
|
+
* // commerce: { api: { clientId: 'abc123' } },
|
|
241
|
+
* // pages: { cart: { quantityUpdateDebounce: 1000 } },
|
|
242
|
+
* // features: { socialLogin: { providers: ['Apple', 'Google'] } }
|
|
243
|
+
* // }
|
|
244
|
+
* // }
|
|
245
|
+
*/
|
|
246
|
+
declare const mergeEnvConfig: (env?: Record<string, string | undefined>, baseConfig?: Record<string, unknown>, options?: MergeEnvConfigOptions) => Record<string, unknown>;
|
|
247
|
+
//#endregion
|
|
248
|
+
export { type BaseConfig, ConfigContext, ConfigProvider, type DefineConfigOptions, type Locale, type MergeEnvConfigOptions, type Site, type Url, appConfigContext, createAppConfig, createAppConfigMiddleware, deepMerge, defineConfig, extractValidPaths, getConfig, mergeEnvConfig, parseEnvValue, pathToObject, useConfig };
|
|
249
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config/get-config.ts","../src/config/context.tsx","../src/config/middleware.ts","../src/config/utils.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;QA2C8D,MAAA,CAAA;EACvC,UAAA,MAAA,CAAA;IAAT,cAAA,CAAA,EAdW,MAcX,CAAA,MAAA,EAAA,OAAA,CAAA;EACX;;AA+BH;;;;;;;;AC1CA;AASa,iBDAG,SCAU,CAAA,UDAU,MCAV,CAAA,MAAA,EAAA,OAAA,CAAA,GDAoC,MCApC,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,OAAA,CAAA,EDCZ,QCDY,CDCH,qBCDG,CAAA,CAAA,EDEvB,CCFuB;AAS1B;;;;;AAEC;AAaD;AAAiC,iBDSjB,SCTiB,CAAA,UDSG,MCTH,CAAA,MAAA,EAAA,OAAA,CAAA,GDS6B,MCT7B,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,CAAA,EDSyD,CCTzD;;;;;;;;;AAjCpB,cAAA,gBAAgB,EAAA,aAAA,CAAA,aAAA,CAAA,MAAA,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;AAS7B;AASA;;;;;AAIU,cAbG,aAagB,EAbH,MAAA,CAAA,OAeH,CAfG,MAeH,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA,CAAA;AASvB;;;;;;iBAfgB,0BAA0B,0BAA0B,IAAI;UAI9D,mBAAA;UACE;ECPI,QAAA,EDQF,SCRE;;;;;;;;iBDiBA,cAAA;;;GAAqC,sBAAmB,kBAAA,CAAA,GAAA,CAAA;;;;;;;ADSxE;;;;;;;;AC1CA;AASA;AASA;;;;;AAEC;AAaD;;;;;;;;;ACjBA;AAAoD,iBAApC,yBAAoC,CAAA,UAAA,UAAA,CAAA,CAAA,MAAA,EACxC,CADwC,CAAA,EAAA;EACxC,MAAA,EAEA,kBAFA,CAEmB,QAFnB,CAAA;EAEmB,MAAA,EACnB,kBADmB,CACA,MADA,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;CAAnB;;;;;;;;;;;;AF5B8C;;;;;AAkB1D;;;;;;;AAiCA;;;;;;;;AC1CA;AASa,cELA,SFKmE,EAAtD,CAAA,UELU,MFKV,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,MAAA,EEL2C,CFK3C,EAAA,MAAA,EELsD,MFKtD,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GELgF,CFKhF;AAS1B;;;;;AAEC;AAaD;;;;;;;;;ACjBA;;;AAG+B,cCoBlB,YDpBkB,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,UAAA,CAAA,ECuBd,MDvBc,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GCwB5B,MDxB4B,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;;;;ACf/B;;;;;;AAmCA;AAqEA;AAqCA;AAiCA;AA4CA;;;;;;;;;;cAlHa;;;;;;;;;;;;;cAqCA;;;;UAiCI,qBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4CJ,uBACJ,iDACQ,mCACH,0BACX"}
|