@ainias42/react-bootstrap-mobile 0.1.9 → 0.1.11

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.
@@ -1,10 +1,12 @@
1
1
  import { RbmComponentProps } from '../../RbmComponentProps';
2
2
  import { InputHTMLAttributes } from 'react';
3
- export type CheckboxProps = RbmComponentProps<{
3
+ import { Override } from '@ainias42/js-helper';
4
+ import { OptionalListener } from '../../Hooks/useListener';
5
+ export type CheckboxProps<OnChangeData, OnChangeCheckedData> = RbmComponentProps<Override<InputHTMLAttributes<HTMLInputElement>, {
4
6
  label?: string;
5
7
  children?: string;
6
8
  isLabelBeforeCheckbox?: boolean;
7
- } & InputHTMLAttributes<HTMLInputElement>>;
8
- declare function Checkbox({ children, label, isLabelBeforeCheckbox, id, className, style, ...props }: CheckboxProps): JSX.Element;
9
+ } & OptionalListener<'onChange', OnChangeData> & OptionalListener<'onChangeChecked', OnChangeCheckedData, boolean>>>;
10
+ declare function Checkbox<OnChangeData, OnChangeCheckedData>({ children, label, isLabelBeforeCheckbox, id, className, style, ...props }: CheckboxProps<OnChangeData, OnChangeCheckedData>): JSX.Element;
9
11
  declare const tmp: typeof Checkbox;
10
12
  export { tmp as Checkbox };
@@ -0,0 +1,20 @@
1
+ import { RbmComponentProps } from '../../RbmComponentProps';
2
+ import { Override } from '../../../TypeHelpers';
3
+ import { InputHTMLAttributes } from 'react';
4
+ import { Listener } from '../../Hooks/useListener';
5
+ export type FileType = {
6
+ name: string;
7
+ url: string;
8
+ mimeType: string;
9
+ uploaded?: boolean;
10
+ blob?: Blob;
11
+ };
12
+ export type MultipleImageInputProps<OnChangeFilesData> = RbmComponentProps<Override<Omit<InputHTMLAttributes<HTMLInputElement>, 'defaultValue' | 'onChange'>, {
13
+ value: FileType[];
14
+ label?: string;
15
+ mimeTypes?: string[];
16
+ maxFiles?: number;
17
+ maxSizePerFile?: number;
18
+ onError?: (error: string) => void;
19
+ } & Listener<'onChangeFiles', OnChangeFilesData, FileType[]>>>;
20
+ export declare const MultipleFileInput: <OnChangeData>({ className, style, value, label, mimeTypes, maxFiles, maxSizePerFile, onError, ...otherProps }: MultipleImageInputProps<OnChangeData>) => JSX.Element;
@@ -7,6 +7,6 @@ export type TextareaProps<OnChangeData> = RbmComponentProps<Override<TextareaHTM
7
7
  onChangeText?: (newText: string) => void;
8
8
  onEnter?: (newText: string) => void;
9
9
  } & OptionalListener<'onChange', OnChangeData>>>;
10
- declare function Textarea<OnChangeData>({ label, className, style, onKeyPress, onChangeText, onEnter, ...otherProps }: TextareaProps<OnChangeData>): JSX.Element;
10
+ declare function Textarea<OnChangeData>({ label, className, style, onKeyUp, onChangeText, onEnter, ...otherProps }: TextareaProps<OnChangeData>): JSX.Element;
11
11
  declare const TextareaMemo: typeof Textarea;
12
12
  export { TextareaMemo as Textarea };
@@ -1,14 +1,13 @@
1
1
  import * as React from 'react';
2
- import { ComponentPropsWithoutRef, PropsWithChildren } from 'react';
2
+ import { ComponentPropsWithoutRef } from 'react';
3
3
  import { Override } from '../../TypeHelpers';
