Skip to content

Commit

Permalink
wip: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dxinteractive committed May 20, 2019
1 parent e522819 commit ca1dce7
Show file tree
Hide file tree
Showing 107 changed files with 2,549 additions and 2,935 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ A library for editing data structures that works really well with React.

## Packages

If you're using React, get [`react-dataparcels`](https://www.npmjs.com/package/react-dataparcels) and you'll also get components and hocs to easily use dataparcels in a React app. If not, go for [`dataparcels`](https://www.npmjs.com/package/dataparcels).
If you're using React, get [`react-dataparcels`](https://www.npmjs.com/package/react-dataparcels) and you'll also get hooks, hocs and components to easily use dataparcels in a React app. If not, go for [`dataparcels`](https://www.npmjs.com/package/dataparcels).
1 change: 0 additions & 1 deletion packages/dataparcels-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"react-dataparcels": "file:.yalc/react-dataparcels",
"react-dataparcels-drag": "file:.yalc/react-dataparcels-drag",
"react-dom": "^16.8.6",
"react-flip-move": "^3.0.2",
"react-helmet": "^5.2.0",
"react-sortable-hoc": "^1.4.0",
"react-spruce": "^0.1.1",
Expand Down
8 changes: 5 additions & 3 deletions packages/dataparcels-docs/src/component/APINavigation.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
// @flow
import React from "react";
import {NavigationList, NavigationListItem} from 'dcme-style';
import {NavigationList, NavigationListItem, Text} from 'dcme-style';
import Link from 'component/Link';

export default () => <NavigationList>
<NavigationListItem><Link to="/api">Api</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/Parcel">Parcel</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ParcelHoc">ParcelHoc</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/useParcelState">useParcelState</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/useParcelBuffer">useParcelBuffer</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ParcelBoundary">ParcelBoundary</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ParcelBoundaryHoc">ParcelBoundaryHoc</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ParcelShape">ParcelShape</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ChangeRequest">ChangeRequest</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/CancelActionMarker">CancelActionMarker</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/shape">shape</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ParcelHoc">ParcelHoc</Link></NavigationListItem>
<NavigationListItem>- <Link to="/api/ParcelBoundaryHoc">ParcelBoundaryHoc</Link></NavigationListItem>
</NavigationList>;
70 changes: 70 additions & 0 deletions packages/dataparcels-docs/src/component/exampleFrame.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// @flow

import type {ComponentType} from 'react';
import type {LayoutElement} from 'dcme-style';
import type {Node} from 'react';

import filter from 'unmutable/lib/filter';
import map from 'unmutable/lib/map';
import toArray from 'unmutable/lib/toArray';
import pipeWith from 'unmutable/lib/util/pipeWith';

import React from 'react';
import {Box, Grid, GridItem, Layout, Terminal, Text} from 'dcme-style';

type Props = {};

type LayoutProps = {
demo: LayoutElement,
data: LayoutElement,
};

const stringify = (value) => {
let replacer = (key, value) => {
// The following works because NaN is the only value in javascript which is not equal to itself.
if(value !== value) {
return 'NaN';
}
return value;
};
return `${JSON.stringify(value, replacer, 4)}`.replace(/"NaN"/g, "NaN");
};

class ExampleFrame extends Layout<Props> {
static elements = ['demo', 'data'];

static layout = ({demo, data}) => <Box modifier="paddingBottomKilo example">
<Box modifier="exampleInner">
<Grid>
<GridItem modifier="6 padding">
{demo()}
</GridItem>
<GridItem modifier="6 padding">
{data()}
</GridItem>
</Grid>
</Box>
</Box>;

demo = (): Node => {
return this.props.children;
};

data = (): Node => {
return pipeWith(
this.props.parcels,
map((parcel, key) => <Box key={key}>
<Text element="div" modifier="monospace">{key}</Text>
<Terminal>{stringify(parcel.value)}</Terminal>
</Box>),
toArray()
);
};
};

export default (parcels: Object, children) => {
return <ExampleFrame
parcels={parcels}
children={children}
/>;
};
34 changes: 21 additions & 13 deletions packages/dataparcels-docs/src/content/API.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
import React from 'react';
import Link from 'gatsby-link';
import {Box, Grid, GridItem, Image, NavigationList, NavigationListItem, Text} from 'dcme-style';
import {Box, BulletList, BulletListItem, Grid, GridItem, Image, NavigationList, NavigationListItem, Text} from 'dcme-style';
import SpruceClassName from 'react-spruce/lib/SpruceClassName';

import IconParcel from 'content/parcel.gif';
Expand Down Expand Up @@ -36,28 +36,36 @@ export default () => <Box>
image={IconParcel}
/>
<Item
name="ParcelHoc"
name="useParcelState"
description={<Box>
<Text element="p" modifier="marginMilli">ParcelHoc is a React higher order component.</Text>
<Text element="p">Its job is to provide a parcel as a prop, and to handle how the parcel binds to React props and lifecycle events.</Text>
<Text element="p" modifier="marginMilli">useParcelState is a React hook.</Text>
<Text element="p">Its job is to provide a parcel stored in state, and to handle how the parcel binds to React props.</Text>
</Box>}
image={IconParcelHoc}
/>
<Item
name="ParcelBoundary"
name="useParcelBuffer"
description={<Box>
<Text element="p" modifier="marginMilli">ParcelBoundary is a React component.</Text>
<Text element="p">Its job is to optimise rendering performance, and to optionally control the flow of parcel changes.</Text>
<Text element="p" modifier="marginMilli">useParcelBuffer is a React hook.</Text>
<Text element="p">Its job is to control the flow of parcel changes.</Text>
</Box>}
image={IconParcelBoundary}
image={IconParcelBoundaryHoc}
/>
<Item
name="ParcelBoundaryHoc"
name="ParcelBoundary"
description={<Box>
<Text element="p" modifier="marginMilli">ParcelBoundaryHoc is a React higher order component.</Text>
<Text element="p">Its job is to control the flow of parcel changes. It is the higher order component version of a ParcelBoundary.</Text>
<Text element="p" modifier="marginMilli">ParcelBoundary is a React component.</Text>
<Text element="p">Its job is to optimise rendering performance, and to optionally control the flow of parcel changes using useParcelBuffer.</Text>
</Box>}
image={IconParcelBoundaryHoc}
image={IconParcelBoundary}
/>
<Text element="p" modifier="margin">See also: <Link className="Link" to="/api/ParcelShape">ParcelShape</Link>, <Link className="Link" to="/api/ChangeRequest">ChangeRequest</Link>, <Link className="Link" to="/api/CancelActionMarker">CancelActionMarker</Link>, <Link className="Link" to="/api/shape">shape</Link>.</Text>
<Text element="p" modifier="margin">See also:</Text>
<BulletList>
<BulletListItem><Link className="Link" to="/api/ChangeRequest">ChangeRequest</Link></BulletListItem>
<BulletListItem><Link className="Link" to="/api/CancelActionMarker">CancelActionMarker</Link></BulletListItem>
<BulletListItem><Link className="Link" to="/api/ParcelShape">ParcelShape</Link></BulletListItem>
<BulletListItem><Link className="Link" to="/api/shape">shape</Link></BulletListItem>
<BulletListItem><Link className="Link" to="/api/ParcelHoc">ParcelHoc</Link></BulletListItem>
<BulletListItem><Link className="Link" to="/api/ParcelBoundaryHoc">ParcelBoundaryHoc</Link></BulletListItem>
</BulletList>
</Box>;
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import Link from 'component/Link';
import Param from 'component/Param';
import ApiPageIcon from 'component/ApiPageIcon';
import ParcelHocExample from 'pages/examples/parcelhoc-example.md';
import ParcelHocInitialValueFromProps from 'pages/examples/parcelhoc-valuefromprops.md';
import ParcelHocOnChange from 'pages/examples/parcelhoc-onchange.md';
import IconParcelBoundary from 'content/parcelboundary.gif';
import {Box, Message} from 'dcme-style';

Expand All @@ -15,7 +12,7 @@ ParcelBoundary is a React component. Its job is to optimise rendering performanc

Each ParcelBoundary is passed a Parcel. By default the ParcelBoundary uses pure rendering, and will only update when the Parcel's data changes to avoid unnecessary re-rendering.

ParcelBoundaries have an internal action buffer that can hold onto changes as they exit the boundary. These are normally released immediately, but also allow for debouncing changes, or putting a hold on all changes so they can be released later.
ParcelBoundaries have an internal buffer that can hold onto changes as they exit the boundary. These are normally released immediately, but also allow for debouncing changes, or putting a hold on all changes so they can be released later. Internally ParcelBoundaries use a [useParcelBuffer](/api/usePaercelBuffer) hook.

```js
import ParcelBoundary from 'react-dataparcels/ParcelBoundary';
Expand All @@ -24,20 +21,16 @@ import ParcelBoundary from 'react-dataparcels/ParcelBoundary';
```js
<ParcelBoundary
parcel={Parcel}
debounce={?number}
pure={?boolean}
forceUpdate={?Array<any>}
forceUpdate={?any[]}
debounce={?number}
hold={?boolean}
modifyBeforeUpdate={?Array<Function>}
onCancel={?Array<Function>}
onRelease={?Array<Function>}
debugBuffer={?boolean}
debugParcel={?boolean}
beforeChange={?Function|Function[]}
>
{(parcel, control) => Node}
</ParcelBoundary>
```
<Box modifier="margin">
<Message>ParcelBoundary is also available as a React higher order component, <Link to="/api/ParcelBoundaryHoc">ParcelBoundaryHoc</Link>.</Message>
<Message>ParcelBoundary is also available as a hook, <Link to="/api/useParcelHook">useParcelHook</Link>.</Message>
</Box>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Link from 'component/Link';
import ValueUpdater from 'docs/notes/ValueUpdater.md';

```flow
modifyBeforeUpdate?: Array<Updater>
beforeChange?: Updater|Updater[]
// updating value - only to be used if shape doesn't change
type Updater = (value: any, changeRequest: ChangeRequest) => any;
Expand All @@ -12,14 +12,14 @@ type Updater = (value: any, changeRequest: ChangeRequest) => any;
type Updater = shape((parcelShape: ParcelShape, changeRequest: ChangeRequest) => any);
```

The `modifyBeforeUpdate` prop allows derived data to be set on the Parcel in the ParcelBoundary.
Whenever the data in a ParcelBoundary is about to be initialised or updated in any way, it is passed through all `modifyBeforeUpdate` functions.
The `beforeChange` prop allows derived data to be set on the Parcel in the ParcelBoundary.
Whenever the data in a ParcelBoundary is about to be initialised or updated in any way, it is passed through all `beforeChange` functions.

Each function in the `modifyBeforeUpdate` array operates just like the `updater` provided to <Link to="/api/Parcel#modifyUp">Parcel.modifyUp()</Link>.
Each function in the `beforeChange` array operates just like the `updater` provided to <Link to="/api/Parcel#modifyUp">Parcel.modifyUp()</Link>.

```js

let modifyBeforeUpdate = [
let beforeChange = [
(value) => ({
...value,
isLong: value.word.length > 15
Expand All @@ -33,7 +33,7 @@ let modifyBeforeUpdate = [
// // ^ this will contain derived data
// }

<ParcelBoundary parcel={exampleParcel} modifyBeforeUpdate={modifyBeforeUpdate}>
<ParcelBoundary parcel={exampleParcel} beforeChange={beforeChange}>
{(exampleParcel) => <input type="text" {...exampleParcel.get('word').spreadDOM()} />}
</ParcelBoundary>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import Link from 'component/Link';

```flow
(parcel: Parcel, control: ParcelBoundaryControl) => Node
(parcel: Parcel, buffer: ParcelBufferControl) => Node
type ParcelBoundaryControl = {
release: () => void,
cancel: () => void,
type ParcelBufferControl = {
submit: () => void,
reset: () => void,
buffered: boolean,
buffer: Action[]
actions: Action[]
}
```

ParcelBoundaries must be given a `childRenderer` function as children. This is called whenever the ParcelBoundary updates.

It is passed a `parcel` and a ParcelBoundaryControl instance.
It is passed a `parcel` and a ParcelBufferControl instance.
- The `parcel` is on the "inside" of the parcel boundary, and is able to update independently of the parcel that was passed into the ParcelBoundary.
- The `control` argument passes a ParcelBoundaryControl which can be used to control the ParcelBoundary's action buffer (see the <Link to="/examples/parcelboundary-hold">hold example</Link>) and information about the current state of the action buffer.
- The `buffer` argument passes a ParcelBufferControl which can be used to control the ParcelBoundary's action buffer and information about the current state of the action buffer.

#### ParcelBoundaryControl
#### ParcelBufferControl

- The `release()` function will release any changes in the buffer, allowing them to propagate upward out of the ParcelBoundary.
- The `cancel()` function will cancel any changes in the buffer.
- The `buffered` boolean indicates if the ParcelBoundary currently contains changes that it hasn't yet released.
- The `buffer` array contains the actions that are currently held in the buffer.
- `originalParcel` contains the Parcel that was passed into the ParcelBoundary, unaffected by any buffering or ParcelBoundary state.
- The `submit()` function will submit changes in the buffer, allowing them to propagate upward out of the ParcelBoundary.
- The `reset()` function will reset the buffer, clearing any changes in the buffer.
- The `buffered` boolean indicates if the ParcelBoundary currently contains changes that it hasn't yet submitted.
- The `actions` array contains the actions that are currently held in the buffer.

The return value of `childRenderer` will be rendered.

```js
// personParcel is a Parcel
<ParcelBoundary parcel={personParcel}>
{(parcel, control) => {
{(parcel, buffer) => {
return <input type="text" {...parcel.spreadDOM()} />;
}}
</ParcelBoundary>
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Link from 'component/Link';

```flow
forceUpdate?: Array<*> // optional
forceUpdate?: any[] // optional
```

While a ParcelBoundary is using pure rendering, `forceUpdate` will force the ParcelBoundary to re-render in response to changes in other props. Each item in the `forceUpdate` array is compared using strict equality against its previous values, and if any are not strictly equal, the ParcelBoundary will re-render.
Expand All @@ -14,5 +14,3 @@ While a ParcelBoundary is using pure rendering, `forceUpdate` will force the Par
{(personParcel) => <Select {...personParcel.spreadDOM()} options={options} />}
</ParcelBoundary>
```

<Link to="/examples/parcelboundary-forceupdate">Example</Link>
2 changes: 0 additions & 2 deletions packages/dataparcels-docs/src/docs/api/parcelBoundary/hold.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,3 @@ When `hold` is true, all changes made to the parcel inside the ParcelBoundary ar
}}
</ParcelBoundary>
```

<Link to="/examples/parcelboundary-hold">Example</Link>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The default behaviour of ParcelBoundary is to update its contents whenever it re

If `keepValue` is true on a ParcelBoundary, and if that ParcelBoundary propagates a change, then that ParcelBoundary will *not* update its value when it receives a new Parcel via props.

This is useful when <Link to="/api/Parcel#modify_methods">modify methods</Link> are being used above the ParcelBoundary, which change the data type on it's trip up to the top level Parcel and back down again.
This is useful when <Link to="/api/Parcel#modify_methods">modify methods</Link> are being used above the ParcelBoundary, which change the data type on its trip up to the top level Parcel and back down again.

```js
let numberParcel = parcel
Expand All @@ -19,12 +19,10 @@ return <ParcelBoundary parcel={numberParcel} keepValue>
{(parcel) => <input type="text" {...parcel.spreadDOM()} />}
</ParcelBoundary>;

// without keepValue, if you type "0.10" in the input above it would
// immediately be replaced with "0.1", as the new value is turned
// into a number on the way up, and into a string on the way down,
// which would make typing very frustrating.

// keepValue keeps "0.10" in the text field.
```

<Link to="/data-editing#Modifying-data-to-fit-the-UI">Example</Link>
The `keepValue` prop is necessary here to allow the ParcelBoundary to be the master of its own state, at least in regards to changes that come from itself. So even when a non-number is entered into the input (e.g. "A"), and this is turned into `NaN` as it passes through `.modifyUp()`, the ParcelBoundary can still remember that it should contain "A".

Other values that are preserved in this example are "0.10", which would be turned into "0.1" by the modify functions, and "0.0000001", which would be turned into "1e-7".

**[See an example of keepValue](/data-editing#Modifying-data-to-fit-the-UI)**
18 changes: 0 additions & 18 deletions packages/dataparcels-docs/src/docs/api/parcelBoundary/onCancel.md

This file was deleted.

18 changes: 0 additions & 18 deletions packages/dataparcels-docs/src/docs/api/parcelBoundary/onRelease.md

This file was deleted.

Loading

0 comments on commit ca1dce7

Please sign in to comment.