Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/nextjs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ export {
withSitecore,
useSitecore,
withEditorChromes,
withPlaceholder,
withAppPlaceholder,
withClientPlaceholder,
withDatasourceCheck,
ImageSizeParameters,
WithSitecoreOptions,
Expand Down
84 changes: 30 additions & 54 deletions packages/react/api/content-sdk-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,14 @@ import { SitePathService } from '@sitecore-content-sdk/content/site';
import { SitePathServiceConfig } from '@sitecore-content-sdk/content/site';

// @public
export const AppPlaceholder: (props: AppPlaceholderProps) => string | number | bigint | boolean | Iterable<React_2.ReactNode> | Promise<string | number | bigint | boolean | React_2.ReactPortal | React_2.ReactElement<unknown, string | React_2.JSXElementConstructor<any>> | Iterable<React_2.ReactNode> | null | undefined> | React_2.JSX.Element | (string | number | bigint | boolean | Iterable<React_2.ReactNode> | Promise<string | number | bigint | boolean | React_2.ReactPortal | React_2.ReactElement<unknown, string | React_2.JSXElementConstructor<any>> | Iterable<React_2.ReactNode> | null | undefined> | React_2.JSX.Element | null | undefined)[] | null | undefined;
export const AppPlaceholder: (props: AppPlaceholderProps) => React_2.JSX.Element;

// Warning: (ae-forgotten-export) The symbol "BasePlaceholderProps" needs to be exported by the entry point api-surface.d.ts
//
// @public
export interface AppPlaceholderProps extends BasePlaceholderProps {
componentMap: ComponentMap;
// Warning: (ae-forgotten-export) The symbol "AppComponentProps" needs to be exported by the entry point api-surface.d.ts
modifyComponentProps?: (componentProps: AppComponentProps) => AppComponentProps;
export type AppPlaceholderProps = Omit<BasePlaceholderProps, 'componentMap' | 'page'> & Required<Pick<BasePlaceholderProps, 'componentMap' | 'page'>> & {
render?: (components: React.ReactNode[], data: ComponentRendering[], props: AppPlaceholderProps) => React.ReactNode;
}
};

// @public
export class BYOCComponent extends React_2.Component<BYOCComponentProps> {
Expand Down Expand Up @@ -179,7 +176,7 @@ export { DictionaryPhrases }
export { DictionaryService }

// @public
export const EditingScripts: () => JSX_2.Element;
export const EditingScripts: () => React_2.JSX.Element;

export { EditMode }

Expand Down Expand Up @@ -375,17 +372,12 @@ export { Page }
export { PageMode }

// @public
export const Placeholder: (props: EnhancedOmit<PlaceholderProps, keyof WithSitecoreProps>) => React_2.JSX.Element;
export const Placeholder: (props: PlaceholderProps) => React_2.JSX.Element;

// @public
interface PlaceholderProps extends BasePlaceholderProps {
// (undocumented)
[key: string]: unknown;
componentMap?: ComponentMap;
// Warning: (ae-forgotten-export) The symbol "ComponentProps" needs to be exported by the entry point api-surface.d.ts
modifyComponentProps?: (componentProps: ComponentProps) => ComponentProps;
type PlaceholderProps = BasePlaceholderProps & {
render?: (components: React.ReactNode[], data: ComponentRendering[], props: PlaceholderProps) => React.ReactNode;
}
};
export { PlaceholderProps as PlaceholderComponentProps }
export { PlaceholderProps }

Expand Down Expand Up @@ -430,19 +422,11 @@ export { RouteData }
// @public
export type SearchStatus = 'idle' | 'loading' | 'success' | 'error';

// Warning: (ae-forgotten-export) The symbol "SitecoreProviderProps" needs to be exported by the entry point api-surface.d.ts
//
// @public
export class SitecoreProvider extends React_2.Component<SitecoreProviderProps, SitecoreProviderState> {
constructor(props: SitecoreProviderProps);
// (undocumented)
componentDidUpdate(prevProps: SitecoreProviderProps): void;
// (undocumented)
static displayName: string;
// (undocumented)
render(): React_2.JSX.Element;
setPage: (value: Page) => void;
}
export const SitecoreProvider: {
(props: SitecoreProviderProps): React_2.JSX.Element;
displayName: string;
};

// @public
export const SitecoreProviderReactContext: React_2.Context<SitecoreProviderState>;
Expand All @@ -451,7 +435,7 @@ export const SitecoreProviderReactContext: React_2.Context<SitecoreProviderState
export interface SitecoreProviderState {
api?: SitecoreProviderProps['api'];
page: Page;
setPage: (value: Page) => void;
setPage?: (value: Page) => void;
}

export { SitePathService }
Expand All @@ -470,6 +454,9 @@ export interface TextField extends FieldMetadata {
value?: string | number;
}

// @public
export function useComponentMap(): ComponentMap;

// @public
export const useInfiniteSearch: <T extends SearchDocument = SearchDocument>(options: UseInfiniteSearchOptions<T>) => UseInfiniteSearchState<T>;

Expand Down Expand Up @@ -519,8 +506,17 @@ export type UseSearchState<T extends SearchDocument = SearchDocument> = Omit<Int
isPreviousData: boolean;
};

// Warning: (ae-forgotten-export) The symbol "ComponentProps" needs to be exported by the entry point api-surface.d.ts
// Warning: (ae-forgotten-export) The symbol "WrapperProps" needs to be exported by the entry point api-surface.d.ts
//
// @public
export function useSitecore(options?: WithSitecoreOptions): WithSitecoreProps;
export const withAppPlaceholder: <T extends ComponentProps, W extends T & WrapperProps>(Component: ComponentType<T>) => (props: W) => React_2.JSX.Element;

// Warning: (ae-forgotten-export) The symbol "ComponentProps_2" needs to be exported by the entry point api-surface.d.ts
// Warning: (ae-forgotten-export) The symbol "WrapperProps_2" needs to be exported by the entry point api-surface.d.ts
//
// @public
export const withClientPlaceholder: <T extends ComponentProps_2, W extends T & WrapperProps_2>(Component: ComponentType<T>) => (props: W) => React_2.JSX.Element;

// Warning: (ae-forgotten-export) The symbol "WithDatasourceCheckOptions" needs to be exported by the entry point api-surface.d.ts
// Warning: (ae-forgotten-export) The symbol "WithDatasourceCheckProps" needs to be exported by the entry point api-surface.d.ts
Expand All @@ -529,7 +525,10 @@ export function useSitecore(options?: WithSitecoreOptions): WithSitecoreProps;
export function withDatasourceCheck(options?: WithDatasourceCheckOptions): <ComponentProps extends WithDatasourceCheckProps>(Component: React_2.ComponentType<ComponentProps>) => (props: ComponentProps) => JSX_2.Element | null;

// @public
export const withEditorChromes: (WrappedComponent: React_2.ComponentClass<unknown> | React_2.FC<unknown>) => React_2.ComponentClass;
export const withEditorChromes: (WrappedComponent: React_2.ComponentClass<unknown> | React_2.FC<unknown>) => {
(props: Record<string, unknown>): React_2.JSX.Element;
displayName: string;
};

// Warning: (ae-forgotten-export) The symbol "WithEmptyFieldEditingComponentProps" needs to be exported by the entry point api-surface.d.ts
// Warning: (ae-forgotten-export) The symbol "WithEmptyFieldEditingComponentOptions" needs to be exported by the entry point api-surface.d.ts
Expand All @@ -542,33 +541,10 @@ export function withEmptyFieldEditingComponent<FieldComponentProps extends WithE
// @public
export function withFieldMetadata<FieldComponentProps extends WithMetadataProps, RefElementType = HTMLElement>(FieldComponent: ComponentType<FieldComponentProps>, isForwardRef?: boolean): React_2.ForwardRefExoticComponent<React_2.PropsWithoutRef<FieldComponentProps> & React_2.RefAttributes<RefElementType>> | ((props: FieldComponentProps) => React_2.JSX.Element);

// Warning: (ae-forgotten-export) The symbol "WithPlaceholderSpec" needs to be exported by the entry point api-surface.d.ts
// Warning: (ae-forgotten-export) The symbol "WithPlaceholderOptions" needs to be exported by the entry point api-surface.d.ts
//
// @public
export function withPlaceholder(placeholders: WithPlaceholderSpec, options?: WithPlaceholderOptions): (WrappedComponent: React_2.ComponentClass<PlaceholderProps> | React_2.FunctionComponent<PlaceholderProps>) => (props: EnhancedOmit<PlaceholderProps, keyof WithSitecoreProps>) => React_2.JSX.Element;

// @public (undocumented)
export function withSitecore(options?: WithSitecoreOptions): <ComponentProps extends WithSitecoreProps>(Component: React_2.ComponentType<ComponentProps>) => (props: WithSitecoreHocProps<ComponentProps>) => React_2.JSX.Element;

// @public
export type WithSitecoreHocProps<ComponentProps> = EnhancedOmit<ComponentProps, keyof WithSitecoreProps>;

// @public
export interface WithSitecoreOptions {
updatable?: boolean;
}

// @public
export interface WithSitecoreProps {
api?: SitecoreProviderState['api'];
page: Page;
updatePage?: ((value: Page) => void) | false;
}

// Warnings were encountered during analysis:
//
// src/components/FEaaS/models.ts:96:3 - (ae-forgotten-export) The symbol "RevisionType" needs to be exported by the entry point api-surface.d.ts
// src/components/SitecoreProvider.tsx:88:30 - (ae-forgotten-export) The symbol "SitecoreProviderProps" needs to be exported by the entry point api-surface.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
5 changes: 3 additions & 2 deletions packages/react/src/components/Date.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React from 'react';
import { withFieldMetadata } from '../enhancers/withFieldMetadata';
import { withEmptyFieldEditingComponent } from '../enhancers/withEmptyFieldEditingComponent';
import { DefaultEmptyFieldEditingComponentText } from './DefaultEmptyFieldEditingComponents';
Expand Down Expand Up @@ -51,7 +51,8 @@ export const DateField: React.FC<DateFieldProps> = withFieldMetadata<DateFieldPr
}

