import { Notice } from '@cerner/terra-docs';
import HowToExample from './example/WorkspaceContentHowToExample?dev-site-example';

# How To Create Workspace Content 

This guide demonstrates the recommended approach for creating a component to be presented within a Workspace.

## Getting Started

This guide will walk through structure, exports, and construction of a stand-alone workspace content component.

Consumers of the [ApplicationNavigation](/application/terra-application/components/application-navigation) component are responsible for defining the overall structure of its workspace. A typical implementation will look something like this:

```jsx
import React from 'react';
import ApplicationNavigation from 'terra-application/lib/application-navigation';

const MyContent1 = () => {...};
const MyContent2 = () => {...};

const WorkspaceContentHowToExample = () => (
  <ApplicationNavigation
    workspace={(
      <ApplicationNavigation.Workspace
        id="application-workspace-example"
        initialActiveItemKey="item-1"
        initialSize={{ scale: 0.5 }}
        initialIsOpen
      >
        <ApplicationNavigation.Workspace.Item
          itemKey="item-1"
          label="Item 1"
          render={() => <MyContent1 />}
        />
        <ApplicationNavigation.Workspace.Item
          itemKey="item-2"
          label="Item 2"
          render={() => <MyContent2 />}
        />
      </ApplicationNavigation.Workspace>
    )}
  />
);

export default WorkspaceContentHowToExample;
```

We will be focusing on creating the content rendered by the Workspace items, in this example `MyContent1` and `MyContent2`.

## Introducing the WorkspaceContent Component

The [WorkspaceContent](/application/terra-application/components/workspace-content) component is essential for integrating into the workspace. It provides the necessary UI and API hooks to present content consistently in the workspace ecosystem. 

<Notice variant="caution" ariaLevel="3">

Components rendered within a workspace *must* render a `WorkspaceContent` component. Failure to do so will result in inconsistent and dysfunctional behavior.

Similarly, only a single WorkspaceContent component should be rendered within any given workspace item. Nested implementations are not supported.

</Notice>

## Creating MyContent1

For MyContent1, we will start with a basic implementation of the WorkspaceContent component.

```jsx
import React from 'react';
import { WorkspaceContent } from 'terra-application/lib/workspace';

const MyContent1 = () => {
  return (
    <WorkspaceContent>
      <div>
        <p>Example Content 1</p>
      </div>
    </WorkspaceContent>
  );
};

MyContent1.labelTranslationId = 'myNamespace.myContent1.label';

export default MyContent1;
```

With its most basic implementation, the WorkspaceContent implementation requires no props. Private communication with its parent Workspace ensures the content is rendered appropriately. 

WorkspaceContent can support any number of children of varying complexity. The main rules to follow for children are:

1. They should be laid out as block-level elements. WorkspaceContent provides its own overflow handling that should not be overwritten.
2. They should not attempt any absolute or fixed positioning that would otherwise interfere with the existing header region within WorkspaceContent.

With this, you have a fully functional content component that can be rendered within a workspace. The following sections will demonstrate how additional properties and APIs can be utilized to build more complex implementations.

<Notice ariaLevel="3">

Workspace content components that wish to maintain ownership over their labeling in the constructed workspace should export the label's associated translation identifier alongside their component. Consumers of the content component can use that id to look up the appropriate label strings.

Typically, this is done with a static property named `labelTranslationId` on the component itself. The examples throughout demonstrate this pattern.

</Notice>

## Adding Visibility Detection to MyContent1

WorkspaceContent components that are not a child of the currently active item will remain mounted. However, they will be removed from the DOM to limit the overall document size. Any dependent logic or listeners that expect to be on the DOM need to be disabled or provided for when no longer on the DOM. In order to facilitate this, the WorkspaceContext provides an `isActive` value that will change when the item associated to the WorkspaceContent component activates/deactivates.

Below is an example using hooks to retrieve the `isActive` value.

```jsx
import React from 'react';
import { WorkspaceContent, WorkspaceContext } from 'terra-application/lib/workspace';

const MyContent1 = () => {
  const { isActive } = React.useContext(WorkspaceContext);

  React.useEffect(() => {
    if (isActive) {
      // add listeners

      return () => {
        // remove listeners
      }
    }
  }, [isActive]);

  return (
    <WorkspaceContent>
      <div>
        <p>Example Content 1</p>
      </div>
    </WorkspaceContent>
  );
};

export default MyContent1;
```

## Adding a Toolbar to MyContent1

The `toolbar` prop can be used to render a styled toolbar component within the WorkspaceContent component. This toolbar is rendered within the component's fixed header region and will not scroll along with content provided as children. 

<Notice variant="ux-recommendation" ariaLevel="3">

The Toolbar and Button components, provided by the terra-toolbar and terra-button packages, should be used as `toolbar` content.

</Notice>

```jsx
import React from 'react';
import Toolbar from 'terra-toolbar';
import Button from 'terra-button';
import { WorkspaceContent, WorkspaceContext } from 'terra-application/lib/workspace';

const MyContent1 = () => {
  const { isActive } = React.useContext(WorkspaceContext);

  React.useEffect(() => {
    if (isActive) {
      // add listeners

      return () => {
        // remove listeners
      }
    }
  }, [isActive]);

  return (
    <WorkspaceContent
      toolbar={(
        <Toolbar>
          <Button text="Action 1" onClick={() => {}} />
          <Button text="Action 2" onClick={() => {}} />
        </Toolbar>
      )}
    >
      <div>
        <p>Example Content 1</p>
      </div>
    </WorkspaceContent>
  );
};

export default MyContent1;
```

