@haensl/services
Version:
Assorted JavaScript services.
346 lines (242 loc) • 9.76 kB
Markdown
# services
Assorted JavaScript services.
[](https://nodei.co/npm/@haensl%2Fservices/)
[](http://badge.fury.io/js/@haensl%2Fservices)
[](https://circleci.com/gh/haensl/services)
## Installation<a name="installation"></a>
### Via `npm`
```bash
$ npm install -S /services
```
### Via `yarn`
```bash
$ yarn add /services
```
## Usage
1. [Install /services](#installation)
2. Use services in your code:
```javascript
import { platform } from '/services';
if (platform.hasWindow) {
// code that relies on existance
// of a global window object
}
```
## Available services
* [component](#component): Wraps utility functions useful in a component context, e.g. generate stateful class names.
* [error](#error): Wraps utility functions pertaining to `Error`s.
* [numbers](#numbers): Wraps utility functions pertaining to numbers, e.g. generating random numbers.
* [platform](#platform): Wraps information about the platform, e.g. _is there a `window`? what is the current scroll position? is there local storage? etc._
* [throttle](#throttle): Wraps functionality to throttle function execution, e.g. `debounce`.
### component service<a name="component"></a>
The component service wraps utility functions useful when working with components.
#### [Methods](#component-methods)
* [`className(states, basename)`](#component.className)
* [`setInputValue(input, value)`](#component.setInputValue)
#### Methods<a name="component-methods"></a>
##### className(states, basename, [separator = `'--'`])<a name="component.className"></a>
Returns a class list string composed of the `basename` followed by the `basename` concatenated with any truthy properties in `states`, wherein the concatenation is separated by `separator` _(default: two dashes, `--`)_.
###### Example
```javascript
import React, { useState } from 'react';
import { component } from '/services';
const MyComponent = () => {
const [isDoingStuff, setIsDoingStuff] = useState(false);
// code manipulating isDoingStuff
const cn = component.className({
isDoingStuff
}, 'MyComponent');
// if isDoingStuff is true
// cn === "MyComponent MyComponent--isDoingStuff"
// else
// cn === "MyComponent"
return (
<div className={ cn }> // className="MyComponent MyComponent--isDoingStuff"
// ...
</div>
);
};
```
##### setInputValue(input, value)<a name="component.setInputValue"></a>
Sets the `value` of an [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) and triggers an `'input'` event. This is for example useful in cases where frameworks' event management makes it hard to programmatically trigger events that adhere to the native JavaScript event behaviour.
###### Example
```javascript
import React, { useEffect, useRef, useState } from 'react';
import { component } from '/services';
const MyComponent = ({
defaultValue = '',
onChange
}) => {
const [value, setValue] = useState(defaultValue);
const input = useRef();
useEffect(() => {
if (!input.current) {
return;
}
component.setInputValue(input.current, defaultValue);
}, [defaultValue]);
return (
<div>
// ...
<input
ref={ input }
onChange={ onChange }
value={ value }
/>
</div>
);
};
```
### error service<a name="error">></a>
The error service wraps utility functions pertaining to `Error`s.
#### [Methods](#error-methods)
* [`attachResponseToError(response, error)`](#error.attachResponseToError)
#### Methods<a name="error-methods"></a>
##### async attachResponseToError(response, error)<a name="error.attachResponseToError"></a>
Attaches HTTP [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) meta data to an `Error`. This is an `async` operation.
###### Example
```javascript
const response = await fetch('/some/api');
if (!response.ok) {
const error = new Error('Failing to fetch from API!');
// extract metadata such as headers, status, etc from response and attach to error object.
await attach(response, error);
throw error;
}
```
### numbers service<a name="numbers"></a>
The numbers service wraps utility functions pertaining to numbers, e.g. random number generation.
#### [Methods](#numbers-methods)
* [`rand({ min, max })`](#numbers.rand)
* [`randInt({ min, max })`](#numbers.randInt)
#### Methods<a name="numbers-methods"></a>
##### rand({ min = 0, max = 1 })<a name="numbers.rand"></a>
Returns a random floating point number between min (inclusive) and max (exclusive). Due to JavaScript rounding, the value will never equal `max`.
###### Example
```javascript
import { numbers } from '/services';
// generates a random number between 0 (inclusive) and 1 (exclusive)
const n = numbers.rand();
// generates a random number between 1 (inclusive) and 300 (exclusive)
const k = numbers.rand({ min: 1, max: 300});
```
##### randInt({ min, max })<a name="numbers.randInt"></a>
Returns a random integer number between min and max (inclusive).
###### Example
```javascript
import { numbers } from '/services';
// generates a random number between 0 (inclusive) and 3 (inclusive)
const n = numbers.randInt({ min: 0, max: 3 });
```
### platform service<a name="platform"></a>
The platform service wraps information about the current runtime platform, e.g. _is there a `window`? what is the current scroll position? is there local storage? etc._
#### [Properties](#platform-properties)
* [`hasDocument`](#platform.hasDocument)
* [`hasDocumenElement`](#platform.hasDocumentElement)
* [`hasLocalStorage`](#platform.hasLocalStorage)
* [`hasSessionStorage`](#platform.hasSessionStorage)
* [`hasWindow`](#platform.hasWindow)
#### [Methods](#platform-methods)
* [`scrollPosition()`](#platform.scrollPosition)
#### Properties<a name="#platform-properties"></a>
##### hasDocument<a name="platform.hasDocument"></a>
Boolean, indicating whether or not the current runtime provides a global `document` object.
###### Example
```javascript
import { platform } from '/services';
if (platform.hasDocument) {
// code that relies on global document object,
// e.g.
if (/utf-8/i.test(document.characterSet)) {
// do stuff that requires utf-8 encoding
}
}
```
##### hasDocumentElement<a name="platform.hasDocumentElement"></a>
Boolean, indicating whether or not the current runtime provides a global `document.documentElement` object.
###### Example
```javascript
import { platform } from '/services';
if (platform.hasDocumentElement) {
// code that relies on the existence of document.documentElement,
// e.g.
if (!(document.documentElement instanceof HTMLHtmlElement)) {
// do stuff the XML way, because we're not in an HTML document
}
}
```
##### hasLocalStorage<a name="platform.hasLocalStorage"></a>
Boolean, indicating whether or not the current runtime provides a global `window.localStorage` object.
###### Example
```javascript
import { platform } from '/services';
if (platform.hasLocalStorage) {
// code that relies on local storage,
// e.g.
window.localStorage.setItem('my-data', data);
} else {
// code that saves data elsewhere
}
```
##### hasSessionStorage<a name="platform.hasSessionStorage"></a>
Boolean, indicating whether or not the current runtime provides a global `window.sessionStorage` object.
###### Example
```javascript
import { platform } from '/services';
if (platform.hasSessionStorage) {
// code that relies on session storage,
// e.g.
window.sessionStorage.setItem('my-data', data);
} else {
// code that saves data elsewhere
}
```
##### hasWindow<a name="platform.hasWindow"></a>
Boolean, indicating whether or not the current runtime provides a global `window` object.
###### Example
```javascript
import { platform } from '/services';
if (platform.hasWindow) {
// code that relies on the global window object,
// e.g.
myComponent.scrollX = window.scrollX + 100;
}
```
#### Methods<a name="platform-methods"></a>
##### scrollPosition()<a name="platform.scrollPosition"></a>
Returns an object with properties `x` and `y` reflecting the current scroll position if applicaple, `null` otherwise.
###### Example
```javascript
import { platform } from '/services';
if (platform.hasWindow) {
window.addEventListener('scroll', () => {
console.log(platform.scrollPosition());
// will print objects like
// { x: 0, y: 10 }
});
} else if (!platform.hasDocument) {
console.log(platform.scrollPosition());
// will print null since there is neither document nor window!
}
```
### throttle service<a name="throttle"></a>
The throttle service wraps functionality used to throttle function execution, e.g. `debounce`.
##### [Methods](#throttle-methods)
* [`debounce(fn, debounceMs)`](#throttle.debounce)
#### Methods<a name="throttle-methods">
##### debounce(fn, debounceMs)<a name="throttle.debounce"></a>
Returns a new function that debounces `fn` by `debounceMs` milliseconds. Debouncing means `fn` is only executed if there are _no calls_ for `debounceMs` milliseconds.
###### Example<a name="throttle.debounce.example"></a>
```javascript
import { throttle, platform } from '/services';
if (platform.hasWindow) {
// only logs when there are no calls
// for 50 milliseconds
const onScroll = throttle.debounce(() => {
console.log(platform.scrollPosition());
}, 50);
window.addEventListener('scroll', onScroll);
}
```
## [Changelog](CHANGELOG.md)
## [License](LICENSE)