if (tag) {
return React.createElement(tag || 'span', htmlProps, children);
const Tag = (tag || 'span') as React.ElementType;
return <Tag {...htmlProps}>{children}</Tag>;
} else {
return <React.Fragment>{children}</React.Fragment>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export const DefaultEmptyFieldEditingComponentText: React.FC<{
[key: string]: unknown;
tag?: string;
}> = (props) => {
return React.createElement(
props.tag || 'span',
{ ...props, suppressHydrationWarning: true },
'[No text in field]'
const Tag = (props.tag || 'span') as React.ElementType;
return (
<Tag {...props} suppressHydrationWarning={true}>
[No text in field]
</Tag>
);
};

Expand Down
7 changes: 2 additions & 5 deletions packages/react/src/components/DesignLibrary/DesignLibrary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ import {
} from '@sitecore-content-sdk/content/editing';
import * as codegen from '@sitecore-content-sdk/content/codegen';
import * as editing from '@sitecore-content-sdk/content/editing';
import { useSitecore } from '../../enhancers/withSitecore';
import { useSitecore, useLoadImportMap } from '../../components/SitecoreProvider';
import { Placeholder, PlaceholderMetadata } from '../Placeholder';
import { DesignLibraryErrorBoundary } from './DesignLibraryErrorBoundary';
import { DynamicComponent } from './models';
import { useLoadImportMap } from '../../enhancers/withLoadImportMap';
import { ErrorComponent } from '../ErrorBoundary';

let {
Expand Down Expand Up @@ -45,8 +44,6 @@ export const __mockDependencies = (mocks: any) => {
* when generation is enabled (`page.mode.designLibrary.isVariantGeneration === true`),
* wires the **variant generation** handshake so the parent (DL Studio) can send
* generated code to preview and iterate on.
* @param {DesignLibraryProps} props
* @param {() => Promise} [props.loadImportMap] Optional async loader that resolves to the import-map used to resolve the generated component’s imports. Required when `isVariantGeneration` is true.
* @returns {JSX.Element} The preview surface, or `null` when not in Design Library mode.
* @public
*/
Expand Down Expand Up @@ -156,7 +153,7 @@ export const DesignLibrary = () => {
cancelled = true;
unsubscribe && unsubscribe();
};
}, [isVariantGeneration, uid]);
}, [isDesignLibrary, isVariantGeneration, uid, loadImportMap, propsState]);

return (
<main>
Expand Down
11 changes: 7 additions & 4 deletions packages/react/src/components/EditingScripts.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
'use client';
import React, { JSX } from 'react';
import { useSitecore } from '../enhancers/withSitecore';
import { getContentSdkPagesClientData, getDesignLibraryScriptLink } from '@sitecore-content-sdk/content/editing';
import React from 'react';
import { useSitecore } from './SitecoreProvider';
import {
getContentSdkPagesClientData,
getDesignLibraryScriptLink,
} from '@sitecore-content-sdk/content/editing';

/**
* Renders client scripts and data for editing/preview mode for Pages.
* Renders script required for the Design Library (when mode.isDesignLibrary is true).
* @returns A JSX element containing the editing scripts or an empty fragment if not in editing/preview mode.
* @public
*/
export const EditingScripts = (): JSX.Element => {
export const EditingScripts = () => {
const {
page: { mode, layout },
api,
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use client';
'use client';
import React, { ReactNode, Suspense } from 'react';
import { Page } from '@sitecore-content-sdk/content/client';
import { ComponentRendering } from '@sitecore-content-sdk/content/layout';
Expand Down
10 changes: 8 additions & 2 deletions packages/react/src/components/File.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isFieldValueEmpty } from '@sitecore-content-sdk/content/layout';
import { isFieldValueEmpty } from '@sitecore-content-sdk/content/layout';
import React from 'react';

export interface FileFieldValue {
Expand Down Expand Up @@ -48,7 +48,13 @@ export const File: React.FC<FileProps> = ({ field, children, ...otherProps }) =>
const anchorAttrs = {
href: file.src,
};
return React.createElement('a', { ...anchorAttrs, ...otherProps }, linkText, children);

return (
<a {...anchorAttrs} {...otherProps}>
{linkText}
{children}
</a>
);
};

File.displayName = 'File';
11 changes: 9 additions & 2 deletions packages/react/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React, { useEffect, useRef, useState } from 'react';
import { ComponentRendering } from '@sitecore-content-sdk/content/layout';
import { form } from '@sitecore-content-sdk/content';
import { useSitecore } from '../enhancers/withSitecore';
import { useSitecore } from './SitecoreProvider';
import { ErrorComponent } from './ErrorBoundary';

let { executeScriptElements, loadForm, subscribeToFormSubmitEvent } = form;
Expand Down Expand Up @@ -86,7 +86,14 @@ export const Form = ({ params, rendering }: FormProps) => {

executeScriptElements(formRef.current);
}
}, [content]);
}, [
content,
isEditing,
params.FormId,
rendering.uid,
context.api?.edge?.clientContextId,
context.api?.edge?.edgeUrl,
]);

