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] Add support for chrome's hydration for fields #1773

Merged
merged 51 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4aea79e
render field metadata for Text field component; introduce field metad…
yavorsk Apr 11, 2024
5c4d4f9
rename FieldMetadata module, add unit test for Text component, add co…
yavorsk Apr 12, 2024
b23334a
add field metadata component to Date, Image and File field components…
yavorsk Apr 12, 2024
889b81e
add field metadata component to link and richtext field components, i…
yavorsk Apr 12, 2024
a8591e9
update FieldMetadata interfaces to prevent build errors in sitecore-j…
yavorsk Apr 12, 2024
f5641e4
export fieldmetadata component and interfaces from sitecore-jss-react
yavorsk Apr 12, 2024
5d16054
add metadata component for nextjs link field component; include unit …
yavorsk Apr 12, 2024
f8cfc3d
add field metadata component to nextimage component; small fix in lin…
yavorsk Apr 12, 2024
dcab12f
unit tests for FieldMetadata
yavorsk Apr 12, 2024
64431fb
update unit test
yavorsk Apr 12, 2024
6a05025
introduce getFieldMetadataMarkup function and used in the field compo…
yavorsk Apr 15, 2024
2e3362c
update changelog
yavorsk Apr 15, 2024
1141690
react - use higher order component to wrap metadata around field comp…
yavorsk Apr 16, 2024
08df912
update nextjs components to use metadata wrapper hoc; aadjust unit tests
yavorsk Apr 16, 2024
752506f
adjust unit tests and fix File component
yavorsk Apr 16, 2024
03b9de9
adjust image field tests; include check for media property in metadat…
yavorsk Apr 16, 2024
ecc5d82
some types updates
yavorsk Apr 16, 2024
4d23b39
some unit tests adjustments and metadata wrapper component update
yavorsk Apr 17, 2024
0b05351
some FieldMetadata related renamings
yavorsk Apr 17, 2024
46481cd
add unit test for RichText nextjs component
yavorsk Apr 17, 2024
cd24bb9
update changelog
yavorsk Apr 17, 2024
0a5c3d5
update changelog pull request
yavorsk Apr 17, 2024
77ccdcd
some type updates
yavorsk Apr 17, 2024
6c74f77
reenable file tests
yavorsk Apr 17, 2024
d5dcd8d
update function description
yavorsk Apr 17, 2024
69fe14b
minor variable renaming
yavorsk Apr 17, 2024
fcb38b9
remove unnecessary commented line
yavorsk Apr 17, 2024
8c47f76
remove unnecessary undefined check
yavorsk Apr 17, 2024
19333b2
move FieldMetada interfaces to base package; extract metadata proptypes
yavorsk Apr 17, 2024
04afea6
move FieldMetadata under enchancments
yavorsk Apr 17, 2024
6c63e83
Merge branch 'feature/JSS-1827' of https://github.com/Sitecore/jss in…
yavorsk Apr 17, 2024
581527e
added some descriptions
yavorsk Apr 17, 2024
32deed2
move and rename FieldMetadata to layout submodule of base package
yavorsk Apr 18, 2024
a0115fd
rename FieldMetadata component
yavorsk Apr 18, 2024
8095600
add tsdoc description for fieldmetadata component
yavorsk Apr 18, 2024
d749ad9
conditionally forwardRef in fieldMetadata
yavorsk Apr 18, 2024
dde6878
two separate withFieldMetadata functions based on if used with forwar…
yavorsk Apr 18, 2024
5cd3c75
single withFieldMetadata function with forwardref parameter
yavorsk Apr 19, 2024
633e322
update with metadata unit test to test the whole structure of markup
yavorsk Apr 19, 2024
c12dbb8
withMetadata refactoring wip
yavorsk Apr 19, 2024
13473fd
Adjusted withFieldMetadata generic type
illiakovalenko Apr 19, 2024
9120a7b
update unit test
yavorsk Apr 22, 2024
e6252f6
wip - refactor field metadata hoc
yavorsk Apr 22, 2024
d5f49e9
Updates
illiakovalenko Apr 23, 2024
6842fc8
Merge branch 'dev' of https://github.com/Sitecore/jss into feature/JS…
illiakovalenko Apr 23, 2024
8277ee6
Updated unit tests, simplified types
illiakovalenko Apr 23, 2024
f8e8232
Update
illiakovalenko Apr 23, 2024
15c9f40
Expose withFieldMetadata as a part of nextjs sdk
illiakovalenko Apr 23, 2024
bdbddd8
Updated PropTypes
illiakovalenko Apr 23, 2024
c86c0d2
Removed extra asserts
illiakovalenko Apr 23, 2024
59cf116
remove media property from propTypes
yavorsk Apr 24, 2024
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: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Our versioning strategy is as follows:

## Unreleased

