-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
09ceae2
commit bca4d17
Showing
16 changed files
with
701 additions
and
703 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { createElement as $ } from 'react' | ||
import { identity, mapValues, map } from 'lodash' | ||
import { withPropsOnChange } from 'recompose' | ||
|
||
const DEFAULT_KEYS = ['value', 'name', 'onChange'] | ||
const DEFAULT_CHILDREN_PROPS = ({ item }) => (value, index) => item(index) | ||
|
||
export function withChildren( | ||
Component, | ||
childProps = DEFAULT_CHILDREN_PROPS, | ||
shouldUpdateOrKeys = DEFAULT_KEYS, | ||
valueName = 'value', | ||
destination = 'children', | ||
) { | ||
/* | ||
Builds an array that maps every item from the `[valueName]` prop with the result of `<Component {...childProps(props)(itemValue, itemIndex)}` and injects it as a `[destination]` prop. | ||
The prop is only updated if `shouldUpdateOrKeys` returns `true` or if a prop whose name is listed in it changes. | ||
Example: | ||
function Item({ value }) { | ||
return $('li', null, value) | ||
} | ||
const List = withChildren(Item, () => value => ({ value }))('ul') | ||
*/ | ||
return withPropsOnChange(shouldUpdateOrKeys, (props) => ({ | ||
[destination]: map( | ||
props[valueName], | ||
((childProps) => (value, index) => | ||
$(Component, { | ||
key: index, | ||
...childProps(value, index), | ||
}))(childProps(props)), | ||
), | ||
})) | ||
} | ||
|
||
export function withChild( | ||
Component, | ||
childProps = identity, | ||
shouldUpdateOrKeys = DEFAULT_KEYS, | ||
destination = 'children', | ||
) { | ||
/* | ||
Builds an element from the provided `Component` with the props from `childProps(props)` and injects it as a `[destination]` prop. | ||
The prop is only updated if `shouldUpdateOrKeys` returns `true` or if a prop whose name is listed in it changes. | ||
*/ | ||
if (typeof Component === 'function') { | ||
return withPropsOnChange(shouldUpdateOrKeys, (props) => ({ | ||
[destination]: $(Component, childProps(props, null)), | ||
})) | ||
} | ||
return withPropsOnChange(shouldUpdateOrKeys, (props) => ({ | ||
[destination]: mapValues(Component, (Component, name) => | ||
$(Component, childProps(props, name)), | ||
), | ||
})) | ||
} | ||
|
||
export const withElement = withChild |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { createElement as $ } from 'react' | ||
|
||
export function withContext(provider, propName) { | ||
/* | ||
Injects a context `provider` that takes its value from `[propName]`. | ||
*/ | ||
return (Component) => | ||
function withContext(props) { | ||
return $(provider, { value: props[propName] }, $(Component, props)) | ||
} | ||
} | ||
|
||
export function fromContext(consumer, propName) { | ||
/* | ||
Injects the value of the context `consumer` into `[propName]`. | ||
*/ | ||
return (Component) => | ||
function fromContext(props) { | ||
return $(consumer, null, (value) => | ||
$(Component, { ...props, [propName]: value }), | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export class AbortError extends Error { | ||
/* | ||
Error to be thrown in case the query call is aborted. | ||
*/ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { concat, get, indexOf, keys, omit, slice, uniq } from 'lodash' | ||
|
||
/* | ||
Empty array to be used in immutable values. Using this instead of `[]` avoids having several instances of immutable empty arrays. | ||
*/ | ||
export const EMPTY_ARRAY = [] | ||
|
||
/* | ||
Empty object to be used in immutable values. Using this instead of `{}` avoids having several instances of immutable empty objects. | ||
*/ | ||
export const EMPTY_OBJECT = {} | ||
|
||
export function insertItem( | ||
array, | ||
value, | ||
index = array == null ? 0 : array.length, | ||
) { | ||
/* | ||
Returns a new array with the `value` inserted into the `array` at the provided `index`, provided `value` is not `undefined`, in which case the `array` is returned untouched. | ||
If the `index` is not provided, the `value` appended to the `array`. | ||
If the `array` is `nil`, it is considered as an `EMPTY_ARRAY`. | ||
*/ | ||
return array == null | ||
? value === undefined | ||
? EMPTY_ARRAY | ||
: [value] | ||
: value === undefined | ||
? array | ||
: [...slice(array, 0, index), value, ...slice(array, index)] | ||
} | ||
|
||
export function insertItems( | ||
array, | ||
value, | ||
index = array == null ? 0 : array.length, | ||
) { | ||
/* | ||
Returns a new array with the `value` array merged into the `array` at the provided `index`, provided `value` is not `nil`, in which case the `array` is returned untouched. | ||
If the `index` is not provided, the `value` array is appended to the `array`. | ||
If the `array` is `nil`, it is considered as an `EMPTY_ARRAY`. | ||
*/ | ||
return array == null | ||
? value == null | ||
? EMPTY_ARRAY | ||
: value | ||
: value == null | ||
? array | ||
: [...slice(array, 0, index), ...value, ...slice(array, index)] | ||
} | ||
|
||
export function replaceItem(array, previousValue, value) { | ||
/* | ||
Returns a new array with the first occurence of the `previousValue` in `array` replaced by `value`. | ||
Returns the same `array` if the `previousValue` is not found. | ||
If the `array` is `nil`, it is considered as an `EMPTY_ARRAY`. | ||
*/ | ||
return setItem(array, indexOf(array, previousValue), value) | ||
} | ||
|
||
export function setItem(array, index, value) { | ||
/* | ||
Returns a new array with `array[index]` set to `value` if `array[index]` is strictly different from `value`. Otherwise, returns the provided `array`. | ||
If `value` is `undefined`, ensures that the returned array does not contain the item found at `index`. | ||
If `index` is greater than `array.length`, appends `value` to the `array`. | ||
If `index` equals `-1` or is `undefined`, returns the `array` untouched. | ||
If the `array` is `nil`, it is considered as an `EMPTY_ARRAY`. | ||
*/ | ||
return index === -1 || index == null | ||
? array == null | ||
? EMPTY_ARRAY | ||
: array | ||
: array == null | ||
? value === undefined | ||
? EMPTY_ARRAY | ||
: [value] | ||
: value === undefined | ||
? index < array.length | ||
? [...slice(array, 0, index), ...slice(array, index + 1)] | ||
: array | ||
: array[index] === value | ||
? array | ||
: [...slice(array, 0, index), value, ...slice(array, index + 1)] | ||
} | ||
|
||
export function setProperty(object, key, value) { | ||
/* | ||
Returns a new object with `object[key]` set to `value` if `object[key]` is strictly different from `value`. Otherwise, returns the provided `object`. | ||
If `value` is `undefined`, ensures that the returned object does not contain the `key`. | ||
If `key` is `undefined`, returns the `object` untouched. | ||
If `object` is `nil`, it is considered as an `EMPTY_OBJECT`. | ||
*/ | ||
return key === undefined | ||
? object == null | ||
? EMPTY_OBJECT | ||
: object | ||
: object == null | ||
? value === undefined | ||
? EMPTY_OBJECT | ||
: { [key]: value } | ||
: value === undefined | ||
? key in object | ||
? omit(object, key) | ||
: object | ||
: object[key] === value | ||
? object | ||
: { ...object, [key]: value } | ||
} | ||
|
||
export function same( | ||
a, | ||
b, | ||
properties = uniq(concat(keys(a), keys(b))), | ||
deep = false, | ||
) { | ||
/* | ||
Returns `true` if objects `a` and `b` have the same `properties`. | ||
Unless provided, `properties` are the combined set of property names from `a` and `b`. | ||
If `deep` is `true`, considers properties as paths (e.g., `p1.p2`). | ||
*/ | ||
const { length } = properties | ||
for (let i = 0; i < length; i++) { | ||
const property = properties[i] | ||
if (deep) { | ||
if (get(a, property) !== get(b, property)) { | ||
return false | ||
} | ||
} else { | ||
if (a[property] !== b[property]) { | ||
return false | ||
} | ||
} | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,16 @@ | ||
export * from './arrays' | ||
export * from './objects' | ||
export * from './values' | ||
export * from './booleans' | ||
export * from './strings' | ||
export * from './numbers' | ||
export * from './children' | ||
export * from './contexts' | ||
export * from './dates' | ||
|
||
export * from './dom' | ||
export * from './tools' | ||
export * from './errors' | ||
export * from './immutables' | ||
export * from './numbers' | ||
export * from './objects' | ||
export * from './promises' | ||
export * from './properties' | ||
export * from './queries' | ||
export * from './strings' | ||
export * from './tools' | ||
export * from './values' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { AbortError } from './errors' | ||
|
||
/* | ||
Returns a promise that resolves after at least `duration` milliseconds. | ||
If a `signal` is provided, listens to it to reject | ||
*/ | ||
export const waitFor = (duration, signal) => | ||
new Promise((resolve, reject) => { | ||
const timer = window.setTimeout(resolve, duration) | ||
if (signal) { | ||
signal.addEventListener('abort', () => { | ||
window.clearTimeout(timer) | ||
reject(new AbortError('Aborted')) | ||
}) | ||
} | ||
}) |
Oops, something went wrong.