@ainias42/react-bootstrap-mobile 0.2.0 → 0.2.2

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.
Files changed (65) hide show
  1. package/bin/updateCopies.js +3 -2
  2. package/bootstrapReactMobile.ts +10 -0
  3. package/dist/bootstrapReactMobile.d.ts +10 -0
  4. package/dist/bootstrapReactMobile.js +1187 -606
  5. package/dist/bootstrapReactMobile.js.map +1 -1
  6. package/dist/src/Components/Clickable/Clickable.d.ts +6 -3
  7. package/dist/src/Components/Dialog/ButtonDialog.d.ts +5 -1
  8. package/dist/src/Components/Flavor.d.ts +3 -1
  9. package/dist/src/Components/FormElements/Button/Button.d.ts +4 -1
  10. package/dist/src/Components/FormElements/Controller/HookForm.d.ts +8 -0
  11. package/dist/src/Components/FormElements/Controller/InputController.d.ts +4 -0
  12. package/dist/src/Components/FormElements/Controller/MultipleFileInputController.d.ts +3 -0
  13. package/dist/src/Components/FormElements/Controller/PasswordInputController.d.ts +4 -0
  14. package/dist/src/Components/FormElements/Controller/SelectController.d.ts +3 -0
  15. package/dist/src/Components/FormElements/Controller/SendFormContext.d.ts +3 -0
  16. package/dist/src/Components/FormElements/Controller/TextareaController.d.ts +4 -0
  17. package/dist/src/Components/FormElements/Controller/withHookController.d.ts +4 -0
  18. package/dist/src/Components/FormElements/Input/FileInput/MultipleFileInput.d.ts +2 -1
  19. package/dist/src/Components/FormElements/Input/Input.d.ts +1 -0
  20. package/dist/src/Components/FormElements/Select/Select.d.ts +2 -1
  21. package/dist/src/Components/FormElements/Textarea/Textarea.d.ts +1 -0
  22. package/dist/src/Components/Hooks/useComposedRef.d.ts +1 -1
  23. package/dist/src/Components/Image/Image.d.ts +2 -2
  24. package/dist/src/Components/Layout/Grid/Grid.d.ts +1 -3
  25. package/dist/src/Components/List/InfiniteList.d.ts +7 -0
  26. package/dist/src/Components/List/List.d.ts +4 -2
  27. package/dist/src/Size.d.ts +8 -0
  28. package/package.json +5 -3
  29. package/src/Components/Clickable/Clickable.tsx +41 -6
  30. package/src/Components/Dialog/ButtonDialog.tsx +19 -10
  31. package/src/Components/Dialog/ConfirmDialog.tsx +1 -0
  32. package/src/Components/Dialog/buttonDialog.scss +20 -8
  33. package/src/Components/Flavor.ts +2 -0
  34. package/src/Components/FormElements/Button/Button.tsx +14 -8
  35. package/src/Components/FormElements/Button/button.scss +17 -0
  36. package/src/Components/FormElements/Controller/HookForm.tsx +43 -0
  37. package/src/Components/FormElements/Controller/InputController.ts +4 -0
  38. package/src/Components/FormElements/Controller/MultipleFileInputController.ts +4 -0
  39. package/src/Components/FormElements/Controller/PasswordInputController.ts +4 -0
  40. package/src/Components/FormElements/Controller/SelectController.ts +4 -0
  41. package/src/Components/FormElements/Controller/SendFormContext.ts +7 -0
  42. package/src/Components/FormElements/Controller/TextareaController.ts +4 -0
  43. package/src/Components/FormElements/Controller/withHookController.tsx +53 -0
  44. package/src/Components/FormElements/Input/FileInput/MultipleFileInput.tsx +4 -1
  45. package/src/Components/FormElements/Input/FileInput/fileInput.scss +5 -6
  46. package/src/Components/FormElements/Input/Input.tsx +17 -6
  47. package/src/Components/FormElements/Input/PasswordInput/PasswordInput.tsx +1 -1
  48. package/src/Components/FormElements/Input/input.scss +5 -0
  49. package/src/Components/FormElements/Select/Select.tsx +5 -0
  50. package/src/Components/FormElements/Select/select.scss +5 -0
  51. package/src/Components/FormElements/Textarea/Textarea.tsx +9 -4
  52. package/src/Components/FormElements/Textarea/textarea.scss +10 -1
  53. package/src/Components/FormElements/hooks/useOnChangeDone.ts +1 -1
  54. package/src/Components/Hooks/useComposedRef.ts +13 -16
  55. package/src/Components/Image/Image.tsx +2 -2
  56. package/src/Components/Layout/Grid/Grid.tsx +5 -4
  57. package/src/Components/List/InfiniteList.tsx +57 -0
  58. package/src/Components/List/List.tsx +14 -5
  59. package/src/Size.ts +9 -0
  60. package/src/scss/_baseClasses.scss +7 -11
  61. package/src/scss/_colors.scss +10 -5
  62. package/src/scss/_default.scss +2 -2
  63. package/src/scss/_flavorMixin.scss +6 -0
  64. package/src/scss/_variables.scss +2 -2
  65. package/webpack.config.js +1 -0