### 🎉 New Features & Improvements
* `[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 FieldMetadaComponent should be rendered instead of the actual field component to enable chrome's hydration when editing in pages. Ability to render metadata has been added to the field rendering components for react and nextjs. ([#1773](https://github.com/Sitecore/jss/pull/1773))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `[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 FieldMetadaComponent should be rendered instead of the actual field component to enable chrome's hydration when editing in pages. Ability to render metadata has been added to the field rendering components for react and nextjs. ([#1773](https://github.com/Sitecore/jss/pull/1773))
* `[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 FieldMetada should be rendered instead of the actual field component to enable chrome's hydration when editing in Pages. Ability to render metadata has been added to the field rendering components for react and nextjs. ([#1773](https://github.com/Sitecore/jss/pull/1773))


## 21.7.1

### 🐛 Bug Fixes
Expand Down
35 changes: 35 additions & 0 deletions packages/sitecore-jss-nextjs/src/components/Link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,39 @@ describe('<Link />', () => {
const rendered = mount(<Link field={field} />).children();
expect(rendered).to.have.length(0);
});

it('should render field metadata component when metadata property is present', () => {
const field = {
value: {
href: '/lorem',
text: 'ipsum',
class: 'my-link',
},
};

const testMetadata = {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
language: 'en',
revision: 'a0b36ce0a7db49418edf90eb9621e145',
version: 1,
},
fieldId: '{414061F4-FBB1-4591-BC37-BFFA67F745EB}',
fieldType: 'single-line',
rawValue: 'Test1',
};

const rendered = mount(
<Page>
<Link field={field} metadata={testMetadata} />
</Page>
);

expect(rendered.find('code')).to.have.length(2);
expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
expect(rendered.html()).to.not.contain(`href="${field.value.href}"`);
expect(rendered.find(NextLink).length).to.equal(0);
expect(rendered.find(ReactLink).length).to.equal(0);
});
});
7 changes: 7 additions & 0 deletions packages/sitecore-jss-nextjs/src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
LinkField,
LinkProps as ReactLinkProps,
LinkPropTypes,
getFieldMetadataMarkup,
} from '@sitecore-jss/sitecore-jss-react';

export type LinkProps = ReactLinkProps & {
Expand All @@ -22,6 +23,7 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
const {
field,
editable,
metadata,
children,
internalLinkMatcher = /^\//g,
showLinkTextWithChildrenPresent,
Expand All @@ -35,6 +37,11 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
return null;
}

// when metadata is present, render it to be used for chrome hydration
if (metadata) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to continue to respect the (user-defined) editable prop for all of these

Suggested change
if (metadata) {
if (metadata && editable) {

return getFieldMetadataMarkup(metadata, children);
}

const value = ((field as LinkFieldValue).href
? field
: (field as LinkField).value) as LinkFieldValue;
Expand Down
23 changes: 23 additions & 0 deletions packages/sitecore-jss-nextjs/src/components/NextImage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,27 @@ describe('<NextImage />', () => {
);
});
});

it('should render field metadata component when metadata property is present', () => {
const testMetadata = {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
language: 'en',
revision: 'a0b36ce0a7db49418edf90eb9621e145',
version: 1,
},
fieldId: '{414061F4-FBB1-4591-BC37-BFFA67F745EB}',
fieldType: 'image',
rawValue: 'Test1',
};

const field = { value: { src: '/assets/img/test0.png', alt: 'my image' } };

const rendered = mount(<NextImage field={field} metadata={testMetadata} />);

expect(rendered.find('code')).to.have.length(2);
expect(rendered.find('img')).to.have.length(0);
expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
});
});
8 changes: 7 additions & 1 deletion packages/sitecore-jss-nextjs/src/components/NextImage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { mediaApi } from '@sitecore-jss/sitecore-jss/media';
import PropTypes from 'prop-types';
import React from 'react';

import {
getEEMarkup,
ImageProps,
ImageField,
ImageFieldValue,
getFieldMetadataMarkup,
} from '@sitecore-jss/sitecore-jss-react';
import Image, { ImageProps as NextImageProperties } from 'next/image';

Expand All @@ -16,6 +16,7 @@ export const NextImage: React.FC<NextImageProps> = ({
editable,
imageParams,
field,
metadata,
mediaUrlPrefix,
fill,
priority,
Expand All @@ -36,6 +37,11 @@ export const NextImage: React.FC<NextImageProps> = ({
return null;
}

// when metadata is present, render it to be used for chrome hydration
if (metadata) {
return getFieldMetadataMarkup(metadata, otherProps.children);
}

const imageField = dynamicMedia as ImageField;

// we likely have an experience editor value, should be a string
Expand Down
27 changes: 26 additions & 1 deletion packages/sitecore-jss-react/src/components/Date.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-unused-expressions */
import { expect } from 'chai';
import { shallow } from 'enzyme';
import { mount, shallow } from 'enzyme';
import React from 'react';
import { DateField } from './Date';

Expand Down Expand Up @@ -81,4 +81,29 @@ describe('<DateField />', () => {

expect(c.html()).equal('<span><h1 class="super">11-23-2001</h1></span>');
});

it('should render field metadata component when metadata property is present', () => {
const props = {
field: {
value: '23-11-2001',
},
metadata: {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
language: 'en',
revision: 'a0b36ce0a7db49418edf90eb9621e145',
version: 1,
},
fieldId: '{414061F4-FBB1-4591-BC37-BFFA67F745EB}',
fieldType: 'date',
rawValue: 'Test1',
},
};

const rendered = mount(<DateField {...props} />);

expect(rendered.find('code')).to.have.length(2);
expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
});
});
22 changes: 22 additions & 0 deletions packages/sitecore-jss-react/src/components/Date.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FieldMetadata, getFieldMetadataMarkup } from './FieldMetadata';

export interface DateFieldProps {
/** The date field data. */
Expand All @@ -19,11 +20,16 @@ export interface DateFieldProps {
*/
editable?: boolean;
render?: (date: Date | null) => React.ReactNode;
/**
* The field metadata; when present it should be exposed for chrome hydration process when rendering in Pages
*/
metadata?: FieldMetadata;
}

export const DateField: React.FC<DateFieldProps> = ({
field,
tag,
metadata,
editable,
render,
...otherProps
Expand All @@ -32,6 +38,11 @@ export const DateField: React.FC<DateFieldProps> = ({
return null;
}

// when metadata is present, render it to be used for chrome hydration
if (metadata) {
return getFieldMetadataMarkup(metadata, otherProps.children);
}

let children: React.ReactNode;

const htmlProps: {
Expand Down Expand Up @@ -64,6 +75,17 @@ DateField.propTypes = {
editable: PropTypes.string,
}).isRequired,
tag: PropTypes.string,
metadata: PropTypes.shape({
contextItem: PropTypes.shape({
id: PropTypes.string,
language: PropTypes.string,
revision: PropTypes.string,
version: PropTypes.number,
}),
fieldId: PropTypes.string,
fieldType: PropTypes.string,
rawValue: PropTypes.string,
}),
editable: PropTypes.bool,
render: PropTypes.func,
};
Expand Down
114 changes: 114 additions & 0 deletions packages/sitecore-jss-react/src/components/FieldMetadata.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/* eslint-disable no-unused-expressions */
import React from 'react';
import { expect } from 'chai';
import { mount, render } from 'enzyme';

import {
FieldMetadataComponent,
FieldMetadataComponentProps,
getFieldMetadataMarkup,
} from './FieldMetadata';
import { describe } from 'node:test';
import { json } from 'stream/consumers';

describe('<FieldMetadataComponent />', () => {
const testMetadata = {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
language: 'en',
revision: 'a0b36ce0a7db49418edf90eb9621e145',
version: 1,
},
fieldId: '{414061F4-FBB1-4591-BC37-BFFA67F745EB}',
fieldType: 'single-line',
rawValue: 'Test1',
};
const stringifiedData = JSON.stringify(testMetadata);

it('Should render provided metadata', () => {
const props: FieldMetadataComponentProps = {
data: stringifiedData,
};

const rendered = mount(<FieldMetadataComponent {...props} />);

expect(rendered.find('code')).to.have.length(2);
expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
expect(rendered.html()).to.include(stringifiedData);
});

it('Should render with provided children', () => {
const props: FieldMetadataComponentProps = {
data: stringifiedData,
};

const rendered = mount(
<FieldMetadataComponent {...props}>
<div>nested</div>
</FieldMetadataComponent>
);

expect(rendered.find('code')).to.have.length(2);
expect(rendered.find('div')).to.have.length(1);
expect(rendered.html()).to.include('nested');
});

it('Should render with default attributes', () => {
const props: FieldMetadataComponentProps = {
data: stringifiedData,
};

const rendered = mount(<FieldMetadataComponent {...props} />);

expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
expect(rendered.html()).to.contain('type="text/sitecore"');
expect(rendered.html()).to.contain('chrometype="field"');
expect(rendered.html()).to.contain('class="scpm"');
});

it('Should render with provided attributes', () => {
const props: FieldMetadataComponentProps = {
data: stringifiedData,
htmlAttributes: {
chrometype: 'foo',
type: 'bar',
className: 'far',
},
};

const rendered = mount(<FieldMetadataComponent {...props} />);

expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
expect(rendered.html()).to.contain('type="bar"');
expect(rendered.html()).to.contain('chrometype="foo"');
expect(rendered.html()).to.contain('class="far"');
});
});

describe('getFieldMetadataMarkup', () => {
it('Should render component with provided metadata and children ', () => {
const testMetadata = {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
language: 'en',
revision: 'a0b36ce0a7db49418edf90eb9621e145',
version: 1,
},
fieldId: '{414061F4-FBB1-4591-BC37-BFFA67F745EB}',
fieldType: 'single-line',
rawValue: 'Test1',
};

const div = <div>nested</div>;

const rendered = mount(getFieldMetadataMarkup(testMetadata, div));
expect(rendered.find('code')).to.have.length(2);
expect(rendered.html()).to.contain('kind="open"');
expect(rendered.html()).to.contain('kind="close"');
expect(rendered.html()).to.include(JSON.stringify(testMetadata));
expect(rendered.html()).to.include('<div>nested</div>');
});
});
Loading