@medway-ui/native 1.9.1 → 1.10.0
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 +2 -2
- package/lib/commonjs/components/Alert.js +36 -25
- package/lib/commonjs/components/Alert.js.map +1 -1
- package/lib/commonjs/components/AlertDialog.js +22 -23
- package/lib/commonjs/components/AlertDialog.js.map +1 -1
- package/lib/commonjs/components/Avatar.js +4 -4
- package/lib/commonjs/components/Badge.js +22 -15
- package/lib/commonjs/components/Badge.js.map +1 -1
- package/lib/commonjs/components/Button.js +56 -42
- package/lib/commonjs/components/Button.js.map +1 -1
- package/lib/commonjs/components/CardNews.js +18 -13
- package/lib/commonjs/components/CardNews.js.map +1 -1
- package/lib/commonjs/components/Carousel.js +12 -8
- package/lib/commonjs/components/Carousel.js.map +1 -1
- package/lib/commonjs/components/Checkbox.js +5 -5
- package/lib/commonjs/components/Checkbox.js.map +1 -1
- package/lib/commonjs/components/Chip.js +52 -23
- package/lib/commonjs/components/Chip.js.map +1 -1
- package/lib/commonjs/components/Choice.js +26 -12
- package/lib/commonjs/components/Choice.js.map +1 -1
- package/lib/commonjs/components/Dialog.js +16 -8
- package/lib/commonjs/components/Dialog.js.map +1 -1
- package/lib/commonjs/components/DropdownMenu.js +35 -14
- package/lib/commonjs/components/DropdownMenu.js.map +1 -1
- package/lib/commonjs/components/EmptyState.js +5 -5
- package/lib/commonjs/components/EmptyState.js.map +1 -1
- package/lib/commonjs/components/FallbackImage.js +42 -35
- package/lib/commonjs/components/FallbackImage.js.map +1 -1
- package/lib/commonjs/components/Feed.js +6 -5
- package/lib/commonjs/components/Feed.js.map +1 -1
- package/lib/commonjs/components/FeedNotice.js +3 -3
- package/lib/commonjs/components/Feedback.js +2 -4
- package/lib/commonjs/components/Feedback.js.map +1 -1
- package/lib/commonjs/components/Filter.js +6 -9
- package/lib/commonjs/components/Filter.js.map +1 -1
- package/lib/commonjs/components/IndexLevel.js +4 -4
- package/lib/commonjs/components/Input.js +25 -20
- package/lib/commonjs/components/Input.js.map +1 -1
- package/lib/commonjs/components/InvitePopover.js +19 -8
- package/lib/commonjs/components/InvitePopover.js.map +1 -1
- package/lib/commonjs/components/Label.js +2 -2
- package/lib/commonjs/components/LeaderboardCard.js +3 -2
- package/lib/commonjs/components/LeaderboardCard.js.map +1 -1
- package/lib/commonjs/components/Loading.js +18 -15
- package/lib/commonjs/components/Loading.js.map +1 -1
- package/lib/commonjs/components/LoadingOverlay.js +36 -43
- package/lib/commonjs/components/LoadingOverlay.js.map +1 -1
- package/lib/commonjs/components/MemberRow.js +7 -6
- package/lib/commonjs/components/MemberRow.js.map +1 -1
- package/lib/commonjs/components/PageHeader.js +3 -2
- package/lib/commonjs/components/PageHeader.js.map +1 -1
- package/lib/commonjs/components/Popover.js +1 -1
- package/lib/commonjs/components/PostForm.js +38 -24
- package/lib/commonjs/components/PostForm.js.map +1 -1
- package/lib/commonjs/components/PrizeCollection.js +5 -5
- package/lib/commonjs/components/PrizeCollection.js.map +1 -1
- package/lib/commonjs/components/RadioGroup.js +65 -15
- package/lib/commonjs/components/RadioGroup.js.map +1 -1
- package/lib/commonjs/components/SectionHeader.js +3 -2
- package/lib/commonjs/components/SectionHeader.js.map +1 -1
- package/lib/commonjs/components/SegmentControl.js +4 -4
- package/lib/commonjs/components/Select.js +7 -6
- package/lib/commonjs/components/Select.js.map +1 -1
- package/lib/commonjs/components/Separator.js +2 -2
- package/lib/commonjs/components/Separator.js.map +1 -1
- package/lib/commonjs/components/Sheet.js +17 -11
- package/lib/commonjs/components/Sheet.js.map +1 -1
- package/lib/commonjs/components/Skeleton.js +2 -2
- package/lib/commonjs/components/Skeleton.js.map +1 -1
- package/lib/commonjs/components/Switch.js +3 -3
- package/lib/commonjs/components/Tabs.js +3 -2
- package/lib/commonjs/components/Tabs.js.map +1 -1
- package/lib/commonjs/components/Tag.js +52 -32
- package/lib/commonjs/components/Tag.js.map +1 -1
- package/lib/commonjs/components/Text.js +1 -1
- package/lib/commonjs/components/ThemedIcon.js +1 -1
- package/lib/commonjs/components/Toast.js +12 -12
- package/lib/commonjs/components/Toast.js.map +1 -1
- package/lib/commonjs/components/Tooltip.js +2 -2
- package/lib/commonjs/editor/NoteEditor.js +190 -67
- 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/editor/index.js.map +1 -1
- package/lib/commonjs/editor/protocol.js +1 -2
- package/lib/commonjs/editor/protocol.js.map +1 -1
- package/lib/commonjs/hooks/useThemeColor.js +41 -19
- package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
- package/lib/commonjs/index.js +46 -46
- package/lib/commonjs/lib/backdrop.js +18 -0
- package/lib/commonjs/lib/backdrop.js.map +1 -0
- package/lib/commonjs/lib/overlay-host.js +5 -3
- package/lib/commonjs/lib/overlay-host.js.map +1 -1
- package/lib/commonjs/lib/raised-surface.js +1 -1
- package/lib/module/components/Alert.js +36 -25
- package/lib/module/components/Alert.js.map +1 -1
- package/lib/module/components/AlertDialog.js +21 -22
- package/lib/module/components/AlertDialog.js.map +1 -1
- package/lib/module/components/Avatar.js +4 -4
- package/lib/module/components/Badge.js +22 -15
- package/lib/module/components/Badge.js.map +1 -1
- package/lib/module/components/Button.js +56 -42
- package/lib/module/components/Button.js.map +1 -1
- package/lib/module/components/CardNews.js +18 -13
- package/lib/module/components/CardNews.js.map +1 -1
- package/lib/module/components/Carousel.js +12 -8
- package/lib/module/components/Carousel.js.map +1 -1
- package/lib/module/components/Checkbox.js +5 -5
- package/lib/module/components/Checkbox.js.map +1 -1
- package/lib/module/components/Chip.js +52 -23
- package/lib/module/components/Chip.js.map +1 -1
- package/lib/module/components/Choice.js +26 -12
- package/lib/module/components/Choice.js.map +1 -1
- package/lib/module/components/Dialog.js +16 -8
- package/lib/module/components/Dialog.js.map +1 -1
- package/lib/module/components/DropdownMenu.js +36 -15
- package/lib/module/components/DropdownMenu.js.map +1 -1
- package/lib/module/components/EmptyState.js +5 -5
- package/lib/module/components/EmptyState.js.map +1 -1
- package/lib/module/components/FallbackImage.js +42 -35
- package/lib/module/components/FallbackImage.js.map +1 -1
- package/lib/module/components/Feed.js +6 -5
- package/lib/module/components/Feed.js.map +1 -1
- package/lib/module/components/FeedNotice.js +3 -3
- package/lib/module/components/Feedback.js +2 -4
- package/lib/module/components/Feedback.js.map +1 -1
- package/lib/module/components/Filter.js +6 -9
- package/lib/module/components/Filter.js.map +1 -1
- package/lib/module/components/IndexLevel.js +4 -4
- package/lib/module/components/Input.js +24 -18
- package/lib/module/components/Input.js.map +1 -1
- package/lib/module/components/InvitePopover.js +20 -9
- package/lib/module/components/InvitePopover.js.map +1 -1
- package/lib/module/components/Label.js +2 -2
- package/lib/module/components/LeaderboardCard.js +3 -2
- package/lib/module/components/LeaderboardCard.js.map +1 -1
- package/lib/module/components/Loading.js +18 -15
- package/lib/module/components/Loading.js.map +1 -1
- package/lib/module/components/LoadingOverlay.js +37 -44
- package/lib/module/components/LoadingOverlay.js.map +1 -1
- package/lib/module/components/MemberRow.js +7 -6
- package/lib/module/components/MemberRow.js.map +1 -1
- package/lib/module/components/PageHeader.js +3 -2
- package/lib/module/components/PageHeader.js.map +1 -1
- package/lib/module/components/Popover.js +1 -1
- package/lib/module/components/PostForm.js +38 -24
- package/lib/module/components/PostForm.js.map +1 -1
- package/lib/module/components/PrizeCollection.js +5 -5
- package/lib/module/components/PrizeCollection.js.map +1 -1
- package/lib/module/components/RadioGroup.js +65 -15
- package/lib/module/components/RadioGroup.js.map +1 -1
- package/lib/module/components/SectionHeader.js +3 -2
- package/lib/module/components/SectionHeader.js.map +1 -1
- package/lib/module/components/SegmentControl.js +4 -4
- package/lib/module/components/Select.js +6 -5
- package/lib/module/components/Select.js.map +1 -1
- package/lib/module/components/Separator.js +2 -2
- package/lib/module/components/Separator.js.map +1 -1
- package/lib/module/components/Sheet.js +17 -11
- package/lib/module/components/Sheet.js.map +1 -1
- package/lib/module/components/Skeleton.js +2 -2
- package/lib/module/components/Skeleton.js.map +1 -1
- package/lib/module/components/Switch.js +3 -3
- package/lib/module/components/Tabs.js +3 -2
- package/lib/module/components/Tabs.js.map +1 -1
- package/lib/module/components/Tag.js +52 -32
- package/lib/module/components/Tag.js.map +1 -1
- package/lib/module/components/Text.js +1 -1
- package/lib/module/components/ThemedIcon.js +1 -1
- package/lib/module/components/Toast.js +12 -12
- package/lib/module/components/Toast.js.map +1 -1
- package/lib/module/components/Tooltip.js +2 -2
- package/lib/module/editor/NoteEditor.js +193 -69
- 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/editor/index.js.map +1 -1
- package/lib/module/editor/protocol.js +1 -2
- package/lib/module/editor/protocol.js.map +1 -1
- package/lib/module/hooks/useThemeColor.js +41 -19
- package/lib/module/hooks/useThemeColor.js.map +1 -1
- package/lib/module/index.js +46 -46
- package/lib/module/lib/backdrop.js +15 -0
- package/lib/module/lib/backdrop.js.map +1 -0
- package/lib/module/lib/overlay-host.js +6 -4
- package/lib/module/lib/overlay-host.js.map +1 -1
- package/lib/module/lib/raised-surface.js +1 -1
- package/lib/typescript/components/Alert.d.ts +1 -1
- package/lib/typescript/components/Alert.d.ts.map +1 -1
- package/lib/typescript/components/AlertDialog.d.ts +1 -1
- package/lib/typescript/components/AlertDialog.d.ts.map +1 -1
- package/lib/typescript/components/Badge.d.ts.map +1 -1
- package/lib/typescript/components/Button.d.ts +1 -0
- package/lib/typescript/components/Button.d.ts.map +1 -1
- package/lib/typescript/components/CardNews.d.ts +7 -2
- package/lib/typescript/components/CardNews.d.ts.map +1 -1
- package/lib/typescript/components/Checkbox.d.ts +3 -1
- package/lib/typescript/components/Checkbox.d.ts.map +1 -1
- package/lib/typescript/components/Chip.d.ts.map +1 -1
- package/lib/typescript/components/Choice.d.ts +4 -1
- package/lib/typescript/components/Choice.d.ts.map +1 -1
- package/lib/typescript/components/Dialog.d.ts +2 -1
- package/lib/typescript/components/Dialog.d.ts.map +1 -1
- package/lib/typescript/components/DropdownMenu.d.ts +3 -2
- package/lib/typescript/components/DropdownMenu.d.ts.map +1 -1
- package/lib/typescript/components/FallbackImage.d.ts.map +1 -1
- package/lib/typescript/components/Feed.d.ts.map +1 -1
- package/lib/typescript/components/Feedback.d.ts.map +1 -1
- package/lib/typescript/components/Filter.d.ts.map +1 -1
- package/lib/typescript/components/IndexLevel.d.ts +1 -1
- package/lib/typescript/components/Input.d.ts +5 -5
- package/lib/typescript/components/Input.d.ts.map +1 -1
- package/lib/typescript/components/InvitePopover.d.ts +1 -1
- package/lib/typescript/components/InvitePopover.d.ts.map +1 -1
- package/lib/typescript/components/LeaderboardCard.d.ts.map +1 -1
- package/lib/typescript/components/Loading.d.ts +1 -1
- package/lib/typescript/components/Loading.d.ts.map +1 -1
- package/lib/typescript/components/LoadingOverlay.d.ts +9 -9
- package/lib/typescript/components/LoadingOverlay.d.ts.map +1 -1
- package/lib/typescript/components/PageHeader.d.ts.map +1 -1
- package/lib/typescript/components/PostForm.d.ts.map +1 -1
- package/lib/typescript/components/RadioGroup.d.ts +4 -2
- package/lib/typescript/components/RadioGroup.d.ts.map +1 -1
- package/lib/typescript/components/SectionHeader.d.ts.map +1 -1
- package/lib/typescript/components/SegmentControl.d.ts +1 -1
- package/lib/typescript/components/Select.d.ts +2 -1
- package/lib/typescript/components/Select.d.ts.map +1 -1
- package/lib/typescript/components/Separator.d.ts.map +1 -1
- package/lib/typescript/components/Sheet.d.ts +2 -1
- package/lib/typescript/components/Sheet.d.ts.map +1 -1
- package/lib/typescript/components/Tabs.d.ts +4 -3
- package/lib/typescript/components/Tabs.d.ts.map +1 -1
- package/lib/typescript/components/Tag.d.ts +3 -1
- package/lib/typescript/components/Tag.d.ts.map +1 -1
- package/lib/typescript/components/ThemedIcon.d.ts +1 -1
- package/lib/typescript/components/Toast.d.ts +1 -1
- package/lib/typescript/components/Toast.d.ts.map +1 -1
- package/lib/typescript/editor/NoteEditor.d.ts +28 -8
- package/lib/typescript/editor/NoteEditor.d.ts.map +1 -1
- package/lib/typescript/editor/editorHtml.generated.d.ts.map +1 -1
- package/lib/typescript/editor/index.d.ts +1 -1
- package/lib/typescript/editor/index.d.ts.map +1 -1
- package/lib/typescript/editor/protocol.d.ts +4 -14
- package/lib/typescript/editor/protocol.d.ts.map +1 -1
- package/lib/typescript/hooks/use-toast.d.ts +1 -1
- package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +91 -91
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/lib/backdrop.d.ts +4 -0
- package/lib/typescript/lib/backdrop.d.ts.map +1 -0
- package/lib/typescript/lib/overlay-host.d.ts +1 -0
- package/lib/typescript/lib/overlay-host.d.ts.map +1 -1
- package/package.json +9 -14
- package/setup/metro.js +26 -73
- package/setup/tailwind.js +16 -8
- package/setup/tokens.native.css +51 -20
- package/src/components/Alert.tsx +37 -20
- package/src/components/AlertDialog.tsx +18 -19
- package/src/components/Badge.tsx +16 -15
- package/src/components/Button.tsx +64 -31
- package/src/components/CardNews.tsx +17 -6
- package/src/components/Carousel.tsx +5 -5
- package/src/components/Checkbox.tsx +17 -7
- package/src/components/Chip.tsx +49 -21
- package/src/components/Choice.tsx +34 -14
- package/src/components/Dialog.tsx +15 -5
- package/src/components/DropdownMenu.tsx +62 -14
- package/src/components/EmptyState.tsx +3 -3
- package/src/components/FallbackImage.tsx +32 -23
- package/src/components/Feed.tsx +2 -1
- package/src/components/Feedback.tsx +0 -1
- package/src/components/Filter.tsx +2 -3
- package/src/components/Input.tsx +83 -64
- package/src/components/InvitePopover.tsx +11 -3
- package/src/components/LeaderboardCard.tsx +4 -1
- package/src/components/Loading.tsx +17 -14
- package/src/components/LoadingOverlay.tsx +33 -50
- package/src/components/MemberRow.tsx +3 -3
- package/src/components/PageHeader.tsx +4 -1
- package/src/components/PostForm.tsx +28 -16
- package/src/components/PrizeCollection.tsx +3 -3
- package/src/components/RadioGroup.tsx +69 -12
- package/src/components/SectionHeader.tsx +4 -1
- package/src/components/Select.tsx +4 -3
- package/src/components/Separator.tsx +2 -2
- package/src/components/Sheet.tsx +15 -8
- package/src/components/Skeleton.tsx +1 -1
- package/src/components/Tabs.tsx +5 -4
- package/src/components/Tag.tsx +56 -35
- package/src/components/Toast.tsx +10 -6
- package/src/editor/NoteEditor.tsx +246 -72
- package/src/editor/editorHtml.generated.ts +1 -1
- package/src/editor/index.ts +8 -4
- package/src/editor/protocol.ts +4 -12
- package/src/hooks/useThemeColor.ts +41 -19
- package/src/index.ts +1 -1
- package/src/lib/backdrop.ts +16 -0
- package/src/lib/overlay-host.tsx +5 -5
|
@@ -54,6 +54,11 @@ interface CardNewsAuthorProps extends Omit<ViewProps, "role"> {
|
|
|
54
54
|
src?: string;
|
|
55
55
|
alt?: string;
|
|
56
56
|
name?: string;
|
|
57
|
+
jobTitle?: string;
|
|
58
|
+
/**
|
|
59
|
+
* @deprecated Use `jobTitle` para o cargo. Sem `jobTitle`, `role` ainda é
|
|
60
|
+
* exibido como cargo; com `jobTitle`, vira o papel de acessibilidade da View.
|
|
61
|
+
*/
|
|
57
62
|
role?: string;
|
|
58
63
|
children?: ReactNode;
|
|
59
64
|
}
|
|
@@ -177,8 +182,8 @@ function CardNewsImage({
|
|
|
177
182
|
}: CardNewsImageProps) {
|
|
178
183
|
const { orientation } = useContext(CardNewsContext);
|
|
179
184
|
const { width } = useWindowDimensions();
|
|
180
|
-
const [
|
|
181
|
-
const showImage = !!src &&
|
|
185
|
+
const [failedSrc, setFailedSrc] = useState<string>();
|
|
186
|
+
const showImage = !!src && failedSrc !== src;
|
|
182
187
|
const showHorizontalImage =
|
|
183
188
|
orientation !== "horizontal" || width >= HORIZONTAL_IMAGE_MIN_WIDTH;
|
|
184
189
|
|
|
@@ -206,11 +211,11 @@ function CardNewsImage({
|
|
|
206
211
|
{...imageProps}
|
|
207
212
|
onError={(event) => {
|
|
208
213
|
imageProps?.onError?.(event);
|
|
209
|
-
|
|
214
|
+
setFailedSrc(src);
|
|
210
215
|
}}
|
|
211
216
|
/>
|
|
212
217
|
) : (
|
|
213
|
-
children ?? <FallbackImage className="absolute inset-0" />
|
|
218
|
+
children ?? <FallbackImage className="absolute inset-0" label={alt} />
|
|
214
219
|
)}
|
|
215
220
|
</View>
|
|
216
221
|
);
|
|
@@ -310,12 +315,18 @@ function CardNewsAuthor({
|
|
|
310
315
|
src,
|
|
311
316
|
alt,
|
|
312
317
|
name,
|
|
318
|
+
jobTitle,
|
|
313
319
|
role,
|
|
314
320
|
children,
|
|
315
321
|
...props
|
|
316
322
|
}: CardNewsAuthorProps) {
|
|
323
|
+
const title = jobTitle ?? role;
|
|
324
|
+
const accessibilityRole =
|
|
325
|
+
jobTitle === undefined ? undefined : (role as ViewProps["role"]);
|
|
326
|
+
|
|
317
327
|
return (
|
|
318
328
|
<View
|
|
329
|
+
role={accessibilityRole}
|
|
319
330
|
className={cn("flex-row items-center gap-2", className)}
|
|
320
331
|
{...props}
|
|
321
332
|
>
|
|
@@ -328,9 +339,9 @@ function CardNewsAuthor({
|
|
|
328
339
|
</AvatarFallback>
|
|
329
340
|
</Avatar>
|
|
330
341
|
<View className="flex flex-col gap-0.5">
|
|
331
|
-
{
|
|
342
|
+
{title ? (
|
|
332
343
|
<Text className="text-xs font-medium leading-xs text-secondary-foreground">
|
|
333
|
-
{
|
|
344
|
+
{title}
|
|
334
345
|
</Text>
|
|
335
346
|
) : null}
|
|
336
347
|
{name ? (
|
|
@@ -48,6 +48,7 @@ function Carousel({
|
|
|
48
48
|
}: CarouselProps) {
|
|
49
49
|
const chevronColor = useThemeColor("primary-foreground");
|
|
50
50
|
const slidePositionLabel = getSlidePositionLabel(slideIndex, slideCount);
|
|
51
|
+
const slideValue = slidePositionLabel ? { text: slidePositionLabel } : undefined;
|
|
51
52
|
|
|
52
53
|
return (
|
|
53
54
|
<View
|
|
@@ -64,11 +65,9 @@ function Carousel({
|
|
|
64
65
|
iconLeft={<ChevronLeftMd width={20} height={20} color={chevronColor} />}
|
|
65
66
|
onPress={onPrevious}
|
|
66
67
|
accessibilityLabel="Slide anterior"
|
|
68
|
+
accessibilityValue={slideValue}
|
|
67
69
|
/>
|
|
68
|
-
<View
|
|
69
|
-
className="h-full min-w-0 flex-1 items-center justify-center px-4"
|
|
70
|
-
accessibilityLabel={slidePositionLabel}
|
|
71
|
-
>
|
|
70
|
+
<View className="h-full min-w-0 flex-1 items-center justify-center px-4">
|
|
72
71
|
{children}
|
|
73
72
|
</View>
|
|
74
73
|
<Button
|
|
@@ -78,6 +77,7 @@ function Carousel({
|
|
|
78
77
|
iconLeft={<ChevronRightMd width={20} height={20} color={chevronColor} />}
|
|
79
78
|
onPress={onNext}
|
|
80
79
|
accessibilityLabel="Próximo slide"
|
|
80
|
+
accessibilityValue={slideValue}
|
|
81
81
|
/>
|
|
82
82
|
</View>
|
|
83
83
|
);
|
|
@@ -147,7 +147,7 @@ function CarouselMetricSlide({
|
|
|
147
147
|
<View className="items-center justify-center">{icon}</View>
|
|
148
148
|
) : null}
|
|
149
149
|
<View className="w-full items-center gap-3">
|
|
150
|
-
<Text className="text-center text-
|
|
150
|
+
<Text className="text-center text-title-lg font-bold leading-title-lg text-primary-foreground">
|
|
151
151
|
{value}
|
|
152
152
|
</Text>
|
|
153
153
|
<Text className="text-center text-sm font-semibold leading-sm text-primary-foreground">
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { useState, type ReactNode } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type PressableStateCallbackType,
|
|
4
|
+
type StyleProp,
|
|
5
|
+
type ViewStyle,
|
|
6
|
+
} from "react-native";
|
|
3
7
|
import { cssInterop } from "nativewind";
|
|
4
8
|
import * as CheckboxPrimitive from "@rn-primitives/checkbox";
|
|
5
9
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
@@ -20,10 +24,13 @@ const StyledCheckboxIndicator = cssInterop(CheckboxPrimitive.Indicator, {
|
|
|
20
24
|
interface CheckboxProps
|
|
21
25
|
extends Omit<
|
|
22
26
|
CheckboxPrimitive.RootProps,
|
|
23
|
-
"checked" | "onCheckedChange" | "children"
|
|
27
|
+
"checked" | "onCheckedChange" | "children" | "style"
|
|
24
28
|
>,
|
|
25
29
|
Omit<VariantProps<typeof checkboxVariants>, "checked" | "disabled"> {
|
|
26
30
|
children?: ReactNode;
|
|
31
|
+
style?:
|
|
32
|
+
| StyleProp<ViewStyle>
|
|
33
|
+
| ((state: PressableStateCallbackType) => StyleProp<ViewStyle>);
|
|
27
34
|
checked?: boolean;
|
|
28
35
|
defaultChecked?: boolean;
|
|
29
36
|
onCheckedChange?: (checked: boolean) => void;
|
|
@@ -91,7 +98,9 @@ function Checkbox({
|
|
|
91
98
|
const [internalChecked, setInternalChecked] = useState(defaultChecked);
|
|
92
99
|
const isControlled = checked !== undefined;
|
|
93
100
|
const isChecked = isControlled ? checked : internalChecked;
|
|
94
|
-
const iconColor = useThemeColor(
|
|
101
|
+
const iconColor = useThemeColor(
|
|
102
|
+
disabled ? "gray-background-fill-muted" : "primary-foreground-onfill"
|
|
103
|
+
);
|
|
95
104
|
|
|
96
105
|
const handleCheckedChange = (nextChecked: boolean) => {
|
|
97
106
|
if (!isControlled) setInternalChecked(nextChecked);
|
|
@@ -115,10 +124,11 @@ function Checkbox({
|
|
|
115
124
|
onCheckedChange={handleCheckedChange}
|
|
116
125
|
disabled={disabled}
|
|
117
126
|
hitSlop={getMinTouchHitSlop(dimension)}
|
|
118
|
-
style={
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
style={
|
|
128
|
+
typeof style === "function"
|
|
129
|
+
? (state: PressableStateCallbackType) => [rootStyle, style(state)]
|
|
130
|
+
: [rootStyle, style]
|
|
131
|
+
}
|
|
122
132
|
className={cn(
|
|
123
133
|
checkboxVariants({
|
|
124
134
|
size,
|
package/src/components/Chip.tsx
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { Pressable, View } from "react-native";
|
|
2
|
+
import { Pressable, View, type AccessibilityActionEvent } from "react-native";
|
|
3
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
4
|
import { CloseSm } from "@medway-ui/icons/native";
|
|
5
5
|
|
|
6
6
|
import { Text } from "@/components/Text";
|
|
7
7
|
import { ThemedIcon } from "@/components/ThemedIcon";
|
|
8
|
+
import { getMinTouchHitSlop } from "@/lib/touch-target";
|
|
8
9
|
import { cn } from "@/lib/utils";
|
|
9
10
|
|
|
10
11
|
const chipVariants = cva(
|
|
@@ -31,12 +32,12 @@ const chipBackgroundVariants = cva("", {
|
|
|
31
32
|
"emphasis-soft": "bg-secondary-background-soft",
|
|
32
33
|
gray: "bg-gray-background-fill",
|
|
33
34
|
"gray-soft": "bg-gray-background-soft",
|
|
34
|
-
success: "bg-
|
|
35
|
-
"success-soft": "bg-
|
|
36
|
-
error: "bg-
|
|
37
|
-
"error-soft": "bg-
|
|
38
|
-
warning: "bg-
|
|
39
|
-
"warning-soft": "bg-
|
|
35
|
+
success: "bg-feedback-success-background-fill",
|
|
36
|
+
"success-soft": "bg-feedback-success-background-soft",
|
|
37
|
+
error: "bg-feedback-error-background-fill",
|
|
38
|
+
"error-soft": "bg-feedback-error-background-soft",
|
|
39
|
+
warning: "bg-feedback-warning-background-fill",
|
|
40
|
+
"warning-soft": "bg-feedback-warning-background-soft",
|
|
40
41
|
go: "bg-go-background-fill",
|
|
41
42
|
"go-soft": "bg-go-background-soft",
|
|
42
43
|
cm: "bg-cm-background-fill",
|
|
@@ -79,12 +80,12 @@ const chipTextVariants = cva("text-center font-semibold", {
|
|
|
79
80
|
"emphasis-soft": "text-secondary-foreground",
|
|
80
81
|
gray: "text-gray-foreground-onfill",
|
|
81
82
|
"gray-soft": "text-gray-foreground",
|
|
82
|
-
success: "text-
|
|
83
|
-
"success-soft": "text-
|
|
84
|
-
error: "text-
|
|
85
|
-
"error-soft": "text-
|
|
86
|
-
warning: "text-
|
|
87
|
-
"warning-soft": "text-
|
|
83
|
+
success: "text-feedback-success-foreground-onfill",
|
|
84
|
+
"success-soft": "text-feedback-success-foreground",
|
|
85
|
+
error: "text-feedback-error-foreground-onfill",
|
|
86
|
+
"error-soft": "text-feedback-error-foreground",
|
|
87
|
+
warning: "text-feedback-warning-foreground-onfill",
|
|
88
|
+
"warning-soft": "text-feedback-warning-foreground",
|
|
88
89
|
go: "text-go-foreground-onfill",
|
|
89
90
|
"go-soft": "text-go-foreground",
|
|
90
91
|
cm: "text-cm-foreground-onfill",
|
|
@@ -131,12 +132,12 @@ const CHIP_ICON_COLOR_TOKEN: Record<ChipVariant, string> = {
|
|
|
131
132
|
"emphasis-soft": "secondary-foreground",
|
|
132
133
|
gray: "gray-foreground-onfill",
|
|
133
134
|
"gray-soft": "gray-foreground",
|
|
134
|
-
success: "
|
|
135
|
-
"success-soft": "
|
|
136
|
-
error: "
|
|
137
|
-
"error-soft": "
|
|
138
|
-
warning: "
|
|
139
|
-
"warning-soft": "
|
|
135
|
+
success: "feedback-success-foreground-onfill",
|
|
136
|
+
"success-soft": "feedback-success-foreground",
|
|
137
|
+
error: "feedback-error-foreground-onfill",
|
|
138
|
+
"error-soft": "feedback-error-foreground",
|
|
139
|
+
warning: "feedback-warning-foreground-onfill",
|
|
140
|
+
"warning-soft": "feedback-warning-foreground",
|
|
140
141
|
go: "go-foreground-onfill",
|
|
141
142
|
"go-soft": "go-foreground",
|
|
142
143
|
cm: "cm-foreground-onfill",
|
|
@@ -151,6 +152,15 @@ const CHIP_ICON_COLOR_TOKEN: Record<ChipVariant, string> = {
|
|
|
151
152
|
"ia-soft": "secondary-foreground",
|
|
152
153
|
};
|
|
153
154
|
|
|
155
|
+
// gap-2/2.5/3 rounded down to px at NativeWind's default 14px rem, so the dismiss slop stops before the label.
|
|
156
|
+
const CHIP_LABEL_GAP: Record<ChipSize, number> = {
|
|
157
|
+
sm: 7,
|
|
158
|
+
md: 8,
|
|
159
|
+
lg: 10,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const DEFAULT_DISMISS_LABEL = "Remover";
|
|
163
|
+
|
|
154
164
|
interface ChipProps
|
|
155
165
|
extends Omit<VariantProps<typeof chipVariants>, "disabled"> {
|
|
156
166
|
children: ReactNode;
|
|
@@ -177,6 +187,11 @@ function Chip({
|
|
|
177
187
|
? CHIP_ICON_COLOR_TOKEN[variant]
|
|
178
188
|
: "primary-foreground";
|
|
179
189
|
const iconColor = disabled ? "gray-foreground-muted" : variantIconColor;
|
|
190
|
+
const dismissLabel = dismissAccessibilityLabel ?? DEFAULT_DISMISS_LABEL;
|
|
191
|
+
const dismissHitSlop = {
|
|
192
|
+
...getMinTouchHitSlop(iconSize),
|
|
193
|
+
left: CHIP_LABEL_GAP[size ?? "lg"],
|
|
194
|
+
};
|
|
180
195
|
|
|
181
196
|
const containerClass = cn(
|
|
182
197
|
chipVariants({ size, disabled }),
|
|
@@ -184,6 +199,12 @@ function Chip({
|
|
|
184
199
|
className
|
|
185
200
|
);
|
|
186
201
|
|
|
202
|
+
const handleAccessibilityAction = (event: AccessibilityActionEvent) => {
|
|
203
|
+
if (disabled) return;
|
|
204
|
+
if (event.nativeEvent.actionName === "activate") onPress?.();
|
|
205
|
+
if (event.nativeEvent.actionName === "dismiss") onDismiss?.();
|
|
206
|
+
};
|
|
207
|
+
|
|
187
208
|
const content = (
|
|
188
209
|
<>
|
|
189
210
|
<Text className={cn(chipTextVariants({ size, variant, disabled }))}>
|
|
@@ -194,8 +215,8 @@ function Chip({
|
|
|
194
215
|
onPress={onDismiss}
|
|
195
216
|
disabled={disabled}
|
|
196
217
|
accessibilityRole="button"
|
|
197
|
-
accessibilityLabel={
|
|
198
|
-
hitSlop={
|
|
218
|
+
accessibilityLabel={dismissLabel}
|
|
219
|
+
hitSlop={dismissHitSlop}
|
|
199
220
|
>
|
|
200
221
|
<ThemedIcon
|
|
201
222
|
icon={CloseSm as never}
|
|
@@ -213,6 +234,13 @@ function Chip({
|
|
|
213
234
|
onPress={onPress}
|
|
214
235
|
disabled={disabled}
|
|
215
236
|
accessibilityRole="button"
|
|
237
|
+
accessibilityState={{ disabled }}
|
|
238
|
+
accessibilityActions={
|
|
239
|
+
onDismiss
|
|
240
|
+
? [{ name: "activate" }, { name: "dismiss", label: dismissLabel }]
|
|
241
|
+
: undefined
|
|
242
|
+
}
|
|
243
|
+
onAccessibilityAction={onDismiss ? handleAccessibilityAction : undefined}
|
|
216
244
|
className={containerClass}
|
|
217
245
|
>
|
|
218
246
|
{content}
|
|
@@ -9,19 +9,24 @@ import { cn } from "@/lib/utils";
|
|
|
9
9
|
|
|
10
10
|
type ChoiceSize = "sm" | "md" | "lg";
|
|
11
11
|
|
|
12
|
-
type
|
|
12
|
+
type ChoiceResolvedTheme =
|
|
13
13
|
| "gray"
|
|
14
14
|
| "primary"
|
|
15
15
|
| "secondary"
|
|
16
|
-
| "
|
|
17
|
-
| "
|
|
18
|
-
| "
|
|
16
|
+
| "success"
|
|
17
|
+
| "error"
|
|
18
|
+
| "warning"
|
|
19
19
|
| "cm"
|
|
20
20
|
| "go"
|
|
21
21
|
| "cir"
|
|
22
22
|
| "ped"
|
|
23
23
|
| "prev";
|
|
24
24
|
|
|
25
|
+
/** @deprecated Use `success`, `error` and `warning`, the names used across the package. Removed in the next major. */
|
|
26
|
+
type ChoiceLegacyTheme = "green" | "red" | "yellow";
|
|
27
|
+
|
|
28
|
+
type ChoiceTheme = ChoiceResolvedTheme | ChoiceLegacyTheme;
|
|
29
|
+
|
|
25
30
|
interface ChoiceProps {
|
|
26
31
|
label: string;
|
|
27
32
|
selected?: boolean;
|
|
@@ -58,13 +63,19 @@ const SIZE_MAP: Record<
|
|
|
58
63
|
},
|
|
59
64
|
};
|
|
60
65
|
|
|
61
|
-
const
|
|
66
|
+
const LEGACY_THEME: Record<ChoiceLegacyTheme, ChoiceResolvedTheme> = {
|
|
67
|
+
green: "success",
|
|
68
|
+
red: "error",
|
|
69
|
+
yellow: "warning",
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const THEME_SELECTED_OUTER_BG: Record<ChoiceResolvedTheme, string> = {
|
|
62
73
|
gray: "bg-gray-background-soft",
|
|
63
74
|
primary: "bg-primary-background-fill",
|
|
64
75
|
secondary: "bg-secondary-background-fill",
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
success: "bg-feedback-success-background-fill",
|
|
77
|
+
error: "bg-feedback-error-background-fill",
|
|
78
|
+
warning: "bg-feedback-warning-background-fill",
|
|
68
79
|
cm: "bg-cm-background-fill",
|
|
69
80
|
go: "bg-go-background-fill",
|
|
70
81
|
cir: "bg-cir-background-fill-emphasis",
|
|
@@ -72,13 +83,13 @@ const THEME_SELECTED_OUTER_BG: Record<ChoiceTheme, string> = {
|
|
|
72
83
|
prev: "bg-prev-background-fill",
|
|
73
84
|
};
|
|
74
85
|
|
|
75
|
-
const THEME_CHECK_COLOR_TOKEN: Record<
|
|
86
|
+
const THEME_CHECK_COLOR_TOKEN: Record<ChoiceResolvedTheme, string> = {
|
|
76
87
|
gray: "secondary-foreground",
|
|
77
88
|
primary: "primary-foreground",
|
|
78
89
|
secondary: "secondary-foreground",
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
success: "feedback-success-foreground",
|
|
91
|
+
error: "feedback-error-foreground",
|
|
92
|
+
warning: "feedback-warning-foreground",
|
|
82
93
|
cm: "cm-foreground",
|
|
83
94
|
go: "go-foreground",
|
|
84
95
|
cir: "cir-foreground",
|
|
@@ -86,6 +97,14 @@ const THEME_CHECK_COLOR_TOKEN: Record<ChoiceTheme, string> = {
|
|
|
86
97
|
prev: "prev-foreground",
|
|
87
98
|
};
|
|
88
99
|
|
|
100
|
+
function isLegacyTheme(theme: ChoiceTheme): theme is ChoiceLegacyTheme {
|
|
101
|
+
return theme in LEGACY_THEME;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function resolveTheme(theme: ChoiceTheme): ChoiceResolvedTheme {
|
|
105
|
+
return isLegacyTheme(theme) ? LEGACY_THEME[theme] : theme;
|
|
106
|
+
}
|
|
107
|
+
|
|
89
108
|
function Choice({
|
|
90
109
|
label,
|
|
91
110
|
selected = false,
|
|
@@ -97,12 +116,13 @@ function Choice({
|
|
|
97
116
|
className,
|
|
98
117
|
}: ChoiceProps) {
|
|
99
118
|
const sz = SIZE_MAP[size] ?? SIZE_MAP.md;
|
|
119
|
+
const resolvedTheme = resolveTheme(theme);
|
|
100
120
|
const isRaised = selected && !disabled;
|
|
101
121
|
|
|
102
122
|
const outerBg = disabled
|
|
103
123
|
? "bg-gray-background-soft-muted"
|
|
104
124
|
: selected
|
|
105
|
-
? THEME_SELECTED_OUTER_BG[
|
|
125
|
+
? THEME_SELECTED_OUTER_BG[resolvedTheme]
|
|
106
126
|
: "bg-gray-background-soft active:bg-gray-background-soft-emphasis";
|
|
107
127
|
|
|
108
128
|
return (
|
|
@@ -145,7 +165,7 @@ function Choice({
|
|
|
145
165
|
colorToken={
|
|
146
166
|
disabled
|
|
147
167
|
? "gray-foreground-muted"
|
|
148
|
-
: THEME_CHECK_COLOR_TOKEN[
|
|
168
|
+
: THEME_CHECK_COLOR_TOKEN[resolvedTheme]
|
|
149
169
|
}
|
|
150
170
|
/>
|
|
151
171
|
</View>
|
|
@@ -3,12 +3,14 @@ import { View, ScrollView, type ViewProps } from "react-native";
|
|
|
3
3
|
import * as DialogPrimitive from "@rn-primitives/dialog";
|
|
4
4
|
import { CloseMd } from "@medway-ui/icons/native";
|
|
5
5
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
6
|
+
import { useBackdropStyle } from "@/lib/backdrop";
|
|
6
7
|
import { cn } from "@/lib/utils";
|
|
7
8
|
import { Separator } from "@/components/Separator";
|
|
8
9
|
|
|
9
10
|
interface DialogContainerProps extends DialogPrimitive.ContentProps {
|
|
10
11
|
showCloseButton?: boolean;
|
|
11
12
|
overlayClassName?: string;
|
|
13
|
+
closeOnOverlayPress?: boolean;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
interface DialogHeaderProps extends ViewProps {
|
|
@@ -41,9 +43,12 @@ function DialogClose({ ...props }: DialogPrimitive.CloseProps) {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
function DialogOverlay({ className, ...props }: DialogPrimitive.OverlayProps) {
|
|
46
|
+
const backdropStyle = useBackdropStyle(className);
|
|
47
|
+
|
|
44
48
|
return (
|
|
45
49
|
<DialogPrimitive.Overlay
|
|
46
|
-
className={cn("absolute inset-0
|
|
50
|
+
className={cn("absolute inset-0", className)}
|
|
51
|
+
style={backdropStyle}
|
|
47
52
|
{...props}
|
|
48
53
|
/>
|
|
49
54
|
);
|
|
@@ -54,22 +59,27 @@ function DialogContainer({
|
|
|
54
59
|
overlayClassName,
|
|
55
60
|
children,
|
|
56
61
|
showCloseButton = true,
|
|
62
|
+
closeOnOverlayPress = true,
|
|
57
63
|
...props
|
|
58
64
|
}: DialogContainerProps) {
|
|
59
65
|
const closeIconColor = useThemeColor("gray-foreground");
|
|
66
|
+
const backdropStyle = useBackdropStyle(overlayClassName);
|
|
60
67
|
|
|
61
68
|
return (
|
|
62
69
|
<DialogPrimitive.Portal>
|
|
63
70
|
<DialogPrimitive.Overlay
|
|
64
|
-
className={cn("absolute inset-0
|
|
71
|
+
className={cn("absolute inset-0", overlayClassName)}
|
|
72
|
+
style={backdropStyle}
|
|
73
|
+
closeOnPress={closeOnOverlayPress}
|
|
65
74
|
/>
|
|
66
75
|
<DialogPrimitive.Content
|
|
67
76
|
className="absolute inset-0 items-center justify-center px-4"
|
|
77
|
+
pointerEvents="box-none"
|
|
68
78
|
{...props}
|
|
69
79
|
>
|
|
70
80
|
<View
|
|
71
81
|
className={cn(
|
|
72
|
-
"relative flex-col max-h-[90%] w-full rounded-
|
|
82
|
+
"relative flex-col max-h-[90%] w-full rounded-lg bg-surface-elevated shadow-lg overflow-hidden",
|
|
73
83
|
className
|
|
74
84
|
)}
|
|
75
85
|
>
|
|
@@ -101,7 +111,7 @@ function DialogContent({
|
|
|
101
111
|
}) {
|
|
102
112
|
return (
|
|
103
113
|
<ScrollView
|
|
104
|
-
className={cn(
|
|
114
|
+
className={cn(containerClassName)}
|
|
105
115
|
contentContainerStyle={{ flexGrow: 1 }}
|
|
106
116
|
>
|
|
107
117
|
<View className={cn("px-8 py-6", className)}>
|
|
@@ -175,7 +185,7 @@ function DialogTitle({ className, iconLeft, iconRight, children, ...props }: Dia
|
|
|
175
185
|
function DialogDescription({ className, ...props }: DialogPrimitive.DescriptionProps) {
|
|
176
186
|
return (
|
|
177
187
|
<DialogPrimitive.Description
|
|
178
|
-
className={cn("text-md leading-md text-content-paragraph", className)}
|
|
188
|
+
className={cn("text-md font-regular leading-md text-content-paragraph", className)}
|
|
179
189
|
{...props}
|
|
180
190
|
/>
|
|
181
191
|
);
|
|
@@ -8,7 +8,18 @@ import {
|
|
|
8
8
|
useState,
|
|
9
9
|
type ReactNode,
|
|
10
10
|
} from "react";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
BackHandler,
|
|
13
|
+
Dimensions,
|
|
14
|
+
Pressable,
|
|
15
|
+
StyleSheet,
|
|
16
|
+
View,
|
|
17
|
+
type PressableProps,
|
|
18
|
+
type PressableStateCallbackType,
|
|
19
|
+
type StyleProp,
|
|
20
|
+
type ViewProps,
|
|
21
|
+
type ViewStyle,
|
|
22
|
+
} from "react-native";
|
|
12
23
|
|
|
13
24
|
import { Text } from "@/components/Text";
|
|
14
25
|
import * as DropdownMenuPrimitive from "@rn-primitives/dropdown-menu";
|
|
@@ -21,8 +32,11 @@ interface DropdownMenuProps extends DropdownMenuPrimitive.RootProps {
|
|
|
21
32
|
children?: ReactNode;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
|
-
interface DropdownMenuTriggerProps extends DropdownMenuPrimitive.TriggerProps {
|
|
35
|
+
interface DropdownMenuTriggerProps extends Omit<DropdownMenuPrimitive.TriggerProps, "style"> {
|
|
25
36
|
children?: ReactNode;
|
|
37
|
+
style?:
|
|
38
|
+
| StyleProp<ViewStyle>
|
|
39
|
+
| ((state: PressableStateCallbackType) => StyleProp<ViewStyle>);
|
|
26
40
|
className?: string;
|
|
27
41
|
}
|
|
28
42
|
|
|
@@ -47,7 +61,7 @@ type MenuActionsContextValue = {
|
|
|
47
61
|
|
|
48
62
|
type MenuAlign = NonNullable<DropdownMenuContentProps["align"]>;
|
|
49
63
|
|
|
50
|
-
type MenuPosition = { top: number; left: number };
|
|
64
|
+
type MenuPosition = { top: number; left: number; triggerTop: number; bottomLimit: number };
|
|
51
65
|
|
|
52
66
|
type TriggerPosition = NonNullable<
|
|
53
67
|
ReturnType<typeof DropdownMenuPrimitive.useRootContext>["triggerPosition"]
|
|
@@ -91,6 +105,13 @@ function DropdownMenu({ children, ...props }: DropdownMenuProps) {
|
|
|
91
105
|
);
|
|
92
106
|
}
|
|
93
107
|
|
|
108
|
+
const TRIGGER_MIN_SIZE: ViewStyle = {
|
|
109
|
+
minWidth: 32,
|
|
110
|
+
minHeight: 32,
|
|
111
|
+
alignItems: "center",
|
|
112
|
+
justifyContent: "center",
|
|
113
|
+
};
|
|
114
|
+
|
|
94
115
|
const DropdownMenuTrigger = forwardRef<
|
|
95
116
|
DropdownMenuPrimitive.TriggerRef,
|
|
96
117
|
DropdownMenuTriggerProps
|
|
@@ -102,15 +123,11 @@ const DropdownMenuTrigger = forwardRef<
|
|
|
102
123
|
accessibilityRole="button"
|
|
103
124
|
hitSlop={6}
|
|
104
125
|
className={cn("items-center justify-center", className)}
|
|
105
|
-
style={
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
justifyContent: "center",
|
|
111
|
-
},
|
|
112
|
-
typeof style === "function" ? style(state) : style,
|
|
113
|
-
]}
|
|
126
|
+
style={
|
|
127
|
+
typeof style === "function"
|
|
128
|
+
? (state: PressableStateCallbackType) => [TRIGGER_MIN_SIZE, style(state)]
|
|
129
|
+
: [TRIGGER_MIN_SIZE, style]
|
|
130
|
+
}
|
|
114
131
|
{...props}
|
|
115
132
|
>
|
|
116
133
|
{children}
|
|
@@ -142,12 +159,22 @@ function computeMenuPosition({
|
|
|
142
159
|
const rawLeft = triggerPosition.pageX + alignOffset[align] - hostOrigin.x;
|
|
143
160
|
const maxLeft = windowWidth - hostOrigin.x - MENU_WIDTH - MENU_EDGE_GAP;
|
|
144
161
|
|
|
162
|
+
const triggerTop = triggerPosition.pageY - hostOrigin.y;
|
|
163
|
+
|
|
145
164
|
return {
|
|
146
165
|
left: Math.max(MENU_EDGE_GAP, Math.min(rawLeft, maxLeft)),
|
|
147
|
-
top:
|
|
166
|
+
top: triggerTop + triggerPosition.height + sideOffset,
|
|
167
|
+
triggerTop,
|
|
168
|
+
bottomLimit: hostOrigin.height - MENU_EDGE_GAP,
|
|
148
169
|
};
|
|
149
170
|
}
|
|
150
171
|
|
|
172
|
+
function resolveMenuTop(position: MenuPosition, menuHeight: number, sideOffset: number) {
|
|
173
|
+
if (position.top + menuHeight <= position.bottomLimit) return position.top;
|
|
174
|
+
|
|
175
|
+
return Math.max(MENU_EDGE_GAP, position.triggerTop - sideOffset - menuHeight);
|
|
176
|
+
}
|
|
177
|
+
|
|
151
178
|
function DropdownMenuContent({
|
|
152
179
|
className,
|
|
153
180
|
align = "end",
|
|
@@ -160,6 +187,8 @@ function DropdownMenuContent({
|
|
|
160
187
|
const { close } = useMenuActions();
|
|
161
188
|
const { open, triggerPosition } = DropdownMenuPrimitive.useRootContext();
|
|
162
189
|
const [menuPosition, setMenuPosition] = useState<MenuPosition | null>(null);
|
|
190
|
+
const [menuHeight, setMenuHeight] = useState<number | null>(null);
|
|
191
|
+
const isMenuMounted = menuPosition !== null;
|
|
163
192
|
const surfaceColor = useThemeColor("surface-elevated");
|
|
164
193
|
const borderColor = useThemeColor("gray-stroke-muted");
|
|
165
194
|
const backdropColor = useThemeColor("black-48");
|
|
@@ -167,6 +196,7 @@ function DropdownMenuContent({
|
|
|
167
196
|
useEffect(() => {
|
|
168
197
|
if (!open || !triggerPosition) {
|
|
169
198
|
setMenuPosition(null);
|
|
199
|
+
setMenuHeight(null);
|
|
170
200
|
return;
|
|
171
201
|
}
|
|
172
202
|
|
|
@@ -208,13 +238,18 @@ function DropdownMenuContent({
|
|
|
208
238
|
style={[
|
|
209
239
|
styles.menu,
|
|
210
240
|
{
|
|
211
|
-
top:
|
|
241
|
+
top:
|
|
242
|
+
menuHeight === null
|
|
243
|
+
? menuPosition.top
|
|
244
|
+
: resolveMenuTop(menuPosition, menuHeight, sideOffset),
|
|
212
245
|
left: menuPosition.left,
|
|
213
246
|
width: MENU_WIDTH,
|
|
214
247
|
backgroundColor: surfaceColor,
|
|
215
248
|
borderColor,
|
|
249
|
+
opacity: menuHeight === null ? 0 : 1,
|
|
216
250
|
},
|
|
217
251
|
]}
|
|
252
|
+
onLayout={(event) => setMenuHeight(event.nativeEvent.layout.height)}
|
|
218
253
|
>
|
|
219
254
|
{children}
|
|
220
255
|
</View>
|
|
@@ -228,12 +263,25 @@ function DropdownMenuContent({
|
|
|
228
263
|
className,
|
|
229
264
|
close,
|
|
230
265
|
id,
|
|
266
|
+
menuHeight,
|
|
231
267
|
menuPosition,
|
|
232
268
|
overlay,
|
|
233
269
|
showOverlay,
|
|
270
|
+
sideOffset,
|
|
234
271
|
surfaceColor,
|
|
235
272
|
]);
|
|
236
273
|
|
|
274
|
+
useEffect(() => {
|
|
275
|
+
if (!isMenuMounted) return;
|
|
276
|
+
|
|
277
|
+
const subscription = BackHandler.addEventListener("hardwareBackPress", () => {
|
|
278
|
+
close();
|
|
279
|
+
return true;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return () => subscription.remove();
|
|
283
|
+
}, [close, isMenuMounted]);
|
|
284
|
+
|
|
237
285
|
useEffect(() => () => overlay.unmount(id), [id, overlay]);
|
|
238
286
|
|
|
239
287
|
return null;
|
|
@@ -17,9 +17,9 @@ type EmptyStateVariant = "regular" | "emphasis" | "success" | "warning" | "error
|
|
|
17
17
|
const ICON_BACKGROUND_BY_VARIANT: Record<EmptyStateVariant, string> = {
|
|
18
18
|
regular: "bg-gray-background-soft",
|
|
19
19
|
emphasis: "bg-secondary-background-soft",
|
|
20
|
-
success: "bg-
|
|
21
|
-
warning: "bg-
|
|
22
|
-
error: "bg-
|
|
20
|
+
success: "bg-feedback-success-background-soft",
|
|
21
|
+
warning: "bg-feedback-warning-background-soft",
|
|
22
|
+
error: "bg-feedback-error-background-soft",
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
function EmptyState({
|