Wikia's reusable React parts.
1. Add it to your project
1.1. Change wikia scoped packages to use artifactory
This setup will work for both yarn
and npm
. If you run into issues consult Artifactory NPM Docs first
$> npm config set @wikia:registry https://artifactory.wikia-inc.com/artifactory/api/npm/wikia-npm/
$> npm config set @fandom:registry https://artifactory.wikia-inc.com/artifactory/api/npm/wikia-npm/
1.2. Add the package to package.json
$> yarn add @wikia/react-common
or
$> npm i @wikia/react-common
2. Use it in the code
import Button from '@wikia/react-common/components/Button';
import IconAdd from '@wikia/react-common/icons/IconAdd';
...
<div>
<Button>
<IconAdd />
Camera
</Button>
</div>
3. Add the CSS to your build
Make sure you include the CSS in your styles.
@import "~@wikia/react-common/components/Icon.css";
@import "~@wikia/react-common/components/Button.css";
[IMPORTANT] Artifactory Setup
This setup will work for both yarn
and npm
. If you run into issues consult Artifactory NPM Docs first
- Verify you can login to Artifactory Wikia
- Change wikia scoped packages to use artifactory
$> npm config set @wikia:registry https://artifactory.wikia-inc.com/artifactory/api/npm/wikia-npm/
- Login
$> npm login --scope=@wikia
- Use artifactory login and artifactory API key for password by going to "Edit Profile" in artifactory web ui
General guidelines
- ES6 React components with
prop-types
saved in.js
file. - Use function syntax if possible, use nesting and flat files.
- 100% lint and coverage and no regressions
- use Jest as a general testing framework and for testing component's rendering
- use Enzyme for testing interactions
- use Sinon for testing callbacks
Step-by-step guide for components
- Assuming the new component's name is
ComponentA
all it's files will be in/source/components/ComponentA/
directory. - Create component in
ComponentA/index.js
. - Add component to
/source/components/index.js
. - Add component to
/config/styleguide.config.json
. - (optionally) create styles in
ComponentA/styles.s?css
and import them inComponentA/index.js
. - Document the usage and props in JSDocs in
ComponentA/index.js
. - Add example or examples in
ComponentA/README.md
. - Add unit test in
ComponentA/index.spec.js
, aim for 100% coverage and all the test cases. - Create new Pull Request.
- Code will be merged to
master
only if there are no regressions and after a successful CR. - When the code is merged to
master
, release new version of the styleguide with one of the release commands.
HOCS
- Higher order components (hoc) can be added by following the guide
Note: The one difference will be to use js static
in the readme to prevent rendering as styleguidist doesn't have access to the hoc
Development server
> yarn dev
Tests
The easiest way is to run the full suite:
> yarn ci
It will run linting (ESLint, Stylelint), Jest and will output coverage report.
Watch
There's a command for watching Jest tests:
> yarn test:watch
Build
Running the build is as simple as:
> yarn build
This will run few build commands in sequence:
- Remove every generated file and directory from the
dist/
directory (equivalent ofyarn clean
). - Build the library outputting built ES5 files to the
dist/
(yarn lib:build
). - Build the styleguide in the
docs/
directory; it contains the build styleguide that will appear on the GitHub pages (yarn styleguide:build
).
Release
After PR is merged into master
branch create new release. You should use SemVer using one of the following commands.
The script will automatically pull newest master
branch, build the documentation, create new release version in the package.json
, create GitHub tag and push this tag to GitHub. After pushing the new tag it will publish the package to artifactory.
Default release; bugfixes, no new features and no breaking changes
> yarn release
New features, but no breaking changes
> yarn release:minor
Breaking changes, regardless how small
> yarn release:major
Theme values are provided in two different ways:
Theme object
The main theme
is just an object with values than can be easily used in plain JavaScript:
Can be used in plain JS
import theme from '@wikia/react-common/theme';
console.log(theme.color.fandom_aqua); // outputs '#00d6d6'
console.log(theme.color.font_size.l); // outputs '18px'
But it's also a ThemeProvider-ready:
import theme from '@wikia/react-common/theme';
const AquaText = styled.span`
color: ${props => props.theme.color.fandom_aqua};
font-family: ${props => props.theme.font_family};
font-size: ${props => props.theme.font_size.l};
@media ${props => props.theme.media.large_up} {
font-size: ${props => props.theme.font_size.xl}
}
`;
export default () => (
<ThemeProvider theme={theme}>
<AquaText>O hai</AquaText>
</ThemeProvider>
);
Theme object structure
Here's how the object looks like (values omitted):
const theme = {
breakpoint_values: /* .. */,
breakpoint_available_width: /* .. */,
breakpoint_available_width_values: /* same as `breakpoint_available_width` without units */,
color: /* .. */,
color_theme: {
light: /* .. */,
dark: /* .. */,
},
content_well_margin: /* ... */,
content_well_margin_value: /* same as `content_well` without units */,
font_family: /* .. */,
font_size: /* .. */,
font_size_value: /* same as `font_size` without units */,
font_weight: /* ... */,
line_height: /* ... */,
media: /* ... */,
};
You can see theme
's values in the source.
Changing theme (customization)
If you want to change/override or add new values to the theme
, there's a handy function for that:
import generateTheme from '@wikia/react-common/theme/generateTheme';
const customTheme = generateTheme({
color: {
link: 'blue',
},
});
Separate theme values
If you don't need the object, there are separate values available:
Breakpoints
The @wikia/react-common/theme/breakpoints
exports the following consts:
BREAKPOINTS
MEDIAQUERIES
CONTENT_WELL_MARGIN
CONTENT_WELL_MARGIN_PX
BREAKPOINTS_AVAILABLE_WIDTH
BREAKPOINTS_AVAILABLE_WIDTH_PX
Colors
The @wikia/react-common/theme/colors
exports the following consts:
COLORS
COLORS_LIGHT_THEME
COLORS_DARK_THEME
Typography
The @wikia/react-common/theme/typography
exports the following consts:
FONT_FAMILY
LINE_HEIGHTS
FONT_WEIGHTS
FONT_SIZES
FONT_SIZES_PX
There are three basic icon sizes: regular (24px), small (18px) and tiny (12px).
Every icon component has size
prop that can modify it's height and width;
in addition every icon's fill
color is defaulted to current color.
Usage:
@import <IconComponent> from '@wikia/react-common/icons/<IconComponent>';
Here's the list of all the icons in different sizes; hover over icon to see component's name
Logos, avatars and other assets
Complete system that can be used in React apps
This is system that controlls the state of site notifications, allows to add them via actions, and outputs them to a component.
It supports plaintext messages and automatically handles dismissing actions when the ⨯ icon is clicked on the notification.
Requirements
The BannerNotification system requires:
redux
(andreact-redux
)immutable
Installation
There are few parts that need to be plugged into place:
Reducer
The reducer/store need to be included in Redux.
Example:
import { BannerNotificationsStore } from '@wikia/react-common/systems/BannerNotifications';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
BannerNotificationsStore,
});
export default rootReducer;
Component
The component that connects to the Redux state needs to be included on the page somewhere so the notifications are visible.
import React from 'react';
import PropTypes from 'prop-types';
import FandomContentWell from '@wikia/react-common/components/FandomContentWell';
import { BannerNotificationsComponent } from '@wikia/react-common/systems/BannerNotifications';
class PageLayout extends React.Component {
static propTypes = {
children: PropTypes.node.isRequired,
}
render() {
return (
<FandomContentWell>
<BannerNotificationsComponent />
{children}
</FandomContentWell>
);
}
}
export default PageLayout;
NOTE: Remember to also include styles!
@import "~@wikia/react-common/systems/BannerNotifications.css";
API
BannerNotifications system exports few actions that should be used to add new notifications:
addAlert(text, [id])
addWarning(text, [id])
addSuccess(text, [id])
addMessage(text, [id])
The id
is optional and it's needed only when the notification needs to be manually removed with removeNotfication(id)
action. If omitted its value is assigned automatically.
Types of notifications are shown in components/BannerNotification section.
Example usage in thunk:
import axios from 'axios';
import { addAlert } from '@wikia/react-common/systems/BannerNotifications';
export const loadData = () => (
async dispatch => {
try {
const response = await axios({
method: 'get',
url: `/api/get-data`,
});
//...
} catch (error) {
dispatch(addAlert('Error loading data from the server'));
console.error(error);
}
}
);
React components
StyledArticleTagsSelector
component.
NOTE: Several props are arrays of Tag
s - Tag
is defined as follows:
interface Tag {
articleId: string;
articleTitle: string;
url?: string;
}
Non-empty state:
Empty state:
Too many tags state:
A styled-component
version of Avatar component
Defaults:
Different sizes:
With hover effect:
Avatar with badges
Defaults:
With maxStackSize
With hidden overflow
With overridden counter
This is a single component used in BannerNotifications
component.
By default its rendered without close button:
But it can be rendered with close buttton:
Or with extra HTML:
Component used to create notifications. For full functionality it needs some app logic to handle the array of messages - adding/removing.
See the following:
- https://github.com/Wikia/f2/blob/master/frontend/react-app/curationTools/containers/Notifications.jsx
- https://github.com/Wikia/f2/tree/master/frontend/react-app/curationTools/reducers/notifications
The messages
prop is an array of bannerNotificationsMessageType
objects with the following props:
id
: unique string that's send as the param of theonClose
functiontype
: one of:'alert'
,'warning'
,'success'
or'message'
.text
: text that is going to be displayed on the notificationpermanent
: a boolean flag - if present the close button won't be displayed on the notification
bannerNotificationsMessageType
is exported along with BannerNotification
By default it renders nothing:
But with proper data it can display all the messages:
Basic button component
Defaults:
Different styles:
Full width:
Button group component
Regular buttons:
Secondary buttons:
Defaults:
Disabled checkbox:
Each radio must have a value assigned to it.
Defaults:
Disabled:
ContentWell wraps children
in wds-content-well
CSS mixin.
Open this example in the new page to see the difference:
Simple circular, countdown-from-10 component with callback.
Click the theme buttons to re-initialize examples.
This timer is always stopped:
Simple circular, countdown-from-10 component with callback.
Click the theme buttons to re-initialize examples.
This timer is always stopped:
Basic Dropdown component
Defaults:
I am a text inside dropdown!
Dropdown using dropdown-tiny chevron:
I am a text inside dropdown!
Dropdown using more-small button:
I am a text inside dropdown!
Nested dropdown:
I am a text inside dropdown!
I am a text inside dropdown!
I am a text inside dropdown!
I am a text inside dropdown!
Defaults:
I am a text inside dropdown!
Dropdown using dropdown-tiny chevron:
I am a text inside dropdown!
Nested dropdown:
I am a text inside dropdown!
I am a text inside dropdown!
I am a text inside dropdown!
I am a text inside dropdown!
ExpandableText component can be used to temporarily limit text showed to the user. It has a button used to fully expand the text. If the source text is shorter than the limit the button do not show.
Both button label and string used to ellipsis has to be configured. Button and the text itself can be syled with classes passed to the component.
Defaults:
An image background that can be used as a sample image.
Defaults:
Custom width and className:
FandomContentWell wraps children
in wds-content-well($use-xxlarge-breakpoint: false)
CSS mixin.
Open this example in the new page to see the difference:
Defaults:
Floating button (icons-only)
Defaults:
Floating button group
Defaults:
Vertical:
Component that's used to either show or hide own children.
Since both show
and hide
shouldn't be used at the same time, hide
has a priority
hide | show | Component visible? |
---|---|---|
undefined | undefined | yes |
undefined | true | yes |
undefined | false | no |
true | (any value) | no |
false | (any value) | yes |
Hide:
Display
HighlightedText
is a text node with highlighted text.
One match:
Multiple matches:
No matches:
A single WDS icon.
NOTE: This icon is using IconSprite
component.
This component uses the Design System icons listed at https://fandomdesignsystem.com/#/components/assets
The name
attribute of the component refers to the icon's DS name.
NOTICE: This component requires <IconSprite />
to work.
Example usage
Standard icon:
Small or tiny icon:
Add your own CSS class for styling:
Other props are just passed to the SVG:
This component needs to be included once in the app in order to use <Icon>
component if there's no other way that the icons are included.
A helper component that encapsulates image preloading logic.
ImagePreloader
component can be used to load (or preload) any image. Both onChange
and children are functions that are called with ImagePreloader
's state with the following:
state
- the current state of the preloading - can be either
pending
,success
orerror
All the states are xported viaImagePreloader.STATE
const.
- the current state of the preloading - can be either
error
- a JavaScript
Error
object (if thestate
iserror
) or null
- a JavaScript
src
- taken from
ImagePreloader
's props
- taken from
srcSet
- taken from
ImagePreloader
's props
- taken from
Usage:
import ImagePreloader from '@wikia/react-common/components/ImagePreloader';
export default ImageWithLoadingMessage = () => (
<ImagePreloader src="http://path.to.image.jpg">
{({ state, src }) => {
if (state === ImagePreloader.STATE.PENDING) {
return <span>Loading image...</span>;
}
if (state === ImagePreloader.STATE.ERROR) {
return <span>Error loading image</span>;
}
return <img src={src} />;
}}
</ImagePreloader>
);
An empty input:
An empty email
input with hint:
Other available types are: text
(default), number
, email
, search
, tel
, url
and password
.
An empty email input with hint (node):
A non-empty input:
Disabled input:
Readonly input:
Input with placeholder:
A non-empty input with the error state:
An non-empty textarea:
An resizeable textarea:
An autoresizeable textarea:
An autoresizeable textarea with custom initial number of rows:
Default:
- First one
- Second one
- Third one
A list with "big items". This makes padding borader and the font size bigger in each element
- First one
- Second one
- Third one
A list with bolded elements.
- First one
- Second one
- Third one
A list with a separator line between each element.
- First one
- Second one
- Third one
A list with links. This is necessary to ensure the elements are fully clickable and are without any surrounding gaps.
A list with ellipsis.
- First one...
- Second one...
- Third one...
Default:
- First one
- Second one
- Third one
A list with "big items". This makes padding borader and the font size bigger in each element
- First one
- Second one
- Third one
A list with bolded elements.
- First one
- Second one
- Third one
A list with a separator line between each element.
- First one
- Second one
- Third one
A list with links. This is necessary to ensure the elements are fully clickable and are without any surrounding gaps.
A list with ellipsis.
- First one...
- Second one...
- Third one...
Open the source and search for "Portal demo".
<Portal id="asd">
<p>This Portal demo will be rendered in Body</p>
</Portal>
A select input. For post-interaction events (onBlur
, onChange
) the signature is onX(value, label)
for single-value selects, and onX([{value, label}, ...])
for multi-select.
Use Select.createOption
to create options to feed to the options
prop.
Basic usage:
Grouped options:
Non-searchable:
Loading indicator:
Multi-select
Controlled multi-input
Controlled single-input
Loader block component used to indicate loading state.
Based on http://fandomdesignsystem.com/#/components/progress-indicators
Defaults:
Custom size and stroke:
NOTE: This component should only be used with <Switch.Wrapper>
,
see <Switch>
above for a complete example.
NOTE: This component should only be used with <Switch.Item>
,
see <Switch>
above for a complete example.
Empty wrapper:
StyledTag
component. Used mostly as an ArticleTag
Defaults:
With extra options
The Timeago component is a small component that shows the number of seconds/minutes/days from given datetime.
One second ago:
Few minutes ago:
Few days ago:
Video Play icon
Defaults:
Custom size:
A standard error message when content cannot be displayed.
Error message:
Adds a hide
prop logic to newly created component
Usage
import withHideComponent from '@react-common/hocs/withHideComponent';
const Comp = props => (<div> test </div>)
const ComponentWithIsHidden = withTimeoutFallback(Spinner);
// Usage
<ComponentWithIsHidden hide/> // ComponentWithIsHidden will be hidden
<ComponentWithIsHidden /> // ComponentWithIsHidden will be visible
Adds a component to display after a set time (accurate to the nearest 100ms)
Usage
import withTimeoutFallback from '@react-common/hocs/withTimeoutFallback';
const Spinner = props => (<div> ...spinner </div>)
const SpinnerWithTimeout = withTimeoutFallback(Spinner);
// Usage
<SpinnerWithTimeout />
Custom Fallback and Timeout:
import withTimeoutFallback from '@react-common/hocs/withTimeoutFallback';
const Spinner = props => (<div> ...spinner </div>)
const Fallback = props => (<div> Error Loading </div>)
const options = {timeout: 10000, FallbackComponent: Fallback};
const SpinnerWithTimeout = withTimeoutFallback(Spinner, options);
// Usage
<SpinnerWithTimeout />
Add an error boundary to any component. By default every error will be sent to the remote log.
withErrorBoundary(Component, options);
The options
param is optional and can have the following:
options.name
- Boundary's name; this will be used in
console.log
and will be sent to remote log NOTE: By default it's equal toComponent.name
(class name of theComponent
HoC param)
- Boundary's name; this will be used in
options.fallback
- a component that will be displayed if there's an error
options.skipLog
- if
true
the remote log will not be used; useful for developing/debugging local code
- if
options.appName
- Front-End application's name; this is sent to remote log
options.appVersion
- Front-End application's verion; this is sent to remote log
There's handy component for fallback - StyledErrorDisplayingContent
;
Examples
Very basic usage:
import withErrorBoundary from '@react-common/hocs/withErrorBoundary';
const Component = props => (<div> Test </div>);
const ComponentWithErrorBoundary = withErrorBoundary(Component);
// Usage
<ComponentWithErrorBoundary />
Options:
import withErrorBoundary from '@react-common/hocs/withErrorBoundary';
const Component = props => (<div> Test </div>);
const FallbackComponent = () => (<div> Alternate error message </div>);
const ComponentWithErrorBoundary = withErrorBoundary(Component, {
name: 'BoundaryName',
fallback: FallbackComponent,
});
// Usage
<ComponentWithErrorBoundary />
Only render a component on the browser
Usage
import withDisabledSSR from '@react-common/hocs/withDisabledSSR';
const Component = props => (<div> ...spinner </div>)
const ComponentWithDisabledSSR = withDisabledSSR(Component);
// Usage
<ComponentWithDisabledSSR />
Custom hook that can be used for a periodical event.
The first param is the callback, the 2nd param is the delay between calls - null
can be used to pause.
Usage
import React, { useState } from 'react';
import useInterval from '@react-common/hooks/useInterval';
// Usage
const CounterComponent = () => {
const [value, setValue] = useState(0);
useInterval(() => {
setValue(value + 1);
}, 1000);
return (
<div>
Counter: <span>{value}</span>
</div>
);
};
Custom hook that calls given handler when element will be scrolled near (100px) it's bottom.
Returns an element to be used as a ref for scrollable element.
Usage
import useLazyLoad from '@react-common/hooks/useLazyLoad';
// Usage
const Component = ({ handler }) => {
const ref = useLazyLoad(handler);
return (
<div ref={ref}>
...
</div>
);
};
Hook to create a React Portal.
Automatically handles creating and tearing-down the root elements (no SRR makes this trivial), so there is no need to ensure the parent target already exists.
Usage
import usePortal from '@react-common/hooks/usePortal';
function Component({ id, children }) {
const target = usePortal(id, [id]);
return createPortal(children, target);
}
The utils/environment.js
offers a few environment config helpers including detection of browser and service urls based on the env.
Usage:
import { isBrowser, isFandomCom, getServicesBaseURL, isProduction, isSandbox, getEventLoggerBase } from '@wikia/react-common/utils/environment';
isProduction(); // checks if the app was built with the production flag (might not be in a prod env though)
isBrowser(); // checks if the window global is available
isFandomCom(); // used to determine the end points for services
isSandbox(); // checks if url is a sandbox
getServicesBaseURL(); // gives the correct services url base on the environment
getEventLoggerBase(); // correct event logger url
The utils/vignette.js
offers few utilities that can be used to deal with Vignette images - most importantly the validation and manipulation of Vignette's URLs.
Validation
There are two functions can be used to validate a proper Vignette ID and URL:
isVignetteUrl(url: String): Boolean
isVignetteId(id: String): Boolean
vignette(imageUrl): VignetteHelper
VignetteHelper
class
This class can be used to extract and manipulate URLs - it can extract Vignette params from given image and new options can be applied. Class' instance keeps the base image URL (server + ID) as well as all the Vignette params.
NOTE: The vignette(url)
function can be used instead of new VignetteHelper(url)
.
API
All the following are instance methods:
isOk(): Boolean
- returns true if the image has been correctly set
resetParams(): void
- resets Vignette params
set(url: String): Boolean
- extracts base image URL and params from Vignette URL; returns false if the URL is not a Vignette one
getParams(): String
- returns the Vigentte params
get(): String
- returns full Vignette URL
clone(): VignetteHelper
- returns clone of the instance
withScaleToHeight(height: Number, allowUpscaling: Boolean = false): void
- returns new instance with changed Vignette params
withScaleToWidth(width: Number, allowUpscaling: Boolean = false): void
- returns new instance with changed Vignette params
withThumbnail(width: Number, height: Number, allowUpscaling: Boolean = false): void
- returns new instance with changed Vignette params
withTopCrop(width: Number, height: Number): void
- returns new instance with changed Vignette params
withSmart(width: Number, height: Number): void
- returns new instance with changed Vignette params
withAuto(width: Number, height: Number, allowUpscaling: Boolean = false): void
- returns new instance with changed Vignette params
withTransform(): VignetteHelper
- returns clone of the instance with changed Vignette params
Usage:
import { VignetteHelper } from '@wikia/react-common/utils/vignette';
const ThumbImage = ({ alt, src, width, height }) => {
const image = new VignetteHelper(src);
const image300px = image.withScaleToWidth(300).get();
const srcSet = `
${image300px} 300w
${image.withScaleToWidth(600).get()} 600w
${image.withScaleToWidth(1000).get()} 2x
`;
return <img src={image300px} alt={alt} srcSet={srcSet} />;
}
// this will be the same as
import { VignetteHelper } from '@wikia/react-common/utils/vignette';
const ThumbImage = ({ alt, src, width, height }) => {
const standardImage = vignette(src);
const srcSet = `
${standardImage.withScaleToWidth(300).get()} 300w
${standardImage.withScaleToWidth(600).get()} 600w
${standardImage.withScaleToWidth(1000).get()} 2x
`;
return <img src={standardImage.get()} alt={alt} srcSet={srcSet} />;
}
More
Additionally, there are few other exports that are used internally, but might be useful:
VIGNETTE_DEFAULT_SERVER
VIGNETTE_MODES
VIGNETTE_UUID_REGEX
VIGNETTE_SERVER_REGEX
VIGNETTE_BASE_IMAGE_REGEX
The utils/copyToClipboard.js
utility can copy any string to the users clipboard if it coincides with a click.
Usage:
import copyToClipboard from '@wikia/react-common/utils/copyToClipboard';
function Component() {
return <div onClick={() => copyToClipboard('string-to-copy')} />
}
The utils/uuidv4.js
generates a UUID v4 on each call
Usage:
import uuidv4 from '@wikia/react-common/utils/uuidv4';
uuidv4(); // generates UUID v4
Wrappers for immutable.js Records.
Model
is a simple wrapper on top of immutable.js' Record in order to simplify Record's usage.
Usage
import Model from '@react-common/models/Model';
export const MY_MODEL_KEYS = Object.freeze({
type: 'type',
name: 'name',
});
const myModelSchema = {
[MY_MODEL_KEYS.type]: '',
[MY_MODEL_KEYS.name]: '',
};
export default class MyModel extends Model(myModelSchema, 'MyModel') {
// ...
}
Model provides few APIs:
Model.empty()
This always returns an empty instance of model (with fields set to what's defined in the schema). It's most useful when generating Redux reducers.
export default function MyStoreReducer(state = MyModel.empty(), action = {}) {
const { type } = action;
switch (type) {
// ...
default:
return state;
}
}
Model.build(...)
This builds Model from POJO (or Model instance) param. If the param is anything but Object or Model it will return undefined
instead.
const data = {
name: 'foo',
type: 'bar',
};
const instance = MyStore.build(data);
Model.buildList(...)
This builds a immutable.js List of Models from an array of POJO.
const data = [
{
name: 'foo',
type: 'bar',
},
{
name: 'another one',
type: 'another one too'
}
];
const list = MyStore.buildList(data);
Loadable
is a simple helper Model
that's intended to keep a loading state and provide an API similar to Finite-state Machine.
The Loadable
's state can be in one of four different states:
- Uninitialized (the default, initial state)
- In Progress
- Completed
- Error
Typical usage
Usually the Loadable
will start as uninitialized, after that it will get switched to In Progress and either Completed or Error state.
- (successful loading) Uninitialized -> In Progress -> Completed
- (unsuccessful loading) Uninitialized -> In Progress -> Error
APIs for reading state
Loadable.isLoadingUninitialized()
- returns
true
is the current state is Uninitialized
- returns
Loadable.isLoadingInProgress()
- returns
true
is the current state is In Progress
- returns
Loadable.isLoadingCompleted()
- returns
true
is the current state is Completed
- returns
Loadable.isLoadingError()
- returns
true
is the current state is Error
- returns
Loadable.isLoadingFinished()
- returns
true
is the current state is either Completed or Error (useful in checking if any loading action has been finished)
- returns
APIs for writing the state
Loadable.withLoadingInProgress()
- returns new instance with state set to In Progress
Loadable.withLoadingCompleted()
- returns new instance with state set to Completed
Loadable.withLoadingError()
- returns new instance with state set to Error