@medway-ui/native 1.1.2 → 1.3.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/lib/commonjs/components/Alert.js +5 -4
- package/lib/commonjs/components/Alert.js.map +1 -1
- package/lib/commonjs/components/Avatar.js +2 -1
- package/lib/commonjs/components/Avatar.js.map +1 -1
- package/lib/commonjs/components/Badge.js +2 -1
- package/lib/commonjs/components/Badge.js.map +1 -1
- package/lib/commonjs/components/Button.js +3 -2
- package/lib/commonjs/components/Button.js.map +1 -1
- package/lib/commonjs/components/CardNews.js +7 -6
- package/lib/commonjs/components/CardNews.js.map +1 -1
- package/lib/commonjs/components/Carousel.js +122 -0
- package/lib/commonjs/components/Carousel.js.map +1 -0
- package/lib/commonjs/components/Checkbox.js +11 -2
- package/lib/commonjs/components/Checkbox.js.map +1 -1
- package/lib/commonjs/components/DropdownMenu.js +225 -0
- package/lib/commonjs/components/DropdownMenu.js.map +1 -0
- package/lib/commonjs/components/EmptyState.js +19 -20
- package/lib/commonjs/components/EmptyState.js.map +1 -1
- package/lib/commonjs/components/Feed.js +82 -0
- package/lib/commonjs/components/Feed.js.map +1 -0
- package/lib/commonjs/components/FeedNotice.js +76 -0
- package/lib/commonjs/components/FeedNotice.js.map +1 -0
- package/lib/commonjs/components/Input.js +21 -9
- package/lib/commonjs/components/Input.js.map +1 -1
- package/lib/commonjs/components/InvitePopover.js +196 -0
- package/lib/commonjs/components/InvitePopover.js.map +1 -0
- package/lib/commonjs/components/Label.js +2 -1
- package/lib/commonjs/components/Label.js.map +1 -1
- package/lib/commonjs/components/LeaderboardCard.js +58 -0
- package/lib/commonjs/components/LeaderboardCard.js.map +1 -0
- package/lib/commonjs/components/MemberRow.js +131 -0
- package/lib/commonjs/components/MemberRow.js.map +1 -0
- package/lib/commonjs/components/PageHeader.js +3 -2
- package/lib/commonjs/components/PageHeader.js.map +1 -1
- package/lib/commonjs/components/PostForm.js +182 -0
- package/lib/commonjs/components/PostForm.js.map +1 -0
- package/lib/commonjs/components/PrizeCollection.js +135 -0
- package/lib/commonjs/components/PrizeCollection.js.map +1 -0
- package/lib/commonjs/components/RadioGroup.js +22 -0
- package/lib/commonjs/components/RadioGroup.js.map +1 -1
- package/lib/commonjs/components/SectionHeader.js +36 -0
- package/lib/commonjs/components/SectionHeader.js.map +1 -0
- package/lib/commonjs/components/Switch.js +33 -19
- package/lib/commonjs/components/Switch.js.map +1 -1
- package/lib/commonjs/components/Tabs.js +156 -0
- package/lib/commonjs/components/Tabs.js.map +1 -0
- package/lib/commonjs/components/Tag.js +2 -1
- package/lib/commonjs/components/Tag.js.map +1 -1
- package/lib/commonjs/components/Text.js +60 -0
- package/lib/commonjs/components/Text.js.map +1 -0
- package/lib/commonjs/components/Toast.js +3 -2
- package/lib/commonjs/components/Toast.js.map +1 -1
- package/lib/commonjs/components/Tooltip.js +2 -2
- package/lib/commonjs/components/Tooltip.js.map +1 -1
- package/lib/commonjs/editor/NoteEditor.js +710 -0
- package/lib/commonjs/editor/NoteEditor.js.map +1 -0
- package/lib/commonjs/editor/editorHtml.generated.js +21 -0
- package/lib/commonjs/editor/editorHtml.generated.js.map +1 -0
- package/lib/commonjs/editor/index.js +33 -0
- package/lib/commonjs/editor/index.js.map +1 -0
- package/lib/commonjs/editor/protocol.js +88 -0
- package/lib/commonjs/editor/protocol.js.map +1 -0
- package/lib/commonjs/hooks/useThemeColor.js +66 -29
- package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
- package/lib/commonjs/index.js +319 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/lib/overlay-host.js +101 -0
- package/lib/commonjs/lib/overlay-host.js.map +1 -0
- package/lib/commonjs/lib/typography.js +26 -0
- package/lib/commonjs/lib/typography.js.map +1 -0
- package/lib/commonjs/nativewind-env.d.js +0 -1
- package/lib/commonjs/nativewind-env.d.js.map +1 -1
- package/lib/module/components/Alert.js +3 -2
- package/lib/module/components/Alert.js.map +1 -1
- package/lib/module/components/Avatar.js +2 -1
- package/lib/module/components/Avatar.js.map +1 -1
- package/lib/module/components/Badge.js +2 -1
- package/lib/module/components/Badge.js.map +1 -1
- package/lib/module/components/Button.js +2 -1
- package/lib/module/components/Button.js.map +1 -1
- package/lib/module/components/CardNews.js +2 -1
- package/lib/module/components/CardNews.js.map +1 -1
- package/lib/module/components/Carousel.js +117 -0
- package/lib/module/components/Carousel.js.map +1 -0
- package/lib/module/components/Checkbox.js +12 -2
- package/lib/module/components/Checkbox.js.map +1 -1
- package/lib/module/components/DropdownMenu.js +216 -0
- package/lib/module/components/DropdownMenu.js.map +1 -0
- package/lib/module/components/EmptyState.js +19 -20
- package/lib/module/components/EmptyState.js.map +1 -1
- package/lib/module/components/Feed.js +77 -0
- package/lib/module/components/Feed.js.map +1 -0
- package/lib/module/components/FeedNotice.js +73 -0
- package/lib/module/components/FeedNotice.js.map +1 -0
- package/lib/module/components/Input.js +21 -9
- package/lib/module/components/Input.js.map +1 -1
- package/lib/module/components/InvitePopover.js +183 -0
- package/lib/module/components/InvitePopover.js.map +1 -0
- package/lib/module/components/Label.js +2 -1
- package/lib/module/components/Label.js.map +1 -1
- package/lib/module/components/LeaderboardCard.js +53 -0
- package/lib/module/components/LeaderboardCard.js.map +1 -0
- package/lib/module/components/MemberRow.js +127 -0
- package/lib/module/components/MemberRow.js.map +1 -0
- package/lib/module/components/PageHeader.js +2 -1
- package/lib/module/components/PageHeader.js.map +1 -1
- package/lib/module/components/PostForm.js +174 -0
- package/lib/module/components/PostForm.js.map +1 -0
- package/lib/module/components/PrizeCollection.js +127 -0
- package/lib/module/components/PrizeCollection.js.map +1 -0
- package/lib/module/components/RadioGroup.js +21 -1
- package/lib/module/components/RadioGroup.js.map +1 -1
- package/lib/module/components/SectionHeader.js +33 -0
- package/lib/module/components/SectionHeader.js.map +1 -0
- package/lib/module/components/Switch.js +34 -20
- package/lib/module/components/Switch.js.map +1 -1
- package/lib/module/components/Tabs.js +148 -0
- package/lib/module/components/Tabs.js.map +1 -0
- package/lib/module/components/Tag.js +2 -1
- package/lib/module/components/Tag.js.map +1 -1
- package/lib/module/components/Text.js +58 -0
- package/lib/module/components/Text.js.map +1 -0
- package/lib/module/components/Toast.js +2 -1
- package/lib/module/components/Toast.js.map +1 -1
- package/lib/module/components/Tooltip.js +1 -1
- package/lib/module/components/Tooltip.js.map +1 -1
- package/lib/module/editor/NoteEditor.js +705 -0
- package/lib/module/editor/NoteEditor.js.map +1 -0
- package/lib/module/editor/editorHtml.generated.js +17 -0
- package/lib/module/editor/editorHtml.generated.js.map +1 -0
- package/lib/module/editor/index.js +5 -0
- package/lib/module/editor/index.js.map +1 -0
- package/lib/module/editor/protocol.js +83 -0
- package/lib/module/editor/protocol.js.map +1 -0
- package/lib/module/hooks/useThemeColor.js +66 -31
- package/lib/module/hooks/useThemeColor.js.map +1 -1
- package/lib/module/index.js +33 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/overlay-host.js +96 -0
- package/lib/module/lib/overlay-host.js.map +1 -0
- package/lib/module/lib/typography.js +22 -0
- package/lib/module/lib/typography.js.map +1 -0
- package/lib/module/nativewind-env.d.js +0 -1
- package/lib/module/nativewind-env.d.js.map +1 -1
- package/lib/typescript/components/Alert.d.ts.map +1 -1
- package/lib/typescript/components/Avatar.d.ts.map +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/CardNews.d.ts.map +1 -1
- package/lib/typescript/components/Carousel.d.ts +29 -0
- package/lib/typescript/components/Carousel.d.ts.map +1 -0
- package/lib/typescript/components/Checkbox.d.ts.map +1 -1
- package/lib/typescript/components/DropdownMenu.d.ts +39 -0
- package/lib/typescript/components/DropdownMenu.d.ts.map +1 -0
- package/lib/typescript/components/EmptyState.d.ts +1 -1
- package/lib/typescript/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/components/Feed.d.ts +22 -0
- package/lib/typescript/components/Feed.d.ts.map +1 -0
- package/lib/typescript/components/FeedNotice.d.ts +17 -0
- package/lib/typescript/components/FeedNotice.d.ts.map +1 -0
- package/lib/typescript/components/Input.d.ts +3 -2
- package/lib/typescript/components/Input.d.ts.map +1 -1
- package/lib/typescript/components/InvitePopover.d.ts +46 -0
- package/lib/typescript/components/InvitePopover.d.ts.map +1 -0
- package/lib/typescript/components/Label.d.ts.map +1 -1
- package/lib/typescript/components/LeaderboardCard.d.ts +16 -0
- package/lib/typescript/components/LeaderboardCard.d.ts.map +1 -0
- package/lib/typescript/components/MemberRow.d.ts +40 -0
- package/lib/typescript/components/MemberRow.d.ts.map +1 -0
- package/lib/typescript/components/PageHeader.d.ts.map +1 -1
- package/lib/typescript/components/PostForm.d.ts +50 -0
- package/lib/typescript/components/PostForm.d.ts.map +1 -0
- package/lib/typescript/components/PrizeCollection.d.ts +35 -0
- package/lib/typescript/components/PrizeCollection.d.ts.map +1 -0
- package/lib/typescript/components/RadioGroup.d.ts +10 -2
- package/lib/typescript/components/RadioGroup.d.ts.map +1 -1
- package/lib/typescript/components/SectionHeader.d.ts +12 -0
- package/lib/typescript/components/SectionHeader.d.ts.map +1 -0
- package/lib/typescript/components/Switch.d.ts.map +1 -1
- package/lib/typescript/components/Tabs.d.ts +32 -0
- package/lib/typescript/components/Tabs.d.ts.map +1 -0
- package/lib/typescript/components/Tag.d.ts.map +1 -1
- package/lib/typescript/components/Text.d.ts +23 -0
- package/lib/typescript/components/Text.d.ts.map +1 -0
- package/lib/typescript/components/Toast.d.ts +1 -1
- package/lib/typescript/components/Toast.d.ts.map +1 -1
- package/lib/typescript/components/Tooltip.d.ts.map +1 -1
- package/lib/typescript/editor/NoteEditor.d.ts +82 -0
- package/lib/typescript/editor/NoteEditor.d.ts.map +1 -0
- package/lib/typescript/editor/editorHtml.generated.d.ts +13 -0
- package/lib/typescript/editor/editorHtml.generated.d.ts.map +1 -0
- package/lib/typescript/editor/index.d.ts +6 -0
- package/lib/typescript/editor/index.d.ts.map +1 -0
- package/lib/typescript/editor/protocol.d.ts +153 -0
- package/lib/typescript/editor/protocol.d.ts.map +1 -0
- package/lib/typescript/hooks/useThemeColor.d.ts +4 -2
- package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +28 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/lib/overlay-host.d.ts +23 -0
- package/lib/typescript/lib/overlay-host.d.ts.map +1 -0
- package/lib/typescript/lib/typography.d.ts +12 -0
- package/lib/typescript/lib/typography.d.ts.map +1 -0
- package/package.json +36 -3
- package/setup/MedwayUiProvider.tsx +15 -3
- package/setup/metro.js +27 -5
- package/setup/tailwind.js +52 -4
- package/setup/tokens.native.css +8 -3
- package/src/components/Alert.tsx +4 -2
- package/src/components/Avatar.tsx +3 -1
- package/src/components/Badge.tsx +3 -1
- package/src/components/Button.tsx +3 -7
- package/src/components/CardNews.tsx +2 -1
- package/src/components/Carousel.tsx +152 -0
- package/src/components/Checkbox.tsx +14 -4
- package/src/components/DropdownMenu.tsx +312 -0
- package/src/components/EmptyState.tsx +21 -23
- package/src/components/Feed.tsx +96 -0
- package/src/components/FeedNotice.tsx +112 -0
- package/src/components/Input.tsx +11 -6
- package/src/components/InvitePopover.tsx +240 -0
- package/src/components/Label.tsx +3 -1
- package/src/components/LeaderboardCard.tsx +70 -0
- package/src/components/MemberRow.tsx +157 -0
- package/src/components/PageHeader.tsx +3 -1
- package/src/components/PostForm.tsx +250 -0
- package/src/components/PrizeCollection.tsx +190 -0
- package/src/components/RadioGroup.tsx +32 -3
- package/src/components/SectionHeader.tsx +45 -0
- package/src/components/Switch.tsx +65 -59
- package/src/components/Tabs.tsx +182 -0
- package/src/components/Tag.tsx +3 -1
- package/src/components/Text.tsx +66 -0
- package/src/components/Toast.tsx +3 -1
- package/src/components/Tooltip.tsx +2 -1
- package/src/editor/NoteEditor.tsx +802 -0
- package/src/editor/editorHtml.generated.ts +14 -0
- package/src/editor/index.ts +13 -0
- package/src/editor/protocol.ts +184 -0
- package/src/hooks/useThemeColor.ts +77 -32
- package/src/index.ts +153 -6
- package/src/lib/overlay-host.tsx +102 -0
- package/src/lib/typography.ts +21 -0
- package/src/nativewind-env.d.ts +2 -0
package/setup/tailwind.js
CHANGED
|
@@ -23,6 +23,47 @@ function resolveNativePackageRoot() {
|
|
|
23
23
|
return path.resolve(__dirname, '..');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* React Native registers Montserrat as separate family names per weight
|
|
28
|
+
* (MontserratMedium, MontserratSemiBold, …). Numeric fontWeight + "Montserrat"
|
|
29
|
+
* does not resolve the file, so weight utilities must set fontFamily instead.
|
|
30
|
+
* Keys stay aligned with Medway UI tokens (`regular` | `medium` | `semibold` | …).
|
|
31
|
+
*/
|
|
32
|
+
const NATIVE_MONTSERRAT_BY_WEIGHT = {
|
|
33
|
+
thin: 'MontserratLight',
|
|
34
|
+
extralight: 'MontserratLight',
|
|
35
|
+
light: 'MontserratLight',
|
|
36
|
+
normal: 'Montserrat',
|
|
37
|
+
regular: 'Montserrat',
|
|
38
|
+
medium: 'MontserratMedium',
|
|
39
|
+
semibold: 'MontserratSemiBold',
|
|
40
|
+
bold: 'MontserratBold',
|
|
41
|
+
extrabold: 'MontserratExtraBold',
|
|
42
|
+
black: 'MontserratBlack',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function createNativeMontserratFontPlugin() {
|
|
46
|
+
// Lazy-require so greenfield web tooling can still import this file if needed.
|
|
47
|
+
const plugin = require('tailwindcss/plugin');
|
|
48
|
+
|
|
49
|
+
return plugin(({ addBase, addUtilities }) => {
|
|
50
|
+
addBase({
|
|
51
|
+
'*': {
|
|
52
|
+
fontFamily: 'Montserrat',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
addUtilities(
|
|
57
|
+
Object.fromEntries(
|
|
58
|
+
Object.entries(NATIVE_MONTSERRAT_BY_WEIGHT).map(([weight, fontFamily]) => [
|
|
59
|
+
`.font-${weight}`,
|
|
60
|
+
{ fontFamily },
|
|
61
|
+
]),
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
26
67
|
/**
|
|
27
68
|
* Tailwind config para apps com @medway-ui/native.
|
|
28
69
|
*
|
|
@@ -38,7 +79,6 @@ function createMedwayUiTailwindConfig(options = {}) {
|
|
|
38
79
|
colors,
|
|
39
80
|
fontFamily,
|
|
40
81
|
fontSize,
|
|
41
|
-
fontWeight,
|
|
42
82
|
lineHeight,
|
|
43
83
|
borderRadius,
|
|
44
84
|
boxShadow,
|
|
@@ -68,17 +108,25 @@ function createMedwayUiTailwindConfig(options = {}) {
|
|
|
68
108
|
darkMode: 'class',
|
|
69
109
|
presets: [require('nativewind/preset')],
|
|
70
110
|
theme: {
|
|
111
|
+
// Disable numeric font-weight utilities; RN needs fontFamily per weight.
|
|
112
|
+
fontWeight: {},
|
|
71
113
|
extend: {
|
|
72
114
|
colors,
|
|
73
|
-
fontFamily
|
|
115
|
+
fontFamily: {
|
|
116
|
+
...fontFamily,
|
|
117
|
+
sans: ['Montserrat'],
|
|
118
|
+
},
|
|
74
119
|
fontSize,
|
|
75
|
-
fontWeight,
|
|
76
120
|
lineHeight,
|
|
77
121
|
borderRadius,
|
|
78
122
|
boxShadow,
|
|
79
123
|
},
|
|
80
124
|
},
|
|
125
|
+
plugins: [createNativeMontserratFontPlugin()],
|
|
81
126
|
};
|
|
82
127
|
}
|
|
83
128
|
|
|
84
|
-
module.exports = {
|
|
129
|
+
module.exports = {
|
|
130
|
+
createMedwayUiTailwindConfig,
|
|
131
|
+
NATIVE_MONTSERRAT_BY_WEIGHT,
|
|
132
|
+
};
|
package/setup/tokens.native.css
CHANGED
|
@@ -545,11 +545,15 @@
|
|
|
545
545
|
--color-gradient-pt-bg-2: var(--color-gray-450);
|
|
546
546
|
|
|
547
547
|
/* === Typography fontfamily === */
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
548
|
+
/* RN: single family name (loaded via expo-font as "Montserrat"). */
|
|
549
|
+
--font-sans: Montserrat;
|
|
551
550
|
|
|
552
551
|
/* === Typography weight === */
|
|
552
|
+
/*
|
|
553
|
+
* Token keys stay the same as web. On native, Tailwind maps these class
|
|
554
|
+
* names (font-medium, font-semibold, …) to Montserrat* fontFamily files
|
|
555
|
+
* in setup/tailwind.js — numeric fontWeight is not used for RN text.
|
|
556
|
+
*/
|
|
553
557
|
--font-weight-regular: 400;
|
|
554
558
|
--font-weight-medium: 500;
|
|
555
559
|
--font-weight-semibold: 600;
|
|
@@ -615,6 +619,7 @@
|
|
|
615
619
|
--sidebar-width-mobile: 256px;
|
|
616
620
|
--sidebar-width-icon: 72px;
|
|
617
621
|
}
|
|
622
|
+
|
|
618
623
|
.dark {
|
|
619
624
|
/* === Dark base colors === */
|
|
620
625
|
--color-background: var(--color-gray-850);
|
package/src/components/Alert.tsx
CHANGED
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
useMemo,
|
|
5
5
|
type ReactNode,
|
|
6
6
|
} from "react";
|
|
7
|
-
import { View,
|
|
7
|
+
import { View, Pressable, type ViewProps, type PressableProps } from "react-native";
|
|
8
|
+
|
|
9
|
+
import { Text } from "@/components/Text";
|
|
8
10
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
9
11
|
import { CloseMd } from "@medway-ui/icons/native";
|
|
10
12
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
@@ -141,7 +143,7 @@ function AlertDescription({ className, children, ...props }: ViewProps & { child
|
|
|
141
143
|
<View className={cn("", className)} {...props}>
|
|
142
144
|
<Text
|
|
143
145
|
numberOfLines={3}
|
|
144
|
-
className={cn("text-sm leading-5", alertTextColorVariants({ variant }))}
|
|
146
|
+
className={cn("text-sm font-medium leading-5", alertTextColorVariants({ variant }))}
|
|
145
147
|
>
|
|
146
148
|
{children}
|
|
147
149
|
</Text>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { View,
|
|
2
|
+
import { View, type ViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
3
5
|
import * as AvatarPrimitive from "@rn-primitives/avatar";
|
|
4
6
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
7
|
import { User } from "@medway-ui/icons/native";
|
package/src/components/Badge.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { View,
|
|
2
|
+
import { View, type ViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
3
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
6
|
import { cn } from "@/lib/utils";
|
|
5
7
|
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Text,
|
|
6
|
-
type PressableProps,
|
|
7
|
-
type ViewStyle,
|
|
8
|
-
} from "react-native";
|
|
2
|
+
import { Pressable, View, type PressableProps, type ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
9
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
10
6
|
import { cn } from "@/lib/utils";
|
|
11
7
|
import { Loading } from "@/components/Loading";
|
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
} from "react";
|
|
9
9
|
import {
|
|
10
10
|
Image,
|
|
11
|
-
Text,
|
|
12
11
|
View,
|
|
13
12
|
useWindowDimensions,
|
|
14
13
|
type ImageProps,
|
|
15
14
|
type ViewProps,
|
|
16
15
|
} from "react-native";
|
|
17
16
|
|
|
17
|
+
import { Text } from "@/components/Text";
|
|
18
|
+
|
|
18
19
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/Avatar";
|
|
19
20
|
import { Button, type ButtonProps } from "@/components/Button";
|
|
20
21
|
import { FallbackImage } from "@/components/FallbackImage";
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { Image, Pressable, View, type ViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
5
|
+
import { ChevronLeftMd, ChevronRightMd } from "@medway-ui/icons/native";
|
|
6
|
+
|
|
7
|
+
import { Button } from "@/components/Button";
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
|
|
10
|
+
interface CarouselProps extends ViewProps {
|
|
11
|
+
slideIndex?: number;
|
|
12
|
+
slideCount?: number;
|
|
13
|
+
onPrevious?: () => void;
|
|
14
|
+
onNext?: () => void;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface CarouselMediaSlideProps extends ViewProps {
|
|
19
|
+
imageSrc?: string;
|
|
20
|
+
image?: ReactNode;
|
|
21
|
+
label: string;
|
|
22
|
+
title: string;
|
|
23
|
+
linkLabel?: string;
|
|
24
|
+
onLinkPress?: () => void;
|
|
25
|
+
linkIcon?: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface CarouselMetricSlideProps extends ViewProps {
|
|
29
|
+
icon?: ReactNode;
|
|
30
|
+
value: string;
|
|
31
|
+
description: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Carousel({
|
|
35
|
+
className,
|
|
36
|
+
children,
|
|
37
|
+
onPrevious,
|
|
38
|
+
onNext,
|
|
39
|
+
...props
|
|
40
|
+
}: CarouselProps) {
|
|
41
|
+
return (
|
|
42
|
+
<View
|
|
43
|
+
className={cn(
|
|
44
|
+
"h-[284px] flex-row items-center justify-between px-6",
|
|
45
|
+
className
|
|
46
|
+
)}
|
|
47
|
+
{...props}
|
|
48
|
+
>
|
|
49
|
+
<Button
|
|
50
|
+
variant="regular-soft"
|
|
51
|
+
size="md"
|
|
52
|
+
className="size-10 min-h-10 min-w-10 max-w-10 p-0"
|
|
53
|
+
iconLeft={<ChevronLeftMd width={20} height={20} color="#00205B" />}
|
|
54
|
+
onPress={onPrevious}
|
|
55
|
+
accessibilityLabel="Slide anterior"
|
|
56
|
+
/>
|
|
57
|
+
<View className="h-full min-w-0 flex-1 items-center justify-center px-4">
|
|
58
|
+
{children}
|
|
59
|
+
</View>
|
|
60
|
+
<Button
|
|
61
|
+
variant="regular-soft"
|
|
62
|
+
size="md"
|
|
63
|
+
className="size-10 min-h-10 min-w-10 max-w-10 p-0"
|
|
64
|
+
iconLeft={<ChevronRightMd width={20} height={20} color="#00205B" />}
|
|
65
|
+
onPress={onNext}
|
|
66
|
+
accessibilityLabel="Próximo slide"
|
|
67
|
+
/>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function CarouselMediaSlide({
|
|
73
|
+
className,
|
|
74
|
+
imageSrc,
|
|
75
|
+
image,
|
|
76
|
+
label,
|
|
77
|
+
title,
|
|
78
|
+
linkLabel = "Ver coleção",
|
|
79
|
+
onLinkPress,
|
|
80
|
+
linkIcon,
|
|
81
|
+
...props
|
|
82
|
+
}: CarouselMediaSlideProps) {
|
|
83
|
+
return (
|
|
84
|
+
<View className={cn("items-center gap-2", className)} {...props}>
|
|
85
|
+
{image ??
|
|
86
|
+
(imageSrc ? (
|
|
87
|
+
<Image
|
|
88
|
+
source={{ uri: imageSrc }}
|
|
89
|
+
accessibilityLabel={title}
|
|
90
|
+
className="h-[188px] w-[161px]"
|
|
91
|
+
resizeMode="contain"
|
|
92
|
+
/>
|
|
93
|
+
) : null)}
|
|
94
|
+
<View className="items-center gap-2">
|
|
95
|
+
<View className="items-center">
|
|
96
|
+
<Text className="text-sm font-medium text-primary-foreground">
|
|
97
|
+
{label}
|
|
98
|
+
</Text>
|
|
99
|
+
<Text className="text-center text-title-xs font-semibold text-primary-foreground">
|
|
100
|
+
{title}
|
|
101
|
+
</Text>
|
|
102
|
+
</View>
|
|
103
|
+
{linkLabel ? (
|
|
104
|
+
<Pressable
|
|
105
|
+
accessibilityRole="link"
|
|
106
|
+
className="flex-row items-center gap-1"
|
|
107
|
+
onPress={onLinkPress}
|
|
108
|
+
>
|
|
109
|
+
<Text className="text-xs font-semibold text-secondary-stroke-emphasis">
|
|
110
|
+
{linkLabel}
|
|
111
|
+
</Text>
|
|
112
|
+
{linkIcon}
|
|
113
|
+
</Pressable>
|
|
114
|
+
) : null}
|
|
115
|
+
</View>
|
|
116
|
+
</View>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function CarouselMetricSlide({
|
|
121
|
+
className,
|
|
122
|
+
icon,
|
|
123
|
+
value,
|
|
124
|
+
description,
|
|
125
|
+
...props
|
|
126
|
+
}: CarouselMetricSlideProps) {
|
|
127
|
+
return (
|
|
128
|
+
<View
|
|
129
|
+
className={cn("max-w-[242px] items-center gap-3", className)}
|
|
130
|
+
{...props}
|
|
131
|
+
>
|
|
132
|
+
{icon ? (
|
|
133
|
+
<View className="items-center justify-center">{icon}</View>
|
|
134
|
+
) : null}
|
|
135
|
+
<View className="w-full items-center gap-3">
|
|
136
|
+
<Text className="text-center text-[32px] font-bold leading-10 text-primary-foreground">
|
|
137
|
+
{value}
|
|
138
|
+
</Text>
|
|
139
|
+
<Text className="text-center text-sm font-semibold leading-sm text-primary-foreground">
|
|
140
|
+
{description}
|
|
141
|
+
</Text>
|
|
142
|
+
</View>
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export { Carousel, CarouselMediaSlide, CarouselMetricSlide };
|
|
148
|
+
export type {
|
|
149
|
+
CarouselMediaSlideProps,
|
|
150
|
+
CarouselMetricSlideProps,
|
|
151
|
+
CarouselProps,
|
|
152
|
+
};
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { useState, type ReactNode } from "react";
|
|
2
2
|
import { type ViewStyle } from "react-native";
|
|
3
|
+
import { cssInterop } from "nativewind";
|
|
3
4
|
import * as CheckboxPrimitive from "@rn-primitives/checkbox";
|
|
4
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
6
|
import { cn } from "@/lib/utils";
|
|
6
7
|
import { Check, RemoveMinus } from "@medway-ui/icons/native";
|
|
7
8
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
8
9
|
|
|
10
|
+
// `@rn-primitives/checkbox` renders plain React Native primitives with no
|
|
11
|
+
// NativeWind support, so `className` is otherwise silently ignored.
|
|
12
|
+
const StyledCheckboxRoot = cssInterop(CheckboxPrimitive.Root, {
|
|
13
|
+
className: "style",
|
|
14
|
+
});
|
|
15
|
+
const StyledCheckboxIndicator = cssInterop(CheckboxPrimitive.Indicator, {
|
|
16
|
+
className: "style",
|
|
17
|
+
});
|
|
18
|
+
|
|
9
19
|
interface CheckboxProps
|
|
10
20
|
extends Omit<
|
|
11
21
|
CheckboxPrimitive.RootProps,
|
|
@@ -99,7 +109,7 @@ function Checkbox({
|
|
|
99
109
|
};
|
|
100
110
|
|
|
101
111
|
return (
|
|
102
|
-
<
|
|
112
|
+
<StyledCheckboxRoot
|
|
103
113
|
checked={isChecked}
|
|
104
114
|
onCheckedChange={handleCheckedChange}
|
|
105
115
|
disabled={disabled}
|
|
@@ -118,15 +128,15 @@ function Checkbox({
|
|
|
118
128
|
)}
|
|
119
129
|
{...props}
|
|
120
130
|
>
|
|
121
|
-
<
|
|
131
|
+
<StyledCheckboxIndicator className="items-center justify-center">
|
|
122
132
|
{iconColor && (uncheckIcon ? (
|
|
123
133
|
<RemoveMinus width={iconSize} height={iconSize} strokeWidth={2.6} color={iconColor} />
|
|
124
134
|
) : (
|
|
125
135
|
<Check width={iconSize} height={iconSize} strokeWidth={2.6} color={iconColor} />
|
|
126
136
|
))}
|
|
127
|
-
</
|
|
137
|
+
</StyledCheckboxIndicator>
|
|
128
138
|
{children}
|
|
129
|
-
</
|
|
139
|
+
</StyledCheckboxRoot>
|
|
130
140
|
);
|
|
131
141
|
}
|
|
132
142
|
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
forwardRef,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useId,
|
|
7
|
+
useMemo,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { Dimensions, Pressable, StyleSheet, View, type PressableProps, type ViewProps } from "react-native";
|
|
11
|
+
|
|
12
|
+
import { Text } from "@/components/Text";
|
|
13
|
+
import * as DropdownMenuPrimitive from "@rn-primitives/dropdown-menu";
|
|
14
|
+
|
|
15
|
+
import { useOverlayHost } from "@/lib/overlay-host";
|
|
16
|
+
import { cn } from "@/lib/utils";
|
|
17
|
+
|
|
18
|
+
interface DropdownMenuProps extends DropdownMenuPrimitive.RootProps {
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface DropdownMenuTriggerProps extends DropdownMenuPrimitive.TriggerProps {
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface DropdownMenuContentProps {
|
|
28
|
+
className?: string;
|
|
29
|
+
children?: ReactNode;
|
|
30
|
+
align?: "start" | "center" | "end";
|
|
31
|
+
sideOffset?: number;
|
|
32
|
+
/** Backdrop dim behind the menu. Defaults to true. */
|
|
33
|
+
overlay?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface DropdownMenuItemProps extends Omit<PressableProps, "children"> {
|
|
37
|
+
icon?: ReactNode;
|
|
38
|
+
children?: ReactNode;
|
|
39
|
+
className?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type MenuActionsContextValue = {
|
|
43
|
+
close: () => void;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const MenuActionsContext = createContext<MenuActionsContextValue | null>(null);
|
|
47
|
+
|
|
48
|
+
function useMenuActions() {
|
|
49
|
+
const ctx = useContext(MenuActionsContext);
|
|
50
|
+
if (!ctx) {
|
|
51
|
+
throw new Error("DropdownMenuItem must be used within DropdownMenu");
|
|
52
|
+
}
|
|
53
|
+
return ctx;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function MenuActionsBridge({ children }: { children: ReactNode }) {
|
|
57
|
+
const { onOpenChange, setTriggerPosition, setContentLayout } =
|
|
58
|
+
DropdownMenuPrimitive.useRootContext();
|
|
59
|
+
|
|
60
|
+
const value = useMemo<MenuActionsContextValue>(
|
|
61
|
+
() => ({
|
|
62
|
+
close: () => {
|
|
63
|
+
setTriggerPosition(null);
|
|
64
|
+
setContentLayout(null);
|
|
65
|
+
onOpenChange(false);
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
[onOpenChange, setContentLayout, setTriggerPosition]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<MenuActionsContext.Provider value={value}>{children}</MenuActionsContext.Provider>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function DropdownMenu({ children, ...props }: DropdownMenuProps) {
|
|
77
|
+
return (
|
|
78
|
+
<DropdownMenuPrimitive.Root {...props}>
|
|
79
|
+
<MenuActionsBridge>{children}</MenuActionsBridge>
|
|
80
|
+
</DropdownMenuPrimitive.Root>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const DropdownMenuTrigger = forwardRef<
|
|
85
|
+
DropdownMenuPrimitive.TriggerRef,
|
|
86
|
+
DropdownMenuTriggerProps
|
|
87
|
+
>(function DropdownMenuTrigger({ className, children, style, ...props }, ref) {
|
|
88
|
+
return (
|
|
89
|
+
<DropdownMenuPrimitive.Trigger
|
|
90
|
+
ref={ref}
|
|
91
|
+
collapsable={false}
|
|
92
|
+
accessibilityRole="button"
|
|
93
|
+
className={cn("items-center justify-center", className)}
|
|
94
|
+
style={(state) => [
|
|
95
|
+
{
|
|
96
|
+
minWidth: 32,
|
|
97
|
+
minHeight: 32,
|
|
98
|
+
alignItems: "center",
|
|
99
|
+
justifyContent: "center",
|
|
100
|
+
},
|
|
101
|
+
typeof style === "function" ? style(state) : style,
|
|
102
|
+
]}
|
|
103
|
+
{...props}
|
|
104
|
+
>
|
|
105
|
+
{children}
|
|
106
|
+
</DropdownMenuPrimitive.Trigger>
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Content renderizado no OverlayHost do MedwayUiProvider (acima da stack).
|
|
112
|
+
* Mantém Root/Trigger do @rn-primitives/dropdown-menu para open + measure.
|
|
113
|
+
*
|
|
114
|
+
* `triggerPosition` vem em coordenadas de janela (pageX/pageY). O OverlayHost
|
|
115
|
+
* fica abaixo do header da navegação, então subtraímos a origem do host.
|
|
116
|
+
*/
|
|
117
|
+
function DropdownMenuContent({
|
|
118
|
+
className,
|
|
119
|
+
align = "end",
|
|
120
|
+
sideOffset = 8,
|
|
121
|
+
overlay: showOverlay = true,
|
|
122
|
+
children,
|
|
123
|
+
}: DropdownMenuContentProps) {
|
|
124
|
+
const id = useId();
|
|
125
|
+
const overlay = useOverlayHost();
|
|
126
|
+
const { close } = useMenuActions();
|
|
127
|
+
const { open, triggerPosition } = DropdownMenuPrimitive.useRootContext();
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (!open || !triggerPosition) {
|
|
131
|
+
overlay.unmount(id);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let cancelled = false;
|
|
136
|
+
const menuWidth = 200;
|
|
137
|
+
const windowWidth = Dimensions.get("window").width;
|
|
138
|
+
|
|
139
|
+
overlay.measureHostOrigin((hostOrigin) => {
|
|
140
|
+
if (cancelled) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let left =
|
|
145
|
+
triggerPosition.pageX - hostOrigin.x;
|
|
146
|
+
|
|
147
|
+
if (align === "end") {
|
|
148
|
+
left =
|
|
149
|
+
triggerPosition.pageX +
|
|
150
|
+
triggerPosition.width -
|
|
151
|
+
menuWidth -
|
|
152
|
+
hostOrigin.x;
|
|
153
|
+
} else if (align === "center") {
|
|
154
|
+
left =
|
|
155
|
+
triggerPosition.pageX +
|
|
156
|
+
triggerPosition.width / 2 -
|
|
157
|
+
menuWidth / 2 -
|
|
158
|
+
hostOrigin.x;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
left = Math.max(8, Math.min(left, windowWidth - hostOrigin.x - menuWidth - 8));
|
|
162
|
+
|
|
163
|
+
const top =
|
|
164
|
+
triggerPosition.pageY +
|
|
165
|
+
triggerPosition.height +
|
|
166
|
+
sideOffset -
|
|
167
|
+
hostOrigin.y;
|
|
168
|
+
|
|
169
|
+
overlay.mount(
|
|
170
|
+
id,
|
|
171
|
+
<MenuActionsContext.Provider value={{ close }}>
|
|
172
|
+
<View style={styles.layer} pointerEvents="box-none">
|
|
173
|
+
<Pressable
|
|
174
|
+
accessibilityLabel="Fechar menu"
|
|
175
|
+
style={[
|
|
176
|
+
StyleSheet.absoluteFill,
|
|
177
|
+
showOverlay ? styles.backdrop : null,
|
|
178
|
+
]}
|
|
179
|
+
onPress={close}
|
|
180
|
+
/>
|
|
181
|
+
<View
|
|
182
|
+
className={cn(
|
|
183
|
+
"overflow-hidden rounded-md border border-gray-stroke-muted bg-surface-elevated p-1 shadow-md",
|
|
184
|
+
className
|
|
185
|
+
)}
|
|
186
|
+
// Fallback visual caso NativeWind não aplique no host de overlay
|
|
187
|
+
style={[
|
|
188
|
+
styles.menu,
|
|
189
|
+
{
|
|
190
|
+
top,
|
|
191
|
+
left,
|
|
192
|
+
width: menuWidth,
|
|
193
|
+
backgroundColor: "white",
|
|
194
|
+
borderRadius: 8,
|
|
195
|
+
borderWidth: 1,
|
|
196
|
+
borderColor: "#E7E9EF",
|
|
197
|
+
padding: 4,
|
|
198
|
+
},
|
|
199
|
+
]}
|
|
200
|
+
>
|
|
201
|
+
{children}
|
|
202
|
+
</View>
|
|
203
|
+
</View>
|
|
204
|
+
</MenuActionsContext.Provider>
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return () => {
|
|
209
|
+
cancelled = true;
|
|
210
|
+
overlay.unmount(id);
|
|
211
|
+
};
|
|
212
|
+
}, [
|
|
213
|
+
align,
|
|
214
|
+
children,
|
|
215
|
+
className,
|
|
216
|
+
close,
|
|
217
|
+
id,
|
|
218
|
+
open,
|
|
219
|
+
overlay,
|
|
220
|
+
showOverlay,
|
|
221
|
+
sideOffset,
|
|
222
|
+
triggerPosition,
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function DropdownMenuGroup({ className, children, ...props }: ViewProps) {
|
|
229
|
+
return (
|
|
230
|
+
<View className={cn("gap-0", className)} {...props}>
|
|
231
|
+
{children}
|
|
232
|
+
</View>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function DropdownMenuSeparator({ className, ...props }: ViewProps) {
|
|
237
|
+
return (
|
|
238
|
+
<View className={cn("my-1 h-px bg-gray-stroke-muted", className)} {...props} />
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function DropdownMenuItem({
|
|
243
|
+
className,
|
|
244
|
+
icon,
|
|
245
|
+
children,
|
|
246
|
+
onPress,
|
|
247
|
+
...props
|
|
248
|
+
}: DropdownMenuItemProps) {
|
|
249
|
+
const { close } = useMenuActions();
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<Pressable
|
|
253
|
+
accessibilityRole="button"
|
|
254
|
+
className={cn(
|
|
255
|
+
"flex-row items-center gap-2 rounded-md px-3 py-2 active:bg-gray-background-soft",
|
|
256
|
+
className
|
|
257
|
+
)}
|
|
258
|
+
onPress={(event) => {
|
|
259
|
+
onPress?.(event);
|
|
260
|
+
close();
|
|
261
|
+
}}
|
|
262
|
+
{...props}
|
|
263
|
+
>
|
|
264
|
+
{icon ? (
|
|
265
|
+
<View className="size-4 shrink-0" pointerEvents="none">
|
|
266
|
+
{icon}
|
|
267
|
+
</View>
|
|
268
|
+
) : null}
|
|
269
|
+
{typeof children === "string" ? (
|
|
270
|
+
<Text
|
|
271
|
+
numberOfLines={1}
|
|
272
|
+
className="flex-1 text-xs font-medium text-gray-foreground"
|
|
273
|
+
>
|
|
274
|
+
{children}
|
|
275
|
+
</Text>
|
|
276
|
+
) : (
|
|
277
|
+
children
|
|
278
|
+
)}
|
|
279
|
+
</Pressable>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const styles = StyleSheet.create({
|
|
284
|
+
layer: {
|
|
285
|
+
...StyleSheet.absoluteFill,
|
|
286
|
+
},
|
|
287
|
+
backdrop: {
|
|
288
|
+
// Alinhado ao Dialog/Sheet (`bg-black/50`); style explícito porque
|
|
289
|
+
// NativeWind pode não aplicar classes montadas no OverlayHost.
|
|
290
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
291
|
+
},
|
|
292
|
+
menu: {
|
|
293
|
+
position: "absolute",
|
|
294
|
+
zIndex: 2,
|
|
295
|
+
elevation: 8,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
export {
|
|
300
|
+
DropdownMenu,
|
|
301
|
+
DropdownMenuContent,
|
|
302
|
+
DropdownMenuGroup,
|
|
303
|
+
DropdownMenuItem,
|
|
304
|
+
DropdownMenuSeparator,
|
|
305
|
+
DropdownMenuTrigger,
|
|
306
|
+
};
|
|
307
|
+
export type {
|
|
308
|
+
DropdownMenuContentProps,
|
|
309
|
+
DropdownMenuItemProps,
|
|
310
|
+
DropdownMenuProps,
|
|
311
|
+
DropdownMenuTriggerProps,
|
|
312
|
+
};
|