Skip to content

Commit

Permalink
Document Cosmos UI (#1526)
Browse files Browse the repository at this point in the history
  • Loading branch information
ovidiuch committed Jun 7, 2023
1 parent 5e40409 commit 285c677
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 107 deletions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Choose a dedicated guide for integrating with a specific bundler, framework, or

- [Fixtures](usage/fixtures.md)
- [Decorators](usage/decorators.md)
- [User Interface](usage/user-interface.md)
- [Configuration](usage/configuration.md)
- [Static Export](usage/static-export.md)
- [Node.js API](usage/node-api.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This major version accomplishes the following:
- Codebase brought up to date with standards and dependencies.
- Webpack plugin extracted from core packages.
- New Vite plugin.
- In progress: Official APIs for both bundler and UI plugins.
- Official APIs for both server and UI plugins.

## Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion docs/plugins/cosmos-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ npm i -D react-cosmos-plugin-open-fixture

### Boolean Input Plugin

This is a [UI plugin](ui-plugins.md) that turns boolean inputs in the [control panel](https://github.com/react-cosmos/react-cosmos/blob/main/docs/usage/fixtures.md#fixture-controls) from a true/false button to a checkbox input.
This is a [UI plugin](ui-plugins.md) that turns boolean inputs in the [Control Panel](/docs/usage/user-interface.md#control-panel) from a true/false button to a checkbox input.

```bash
npm i -D react-cosmos-plugin-boolean-input
Expand Down
6 changes: 3 additions & 3 deletions docs/usage/fixtures.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ The file paths of your fixture files (relative to your project root) are used to
| `fixtureFileSuffix` | Suffix for fixture files (eg. `example.fixture.jsx`). | `"fixture"` |
| `ignore` | Patterns for ignoring fixture and decorator files (eg. `["**/dist/**"]`). | |

## Fixture Controls
## UI controls

A props panel is created automatically for [Node fixtures](#node-fixtures) in the Cosmos UI. This enables you to tweek component props and see the result in real time, without any configuration.
Props controls are created automatically for [Node fixtures](#node-fixtures) in the Cosmos UI. This enables you to tweek component props and see the result in real time, without any configuration.

You can also get a custom control panel by manually defining the UI controls in your fixtures.
You can also create custom controls in the [Control Panel](user-interface.md#control-panel) by manually defining them in your fixtures.

### `useValue`

Expand Down
Binary file added docs/usage/screenshots/fixture-search.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/usage/screenshots/fixture-tree-view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/usage/screenshots/notifications.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/usage/screenshots/props-panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/usage/screenshots/responsive-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
104 changes: 104 additions & 0 deletions docs/usage/user-interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# User Interface

This section highlights the main functionality of the React Cosmos UI.

Visit [reactcosmos.org/demo/](https://reactcosmos.org/demo/) for a live demo of React Cosmos.

## Fixture Tree View

An elegant file-system based tree view navigation system. Folders can be collapsed,
and their state persists between sessions.

<img alt="" width="400" src="screenshots/fixture-tree-view.png" />

## Fixture Search

A snappy fixture search feature with fuzzy matching. Use `⌘ + P` from anywhere to launch the search modal.

<img alt="" width="400" src="screenshots/fixture-search.png" />

## Fixture Bookmarks

A convenient way to keep certain fixtures readily accessible while actively working with them.

## Fixture Preview

The fixture preview is the heart of React Cosmos. It loads a Cosmos renderer in an `iframe` within the Cosmos UI.

Communication and state synchronization between the Cosmos UI and the renderer is accomplished through [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

## Responsive Preview

Viewport controls that allow simulation of screen size and orientation, with the option to choose from a predefined list of common devices.

<img alt="" width="400" src="screenshots/responsive-preview.png" />

A screen size can be embedded into a fixture using the [`<Viewport>`](fixtures.md#viewport) decorator.

## Full-Screen Preview

Launch the selected fixture into a full-screen preview, breaking away from the Cosmos UI shell.

> A full-screen preview functions as a [Remote Renderer](#remote-renderer).
## Remote Renderer

You can have multiple DOM remote renderers open simultaneously, allowing you to view the same fixture on different resolutions, browsers, or devices. It's also possible to preview different fixtures concurrently. The React Native renderer is another example of a remote renderer.

You can open a remote renderer by using the "Copy remote renderer URL" button from the home screen, or by launching a [Full-Screen Preview](#full-screen-preview). In the former case the renderer will follow the selected fixture from the Cosmos UI, while in the latter case the selected fixture is locked for that renderer.

Communication and state synchronization between the Cosmos UI and a remote renderer is accomplished through `WebSocket`. State synchronization between multiple renderers is supported, with one primary renderer controlling the state while the others mirror it.

## Reload Renderer

The reload renderer button triggers a full reload of the fixture preview. It is particularly useful for React Native apps, as it invokes `DevSettings.reload` within the renderer.

## Open Fixture Source

Launches the source code of the current fixture in your default code editor.

> **Note** You need to install the [Open Fixture Plugin](../plugins/cosmos-plugins.md#open-fixture-plugin) to enable this capability.
## Control Panel

UI controls that provide powerful component data manipulation.

<img alt="" width="400" src="screenshots/props-panel.png" />

Three types of controls are currently supported:

| Control type | Description |
| ------------ | ------------------------------------------------------------------------------------------------------------------------- |
| Props | Automatically generated based on React element props. Only works with [Node Fixtures](fixtures.md#node-fixtures). |
| Class State | Automatically generated based on React Class components, which are deprecated but supported indefinitely. |
| Custom | Defined using [custom fixture hooks](fixtures.md#ui-controls) that can be represented as text inputs or select dropdowns. |

## Adjustable Panels

The Cosmos UI features two slick resizable and collapsible panels on each side. Their state persists between sessions.

## Notifications

A beautiful notifications interface used to communicate renderer and server connectivity, and other useful information. It can be invoked from anywhere in the Cosmos UI, including 3rd party plugins.

<img alt="" width="400" src="screenshots/notifications.png" />

## Keyboard Shortcuts

The Cosmos UI supports a set of useful keyboard shortcuts for the most commonly used actions:

| Shortcut | Action |
| ----------- | -------------------- |
| `⌘ + P` | Search fixtures |
| `⌘ + ⇧ + P` | Toggle fixture list |
| `⌘ + ⇧ + K` | Toggle control panel |
| `⌘ + ⇧ + E` | Edit fixture |
| `⌘ + ⇧ + F` | Go full screen |

## UI Plugins

The Cosmos UI can be extended using [UI Plugins](../plugins/ui-plugins.md).

---

[Join us on Discord](https://discord.gg/3X95VgfnW5) for feedback, questions and ideas.
49 changes: 0 additions & 49 deletions examples/webpack/src/__fixtures__/Controls.tsx

This file was deleted.

33 changes: 0 additions & 33 deletions examples/webpack/src/__fixtures__/Props.tsx

This file was deleted.

44 changes: 44 additions & 0 deletions examples/webpack/src/__fixtures__/controls/Custom Panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { useSelect, useValue } from 'react-cosmos/client';

export default () => {
const [name] = useValue('name', { defaultValue: 'Mark Normand' });
const [age] = useValue('age', { defaultValue: 39 });
const [comedy] = useValue('comedy', { defaultValue: true });
const [special, setSpecial] = useSelect('special', {
options: ['Still Got It', "Don't Be Yourself", 'Out to Lunch'],
defaultValue: 'Out to Lunch',
});
const [podcast] = useValue('podcast', {
defaultValue: {
name: 'Tuesdays with Stories',
cohost: 'Joe List',
episodes: 300,
endDate: null,
tagRegex: /itsallpipes/g,
},
});

function renderButton(option: typeof special) {
return (
<button disabled={special === option} onClick={() => setSpecial(option)}>
{option}
</button>
);
}

return (
<>
<MyComponent name={name} age={age} comedy={comedy} podcast={podcast} />
<div>
{renderButton('Still Got It')}
{renderButton("Don't Be Yourself")}
{renderButton('Out to Lunch')}
</div>
</>
);
};

function MyComponent(props: Record<string, any>) {
return <pre>{JSON.stringify(props, null, 2)}</pre>;
}
32 changes: 32 additions & 0 deletions examples/webpack/src/__fixtures__/controls/Props Panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useEffect, useRef } from 'react';

export default (
<Comedian
name="Mark Normand"
age={39}
comedy={true}
specials={['Still Got It', "Don't Be Yourself", 'Out to Lunch']}
podcast={{
name: 'Tuesdays with Stories',
cohost: 'Joe List',
episodes: 300,
endDate: null,
tagRegex: /itsallpipes/g,
}}
onCallback={() => 'yes'}
/>
);

function Comedian(props: Record<string, any>) {
const mounted = useRef(false);
useEffect(() => {
if (mounted.current) {
// console.log('Props change');
} else {
mounted.current = true;
// console.log('New instance');
}
});

return <pre>{JSON.stringify(props, null, 2)}</pre>;
}
47 changes: 27 additions & 20 deletions packages/react-cosmos/src/getFixtures/getFixtures.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,36 @@ it('returns fixture info', async () => {

expect(fixtures).toEqual([
{
absoluteFilePath: path.join(rootDir, 'src/__fixtures__/Controls.tsx'),
fileName: 'Controls',
absoluteFilePath: path.join(
rootDir,
'src/__fixtures__/controls/Custom Panel.tsx'
),
fileName: 'Custom Panel',
getElement: expect.any(Function),
name: null,
parents: [],
relativeFilePath: 'src/__fixtures__/Controls.tsx',
parents: ['controls'],
relativeFilePath: 'src/__fixtures__/controls/Custom Panel.tsx',
rendererUrl:
'http://localhost:5000/renderer.html?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2FControls.tsx%22%7D',
'http://localhost:5000/renderer.html?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2Fcontrols%2FCustom+Panel.tsx%22%7D',
playgroundUrl:
'http://localhost:5000/?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2FControls.tsx%22%7D',
treePath: ['Controls'],
'http://localhost:5000/?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2Fcontrols%2FCustom+Panel.tsx%22%7D',
treePath: ['controls', 'Custom Panel'],
},
{
absoluteFilePath: path.join(
rootDir,
'src/__fixtures__/controls/Props Panel.tsx'
),
fileName: 'Props Panel',
getElement: expect.any(Function),
name: null,
parents: ['controls'],
relativeFilePath: 'src/__fixtures__/controls/Props Panel.tsx',
rendererUrl:
'http://localhost:5000/renderer.html?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2Fcontrols%2FProps+Panel.tsx%22%7D',
playgroundUrl:
'http://localhost:5000/?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2Fcontrols%2FProps+Panel.tsx%22%7D',
treePath: ['controls', 'Props Panel'],
},
{
absoluteFilePath: path.join(rootDir, 'src/Counter.fixture.tsx'),
Expand Down Expand Up @@ -136,19 +155,7 @@ it('returns fixture info', async () => {
'http://localhost:5000/renderer.html?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2FHelloWorld.ts%22%7D',
treePath: ['HelloWorld'],
},
{
absoluteFilePath: path.join(rootDir, 'src/__fixtures__/Props.tsx'),
fileName: 'Props',
getElement: expect.any(Function),
name: null,
parents: [],
relativeFilePath: 'src/__fixtures__/Props.tsx',
rendererUrl:
'http://localhost:5000/renderer.html?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2FProps.tsx%22%7D',
playgroundUrl:
'http://localhost:5000/?fixtureId=%7B%22path%22%3A%22src%2F__fixtures__%2FProps.tsx%22%7D',
treePath: ['Props'],
},

{
absoluteFilePath: path.join(
rootDir,
Expand Down

0 comments on commit 285c677

Please sign in to comment.