@@ -0,0 +1,4 @@
1
+ import { MultipleFileInput } from "../Input/FileInput/MultipleFileInput";
2
+ import { withHookController } from "./withHookController";
3
+
4
+ export const MultipleFileInputController = withHookController(MultipleFileInput, 'onChangeFiles');
@@ -0,0 +1,4 @@
1
+ import { withHookController } from "./withHookController";
2
+ import { PasswordInput } from "../Input/PasswordInput/PasswordInput";
3
+
4
+ export const PasswordInputController = withHookController(PasswordInput, "onChangeText");
@@ -0,0 +1,4 @@
1
+ import { withHookController } from "./withHookController";
2
+ import { Select } from "../Select/Select";
3
+
4
+ export const SelectController = withHookController(Select, "onChangeValue");
@@ -0,0 +1,7 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ export const SendFormContext = createContext<(() => void)|undefined>(undefined);
4
+
5
+ export function useSendFormContext(){
6
+ return useContext(SendFormContext);
7
+ }
@@ -0,0 +1,4 @@
1
+ import { withHookController } from "./withHookController";
2
+ import { Textarea } from "../Textarea/Textarea";
3
+
4
+ export const TextareaController = withHookController(Textarea, 'onChangeText');
@@ -0,0 +1,53 @@
1
+ import React, { ComponentProps, ComponentRef, ComponentType, ForwardedRef, useCallback } from "react";
2
+ import { FieldPath, FieldValues, useController, useFormContext } from "react-hook-form";
3
+ import { useComposedRef } from "../../Hooks/useComposedRef";
4
+ import { withForwardRef } from "../../../helper/withForwardRef";
5
+
6
+ export function withHookController<C extends ComponentType<any>, OnChangeProp extends keyof ComponentProps<C>>(Comp: C, onChangeProp: OnChangeProp, emptyValue: any = null) {
7
+ type RefType = ComponentRef<C>;
8
+ type OldProps = ComponentProps<C>;
9
+
10
+ type Props<Values extends FieldValues, Name extends FieldPath<Values> = FieldPath<Values>> = Omit<
11
+ OldProps,
12
+ 'name' | 'onBlur' | OnChangeProp | 'ref' | 'value'
13
+ > & { name: Name };
14
+
15
+ function WithHookComponent<Values extends FieldValues, Name extends FieldPath<Values> = FieldPath<Values>>(
16
+ {name, ...otherProps}: Props<Values, Name>,
17
+ ref?: ForwardedRef<RefType>
18
+ ) {
19
+ const children = "children" in otherProps ? otherProps.children : undefined;
20
+
21
+ const {field, fieldState} = useController({name});
22
+ const {clearErrors} = useFormContext();
23
+ const composedRef = useComposedRef(ref, field.ref);
24
+ const errorMessage = fieldState.error?.message;
25
+
26
+ const internalOnChange = useCallback(
27
+ (arg: any) => {
28
+ clearErrors(name);
29
+ field.onChange(arg);
30
+ },
31
+ [clearErrors, field, name]
32
+ );
33
+ const onChangeProps = {
34
+ [onChangeProp]: internalOnChange
35
+ }
36
+
37
+ return (
38
+ // @ts-expect-error Because of the prop spreading, typescript is really confused here
39
+ <Comp
40
+ {...otherProps}
41
+ {...field}
42
+ {...onChangeProps}
43
+ value={field.value ?? emptyValue}
44
+ ref={composedRef}
45
+ error={errorMessage}
46
+ >
47
+ {children}
48
+ </Comp>
49
+ );
50
+ }
51
+
52
+ return withForwardRef(WithHookComponent);
53
+ }
@@ -3,7 +3,6 @@ import {RbmComponentProps} from '../../../RbmComponentProps';
3
3
  import {Override} from '../../../../TypeHelpers';