## Creating MyContent2

We will create MyContent2 with the same basic implementation we started with for MyContent1.

```jsx
import React from 'react';
import { WorkspaceContent } from 'terra-application/lib/workspace';

const MyContent2 = () => {
  return (
    <WorkspaceContent>
      <div>
        <p>Example Content 2</p>
      </div>
    </WorkspaceContent>
  );
};

MyContent2.labelTranslationId = 'myNamespace.myContent2.label';

export default MyContent2;
```

## Adding NotificationBanners to MyContent2

Each WorkspaceContent component provides a region for rendering notification banners. To render a notification banner, a [NotificationBanner](/application/terra-application/components/notification-banner) must be rendered as a child of the WorkspaceContent component. Any number of banners may be rendered, but too many may impact the user experience.

The banners are rendered within the component's fixed header region and will not scroll along with content provided as children. 

```jsx
import React from 'react';
import { WorkspaceContent } from 'terra-application/lib/workspace';
import NotificationBanner from 'terra-application/lib/notification-banner';

const MyContent2 = () => {
  const [showAlertBanner, setShowAlertBanner] = useState(false);

  return (
    <WorkspaceContent>
      <div>
        <p>Example Content 2</p>
        <button type="button" onClick={() => { setShowAlertBanner(true); }}>Show Alert Banner</button>
      </div>
      {showAlertBanner && (
        <NotificationBanner
          variant="hazard-high"
          id="my-component-notification-id"
          onRequestClose={() => setShowAlertBanner(false)}
        />
      )}
    </WorkspaceContent>
  );
};

MyContent2.labelTranslationId = 'myNamespace.myContent2.label';

export default MyContent2;
```

## Adding ActivityOverlay to MyContent2

The WorkspaceContent component can receive an `activityOverlay` prop that will be rendered over the component's child content.

The provided `WorkspaceContent.ActivityOverlay` is the only supported component at this time.

```jsx
import React from 'react';
import { WorkspaceContent } from 'terra-application/lib/workspace';
import NotificationBanner from 'terra-application/lib/notification-banner';

const MyContent2 = () => {
  const [showAlertBanner, setShowAlertBanner] = React.useState(false);
  const [isLoading, setIsLoading] = React.useState(false);

  return (
    <WorkspaceContent
      activityOverlay={isLoading ? (
        <WorkspaceContent.ActivityOverlay variant="loading" />
      ) : undefined}
    >
      <div>
        <p>Example Content 2</p>
        <button type="button" onClick={() => { setShowAlertBanner(true); }}>Show Alert Banner</button>
        <button type="button" onClick={() => { setIsLoading(true); }}>Show Activity Overlay</button>
      </div>
      {showAlertBanner && (
        <NotificationBanner
          variant="hazard-high"
          id="my-component-notification-id"
          onRequestClose={() => setShowAlertBanner(false)}
        />
      )}
    </WorkspaceContent>
  );
};

MyContent2.labelTranslationId = 'myNamespace.myContent2.label';

export default MyContent2;
```

## Adding StatusOverlay to MyContent2

The WorkspaceContent component can receive an `statusOverlay` prop that will be rendered over the component's other content.

The provided `WorkspaceContent.StatusOverlay` is the only supported component at this time.

<Notice ariaLevel="3">

Note that this can be combined with and presented alongside the activity overlay if both props are provided. However, the activity overlay will render on top of the status overlay.

</Notice>

```jsx
import React from 'react';
import { WorkspaceContent } from 'terra-application/lib/workspace';
import NotificationBanner from 'terra-application/lib/notification-banner';

const MyContent2 = () => {
  const [showAlertBanner, setShowAlertBanner] = React.useState(false);
  const [isLoading, setIsLoading] = React.useState(false);
  const [hasNoResults, setHasNoResults] = React.useState(false);

  return (
    <WorkspaceContent
      activityOverlay={isLoading ? (
        <WorkspaceContent.ActivityOverlay variant="loading" />
      ) : undefined}
      statusOverlay={hasNoResults ? (
        <WorkspaceContent.StatusOverlay variant="no-matching-results" /> 
      ) : undefined}
    >
      <div>
        <p>Example Content 2</p>
        <button type="button" onClick={() => { setShowAlertBanner(true); }}>Show Alert Banner</button>
        <button type="button" onClick={() => { setIsLoading(true); }}>Show Activity Overlay</button>
        <button type="button" onClick={() => { setHasNoResults(true); }}>Show Status Overlay</button>
      </div>
      {showAlertBanner && (
        <NotificationBanner
          variant="hazard-high"
          id="my-component-notification-id"
          onRequestClose={() => setShowAlertBanner(false)}
        />
      )}
    </WorkspaceContent>
  );
};

MyContent2.labelTranslationId = 'myNamespace.myContent2.label';

export default MyContent2;
```

## Wrapping Up

With that, we have demonstrated all capabilities of the WorkspaceContent component. Please review the results in the below example.

<HowToExample />
