Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bloomreach/react-sdk

Package Overview
Dependencies
Maintainers
34
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bloomreach/react-sdk - npm Package Compare versions

Comparing version 0.1.0-saas to 0.2.0-saas

dist/index.es6.js

121

dist/index.d.ts

@@ -1,3 +0,118 @@

export { BrComponent, BrComponentContext, BrProps } from './component';
export { BrManageContentButton, BrManageMenuButton } from './cms';
export { BrPage, BrPageContext } from './page';
/// <reference types="react" />
import { Component, Page, Container, ContainerItem, ManageContentButton, Menu, Configuration, PageModel } from '@bloomreach/spa-sdk';
import React from 'react';
/**
* The React Context holding the current brXM Component.
*/
declare const BrComponentContext: React.Context<Component | undefined>;
interface BrComponentProps {
/**
* The path to a component.
* The path is defined as a slash-separated components name chain
* relative to the current component (e.g. `main/container`).
* If it is omitted, all the children will be rendered.
*/
path?: string;
}
/**
* The brXM component.
*/
declare class BrComponent extends React.Component<BrComponentProps> {
static contextType: React.Context<Component | undefined>;
context: React.ContextType<typeof BrComponentContext>;
private getComponents;
private renderComponents;
render(): JSX.Element;
}
/**
* The mapped component properties.
*/
interface BrProps<T extends Component = Component> {
/**
* The mapped component.
*/
component: T;
/**
* The current page.
*/
page: Page;
}
declare type BrComponent$1 = React.ComponentType<BrProps<Component>> | React.ComponentType<BrProps<Container>> | React.ComponentType<BrProps<ContainerItem>>;
declare const BrMappingContext: React.Context<Record<string | number | symbol, BrComponent$1>>;
/**
* The React Context holding the current brXM Page.
*/
declare const BrPageContext: React.Context<Page | undefined>;
/**
* The button component that opens for editing a content.
*/
declare class BrManageContentButton extends React.Component<ManageContentButton> {
static contextType: React.Context<Page | undefined>;
context: React.ContextType<typeof BrPageContext>;
render(): JSX.Element | null;
}
interface BrManageMenuButtonProps {
/**
* The related menu model.
*/
menu: Menu;
}
/**
* The button component that opens a menu editor.
*/
declare class BrManageMenuButton extends React.Component<BrManageMenuButtonProps> {
static contextType: React.Context<Page | undefined>;
context: React.ContextType<typeof BrPageContext>;
render(): JSX.Element | null;
}
interface BrPageProps {
/**
* The configuration of the SPA SDK.
* @see https://www.npmjs.com/package/@bloomreach/spa-sdk#configuration
*/
configuration: Configuration;
/**
* The brXM and React components mapping.
*/
mapping: React.ContextType<typeof BrMappingContext>;
/**
* The pre-initialized page instance or prefetched page model.
* Mostly this property should be used to transfer state from the server-side to the client-side.
*/
page?: Page | PageModel;
}
interface BrPageState {
page?: Page;
}
/**
* @typedef {Object} BrPageProps
* @property {Configuration} configuration The configuration of the SPA SDK.
* @property {Object} mapping The brXM and React components mapping.
* @property {Page | PageModel | undefined} page The pre-initialized page instance or prefetched page model.
* Mostly this property should be used to transfer state from the server-side to the client-side.
*/
/**
* The brXM page.
*/
declare class BrPage extends React.Component<BrPageProps, BrPageState> {
/**
* @param props {BrPageProps}
*/
constructor(props: BrPageProps);
componentDidMount(): void;
componentDidUpdate(prevProps: BrPageProps, prevState: BrPageState): void;
componentWillUnmount(): void;
private initialize;
private destroy;
render(): JSX.Element | null;
}
export { BrComponent, BrComponentContext, BrManageContentButton, BrManageMenuButton, BrPage, BrPageContext, BrProps };

114

dist/index.js

