jsharmony-cms-sdk-next
Version:
jsHarmony CMS SDK for Next.js
694 lines (650 loc) • 24 kB
TypeScript
/*!
Copyright 2024 apHarmony
This file is part of jsHarmony.
jsHarmony is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jsHarmony is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this package. If not, see <http://www.gnu.org/licenses/>.
*/
import { GetServerSidePropsResult } from 'next';
import { Metadata } from 'next';
import { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { PropsWithChildren } from 'react';
import { default as React_2 } from 'react';
import { ReactElement } from 'react';
import { ResolvingMetadata } from 'next';
import { ValidationMap } from 'react';
import { WeakValidationMap } from 'react';
/**
* JshCms - renders head, editor, script, style, footer tags, and a container for JshCmsContentArea tags
* @remarks
*
* @example
* ```
* <JshCms jshCmsPage={jshCmsPage} jshCmsConfig={JshCmsConfig}>
* <h1 cms-title="true">{jshCmsPage.title||'Title'}</h1>
* <JshCmsContentArea cms-content="body">Page Content</JshCmsContentArea>
* </JshCms>
* ```
* @public
*/
export declare function JshCms(props: JshCmsProps): React_2.JSX.Element;
/**
* @public
*/
export declare interface JshCmsConfig {
/** URL to published CMS content files */
contentUrl?: string;
/** Path to redirect listing JSON file (relative to contentUrl) */
redirectListingPath?: string | null;
/** Default Directory Document (e.g. index.html) */
defaultDocument?: string;
/** The CMS Server URLs that will be enabled for Page Editing (set to '*' to enable any remote CMS)
* - Used by jshCmsPage.editorScriptPath, and the getEditorScriptPath function
* - NOT used by jsHarmonyCmsEditor.js - the launcher instead uses accessKeys for validating the remote CMS
*/
cmsServerUrls?: string[];
/** Cache duration (seconds) */
cacheDuration?: number;
}
/**
* JshCmsContentArea - Render content area.
* @remarks
* React function component for rendering content area content and associated portals for child component rendering.
*
* @example
* ```
* <JshCmsContentArea cms-content="body" jshCmsPage={jshCmsPage}>
* Optional Default Body Content
* </JshCmsContentArea>
* ```
* @public
*/
export declare function JshCmsContentArea(props: JshCmsContentAreaProps): React_2.JSX.Element;
/**
* @public
*/
export declare interface JshCmsContentAreaProps {
jshCmsPage?: JshCmsPage;
jshCmsContentComponents?: JshCmsContentComponent<any>[];
['cms-content']: string;
[key: string]: any;
}
/**
* JshCmsContentComponent - Content Component.
* @public
*/
export declare interface JshCmsContentComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
jshCmsComponentConfig?: JshCmsContentComponentConfig | undefined;
}
/**
* JshCmsContentComponent - Content Component.
* @public
*/
export declare class JshCmsContentComponent<P = {}> implements JshCmsContentComponent<P> {
static extractChildrenAsReactElements(container: Element): ReactElement[];
}
/**
* JshCmsContentComponent - Content Component Config.
* @public
*/
export declare interface JshCmsContentComponentConfig {
selector: string;
onBeforeRender?: (componentContainer: Element, contentComponentProps: JshCmsContentComponentProps | null) => void;
onRender?: (componentContainer: Element, contentComponentProps: JshCmsContentComponentProps | null) => void;
render?: (componentContainer: Element, contentComponentProps: JshCmsContentComponentProps | null) => JshCmsContentComponentRender | undefined;
}
/**
* JshCmsContentComponentInstance - Content Component Instance.
* @public
*/
export declare interface JshCmsContentComponentInstance {
container: Element;
element: ReactElement;
key: string;
}
/**
* @public
*/
export declare interface JshCmsContentComponentProps {
data: unknown;
properties: unknown;
isInEditor: boolean;
isInPageEditor: boolean;
isInComponentEditor: boolean;
isItemPreview: boolean;
isGridRowPreview: boolean;
}
/**
* JshCmsContentComponentInstance - Content Component Render Parameters.
* @public
*/
export declare interface JshCmsContentComponentRender {
container?: Element;
element: ReactElement;
key?: string;
}
/**
* @internal
*/
export declare const JshCmsContext: React_2.Context<JshCmsContextData>;
/**
* @public
*/
export declare interface JshCmsContextData {
jshCmsConfig: JshCmsConfig | undefined;
jshCmsPage: JshCmsPage | undefined;
}
/**
* JshCmsEditor - render editor support script when page is loaded in the CMS editor.
* @remarks
* Simple React function component for conditionally including tags in pages. These are trivial and can be replaced with custom code as needed.
* Note: CMS was designed to support additional head tags. Next.js takes full control of the head, so these must be placed elsewhere.
*
* @example
* ```
* <JshCmsEditor jshCmsPage={jshCmsPage} />
* ```
* @public
*/
export declare function JshCmsEditor(props: JshCmsElementProps): React_2.JSX.Element;
/**
* @public
*/
export declare interface JshCmsElementProps {
jshCmsPage?: JshCmsPage;
[key: string]: any;
}
/**
* JshCsFooter - render additional footer tags (if any).
* @remarks
* Simple React function component for conditionally including tags in pages. These are trivial and can be replaced with custom code as needed.
*
* @example
* ```
* <JshCmsFooter jshCmsPage={jshCmsPage} />
* ```
* @public
*/
export declare function JshCmsFooter(props: JshCmsElementProps): React_2.JSX.Element;
/**
* JshCmsHead - render additional head tags (if any). Note that this feature in particular is questionable with the Next.js head management, and since raw text must have a container, it is rendered in a div.
* @remarks
* Simple React function component for conditionally including tags in pages. These are trivial and can be replaced with custom code as needed.
* Note: CMS was designed to support additional head tags. Next.js takes full control of the head, so these must be placed elsewhere.
*
* @example
* ```
* <JshCmsHead jshCmsPage={jshCmsPage} />
* ```
* @public
*/
export declare function JshCmsHead(props: JshCmsElementProps): React_2.JSX.Element;
/**
* @public
*/
export declare interface JshCmsMetadataProps {
params: {
[key: string]: string[] | string | undefined;
};
}
/**
* @public
*/
export declare interface JshCmsPage {
content: {
[areaId: string]: string;
};
css: string;
/** If page was opened from a CMS Editor in config.cmsServerUrls, the HTML script to launch the Editor */
editorScriptPath: string | null;
footer: string;
header: string;
/** Whether the page was opened from the CMS Editor */
isInEditor: boolean;
js: string;
page_template_id: string;
properties: {
[propName: string]: any;
};
seo: {
canonical_url: string;
keywords: string;
metadesc: string;
/** Title for HEAD */
title: string;
};
/** Title for Page Body Content */
title: string;
/** Whether the page was Not Found (page data will return empty) */
notFound: boolean;
}
/**
* @public
*/
export declare class JshCmsPage implements JshCmsPage {
/**
* getEmptyPage - An empty JshCmsPage object, for blank editors or initializing useState
* @param pageTemplateId - page template id for newly created pages
* @public
*/
static getEmptyPage(pageTemplateId: string): JshCmsPage;
/**
* getNotFoundPage - An empty JshCmsPage object, with the notFound flag set
* @param pageTemplateId - page template id for newly created pages
* @public
*/
static getNotFoundPage(pageTemplateId: string): JshCmsPage;
/**
* getPage - Get CMS Page Data
* @param pathname - Root-relative Page URL
* @param params - Page load parameters
* @param config - Configuration parameters
* @public
*/
static getPage(pathname: string[] | string | undefined, params: {
[key: string]: string[] | string | undefined;
}, config: JshCmsPageRequest): Promise<JshCmsPage>;
/**
* getMetadata - provides a basic version of a Next.js metadata function that provides CMS SEO data.
*
* @remarks
* If you application has additional metadata needs, you may wish to copy this function into your generateMetadata function.
* {@link https://nextjs.org/docs/app/api-reference/functions/generate-metadata}
*
* @param props - params from the incoming request
* @param parent - metadata from previous functions
* @param config - CMS configuration parameters
* @public
*/
static getMetadata({ params }: JshCmsMetadataProps, // eslint-disable-line @typescript-eslint/no-unused-vars
parent: ResolvingMetadata, config: JshCmsPageRequest): Promise<Metadata>;
/**
* getEditorScriptPath - Generate script for CMS Editor
* @remarks
* - The provided url is validated against cmsServerUrls
* - If the CMS Server is not found in cmsServerUrls, an empty element will be returned
*
* @param cmsServerUrl - URL from jshcms_url parameter
* @param cmsServerUrls - list of allowed CMS editor servers
* @returns path to the editor script
*
* @public
*/
static getEditorScriptPath(cmsServerUrl: string, cmsServerUrls: string[]): string | null;
/**
* getStandalonePage [Main Entry Point] - Get CMS Page Data for Standalone Integration
* @remarks
* if page is opened from CMS Editor or Not Found, an empty JshCmsPage Object will be returned
*
* @param pathname - Root relative path being requested
* @param params - Request url parameters
* @param config - CMS Configuration parameters
* @returns JshCmsPage Object, with set properties: isInEditor, editorScriptPath, notFound
* @public
*/
static getStandalonePage(pathname: string[] | string | undefined, params: {
[key: string]: string[] | string | undefined;
}, config: JshCmsPageRequest): Promise<JshCmsPage>;
/**
* getPath - Transform a page url into cms content file path
* @param contentUrl - CMS content export folder
* @param pathname - Root relative path being requested
* @returns normalized path
* @public
*/
static getPath(contentUrl: string, pathname: string): string;
/**
* getPathVariations - creations variations of a cms content path to try, e.g. as provided and with index.html
* @param pathname - Root relative path being requested
* @param defaultDocument - default document if not in url, e.g. 'index.html'
* @returns list of paths to try
* @public
*/
static getPathVariations(pathname: string, defaultDocument: string): string[];
/**
* resolvePath - Convert URL to CMS Content Paths
* @param contentUrl - CMS content URL
* @param pathname - Root relative path being requested
* @param defaultDocument - default document if not in url, e.g. 'index.html'
* @returns list of paths to try
* @public
*/
static resolvePath(contentUrl: string, pathname: string, defaultDocument: string): string[];
}
/**
* JshCmsPageComponent - Page Component.
* @public
*/
export declare function JshCmsPageComponent(props: JshCmsPageComponentProps): React_2.JSX.Element;
/**
* @public
*/
export declare interface JshCmsPageComponentProps {
componentId: string;
[key: string]: any;
}
/**
* JshCmsPageConfig - render config settings as a script tag
* @remarks
* Simple React function component for conditionally including tags in pages. These are trivial and can be replaced with custom code as needed.
* Note: CMS was designed to support additional head tags. Next.js takes full control of the head, so these must be placed elsewhere.
*
* @example
* ```
<JshCmsPageConfig cms-template="Two Column Page Template" config={{
"content_elements": {
"left": { "title": "Left" },
"right": { "title": "Right" }
}
}} />
* ```
* @public
*/
export declare function JshCmsPageConfig(props: JshCmsPageConfigProps): React_2.JSX.Element | undefined;
/**
* @public
*/
export declare interface JshCmsPageConfigDefinition {
title?: string;
/**
* Each editable content area has one entry in
* content_elements. If no content areas are defined,
* a default content area named "body" will be added.
*/
content_elements?: {
[content_area_name: string]: {
title?: string;
editor_toolbar?: {
/** Dock position for the Editor Menu and Toolbar. Defaults to 'auto'. */
dock?: 'auto' | 'bottom' | 'top_offset' | 'top';
/** Whether to display the editor menu. Defaults to true. */
show_menu?: boolean;
/** Whether to display the editor toolbar. Defaults to true. */
show_toolbar?: boolean;
};
/** Editable area type. Defaults to 'htmleditor' */
type?: 'htmleditor' | 'text';
};
};
/**
* Default value for each content area. If omitted,
* the HTML content will be used.
*/
default_content?: {
[content_area_name: string]: string;
};
/** Page Properties fields */
properties?: {
fields: unknown[];
};
options?: {
/** If set to false, no cms-title element required on the page. Defaults to true. */
title_element_required?: boolean;
/** Page toolbar dock position. Defaults to 'top_offset'. */
dock?: 'bottom' | 'top_offset' | 'top';
};
/** SYSTEM - Hard-coded content element content. */
content?: {
[content_area_name: string]: string | {
title?: string;
};
};
}
/**
* @public
*/
export declare interface JshCmsPageConfigProps {
config?: JshCmsPageConfigDefinition;
}
/**
* @public
*/
export declare interface JshCmsPageRequest {
/** CMS content URL */
contentUrl: string;
/** default document if not in url, e.g. 'index.html' */
defaultDocument: string;
/** valid CMS server URLs */
cmsServerUrls: string[];
/** cache duration in seconds */
cacheDuration: number;
}
/**
* @public
*/
export declare interface JshCmsProps {
jshCmsConfig: JshCmsConfig;
jshCmsPage?: JshCmsPage;
children?: React_2.ReactNode;
}
/**
* @public
*/
export declare function JshCmsProvider(props: JshCmsProviderProps): React_2.JSX.Element;
/**
* @public
*/
export declare interface JshCmsProviderProps {
jshCmsConfig?: JshCmsConfig;
jshCmsPage?: JshCmsPage;
children?: React_2.ReactNode;
}
/**
* A redirect loaded from the CMS data file
* @public
*/
export declare interface JshCmsRedirect {
redirect_key: number;
redirect_url: string;
/** 'BEGINS'|'BEGINSICASE'|'EXACT'|'EXACTICASE'|'REGEX'|'REGEXICASE' */
redirect_url_type: string;
redirect_dest: string;
/** '301'|'302'|'PASSTHRU' */
redirect_http_code: string;
}
/**
* Resolved redirect result
* @public
*/
export declare interface JshCmsRoute {
/** '301'|'302'|'PASSTHRU' */
http_code: string;
url: string;
}
/**
* @public
*/
export declare class JshCmsRouter {
/** URL to published CMS content files */
contentUrl: string;
/** Path to redirect listing JSON file (relative to contentUrl) */
redirectListingPath: string | null;
/** The CMS Server URLs that will be enabled for Page Editing (set to '*' to enable any remote CMS)
* - Used by jshCmsPage.editorScriptPath, and the getEditorScriptPath function
* - NOT used by jsHarmonyCmsEditor.js - the launcher instead uses accessKeys for validating the remote CMS
*/
cmsServerUrls: string[];
/** Default Directory Document (e.g. index.html) */
defaultDocument: string;
/** Cache duration (seconds) */
cacheDuration: number;
constructor(config: JshCmsConfig);
/** getConfig - Get the current config */
getConfig(): JshCmsConfig;
/** getRedirectListingPath - Get the configured path for the redirect listing file */
getRedirectListingPath(): string | undefined;
/**
* getRedirectData - Get CMS Redirect Data
* @param origin - http origin
* @returns Redirects
*/
getRedirectData(origin: string): Promise<JshCmsRedirect[]>;
/**
* getRedirect - Lookup the redirect for a request, if any
* @param request - Request object providing target path and origin
* @returns Appropriate redirect, if one was found
*/
getRedirect(request: NextRequest): Promise<JshCmsRoute | undefined>;
/**
* processJshCmsRedirects - Execute the redirect for a request, if any
* @param request - Request object providing target path and origin
* @returns Appropriate response, if one was found
*/
processRedirects(request: NextRequest): Promise<NextResponse | undefined>;
/**
*hasPage - Check if a page object file exists to decide if a route is available.
* @param pathname - target path
*/
hasPage(pathname: string): Promise<boolean>;
/**
* getStandalonePage [Main Entry Point] - Get CMS Page Data for Standalone Integration
* @remarks
* if page is opened from CMS Editor or Not Found, an empty Page Object will be returned
*
* @param pathname - Root relative path being requested
* @param params - Request url parameters
* @returns Page Object, with filled properties: isInEditor, editorScriptPath, notFound
*/
getStandalonePage(pathname: string[] | string | undefined, params: {
[key: string]: string[] | string | undefined;
}): Promise<JshCmsPage>;
/**
* getEmptyPage - An empty Page object, for blank editors or initializing useState
* @param pageTemplateId - page template id for newly created pages
*/
getEmptyPage(pageTemplateId: string): JshCmsPage;
/**
* getMetadata - provides a basic version of a Next.js metadata function that provides CMS SEO data.
* @remarks
* If you application has additional metadata needs, you may wish to copy the base function into your generateMetadata function.
* {@link https://nextjs.org/docs/app/api-reference/functions/generate-metadata}
*/
getMetadata({ params }: JshCmsMetadataProps, parent: ResolvingMetadata): Promise<Metadata>;
/**
*getPage - Returns a Page object for a specified path
* @param pathname - Root relative path being requested
* @param params - Request url parameters
* @returns Page Object, with filled properties: isInEditor, editorScriptPath, notFound
*/
getPage(pathname: string[] | string | undefined, params: {
[key: string]: string[] | string | undefined;
}): Promise<JshCmsPage>;
/**
*serve [Main Entry Point] - Serves CMS content for a target URL
* @remarks
* if page is opened from CMS Editor or Not Found, an empty Page Object will be returned
*
* @param pathname - Root relative path being requested
* @param params - Request url parameters
* @returns Page Object, with filled properties: isInEditor, editorScriptPath, notFound
*/
serve(pathname: string[] | string | undefined, params: {
[key: string]: string[] | string | undefined;
}): Promise<GetServerSidePropsResult<{
jshCmsPage: JshCmsPage;
}>>;
/**
* loadRedirectData - Load and parse the redirects file
* @param redirectListingPath - Path to exported CMS redirects
* @returns List of redirects
* @public
*/
loadRedirectData(redirectListingPath: string, origin: string): Promise<JshCmsRedirect[]>;
/**
* processRoute - Provides simple handling of redirects in Next.js, replace as needed.
* @param route - Path and code of a found redirect
* @param requestUrl - Original request url
* @returns Response, if a valid redirect was provided.
* @public
*/
static processRoute(route: JshCmsRoute, requestUrl: URL | string | undefined): NextResponse | undefined;
/**
* matchRedirect - Check if URL matches redirects and return first match
* @param redirects - Array of CMS Redirects
* @param urlpath - Target URL path
* @public
*/
static matchRedirect(redirects: JshCmsRedirect[], urlpath: string): JshCmsRoute | undefined;
/**
* getRedirectBase - Looks up matching redirect, if any.
* @param pathname - target path
* @param contentUrl - URL to content files
* @param redirectListingPath - Path to exported CMS redirects
* @returns path and code if found
*/
private getRedirectBase;
/**
* hasPageBase - Check if a page object file exists to decide if a route is available.
* @param pathname - target url path name
* @param contentUrl - URL to CMS content files
* @param defaultDocument - default document if not in url, e.g. 'index.html'
*/
private hasPageBase;
}
/**
* JshCmsScript - render additional javascript (if any) as a script tag
* @remarks
* Simple React function component for conditionally including tags in pages. These are trivial and can be replaced with custom code as needed.
* Note: CMS was designed to support additional head tags. Next.js takes full control of the head, so these must be placed elsewhere.
*
* @example
* ```
* <JshCmsScript jshCmsPage={jshCmsPage} />
* ```
* @public
*/
export declare function JshCmsScript(props: JshCmsElementProps): React_2.JSX.Element;
/**
* JshCmsStyle - render additional css (if any) as a style tag
* @remarks
* Simple React function component for conditionally including tags in pages. These are trivial and can be replaced with custom code as needed.
* Note: CMS was designed to support additional head tags. Next.js takes full control of the head, so these must be placed elsewhere.
*
* @example
* ```
* <JshCmsStyle jshCmsPage={jshCmsPage} />
* ```
* @public
*/
export declare function JshCmsStyle(props: JshCmsElementProps): React_2.JSX.Element;
/**
* @internal
*/
export declare interface notifyUpdateProps {
element: HTMLElement;
componentId: string;
contentAreaName: string;
data?: unknown;
properties?: unknown;
isItemPreview?: boolean;
isGridRowPreview?: boolean;
content?: string;
}
/**
* @public
*/
export declare const useJshCms: () => JshCmsContextData;
/**
* @public
*/
export declare function useJshCmsPageComponentData<T>(props: {
jshCmsPage?: JshCmsPage;
componentId: string;
contentAreaName?: string;
}): {
componentData: (T | null);
};
export { }