if (isEditing && error) {
return <ErrorComponent message="There was a problem loading this section" />;
Expand Down
14 changes: 6 additions & 8 deletions packages/react/src/components/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use client';
'use client';
import React, { RefAttributes, forwardRef } from 'react';
import { FieldMetadata, isFieldValueEmpty } from '@sitecore-content-sdk/content/layout';
import { withFieldMetadata } from '../enhancers/withFieldMetadata';
Expand Down Expand Up @@ -91,14 +91,12 @@ export const Link: React.FC<LinkProps> = withFieldMetadata<LinkProps, HTMLAnchor
const linkText =
showLinkTextWithChildrenPresent || !children ? link.text || link.href : null;

const element = React.createElement(
'a',
{ ...anchorAttrs, ...otherProps, key: 'link', ref },
linkText,
children
return (
<a {...anchorAttrs} {...otherProps} key="link" ref={ref}>
{linkText}
{children}
</a>
);

return <React.Fragment>{element}</React.Fragment>;
}
),
{ defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText, isForwardRef: true }
Expand Down
46 changes: 46 additions & 0 deletions packages/react/src/components/Placeholder/AppPlaceholder.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,52 @@ describe('App Placeholder logic', () => {
// 4 placeholders in total, 8 code blocks
expect(wrapper?.container.querySelectorAll('.scpm').length).to.equal(8);
});

it('should use renderEach for each child in the placeholder when page editing is enabled', () => {
const page = getPage();
const components = new Map<string, React.FC>();

page.mode.isEditing = true;

components.set('Child', () => 'Child');

const route = {
name: 'Render Each Test',
placeholders: {
main: [
{
componentName: 'Child',
},
{
componentName: 'Child',
},
],
},
};
page.layout = {
sitecore: {
context: {},
route,
},
};
const phKey = 'main';

const renderedComponent = render(
<SitecoreProvider componentMap={componentMap} page={page}>
<AppPlaceholder
name={phKey}
rendering={page.layout.sitecore.route}
componentMap={components}
page={page}
render={(children) => <div className="parentWrapper">{children}</div>}
renderEach={(child) => <div className="wrapper">{child}</div>}
/>
</SitecoreProvider>
);

expect(renderedComponent.container.querySelectorAll('.parentWrapper').length).to.equal(1);
expect(renderedComponent.container.querySelectorAll('.wrapper').length).to.equal(2);
});
});
});

Expand Down
Loading
Loading