@@ -15,40 +15,24 @@ (function(global, factory) {

*/ const BrComponentContext = React__default["default"].createContext(undefined);
class BrMeta extends React__default["default"].Component {
constructor() {
super(...arguments);
this.headRef = React__default["default"].createRef();
this.tailRef = React__default["default"].createRef();
}
componentDidMount() {
this.renderMeta();
}
componentDidUpdate(prevProps) {
prevProps.meta.clear();
this.renderMeta();
}
componentWillUnmount() {
this.props.meta.clear();
}
renderMeta() {
var _a, _b, _c;
const head = (_b = (_a = this.headRef) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.nextSibling;
const tail = (_c = this.tailRef) === null || _c === void 0 ? void 0 : _c.current;
if (!head || !tail) {
function BrMeta({children, meta}) {
var _a;
const head = React.useRef(null);
const tail = React.useRef(null);
React.useEffect((() => {
var _a;
if (!((_a = head.current) === null || _a === void 0 ? void 0 : _a.nextSibling) || !tail.current) {
return;
}
this.props.meta.render(head, tail);
}
render() {
return React__default["default"].createElement(React__default["default"].Fragment, null, this.props.meta.length > 0 && React__default["default"].createElement("span", {
style: {
display: "none"
},
ref: this.headRef
}), this.props.children, this.props.meta.length > 0 && React__default["default"].createElement("span", {
style: {
display: "none"
},
ref: this.tailRef
}));
}
return meta.render(head.current.nextSibling, tail.current);
}), [ meta, (_a = head.current) === null || _a === void 0 ? void 0 : _a.nextSibling, tail.current ]);
return React__default["default"].createElement(React__default["default"].Fragment, null, meta.length > 0 && React__default["default"].createElement("span", {
style: {
display: "none"
},
ref: head
}), children, meta.length > 0 && React__default["default"].createElement("span", {
style: {
display: "none"
},
ref: tail
}));
}

@@ -61,14 +45,10 @@ /**

getMapping() {
return this.props.component.getName();
return this.context[this.props.component.getName()];
}
fallback() {
return this.props.children;
}
render() {
const mapping = this.getMapping();
const component = mapping && this.context[mapping];
if (!component) {
return this.fallback();
if (!mapping) {
return this.props.children;
}
return React__default["default"].createElement(component, this.props);
return React__default["default"].createElement(mapping, this.props);
}

@@ -116,8 +96,5 @@ }

var _a;
if (!((_a = this.context) === null || _a === void 0 ? void 0 : _a.isPreview())) {
return null;
}
return React__default["default"].createElement(BrMeta, {
meta: this.props.content.getMeta()
});
return ((_a = this.context) === null || _a === void 0 ? void 0 : _a.isPreview()) ? React__default["default"].createElement(BrMeta, {
meta: this.context.getButton(spaSdk.TYPE_MANAGE_CONTENT_BUTTON, this.props)
}) : null;
}

@@ -131,8 +108,4 @@ }

var _a;
if (!((_a = this.context) === null || _a === void 0 ? void 0 : _a.isPreview())) {
return null;
}
const meta = spaSdk.isMenu(this.props.menu) ? this.props.menu.getMeta() : this.props.menu._meta && this.context.getMeta(this.props.menu._meta);
return meta ? React__default["default"].createElement(BrMeta, {
meta
return ((_a = this.context) === null || _a === void 0 ? void 0 : _a.isPreview()) ? React__default["default"].createElement(BrMeta, {
meta: this.context.getButton(spaSdk.TYPE_MANAGE_MENU_BUTTON, this.props.menu)
}) : null;

@@ -144,20 +117,21 @@ }

getMapping() {
return this.props.component.getType();
}
fallback() {
switch (this.props.component.getType()) {
const type = this.props.component.getType();
if (type && type in this.context) {
return this.context[type];
}
switch (type) {
case spaSdk.TYPE_CONTAINER_INLINE:
return React__default["default"].createElement(BrContainerInline, Object.assign({}, this.props));
return BrContainerInline;
case spaSdk.TYPE_CONTAINER_NO_MARKUP:
return React__default["default"].createElement(BrContainerNoMarkup, Object.assign({}, this.props));
return BrContainerNoMarkup;
case spaSdk.TYPE_CONTAINER_ORDERED_LIST:
return React__default["default"].createElement(BrContainerOrderedList, Object.assign({}, this.props));
return BrContainerOrderedList;
case spaSdk.TYPE_CONTAINER_UNORDERED_LIST:
return React__default["default"].createElement(BrContainerUnorderedList, Object.assign({}, this.props));
return BrContainerUnorderedList;
default:
return React__default["default"].createElement(BrContainerBox, Object.assign({}, this.props));
return BrContainerBox;
}

@@ -184,7 +158,9 @@ }

getMapping() {
return this.props.component.getType();
var _a;
const type = this.props.component.getType();
if (type && type in this.context) {
return this.context[type];
}
return (_a = this.context[spaSdk.TYPE_CONTAINER_ITEM_UNDEFINED]) !== null && _a !== void 0 ? _a : BrContainerItemUndefined;
}
fallback() {
return React__default["default"].createElement(BrContainerItemUndefined, Object.assign({}, this.props));
}
onUpdate() {

@@ -191,0 +167,0 @@ this.forceUpdate((() => this.props.page.sync()));

{
"name": "@bloomreach/react-sdk",
"version": "0.1.0-saas",
"version": "0.2.0-saas",
"description": "Bloomreach SPA SDK for React",

@@ -14,4 +14,4 @@ "keywords": [

"type": "git",
"url": "https://code.onehippo.org/cms-community/bloomreach-spa-sdk",
"directory": "packages/react-sdk"
"url": "https://github.com/bloomreach/brxm.git",
"directory": "spa-sdk/packages/react-sdk"
},

@@ -42,3 +42,3 @@ "bugs": {

"dependencies": {
"@bloomreach/spa-sdk": "^0.1.0-saas"
"@bloomreach/spa-sdk": "^0.2.0-saas"
},

@@ -68,2 +68,3 @@ "peerDependencies": {

"rollup": "^2.32",
"rollup-plugin-dts": "^1.4",
"rollup-plugin-terser": "^7.0",

@@ -70,0 +71,0 @@ "rollup-plugin-typescript2": "^0.28",

@@ -20,2 +20,3 @@ # Bloomreach React SDK

- [React Router](https://reacttraining.com/react-router/) and [Next Routes](https://github.com/fridays/next-routes) support;
- [React Native](https://reactnative.dev/) support;
- [Enzyme](https://airbnb.io/enzyme/) and [Jest](https://jestjs.io/) support.

@@ -27,3 +28,3 @@

```bash
npm install @bloomreach/react-sdk
npm install @bloomreach/react-sdk@saas
```

@@ -33,3 +34,3 @@

```bash
yarn add @bloomreach/react-sdk
yarn add @bloomreach/react-sdk@saas
```

@@ -116,2 +117,10 @@

- By default, container items that are not mapped will be rendered as a warning text. There is an option to override the fallback.
```jsx
import { TYPE_CONTAINER_ITEM_UNDEFINED } from '@bloomreach/spa-sdk';
import Fallback from './components/Fallback';
return <BrPage mapping={{ [TYPE_CONTAINER_ITEM_UNDEFINED]: Fallback }} />;
```
### Inline Mapping

@@ -160,2 +169,150 @@ There is also another way to render a component.

### Buttons
- Manage menu button can be placed inside a menu component using `BrManageMenuButton` component.
```tsx
import React from 'react';
import { Menu, Reference } from '@bloomreach/spa-sdk';
import { BrComponentContext, BrManageMenuButton, BrPageContext } from '@bloomreach/react-sdk';
interface MenuModels {
menu: Reference;
}
export default function MenuComponent() {
const component = React.useContext(BrComponentContext);
const page = React.useContext(BrPageContext);
const menuRef = component?.getModels<MenuModels>().menu;
const menu = menuRef && page?.getContent<Menu>(menuRef);
if (!menu) {
return null;
}
return (
<ul className={page?.isPreview() ? 'has-edit-button' : ''}>
{/* ... */}
<BrManageMenuButton menu={menu} />
</ul>
);
}
```
- Manage content button can be placed inside a component using `BrManageContentButton` component with non-empty `content` property.
```tsx
import React from 'react';
import { Document, Reference } from '@bloomreach/spa-sdk';
import { BrManageContentButton, BrProps } from '@bloomreach/react-sdk';
interface BannerModels {
document: Reference;
}
export default function Banner({ component, page }: BrProps) {
const { document: documentRef } = component.getModels<BannerModels>();
const document = documentRef && page.getContent<Document>(documentRef);
return (
<div className={page.isPreview() ? 'has-edit-button' : ''}>
{/* ... */}
<BrManageContentButton
content={document}
documentTemplateQuery="new-banner-document"
folderTemplateQuery="new-banner-folder"
parameter="document"
root="banners"
relative
/>
</div>
);
}
```
- Add new content button can be placed inside a component using `BrManageContentButton` directive but without passing a content entity.
```tsx
import React from 'react';
import { BrManageContentButton, BrProps } from '@bloomreach/react-sdk';
export default function News({ component, page }: BrProps) {
// ...
return (
<div className={page.isPreview() ? 'has-edit-button' : ''}>
{/* ... */}
<BrManageContentButton
documentTemplateQuery="new-news-document"
folderTemplateQuery="new-news-folder"
root="news"
/>
</div>
);
}
```
### React Native
The SDK is fully compatible with [React Native](https://reactnative.dev/) framework, but there are some of the best practices.
- It is impossible to use `<div>` elements in React Native, and it is recommended to use the `hst.nomarkup` container type in the backend configuration.
- If there is a need to support other container types, those types should be overridden explicitly in the mapping. The default implementation is using HTML entities as described in the [documentation](https://documentation.bloomreach.com/library/concepts/template-composer/channel-editor-containers.html).
```jsx
import React from 'react';
import { View } from 'react-native';
import { TYPE_CONTAINER_BOX } from '@bloomreach/spa-sdk';
function MyBoxContainer() {
return (
<View>
{React.Children.map(props.children, child => (
<View>
{child}
</View>
))}
</View>
);
}
export default function App() {
return <BrPage mapping={{ [TYPE_CONTAINER_BOX]: MyBoxContainer }} />;
}
```
- The fallback mapping should be overridden to prevent errors on production when a new component type pops up on the backend since the default implementation is returning a plain text node.
```jsx
import React from 'react';
import { Text } from 'react-native';
import { TYPE_CONTAINER_ITEM_UNDEFINED } from '@bloomreach/spa-sdk';
function Fallback({ component, page }) {
return page.isPreview() && <Text>Component "{component.getType()}" is not defined.</Text>;
}
export default function App() {
return <BrPage mapping={{ [TYPE_CONTAINER_ITEM_UNDEFINED]: Fallback }} />;
}
```
- For integration with [the Relevance Module](https://documentation.bloomreach.com/14/library/enterprise/enterprise-features/targeting/targeting.html), the visitor identifier storing and passing should be handled on the application side. There is the `visitor` option in the [configuration](#configuration) that enables a setup without using cookies.
```jsx
import React, { useEffect, useMemo, useRef } from 'react';
import { read, write } from './storage';
export default function App() {
const ref = useRef(null);
const configuration = {
/* ... */
visitor: read('visitor'),
};
const visitor = ref.current
&& ref.current.state.page
&& ref.current.state.page.getVisitor();
useEffect(() => void visitor && write('visitor', visitor), [visitor && visitor.id]);
return <BrPage ref={ref} configuration={configuration} />;
}
```
### Reference

@@ -184,3 +341,3 @@ The React SDK is using [Bloomreach SPA SDK](https://www.npmjs.com/package/@bloomreach/spa-sdk#reference) to interact with the brXM.

#### BrManageContentButton
This component places a button on the page that opens the linked content in the document editor.
This component places a button on the page that opens the linked content in the document editor or opens a document editor to create a new one.
The button will only be shown in preview mode.

@@ -190,3 +347,9 @@

--- | :---: | ---
`content` | _yes_ | The content entity to open for editing.
`content` | _no_ | The content entity to open for editing.
`documentTemplateQuery` | _no_ | Template query to use for creating new documents.
`folderTemplateQuery` | _no_ | Template query to use in case folders specified by `path` do not yet exist and must be created.
`path` | _no_ | Initial location of a new document, relative to the `root`.
`parameter` | _no_ | Name of the component parameter in which the document path is stored.
`relative` | _no_ | Flag indicating that the picked value should be stored as a relative path.
`root` | _no_ | Path to the root folder of selectable document locations.

@@ -193,0 +356,0 @@ #### BrManageMenuButton

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc