@enonic/nextjs-adapter 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ComponentRegistry.d.ts +2 -2
- package/guillotine/fetchContent.d.ts +1 -0
- package/guillotine/fetchContent.js +34 -17
- package/package.json +10 -10
- package/views/Region.jsx +1 -6
- package/views/StaticContent.d.ts +15 -0
- package/views/StaticContent.jsx +38 -0
package/ComponentRegistry.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export interface ComponentDefinition {
|
|
|
14
14
|
processor?: DataProcessor;
|
|
15
15
|
view?: React.FunctionComponent<any>;
|
|
16
16
|
}
|
|
17
|
-
export type DataProcessor = (data: any, context?: Context) => Promise<Record<string, any>>;
|
|
17
|
+
export type DataProcessor = (data: any, context?: Context, config?: any) => Promise<Record<string, any>>;
|
|
18
18
|
export type VariablesGetter = (path: string, context?: Context, config?: any) => VariablesGetterResult;
|
|
19
|
-
export type QueryGetter = (config?: any) => string;
|
|
19
|
+
export type QueryGetter = (path: string, context?: Context, config?: any) => string;
|
|
20
20
|
export type VariablesGetterResult = {
|
|
21
21
|
[variables: string]: any;
|
|
22
22
|
path: string;
|
|
@@ -40,6 +40,7 @@ export interface ServerSideParams extends ParsedUrlQuery {
|
|
|
40
40
|
export interface PreviewParams {
|
|
41
41
|
contentPath: string[];
|
|
42
42
|
headers: Record<string, string>;
|
|
43
|
+
params: Record<string, string>;
|
|
43
44
|
}
|
|
44
45
|
export type Context = GetServerSidePropsContext<ServerSideParams, PreviewParams>;
|
|
45
46
|
export interface MinimalContext {
|
|
@@ -230,27 +230,40 @@ function prefixLayoutPath(contentType, path) {
|
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
function buildPage(contentType, comps = []) {
|
|
233
|
-
|
|
233
|
+
const page = {
|
|
234
234
|
type: XP_COMPONENT_TYPE.PAGE,
|
|
235
235
|
path: '/',
|
|
236
236
|
};
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
237
|
+
return buildComponentTree(comps, page, contentType);
|
|
238
|
+
}
|
|
239
|
+
function buildComponentTree(comps, rootComp, contentType) {
|
|
240
|
+
const rootTree = {};
|
|
241
|
+
const isFragmentType = contentType === FRAGMENT_CONTENTTYPE_NAME;
|
|
242
|
+
if (isFragmentType) {
|
|
243
|
+
rootComp.regions = rootTree;
|
|
240
244
|
}
|
|
241
245
|
comps.forEach(cmp => {
|
|
242
246
|
var _a;
|
|
243
247
|
const cmpPath = parseComponentPath(contentType, cmp.path);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
if (cmp.path === '/') {
|
|
249
|
+
if (cmp.type === XP_COMPONENT_TYPE.PAGE && rootComp.type === XP_COMPONENT_TYPE.PAGE) {
|
|
250
|
+
// add page values to page object
|
|
251
|
+
rootComp = Object.assign(rootComp, cmp);
|
|
252
|
+
rootComp.page.regions = rootTree;
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
else if (cmp.type === XP_COMPONENT_TYPE.LAYOUT && rootComp.type === XP_COMPONENT_TYPE.FRAGMENT) {
|
|
256
|
+
// when rendering fragment as part of the page with layout at root path
|
|
257
|
+
// remove other children from list as they will be included in layout
|
|
258
|
+
rootComp.fragment.fragment.components = [cmp];
|
|
259
|
+
cmp.regions = rootTree;
|
|
260
|
+
}
|
|
250
261
|
}
|
|
251
|
-
|
|
252
|
-
|
|
262
|
+
if (cmp.type === XP_COMPONENT_TYPE.FRAGMENT) {
|
|
263
|
+
// build component subtree for fragment
|
|
264
|
+
cmp = buildComponentTree(cmp.fragment.fragment.components, cmp, contentType);
|
|
253
265
|
}
|
|
266
|
+
const region = getParentRegion(rootTree, contentType, cmpPath, comps, true);
|
|
254
267
|
if (region) {
|
|
255
268
|
// getting the index of component from string like '/main/0/left/11'
|
|
256
269
|
const cmpIndex = (_a = cmpPath[cmpPath.length - 1]) === null || _a === void 0 ? void 0 : _a.index;
|
|
@@ -262,7 +275,7 @@ function buildPage(contentType, comps = []) {
|
|
|
262
275
|
}
|
|
263
276
|
}
|
|
264
277
|
});
|
|
265
|
-
return
|
|
278
|
+
return rootComp;
|
|
266
279
|
}
|
|
267
280
|
function combineMultipleQueries(queriesWithVars) {
|
|
268
281
|
const queries = [];
|
|
@@ -342,11 +355,16 @@ function applyProcessors(componentDescriptors, contentResults, context) {
|
|
|
342
355
|
// if there is a query then there must be a result for it
|
|
343
356
|
data = contentResults.contents[dataCounter++];
|
|
344
357
|
}
|
|
345
|
-
|
|
358
|
+
const config = getComponentConfig(desc.component);
|
|
359
|
+
return yield propsProcessor(data, context, config);
|
|
346
360
|
}));
|
|
347
361
|
return Promise.allSettled(processorPromises);
|
|
348
362
|
});
|
|
349
363
|
}
|
|
364
|
+
function getComponentConfig(cmp) {
|
|
365
|
+
const cmpData = cmp && cmp[cmp.type];
|
|
366
|
+
return cmpData && 'config' in cmpData ? cmpData.config : undefined;
|
|
367
|
+
}
|
|
350
368
|
function collectComponentDescriptors(components, componentRegistry, requestedComponentPath, xpContentPath, context) {
|
|
351
369
|
const descriptors = [];
|
|
352
370
|
for (const cmp of (components || [])) {
|
|
@@ -357,8 +375,7 @@ function collectComponentDescriptors(components, componentRegistry, requestedCom
|
|
|
357
375
|
const cmpDef = ComponentRegistry.getByComponent(cmp);
|
|
358
376
|
if (cmpDef) {
|
|
359
377
|
// const partPath = `${xpContentPath}/_component${cmp.path}`;
|
|
360
|
-
const
|
|
361
|
-
const config = cmpData && 'config' in cmpData ? cmpData.config : undefined;
|
|
378
|
+
const config = getComponentConfig(cmp);
|
|
362
379
|
const queryAndVariables = getQueryAndVariables(cmp.type, xpContentPath, cmpDef.query, context, config);
|
|
363
380
|
if (queryAndVariables) {
|
|
364
381
|
descriptors.push({
|
|
@@ -427,7 +444,7 @@ function getQueryAndVariables(type, path, selectedQuery, context, config) {
|
|
|
427
444
|
throw Error(`Query for content type ${type} should be a string or function, not: ${typeof query}`);
|
|
428
445
|
}
|
|
429
446
|
if (typeof query === 'function') {
|
|
430
|
-
query = query(config);
|
|
447
|
+
query = query(path, context, config);
|
|
431
448
|
}
|
|
432
449
|
if (query) {
|
|
433
450
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enonic/nextjs-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -13,21 +13,21 @@
|
|
|
13
13
|
"lint:fix": "eslint --fix ."
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"html-react-parser": "^3.0.
|
|
17
|
-
"next": "^13.
|
|
16
|
+
"html-react-parser": "^3.0.7",
|
|
17
|
+
"next": "^13.1.2",
|
|
18
18
|
"react": "^18.2.0",
|
|
19
19
|
"react-dom": "^18.2.0",
|
|
20
20
|
"unescape": "^1.0.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@enonic/eslint-config": "^
|
|
24
|
-
"@types/node": "^18.11.
|
|
23
|
+
"@enonic/eslint-config": "^1.1.0",
|
|
24
|
+
"@types/node": "^18.11.18",
|
|
25
25
|
"@types/react": "^18.0.26",
|
|
26
|
-
"@types/react-dom": "^18.0.
|
|
27
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
28
|
-
"@typescript-eslint/parser": "^5.
|
|
29
|
-
"eslint": "^8.
|
|
30
|
-
"eslint-plugin-react": "^7.
|
|
26
|
+
"@types/react-dom": "^18.0.10",
|
|
27
|
+
"@typescript-eslint/eslint-plugin": "^5.48.1",
|
|
28
|
+
"@typescript-eslint/parser": "^5.48.1",
|
|
29
|
+
"eslint": "^8.32.0",
|
|
30
|
+
"eslint-plugin-react": "^7.32.0",
|
|
31
31
|
"typescript": "^4.9.4"
|
|
32
32
|
}
|
|
33
33
|
}
|
package/views/Region.jsx
CHANGED
|
@@ -15,12 +15,7 @@ export const RegionView = (props) => {
|
|
|
15
15
|
regionAttrs.id = name + 'Region';
|
|
16
16
|
regionAttrs[PORTAL_REGION_ATTRIBUTE] = name;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
return <div {...regionAttrs}>{children}</div>;
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
return <>{children}</>;
|
|
23
|
-
}
|
|
18
|
+
return <div {...regionAttrs}>{children}</div>;
|
|
24
19
|
};
|
|
25
20
|
/** Multiple regions, or only one if named in props.selected */
|
|
26
21
|
const RegionsView = (props) => {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface StaticContentProps extends Record<string, any> {
|
|
3
|
+
children?: ReactNode | ReactNode[];
|
|
4
|
+
element?: string;
|
|
5
|
+
condition: boolean;
|
|
6
|
+
}
|
|
7
|
+
export default function StaticContent({ children, element, condition, ...props }: StaticContentProps): import("react").DOMElement<{
|
|
8
|
+
[x: string]: any;
|
|
9
|
+
}, Element> | import("react").ReactElement<{
|
|
10
|
+
ref: boolean | import("react").MutableRefObject<any>;
|
|
11
|
+
suppressHydrationWarning: boolean;
|
|
12
|
+
dangerouslySetInnerHTML: {
|
|
13
|
+
__html: string;
|
|
14
|
+
};
|
|
15
|
+
}, string | import("react").JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { createElement, useEffect, useRef, useState } from 'react';
|
|
13
|
+
function useStaticContent() {
|
|
14
|
+
const ref = useRef(null);
|
|
15
|
+
const [render, setRender] = useState(typeof window === 'undefined');
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
var _a;
|
|
18
|
+
// check if the innerHTML is empty as client side navigation
|
|
19
|
+
// need to render the component without server-side backup
|
|
20
|
+
const isEmpty = ((_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.innerHTML) === '';
|
|
21
|
+
if (isEmpty) {
|
|
22
|
+
setRender(true);
|
|
23
|
+
}
|
|
24
|
+
}, []);
|
|
25
|
+
return [render, ref];
|
|
26
|
+
}
|
|
27
|
+
export default function StaticContent(_a) {
|
|
28
|
+
var { children, element = 'div', condition = true } = _a, props = __rest(_a, ["children", "element", "condition"]);
|
|
29
|
+
const [render, ref] = useStaticContent();
|
|
30
|
+
// just render if:
|
|
31
|
+
// - condition is false
|
|
32
|
+
// - we're in the server or a spa navigation
|
|
33
|
+
if (render || !condition) {
|
|
34
|
+
return createElement(element, props, ...[].concat(children));
|
|
35
|
+
}
|
|
36
|
+
// avoid re-render on the client
|
|
37
|
+
return createElement(element, Object.assign(Object.assign({}, props), { ref, suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: '' } }));
|
|
38
|
+
}
|