4
4
  import {ChangeEventHandler, DragEvent, InputHTMLAttributes, useCallback, useRef} from 'react';
5
5
  import {Listener, useListenerWithExtractedProps} from '../../../Hooks/useListener';
6
-
7
6
  import styles from './fileInput.scss';
8
7
  import {withMemo} from '../../../../helper/withMemo';
9
8
  import classNames from 'classnames';
@@ -17,6 +16,7 @@ import {Image} from '../../../Image/Image';
17
16
  import {Clickable} from '../../../Clickable/Clickable';
18
17
  import {Inline} from '../../../Layout/Inline';
19
18
  import {FileType} from "./FileType";
19
+ import { InlineBlock } from "../../../Layout/InlineBlock";
20
20
 
21
21
 
22
22
  export type MultipleFileInputProps<OnChangeFilesData> = RbmComponentProps<
@@ -31,6 +31,7 @@ export type MultipleFileInputProps<OnChangeFilesData> = RbmComponentProps<
31
31
  onError?: (error: string) => void;
32
32
  allowOverride?: boolean
33
33
  showDeleteButton?: boolean
34
+ error?: string,
34
35
  } & Listener<'onChangeFiles', OnChangeFilesData, FileType[]>
35
36
  >
36
37
  >;
@@ -46,6 +47,7 @@ export const MultipleFileInput = withMemo(function MultipleImageInput<OnChangeDa
46
47
  allowOverride = maxFiles === 1,
47
48
  onError,
48
49
  showDeleteButton = true,
50
+ error,
49
51
  ...otherProps
50
52
  }: MultipleFileInputProps<OnChangeData>) {
51
53
  // Variables
@@ -275,6 +277,7 @@ export const MultipleFileInput = withMemo(function MultipleImageInput<OnChangeDa
275
277
  </Clickable>
276
278
  </Grow>
277
279
  </Flex>
280
+ {error && <InlineBlock className={styles.error}><Text>{error}</Text></InlineBlock>}
278
281
  </span>
279
282
  );
280
283
  },
@@ -79,11 +79,10 @@
79
79
 
80
80
  .value {
81
81
  display: none;
82
- //position: absolute;
83
- //top: 0;
84
- //left: 0;
85
- //right: 0;
86
- //bottom: 0;
87
- //opacity: 0;
82
+ }
83
+
84
+ .error {
85
+ font-size: 0.7rem;
86
+ --text-primary-default-color: var(--text-error)
88
87
  }
89
88
  }
@@ -5,7 +5,7 @@ import {
5
5
  KeyboardEvent,
6
6
  MutableRefObject,
7
7
  useCallback, useEffect,
8
- useMemo,
8
+ useMemo, useRef,
9
9
  } from 'react';
10
10
  import { RbmComponentProps } from '../../RbmComponentProps';
11
11
  import { Override } from '../../../TypeHelpers';
@@ -16,6 +16,9 @@ import styles from './input.scss';
16
16
  import classNames from 'classnames';
17
17
  import { useComposedRef } from '../../Hooks/useComposedRef';
18
18
  import { useOnChangeDone } from '../hooks/useOnChangeDone';
19
+ import { InlineBlock } from "../../Layout/InlineBlock";
20
+ import { Text } from "../../Text/Text";
21
+ import { useSendFormContext } from "../Controller/SendFormContext";
19
22
 
20
23
  export type InputProps<OnChangeData, OnBlurData, OnChangeDoneData> = RbmComponentProps<
21
24
  Override<
@@ -25,6 +28,7 @@ export type InputProps<OnChangeData, OnBlurData, OnChangeDoneData> = RbmComponen
25
28
  inline?: boolean;
26
29
  onChangeText?: (newText: string) => void;
27
30
  onEnter?: (newText: string) => void;
31
+ error?: string,
28
32
  } & OptionalListener<'onChange', OnChangeData> &
29
33
  OptionalListener<'onBlur', OnBlurData> &
30
34
  OptionalListener<'onChangeDone', OnChangeDoneData>
@@ -39,7 +43,9 @@ export const Input = withForwardRef(function Input<OnChangeData, OnBlurData, OnC
39
43
  onKeyDown,
40
44
  inline = false,
41
45
  value,
46
+ error,
42
47
  onChangeText,
48
+ onEnter,
43
49
  ...otherProps
44
50
  }: InputProps<OnChangeData, OnBlurData, OnChangeDoneData>,
45
51
  ref: MutableRefObject<HTMLInputElement> | null
@@ -77,9 +83,13 @@ export const Input = withForwardRef(function Input<OnChangeData, OnBlurData, OnC
77
83
  return "";
78
84
  }, [value, otherProps.max, otherProps.min, otherProps.type]);
79
85
  // Refs
80
- const innerRef = useComposedRef(ref);
86
+ const innerRef = useRef<HTMLInputElement>(null);
87
+ const refFunction = useComposedRef(ref, innerRef);
81
88
 
82
89
  // Callbacks
90
+ const sendForm = useSendFormContext();
91
+ onEnter ??= sendForm;
92
+
83
93
  const [onChangeWithData, otherPropsWithoutOnchange] = useListenerWithExtractedProps<'onChange', OnChangeData>(
84
94
  'onChange',
85
95
  otherProps
@@ -117,13 +127,13 @@ export const Input = withForwardRef(function Input<OnChangeData, OnBlurData, OnC
117
127
  const realOnKeyDown = useCallback(
118
128
  (e: KeyboardEvent<HTMLInputElement>) => {
119
129
  onKeyDown?.(e);
120
- if (otherProps.onEnter && e.key === 'Enter' && !e.defaultPrevented) {
130
+ if (onEnter && e.key === 'Enter' && !e.defaultPrevented) {
121
131
  if (otherProps.type === "number") {
122
132
  const stringValue = (e.target as HTMLInputElement).value;
123
133
  const val = !Number.isNaN(Number(stringValue)) ? stringValue : !Number.isNaN(parseFloat(stringValue)) ? String(parseFloat(stringValue)) : "";
124
- otherProps.onEnter(val);
134
+ onEnter(val);
125
135
  } else {
126
- otherProps.onEnter((e.target as HTMLInputElement).value);
136
+ onEnter((e.target as HTMLInputElement).value);
127
137
  }
128
138
  }
129
139
 
@@ -177,12 +187,13 @@ export const Input = withForwardRef(function Input<OnChangeData, OnBlurData, OnC
177
187
  {...otherPropsWithoutData}
178
188
  value={usedValue}
179
189
  type={otherProps.type === "number" ? "text" : otherProps.type}
180
- ref={innerRef}
190
+ ref={refFunction}
181
191
  className={styles.text}
182
192
  onBlur={onBlur}
183
193
  onChange={onChange}
184
194
  onKeyDown={realOnKeyDown}
185
195
  />
196
+ {error && <InlineBlock className={styles.error}><Text>{error}</Text></InlineBlock>}
186
197
  </label>
187
198
  );
188
199
  },
@@ -45,7 +45,7 @@ export const PasswordInput = withForwardRef(function PasswordInput<OnChangeData,
45
45
  <Grow>
46
46
  <Input {...props} type={isVisible ? 'text' : 'password'} ref={ref} />
47
47
  </Grow>
48
- <Clickable onClick={toggleVisible} className={styles.showButton}>
48
+ <Clickable onClick={toggleVisible} className={styles.showButton} interactable={false}>
49
49
  <Icon icon={isVisible ? faEye : faEyeSlash} />
50
50
  </Clickable>
51
51
  </Flex>
@@ -75,4 +75,9 @@
75
75
  }
76
76
  }
77
77
  }
78
+
79
+ .error {
80
+ font-size: 0.7rem;
81
+ --text-primary-default-color: var(--text-error)
82
+ }
78
83
  }
@@ -7,6 +7,8 @@ import {OptionalListener, useListenerWithExtractedProps} from '../../Hooks/useLi
7
7
  import styles from './select.scss';
8
8
  import { withMemo } from '../../../helper/withMemo';
9
9
  import classNames from 'classnames';
10
+ import { InlineBlock } from "../../Layout/InlineBlock";
11
+ import { Text } from "../../Text/Text";
10
12
 
11
13
  export type SelectOption = {
12
14
  label: string;
@@ -23,6 +25,7 @@ export type SelectProps<OnChangeData> = RbmComponentProps<
23
25
  onChangeValue?: (newValue: string) => void;
24
26
  inline?: boolean;
25
27
  small?: boolean;
28
+ error?: string;
26
29
  } & OptionalListener<'onChange', OnChangeData>
27
30
  >
28
31
  >;
@@ -35,6 +38,7 @@ export const Select = withMemo(function Select<OnChangeData>({
35
38
  onChangeValue,
36
39
  inline = false,
37
40
  small = false,
41
+ error,
38
42
  ...otherProps
39
43
  }: SelectProps<OnChangeData>) {
40
44
  // Variables
@@ -72,6 +76,7 @@ export const Select = withMemo(function Select<OnChangeData>({
72
76
  </option>
73
77
  ))}
74
78
  </select>
79
+ {error && <InlineBlock className={styles.error}><Text>{error}</Text></InlineBlock>}
75
80
  </label>
76
81
  );
77
82
  },
@@ -53,4 +53,9 @@
53
53
  height: initial;
54
54
  line-height: 1.5rem;
55
55
  }
56
+
57
+ .error {
58
+ font-size: 0.7rem;
59
+ --text-primary-default-color: var(--text-error)
60
+ }
56
61
  }
@@ -7,15 +7,16 @@ import {
7
7
  KeyboardEvent,
8
8
  ChangeEvent,
9
9
  MutableRefObject,
10
- CSSProperties
10
+ CSSProperties, useRef
11
11
  } from 'react';
12
12
  import { OptionalListener, useListenerWithExtractedProps } from '../../Hooks/useListener';
13
-
14
13
  import styles from './textarea.scss';
15
14
  import classNames from 'classnames';
16
15
  import { withForwardRef } from "../../../helper/withForwardRef";
17
16
  import { useOnChangeDone } from "../hooks/useOnChangeDone";
18
17
  import { useComposedRef } from "../../Hooks/useComposedRef";
18
+ import { InlineBlock } from "../../Layout/InlineBlock";
19
+ import { Text } from "../../Text/Text";
19
20
 
20
21
  export type TextareaProps<OnChangeData, OnChangeDoneData> = RbmComponentProps<
21
22
  Override<
@@ -27,6 +28,7 @@ export type TextareaProps<OnChangeData, OnChangeDoneData> = RbmComponentProps<
27
28
  onEscape?: (newText: string) => void;
28
29
  textareaStyles?: CSSProperties & Record<`--${string}`, string | number | undefined>,
29
30
  containerRef?: MutableRefObject<HTMLLabelElement|null>
31
+ error?: string,
30
32
  } & OptionalListener<'onChange', OnChangeData>
31
33
  & OptionalListener<'onChangeDone', OnChangeDoneData>
32
34
  >
@@ -42,10 +44,12 @@ export const Textarea = withForwardRef(function Textarea<OnChangeData, OnChangeD
42
44
  onEscape,
43
45
  textareaStyles,
44
46
  containerRef,
47
+ error,
45
48
  ...otherProps
46
49
  }: TextareaProps<OnChangeData, OnChangeDoneData>, ref: MutableRefObject<HTMLTextAreaElement> | null) {
47
50
  // Refs
48
- const innerRef = useComposedRef(ref);
51
+ const innerRef = useRef<HTMLTextAreaElement>(null);
52
+ const refSetter = useComposedRef(ref, innerRef);
49
53
 
50
54
  // Variables
51
55
 
@@ -98,7 +102,8 @@ export const Textarea = withForwardRef(function Textarea<OnChangeData, OnChangeD
98
102
  <label className={classNames(styles.container, className)} style={style} ref={containerRef}>
99
103
  {label ? <span className={styles.label}>{label}</span> : null}
100
104
  <textarea {...otherPropsWithoutData} style={textareaStyles} onKeyUp={realOnKeyPress}
101
- className={styles.textarea} onChange={onChange} ref={innerRef}/>
105
+ className={styles.textarea} onChange={onChange} ref={refSetter}/>
106
+ {error && <InlineBlock className={styles.error}><Text>{error}</Text></InlineBlock>}
102
107
  </label>
103
108
  );
104
109
  }, styles);
