[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)

# `@cortexapps/plugin-core`

This package provides an easy-to-use bridge between Cortex plugins and the Cortex web app.

Install it with

```cli
yarn add @cortexapps/plugin-core
```

or

```cli
npm install @cortexapps/plugin-core
```

## CortexApi

The primary entity exposed is `CortexApi`, which has the methods `proxyFetch()`, `getContext()` and `pluginInit()`.

### `pluginInit`

Call `pluginInit()` as early as possible to trigger the iframe host to inject theme styles into your plugin.

#### Parameters

None

#### Returns

`void`

### `proxyFetch`

> **NOTE**: As of 1.3.0, the global `fetch` method is monkey patched to call `proxyFetch()` under the hood. This means that you can use `fetch()` as you normally would in a Cortex plugin and it will automatically be proxied through Cortex.

`proxyFetch` provides a method for plugins to make API requests through a Cortex proxy in order to avoid browser CORS restrictions and securely add authentication. Its signature is nearly identical to the native browser `fetch()` method, but some properties have been flattened for transfer across the iframe bridge.

#### Parameters

| name  | type         | description                                                                 |
| ----- | ------------ | --------------------------------------------------------------------------- |
| input | RequestInput | See [browser fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) |
| info  | RequestInfo  | See [browser fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) |

#### Returns

`Promise<ShimResponse>` - nearly identical to browser response. See [source code](./src/api/ShimResponse.ts) for more details.

#### Example

```ts
import { CortexApi } from '@cortexapps/plugin-core';

const commentOnPullRequest = async ({
  comment: string,
  owner: string,
  pullNumber: string | number,
  repo: string,
}) => {
  const response = await CortexApi.proxyFetch(
    `https://api.github.com/${owner}/${repo}/pulls/${pullNumber}/comments`,
    {
      body: comment,
      method: 'POST',
    }
  );

  return response.json();
};
```

### Using `proxyFetch` with [octokit](https://github.com/octokit)

> **NOTE**: As of 1.3.0, using an octokit plugin (or adjusting other libraries) is not necessary as the global `fetch` method is shimmed by default.

Use the `octokitPlugin` to easily use octokit in a Cortex plugin.

```ts
import { CortexApi, octokitPlugin } from '@cortexapps/plugin-core';
import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest";

const CortexOctokit = Octoki.plugin(octokitPlugin);

const getWorkflow = async (options: {
  id: number;
  owner: string;
  repo: string;
}): Promise<
  RestEndpointMethodTypes["actions"]["getWorkflow"]["response"]["data"]
> {
  const { owner, repo, id } = options;
  const octokit = new CortexOctokit({ CortexApi });

  const workflow = await octokit.actions.getWorkflow({
    owner,
    repo,
    workflow_id: id,
  });

  return workflow.data;
};
```

### `getContext`

> **NOTE**: As of 1.2.0, context is also available via the `useCortexContext` hook.

#### Parameters

None

#### Returns

| name     | type                  | description                                                                                                                                                                         |
| -------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| entity   | CortexEntity?         | Details about the entity associated with the page the plugin is being rendered if applicable, otherwise null. See [Cortex Entity](./src/api/cortexEntityTypes.ts) for more details. |
| location | PluginContextLocation | Which location type this plugin is being rendered. [Location](./src/api/cortexEntityTypes.ts) for more details.                                                                     |
| user     | CortexUser            | See [Cortex User](./src/api/cortexEntityTypes.ts) for more details.                                                                                                                 |

#### Example

```ts
import { CortexApi } from '@cortexapps/plugin-core';

const getCurrentUser = async () => {
  const response = await CortexApi.getContext();
  const resJson = await response.json();

  return resJson.user;
};
```

## Component library

### Deprecation and Migration from 2.x

The component library is deprecated for versions >=3.0.0 and only critical fixes will be supported. Please use
https://www.npmjs.com/package/@cortexapps/react-plugin-ui for React components and documentation.

To help in your migration, `plugin-core/components` have been converted to use `react-plugin-ui`, but it requires some
steps to fully migrate:

1. Install both `@cortexapps/plugin-core@3.0.0` and `@cortexapps/react-plugin-ui@1.0.0` as dependencies
2. Include `import "@cortexapps/react-plugin-ui/index.css";` global styling
3. When your application boots, call `CortexApi.pluginInit();` to subscribe to theme changes
4. Be sure that your plugin is utilizing `<PluginProvider>` context wrapper. This provides dark/light mode classes on `<body>`

These steps should enable your component to switch between dark/light modes and visually match our component styling.

The new styling applies CSS resets to base elements (such as `ul`/`li`)--some minor visual adjustments may be required
in some areas of your plugin if they are affected.

### Component details

Check out the component library in Storybook by running it locally with `yarn storybook`.

Import your components from `@cortexapps/plugin-core/components` to use them in the app.

```tsx
import React from 'react';
import { Button } from '@cortexapps/plugin-core/components';

interface SubmitButtonProps extends React.PropsWithChildren;

const SubmitButton: React.FC<SubmitButtonProps> = ({ children }) => {
  return (
    <Button type="submit">{children}</Button>
  );
};

export default SubmitButton;
```

### Available components

- Anchor
- Badge
- Box
- Breadcrumb
- Button
- Card
- Checkbox
- Clickable
  - A convenient wrapper for rendering an `<a>` or a `<button>` (depending on the props) without the typical `<a>` or `<button>` styling
- Dropdown
- FancyToggle
- FormLabel
- an icon set (courtesy of [Phosphor icons](https://phosphoricons.com/))
- Input
- Label
- LinearPercentage
- List
- Loader
- Logo
  - This is the Cortex logo!
- Modal
- Pill
- Portal
  - You probably don't need to worry about this one -- this is what we use internally for rendering modals and similar
- ProgressBar
- Stack
  - A super useful component for applying even spacing between children
- Tabs
- Tag
- Text
- Title
- Toggle
- Typeahead

See the typings and Storybook for more details.