4
- export type FullScreenProps<AsType extends keyof JSX.IntrinsicElements> = PropsWithChildren<Override<ComponentPropsWithoutRef<AsType>, {
4
+ import { RbmComponentProps } from '../RbmComponentProps';
5
+ export type FullScreenProps<AsType extends keyof JSX.IntrinsicElements> = RbmComponentProps<Override<ComponentPropsWithoutRef<AsType>, {
5
6
  as?: AsType;
6
7
  fullscreenKey?: string;
7
8
  onEnterFullscreen?: () => void;
8
9
  onLeaveFullscreen?: () => void;
9
10
  }>>;
10
- declare function FullScreen<AsTag extends keyof JSX.IntrinsicElements = 'span'>({ children, as, fullscreenKey, onEnterFullscreen, onLeaveFullscreen, ...otherProps }: FullScreenProps<AsTag>): React.ReactElement<Omit<FullScreenProps<AsTag>, "children" | "as" | "fullscreenKey" | "onEnterFullscreen" | "onLeaveFullscreen"> & {
11
- ref: React.RefObject<React.ComponentRef<AsTag>>;
12
- }, string | React.JSXElementConstructor<any>>;
11
+ declare function FullScreen<AsTag extends keyof JSX.IntrinsicElements = 'span'>({ children, as, fullscreenKey, onEnterFullscreen, onLeaveFullscreen, ...otherProps }: FullScreenProps<AsTag>): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
13
12
  declare const FullScreenMemo: typeof FullScreen;
14
13
  export { FullScreenMemo as FullScreen };
@@ -7,19 +7,22 @@ export type GridItemProps = RbmComponentProps<{
7
7
  lg?: number;
8
8
  xl?: number;
9
9
  xxl?: number;
10
+ print?: number;
10
11
  startXs?: number;
11
12
  startSm?: number;
12
13
  startMd?: number;
13
14
  startLg?: number;
14
15
  startXl?: number;
15
16
  startXxl?: number;
17
+ startPrint?: number;
16
18
  orderXs?: number;
17
19
  orderSm?: number;
18
20
  orderMd?: number;
19
21
  orderLg?: number;
20
22
  orderXl?: number;
21
23
  orderXxl?: number;
24
+ orderPrint?: number;
22
25
  }>;
23
- declare function GridItem({ style, children, className, __allowChildren, size, sm, md, lg, xl, xxl, startXs, startMd, startSm, startLg, startXl, startXxl, orderXs, orderSm, orderMd, orderLg, orderXxl, orderXl, }: GridItemProps): JSX.Element;
26
+ declare function GridItem({ style, children, className, __allowChildren, size, sm, md, lg, xl, xxl, print, startXs, startMd, startSm, startLg, startXl, startXxl, startPrint, orderXs, orderSm, orderMd, orderLg, orderXxl, orderXl, orderPrint, }: GridItemProps): JSX.Element;
24
27
  declare const GridItemMemo: typeof GridItem;
25
28
  export { GridItemMemo as GridItem };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainias42/react-bootstrap-mobile",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Mobile React Components using Bootstrap",
5
5
  "main": "dist/bootstrapReactMobile",
6
6
  "scripts": {
@@ -1,20 +1,26 @@
1
1
  import * as React from 'react';
2
2
  import { RbmComponentProps } from '../../RbmComponentProps';
3
- import { InputHTMLAttributes } from 'react';
3
+ import { ChangeEventHandler, InputHTMLAttributes, useCallback } from 'react';
4
4
 
5
5
  import styles from './checkbox.scss';
6
6
  import { withMemo } from '../../../helper/withMemo';
7
7
  import classNames from 'classnames';
8
+ import { Override } from '@ainias42/js-helper';
9
+ import { OptionalListener, useListenerWithExtractedProps } from '../../Hooks/useListener';
8
10
 
9
- export type CheckboxProps = RbmComponentProps<
10
- {
11
- label?: string;
12
- children?: string;
13
- isLabelBeforeCheckbox?: boolean;
14
- } & InputHTMLAttributes<HTMLInputElement>
11
+ export type CheckboxProps<OnChangeData, OnChangeCheckedData> = RbmComponentProps<
12
+ Override<
13
+ InputHTMLAttributes<HTMLInputElement>,
14
+ {
15
+ label?: string;
16
+ children?: string;
17
+ isLabelBeforeCheckbox?: boolean;
18
+ } & OptionalListener<'onChange', OnChangeData> &
19
+ OptionalListener<'onChangeChecked', OnChangeCheckedData, boolean>
20
+ >
15
21
  >;
16
22
 
17
- function Checkbox({
23
+ function Checkbox<OnChangeData, OnChangeCheckedData>({
18
24
  children,
19
25
  label = '',
20
26
  isLabelBeforeCheckbox = false,
@@ -22,7 +28,7 @@ function Checkbox({
22
28
  className,
23
29
  style,
24
30
  ...props
25
- }: CheckboxProps) {
31
+ }: CheckboxProps<OnChangeData, OnChangeCheckedData>) {
26
32
  // Variables
27
33
 
28
34
  // States
@@ -30,6 +36,23 @@ function Checkbox({
30
36
  // Refs
31
37
 
32
38
  // Callbacks
39
+ const [onChange, otherPropsWithoutChange] = useListenerWithExtractedProps<'onChange', OnChangeData>(
40
+ 'onChange',
41
+ props
42
+ );
43
+
44
+ const [onChangeChecked, otherPropsWithoutData] = useListenerWithExtractedProps<
45
+ 'onChangeChecked',
46
+ OnChangeCheckedData
47
+ >('onChangeChecked', otherPropsWithoutChange);
48
+
49
+ const onChangeInner = useCallback<ChangeEventHandler<HTMLInputElement>>(
50
+ (e) => {
51
+ onChangeChecked(e.target.checked);
52
+ onChange(e);
53
+ },
54
+ [onChange, onChangeChecked]
55
+ );
33
56
 
34
57
  // Effects
35
58
 
@@ -49,7 +72,13 @@ function Checkbox({
49
72
  <span className={classNames(styles.checkbox, className)} style={style}>
50
73
  <label htmlFor={id} key={id}>
51
74
  <span className={styles.label}>{preLabel}</span>
52
- <input {...props} type="checkbox" id={id} className={styles.input} />
75
+ <input
76
+ {...otherPropsWithoutData}
77
+ type="checkbox"
78
+ id={id}
79
+ className={styles.input}
80
+ onChange={onChangeInner}
81
+ />
53
82
  <span className={styles.checkmark} />
54
83
  <span className={styles.label}>{label}</span>
55
84
  </label>
@@ -39,6 +39,7 @@
39
39
 
40
40
  @include design($material) {
41
41
  width: 18px;
42
+ min-width: 18px;
42
43
  height: 18px;
43
44
  margin: 2px;
44
45
 
@@ -51,6 +52,7 @@
51
52
  }
52
53
  @include design($flat) {
53
54
  width: 22px;
55
+ min-width: 22px;
54
56
  height: 22px;
55
57
 
56
58
  &::before {
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { useCallback, useRef, useState, MouseEvent } from 'react';
2
+ import { useCallback, useRef, useState, MouseEvent, useEffect, useLayoutEffect } from 'react';
3
3
  import { Color, ColorChangeHandler, ColorResult, SketchPicker } from 'react-color';
4
4
  import { OptionalListener, useListener } from '../../Hooks/useListener';
5
5
  import { withMemo } from '../../../helper/withMemo';
@@ -50,6 +50,7 @@ function ColorInput<OnChangeData>({
50
50
 
51
51
  // Refs
52
52
  const containerRef = useRef<HTMLDivElement>(null);
53
+ const modalRef = useRef<HTMLDivElement>(null);
53
54
 
54
55
  // States
55
56
  const [color, setColor] = useState<string>(value ?? defaultValue ?? '#000000FF');
@@ -89,7 +90,6 @@ function ColorInput<OnChangeData>({
89
90
  (e: MouseEvent) => {
90
91
  if (e.target === containerRef?.current) {
91
92
  setIsOpen(false);
92
- console.log('onContainerClick', colVal);
93
93
  addColor(colVal);
94
94
  onClose?.(colVal);
95
95
  }
@@ -107,6 +107,19 @@ function ColorInput<OnChangeData>({
107
107
  );
108
108
 
109
109
  // Effects
110
+ useLayoutEffect(() => {
111
+ if (!modalRef.current) {
112
+ return;
113
+ }
114
+ const dimension = modalRef.current.getBoundingClientRect();
115
+ if (dimension.right > window.innerWidth || dimension.bottom > window.innerHeight) {
116
+ const newPosition = {
117
+ x: Math.max(0, Math.min(window.innerWidth - dimension.width, position.x)),
118
+ y: Math.max(0, Math.min(window.innerHeight - dimension.height, position.y)),
119
+ };
120
+ setPosition(newPosition);
121
+ }
122
+ }, [position]);
110
123
 
111
124
  // Other
112
125
 
@@ -115,7 +128,7 @@ function ColorInput<OnChangeData>({
115
128
  <span className={styles.colorInput}>
116
129
  {isOpen ? (
117
130
  <div onClick={onContainerClick} className={styles.modalContainer} ref={containerRef}>
118
- <div className={styles.modal} style={{ top: position.y, left: position.x }}>
131
+ <div className={styles.modal} style={{ top: position.y, left: position.x }} ref={modalRef}>
119
132
  <SketchPicker
120
133
  color={colVal}
121
134
  onChange={onChange}
@@ -23,6 +23,7 @@ export type ImageInputProps<OnChangeData> = RbmComponentProps<
23
23
  >
24
24
  >;
25
25
 
26
+ // TODO use MultipleFileInput internal
26
27
  function ImageInput<OnChangeData>({
27
28
  className,
28
29
  style,
@@ -79,7 +80,7 @@ function ImageInput<OnChangeData>({
79
80
 
80
81
  return (
81
82
  // eslint-disable-next-line jsx-a11y/label-has-associated-control
82
- <label className={classNames(styles.imageInput, className)} style={style}>
83
+ <label className={classNames(styles.fileInput, className)} style={style}>
83
84
  {label ? <span>{label}</span> : null}
84
85
  <img
85
86
  src={(value ?? image)?.url}
@@ -0,0 +1,240 @@
1
+ import * as React from 'react';
2
+ import { RbmComponentProps } from '../../RbmComponentProps';
3
+ import { Override } from '../../../TypeHelpers';
4
+ import { ChangeEventHandler, DragEvent, DragEventHandler, InputHTMLAttributes, useCallback, useRef } from 'react';
5
+ import { Listener, useListenerWithExtractedProps } from '../../Hooks/useListener';
6
+
7
+ import styles from './imageInput.scss';
8
+ import { withMemo } from '../../../helper/withMemo';
9
+ import classNames from 'classnames';
10
+ import { Block } from '../../Layout/Block';
11
+ import { Text } from '../../Text/Text';
12
+ import { Flex } from '../../Layout/Flex';
13
+ import { Grow } from '../../Layout/Grow';
14
+ import { Icon } from '../../Icon/Icon';
15
+ import { faPlus, faTimesCircle } from '@fortawesome/free-solid-svg-icons';
16
+ import { Image } from '../../Image/Image';
17
+ import { Clickable } from '../../Clickable/Clickable';
18
+ import { Inline } from '../../Layout/Inline';
19
+
20
+ export type FileType = { name: string; url: string; mimeType: string; uploaded?: boolean; blob?: Blob };
21
+
22
+ export type MultipleImageInputProps<OnChangeFilesData> = RbmComponentProps<
23
+ Override<
24
+ Omit<InputHTMLAttributes<HTMLInputElement>, 'defaultValue' | 'onChange'>,
25
+ {
26
+ value: FileType[];
27
+ label?: string;
28
+ mimeTypes?: string[];
29
+ maxFiles?: number;
30
+ maxSizePerFile?: number;
31
+ onError?: (error: string) => void;
32
+ } & Listener<'onChangeFiles', OnChangeFilesData, FileType[]>
33
+ >
34
+ >;
35
+
36
+ export const MultipleFileInput = withMemo(function MultipleImageInput<OnChangeData>({
37
+ className,
38
+ style,
39
+ value,
40
+ label,
41
+ mimeTypes = ['image/*'],
42
+ maxFiles = 1,
43
+ maxSizePerFile = 1024 * 1024 * 10,
44
+ onError,
45
+ ...otherProps
46
+ }: MultipleImageInputProps<OnChangeData>) {
47
+ // Variables
48
+
49
+ // Refs
50
+ const inputRef = useRef<HTMLInputElement>(null);
51
+
52
+ // States
53
+
54
+ // Selectors
55
+
56
+ // Callbacks
57
+ const checkMimeType = useCallback(
58
+ (fileType: string) => {
59
+ return mimeTypes.some((type) => {
60
+ if (type === '*/*' || type === '*') {
61
+ return true;
62
+ }
63
+ if (type.endsWith('/*')) {
64
+ return fileType.startsWith(type.substring(0, type.length - 2));
65
+ }
66
+ return fileType === type;
67
+ });
68
+ },
69
+ [mimeTypes]
70
+ );
71
+
72
+ const [onChangeFiles, ...props] = useListenerWithExtractedProps('onChangeFiles', otherProps);
73
+ const getBase64 = useCallback((inputFiles: Blob[]) => {
74
+ const promises = inputFiles.map(
75
+ (file) =>
76
+ new Promise<string>((resolve, reject) => {
77
+ const reader = new FileReader();
78
+ reader.onload = () => {
79
+ resolve(reader.result as string);
80
+ };
81
+ reader.onerror = reject;
82
+ reader.readAsDataURL(file);
83
+ })
84
+ );
85
+ return Promise.all(promises);
86
+ }, []);
87
+
88
+ const onNewFiles = useCallback(
89
+ async (newFiles: File[]) => {
90
+ if (newFiles.length + value.length > maxFiles) {
91
+ onError?.(`Es sind nur ${maxFiles} Dateien erlaubt.`);
92
+ return;
93
+ }
94
+
95
+ if (newFiles.some((file) => file.size > maxSizePerFile)) {
96
+ onError?.(`Eine Datei ist zu groß. Jede Datei darf nur ${maxSizePerFile / 1024 / 1024}MB groß sein.`);
97
+ return;
98
+ }
99
+
100
+ if (newFiles.some((file) => !checkMimeType(file.type))) {
101
+ onError?.('Eine Datei ist im falschen Format');
102
+ return;
103
+ }
104
+
105
+ const newUrls = await getBase64(newFiles);
106
+ const newValue = newFiles.map((file, index) => ({
107
+ name: file.name,
108
+ url: newUrls[index],
109
+ mimeType: file.type,
110
+ blob: file,
111
+ }));
112
+
113
+ onChangeFiles([...value, ...newValue]);
114
+ },
115
+ [checkMimeType, getBase64, maxFiles, maxSizePerFile, onChangeFiles, onError, value]
116
+ );
117
+
118
+ const onInputChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
119
+ async (e) => {
120
+ if (!e.target.files || e.target.files.length === 0) {
121
+ return;
122
+ }
123
+
124
+ const newFiles = Array.from(e.target.files);
125
+ await onNewFiles(newFiles);
126
+ },
127
+ [onNewFiles]
128
+ );
129
+
130
+ const removeFile = useCallback(
131
+ (_: any, index: number) => {
132
+ if (index >= 0 && index < value.length) {
133
+ const newData = [...value];
134
+ newData.splice(index, 1);
135
+ onChangeFiles(newData);
136
+ }
137
+ },
138
+ [onChangeFiles, value]
139
+ );
140
+
141
+ const onDrop = useCallback<DragEventHandler>(
142
+ async (event) => {
143
+ event.preventDefault();
144
+
145
+ const files: File[] = [];
146
+ if (event.dataTransfer.items) {
147
+ for (let i = 0; i < event.dataTransfer.items.length; i++) {
148
+ if (event.dataTransfer.items[i].kind === 'file') {
149
+ const file = event.dataTransfer.items[i].getAsFile();
150
+ if (file) {
151
+ files.push(file);
152
+ }
153
+ }
154
+ }
155
+ } else {
156
+ for (let i = 0; i < event.dataTransfer.files.length; i++) {
157
+ files.push(event.dataTransfer.files[i]);
158
+ }
159
+ }
160
+
161
+ await onNewFiles(files);
162
+ },
163
+ [onNewFiles]
164
+ );
165
+
166
+ const onDragOver = useCallback((e: DragEvent) => e.preventDefault(), []);
167
+
168
+ // Effects
169
+
170
+ // Other
171
+
172
+ // Render Functions
173
+ const renderFile = (file: FileType) => {
174
+ if (file.mimeType.startsWith('image/')) {
175
+ return (
176
+ <Image
177
+ key={file.url}
178
+ src={file.url}
179
+ alt={file.name}
180
+ className={classNames(styles.previewImage, file.url)}
181
+ />
182
+ );
183
+ }
184
+ // TODO style
185
+ return (
186
+ <Block>
187
+ <Text>{file.name}</Text>
188
+ </Block>
189
+ );
190
+ };
191
+
192
+ return (
193
+ <label
194
+ className={classNames(styles.fileInput, className)}
195
+ style={style}
196
+ onDrop={onDrop}
197
+ onDragOver={onDragOver}
198
+ >
199
+ <Flex horizontal={true}>
200
+ {!!label && (
201
+ <Grow>
202
+ <Text>{label}</Text>
203
+ </Grow>
204
+ )}
205
+ {maxFiles > 1 && (
206
+ <Inline>
207
+ <Text>
208
+ {value.length}/{maxFiles}
209
+ </Text>
210
+ </Inline>
211
+ )}
212
+ </Flex>
213
+ <Flex horizontal={true} className={styles.previewContainer}>
214
+ {value?.map((file, index) => (
215
+ <Grow className={styles.preview} center={true} key={file.url}>
216
+ {renderFile(file)}
217
+ <Clickable className={styles.previewRemove} onClick={removeFile} onClickData={index}>
218
+ <Icon icon={faTimesCircle} />
219
+ </Clickable>
220
+ </Grow>
221
+ ))}
222
+ {value.length < maxFiles && (
223
+ <Grow className={styles.addFile} center={true} __allowChildren="html">
224
+ <Icon icon={faPlus} />
225
+ <input
226
+ {...props}
227
+ ref={inputRef}
228
+ className={styles.value}
229
+ onChange={onInputChange}
230
+ type="file"
231
+ multiple={maxFiles > 1}
232
+ accept={mimeTypes.join(', ')}
233
+ />
234
+ </Grow>
235
+ )}
236
+ </Flex>
237
+ </label>
238
+ );
239
+ },
240
+ styles);
@@ -1,18 +1,53 @@
1
- .imageInput {
1
+ .fileInput {
2
2
  display: flex;
3
3
  flex-direction: column;
4
4
  position: relative;
5
5
  cursor: pointer;
6
6
 
7
- .preview {
8
- flex: 1;
9
- object-fit: contain;
7
+ .previewContainer {
8
+ align-items: stretch;
9
+ flex-grow: 1;
10
10
 
11
- &.empty {
12
- background-color: #d3d3d3;
11
+ .preview {
12
+ position: relative;
13
+ border: 1px solid var(--border-light);
14
+
15
+ .previewRemove {
16
+ position: absolute;
17
+ top: 5px;
18
+ right: 5px;
19
+ opacity: 0;
20
+ font-size: 1.5rem;
21
+
22
+ svg {
23
+ background: white;
24
+ }
25
+ }
26
+
27
+ &:hover .previewRemove {
28
+ opacity: 0.7;
29
+ }
30
+ }
31
+
32
+ .previewImage {
33
+ width: 100%;
34
+ height: 100%;
35
+ object-fit: contain;
36
+ }
37
+
38
+ .addFile {
39
+ position: relative;
40
+ border-radius: 3px;
41
+ background-color: var(--border-light);
42
+
43
+ display: flex;
44
+ justify-content: center;
45
+ align-items: center;
46
+ font-size: 2rem;
13
47
  }
14
48
  }
15
49
 
50
+
16
51
  .value {
17
52
  position: absolute;
18
53
  top: 0;
@@ -23,7 +23,7 @@ function Textarea<OnChangeData>({
23
23
  label,
24
24
  className,
25
25
  style,
26
- onKeyPress,
26
+ onKeyUp,
27
27
  onChangeText,
28
28
  onEnter,
29
29
  ...otherProps
@@ -48,14 +48,14 @@ function Textarea<OnChangeData>({
48
48
 
49
49
  const realOnKeyPress = useCallback(
50
50
  (e: KeyboardEvent<HTMLTextAreaElement>) => {
51
- if (onKeyPress) {
52
- onKeyPress(e);
51
+ if (onKeyUp) {
52
+ onKeyUp(e);
53
53
  }
54
54
  if (onEnter && e.key === 'Enter' && !e.defaultPrevented) {
55
55
  onEnter((e.target as HTMLTextAreaElement).value);
56
56
  }
57
57
  },
58
- [onEnter, onKeyPress]
58
+ [onEnter, onKeyUp]
59
59
  );
60
60
 
61
61
  // Effects
@@ -67,7 +67,7 @@ function Textarea<OnChangeData>({
67
67
  return (
68
68
  <label className={classNames(styles.container, className)} style={style}>
69
69
  {label ? <span className={styles.label}>{label}</span> : null}
70
- <textarea {...otherProps} onKeyPress={realOnKeyPress} className={styles.textarea} onChange={onChange} />
70
+ <textarea {...otherProps} onKeyUp={realOnKeyPress} className={styles.textarea} onChange={onChange} />
71
71
  </label>
72
72
  );
73
73
  }
@@ -1,18 +1,11 @@
1
1
  import * as React from 'react';
2
- import {
3
- ComponentPropsWithoutRef,
4
- ComponentRef,
5
- PropsWithChildren,
6
- useCallback,
7
- useEffect,
8
- useMemo,
9
- useRef,
10
- } from 'react';
2
+ import { ComponentPropsWithoutRef, ComponentRef, useCallback, useEffect, useMemo, useRef } from 'react';
11
3
  import { Override } from '../../TypeHelpers';
12
4
  import { withMemo } from '../../helper/withMemo';
13
5
  import { useWindow } from '../../WindowContext/WindowContext';
6
+ import { RbmComponentProps } from '../RbmComponentProps';
14
7
 
15
- export type FullScreenProps<AsType extends keyof JSX.IntrinsicElements> = PropsWithChildren<
8
+ export type FullScreenProps<AsType extends keyof JSX.IntrinsicElements> = RbmComponentProps<
16
9
  Override<
17
10
  ComponentPropsWithoutRef<AsType>,
18
11
  { as?: AsType; fullscreenKey?: string; onEnterFullscreen?: () => void; onLeaveFullscreen?: () => void }
@@ -81,6 +74,8 @@ function FullScreen<AsTag extends keyof JSX.IntrinsicElements = 'span'>({
81
74
  // Render Functions
82
75
  const element = as ?? 'span';
83
76
  const props = useMemo(() => ({ ...otherProps, ref: containerRef }), [otherProps]);
77
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
78
+ // @ts-ignore
84
79
  return React.createElement(element, props, children);
85
80
  }
86
81