@idealyst/components 1.2.106 → 1.2.108
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 +4 -4
- package/src/Dialog/Dialog.native.tsx +1 -1
- package/src/Form/Form.native.tsx +38 -0
- package/src/Form/Form.styles.tsx +14 -0
- package/src/Form/Form.web.tsx +50 -0
- package/src/Form/FormContext.ts +12 -0
- package/src/Form/fields/FormCheckbox.tsx +27 -0
- package/src/Form/fields/FormField.tsx +11 -0
- package/src/Form/fields/FormRadioGroup.tsx +24 -0
- package/src/Form/fields/FormSelect.tsx +27 -0
- package/src/Form/fields/FormSlider.tsx +26 -0
- package/src/Form/fields/FormSwitch.tsx +26 -0
- package/src/Form/fields/FormTextArea.tsx +27 -0
- package/src/Form/fields/FormTextInput.tsx +55 -0
- package/src/Form/index.native.ts +35 -0
- package/src/Form/index.ts +35 -0
- package/src/Form/index.web.ts +35 -0
- package/src/Form/types.ts +105 -0
- package/src/Form/useForm.ts +279 -0
- package/src/Form/useFormField.ts +21 -0
- package/src/Popover/Popover.native.tsx +1 -1
- package/src/RadioButton/RadioButton.styles.tsx +28 -0
- package/src/RadioButton/RadioGroup.native.tsx +28 -3
- package/src/RadioButton/RadioGroup.web.tsx +37 -1
- package/src/RadioButton/types.ts +16 -0
- package/src/Screen/Screen.native.tsx +12 -3
- package/src/Select/Select.native.tsx +10 -6
- package/src/Select/Select.styles.tsx +8 -8
- package/src/Select/Select.web.tsx +11 -7
- package/src/Select/types.ts +4 -2
- package/src/Slider/Slider.native.tsx +122 -0
- package/src/Slider/Slider.styles.tsx +48 -11
- package/src/Slider/Slider.web.tsx +54 -5
- package/src/Slider/types.ts +15 -0
- package/src/Switch/Switch.native.tsx +48 -20
- package/src/Switch/Switch.styles.tsx +28 -0
- package/src/Switch/Switch.web.tsx +55 -16
- package/src/Switch/types.ts +10 -0
- package/src/TextInput/TextInput.native.tsx +123 -40
- package/src/TextInput/TextInput.styles.tsx +47 -9
- package/src/TextInput/TextInput.web.tsx +163 -51
- package/src/TextInput/types.ts +16 -1
- package/src/hooks/useSmartPosition.native.ts +1 -1
- package/src/index.native.ts +19 -0
- package/src/index.ts +19 -0
- package/src/internal/BoundedModalContent.native.tsx +1 -1
- package/src/internal/SafeAreaDebugOverlay.native.tsx +1 -1
|
@@ -6,7 +6,7 @@ import { isIconName } from '../Icon/icon-resolver';
|
|
|
6
6
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
7
7
|
import { textInputStyles } from './TextInput.styles';
|
|
8
8
|
import { TextInputProps } from './types';
|
|
9
|
-
import { getWebFormAriaProps } from '../utils/accessibility';
|
|
9
|
+
import { getWebFormAriaProps, combineIds, generateAccessibilityId } from '../utils/accessibility';
|
|
10
10
|
import type { IdealystElement } from '../utils/refTypes';
|
|
11
11
|
import { flattenStyle } from '../utils/flattenStyle';
|
|
12
12
|
|
|
@@ -31,6 +31,9 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
31
31
|
size = 'md',
|
|
32
32
|
type = 'outlined',
|
|
33
33
|
hasError = false,
|
|
34
|
+
error,
|
|
35
|
+
helperText,
|
|
36
|
+
label,
|
|
34
37
|
// Spacing variants from FormInputStyleProps
|
|
35
38
|
margin,
|
|
36
39
|
marginVertical,
|
|
@@ -65,6 +68,18 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
65
68
|
const isPasswordField = inputMode === 'password' || secureTextEntry;
|
|
66
69
|
const shouldShowPasswordToggle = isPasswordField && (showPasswordToggle !== false);
|
|
67
70
|
|
|
71
|
+
// Derive hasError from error prop or hasError boolean
|
|
72
|
+
const computedHasError = Boolean(error) || hasError;
|
|
73
|
+
|
|
74
|
+
// Determine if we need a wrapper (when label, error, or helperText is present)
|
|
75
|
+
const needsWrapper = Boolean(label) || Boolean(error) || Boolean(helperText);
|
|
76
|
+
|
|
77
|
+
// Generate unique IDs for accessibility
|
|
78
|
+
const inputId = useMemo(() => id || generateAccessibilityId('textinput'), [id]);
|
|
79
|
+
const errorId = useMemo(() => `${inputId}-error`, [inputId]);
|
|
80
|
+
const helperId = useMemo(() => `${inputId}-helper`, [inputId]);
|
|
81
|
+
const labelId = useMemo(() => label ? `${inputId}-label` : undefined, [inputId, label]);
|
|
82
|
+
|
|
68
83
|
// Get theme for icon sizes and colors
|
|
69
84
|
const { theme } = useUnistyles();
|
|
70
85
|
const iconSize = theme.sizes.input[size].iconSize;
|
|
@@ -138,7 +153,7 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
138
153
|
size,
|
|
139
154
|
type,
|
|
140
155
|
focused: isFocused,
|
|
141
|
-
hasError,
|
|
156
|
+
hasError: computedHasError,
|
|
142
157
|
disabled,
|
|
143
158
|
margin,
|
|
144
159
|
marginVertical,
|
|
@@ -146,19 +161,34 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
146
161
|
});
|
|
147
162
|
|
|
148
163
|
// Get web props for all styled elements (all styles are dynamic functions)
|
|
149
|
-
const dynamicContainerStyle = (textInputStyles.container as any)({ type, focused: isFocused, hasError, disabled });
|
|
150
|
-
const {ref: containerStyleRef, ...containerProps} = getWebProps([dynamicContainerStyle, flattenStyle(style)]);
|
|
164
|
+
const dynamicContainerStyle = (textInputStyles.container as any)({ type, focused: isFocused, hasError: computedHasError, disabled });
|
|
165
|
+
const {ref: containerStyleRef, ...containerProps} = getWebProps([dynamicContainerStyle, !needsWrapper && flattenStyle(style)].filter(Boolean));
|
|
151
166
|
const leftIconContainerProps = getWebProps([(textInputStyles.leftIconContainer as any)({})]);
|
|
152
167
|
const rightIconContainerProps = getWebProps([(textInputStyles.rightIconContainer as any)({})]);
|
|
153
168
|
const passwordToggleProps = getWebProps([(textInputStyles.passwordToggle as any)({})]);
|
|
154
169
|
|
|
170
|
+
// Wrapper, label, and footer styles
|
|
171
|
+
const wrapperStyleComputed = (textInputStyles.wrapper as any)({});
|
|
172
|
+
const labelStyleComputed = (textInputStyles.label as any)({ disabled });
|
|
173
|
+
const footerStyleComputed = (textInputStyles.footer as any)({});
|
|
174
|
+
const helperTextStyleComputed = (textInputStyles.helperText as any)({ hasError: computedHasError });
|
|
175
|
+
|
|
176
|
+
const wrapperProps = getWebProps([wrapperStyleComputed, flattenStyle(style)]);
|
|
177
|
+
const labelProps = getWebProps([labelStyleComputed]);
|
|
178
|
+
const footerProps = getWebProps([footerStyleComputed]);
|
|
179
|
+
const helperTextProps = getWebProps([helperTextStyleComputed]);
|
|
180
|
+
|
|
155
181
|
// Get input props
|
|
156
182
|
const inputWebProps = getWebProps([(textInputStyles.input as any)({})]);
|
|
157
183
|
|
|
158
184
|
// Generate accessibility props
|
|
159
185
|
const ariaProps = useMemo(() => {
|
|
160
|
-
// Derive invalid state from
|
|
161
|
-
const isInvalid = accessibilityInvalid ??
|
|
186
|
+
// Derive invalid state from computedHasError or explicit accessibilityInvalid
|
|
187
|
+
const isInvalid = accessibilityInvalid ?? computedHasError;
|
|
188
|
+
const describedByIds = combineIds(
|
|
189
|
+
accessibilityDescribedBy,
|
|
190
|
+
error ? errorId : helperText ? helperId : undefined
|
|
191
|
+
);
|
|
162
192
|
|
|
163
193
|
return getWebFormAriaProps({
|
|
164
194
|
accessibilityLabel,
|
|
@@ -166,8 +196,8 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
166
196
|
accessibilityDisabled: accessibilityDisabled ?? disabled,
|
|
167
197
|
accessibilityHidden,
|
|
168
198
|
accessibilityRole: accessibilityRole ?? 'textbox',
|
|
169
|
-
accessibilityLabelledBy,
|
|
170
|
-
accessibilityDescribedBy,
|
|
199
|
+
accessibilityLabelledBy: accessibilityLabelledBy ?? labelId,
|
|
200
|
+
accessibilityDescribedBy: describedByIds,
|
|
171
201
|
accessibilityControls,
|
|
172
202
|
accessibilityExpanded,
|
|
173
203
|
accessibilityPressed,
|
|
@@ -175,7 +205,7 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
175
205
|
accessibilityHasPopup,
|
|
176
206
|
accessibilityRequired,
|
|
177
207
|
accessibilityInvalid: isInvalid,
|
|
178
|
-
accessibilityErrorMessage,
|
|
208
|
+
accessibilityErrorMessage: accessibilityErrorMessage ?? (error ? errorId : undefined),
|
|
179
209
|
accessibilityAutoComplete,
|
|
180
210
|
});
|
|
181
211
|
}, [
|
|
@@ -186,7 +216,12 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
186
216
|
accessibilityHidden,
|
|
187
217
|
accessibilityRole,
|
|
188
218
|
accessibilityLabelledBy,
|
|
219
|
+
labelId,
|
|
189
220
|
accessibilityDescribedBy,
|
|
221
|
+
error,
|
|
222
|
+
errorId,
|
|
223
|
+
helperText,
|
|
224
|
+
helperId,
|
|
190
225
|
accessibilityControls,
|
|
191
226
|
accessibilityExpanded,
|
|
192
227
|
accessibilityPressed,
|
|
@@ -194,7 +229,7 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
194
229
|
accessibilityHasPopup,
|
|
195
230
|
accessibilityRequired,
|
|
196
231
|
accessibilityInvalid,
|
|
197
|
-
|
|
232
|
+
computedHasError,
|
|
198
233
|
accessibilityErrorMessage,
|
|
199
234
|
accessibilityAutoComplete,
|
|
200
235
|
]);
|
|
@@ -257,57 +292,134 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
|
|
|
257
292
|
|
|
258
293
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
259
294
|
|
|
260
|
-
|
|
295
|
+
const handleContainerPress = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
261
296
|
e.preventDefault();
|
|
262
297
|
e.stopPropagation();
|
|
263
298
|
containerRef.current?.focus();
|
|
264
|
-
}
|
|
299
|
+
};
|
|
265
300
|
|
|
266
301
|
const mergedContainerRef = useMergeRefs(containerRef, containerStyleRef);
|
|
267
302
|
|
|
303
|
+
const showFooter = Boolean(error) || Boolean(helperText);
|
|
304
|
+
|
|
305
|
+
// If no wrapper needed, return flat input container
|
|
306
|
+
if (!needsWrapper) {
|
|
307
|
+
return (
|
|
308
|
+
<div onClick={handleContainerPress} ref={mergedContainerRef} {...containerProps} id={id} data-testid={testID}>
|
|
309
|
+
{/* Left Icon */}
|
|
310
|
+
{leftIcon && (
|
|
311
|
+
<span {...leftIconContainerProps}>
|
|
312
|
+
{renderLeftIcon()}
|
|
313
|
+
</span>
|
|
314
|
+
)}
|
|
315
|
+
|
|
316
|
+
{/* Input */}
|
|
317
|
+
<input
|
|
318
|
+
{...inputWebProps}
|
|
319
|
+
{...ariaProps}
|
|
320
|
+
id={inputId}
|
|
321
|
+
ref={mergedInputRef}
|
|
322
|
+
type={getInputType()}
|
|
323
|
+
value={value}
|
|
324
|
+
onClick={handlePress}
|
|
325
|
+
onChange={handleChange}
|
|
326
|
+
onFocus={handleFocus}
|
|
327
|
+
onBlur={handleBlur}
|
|
328
|
+
onKeyDown={handleKeyDown}
|
|
329
|
+
placeholder={placeholder}
|
|
330
|
+
disabled={disabled}
|
|
331
|
+
autoCapitalize={autoCapitalize}
|
|
332
|
+
/>
|
|
333
|
+
|
|
334
|
+
{/* Right Icon or Password Toggle */}
|
|
335
|
+
{shouldShowPasswordToggle ? (
|
|
336
|
+
<button
|
|
337
|
+
{...passwordToggleProps}
|
|
338
|
+
onClick={togglePasswordVisibility}
|
|
339
|
+
disabled={disabled}
|
|
340
|
+
aria-label={isPasswordVisible ? 'Hide password' : 'Show password'}
|
|
341
|
+
type="button"
|
|
342
|
+
tabIndex={-1}
|
|
343
|
+
>
|
|
344
|
+
{renderPasswordToggleIcon()}
|
|
345
|
+
</button>
|
|
346
|
+
) : rightIcon ? (
|
|
347
|
+
<span {...rightIconContainerProps}>
|
|
348
|
+
{renderRightIcon()}
|
|
349
|
+
</span>
|
|
350
|
+
) : null}
|
|
351
|
+
</div>
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// With wrapper for label/error/helperText
|
|
268
356
|
return (
|
|
269
|
-
<div
|
|
270
|
-
{
|
|
271
|
-
|
|
272
|
-
<span {...leftIconContainerProps}>
|
|
273
|
-
{renderLeftIcon()}
|
|
274
|
-
</span>
|
|
357
|
+
<div {...wrapperProps} id={id} data-testid={testID}>
|
|
358
|
+
{label && (
|
|
359
|
+
<label {...labelProps} id={labelId} htmlFor={inputId}>{label}</label>
|
|
275
360
|
)}
|
|
276
361
|
|
|
277
|
-
{
|
|
278
|
-
|
|
279
|
-
{
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
{
|
|
298
|
-
|
|
362
|
+
<div onClick={handleContainerPress} ref={mergedContainerRef} {...containerProps}>
|
|
363
|
+
{/* Left Icon */}
|
|
364
|
+
{leftIcon && (
|
|
365
|
+
<span {...leftIconContainerProps}>
|
|
366
|
+
{renderLeftIcon()}
|
|
367
|
+
</span>
|
|
368
|
+
)}
|
|
369
|
+
|
|
370
|
+
{/* Input */}
|
|
371
|
+
<input
|
|
372
|
+
{...inputWebProps}
|
|
373
|
+
{...ariaProps}
|
|
374
|
+
id={inputId}
|
|
375
|
+
ref={mergedInputRef}
|
|
376
|
+
type={getInputType()}
|
|
377
|
+
value={value}
|
|
378
|
+
onClick={handlePress}
|
|
379
|
+
onChange={handleChange}
|
|
380
|
+
onFocus={handleFocus}
|
|
381
|
+
onBlur={handleBlur}
|
|
382
|
+
onKeyDown={handleKeyDown}
|
|
383
|
+
placeholder={placeholder}
|
|
299
384
|
disabled={disabled}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
385
|
+
autoCapitalize={autoCapitalize}
|
|
386
|
+
/>
|
|
387
|
+
|
|
388
|
+
{/* Right Icon or Password Toggle */}
|
|
389
|
+
{shouldShowPasswordToggle ? (
|
|
390
|
+
<button
|
|
391
|
+
{...passwordToggleProps}
|
|
392
|
+
onClick={togglePasswordVisibility}
|
|
393
|
+
disabled={disabled}
|
|
394
|
+
aria-label={isPasswordVisible ? 'Hide password' : 'Show password'}
|
|
395
|
+
type="button"
|
|
396
|
+
tabIndex={-1}
|
|
397
|
+
>
|
|
398
|
+
{renderPasswordToggleIcon()}
|
|
399
|
+
</button>
|
|
400
|
+
) : rightIcon ? (
|
|
401
|
+
<span {...rightIconContainerProps}>
|
|
402
|
+
{renderRightIcon()}
|
|
403
|
+
</span>
|
|
404
|
+
) : null}
|
|
405
|
+
</div>
|
|
406
|
+
|
|
407
|
+
{showFooter && (
|
|
408
|
+
<div {...footerProps}>
|
|
409
|
+
<div style={{ flex: 1 }}>
|
|
410
|
+
{error && (
|
|
411
|
+
<span {...helperTextProps} id={errorId} role="alert">
|
|
412
|
+
{error}
|
|
413
|
+
</span>
|
|
414
|
+
)}
|
|
415
|
+
{!error && helperText && (
|
|
416
|
+
<span {...helperTextProps} id={helperId}>
|
|
417
|
+
{helperText}
|
|
418
|
+
</span>
|
|
419
|
+
)}
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
)}
|
|
311
423
|
</div>
|
|
312
424
|
);
|
|
313
425
|
});
|
package/src/TextInput/types.ts
CHANGED
|
@@ -167,10 +167,25 @@ export interface TextInputProps extends FormInputStyleProps, FormAccessibilityPr
|
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
169
|
* Whether the input has an error state
|
|
170
|
-
* @deprecated Use intent="danger" instead
|
|
170
|
+
* @deprecated Use error prop or intent="danger" instead
|
|
171
171
|
*/
|
|
172
172
|
hasError?: boolean;
|
|
173
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Error message to display below the input. When set, the input shows error styling.
|
|
176
|
+
*/
|
|
177
|
+
error?: string;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Helper text to display below the input. Hidden when error is set.
|
|
181
|
+
*/
|
|
182
|
+
helperText?: string;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Label text to display above the input
|
|
186
|
+
*/
|
|
187
|
+
label?: string;
|
|
188
|
+
|
|
174
189
|
/**
|
|
175
190
|
* Called when the user submits the input (presses Enter on web, or the return key on mobile).
|
|
176
191
|
* Use this for form submission or moving to the next field.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { useSafeAreaInsets } from '
|
|
2
|
+
import { useSafeAreaInsets } from '@idealyst/theme';
|
|
3
3
|
import { calculateSmartPosition, type Placement } from '../utils/positionUtils.native';
|
|
4
4
|
|
|
5
5
|
export interface UseSmartPositionOptions {
|
package/src/index.native.ts
CHANGED
|
@@ -119,6 +119,9 @@ export * from './Platform/types';
|
|
|
119
119
|
export { Keyboard } from './Keyboard';
|
|
120
120
|
export * from './Keyboard/types';
|
|
121
121
|
|
|
122
|
+
export { default as Form, useForm } from './Form';
|
|
123
|
+
export * from './Form/types';
|
|
124
|
+
|
|
122
125
|
export type { ButtonProps } from './Button/types';
|
|
123
126
|
export type { IconButtonProps } from './IconButton/types';
|
|
124
127
|
export type { TextProps } from './Text/types';
|
|
@@ -165,6 +168,22 @@ export type {
|
|
|
165
168
|
KeyboardSubscription,
|
|
166
169
|
KeyboardStatic,
|
|
167
170
|
} from './Keyboard/types';
|
|
171
|
+
export type {
|
|
172
|
+
FormProps,
|
|
173
|
+
UseFormOptions,
|
|
174
|
+
UseFormReturn,
|
|
175
|
+
FormValues,
|
|
176
|
+
FormErrors,
|
|
177
|
+
FormTextInputProps,
|
|
178
|
+
FormTextAreaProps,
|
|
179
|
+
FormSelectProps,
|
|
180
|
+
FormCheckboxProps,
|
|
181
|
+
FormRadioGroupProps,
|
|
182
|
+
FormSwitchProps,
|
|
183
|
+
FormSliderProps,
|
|
184
|
+
FormFieldProps,
|
|
185
|
+
FieldRenderProps,
|
|
186
|
+
} from './Form/types';
|
|
168
187
|
|
|
169
188
|
// Event utilities
|
|
170
189
|
export * from './utils/events';
|
package/src/index.ts
CHANGED
|
@@ -127,6 +127,9 @@ export * from './Platform/types';
|
|
|
127
127
|
export { Keyboard } from './Keyboard';
|
|
128
128
|
export * from './Keyboard/types';
|
|
129
129
|
|
|
130
|
+
export { default as Form, useForm } from './Form';
|
|
131
|
+
export * from './Form/types';
|
|
132
|
+
|
|
130
133
|
export type { ButtonProps } from './Button/types';
|
|
131
134
|
export type { IconButtonProps } from './IconButton/types';
|
|
132
135
|
export type { TextProps } from './Text/types';
|
|
@@ -174,6 +177,22 @@ export type {
|
|
|
174
177
|
KeyboardSubscription,
|
|
175
178
|
KeyboardStatic,
|
|
176
179
|
} from './Keyboard/types';
|
|
180
|
+
export type {
|
|
181
|
+
FormProps,
|
|
182
|
+
UseFormOptions,
|
|
183
|
+
UseFormReturn,
|
|
184
|
+
FormValues,
|
|
185
|
+
FormErrors,
|
|
186
|
+
FormTextInputProps,
|
|
187
|
+
FormTextAreaProps,
|
|
188
|
+
FormSelectProps,
|
|
189
|
+
FormCheckboxProps,
|
|
190
|
+
FormRadioGroupProps,
|
|
191
|
+
FormSwitchProps,
|
|
192
|
+
FormSliderProps,
|
|
193
|
+
FormFieldProps,
|
|
194
|
+
FieldRenderProps,
|
|
195
|
+
} from './Form/types';
|
|
177
196
|
|
|
178
197
|
export { useMergeRefs };
|
|
179
198
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
import { View, Dimensions, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { useSafeAreaInsets } from '
|
|
3
|
+
import { useSafeAreaInsets } from '@idealyst/theme';
|
|
4
4
|
|
|
5
5
|
interface BoundedModalContentProps {
|
|
6
6
|
children: ReactNode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View, Text, Dimensions, StyleSheet } from 'react-native';
|
|
3
|
-
import { useSafeAreaInsets } from '
|
|
3
|
+
import { useSafeAreaInsets } from '@idealyst/theme';
|
|
4
4
|
|
|
5
5
|
interface SafeAreaDebugOverlayProps {
|
|
6
6
|
visible?: boolean;
|