@craigmcc/shared-react
v2.2.1
Published
Library of useful React components to be shared across applications.
Downloads
36
Maintainers
Readme
Shared React Components Library
This module contains a number of React components that I have shared across multiple applications the old fashioned way (cut-n-paste). It's time to make them a separate thing that can be maintained and updated in one place.
Installation
This library depends on the following peer dependencies, but is flexible about
which version is used. Check the peerDependencies
section of the
package.json
file to see what minimum versions are required.
If needed, you can install the peer dependencies:
npm install bootstrap react react-bootstrap react-bootstrap-icons react-dom react-hook-form react-toastify
To install this library itself:
npm install @craigmcc/shared-react
The components depend on react-bootstrap
(and therefore bootstrap
itself)
for styling, so somewhere in your application you will need to import the Bootstrap
styles. The easiest way is to include the following in your outermost App.tsx
or App.jsx
file:
import 'bootstrap/dist/css/bootstrap-min.css';
Likewise, you will need to import the react-toastify styles, along with the
declaration for the <ToastContainer>
component. Again, the easiest
way is to include the following in your outermost App.tsx
or App.jsx
file:
import {ToastContainer} from 'react-toastify';
import `react-toastify/dist/ReactToastify.css`;
Finally, in your App.tsx
or App.jsx
file, include a <ToastContainer>
component, normally above and outside all of your application components.
This component is used to configure the default characteristics for all
toast notifications that your application produces -- see the react-toastify
documentation for details.
Data Handler Types
The following function definitions are used to declare Typescript method signatures for functions that respond to events:
export type HandleAction = () => void;
export type HandleBoolean = (newBoolean: boolean) => void;
export type HandleValue = (newValue: string) => void;
Included Components
The following general purpose components are provided by this library:
| Component Name | Description | |---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| | AddButon | A stylized button with a "+" icon. | | BackButon | A stylized button with a "<" icon. | | Callout | A text area with variant background colors, useful in documentation. | | CheckBox | A standalone checkbox input, with optional decorations. Suitable for use cases where a form is overkill. | | Pagination | Very simple pagination controls when managing a multiple page table. | | SearchBar | General purpose search bar, with optional decorations. You can choose to be notified on each keystroke, or only when the value is completed. |
In addition, the following components render a <Form.Group>
element (from
react-bootstrap) that are useful in creating fields for an HTML form:
| Component Name | Description | |----------------------------------|---------------------------------------| | CheckBoxField | A form input element for a checkbox. | | SelectField | A form element for a select dropdown. | | TextField | A form element for a text input. |
Also, the following components render a toast notification, while a fetching or mutating operation is in progress. They are typically used in conjunction with a corresponding React custom hook that performs the requested function asynchronously, but this is not required.
| Component Name | Description | | --------------------------------- |------------------------------------------------------------------------------------------------| | FetchingProgress | Display a toast while a "fetching" API call is in progress, or an error toast if it fails. | | MutatingProgress | Display a toast while a "mutating" API call is in progress, or an error toast if it fails. |
AddButton
Usage
Import this component in your using component module (either JSX or TSX):
import {AddButton, HandleAction} from "@craigmcc/shared-react";
Then use it in your rendered return value, in the usual way:
<AddButton {AddButtonProps}/>
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value | |-----------|--------------|----------|-------------------------------------------------|----------------| | disabled | boolean | No | Should the rendered element be marked disabled? | false | | handleAdd | HandleAction | No | Function to handle button clicks | no handler | | testId | string | No | Optional "data-testid" value for tests | no data-testid |
BackButton
Usage
Import this component in your using component module (either JSX or TSX):
import {BackButton, HandleAction} from "@craigmcc/shared-react";
Then use it in your rendered return value, in the usual way:
<BackButton {BackButtonProps}/>
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value | |------------|--------------|----------|-------------------------------------------------|----------------| | disabled | boolean | No | Should the rendered element be marked disabled? | false | | handleBack | HandleAction | No | Function to handle button clicks | no handler | | testId | string | No | Optional "data-testid" value for tests | no data-testid |
Callout
Usage
Import this component in your using component module (either JSX or TSX):
import {Callout} from "@craigmcc/shared-react";
Then use it in your rendered return value, in the usual way:
<Callout {CalloutProps}/>
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value | |----------|-----------|----------|----------------------------------------------|---------------------------| | children | ReactNode | Yes | Text content to be rendered in this Callout | NO DEFAULT | | icon | boolean | No | Should a title icon be rendered? | true (if title specified) | | title | string | No | Optional title (header) for this Callout | no title | | variant | string | No | Bootstrap variant style for background color | info |
The variant values are the standard ones for Bootstrap: primary, secondary, success, danger, warning, info, light, and dark. This chooses the color of the background for the callout, and also the complementary color for the displayed text.
CheckBox
Usage:
Import this component in your using component module (either JSX or TSX):
import {CheckBox, HandleBoolean} from '@craigmcc/shared-react';
Then use it in your rendered return value, in the usual way:
<CheckBox {CheckBoxProps} />
Supported Configuration Properties:
| Name | Data Type | Required | Description | Default Value | |--------------|---------------|----------|-------------------------------------------------|---------------| | autoFocus | boolean | No | Should the rendered element receive autoFocus? | false | | disabled | boolean | No | Should the rendered element be marked disabled? | false | | handleChange | HandleBoolean | Yes | Function to handle value changes | NO DEFAULT | | label | string | Yes | Element label | NO DEFAULT | | name | string | No | Input control name | checkBox | | value | boolean | No | Initially rendered value | false |
Examples:
<CheckBox
handleChange={handleMagicChange}
label="Enable the magic?"
value={true}
/>
<form class="align-items-center">
<div id="checkBoxGroup">
<input type="checkbox" id="checkBox" class="form-check-input" checked>
<label for="checkBox" class="ms-2 form-check-label">Enable the magic?</label>
</div>
</form>
<CheckBox
disabled={true}
handleChange={handleActiveChange}
label="Active items only?"
name="active"
/>
<form class="align-items-center">
<div id="activeGroup">
<input disabled type="checkbox" id="active" class="form-check-input">
<label for="active" class="ms-2 form-check-label">Active items only?</label>
</div>
</form>
Behavior Notes:
- The
handleChange
function will be called whenever the checkbox is checked or unchecked.
CheckBoxField
Usage:
Import this component in your using component module (either JSX or TSX):
import {CheckBoxField} from "@craigmcc/shared-react";
Then use in your rendered return value (within a <Form>
component from react-boostrap)
in the usual way:
<CheckBoxField {CheckBoxFieldProps}/>
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value |
|-----------|-----------------|----------|-----------------------------------------------------------------|---------------|
| as | ElementType | No | Render the <Form.Group>
as a component of this type. | Col |
| autoFocus | boolean | No | Should this field receive autoFocus? | false |
| className | string | No | CSS style class names (space separated) for the <Form.Group>
. | none |
| disabled | boolean | No | Should this field be disabled? | false |
| error | FieldError | No | FieldError object for this field (if any). | no error |
| invalid? | string | No | Error message if input is invalid | no message |
| label | string | Yes | Field label. | NO DEFAULT |
| name | string | Yes | Name of this field (must be unique in a form). | NO DEFAULT |
| readOnly | boolean | No | Should this field be marked as read only? | false |
| register | UseFormRegister | Yes | register
object from useForm()
. | NO DEFAULT |
| type | string | No | Input control type ("checkbox" or "radio"). | checkbox |
Behavior Notes
- The field label will appear after the checkbox, in the usual react-bootstrap style.
FetchingProgress
Usage:
Import this component in your using component module (either JSX or TSX):
import {FetchingProgress} from '@craigmcc/shared-react';
Then, render this component somewhere in your component's output. The actual
location of the rendered toast is based on the settings you configured in the
<ToastContainer>
component described earlier.
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value |
|-----------|-----------------|----------|-----------------------------------------------------------------------|---------------------------------|
| duration | number | No | Number of ms to display this toast if not cleared (0=forever) | Default from <ToastContainer>
|
| error | Error or null | No | Error thrown by fetch logic (typically from a custom hook) | No notification |
| loading | boolean | No | Flag indicating a fetch is in progress (typically from a custom hook) | No notification |
| message | string | Yes | Message displayed in this toast while loading is in progress | NO DEFAULT |
Example:
Assume you have a custom hook that performs a fetch, and returns (among other things):
- error: Error | null - Javascript error thrown by the fetch operation.
- loading: boolean - Flag indicating that the fetch operation is in progress.
Then, you might include a progress component like this:
<FetchingProgress
error={customHook.error}
loading={customHook.loading}
message="Fetching selected customers"
/>
MutatingProgress
Usage:
Import this component in your using component module (either JSX or TSX):
import {MutatingProgress} from '@craigmcc/shared-react';
Then, render this component somewhere in your component's output. The actual
location of the rendered toast is based on the settings you configured in the
<ToastContainer>
component described earlier.
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value |
|-----------|-----------------|----------|--------------------------------------------------------------------------|---------------------------------|
| duration | number | No | Number of ms to display this toast if not cleared (0=forever) | Default from <ToastContainer>
|
| error | Error or null | No | Error thrown by mutating logic (typically from a custom hook) | No notification |
| executing | boolean | No | Flag indicating a mutation is in progress (typically from a custom hook) | No notification |
| message | string | Yes | Message displayed in this toast while mutation is in progress | NO DEFAULT |
Example:
Assume you have a custom hook that performs a mutation, and returns (among other things):
- error: Error | null - Javascript error thrown by the mutation operation.
- executing: boolean - Flag indicating that the mutation operation is in progress.
Then, you might include a progress component like this:
<MutatingProgress
error={customHook.error}
executing={customHook.executing}
message="Updating the selected order"
/>
Pagination
Usage:
Import this component in your using component module (either JSX or TSX):
import {Pagination, HandleAction} from '@craigmcc/shared-react';
Then use it in your rendered return value, in the usual way:
<Pagination {PaginationProps} />
Supported Configuration Properties:
| Name | Data Type | Required | Description | Default Value | |----------------|--------------|----------|-------------------------------------------------|-------------------| | currentPage | number | Yes | One-relative current page number | NO DEFAULT | | handleNext | HandleAction | No | Function to handle "next" button clicks | No handler | | handlePrevious | HandleAction | No | Function to handle "previous" button clicks | No handler | | lastPage | boolean | Yes | Is this the last page (disables "Next")? | NO DEFAULT | | variant | string | No | Bootstrap variant style for buttons | outline-secondary |
Examples:
<Pagination
handleNext={handlePaginationNext}
handlePrevious={handlePaginationPrevious}
lastPage={false}
variant="secondary"
/>
<button type="button" class="me-1 btn btn-secondary"><</button>
<button type="button" disabled class="me-1 btn btn-secondary">2</button>
<button type="button" class="btn btn-secondary">></button>
Behavior Notes:
- Previous Page control (
<
) will be disabled on the first page, and enabled otherwise. - Current page number will always be disabled. It is styled as a button for visual consistency only.
- Next Page control ('>') will be disabled if
lastPage
is set to true.
SearchBar
Usage:
Import this component in your using component module (either JSX or TSX):
import {SearchBar, HandleValue} from '@craigmcc/shared-react';
Then use it in your rendered return value, in the usual way:
<SearchBar {SearchBarProps} />
Supported Configuration Properties:
| Name | Data Type | Required | Description | Default Value | |--------------|-------------|----------|----------------------------------------------------|---------------| | autoFocus | boolean | No | Should the rendered element receive autoFocus? | false | | disabled | boolean | No | Should the rendered element be marked disabled? | false | | handleChange | HandleValue | No | Function to handle value changes on each keystroke | No handler | | handleValue | HandleValue | No | Function to handle value on enter/tab | No handler | | htmlSize | number | No | Number of characters hint for input control | Not set | | label | string | No | Element label | "Search For:" | | name | string | No | Input control name | searchBar | | placeholder | string | No | Placeholder text | Not set | | value | boolean | No | Initially rendered value | "" |
Examples:
<SearchBar
handleChange={handleSearchBarChange}
handleValue={handleSearchBarValue}
label="Select Customer:"
name="selectCustomer"
placeholder="Specify all or part of the customer name"
/>
<form class="align-items-center">
<div id="selectCustomerGroup" class="row">
<label for="selectCustomer" class="form-label col-auto">Select Customer:</label>
<div class="col-auto">
<input placeholder="Specify all or part of customer name" id="selectCustomer" class="form-control form-control-sm" value>
</div>
</div>
</form>
Behavior Notes:
- The
handleChange
function (if any) will be called on each keystroke. - The
handleValue
function (if any) will be called when Enter or Tab is pressed.
SelectField
Usage:
Import this component in your using component module (either JSX or TSX):
import {SelectField} from "@craigmcc/shared-react";
Then use in your rendered return value (within a <Form>
component from react-boostrap)
in the usual way:
<SelectField {SelectFieldProps}/>
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value |
|-----------|-----------------|----------|-----------------------------------------------------------------|---------------|
| as | ElementType | No | Render the <Form.Group>
as a component of this type. | Col |
| autoFocus | boolean | No | Should this field receive autoFocus? | false |
| className | string | No | CSS style class names (space separated) for the <Form.Group>
. | none |
| disabled | boolean | No | Should this field be disabled? | false |
| error | FieldError | No | FieldError object for this field (if any). | no error |
| header | SelectOption | No | Optional placeholder rendered above the options list. | none |
| label | string | Yes | Field label. | NO DEFAULT |
| name | string | Yes | Name of this field (must be unique in a form). | NO DEFAULT |
| options | SelectOption[] | Yes | Array of select options with label and value properties. | NO DEFAULT |
| readOnly | boolean | No | Should this field be marked as read only? | false |
| register | UseFormRegister | Yes | register
object from useForm()
. | NO DEFAULT |
| valid | string | No | Help message for valid input | none |
Behavior Notes
- The field label will appear above the select field, in the usual react-bootstrap style.
TextField
Usage:
Import this component in your using component module (either JSX or TSX):
import {TextField} from "@craigmcc/shared-react";
Then use in your rendered return value (within a <Form>
component from react-boostrap)
in the usual way:
<TextField {TextFieldProps}/>
Supported Configuration Properties
| Name | Data Type | Required | Description | Default Value |
|-------------|-----------------|----------|-----------------------------------------------------------------|---------------|
| as | ElementType | No | Render the <Form.Group>
as a component of this type. | Col |
| autoFocus | boolean | No | Should this field receive autoFocus? | false |
| className | string | No | CSS style class names (space separated) for the <Form.Group>
. | none |
| disabled | boolean | No | Should this field be disabled? | false |
| error | FieldError | No | FieldError object for this field (if any). | no error |
| htmlSize | number | No | HTML size of text field. | none |
| label | string | Yes | Field label. | NO DEFAULT |
| name | string | Yes | Name of this field (must be unique in a form). | NO DEFAULT |
| placeholder | string | No | Placeholder text when the field has no value. | none |
| readOnly | boolean | No | Should this field be marked as read only? | false |
| register | UseFormRegister | Yes | register
object from useForm()
. | NO DEFAULT |
| type | string | No | Input field type (date | hidden |month|number|password|text|time). | text
| valid | string | No | Help message for valid input | none |
Behavior Notes
- The field label will appear above the text field, in the usual react-bootstrap style.