@@ -1,12 +1,16 @@
1
1
  .container {
2
2
  width: 100%;
3
- height: 10rem;
3
+ min-height: 10rem;
4
+ height: 100%;
5
+ display: flex;
6
+ flex-direction: column;
4
7
 
5
8
  .label {
6
9
  display: block;
7
10
  }
8
11
 
9
12
  textarea {
13
+ flex: 1;
10
14
  background-color: #efeff4;
11
15
  color: #1f1f21;
12
16
  box-shadow: none;
@@ -19,4 +23,9 @@
19
23
  border-radius: 4px;
20
24
  border: 1px solid var(--border-light);
21
25
  }
26
+
27
+ .error {
28
+ font-size: 0.7rem;
29
+ --text-primary-default-color: var(--text-error)
30
+ }
22
31
  }
@@ -10,7 +10,7 @@ export function useOnChangeDone(onChangeDone: (ev: any) => void, ref?: MutableRe
10
10
  return () => {
11
11
  elem?.removeEventListener('change', onChangeDone);
12
12
  };
13
- }, [ref, onChangeDone, usedRef]);
13
+ }, [onChangeDone, usedRef]);
14
14
 
15
15
  return usedRef;
16
16
  }
@@ -1,17 +1,14 @@
1
- import { ForwardedRef, useEffect, useRef } from 'react';
2
-
3
- export const useComposedRef = <T>(ref: ForwardedRef<T>, initialValue: T | null = null) => {
4
- const targetRef = useRef<T>(initialValue);
5
-
6
- useEffect(() => {
7
- if (!ref) return;
8
-
9
- if (typeof ref === 'function') {
10
- ref(targetRef.current);
11
- } else {
12
- ref.current = targetRef.current;
1
+ import { ForwardedRef, useCallback, useEffect, useRef } from 'react';
2
+
3
+ export function useComposedRef<RefVal>(...refs: (ForwardedRef<RefVal> | undefined)[]) {
4
+ return useCallback((val: RefVal | null) => {
5
+ for (const ref of refs) {
6
+ if (typeof ref === 'function') {
7
+ ref(val);
8
+ } else if (ref) {
9
+ ref.current = val;
10
+ }
13
11
  }
14
- }, [ref]);
15
-
16
- return targetRef;
17
- };
12
+ // eslint-disable-next-line react-hooks/exhaustive-deps
13
+ }, refs);
14
+ }
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { withMemo } from '../../helper/withMemo';
3
3
  import { RbmComponentProps, WithNoChildren } from '../RbmComponentProps';
4
- import { CSSProperties, DOMAttributes } from 'react';
4
+ import { CSSProperties } from 'react';
5
5
  import { Override } from '../../TypeHelpers';
6
6
 
7
7
  import styles from './image.scss';
@@ -9,7 +9,7 @@ import classNames from 'classnames';
9
9
 
10
10
  export type ImageProps = RbmComponentProps<
11
11
  Override<
12
- Omit<React.ComponentPropsWithoutRef<'img'>, keyof DOMAttributes<'img'>>,
12
+ React.ComponentPropsWithoutRef<'img'>,
13
13
  {
14
14
  src: string;
15
15
  style?: CSSProperties;
@@ -1,10 +1,10 @@
1
1
  import * as React from 'react';
2
- import { withMemo } from '../../../helper/withMemo';
3
2
  import { RbmComponentProps } from '../../RbmComponentProps';
4
3
  import { Block } from '../Block';
5
4
  import classNames from 'classnames';
6
5
  import styles from './grid.scss';
7
- import { useMemo } from 'react';
6
+ import { ForwardedRef, useMemo } from 'react';
7
+ import { withForwardRef } from "../../../helper/withForwardRef";
8
8
 
9
9
  export type GridProps = RbmComponentProps<{
10
10
  columns?: number;
@@ -12,7 +12,7 @@ export type GridProps = RbmComponentProps<{
12
12
  useContainerWidth?: boolean;
13
13
  }>;
14
14
 
15
- function Grid({ style, children, columns = 12, rows = 1, useContainerWidth = false, className, __allowChildren }: GridProps) {
15
+ function Grid({ style, children, columns = 12, rows = 1, useContainerWidth = false, className, __allowChildren }: GridProps, ref?:ForwardedRef<HTMLDivElement>) {
16
16
  // Variables
17
17
  const appliedStyle = useMemo(
18
18
  () => ({
@@ -39,6 +39,7 @@ function Grid({ style, children, columns = 12, rows = 1, useContainerWidth = fal
39
39
 
40
40
  return (
41
41
  <Block
42
+ ref={ref}
42
43
  style={appliedStyle}
43
44
  className={classNames(styles.grid, className, {[styles.useContainerWidth]: useContainerWidth})}
44
45
  __allowChildren={__allowChildren as 'all'}
@@ -49,5 +50,5 @@ function Grid({ style, children, columns = 12, rows = 1, useContainerWidth = fal
49
50
  }
50
51
 
51
52
  // Need RowMemo for autocompletion of phpstorm
52
- const GridMemo = withMemo(Grid, styles);
53
+ const GridMemo = withForwardRef(Grid, styles);
53
54
  export { GridMemo as Grid };
@@ -0,0 +1,57 @@
1
+ import React, { CSSProperties, ReactElement, ReactNode, useCallback, useState } from 'react';
2
+ import InfiniteLoader from "react-window-infinite-loader";
3
+ import { RbmComponentProps } from "../RbmComponentProps";
4
+ import { List, ListProps } from "./List";
5
+ import { withMemo } from "../../helper/withMemo";
6
+
7
+ export type InfiniteListProps<ItemType> = ListProps<ItemType> &{
8
+ hasNextPage: boolean,
9
+ loadNextPage: () => unknown | Promise<unknown>,
10
+ };
11
+
12
+ export const InfiniteList = withMemo(function InfiniteList<ItemType>({
13
+ renderItem,
14
+ itemHeight,
15
+ items,
16
+ renderBefore,
17
+ keyExtractor,
18
+ hasNextPage,
19
+ loadNextPage,
20
+ style,
21
+ className
22
+ }: InfiniteListProps<ItemType>) {
23
+ // Refs
24
+
25
+ // States/Variables/Selectors
26
+ const [isPageLoading, setIsPageLoading] = useState(false);
27
+
28
+ // Dispatch
29
+
30
+ // Callbacks
31
+ const isItemLoaded = useCallback((index: number) => !hasNextPage || index < items.length, [hasNextPage, items]);
32
+
33
+ const loadMore = useCallback(async () => {
34
+ if (!isPageLoading) {
35
+ setIsPageLoading(true);
36
+ try {
37
+ loadNextPage()
38
+ } finally {
39
+ setIsPageLoading(false);
40
+ }
41
+ }
42
+ }, [isPageLoading, loadNextPage])
43
+
44
+ // Effects
45
+
46
+ // Other
47
+
48
+ // RenderFunctions
49
+
50
+ return <InfiniteLoader isItemLoaded={isItemLoaded} loadMoreItems={loadMore}
51
+ itemCount={hasNextPage ? items.length + 1 : items.length}>{({onItemsRendered, ref}) => (
52
+ <List
53
+ items={items} renderItem={renderItem} style={style} className={className} itemHeight={itemHeight}
54
+ renderBefore={renderBefore} keyExtractor={keyExtractor} ref={ref} onItemsRendered={onItemsRendered}/>
55
+ )}
56
+ </InfiniteLoader>;
57
+ });
@@ -1,12 +1,13 @@
1
1
  import * as React from 'react';
2
- import { ComponentType, CSSProperties, ReactElement, ReactNode, useCallback, useState } from 'react';
2
+ import { ComponentType, CSSProperties, ForwardedRef, ReactElement, ReactNode, useCallback, useState } from 'react';
3
3
  import { RbmComponentProps } from '../RbmComponentProps';
4
4
 
5
5
  import styles from './list.scss';
6
6
  import { withMemo } from '../../helper/withMemo';
7
- import { FixedSizeList, ListChildComponentProps } from 'react-window';
7
+ import { FixedSizeList, FixedSizeListProps, ListChildComponentProps } from 'react-window';
8
8
  import AutoSizer from 'react-virtualized-auto-sizer';
9
9
  import { SizeCalculator, SizeCalculatorProps } from '../SizeCalculator/SizeCalculator';
10
+ import { withForwardRef } from "../../helper/withForwardRef";
10
11
 
11
12
  export type ListProps<ItemType> = RbmComponentProps<{
12
13
  renderItem: (item: ItemType, style: CSSProperties, index: number) => ReactElement;
@@ -14,15 +15,19 @@ export type ListProps<ItemType> = RbmComponentProps<{
14
15
  items: ItemType[];
15
16
  renderBefore?: (item: ItemType, index: number) => ReactNode;
16
17
  keyExtractor?: (item: ItemType, index: number) => string;
18
+ onItemsRendered?: FixedSizeListProps<ItemType>['onItemsRendered'];
19
+ autoSizeClassName?: string;
17
20
  }>;
18
21
 
19
- export const List = withMemo(function List<ItemType>({
22
+ export const List = withForwardRef(function List<ItemType>({
20
23
  items,
21
24
  renderItem,
22
25
  itemHeight: initialItemHeight = 0,
23
26
  className,
24
27
  style,
25
- }: ListProps<ItemType>) {
28
+ onItemsRendered,
29
+ autoSizeClassName,
30
+ }: ListProps<ItemType>, ref: ForwardedRef<FixedSizeList<ItemType>>) {
26
31
  // Variables
27
32
 
28
33
  // States
@@ -45,7 +50,7 @@ export const List = withMemo(function List<ItemType>({
45
50
  // Render Functions
46
51
 
47
52
  return (
48
- <AutoSizer>
53
+ <AutoSizer className={autoSizeClassName}>
49
54
  {({ height, width }: { height?: number; width?: number }) => {
50
55
  return (
51
56
  <>
@@ -54,6 +59,8 @@ export const List = withMemo(function List<ItemType>({
54
59
  {renderItem(
55
60
  items[0],
56
61
  {
62
+ visibility: 'hidden',
63
+ pointerEvents: 'none',
57
64
  position: 'relative',
58
65
  top: '0px',
59
66
  left: '0px',
@@ -66,6 +73,8 @@ export const List = withMemo(function List<ItemType>({
66
73
  )}
67
74
  {height !== undefined && width !== undefined && (
68
75
  <FixedSizeList
76
+ onItemsRendered={onItemsRendered}
77
+ ref={ref}
69
78
  height={height}
70
79
  itemCount={items.length}
71
80
  width={width}
package/src/Size.ts ADDED
@@ -0,0 +1,9 @@
1
+
2
+ export enum Size {
3
+ xSmall,
4
+ small,
5
+ medium,
6
+ large,
7
+ xLarge,
8
+ xxLarge,
9
+ };
@@ -1,12 +1,12 @@
1
- :global(.full-height) {
1
+ .full-height {
2
2
  height: 100%;
3
3
  }
4
4
 
5
- :global(.full-min-height) {
5
+ .full-min-height {
6
6
  min-height: 100%;
7
7
  }
8
8
 
9
- :global(.scrollable) {
9
+ .scrollable {
10
10
  overflow-y: auto;
11
11
  }
12
12
 
@@ -14,14 +14,10 @@
14
14
  width: 100%;
15
15
  }
16
16
 
17
- :global(.flat-hidden) {
18
- @include design($flat) {
19
- display: none;
20
- }
17
+ .#{$flat} .#{$flat}-hidden {
18
+ display: none;
21
19
  }
22
20
 
23
- :global(.material-hidden) {
24
- @include design($material) {
25
- display: none;
26
- }
21
+ .#{$material} .#{$material}-hidden {
22
+ display: none;
27
23
  }