@jasperoosthoek/react-toolbox 0.6.4 → 0.6.6

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.4",
3
+ "version": "0.6.6",
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;
@@ -169,7 +169,7 @@ export type DisabledProps = {
169
169
  initialValue: any;
170
170
  }
171
171
 
172
- export type FormSelectProps = Omit<FormInputProps, 'disabled' | 'onChange'> & {
172
+ export interface FormSelectProps extends Omit<FormInputProps, 'disabled' | 'onChange' | 'list'> {
173
173
  onChange: (value: number | string | number[] | string[] | null) => void;
174
174
  list: any[];
175
175
  multiple?: boolean;
@@ -357,48 +357,19 @@ export const FormBadgesSelection = ({
357
357
  );
358
358
  }
359
359
 
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;
360
+ export interface FormDropdownProps<T> extends Omit<FormInputProps, 'disabled' | 'onChange' | 'list'> {
361
+ onChange: (value: number | string | number[] | string[] | null) => void;
362
+ list: T[];
363
+ idKey?: keyof T;
364
+ nameKey?: keyof T;
396
365
  disabled?: boolean | ((props: DisabledProps) => boolean);
397
366
  variant?: Variant;
398
367
  }
399
- export const FormDropdown = ({
400
- list,
401
- id = 'id',
368
+
369
+ export const FormDropdown = <T,>({
370
+ list: listBase,
371
+ idKey = 'id' as keyof T,
372
+ nameKey = 'name' as keyof T,
402
373
  value,
403
374
  onChange,
404
375
  label,
@@ -409,13 +380,40 @@ export const FormDropdown = ({
409
380
  disabled,
410
381
  initialState,
411
382
  initialValue,
412
- variant='light',
413
- keyName,
383
+ variant = 'light',
414
384
  pristine,
385
+ keyName,
415
386
  ...restProps
416
- }: FormDropdownProps) => {
387
+ }: FormDropdownProps<T>) => {
417
388
  const { strings } = useLocalization();
418
- const selectedItem = list.find(({ [id]: itemId }) => itemId === value);
389
+
390
+ const [list, mismatch] = useMemo(() => {
391
+ if (!listBase || !Array.isArray(listBase)) {
392
+ return [null, null] as [T[] | null, any];
393
+ }
394
+ const mismatch = listBase?.find((item: any) => (
395
+ !['number', 'string'].includes(typeof item[idKey])
396
+ || !['number', 'string'].includes(typeof item[nameKey])
397
+ ))
398
+ if (mismatch) return [null, mismatch];
399
+ return [listBase, null];
400
+ }, [listBase])
401
+
402
+ if (!list) {
403
+ console.error(
404
+ `FormDropdown Error:
405
+ - Each item in 'list' must include a valid 'idKey' (${String(idKey)}) and 'nameKey' (${String(nameKey)}).
406
+ - Both keys must exist on every item and be of type 'string' or 'number'.
407
+ - One or more items failed this check.
408
+
409
+ Received list:`,
410
+ listBase,
411
+ ...mismatch ? ['First mismatch:', mismatch] : []
412
+ );
413
+ return null;
414
+ }
415
+
416
+ const selectedItem = list.find(item => item[idKey] === value);
419
417
  return (
420
418
  <Form.Group controlId={controlId}>
421
419
  {label && <Form.Label>{label}</Form.Label>}
@@ -424,7 +422,7 @@ export const FormDropdown = ({
424
422
  <Dropdown>
425
423
  <Dropdown.Toggle variant={variant}>
426
424
  {selectedItem
427
- ? selectedItem.name
425
+ ? selectedItem[nameKey] as string
428
426
  : strings.getString('choose_one')
429
427
  }
430
428
  </Dropdown.Toggle>
@@ -434,15 +432,15 @@ export const FormDropdown = ({
434
432
  key={key}
435
433
  disabled={
436
434
  typeof disabled === 'function'
437
- ? disabled({ initialValue, list, value: item[id], state, initialState })
435
+ ? disabled({ initialValue, list, value: item[idKey] as string, state, initialState })
438
436
  : disabled
439
437
  }
440
- selected={value === item[id]}
438
+ selected={value === item[idKey]}
441
439
  cursor='pointer'
442
- onClick={() => onChange(item[id])}
440
+ onClick={() => onChange(item[idKey] as any)}
443
441
  {...restProps}
444
442
  >
445
- {item.name}
443
+ {item[nameKey] as string}
446
444
  </Dropdown.Item>
447
445
  )}
448
446
  </Dropdown.Menu>
@@ -48,7 +48,7 @@ export type DataTableColumn<R> = {
48
48
  className?: string;
49
49
  value?: number | string | ((row: R) => number);
50
50
  formatSum?: ((value: number) => ReactElement | string | number) | ReactElement | string | number;
51
- selector: number | string | ((row: R) => ReactElement | string | number | (ReactElement | string | number)[]);
51
+ selector: number | string | ((row: R) => ReactElement | string | number | null | (ReactElement | string | number | null)[]);
52
52
  onClick?: OnClickRow<R>;
53
53
  }
54
54