Skip to content

Commit

Permalink
Fix #1164 POC: Render using a single catchAll siteMapping
Browse files Browse the repository at this point in the history
  • Loading branch information
ComLock committed Nov 8, 2024
1 parent b007554 commit 339c6eb
Show file tree
Hide file tree
Showing 19 changed files with 207 additions and 96 deletions.
6 changes: 6 additions & 0 deletions src/main/resources/react4xp/entries/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import type {DecoratedComponent} from '@enonic/react-components';

// import { toStr } from '@enonic/js-utils/value/toStr';
import * as React from 'react';

import {XpComponent} from '@enonic/react-components';
import {componentRegistry} from '../componentRegistry';

export interface AppProps {
component: DecoratedComponent
}

export default (props) => {
props.componentRegistry = componentRegistry;
// console.info('App props sent to XpComponent:', toStr(props));
Expand Down
38 changes: 16 additions & 22 deletions src/main/resources/react4xp/layouts/TwoColumnsLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,28 @@
// import type {Region} from '@enonic-types/core';
import type {ComponentRegistry} from '@enonic/react-components';

import { toStr } from '@enonic/js-utils/value/toStr';
import {XpRegions} from '@enonic/react-components';
// import { toStr } from '@enonic/js-utils/value/toStr';
import {XpLayout} from '@enonic/react-components';
import * as React from 'react';
// import dayjs from 'dayjs';

export interface TwoColumnsLayoutProps {
componentRegistry?: ComponentRegistry;
componentRegistry: ComponentRegistry;
// regions: Record<string, Region>;
regions: Record<string, unknown>;
}

export function TwoColumnsLayout (props: TwoColumnsLayoutProps) {
console.debug('TwoColumnsLayout props:', toStr(props));
const regionsProps = {
componentRegistry: props.componentRegistry,
regions: props.regions
};
console.debug('TwoColumnsLayout regionsProps:', toStr(regionsProps));
return <div data-portal-component-type="layout">
<div style={{
columnGap: '1em',
display: 'grid',
gridTemplateColumns: '1fr 1fr'
}}>
{/* @ts-ignore */}

<XpRegions {...regionsProps}/>
{/* <div>Layout: {dayjs().format()}</div> */}
</div>
</div>;
// console.debug('TwoColumnsLayout props:', toStr(props));
return (
// @ts-expect-error regions not compatible
<XpLayout
as="layout"
{...props}
style={{
columnGap: '1em',
display: 'grid',
gridTemplateColumns: '1fr 1fr'
}}>
</XpLayout>
);
}
10 changes: 5 additions & 5 deletions src/main/resources/react4xp/macros/panel.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?dufvmt');
src: url('fonts/icomoon.eot?dufvmt#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?dufvmt') format('truetype'),
url('fonts/icomoon.woff?dufvmt') format('woff'),
url('fonts/icomoon.svg?dufvmt#icomoon') format('svg');
src: url('../fonts/icomoon.eot?dufvmt');
src: url('../fonts/icomoon.eot?dufvmt#iefix') format('embedded-opentype'),
url('../fonts/icomoon.ttf?dufvmt') format('truetype'),
url('../fonts/icomoon.woff?dufvmt') format('woff'),
url('../fonts/icomoon.svg?dufvmt#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
Expand Down
24 changes: 15 additions & 9 deletions src/main/resources/react4xp/pages/DefaultPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
// import type {Region} from '@enonic-types/core';
// import type {ComponentRegistry} from '@enonic/react-components';

// import './default.sass'; // Create Error reference failed
import './default.sass'; // Create Error reference failed
// import { toStr } from '@enonic/js-utils/value/toStr';
import {
ComponentRegistry,
XpRegions
XpPage
} from '@enonic/react-components';
import dayjs from 'dayjs';
// import dayjs from 'dayjs';
import * as React from 'react';


export interface DefaultPageProps {
componentRegistry?: ComponentRegistry;
componentRegistry: ComponentRegistry;
// regions: Record<string, Region>;
regions: Record<string, unknown>;
}
Expand All @@ -21,10 +22,15 @@ export interface DefaultPageProps {
export function DefaultPage(props: DefaultPageProps) {
// console.info('DefaultPage props:', toStr(props));
return (
<div className="default-page">
{/* @ts-ignore */}
<XpRegions {...props} />
<div>Page: {dayjs().format()}</div>
</div>
// @ts-expect-error regions not compatible
<XpPage
as='main'
className="default-page"
{...props}
>
{/* Warning: Text content did not match. Server: "2024-11-08T09:36:59+01:00" Client: "2024-11-08T09:37:00+01:00" */}
{/* Uncaught Error: Text content does not match server-rendered HTML. */}
{/* <div>Page: {dayjs().format()}</div> */}
</XpPage>
);
}
4 changes: 2 additions & 2 deletions src/main/resources/react4xp/pages/default.sass
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@font-face
font-family: 'Open Sans'
src: url("./font/opensans-regular.eot")
src: url("./font/opensans-regular.eot?#iefix") format("embedded-opentype"), url("./font/opensans-regular.woff") format("woff"), url("./font/opensans-regular.ttf") format("truetype"), url("./font/opensans-regular.svg#open_sansregular") format("svg")
src: url("../fonts/opensans-regular.eot")
src: url("../fonts/opensans-regular.eot?#iefix") format("embedded-opentype"), url("../fonts/opensans-regular.woff") format("woff"), url("../fonts/opensans-regular.ttf") format("truetype"), url("../fonts/opensans-regular.svg#open_sansregular") format("svg")

body
font-family: 'Open Sans', sans-serif
17 changes: 14 additions & 3 deletions src/main/resources/react4xp/parts/ExamplePart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import type {

import './example.sass';
import * as React from 'react';
import {RichText} from '@enonic/react-components';
import {
RichText,
XpPart,
} from '@enonic/react-components';

export interface ExampleProps {
data: RichTextData;
Expand All @@ -16,16 +19,24 @@ export function ExamplePart({
componentRegistry,
data
}: ExampleProps) {
const [text, setText] = React.useState('initial state');
React.useEffect(()=> {
// console.info('ExamplePart useEffect');
setText('useEffect state');
}, [])
// console.info('ExamplePart data', data);
if (!data) {
return <div>Example Part: Please fill in the htmlArea.</div>;
}
return (
<div data-portal-component-type="part">
<XpPart
as='part'
>
<p>{text}</p>
<RichText
componentRegistry={componentRegistry}
data={data}
/>
</div>
</XpPart>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { toStr } from '@enonic/js-utils/value/toStr';
import type {AppProps} from '/react4xp/entries/App';

// import { toStr } from '@enonic/js-utils/value/toStr';
// import {get as getContentByKey} from '/lib/xp/content';
// import {
// getComponent as getComponentSchema,
Expand All @@ -19,27 +21,30 @@ import {componentProcessor} from '/site/controllers/componentProcessor';
// import {toHtml} from 'hast-util-to-html'

export function get(request) {
// log.info('react4xp controller request:%s', toStr(request));
// log.info('app controller request:%s', toStr(request));

const content = getContent();
// log.info('react4xp controller content:%s', toStr(content));
// log.info('app controller content:%s', toStr(content));

const {
fragment,
page
} = content;
// const {
// fragment,
// page
// } = content;

const component = page || fragment;
// const component = page || fragment;
// log.info('app controller component:%s', toStr(component));

const decoratedComponent = componentProcessor.process({
component,
content,
// component,
// content,
request
});
// log.info('react4xp controller decoratedComponent:%s', toStr(decoratedComponent));
// log.info('app controller decoratedComponent:%s', toStr(decoratedComponent));

const {props} = decoratedComponent;
// log.info('react4xp controller props:%s', toStr(props));
const props: AppProps = {
component: decoratedComponent
}
// log.info('app controller props:%s', toStr(props));

const react4xpId = `react4xp_${content._id}`;

Expand All @@ -48,7 +53,7 @@ export function get(request) {
<meta charset="UTF-8">
<title>${content.displayName}</title>
</head>
<body class="xp-page" data-portal-component-type="page">
<body>
<div id="${react4xpId}"></div>
</body>
</html>`;
Expand All @@ -67,8 +72,8 @@ export function get(request) {

// If your page react component doesn't use fetch or hooks you may
// disable hydration:
hydrate: false,
// hydrate: true, // TODO: Error: Hydration failed because the initial UI does not match what was rendered on the server.
// hydrate: false,
hydrate: true, // TODO: Error: Hydration failed because the initial UI does not match what was rendered on the server.

// Client-side rendering of page isn't fully supported yet.
// Therefore the default is SSR with hydration even when
Expand All @@ -89,23 +94,23 @@ export function get(request) {
}
);

const {
body,
pageContributions,
status,
...rest
} = output;
log.info('react4xp controller body:%s', body);
// log.info('react4xp controller body:%s', format(body, " ", 80));
// log.info('react4xp controller body:%s', toDiffableHtml(body));
// const {
// body,
// pageContributions,
// status,
// ...rest
// } = output;
// log.info('app controller body:%s', body);
// log.info('app controller body:%s', format(body, " ", 80));
// log.info('app controller body:%s', toDiffableHtml(body));

// NOPE drags in entities with Uint16Array
// const tree = fromHtml(body);
// format(tree);
// const formattedBody = toHtml(tree);
// log.info('react4xp controller body:%s', formattedBody);
// log.info('app controller body:%s', formattedBody);

// log.info('react4xp controller pageContributions:%s', toStr(pageContributions));
// log.info('react4xp controller rest:%s', toStr(rest));
// log.info('app controller pageContributions:%s', toStr(pageContributions));
// log.info('app controller rest:%s', toStr(rest));
return output;
}
39 changes: 29 additions & 10 deletions src/main/resources/site/controllers/componentProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
// import { toStr } from '@enonic/js-utils/value/toStr';
import { toStr } from '@enonic/js-utils/value/toStr';
import {get as getContentByKey} from '/lib/xp/content';
import {
getComponent as getComponentSchema,
listSchemas
} from '/lib/xp/schema';
import {processHtml} from '/lib/xp/portal';
import {ComponentProcessor} from '@enonic/react-components/processComponents';
import {
getContent as getCurrentContent,
getSiteConfig as getCurrentSiteConfig,
processHtml
} from '/lib/xp/portal';
import {ComponentProcessor} from '@enonic/react-components/ComponentProcessor';

export const componentProcessor = new ComponentProcessor({
getComponentSchema,
getContentByKey,
getCurrentContent,
getCurrentSiteConfig,
listSchemas,
processHtml
});
Expand All @@ -20,8 +26,15 @@ componentProcessor.addPart('com.enonic.app.react4xp:example', {
content,
processedConfig,
request,
siteConfig,
}) => {
// log.info('part toProps:%s', toStr({ component, content, processedConfig, request }));
// log.info('part toProps:%s', toStr({
// // component,
// // content,
// // processedConfig,
// // request,
// siteConfig
// }));
return {
data: processedConfig.anHtmlArea
};
Expand All @@ -35,8 +48,15 @@ componentProcessor.addLayout("com.enonic.app.react4xp:twoColumns", {
processedComponent,
processedConfig,
request,
siteConfig,
}) => {
// log.info('layout toProps:%s', toStr({ component, content, processedConfig, request }));
// log.info('layout toProps:%s', toStr({
// // component,
// // content,
// // processedConfig,
// // request,
// siteConfig,
// }));
const {regions} = processedComponent;
// const {mode} = request;
// log.info('mode:%s', mode);
Expand Down Expand Up @@ -64,12 +84,14 @@ componentProcessor.addPage("com.enonic.app.react4xp:default", {
processedComponent,
processedConfig,
request,
siteConfig,
}) => {
// log.info('page toProps:%s', toStr({
// component,
// // component,
// // content,
// // processedConfig,
// // request,
// siteConfig,
// }));
const {regions} = processedComponent;
// const {mode} = request;
Expand All @@ -78,11 +100,8 @@ componentProcessor.addPage("com.enonic.app.react4xp:default", {
components: []
};
}
processedComponent.props = { // The props that DefaultPage will receive
return {
regions
}
return { // The props that XpComponent will receive
component: processedComponent,
};
},
});
Loading

0 comments on commit 339c6eb

Please sign in to comment.