@medway-ui/native 1.6.1 → 1.7.1
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/README.md +27 -2
- package/lib/commonjs/components/Alert.js +3 -1
- package/lib/commonjs/components/Alert.js.map +1 -1
- package/lib/commonjs/components/AlertDialog.js +5 -2
- package/lib/commonjs/components/AlertDialog.js.map +1 -1
- package/lib/commonjs/components/Badge.js +37 -2
- package/lib/commonjs/components/Badge.js.map +1 -1
- package/lib/commonjs/components/Button.js +32 -1
- package/lib/commonjs/components/Button.js.map +1 -1
- package/lib/commonjs/components/Carousel.js +12 -2
- package/lib/commonjs/components/Carousel.js.map +1 -1
- package/lib/commonjs/components/Checkbox.js +2 -0
- package/lib/commonjs/components/Checkbox.js.map +1 -1
- package/lib/commonjs/components/Chip.js +208 -0
- package/lib/commonjs/components/Chip.js.map +1 -0
- package/lib/commonjs/components/Choice.js +116 -0
- package/lib/commonjs/components/Choice.js.map +1 -0
- package/lib/commonjs/components/Dialog.js +27 -16
- package/lib/commonjs/components/Dialog.js.map +1 -1
- package/lib/commonjs/components/DropdownMenu.js +73 -57
- package/lib/commonjs/components/DropdownMenu.js.map +1 -1
- package/lib/commonjs/components/EmptyState.js +9 -2
- package/lib/commonjs/components/EmptyState.js.map +1 -1
- package/lib/commonjs/components/Feed.js +7 -3
- package/lib/commonjs/components/Feed.js.map +1 -1
- package/lib/commonjs/components/Feedback.js +77 -0
- package/lib/commonjs/components/Feedback.js.map +1 -0
- package/lib/commonjs/components/Filter.js +93 -0
- package/lib/commonjs/components/Filter.js.map +1 -0
- package/lib/commonjs/components/IndexLevel.js +4 -3
- package/lib/commonjs/components/IndexLevel.js.map +1 -1
- package/lib/commonjs/components/Input.js +149 -45
- package/lib/commonjs/components/Input.js.map +1 -1
- package/lib/commonjs/components/InvitePopover.js +4 -1
- package/lib/commonjs/components/InvitePopover.js.map +1 -1
- package/lib/commonjs/components/MemberRow.js +3 -4
- package/lib/commonjs/components/MemberRow.js.map +1 -1
- package/lib/commonjs/components/PostForm.js +18 -8
- package/lib/commonjs/components/PostForm.js.map +1 -1
- package/lib/commonjs/components/PrizeCollection.js +1 -1
- package/lib/commonjs/components/RadioGroup.js +7 -0
- package/lib/commonjs/components/RadioGroup.js.map +1 -1
- package/lib/commonjs/components/Select.js +1 -1
- package/lib/commonjs/components/Sheet.js +4 -1
- package/lib/commonjs/components/Sheet.js.map +1 -1
- package/lib/commonjs/components/Skeleton.js +55 -4
- package/lib/commonjs/components/Skeleton.js.map +1 -1
- package/lib/commonjs/components/Switch.js +2 -0
- package/lib/commonjs/components/Switch.js.map +1 -1
- package/lib/commonjs/components/Tabs.js +2 -0
- package/lib/commonjs/components/Tabs.js.map +1 -1
- package/lib/commonjs/components/Toast.js +355 -79
- package/lib/commonjs/components/Toast.js.map +1 -1
- package/lib/commonjs/editor/NoteEditor.js +41 -14
- package/lib/commonjs/editor/NoteEditor.js.map +1 -1
- package/lib/commonjs/editor/editorHtml.generated.js +1 -1
- package/lib/commonjs/editor/editorHtml.generated.js.map +1 -1
- package/lib/commonjs/hooks/useThemeColor.js +693 -65
- package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
- package/lib/commonjs/hooks/useTrackedText.js +21 -0
- package/lib/commonjs/hooks/useTrackedText.js.map +1 -0
- package/lib/commonjs/index.js +46 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/lib/optional-deps.js +20 -0
- package/lib/commonjs/lib/optional-deps.js.map +1 -0
- package/lib/commonjs/lib/touch-target.js +19 -0
- package/lib/commonjs/lib/touch-target.js.map +1 -0
- package/lib/module/components/Alert.js +3 -1
- package/lib/module/components/Alert.js.map +1 -1
- package/lib/module/components/AlertDialog.js +5 -2
- package/lib/module/components/AlertDialog.js.map +1 -1
- package/lib/module/components/Badge.js +36 -2
- package/lib/module/components/Badge.js.map +1 -1
- package/lib/module/components/Button.js +32 -1
- package/lib/module/components/Button.js.map +1 -1
- package/lib/module/components/Carousel.js +12 -2
- package/lib/module/components/Carousel.js.map +1 -1
- package/lib/module/components/Checkbox.js +2 -0
- package/lib/module/components/Checkbox.js.map +1 -1
- package/lib/module/components/Chip.js +204 -0
- package/lib/module/components/Chip.js.map +1 -0
- package/lib/module/components/Choice.js +112 -0
- package/lib/module/components/Choice.js.map +1 -0
- package/lib/module/components/Dialog.js +28 -17
- package/lib/module/components/Dialog.js.map +1 -1
- package/lib/module/components/DropdownMenu.js +74 -58
- package/lib/module/components/DropdownMenu.js.map +1 -1
- package/lib/module/components/EmptyState.js +9 -2
- package/lib/module/components/EmptyState.js.map +1 -1
- package/lib/module/components/Feed.js +7 -3
- package/lib/module/components/Feed.js.map +1 -1
- package/lib/module/components/Feedback.js +74 -0
- package/lib/module/components/Feedback.js.map +1 -0
- package/lib/module/components/Filter.js +89 -0
- package/lib/module/components/Filter.js.map +1 -0
- package/lib/module/components/IndexLevel.js +4 -3
- package/lib/module/components/IndexLevel.js.map +1 -1
- package/lib/module/components/Input.js +149 -45
- package/lib/module/components/Input.js.map +1 -1
- package/lib/module/components/InvitePopover.js +4 -1
- package/lib/module/components/InvitePopover.js.map +1 -1
- package/lib/module/components/MemberRow.js +3 -4
- package/lib/module/components/MemberRow.js.map +1 -1
- package/lib/module/components/PostForm.js +18 -8
- package/lib/module/components/PostForm.js.map +1 -1
- package/lib/module/components/PrizeCollection.js +1 -1
- package/lib/module/components/RadioGroup.js +7 -0
- package/lib/module/components/RadioGroup.js.map +1 -1
- package/lib/module/components/Select.js +1 -1
- package/lib/module/components/Sheet.js +4 -1
- package/lib/module/components/Sheet.js.map +1 -1
- package/lib/module/components/Skeleton.js +56 -5
- package/lib/module/components/Skeleton.js.map +1 -1
- package/lib/module/components/Switch.js +2 -0
- package/lib/module/components/Switch.js.map +1 -1
- package/lib/module/components/Tabs.js +2 -0
- package/lib/module/components/Tabs.js.map +1 -1
- package/lib/module/components/Toast.js +360 -84
- package/lib/module/components/Toast.js.map +1 -1
- package/lib/module/editor/NoteEditor.js +41 -14
- package/lib/module/editor/NoteEditor.js.map +1 -1
- package/lib/module/editor/editorHtml.generated.js +1 -1
- package/lib/module/editor/editorHtml.generated.js.map +1 -1
- package/lib/module/hooks/useThemeColor.js +693 -65
- package/lib/module/hooks/useThemeColor.js.map +1 -1
- package/lib/module/hooks/useTrackedText.js +18 -0
- package/lib/module/hooks/useTrackedText.js.map +1 -0
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/optional-deps.js +16 -0
- package/lib/module/lib/optional-deps.js.map +1 -0
- package/lib/module/lib/touch-target.js +15 -0
- package/lib/module/lib/touch-target.js.map +1 -0
- package/lib/typescript/components/Alert.d.ts.map +1 -1
- package/lib/typescript/components/AlertDialog.d.ts.map +1 -1
- package/lib/typescript/components/Badge.d.ts +1 -1
- package/lib/typescript/components/Badge.d.ts.map +1 -1
- package/lib/typescript/components/Button.d.ts.map +1 -1
- package/lib/typescript/components/Carousel.d.ts +1 -1
- package/lib/typescript/components/Carousel.d.ts.map +1 -1
- package/lib/typescript/components/Checkbox.d.ts.map +1 -1
- package/lib/typescript/components/Chip.d.ts +30 -0
- package/lib/typescript/components/Chip.d.ts.map +1 -0
- package/lib/typescript/components/Choice.d.ts +17 -0
- package/lib/typescript/components/Choice.d.ts.map +1 -0
- package/lib/typescript/components/Dialog.d.ts.map +1 -1
- package/lib/typescript/components/DropdownMenu.d.ts +0 -7
- package/lib/typescript/components/DropdownMenu.d.ts.map +1 -1
- package/lib/typescript/components/EmptyState.d.ts +3 -2
- package/lib/typescript/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/components/Feed.d.ts.map +1 -1
- package/lib/typescript/components/Feedback.d.ts +17 -0
- package/lib/typescript/components/Feedback.d.ts.map +1 -0
- package/lib/typescript/components/Filter.d.ts +17 -0
- package/lib/typescript/components/Filter.d.ts.map +1 -0
- package/lib/typescript/components/IndexLevel.d.ts.map +1 -1
- package/lib/typescript/components/Input.d.ts +3 -3
- package/lib/typescript/components/Input.d.ts.map +1 -1
- package/lib/typescript/components/InvitePopover.d.ts.map +1 -1
- package/lib/typescript/components/MemberRow.d.ts.map +1 -1
- package/lib/typescript/components/PostForm.d.ts.map +1 -1
- package/lib/typescript/components/RadioGroup.d.ts.map +1 -1
- package/lib/typescript/components/Sheet.d.ts.map +1 -1
- package/lib/typescript/components/Skeleton.d.ts +1 -1
- package/lib/typescript/components/Skeleton.d.ts.map +1 -1
- package/lib/typescript/components/Switch.d.ts.map +1 -1
- package/lib/typescript/components/Tabs.d.ts.map +1 -1
- package/lib/typescript/components/Tag.d.ts +2 -2
- package/lib/typescript/components/ThemedIcon.d.ts +1 -1
- package/lib/typescript/components/ThemedIcon.d.ts.map +1 -1
- package/lib/typescript/components/Toast.d.ts +24 -13
- package/lib/typescript/components/Toast.d.ts.map +1 -1
- package/lib/typescript/editor/NoteEditor.d.ts.map +1 -1
- package/lib/typescript/editor/editorHtml.generated.d.ts.map +1 -1
- package/lib/typescript/hooks/useThemeColor.d.ts +0 -10
- package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -1
- package/lib/typescript/hooks/useTrackedText.d.ts +6 -0
- package/lib/typescript/hooks/useTrackedText.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +9 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/lib/optional-deps.d.ts +23 -0
- package/lib/typescript/lib/optional-deps.d.ts.map +1 -0
- package/lib/typescript/lib/touch-target.d.ts +5 -0
- package/lib/typescript/lib/touch-target.d.ts.map +1 -0
- package/package.json +6 -1
- package/setup/createMedwayUiNavigator.tsx +4 -7
- package/setup/metro.js +12 -3
- package/setup/tokens.native.css +268 -258
- package/src/components/Alert.tsx +3 -1
- package/src/components/AlertDialog.tsx +8 -3
- package/src/components/Badge.tsx +51 -3
- package/src/components/Button.tsx +39 -1
- package/src/components/Carousel.tsx +17 -3
- package/src/components/Checkbox.tsx +2 -0
- package/src/components/Chip.tsx +227 -0
- package/src/components/Choice.tsx +139 -0
- package/src/components/Dialog.tsx +39 -23
- package/src/components/DropdownMenu.tsx +99 -87
- package/src/components/EmptyState.tsx +18 -3
- package/src/components/Feed.tsx +4 -3
- package/src/components/Feedback.tsx +111 -0
- package/src/components/Filter.tsx +106 -0
- package/src/components/IndexLevel.tsx +8 -10
- package/src/components/Input.tsx +142 -54
- package/src/components/InvitePopover.tsx +5 -1
- package/src/components/MemberRow.tsx +3 -5
- package/src/components/PostForm.tsx +16 -9
- package/src/components/PrizeCollection.tsx +1 -1
- package/src/components/RadioGroup.tsx +8 -0
- package/src/components/Select.tsx +1 -1
- package/src/components/Sheet.tsx +4 -1
- package/src/components/Skeleton.tsx +47 -6
- package/src/components/Switch.tsx +2 -0
- package/src/components/Tabs.tsx +2 -0
- package/src/components/ThemedIcon.tsx +1 -1
- package/src/components/Toast.tsx +489 -87
- package/src/editor/NoteEditor.tsx +50 -11
- package/src/editor/editorHtml.generated.ts +1 -1
- package/src/hooks/useThemeColor.ts +757 -64
- package/src/hooks/useTrackedText.ts +20 -0
- package/src/index.ts +36 -1
- package/src/lib/optional-deps.ts +27 -0
- package/src/lib/touch-target.ts +12 -0
- package/setup/index.tsx +0 -42
package/src/components/Input.tsx
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
} from "@medway-ui/icons/native";
|
|
33
33
|
import { Text, type TextComponentProps } from "@/components/Text";
|
|
34
34
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
35
|
+
import { useTrackedText } from "@/hooks/useTrackedText";
|
|
35
36
|
import { fontFamilyMedium } from "@/lib/typography";
|
|
36
37
|
import { cn } from "@/lib/utils";
|
|
37
38
|
|
|
@@ -72,6 +73,9 @@ export interface InputNumericProps
|
|
|
72
73
|
label?: string;
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
type FocusHandler = TextInputProps["onFocus"];
|
|
77
|
+
type BlurHandler = TextInputProps["onBlur"];
|
|
78
|
+
|
|
75
79
|
export interface InputLabelProps {
|
|
76
80
|
children?: ReactNode;
|
|
77
81
|
floated?: boolean;
|
|
@@ -213,11 +217,38 @@ function applyInputIconSize(
|
|
|
213
217
|
});
|
|
214
218
|
}
|
|
215
219
|
|
|
216
|
-
function
|
|
217
|
-
const [visible, setVisible] = useState(false);
|
|
220
|
+
function useInputFocus(onFocus?: FocusHandler, onBlur?: BlurHandler) {
|
|
218
221
|
const [focused, setFocused] = useState(false);
|
|
219
|
-
|
|
220
|
-
const
|
|
222
|
+
|
|
223
|
+
const handleFocus: NonNullable<FocusHandler> = (event) => {
|
|
224
|
+
setFocused(true);
|
|
225
|
+
onFocus?.(event);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const handleBlur: NonNullable<BlurHandler> = (event) => {
|
|
229
|
+
setFocused(false);
|
|
230
|
+
onBlur?.(event);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return { focused, handleFocus, handleBlur };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function InputPassword({
|
|
237
|
+
className,
|
|
238
|
+
size = "lg",
|
|
239
|
+
invalid = false,
|
|
240
|
+
label,
|
|
241
|
+
value,
|
|
242
|
+
defaultValue,
|
|
243
|
+
onFocus,
|
|
244
|
+
onBlur,
|
|
245
|
+
onChangeText,
|
|
246
|
+
...props
|
|
247
|
+
}: InputPasswordProps) {
|
|
248
|
+
const [visible, setVisible] = useState(false);
|
|
249
|
+
const { focused, handleFocus, handleBlur } = useInputFocus(onFocus, onBlur);
|
|
250
|
+
const { text, handleChangeText } = useTrackedText(value, defaultValue, onChangeText);
|
|
251
|
+
const isFloated = focused || text !== "";
|
|
221
252
|
const iconColor = useThemeColor("gray-foreground");
|
|
222
253
|
const iconSize = size === "md" ? INPUT_ICON_SIZE_MD : INPUT_ICON_SIZE_LG;
|
|
223
254
|
|
|
@@ -242,10 +273,13 @@ function InputPassword({ className, size = "lg", invalid = false, label, ...prop
|
|
|
242
273
|
"pl-12 pr-12 font-medium",
|
|
243
274
|
className
|
|
244
275
|
)}
|
|
245
|
-
|
|
246
|
-
|
|
276
|
+
value={value}
|
|
277
|
+
defaultValue={defaultValue}
|
|
247
278
|
accessibilityLabel={label}
|
|
248
279
|
{...props}
|
|
280
|
+
onFocus={handleFocus}
|
|
281
|
+
onBlur={handleBlur}
|
|
282
|
+
onChangeText={handleChangeText}
|
|
249
283
|
style={[{ fontFamily: fontFamilyMedium }, props.style]}
|
|
250
284
|
/>
|
|
251
285
|
</View>
|
|
@@ -253,7 +287,9 @@ function InputPassword({ className, size = "lg", invalid = false, label, ...prop
|
|
|
253
287
|
<Pressable
|
|
254
288
|
onPress={() => setVisible((v) => !v)}
|
|
255
289
|
disabled={props.editable === false}
|
|
256
|
-
|
|
290
|
+
accessibilityRole="button"
|
|
291
|
+
accessibilityLabel={visible ? "Ocultar senha" : "Mostrar senha"}
|
|
292
|
+
hitSlop={10}
|
|
257
293
|
>
|
|
258
294
|
{iconColor && (visible ? (
|
|
259
295
|
<Hide width={iconSize} height={iconSize} strokeWidth={INPUT_ICON_STROKE_WIDTH} color={iconColor} />
|
|
@@ -278,26 +314,28 @@ function InputNumeric({
|
|
|
278
314
|
editable = true,
|
|
279
315
|
allowNegative = false,
|
|
280
316
|
label,
|
|
317
|
+
onFocus,
|
|
318
|
+
onBlur,
|
|
281
319
|
...props
|
|
282
320
|
}: InputNumericProps) {
|
|
283
321
|
const [internalValue, setInternalValue] = useState(String(defaultValue ?? ""));
|
|
284
322
|
const isControlled = value !== undefined;
|
|
285
323
|
const displayValue = isControlled ? String(value ?? "") : internalValue;
|
|
286
|
-
const
|
|
324
|
+
const { focused, handleFocus, handleBlur } = useInputFocus(onFocus, onBlur);
|
|
287
325
|
const isFloated = focused || displayValue !== "";
|
|
288
326
|
const iconColor = useThemeColor("gray-foreground");
|
|
289
327
|
|
|
290
328
|
const numericValue = parseFloat(displayValue.replace(",", ".")) || 0;
|
|
329
|
+
const lowerBound = Math.max(min ?? -Infinity, allowNegative ? -Infinity : 0);
|
|
291
330
|
|
|
292
331
|
const handleStep = useCallback(
|
|
293
332
|
(delta: number) => {
|
|
294
|
-
|
|
295
|
-
if (min !== undefined && next < min) next = min;
|
|
333
|
+
const next = Math.max(numericValue + delta, lowerBound);
|
|
296
334
|
const nextStr = String(next);
|
|
297
335
|
if (!isControlled) setInternalValue(nextStr);
|
|
298
336
|
onChangeText?.(nextStr);
|
|
299
337
|
},
|
|
300
|
-
[numericValue,
|
|
338
|
+
[numericValue, lowerBound, isControlled, onChangeText]
|
|
301
339
|
);
|
|
302
340
|
|
|
303
341
|
const chevronSize = size === "md" ? CHEVRON_SIZE_MD : CHEVRON_SIZE_LG;
|
|
@@ -322,8 +360,6 @@ function InputNumeric({
|
|
|
322
360
|
onChangeText?.(cleaned);
|
|
323
361
|
}}
|
|
324
362
|
editable={editable}
|
|
325
|
-
onFocus={() => setFocused(true)}
|
|
326
|
-
onBlur={() => setFocused(false)}
|
|
327
363
|
className={cn(
|
|
328
364
|
inputVariants({ size, invalid, focused, disabled: !editable }),
|
|
329
365
|
iconLeft ? "pl-12" : "",
|
|
@@ -332,6 +368,8 @@ function InputNumeric({
|
|
|
332
368
|
)}
|
|
333
369
|
accessibilityLabel={label}
|
|
334
370
|
{...props}
|
|
371
|
+
onFocus={handleFocus}
|
|
372
|
+
onBlur={handleBlur}
|
|
335
373
|
style={[{ fontFamily: fontFamilyMedium }, props.style]}
|
|
336
374
|
/>
|
|
337
375
|
</View>
|
|
@@ -341,7 +379,9 @@ function InputNumeric({
|
|
|
341
379
|
disabled={!editable}
|
|
342
380
|
onPress={() => handleStep(1)}
|
|
343
381
|
className="items-center justify-center p-1"
|
|
344
|
-
|
|
382
|
+
accessibilityRole="button"
|
|
383
|
+
accessibilityLabel="Aumentar valor"
|
|
384
|
+
hitSlop={{ top: 12, bottom: 4, left: 16, right: 16 }}
|
|
345
385
|
>
|
|
346
386
|
{iconColor && (
|
|
347
387
|
<ChevronDown
|
|
@@ -357,7 +397,9 @@ function InputNumeric({
|
|
|
357
397
|
disabled={!editable}
|
|
358
398
|
onPress={() => handleStep(-1)}
|
|
359
399
|
className="items-center justify-center p-1"
|
|
360
|
-
|
|
400
|
+
accessibilityRole="button"
|
|
401
|
+
accessibilityLabel="Diminuir valor"
|
|
402
|
+
hitSlop={{ top: 4, bottom: 12, left: 16, right: 16 }}
|
|
361
403
|
>
|
|
362
404
|
{iconColor && (
|
|
363
405
|
<ChevronDown width={chevronSize} height={chevronSize} strokeWidth={3} color={iconColor} />
|
|
@@ -369,7 +411,7 @@ function InputNumeric({
|
|
|
369
411
|
);
|
|
370
412
|
}
|
|
371
413
|
|
|
372
|
-
function
|
|
414
|
+
function InputTextual({
|
|
373
415
|
className,
|
|
374
416
|
type = "text",
|
|
375
417
|
size = "lg",
|
|
@@ -380,45 +422,17 @@ function Input({
|
|
|
380
422
|
value,
|
|
381
423
|
defaultValue,
|
|
382
424
|
editable = true,
|
|
425
|
+
onFocus,
|
|
426
|
+
onBlur,
|
|
427
|
+
onChangeText,
|
|
383
428
|
...props
|
|
384
429
|
}: InputProps) {
|
|
385
|
-
const
|
|
386
|
-
const
|
|
387
|
-
const isFloated = focused ||
|
|
430
|
+
const { focused, handleFocus, handleBlur } = useInputFocus(onFocus, onBlur);
|
|
431
|
+
const { text, handleChangeText } = useTrackedText(value, defaultValue, onChangeText);
|
|
432
|
+
const isFloated = focused || text !== "";
|
|
388
433
|
const iconColor = useThemeColor("gray-foreground");
|
|
389
434
|
const errorIconColor = useThemeColor("feedback-error-foreground");
|
|
390
435
|
|
|
391
|
-
if (type === "numeric") {
|
|
392
|
-
return (
|
|
393
|
-
<InputNumeric
|
|
394
|
-
className={className}
|
|
395
|
-
size={size}
|
|
396
|
-
invalid={invalid}
|
|
397
|
-
iconLeft={iconLeft}
|
|
398
|
-
value={value as string}
|
|
399
|
-
defaultValue={defaultValue as string}
|
|
400
|
-
editable={editable}
|
|
401
|
-
label={label}
|
|
402
|
-
{...props}
|
|
403
|
-
/>
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
if (type === "password") {
|
|
408
|
-
return (
|
|
409
|
-
<InputPassword
|
|
410
|
-
className={className}
|
|
411
|
-
size={size}
|
|
412
|
-
invalid={invalid}
|
|
413
|
-
value={value as string}
|
|
414
|
-
defaultValue={defaultValue as string}
|
|
415
|
-
editable={editable}
|
|
416
|
-
label={label}
|
|
417
|
-
{...props}
|
|
418
|
-
/>
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
436
|
const iconSize = size === "md" ? INPUT_ICON_SIZE_MD : INPUT_ICON_SIZE_LG;
|
|
423
437
|
const defaultIconLeft =
|
|
424
438
|
type === "email" && iconColor ? (
|
|
@@ -448,11 +462,9 @@ function Input({
|
|
|
448
462
|
{label && <InputLabel floated={isFloated} disabled={!editable}>{label}</InputLabel>}
|
|
449
463
|
<TextInput
|
|
450
464
|
keyboardType={type === "email" ? "email-address" : "default"}
|
|
451
|
-
value={value
|
|
452
|
-
defaultValue={defaultValue
|
|
465
|
+
value={value}
|
|
466
|
+
defaultValue={defaultValue}
|
|
453
467
|
editable={editable}
|
|
454
|
-
onFocus={() => setFocused(true)}
|
|
455
|
-
onBlur={() => setFocused(false)}
|
|
456
468
|
className={cn(
|
|
457
469
|
inputVariants({ size, invalid, focused, disabled: !editable }),
|
|
458
470
|
resolvedIconLeft ? "pl-12" : "",
|
|
@@ -462,6 +474,9 @@ function Input({
|
|
|
462
474
|
)}
|
|
463
475
|
accessibilityLabel={label}
|
|
464
476
|
{...props}
|
|
477
|
+
onFocus={handleFocus}
|
|
478
|
+
onBlur={handleBlur}
|
|
479
|
+
onChangeText={handleChangeText}
|
|
465
480
|
style={[{ fontFamily: fontFamilyMedium }, props.style]}
|
|
466
481
|
/>
|
|
467
482
|
</View>
|
|
@@ -474,6 +489,79 @@ function Input({
|
|
|
474
489
|
);
|
|
475
490
|
}
|
|
476
491
|
|
|
492
|
+
function Input({
|
|
493
|
+
className,
|
|
494
|
+
type = "text",
|
|
495
|
+
size = "lg",
|
|
496
|
+
invalid = false,
|
|
497
|
+
iconLeft,
|
|
498
|
+
iconRight,
|
|
499
|
+
label,
|
|
500
|
+
value,
|
|
501
|
+
defaultValue,
|
|
502
|
+
editable = true,
|
|
503
|
+
onFocus,
|
|
504
|
+
onBlur,
|
|
505
|
+
onChangeText,
|
|
506
|
+
...props
|
|
507
|
+
}: InputProps) {
|
|
508
|
+
if (type === "numeric") {
|
|
509
|
+
return (
|
|
510
|
+
<InputNumeric
|
|
511
|
+
className={className}
|
|
512
|
+
size={size}
|
|
513
|
+
invalid={invalid}
|
|
514
|
+
iconLeft={iconLeft}
|
|
515
|
+
value={value}
|
|
516
|
+
defaultValue={defaultValue}
|
|
517
|
+
editable={editable}
|
|
518
|
+
label={label}
|
|
519
|
+
onFocus={onFocus}
|
|
520
|
+
onBlur={onBlur}
|
|
521
|
+
onChangeText={onChangeText}
|
|
522
|
+
{...props}
|
|
523
|
+
/>
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (type === "password") {
|
|
528
|
+
return (
|
|
529
|
+
<InputPassword
|
|
530
|
+
className={className}
|
|
531
|
+
size={size}
|
|
532
|
+
invalid={invalid}
|
|
533
|
+
value={value}
|
|
534
|
+
defaultValue={defaultValue}
|
|
535
|
+
editable={editable}
|
|
536
|
+
label={label}
|
|
537
|
+
onFocus={onFocus}
|
|
538
|
+
onBlur={onBlur}
|
|
539
|
+
onChangeText={onChangeText}
|
|
540
|
+
{...props}
|
|
541
|
+
/>
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return (
|
|
546
|
+
<InputTextual
|
|
547
|
+
className={className}
|
|
548
|
+
type={type}
|
|
549
|
+
size={size}
|
|
550
|
+
invalid={invalid}
|
|
551
|
+
iconLeft={iconLeft}
|
|
552
|
+
iconRight={iconRight}
|
|
553
|
+
label={label}
|
|
554
|
+
value={value}
|
|
555
|
+
defaultValue={defaultValue}
|
|
556
|
+
editable={editable}
|
|
557
|
+
onFocus={onFocus}
|
|
558
|
+
onBlur={onBlur}
|
|
559
|
+
onChangeText={onChangeText}
|
|
560
|
+
{...props}
|
|
561
|
+
/>
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
|
|
477
565
|
export {
|
|
478
566
|
Input,
|
|
479
567
|
InputAdornment,
|
|
@@ -8,6 +8,7 @@ import { CloseMd } from "@medway-ui/icons/native";
|
|
|
8
8
|
import { Button } from "@/components/Button";
|
|
9
9
|
import { Input } from "@/components/Input";
|
|
10
10
|
import { Separator } from "@/components/Separator";
|
|
11
|
+
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
11
12
|
import { cn } from "@/lib/utils";
|
|
12
13
|
|
|
13
14
|
interface InvitePopoverProps extends PopoverPrimitive.RootProps {
|
|
@@ -87,17 +88,20 @@ function InvitePopoverContent({
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
function InvitePopoverClose({ className, ...props }: PopoverPrimitive.CloseProps) {
|
|
91
|
+
const closeIconColor = useThemeColor("primary-foreground-onfill");
|
|
92
|
+
|
|
90
93
|
return (
|
|
91
94
|
<PopoverPrimitive.Close
|
|
92
95
|
className={cn(
|
|
93
96
|
"mb-4 size-12 items-center justify-center self-end rounded-pill bg-primary-background-fill active:bg-primary-background-fill-emphasis",
|
|
94
97
|
className
|
|
95
98
|
)}
|
|
99
|
+
accessibilityRole="button"
|
|
96
100
|
accessibilityLabel="Fechar"
|
|
97
101
|
{...props}
|
|
98
102
|
>
|
|
99
103
|
<View className="size-6">
|
|
100
|
-
<CloseMd width={24} height={24} color=
|
|
104
|
+
<CloseMd width={24} height={24} color={closeIconColor} strokeWidth={2.2} />
|
|
101
105
|
</View>
|
|
102
106
|
</PopoverPrimitive.Close>
|
|
103
107
|
);
|
|
@@ -13,7 +13,7 @@ const rankIndicatorVariants = cva("size-[22px] rounded-full", {
|
|
|
13
13
|
rank: {
|
|
14
14
|
1: "bg-yellow-background-fill",
|
|
15
15
|
2: "bg-gray-background-fill",
|
|
16
|
-
3: "bg-
|
|
16
|
+
3: "bg-bronze-background-fill",
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
defaultVariants: {
|
|
@@ -95,16 +95,14 @@ function MemberRow({
|
|
|
95
95
|
}: MemberRowProps) {
|
|
96
96
|
const initials = avatarFallback ?? getInitials(name);
|
|
97
97
|
|
|
98
|
-
if (variant === "selectable") {
|
|
99
|
-
const selectionValue = (props as MemberRowSelectableProps).value;
|
|
100
|
-
|
|
98
|
+
if (variant === "selectable" && value !== undefined) {
|
|
101
99
|
return (
|
|
102
100
|
<View
|
|
103
101
|
className={cn(memberRowVariants({ variant, highlighted }), className)}
|
|
104
102
|
{...props}
|
|
105
103
|
>
|
|
106
104
|
<View className="min-w-0 flex-1 flex-row items-center gap-4">
|
|
107
|
-
<RadioGroupItem value={
|
|
105
|
+
<RadioGroupItem value={value} size="md" />
|
|
108
106
|
<View className="min-w-0 flex-1 flex-row items-center gap-2">
|
|
109
107
|
<Avatar size="sm" alt={avatarAlt ?? name}>
|
|
110
108
|
{avatarSrc ? <AvatarImage src={avatarSrc} /> : null}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactElement, type ReactNode } from "react";
|
|
1
|
+
import { useState, type ReactElement, type ReactNode } from "react";
|
|
2
2
|
import { Pressable, TextInput, View, type PressableProps, type TextInputProps, type ViewProps } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { Text } from "@/components/Text";
|
|
@@ -6,6 +6,7 @@ import { Text } from "@/components/Text";
|
|
|
6
6
|
import { Button } from "@/components/Button";
|
|
7
7
|
import { Checkbox } from "@/components/Checkbox";
|
|
8
8
|
import { Input, InputText, inputVariants } from "@/components/Input";
|
|
9
|
+
import { useTrackedText } from "@/hooks/useTrackedText";
|
|
9
10
|
import { cn } from "@/lib/utils";
|
|
10
11
|
|
|
11
12
|
interface PostFormProps extends ViewProps {
|
|
@@ -124,7 +125,7 @@ function PostFormDescription({
|
|
|
124
125
|
editable = true,
|
|
125
126
|
...props
|
|
126
127
|
}: PostFormDescriptionProps) {
|
|
127
|
-
const
|
|
128
|
+
const { text, handleChangeText } = useTrackedText(value, defaultValue, onChangeText);
|
|
128
129
|
|
|
129
130
|
return (
|
|
130
131
|
<View className={cn("gap-1", className)}>
|
|
@@ -134,7 +135,7 @@ function PostFormDescription({
|
|
|
134
135
|
maxLength={maxLength}
|
|
135
136
|
value={value}
|
|
136
137
|
defaultValue={defaultValue}
|
|
137
|
-
onChangeText={
|
|
138
|
+
onChangeText={handleChangeText}
|
|
138
139
|
placeholder={placeholder}
|
|
139
140
|
editable={editable}
|
|
140
141
|
className={cn(
|
|
@@ -151,7 +152,7 @@ function PostFormDescription({
|
|
|
151
152
|
style={[{ fontFamily: "MontserratMedium" }, props.style]}
|
|
152
153
|
/>
|
|
153
154
|
<InputText className="text-right text-xs font-medium text-gray-foreground">
|
|
154
|
-
{
|
|
155
|
+
{text.length} / {maxLength}
|
|
155
156
|
</InputText>
|
|
156
157
|
</View>
|
|
157
158
|
);
|
|
@@ -196,11 +197,18 @@ function PostFormCheckboxOption({
|
|
|
196
197
|
disabled,
|
|
197
198
|
...props
|
|
198
199
|
}: PostFormCheckboxOptionProps) {
|
|
199
|
-
const
|
|
200
|
+
const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);
|
|
201
|
+
const isControlled = checked !== undefined;
|
|
202
|
+
const isChecked = isControlled ? checked : internalChecked;
|
|
203
|
+
|
|
204
|
+
const handleCheckedChange = (nextChecked: boolean) => {
|
|
205
|
+
if (!isControlled) setInternalChecked(nextChecked);
|
|
206
|
+
onCheckedChange?.(nextChecked);
|
|
207
|
+
};
|
|
200
208
|
|
|
201
209
|
const toggle = () => {
|
|
202
210
|
if (disabled) return;
|
|
203
|
-
|
|
211
|
+
handleCheckedChange(!isChecked);
|
|
204
212
|
};
|
|
205
213
|
|
|
206
214
|
return (
|
|
@@ -210,9 +218,8 @@ function PostFormCheckboxOption({
|
|
|
210
218
|
>
|
|
211
219
|
<Checkbox
|
|
212
220
|
size="lg"
|
|
213
|
-
checked={
|
|
214
|
-
|
|
215
|
-
onCheckedChange={onCheckedChange}
|
|
221
|
+
checked={isChecked}
|
|
222
|
+
onCheckedChange={handleCheckedChange}
|
|
216
223
|
disabled={disabled}
|
|
217
224
|
/>
|
|
218
225
|
<Pressable
|
|
@@ -37,7 +37,7 @@ interface PrizeItemProps extends ViewProps {
|
|
|
37
37
|
const rankColors: Record<1 | 2 | 3, string> = {
|
|
38
38
|
1: "bg-yellow-background-fill",
|
|
39
39
|
2: "bg-gray-background-fill",
|
|
40
|
-
3: "bg-
|
|
40
|
+
3: "bg-bronze-background-fill",
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
function PrizeCollection({
|
|
@@ -3,6 +3,7 @@ import * as RadioGroupPrimitive from "@rn-primitives/radio-group";
|
|
|
3
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
4
|
import { type ReactNode } from "react";
|
|
5
5
|
import { cn } from "@/lib/utils";
|
|
6
|
+
import { getMinTouchHitSlop } from "@/lib/touch-target";
|
|
6
7
|
|
|
7
8
|
interface RadioGroupItemProps
|
|
8
9
|
extends RadioGroupPrimitive.ItemProps,
|
|
@@ -14,6 +15,12 @@ const INNER_DOT_SIZES: Record<"sm" | "md" | "lg", number> = {
|
|
|
14
15
|
lg: 14,
|
|
15
16
|
};
|
|
16
17
|
|
|
18
|
+
const RADIO_DIMENSIONS: Record<"sm" | "md" | "lg", number> = {
|
|
19
|
+
sm: 16,
|
|
20
|
+
md: 20,
|
|
21
|
+
lg: 24,
|
|
22
|
+
};
|
|
23
|
+
|
|
17
24
|
const radioGroupVariants = cva(
|
|
18
25
|
"items-center justify-center rounded-full border-2 shrink-0 bg-surface-card border-gray-stroke-muted",
|
|
19
26
|
{
|
|
@@ -46,6 +53,7 @@ function RadioGroupItem({ className, size = "md", variant, ...props }: RadioGrou
|
|
|
46
53
|
|
|
47
54
|
return (
|
|
48
55
|
<RadioGroupPrimitive.Item
|
|
56
|
+
hitSlop={getMinTouchHitSlop(RADIO_DIMENSIONS[resolvedSize])}
|
|
49
57
|
className={cn(radioGroupVariants({ size, variant }), className)}
|
|
50
58
|
{...props}
|
|
51
59
|
>
|
|
@@ -114,7 +114,7 @@ function SelectValue({ className, placeholder, ...props }: SelectPrimitive.Value
|
|
|
114
114
|
function SelectContent({ className, children, ...props }: SelectPrimitive.ContentProps) {
|
|
115
115
|
return (
|
|
116
116
|
<SelectPrimitive.Portal>
|
|
117
|
-
<SelectPrimitive.Overlay className="absolute inset-0 bg-black
|
|
117
|
+
<SelectPrimitive.Overlay className="absolute inset-0 bg-black-24">
|
|
118
118
|
<SelectPrimitive.Content
|
|
119
119
|
className={cn(
|
|
120
120
|
"z-50 min-w-48 overflow-hidden rounded-md border border-gray-stroke-muted bg-surface-elevated shadow-lg",
|
package/src/components/Sheet.tsx
CHANGED
|
@@ -68,7 +68,7 @@ function SheetContainer({
|
|
|
68
68
|
return (
|
|
69
69
|
<DialogPrimitive.Portal>
|
|
70
70
|
<DialogPrimitive.Overlay
|
|
71
|
-
className={cn("absolute inset-0 bg-black
|
|
71
|
+
className={cn("absolute inset-0 bg-black-48", overlayClassName)}
|
|
72
72
|
/>
|
|
73
73
|
<DialogPrimitive.Content
|
|
74
74
|
className={cn(overlayPositionMap[side])}
|
|
@@ -84,6 +84,9 @@ function SheetContainer({
|
|
|
84
84
|
{children}
|
|
85
85
|
{showCloseButton && (
|
|
86
86
|
<DialogPrimitive.Close
|
|
87
|
+
accessibilityRole="button"
|
|
88
|
+
accessibilityLabel="Fechar"
|
|
89
|
+
hitSlop={8}
|
|
87
90
|
className={cn(
|
|
88
91
|
closeButtonPositionMap[side],
|
|
89
92
|
"rounded-pill p-1.5 active:bg-gray-background-soft"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
-
import { type ViewProps } from "react-native";
|
|
2
|
+
import { StyleSheet, View, type ViewProps } from "react-native";
|
|
3
3
|
import Animated, {
|
|
4
4
|
cancelAnimation,
|
|
5
5
|
Easing,
|
|
@@ -16,8 +16,41 @@ interface SkeletonProps extends ViewProps {
|
|
|
16
16
|
className?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// `bg-*` after any variant (`dark:`, `data-[state=on]:`, `[&>*]:`), with or
|
|
20
|
+
// without the important modifier (`!bg-*`).
|
|
21
|
+
const BACKGROUND_CLASS = /(?:^|:)!?bg-/;
|
|
22
|
+
|
|
23
|
+
/** Background classes paint the pulsing layer; the rest shape the box. */
|
|
24
|
+
function splitClassName(className: string | undefined) {
|
|
25
|
+
const classes = className?.split(/\s+/).filter(Boolean) ?? [];
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
box: classes.filter((name) => !BACKGROUND_CLASS.test(name)).join(" "),
|
|
29
|
+
background: classes.filter((name) => BACKGROUND_CLASS.test(name)).join(" "),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Same split for `style`: `backgroundColor` paints the pulsing layer. */
|
|
34
|
+
function splitStyle(style: ViewProps["style"]) {
|
|
35
|
+
const flat = StyleSheet.flatten(style);
|
|
36
|
+
if (flat?.backgroundColor === undefined) {
|
|
37
|
+
return { box: style, background: undefined };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { backgroundColor, ...box } = flat;
|
|
41
|
+
return { box, background: { backgroundColor } };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// NativeWind only maps `className` on registered components, and a Reanimated
|
|
45
|
+
// view isn't one: the classes were dropped and the skeleton had no size or
|
|
46
|
+
// color. Registering it doesn't help either, since NativeWind then merges the
|
|
47
|
+
// classes and the animated style into one object that Reanimated reads as the
|
|
48
|
+
// animated style alone. So the classes stay on plain views and only the pulse
|
|
49
|
+
// runs on the Reanimated one.
|
|
50
|
+
function Skeleton({ className, style, children, ...props }: SkeletonProps) {
|
|
20
51
|
const shimmer = useSharedValue(0);
|
|
52
|
+
const classes = splitClassName(className);
|
|
53
|
+
const styles = splitStyle(style);
|
|
21
54
|
|
|
22
55
|
useEffect(() => {
|
|
23
56
|
shimmer.value = withRepeat(
|
|
@@ -33,11 +66,19 @@ function Skeleton({ className, style, ...props }: SkeletonProps) {
|
|
|
33
66
|
}));
|
|
34
67
|
|
|
35
68
|
return (
|
|
36
|
-
<
|
|
37
|
-
style={
|
|
38
|
-
className={cn("rounded-md
|
|
69
|
+
<View
|
|
70
|
+
style={styles.box}
|
|
71
|
+
className={cn("overflow-hidden rounded-md", classes.box)}
|
|
39
72
|
{...props}
|
|
40
|
-
|
|
73
|
+
>
|
|
74
|
+
<Animated.View style={[StyleSheet.absoluteFill, animatedStyle]}>
|
|
75
|
+
<View
|
|
76
|
+
style={styles.background}
|
|
77
|
+
className={cn("flex-1 bg-gray-150", classes.background)}
|
|
78
|
+
/>
|
|
79
|
+
</Animated.View>
|
|
80
|
+
{children}
|
|
81
|
+
</View>
|
|
41
82
|
);
|
|
42
83
|
}
|
|
43
84
|
|
|
@@ -9,6 +9,7 @@ import Animated, {
|
|
|
9
9
|
} from "react-native-reanimated";
|
|
10
10
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
11
11
|
import { cn } from "@/lib/utils";
|
|
12
|
+
import { getMinTouchHitSlop } from "@/lib/touch-target";
|
|
12
13
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
13
14
|
|
|
14
15
|
interface SwitchProps
|
|
@@ -141,6 +142,7 @@ function Switch({
|
|
|
141
142
|
checked={isChecked}
|
|
142
143
|
onCheckedChange={handleCheckedChange}
|
|
143
144
|
disabled={disabled}
|
|
145
|
+
hitSlop={getMinTouchHitSlop(dimensions.width, dimensions.height)}
|
|
144
146
|
style={(state) => [
|
|
145
147
|
rootStyle,
|
|
146
148
|
typeof style === "function" ? style(state) : style,
|
package/src/components/Tabs.tsx
CHANGED
|
@@ -118,10 +118,12 @@ function TabsTrigger({
|
|
|
118
118
|
if (variant === "filter") {
|
|
119
119
|
const hasLabel = typeof children === "string" && children.length > 0;
|
|
120
120
|
const showLabel = isActive && hasLabel;
|
|
121
|
+
const accessibilityLabel = props.accessibilityLabel ?? (hasLabel ? children : undefined);
|
|
121
122
|
|
|
122
123
|
return (
|
|
123
124
|
<TabsPrimitive.Trigger asChild value={value} {...props}>
|
|
124
125
|
<Pressable
|
|
126
|
+
accessibilityLabel={accessibilityLabel}
|
|
125
127
|
className={cn(
|
|
126
128
|
"relative min-h-12 flex-1 flex-row items-center justify-center gap-3 py-3",
|
|
127
129
|
className
|