@jasperoosthoek/react-toolbox 0.6.5 → 0.6.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@jasperoosthoek/react-toolbox",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "author": "jasperoosthoek",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,4 +1,4 @@
1
- import React, { ReactElement, ChangeEvent, KeyboardEvent } from 'react';
1
+ import React, { ReactElement, ChangeEvent, KeyboardEvent, useMemo } from 'react';
2
2
  import { Form, FormControl, Badge, Dropdown, BadgeProps, FormControlProps, FormCheckProps } from 'react-bootstrap';
3
3
  import { Variant} from 'react-bootstrap/types';
4
4
  import { useLocalization } from '../../localization/LocalizationContext';
@@ -34,7 +34,7 @@ export type FormType = {
34
34
  pristine: boolean;
35
35
  }
36
36
 
37
- export type FormInputProps = Omit<FormControlProps, 'onChange'> & FormType & {
37
+ export interface FormInputProps extends Omit<FormControlProps, 'onChange'>, FormType {
38
38
  onChange: (value: FormValue) => void;
39
39
  controlId?: string;
40
40
  label?: ReactElement;
@@ -92,7 +92,7 @@ export const FormDate = (props: FormInputProps) => (
92
92
  />
93
93
  )
94
94
 
95
- export type FormDateTimeProps = Omit<FormInputProps, 'onChange' | 'value'> & {
95
+ export interface FormDateTimeProps extends Omit<FormInputProps, 'onChange' | 'value'> {
96
96
  value: string | Moment;
97
97
  onChange: (value: string) => void;
98
98
  }
@@ -111,7 +111,7 @@ export const FormDateTime = ({ value, onChange, ...restProps }: FormDateTimeProp
111
111
  );
112
112
 
113
113
 
114
- export type FormCheckboxProps = Omit<FormCheckProps, 'onChange'> & FormType & {
114
+ export interface FormCheckboxProps extends Omit<FormCheckProps, 'onChange'>, FormType {
115
115
  onChange: (value: boolean) => void;
116
116
  controlId?: string;
117
117
  label?: ReactElement;
@@ -161,7 +161,6 @@ export const FormSwitch = ({ className = '', ...restProps }: FormCheckboxProps)
161
161
  );
162
162
 
163
163
  export type DisabledProps = {
164
-
165
164
  list: any[];
166
165
  value: string | number;
167
166
  state: any;
@@ -169,7 +168,7 @@ export type DisabledProps = {
169
168
  initialValue: any;
170
169
  }
171
170
 
172
- export type FormSelectProps = Omit<FormInputProps, 'disabled' | 'onChange'> & {
171
+ export interface FormSelectProps extends Omit<FormInputProps, 'disabled' | 'onChange' | 'list'> {
173
172
  onChange: (value: number | string | number[] | string[] | null) => void;
174
173
  list: any[];
175
174
  multiple?: boolean;
@@ -357,48 +356,19 @@ export const FormBadgesSelection = ({
357
356
  );
358
357
  }
359
358
 
360
- // export const FormSelectControl = ({
361
- // controlId,
362
- // label,
363
- // formProps,
364
- // onChange,
365
- // options,
366
- // defaultValue,
367
- // children,
368
- // ...restProps
369
- // }) => (
370
- // <InputGroup controlId={controlId}>
371
- // {label && <Form.Label>{label}</Form.Label>}
372
- // <FormControl as='select'
373
- // onChange={e => onChange(e.target.value)}
374
- // {...formProps}
375
- // {...restProps}
376
- // >
377
- // {options.map(({ value, children, ...option }) =>
378
- // <option
379
- // key={value}
380
- // value={value}
381
- // defaultValue={defaultValue}
382
- // {...option}
383
- // >
384
- // {children}
385
- // </option>
386
- // )}
387
- // </FormControl>
388
- // {children}
389
- // </InputGroup>
390
- // );
391
-
392
- export type FormDropdownProps = Omit<FormInputProps, 'disabled' | 'onChange'> & {
393
- onChange: (value: number | string | number[] | string[] | null) => void;
394
- list: any[];
395
- idKey?: string;
359
+ export interface FormDropdownProps<T> extends Omit<FormInputProps, 'disabled' | 'onChange' | 'list'> {
360
+ onChange: (value: number | string | number[] | string[] | null) => void;
361
+ list: T[];
362
+ idKey?: keyof T;
363
+ nameKey?: keyof T;
396
364
  disabled?: boolean | ((props: DisabledProps) => boolean);
397
365
  variant?: Variant;
398
366
  }
399
- export const FormDropdown = ({
400
- list,
401
- id = 'id',
367
+
368
+ export const FormDropdown = <T,>({
369
+ list: listBase,
370
+ idKey = 'id' as keyof T,
371
+ nameKey = 'name' as keyof T,
402
372
  value,
403
373
  onChange,
404
374
  label,
@@ -409,13 +379,40 @@ export const FormDropdown = ({
409
379
  disabled,
410
380
  initialState,
411
381
  initialValue,
412
- variant='light',
413
- keyName,
382
+ variant = 'light',
414
383
  pristine,
384
+ keyName,
415
385
  ...restProps
416
- }: FormDropdownProps) => {
386
+ }: FormDropdownProps<T>) => {
417
387
  const { strings } = useLocalization();
418
- const selectedItem = list.find(({ [id]: itemId }) => itemId === value);
388
+
389
+ const [list, mismatch] = useMemo(() => {
390
+ if (!listBase || !Array.isArray(listBase)) {
391
+ return [null, null] as [T[] | null, any];
392
+ }
393
+ const mismatch = listBase?.find((item: any) => (
394
+ !['number', 'string'].includes(typeof item[idKey])
395
+ || !['number', 'string'].includes(typeof item[nameKey])
396
+ ))
397
+ if (mismatch) return [null, mismatch];
398
+ return [listBase, null];
399
+ }, [listBase])
400
+
401
+ if (!list) {
402
+ console.error(
403
+ `FormDropdown Error:
404
+ - Each item in 'list' must include a valid 'idKey' (${String(idKey)}) and 'nameKey' (${String(nameKey)}).
405
+ - Both keys must exist on every item and be of type 'string' or 'number'.
406
+ - One or more items failed this check.
407
+
408
+ Received list:`,
409
+ listBase,
410
+ ...mismatch ? ['First mismatch:', mismatch] : []
411
+ );
412
+ return null;
413
+ }
414
+
415
+ const selectedItem = list.find(item => item[idKey] === value);
419
416
  return (
420
417
  <Form.Group controlId={controlId}>
421
418
  {label && <Form.Label>{label}</Form.Label>}
@@ -424,7 +421,7 @@ export const FormDropdown = ({
424
421
  <Dropdown>
425
422
  <Dropdown.Toggle variant={variant}>
426
423
  {selectedItem
427
- ? selectedItem.name
424
+ ? selectedItem[nameKey] as string
428
425
  : strings.getString('choose_one')
429
426
  }
430
427
  </Dropdown.Toggle>
@@ -434,15 +431,15 @@ export const FormDropdown = ({
434
431
  key={key}
435
432
  disabled={
436
433
  typeof disabled === 'function'
437
- ? disabled({ initialValue, list, value: item[id], state, initialState })
434
+ ? disabled({ initialValue, list, value: item[idKey] as number | string, state, initialState })
438
435
  : disabled
439
436
  }
440
- selected={value === item[id]}
437
+ selected={value === item[idKey]}
441
438
  cursor='pointer'
442
- onClick={() => onChange(item[id])}
439
+ onClick={() => onChange(item[idKey] as number | string)}
443
440
  {...restProps}
444
441
  >
445
- {item.name}
442
+ {item[nameKey] as string}
446
443
  </Dropdown.Item>
447
444
  )}
448
445
  </Dropdown.Menu>
@@ -67,9 +67,10 @@ export type OnMove<R> = ({ item, target, reset }: OnMoveProps<R>) => void;
67
67
  export type OnClickRow<R> = (row: R) => void;
68
68
 
69
69
  export type DataTableHeader = {
70
- search?: boolean,
71
- numberOfRows?: boolean,
72
- pagination?: boolean,
70
+ search?: boolean;
71
+ numberOfRows?: boolean;
72
+ pagination?: boolean;
73
+ customHeader?: ReactElement | string;
73
74
  };
74
75
 
75
76
  export type DataTableProps<D extends any[]> = {
@@ -211,14 +212,19 @@ export const DataTable = <D extends any[]>({
211
212
  )), [columns])
212
213
 
213
214
  if (!Component) return null;
215
+
216
+ const customHeader = showHeader && (showHeader as DataTableHeader).customHeader;
217
+ const sm = customHeader ? 4 : 6;
218
+ const lg = customHeader ? 3 : 4;
219
+
214
220
  return (
215
221
  <div style={style} className={className}>
216
- {showHeader &&
222
+ {(showHeader) &&
217
223
  <Row className="mb-4">
218
224
  {(showHeader === true || showHeader.search) && (
219
225
  <Col
220
226
  xs={12}
221
- lg={4}
227
+ lg={lg}
222
228
  className="d-flex flex-col justify-content-end align-items-end"
223
229
  >
224
230
  <InputGroup>
@@ -240,8 +246,8 @@ export const DataTable = <D extends any[]>({
240
246
  {(showHeader === true || showHeader.numberOfRows) && (
241
247
  <Col
242
248
  xs={12}
243
- sm={6}
244
- lg={4}
249
+ sm={sm}
250
+ lg={lg}
245
251
  className="d-flex flex-col justify-content-lg-center align-items-center justify-content-sm-start mb-2 mb-sm-0"
246
252
  >
247
253
  <Form.Group>
@@ -275,8 +281,8 @@ export const DataTable = <D extends any[]>({
275
281
  {(showHeader === true || showHeader.pagination) && (
276
282
  <Col
277
283
  xs={12}
278
- sm={6}
279
- lg={4}
284
+ sm={sm}
285
+ lg={lg}
280
286
  className="d-flex flex-col justify-content-end align-items-end"
281
287
  >
282
288
  <ButtonGroup>
@@ -308,6 +314,17 @@ export const DataTable = <D extends any[]>({
308
314
  </ButtonGroup>
309
315
  </Col>
310
316
  )}
317
+
318
+ {customHeader && (
319
+ <Col
320
+ xs={12}
321
+ sm={sm}
322
+ lg={lg}
323
+ className="d-flex flex-col justify-content-end align-items-end"
324
+ >
325
+ {customHeader}
326
+ </Col>
327
+ )}
311
328
  </Row>
312
329
  }
313
330