@jasperoosthoek/react-toolbox 0.5.5 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@jasperoosthoek/react-toolbox",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "author": "jasperoosthoek",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/jasperoosthoek/react-toolbox.git"
9
9
  },
10
- "description": "Functional factory to create Redux actions and reducers that interface with a backend",
10
+ "description": "Extensive library of React components that work together with react-bootstrap",
11
11
  "files": [
12
12
  "src/",
13
13
  "dist/",
@@ -1,5 +1,5 @@
1
- import React, { useState, useRef, useContext, ChangeEvent, MouseEvent, ReactElement } from 'react';
2
- import { Button, ButtonProps as ReactBootstrapButtonProps, Modal, Form } from 'react-bootstrap';
1
+ import React, { useRef, ChangeEvent } from 'react';
2
+ import { Button, ButtonProps as ReactBootstrapButtonProps, Form } from 'react-bootstrap';
3
3
  import {
4
4
  AiFillCaretDown,
5
5
  AiFillCaretUp,
@@ -1,7 +1,6 @@
1
1
  import React, { ReactElement, ChangeEvent, KeyboardEvent } from 'react';
2
2
  import { Form, FormControl, Badge, Dropdown, BadgeProps, FormControlProps, FormCheckProps } from 'react-bootstrap';
3
3
  import { Variant} from 'react-bootstrap/types';
4
- import PropTypes from 'prop-types';
5
4
  import { useLocalization } from '../../localization/LocalizationContext';
6
5
  import moment, { Moment } from 'moment';
7
6
 
@@ -264,9 +263,6 @@ export const FormSelect = ({
264
263
  </Form.Group>
265
264
  </>;
266
265
  }
267
- FormSelect.propTypes = {
268
- onChange: PropTypes.func.isRequired,
269
- }
270
266
 
271
267
  export interface BadgeSelectionProps extends BadgeProps {
272
268
  selected: boolean;
@@ -32,7 +32,7 @@ export type Validate = (state: any) => any
32
32
  export type ModalTitle = ReactElement | string;
33
33
 
34
34
  export type Width = 25 | 50 | 75 | 100;
35
- export type CreateEditModalProps<
35
+ export type FormModalProps<
36
36
  T extends FormFields,
37
37
  K extends IncludeData<T>
38
38
  > = {
@@ -49,7 +49,7 @@ export type CreateEditModalProps<
49
49
  width?: Width;
50
50
  }
51
51
 
52
- export const CreateEditModal = <
52
+ export const FormModal = <
53
53
  T extends FormFields,
54
54
  K extends IncludeData<T>
55
55
  >({
@@ -65,9 +65,10 @@ export const CreateEditModal = <
65
65
  dialogClassName='',
66
66
  width,
67
67
  ...restProps
68
- }: CreateEditModalProps<T, K>) => {
68
+ }: FormModalProps<T, K>) => {
69
+
69
70
  if (Object.values(restProps).length !==0) {
70
- console.error(`Unrecognised props given to CreateEditModal:`, restProps);
71
+ console.error(`Unrecognised props given to FormModal:`, restProps);
71
72
  }
72
73
 
73
74
  const getInitialFormData = () => ({
@@ -9,26 +9,28 @@ import {
9
9
  Validate,
10
10
  ModalTitle,
11
11
  Width,
12
- CreateEditModal,
12
+ FormModal,
13
13
 
14
- } from './CreateEditModal';
14
+ } from './FormModal';
15
15
  import { FormValue } from './FormFields';
16
16
  import { ButtonProps, CreateButton, EditButton } from '../buttons/IconButtons';
17
- const out_of_context_error = 'The useError hook should only be used in a child of the CreateEditModalProvider component.';
18
17
 
19
18
  export type ShowCreateModal = (show?: boolean) => void;
20
19
  export type ShowEditModal<T, K> = (state: { [key in keyof T]: FormValue } & K) => void;
21
20
 
22
21
  export type ShowCreateModalButton = ButtonProps;
23
22
  export const ShowCreateModalButton = ({ onClick, ...props }: ButtonProps) => {
24
- const { showCreateModal } = useCreateEditModal();
23
+ const { showCreateModal, hasProvider } = useFormModal();
25
24
 
26
25
  return (
27
26
  <CreateButton
28
27
  {...props}
29
- onClick={(e) => {
28
+ onClick={(e) => {
29
+ // A onClick function was given to CreateButton
30
30
  if (onClick) onClick(e);
31
- showCreateModal();
31
+ // CreateButton is inside a CreateEditButtonProvider which can handle
32
+ // showCreateModal. Without the provider, showCreateModal will log an error
33
+ if (hasProvider) showCreateModal();
32
34
  }}
33
35
  />
34
36
  )
@@ -37,40 +39,45 @@ export interface ShowEditModalButtonProps<T, K> extends ButtonProps {
37
39
  state: { [key in keyof T]: FormValue } & K;
38
40
  }
39
41
  export const ShowEditModalButton = ({ state, onClick, ... props }: ShowEditModalButtonProps<T, K>) => {
40
- const { showEditModal } = useCreateEditModal();
42
+ const { showEditModal, hasProvider } = useFormModal();
41
43
 
42
44
  return (
43
45
  <EditButton
44
46
  {...props}
45
47
  onClick={(e) => {
48
+ // A onClick function was given to CreateButton
46
49
  if (onClick) onClick(e);
47
- showEditModal(state);
50
+ // CreateButton is inside a CreateEditButtonProvider which can handle
51
+ // showEditModal. Without the provider, showEditModal will log an error
52
+ if (hasProvider) showEditModal(state);
48
53
  }}
49
54
  />
50
55
  )
51
56
  }
52
57
 
53
- type CreateEditModalContextType<T, K> = {
58
+ type FormModalContextType<T, K> = {
54
59
  showCreateModal: ShowCreateModal;
55
60
  showEditModal: ShowEditModal<T, K>;
61
+ hasProvider: boolean;
56
62
  }
57
63
 
58
64
  type T = any;
59
65
  type K = any;
60
- const defaultErrorState: CreateEditModalContextType<T, K> = {
66
+ const defaultErrorState: FormModalContextType<T, K> = {
61
67
  showCreateModal: () => {
62
- console.error(out_of_context_error)
68
+ console.error('The showCreateModal function should only be used in a child of the FormModalProvider component.');
63
69
  },
64
- showEditModal: (state: { [key in keyof T]: FormValue } & K) => {
65
- console.error(out_of_context_error)
70
+ showEditModal: (state: { [key in keyof T]: FormValue } & K) => {
71
+ console.error('The showEditModal function should only be used in a child of the FormModalProvider component.');
66
72
  },
73
+ hasProvider: false,
67
74
  };
68
- export const CreateEditModalContext = React.createContext(defaultErrorState);
75
+ export const FormModalContext = React.createContext(defaultErrorState);
69
76
 
70
- export const useCreateEditModal = () => useContext(CreateEditModalContext);
77
+ export const useFormModal = () => useContext(FormModalContext);
71
78
 
72
79
 
73
- export type CreateEditModalProviderProps<
80
+ export type FormModalProviderProps<
74
81
  T extends FormFields,
75
82
  K extends IncludeData<T>
76
83
  > = {
@@ -88,7 +95,7 @@ export type CreateEditModalProviderProps<
88
95
  width?: Width;
89
96
  children: ReactNode;
90
97
  }
91
- export const CreateEditModalProvider: React.FC<CreateEditModalProviderProps<T, K>> = ({
98
+ export const FormModalProvider: React.FC<FormModalProviderProps<T, K>> = ({
92
99
  createModalTitle,
93
100
  editModalTitle,
94
101
  formFields,
@@ -104,16 +111,17 @@ export const CreateEditModalProvider: React.FC<CreateEditModalProviderProps<T, K
104
111
  const [instanceInEditModal, showEditModal] = useState<({ [key in keyof T]: FormValue } & K) | null>(null);
105
112
  const { strings } = useLocalization();
106
113
  return (
107
- <CreateEditModalContext.Provider
114
+ <FormModalContext.Provider
108
115
  value={{
109
116
  showCreateModal: (show?: boolean) =>
110
117
  showCreateModal(typeof show === 'undefined' ? true : show),
111
118
  showEditModal,
119
+ hasProvider: true,
112
120
  }}>
113
121
  {children}
114
122
 
115
123
  {createModalActive && (onCreate || onSave) && (
116
- <CreateEditModal
124
+ <FormModal
117
125
  modalTitle={createModalTitle || strings.getString('modal_create')}
118
126
  onHide={() => showCreateModal(false)}
119
127
  initialState={initialState}
@@ -125,7 +133,7 @@ export const CreateEditModalProvider: React.FC<CreateEditModalProviderProps<T, K
125
133
  />
126
134
  )}
127
135
  {instanceInEditModal && (onUpdate || onSave) && (
128
- <CreateEditModal
136
+ <FormModal
129
137
  show={!!instanceInEditModal}
130
138
  modalTitle={editModalTitle || strings.getString('modal_edit')}
131
139
  onHide={() => showEditModal(null)}
@@ -137,6 +145,6 @@ export const CreateEditModalProvider: React.FC<CreateEditModalProviderProps<T, K
137
145
  dialogClassName={dialogClassName}
138
146
  />
139
147
  )}
140
- </CreateEditModalContext.Provider>
148
+ </FormModalContext.Provider>
141
149
  );
142
150
  };
@@ -1,4 +1,3 @@
1
- import { useDragDropManager } from 'react-dnd';
2
1
  import React, {
3
2
  useEffect,
4
3
  useState,
@@ -7,6 +6,7 @@ import React, {
7
6
  ReactElement,
8
7
  ReactNode,
9
8
  ChangeEvent,
9
+ useMemo,
10
10
  Ref,
11
11
  } from 'react';
12
12
  import { FaSort, FaSortUp, FaSortDown } from 'react-icons/fa';
@@ -25,16 +25,11 @@ import {
25
25
  import { CloseButton } from '../buttons/IconButtons';
26
26
  import { DragAndDropList, DragAndDropListComponent, DragAndDropListComponentProps } from './DragAndDropList';
27
27
  import { useLocalization } from '../../localization/LocalizationContext';
28
- import { useCreateEditModal } from '../forms/CreateEditModalProvider';
28
+ import { useFormModal } from '../forms/FormModalProvider';
29
29
 
30
- const PaginationButton = (props: ButtonProps) => {
31
-
32
- const manager = useDragDropManager();
33
- console.log({ manager })
34
- return (
30
+ const PaginationButton = (props: ButtonProps) => (
35
31
  <Button variant='outline-secondary' size='sm' {...props} />
36
32
  )
37
- }
38
33
 
39
34
  export type OrderByColumn<R> = string | ((row: R) => string | number);
40
35
 
@@ -51,6 +46,8 @@ export type DataTableColumn<R> = {
51
46
  orderBy?: OrderByColumn<R>;
52
47
  optionsDropdown?: OptionsDropdown;
53
48
  className?: string;
49
+ value?: number | string | ((row: R) => number);
50
+ formatSum?: ((value: number) => ReactElement | string | number) | ReactElement | string | number;
54
51
  selector: number | string | ((row: R) => ReactElement | string | number | (ReactElement | string | number)[]);
55
52
  onClick?: OnClickRow<R>;
56
53
  }
@@ -93,6 +90,7 @@ export type DataTableProps<D extends any[]> = {
93
90
  className?: string;
94
91
  rowClassName?: string | ((row: D[number]) => string);
95
92
  style?: any;
93
+ showSum?: boolean;
96
94
  }
97
95
 
98
96
  export const DataTable = <D extends any[]>({
@@ -113,13 +111,11 @@ export const DataTable = <D extends any[]>({
113
111
  className,
114
112
  rowClassName,
115
113
  style,
114
+ showSum,
116
115
  ...restProps
117
116
  }: DataTableProps<D>) => {
118
- const { showEditModal } = useCreateEditModal()
117
+ const { showEditModal, hasProvider } = useFormModal();
119
118
  type R = D[number];
120
-
121
- const manager = useDragDropManager();
122
- console.log({ manager })
123
119
 
124
120
  if (Object.keys(restProps).length !== 0) console.error('Unrecognised props:', restProps);
125
121
 
@@ -186,7 +182,7 @@ export const DataTable = <D extends any[]>({
186
182
  {...{ ...(typeof onClickRow === 'function' || showEditModal)
187
183
  ? { onClick: () => {
188
184
  if (onClickRow) onClickRow(row);
189
- if (showEditModal) showEditModal(row);
185
+ if (hasProvider) showEditModal(row);
190
186
  } }
191
187
  : {}
192
188
  }}
@@ -207,6 +203,12 @@ export const DataTable = <D extends any[]>({
207
203
  )}
208
204
  </tr>
209
205
  );
206
+
207
+ const sums = useMemo(() => columns.map(({ value }) => (
208
+ value && data.reduce((sum, row) => (
209
+ sum + (typeof value === 'function' ? value(row) : row[value])
210
+ ), 0)
211
+ )), [columns])
210
212
 
211
213
  if (!Component) return null;
212
214
  return (
@@ -423,6 +425,25 @@ export const DataTable = <D extends any[]>({
423
425
  : data.map((row, index) => <Component row={row} key={index} />)
424
426
  }
425
427
  </tbody>
428
+ {showSum && (
429
+ <tfoot>
430
+ <tr>
431
+
432
+ {columns.map(({ value, formatSum }, index) =>
433
+ <td
434
+ key={index}
435
+ >
436
+ {value
437
+ ? (typeof formatSum === 'function'
438
+ ? formatSum(sums[index])
439
+ : sums[index]
440
+ )
441
+ : formatSum}
442
+ </td>
443
+ )}
444
+ </tr>
445
+ </tfoot>
446
+ )}
426
447
  </Table>
427
448
  </div>
428
449
  )
@@ -1,4 +1,3 @@
1
-
2
1
  import React, { useCallback, useEffect, useState, useRef, ReactElement } from 'react';
3
2
  import { useDrag, useDrop } from 'react-dnd';
4
3
 
package/src/index.ts CHANGED
@@ -4,8 +4,8 @@ export { default as ConfirmButton } from './components/buttons/ConfirmButton';
4
4
  export { default as DeleteConfirmButton } from './components/buttons/DeleteConfirmButton';
5
5
  export * from './components/buttons/DeleteConfirmButton';
6
6
 
7
- export * from './components/forms/CreateEditModal';
8
- export * from './components/forms/CreateEditModalProvider';
7
+ export * from './components/forms/FormModal';
8
+ export * from './components/forms/FormModalProvider';
9
9
  export * from './components/forms/FormFields';
10
10
 
11
11
  export * from './components/indicators/LoadingIndicator';