Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sitecore-jss-react] [sitecore-jss-nextjs] Reconciled withSitecoreContext and Placeholder types #1797

Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ Our versioning strategy is as follows:

### 🛠 Breaking Change

* Editing Integration Support: ([#1776](https://github.com/Sitecore/jss/pull/1776))([#1792](https://github.com/Sitecore/jss/pull/1792)) ([#1773](https://github.com/Sitecore/jss/pull/1773))
* Editing Integration Support: ([#1776](https://github.com/Sitecore/jss/pull/1776))([#1792](https://github.com/Sitecore/jss/pull/1792)) ([#1773](https://github.com/Sitecore/jss/pull/1773))([#1797](https://github.com/Sitecore/jss/pull/1797))
* `[sitecore-jss-react]` Introduces `PlaceholderMetadata` component which supports the hydration of chromes on Pages by rendering the components and placeholders with required metadata.
* `[sitecore-jss]` Chromes are hydrated based on the basis of new `editMode` property derived from LayoutData, which is defined as an enum consisting of `metadata` and `chromes`.
* `[sitecore-jss-react]` _sitecoreContext_ property within the `WithSitecoreContextProps` interface has been made optional. If you use _withSitecoreContext_ HOC please add safegaurds for scenarios where `sitecoreContext` could be undefined.
* `WithSitecoreContextHocProps` is now deprecated and removed. Please use your own component prop types.
* `ComponentConsumerProps` is removed. You might need to reuse _WithSitecoreContextProps_ type.
* `[sitecore-jss-react]` `[sitecore-jss-nextjs]` Introduce FieldMetadata component and functionality to render it when metadata field property is provided in the field's layout data. In such case the field component is wrapped with metadata markup to enable chromes hydration when editing in pages. Ability to render metadata has been added to the field rendering components for react and nextjs.

## 22.0.0
Expand Down
3 changes: 1 addition & 2 deletions docs/upgrades/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
# react

* With the simplification of Editing Support work we have added the following breaking changes to the `sitecore-jss-react` package. Please make the necessary updates.
- `sitecoreContext` property within the `WithSitecoreContextProps` interface has been made optional. Please add safegaurds for scenarios where `sitecoreContext` could be undefined.
- `WithSitecoreContextHocProps` is now deprecated and removed. We suggest that you define and use your own component prop types.
- `ComponentConsumerProps` is removed. You might need to reuse _WithSitecoreContextProps_ type.

### headless-ssr-experience-edge
* Replace `scripts/generate-config.js` if you have not modified it. Otherwise:
Expand Down
9 changes: 8 additions & 1 deletion packages/sitecore-jss-nextjs/src/components/Placeholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ import React, { useContext } from 'react';
import {
Placeholder as ReactPlaceholder,
PlaceholderComponentProps,
WithSitecoreContextProps,
EnhancedOmit,
} from '@sitecore-jss/sitecore-jss-react';
import { ComponentPropsReactContext } from './ComponentPropsContext';

export const Placeholder = (props: PlaceholderComponentProps) => {
/**
* React Placeholder component wrapped by withSitecoreContext, so these properties shouldn't be passed to the Next.js Placeholder.
*/
type PlaceholderProps = EnhancedOmit<PlaceholderComponentProps, keyof WithSitecoreContextProps>;

export const Placeholder = (props: PlaceholderProps) => {
const componentPropsContext = useContext(ComponentPropsReactContext);

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/sitecore-jss-nextjs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ export {
withPlaceholder,
withDatasourceCheck,
ImageSizeParameters,
ComponentConsumerProps,
WithSitecoreContextOptions,
WithSitecoreContextProps,
WithSitecoreContextHocProps,
withFieldMetadata,
} from '@sitecore-jss/sitecore-jss-react';
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ export interface PlaceholderProps {
/**
* Context data from the Sitecore Layout Service
*/
sitecoreContext?: SitecoreContextValue;

sitecoreContext: SitecoreContextValue;
/**
* The message that gets displayed while component is loading
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { shallow } from 'enzyme';

import { SitecoreContext } from './SitecoreContext';
import { ComponentFactory } from './sharedTypes';
import { withSitecoreContext, ComponentConsumerProps } from '../enhancers/withSitecoreContext';
import { WithSitecoreContextProps, withSitecoreContext } from '../enhancers/withSitecoreContext';
import { LayoutServiceData } from '../index';

interface NestedComponentProps extends ComponentConsumerProps {
interface NestedComponentProps extends WithSitecoreContextProps {
anotherProperty?: string;
}
const NestedComponent: FC<NestedComponentProps> = (props: NestedComponentProps) => (
Expand Down
30 changes: 15 additions & 15 deletions packages/sitecore-jss-react/src/enhancers/withFieldMetadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@ export function withFieldMetadata<
>(FieldComponent: ComponentType<FieldComponentProps>, isForwardRef = false) {
if (isForwardRef) {
// eslint-disable-next-line react/display-name
return forwardRef(
({ ...props }: FieldComponentProps, ref: React.ForwardedRef<RefElementType>) => {
const metadata = props.field?.metadata;
return forwardRef((props: FieldComponentProps, ref: React.ForwardedRef<RefElementType>) => {
const { editable = true } = props;
const metadata = props.field?.metadata;

if (!metadata || !props.editable) {
return <FieldComponent {...props} ref={ref} />;
}

return (
<FieldMetadata metadata={metadata}>
<FieldComponent {...props} ref={ref} />
</FieldMetadata>
);
if (!metadata || !editable) {
return <FieldComponent {...props} ref={ref} />;
}
);

return (
<FieldMetadata metadata={metadata}>
<FieldComponent {...props} ref={ref} />
</FieldMetadata>
);
});
}

// eslint-disable-next-line react/display-name
return ({ ...props }: FieldComponentProps) => {
return (props: FieldComponentProps) => {
const { editable = true } = props;
const metadata = props.field?.metadata;

if (!metadata || !props.editable) {
if (!metadata || !editable) {
return <FieldComponent {...props} />;
}

Expand Down
18 changes: 11 additions & 7 deletions packages/sitecore-jss-react/src/enhancers/withSitecoreContext.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import React, { ReactNode } from 'react';
import React from 'react';
import { EnhancedOmit } from '@sitecore-jss/sitecore-jss/utils';
import { SitecoreContextReactContext, SitecoreContextValue } from '../components/SitecoreContext';

export interface WithSitecoreContextOptions {
updatable?: boolean;
}

// The props that HOC will inject
export interface WithSitecoreContextProps {
sitecoreContext?: SitecoreContextValue;
sitecoreContext: SitecoreContextValue;
updateSitecoreContext?: ((value: SitecoreContextValue) => void) | false;
}

export interface ComponentConsumerProps extends WithSitecoreContextProps {
children?: ReactNode;
}
// The props that HOC will receive.
export type WithSitecoreContextHocProps<ComponentProps> = EnhancedOmit<
illiakovalenko marked this conversation as resolved.
Show resolved Hide resolved
ComponentProps,
keyof WithSitecoreContextProps
>;

/**
* @param {WithSitecoreContextOptions} [options]
*/
export function withSitecoreContext(options?: WithSitecoreContextOptions) {
return function withSitecoreContextHoc<ComponentProps extends ComponentConsumerProps>(
return function withSitecoreContextHoc<ComponentProps extends WithSitecoreContextProps>(
Component: React.ComponentType<ComponentProps>
) {
return function WithSitecoreContext(props: ComponentProps) {
return function WithSitecoreContext(props: WithSitecoreContextHocProps<ComponentProps>) {
return (
<SitecoreContextReactContext.Consumer>
{(context) => (
Expand Down
3 changes: 2 additions & 1 deletion packages/sitecore-jss-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export {
FieldEditButton,
WebEditButton,
EditButtonTypes,
EnhancedOmit,
} from '@sitecore-jss/sitecore-jss/utils';
export {
getContentStylesheetLink,
Expand Down Expand Up @@ -92,9 +93,9 @@ export {
export {
withSitecoreContext,
useSitecoreContext,
ComponentConsumerProps,
WithSitecoreContextOptions,
WithSitecoreContextProps,
WithSitecoreContextHocProps,
} from './enhancers/withSitecoreContext';
export { withEditorChromes } from './enhancers/withEditorChromes';
export { withPlaceholder } from './enhancers/withPlaceholder';
Expand Down
2 changes: 1 addition & 1 deletion packages/sitecore-jss/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { default as isServer } from './is-server';
export { resolveUrl, isAbsoluteUrl, isTimeoutError } from './utils';
export { resolveUrl, isAbsoluteUrl, isTimeoutError, EnhancedOmit } from './utils';
export { tryParseEnvValue } from './env';
export {
ExperienceEditor,
Expand Down
7 changes: 7 additions & 0 deletions packages/sitecore-jss/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { ParsedUrlQueryInput } from 'querystring';
import { AxiosError } from 'axios';
import { ResponseError } from '../data-fetcher';

/**
* Omit properties from T that are in K. This is a simplified version of TypeScript's built-in `Omit` utility type.
* Since default `Omit` doesn't support indexing types, we had to introduce this custom implementation.
*/
// eslint-disable-next-line prettier/prettier
export type EnhancedOmit<T, K extends PropertyKey> = { [P in keyof T as Exclude<P, K>]: T[P] };

/**
* note: encodeURIComponent is available via browser (window) or natively in node.js
* if you use another js engine for server-side rendering you may not have native encodeURIComponent
Expand Down