improve docs code blocks highlighting (#2049)
Summary: This PR adds missing Objective-C entry to the Docusaurus config, fixes Objective-C code blocks label and adds or replaces several code block labels to improve the currently highlighted blocks. Prism in Docusaurus by default also includes syntax highlight for `jsx` and `tsx`, which improves the nodes and props highlight, so I have used those syntaxes in few places too. I have also fixed one typo that I have spotted and my IDE made a cleanup of whitespaces in edited files. ## Changelog * [website] improve docs code blocks highlighting Pull Request resolved: https://github.com/facebook/flipper/pull/2049 Test Plan: The changes have been tested running Flipper website on `localhost`. ## Preview <img width="650" alt="Screenshot 2021-03-12 150934" src="https://user-images.githubusercontent.com/719641/110951135-fff20d00-8344-11eb-96db-1bdc82c8d5ea.png"> <img width="649" alt="Screenshot 2021-03-12 151022" src="https://user-images.githubusercontent.com/719641/110951268-2ca62480-8345-11eb-9d3b-1a48f1267776.png"> Reviewed By: priteshrnandgaonkar Differential Revision: D27336599 Pulled By: passy fbshipit-source-id: c2dfb3d8cad4675da0f5e1270cada1e56a0175c0
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e4a814502a
commit
40e6cdebb1
@@ -13,7 +13,7 @@ Displaying your data in a table might work for many use-cases. However, dependin
|
||||
For our sea mammals app, we might not only want to see them listed as image URLs in a table but render the actual images in nice little cards. When selecting one of the cards we still want to display all details in the sidebar.
|
||||
<img alt="Custom cards UI for our sea mammals plugin" src={useBaseUrl("img/js-custom.png")} />
|
||||
|
||||
Currently, the default export in our `index.tsx` is from `createTablePlugin`.
|
||||
Currently, the default export in our `index.tsx` is from `createTablePlugin`.
|
||||
Now we are going to replace this with a custom React component by using the more flexible APIs exposed by `flipper-plugin` .
|
||||
So first let's add `flipper-plugin` as dependency: `yarn add --peer flipper-plugin antd && yarn add --dev flipper-plugin antd`.
|
||||
|
||||
@@ -21,7 +21,7 @@ After that, we replace our `createTablePlugin` with a `plugin` definition, and a
|
||||
Separating those two concepts helps with testing and maintaining state when the user switches plugins.
|
||||
|
||||
|
||||
```typescript
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import {PluginClient, createState} from 'flipper-plugin';
|
||||
|
||||
@@ -71,13 +71,13 @@ export function Component() {
|
||||
## The `plugin` declaration
|
||||
|
||||
The implementation of our plugin is driven by the named, exported function `plugin` as defined at `(3)`.
|
||||
The `plugin` method is called upon instantiating the plugin.
|
||||
The `plugin` method receives one argument, the `client`, which provides all APIs needed to both interact with Flipper desktop,
|
||||
and the plugin loaded into the client application.
|
||||
The `PluginClient` types all available APIs and takes two generic arguments.
|
||||
The `plugin` method is called upon instantiating the plugin.
|
||||
The `plugin` method receives one argument, the `client`, which provides all APIs needed to both interact with Flipper desktop,
|
||||
and the plugin loaded into the client application.
|
||||
The `PluginClient` types all available APIs and takes two generic arguments.
|
||||
|
||||
The first, `Events`, describes all possible events that can be sent from the client plugin to the desktop plugin,
|
||||
and determines the events available for `client.onMessage` (see below).
|
||||
The first, `Events`, describes all possible events that can be sent from the client plugin to the desktop plugin,
|
||||
and determines the events available for `client.onMessage` (see below).
|
||||
In our example, only one event can occur, `newRow`, as defined at `(2)`.
|
||||
But typically there are more.
|
||||
The data provided by this `newRow` event is described with the `Row` type, as defined at `(3)`.
|
||||
@@ -91,31 +91,31 @@ In this case, we return the state atoms `rows` and `selectedID`, and expose the
|
||||
Since the `plugin` function will execute only once during the entire life-cycle of the plugin, we can use local variables in the function body to preserve state.
|
||||
In our example, we create two pieces of state, the set of rows available, `rows`, and the current selection: `selectionID`. See `(5)`.
|
||||
|
||||
It is possible to store state directly in `let` declarations, but `createState` creates a storage container that gives us a few advantages.
|
||||
It is possible to store state directly in `let` declarations, but `createState` creates a storage container that gives us a few advantages.
|
||||
Most importantly, state created using `createState` can be subscribed to by our UI components using the `useValue` hook.
|
||||
Secondly, state created with `createState` can be made part of Flipper imports / exports.
|
||||
We can enable this feature by providing a unique `persist` key.
|
||||
Secondly, state created with `createState` can be made part of Flipper imports / exports.
|
||||
We can enable this feature by providing a unique `persist` key.
|
||||
The current value of a the container can be read using `.get()`, and `.set()` or `.update()` can be used to replace the current value.
|
||||
|
||||
The `client` can be used to receive and send information to the client plugin.
|
||||
The `client` can be used to receive and send information to the client plugin.
|
||||
With `client.send`, we can invoke methods on the plugin.
|
||||
With `client.onMessage` (`(6)`) we can subscribe to the specific events as specified with the `Events` type (`(2)`).
|
||||
In the event handler, we can update some pieces of state, using the `.set` method to replace state, or the `.update` method to immutably update the state using [immer](https://immerjs.github.io/immer).
|
||||
In the event handler, we can update some pieces of state, using the `.set` method to replace state, or the `.update` method to immutably update the state using [immer](https://immerjs.github.io/immer).
|
||||
In this case, we add the received row to the `rows` state under its own `id`.
|
||||
|
||||
Finally, `(7)`, we create (and expose at `(4)`) a utility to update the selection, which we will user later in our UI.
|
||||
|
||||
Note that no state should be stored outside the `plugin` definition; multiple invocations of `plugin` can be 'alive' if multiple connected apps are using the plugin.
|
||||
Note that no state should be stored outside the `plugin` definition; multiple invocations of `plugin` can be 'alive' if multiple connected apps are using the plugin.
|
||||
Storing the state inside the closure makes sure no state is mixed up.
|
||||
|
||||
### Testing `plugin` logic
|
||||
|
||||
Before we create the UI for our plugin, we are going to pretend that we always write unit tests first.
|
||||
Unit tests will be picked automatically by Jest if they are named like `__tests__/*.spec.tsx`, so we create a file called `__tests__/seamammals.spec.tsx` and start the test runner by
|
||||
Before we create the UI for our plugin, we are going to pretend that we always write unit tests first.
|
||||
Unit tests will be picked automatically by Jest if they are named like `__tests__/*.spec.tsx`, so we create a file called `__tests__/seamammals.spec.tsx` and start the test runner by
|
||||
running `yarn test --watch` in our plugin root.
|
||||
Here is our initial unit test:
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
// (1)
|
||||
import {TestUtils} from 'flipper-plugin';
|
||||
// (2)
|
||||
@@ -159,11 +159,11 @@ test('It can store rows', () => {
|
||||
```
|
||||
|
||||
Testing utilities for plugins are shipped as part of `flipper-plugin`, so we import them (`(1)`).
|
||||
Secondly, we directly import our above plugin implementation into our unit test.
|
||||
Secondly, we directly import our above plugin implementation into our unit test.
|
||||
Using `as`, we put the entire implementation into one object, which is the format in which our utilities expect them (`(2)`).
|
||||
|
||||
Using `TestUtils.startPlugin` (`(3)`) we can instantiate our plugin in a fully mocked environment,
|
||||
in which our plugin can do everything except for actually rendering, which makes this operation really cheap.
|
||||
in which our plugin can do everything except for actually rendering, which makes this operation really cheap.
|
||||
From the `startPlugin`, we get back an `instance`, which corresponds to the object we returned from our `plugin` implementation (`(4)` in our previous listing).
|
||||
Beyond that, we get a bunch of utilities to interact with our plugin.
|
||||
The full list is documented [here](../extending/flipper-plugin#the-test-runner-object), but for this test we are only interested in `sendEvent`.
|
||||
@@ -178,13 +178,13 @@ The assertions are provided by [Jest](https://jestjs.io/), and `toMatchInlineSna
|
||||
|
||||
_Note: For now, the plugin implementation as shown here uses the old Flipper component library `flipper`, expect nicer components in the future as part of `flipper-plugin`._
|
||||
|
||||
So far, in `index.tsx`, our `Component` didn't do anything useful yet. Time to build some nice UI.
|
||||
So far, in `index.tsx`, our `Component` didn't do anything useful yet. Time to build some nice UI.
|
||||
Flipper leverages Ant design, so any [official Ant component](https://ant.design/components/overview/) can be used in Flipper plugins.
|
||||
|
||||
The styling system used by Flipper can be found by starting Flipper, and opening `View > Flipper Style Guide`.
|
||||
The styling system used by Flipper can be found by starting Flipper, and opening `View > Flipper Style Guide`.
|
||||
The different `Layout` elements are documented there as well.
|
||||
|
||||
```typescript
|
||||
```tsx
|
||||
import React, {memo} from 'react';
|
||||
import {Typography, Card} from 'antd';
|
||||
import {
|
||||
@@ -240,12 +240,12 @@ function renderSidebar(row: Row) {
|
||||
}
|
||||
```
|
||||
|
||||
A plugin module can have many components, but it should always export one component named `Component` that is used as the root component for the plugin rendering.
|
||||
A plugin module can have many components, but it should always export one component named `Component` that is used as the root component for the plugin rendering.
|
||||
The component mustn't take any props, and will be mounted by Flipper when the user selects the plugin (`(1)`).
|
||||
|
||||
Inside the component we can grab the relevant instance of the plugin by using the `usePlugin` (`(2)`) hook.
|
||||
Inside the component we can grab the relevant instance of the plugin by using the `usePlugin` (`(2)`) hook.
|
||||
This returns the instance API we returned in the first listing at the end of the `plugin` function.
|
||||
Our original `plugin` definition is passed to the `usePlugin` as argument.
|
||||
Our original `plugin` definition is passed to the `usePlugin` as argument.
|
||||
This is done to get the typings of `instance` correct and should always be done.
|
||||
|
||||
With the `useValue` hook (`(3)`), we can grab the current value from the states we created earlier using `createState`.
|
||||
@@ -254,7 +254,7 @@ The benefit of `useValue(instance.rows)` over using `rows.get()`, is that the fi
|
||||
Since both `usePlugin` and `useValue` are hooks, they usual React rules for them apply; they need to be called unconditionally.
|
||||
So it is recommended to put them at the top of your component body.
|
||||
Both hooks can not only be used in the root `Component`, but also in any other component in your plugin component tree.
|
||||
So it is not necessary to grab all the data at the root, or pass down the `instance` to all child components.
|
||||
So it is not necessary to grab all the data at the root, or pass down the `instance` to all child components.
|
||||
|
||||
Finally (`(4)`) we render the data we have. The details have been left out here, as from here it is just idiomatic React code.
|
||||
The source of the other `MammalCard` component can be found [here](https://github.com/facebook/flipper/blob/master/desktop/plugins/seamammals/src/index.tsx#L113-L165).
|
||||
@@ -264,7 +264,7 @@ The source of the other `MammalCard` component can be found [here](https://githu
|
||||
At this moment the plugin is ready to be used in Flipper, and opening it should lead to sane results.
|
||||
But let's verify with some tests that the UI works correctly, and doesn't regress in the future by adding another unit test to the `seamammals.spec.tsx` file and assert that the rendering is correct and interactive:
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
test('It can have selection and render details', async () => {
|
||||
// (1)
|
||||
const {
|
||||
@@ -336,18 +336,18 @@ test('It can have selection and render details', async () => {
|
||||
});
|
||||
```
|
||||
|
||||
Like in our previous test, we use `TestUtils` to start our plugin.
|
||||
But rather than using `startPlugin`, we now use `renderPlugin`.
|
||||
Like in our previous test, we use `TestUtils` to start our plugin.
|
||||
But rather than using `startPlugin`, we now use `renderPlugin`.
|
||||
Which does the same but also renders the component in memory, using [react-testing-library](https://testing-library.com/docs/react-testing-library/intro).
|
||||
The `renderer` returned by `startPlugin` allows us to interact with the DOM.
|
||||
|
||||
Like in the previous test, we start by sending some events to the plugin (`(2)`).
|
||||
After that (`(3)`), our new data should be reflected in the dom.
|
||||
Since we used `<Card data-testid={row.title}` in our component implementation (not shown above) we can search in the DOM based on that test-id to find the right element.
|
||||
But it is also possible to search for a specific classname, etc.
|
||||
After that (`(3)`), our new data should be reflected in the dom.
|
||||
Since we used `<Card data-testid={row.title}` in our component implementation (not shown above) we can search in the DOM based on that test-id to find the right element.
|
||||
But it is also possible to search for a specific classname, etc.
|
||||
The available queries are documented [here](https://testing-library.com/docs/dom-testing-library/api-queries#queries).
|
||||
|
||||
Rather than just checking that the rendering isn't `null`, we can also take a snapshot of the DOM, and assert that it doesn't change accidentally in the future.
|
||||
Rather than just checking that the rendering isn't `null`, we can also take a snapshot of the DOM, and assert that it doesn't change accidentally in the future.
|
||||
Jest's `toMatchInlineSnapshot` (`(4)`) is quite useful for that.
|
||||
But don't overuse it as large snapshots are pretty useless and just create a maintenance burden without catching much.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ can sort, filter and select items for more detailed information.
|
||||
|
||||
We start by defining what our table rows look like as types:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
type Id = number;
|
||||
|
||||
type Row = {
|
||||
@@ -43,7 +43,7 @@ that we know when something new was added to the table. We will use the
|
||||
|
||||
Next, we define which columns to show and how to display them:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
const columns = {
|
||||
title: {
|
||||
value: 'Title',
|
||||
@@ -73,7 +73,7 @@ table. You could, for instance, show images that you referenced.
|
||||
For this tutorial, however, we will just show the full object by
|
||||
using our `ManagedDataInspector` UI component:
|
||||
|
||||
```javascript
|
||||
```jsx
|
||||
import {Panel, ManagedDataInspector} from 'flipper';
|
||||
|
||||
function renderSidebar(row: Row) {
|
||||
@@ -96,7 +96,7 @@ also render individual rows in our table but instead of a React
|
||||
component, we provide a description of the data based
|
||||
on the column keys we have set up before.
|
||||
|
||||
```javascript
|
||||
```jsx
|
||||
function buildRow(row: Row): TableBodyRow {
|
||||
return {
|
||||
columns: {
|
||||
@@ -130,7 +130,7 @@ any row and copy the content to their clipboard.
|
||||
Now that we've build all the individual pieces, we
|
||||
just need to hook it all up using `createTablePlugin`:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
export default createTablePlugin<Row>({
|
||||
method: 'newRow',
|
||||
columns,
|
||||
|
||||
Reference in New Issue
Block a user