Skip to content

Commit

Permalink
wip render processed components
Browse files Browse the repository at this point in the history
  • Loading branch information
ComLock committed Nov 6, 2024
1 parent 991a0a0 commit c007533
Show file tree
Hide file tree
Showing 26 changed files with 1,213 additions and 399 deletions.
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"types": "dist/index.d.ts",
"dependencies": {
"@enonic/js-utils": "^1.8.0",
"clsx": "^2.1.1",
"domelementtype": "^2.3.0",
"html-react-parser": "^5.1.10",
"uri-js": "^4.4.1"
Expand Down
136 changes: 136 additions & 0 deletions src/ComponentRegistry/XpComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import type {Component} from '@enonic-types/core';
import type {ComponentRegistry} from '../ComponentRegistry';
// import type {MacroComponent} from './types';
import type {
DecoratedLayoutComponent,
DecoratedPageComponent,
} from '../types';

import * as React from 'react';
import {XP_COMPONENT_TYPE} from '../constants';
import {XpComponentComment} from './XpComponentComment';
// import {XpLayout} from './XpLayout';
// import {XpPage} from './XpPage';
import {XpPart} from './XpPart';
// import {RichText} from './RichText';
// import {Macro as FallbackMacro} from './RichText/Macro';
// import {replaceMacroComments} from './replaceMacroComments';


// interface RestProps {
// componentRegistry?: ComponentRegistry
// }

// const Macro: MacroComponent<RestProps> = ({
// componentRegistry,
// config,
// descriptor,
// children
// }) => {
// console.info('MacroWithComponentRegistry', {config, descriptor, children});
// if (componentRegistry) {
// // @ts-ignore
// if (descriptor === 'info') {
// const InfoMacro = componentRegistry.getMacro<{
// header: string
// text: string
// }>('macro');
// console.info(InfoMacro);
// const {
// body,
// header,
// } = config;
// console.info('MacroWithComponentRegistry', {body, header});
// return (
// <InfoMacro header={header} text={body}/>
// );
// }
// }
// return null;
// }

export function XpComponent({
component,
componentRegistry
}: {
component: Component
componentRegistry?: ComponentRegistry
}) {
if (!componentRegistry) {
return (
<XpComponentComment component={component}/>
);
}

const {
type
} = component;
// console.info('XpComponent type:', type);

if (type === XP_COMPONENT_TYPE.PART) {
return (
<XpPart
component={component}
componentRegistry={componentRegistry}
/>
);
}

if (type === XP_COMPONENT_TYPE.LAYOUT) {
const layoutDefinition = componentRegistry.getLayout(component.descriptor);
if (!layoutDefinition) {
throw new Error(`Layout definition not found for descriptor: ${component.descriptor}`);
}
const {View: LayoutView} = layoutDefinition;
if (!LayoutView) {
throw new Error(`Layout definition missing View for descriptor: ${component.descriptor}`);
}
const {props} = component as DecoratedLayoutComponent;
if (!props) {
throw new Error(`Layout component missing props: ${component.descriptor}`);
}
props.componentRegistry = componentRegistry;
return (
<LayoutView {...props}/>
);
}

if (type === XP_COMPONENT_TYPE.PAGE) {
const pageDefinition = componentRegistry.getPage(component.descriptor);
if (!pageDefinition) {
throw new Error(`Page definition not found for descriptor: ${component.descriptor}`);
}
const {View: PageView} = pageDefinition;
if (!PageView) {
throw new Error(`Page definition missing View for descriptor: ${component.descriptor}`);
}
const {props} = component as DecoratedPageComponent;
if (!props) {
throw new Error(`Page component missing props: ${component.descriptor}`);
}
props.componentRegistry = componentRegistry;
return (
<PageView {...props}/>
);
}

// if (type === XP_COMPONENT_TYPE.TEXT) {
// // console.info('XpComponent', {component});

// // const data = {};
// const data = replaceMacroComments(component.text);
// console.info('data', data);

// // componentRegistry={componentRegistry}
// // Macro={Macro}
// return (
// <RichText<RestProps>
// data={data}
// />
// );
// }

return (
<XpComponentComment component={component}/>
);
}
14 changes: 14 additions & 0 deletions src/ComponentRegistry/XpComponentComment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type {Component} from '@enonic-types/core';

export function XpComponentComment({
component
}: {
component?: Component
}): JSX.Element | null {
if (!component || !component.path) {
return null;
}
return (
<>{/*# COMPONENT ${component.path} */}</>
);
}
32 changes: 32 additions & 0 deletions src/ComponentRegistry/XpLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type {LayoutComponent} from '@enonic-types/core';
import type {ClassValue} from 'clsx';
import type {ComponentRegistry} from '../ComponentRegistry';

import cx from 'clsx';
import {XpRegions} from './XpRegions';

export function XpLayout({
as,
className,
component,
componentRegistry,
}: {
as?: string;
className?: ClassValue;
component: LayoutComponent;
componentRegistry: ComponentRegistry;
}) {
// console.debug('XpLayout component:', component.descriptor);
const {regions} = component;
const ElementType = (as || 'div') as keyof JSX.IntrinsicElements;
return (
<ElementType
className={cx(className)}
>
<XpRegions
regions={regions}
componentRegistry={componentRegistry}
/>
</ElementType>
);
}
50 changes: 50 additions & 0 deletions src/ComponentRegistry/XpPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type {
PageComponent,
PageContributions,
} from '@enonic-types/core';
import type {ClassValue} from 'clsx';
import type {ComponentRegistry} from '../ComponentRegistry';

import cx from 'clsx';
import {XpRegions} from './XpRegions';

export function XpPage({
bodyBegin,
bodyEnd,
className,
component,
componentRegistry,
headBegin,
headEnd,
title
}: {
bodyBegin?: React.ReactNode;
bodyEnd?: React.ReactNode;
className?: ClassValue
component: PageComponent
componentRegistry: ComponentRegistry
headBegin?: React.ReactNode;
headEnd?: React.ReactNode;
title?: string
}) {
const {regions} = component;
return (
<html
className={cx(className)}
>
<head>
{headBegin ? headBegin : null}
{title ? <title>{title}</title> : null}
{headEnd ? headEnd : null}
</head>
<body className="xp-page">
{bodyBegin ? bodyBegin : null}
<XpRegions
regions={regions}
componentRegistry={componentRegistry}
/>
{bodyEnd ? bodyEnd : null}
</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import type {PartComponent} from '@enonic-types/core';
// import type {PartComponent} from '@enonic-types/core';
import type {
ComponentRegistry,
DecoratedPartComponent,
} from '../types';

import type {ComponentRegistry} from '../types';
import * as React from 'react';


export function BasePart({
export function XpPart({
component,
componentRegistry
}: {
component: PartComponent
component: DecoratedPartComponent
componentRegistry: ComponentRegistry
}) {
// console.debug('BasePart component', component);
// console.info('XpPart component', component.);

const {
config: props,
descriptor
config,
props = config,
descriptor,
} = component;
// console.debug('BasePart descriptor', descriptor);
// console.debug('XpPart descriptor:', descriptor);

const partDefinition = componentRegistry.getPart(descriptor);
if (!partDefinition) {
Expand All @@ -29,5 +33,7 @@ export function BasePart({
// TODO return ErrorBoundary instead of throwing.
}
props.componentRegistry = componentRegistry;
return (<View {...props}/>);
return (
<View {...props}/>
);
}
42 changes: 42 additions & 0 deletions src/ComponentRegistry/XpRegion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type {Component} from '@enonic-types/core';
import type {ClassValue} from 'clsx';
import type {ComponentRegistry} from '../ComponentRegistry';

import cx from 'clsx';
import {XpComponent} from './XpComponent';

export const XpRegion = ({
as,
className,
components = [],
componentRegistry,
name,
}: {
as?: string
className?: ClassValue
components: Component[]
componentRegistry?: ComponentRegistry
name: string
}) => {
if (!((name || '').trim())) {
console.error(`<Region NO_NAME> name: ${JSON.stringify(name)}`);
throw Error(`Can't render <Region> without a 'name' prop.`);
}
// console.debug('XpRegion name:', name);

const ElementType = (as || 'div') as keyof JSX.IntrinsicElements;
return (
<ElementType
className={cx('xp-region', className)}
data-portal-region={name}
>
{
components.map((component, i) => <XpComponent
component={component}
componentRegistry={componentRegistry}
key={i}
/>)
}
</ElementType>
);
}
22 changes: 22 additions & 0 deletions src/ComponentRegistry/XpRegions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type {Region} from '@enonic-types/core';
import type {ComponentRegistry} from '../ComponentRegistry';

import {XpRegion} from './XpRegion';

export function XpRegions({
componentRegistry,
regions
}: {
componentRegistry: ComponentRegistry;
regions: Record<string, Region>;
}) {
// console.debug('XpRegions regions:', regions);
return Object.keys(regions).map((name, i) =>
<XpRegion
components={regions[name].components}
componentRegistry={componentRegistry}
key={`region-${i}-${name}`}
name={name}
/>
)
}
Loading

0 comments on commit c007533

Please sign in to comment.