@ecohouse/ui 0.1.35 → 0.1.36
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 +1 -0
- package/dist/index.cjs +508 -347
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +158 -128
- package/dist/index.d.ts +158 -128
- package/dist/index.js +505 -348
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/SegmentedToggle/SegmentedToggle.stories.tsx +9 -0
- package/src/components/SegmentedToggle/SegmentedToggle.tsx +19 -13
- package/src/icons/MoreHorizontal/MoreHorizontalIcon.tsx +26 -0
- package/src/icons/MoreHorizontal/MoreHorizontalIcon.web.tsx +25 -0
- package/src/icons/MoreHorizontal/index.ts +1 -0
- package/src/icons/MoreHorizontal/moreHorizontalPath.ts +2 -0
- package/src/icons/TableView/TableViewIcon.tsx +20 -0
- package/src/icons/TableView/TableViewIcon.web.tsx +26 -0
- package/src/icons/TableView/index.ts +1 -0
- package/src/icons/TableView/tableViewPath.ts +2 -0
- package/src/icons/index.ts +2 -0
- package/src/icons/registry.ts +6 -0
- package/src/index.ts +6 -0
- package/src/primitives/IconStatusBadge/IconStatusBadge.stories.tsx +21 -0
- package/src/primitives/IconStatusBadge/IconStatusBadge.tsx +76 -0
- package/src/primitives/IconStatusBadge/index.ts +2 -0
- package/src/primitives/InfoCardV2/InfoCardV2.stories.tsx +64 -0
- package/src/primitives/InfoCardV2/InfoCardV2.tsx +116 -0
- package/src/primitives/InfoCardV2/index.ts +2 -0
- package/src/primitives/index.ts +7 -0
package/package.json
CHANGED
|
@@ -52,6 +52,15 @@ type Story = StoryObj<typeof meta>;
|
|
|
52
52
|
|
|
53
53
|
export const WithIcons: Story = {};
|
|
54
54
|
|
|
55
|
+
export const IconOnly: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
options: [
|
|
58
|
+
{ value: "grid", label: "Grid view", icon: LayoutGridIcon, showLabel: false },
|
|
59
|
+
{ value: "list", label: "List view", icon: ListViewIcon, showLabel: false },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
55
64
|
export const WithoutIcons: Story = {
|
|
56
65
|
args: { options: optionsWithoutIcons, defaultValue: "first" },
|
|
57
66
|
};
|
|
@@ -20,6 +20,8 @@ export interface SegmentedToggleOption {
|
|
|
20
20
|
value: string;
|
|
21
21
|
label: string;
|
|
22
22
|
icon?: IconComponent;
|
|
23
|
+
/** Hides the visual label while retaining it as the accessible name. */
|
|
24
|
+
showLabel?: boolean;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export interface SegmentedToggleProps extends Omit<ViewProps, "style" | "children"> {
|
|
@@ -163,7 +165,7 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
163
165
|
accessibilityRole="radiogroup"
|
|
164
166
|
>
|
|
165
167
|
{!fullWidth
|
|
166
|
-
? options.map(({ value: optionValue, label, icon: Icon }, index) => (
|
|
168
|
+
? options.map(({ value: optionValue, label, icon: Icon, showLabel = true }, index) => (
|
|
167
169
|
<View
|
|
168
170
|
key={`${optionValue}-measurement`}
|
|
169
171
|
pointerEvents="none"
|
|
@@ -182,7 +184,9 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
182
184
|
style={styles.optionMeasurement}
|
|
183
185
|
>
|
|
184
186
|
{Icon ? <Icon size={ICON_SIZE} /> : null}
|
|
185
|
-
|
|
187
|
+
{showLabel ? (
|
|
188
|
+
<Text style={[styles.label, styles.contentWidthLabel]}>{label}</Text>
|
|
189
|
+
) : null}
|
|
186
190
|
</View>
|
|
187
191
|
))
|
|
188
192
|
: null}
|
|
@@ -195,7 +199,7 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
195
199
|
]}
|
|
196
200
|
/>
|
|
197
201
|
) : null}
|
|
198
|
-
{options.map(({ value: optionValue, label, icon: Icon }, index) => {
|
|
202
|
+
{options.map(({ value: optionValue, label, icon: Icon, showLabel = true }, index) => {
|
|
199
203
|
const selected = optionValue === selectedValue;
|
|
200
204
|
const iconColor = selected ? colors.primary : colors.whiteAlpha20;
|
|
201
205
|
const labelColor = selected ? colors.whiteAlpha86 : colors.whiteAlpha40;
|
|
@@ -219,16 +223,18 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
219
223
|
>
|
|
220
224
|
<View style={styles.optionContent}>
|
|
221
225
|
{Icon ? <Icon size={ICON_SIZE} color={iconColor} /> : null}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
226
|
+
{showLabel ? (
|
|
227
|
+
<Text
|
|
228
|
+
numberOfLines={fullWidth ? 1 : undefined}
|
|
229
|
+
style={[
|
|
230
|
+
styles.label,
|
|
231
|
+
!fullWidth && styles.contentWidthLabel,
|
|
232
|
+
{ color: labelColor },
|
|
233
|
+
]}
|
|
234
|
+
>
|
|
235
|
+
{label}
|
|
236
|
+
</Text>
|
|
237
|
+
) : null}
|
|
232
238
|
</View>
|
|
233
239
|
</Pressable>
|
|
234
240
|
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Svg, { Path } from "react-native-svg";
|
|
2
|
+
import { colors } from "../../theme";
|
|
3
|
+
import type { IconProps } from "../types";
|
|
4
|
+
import { MORE_HORIZONTAL_PATH } from "./moreHorizontalPath";
|
|
5
|
+
|
|
6
|
+
export { MORE_HORIZONTAL_PATH } from "./moreHorizontalPath";
|
|
7
|
+
|
|
8
|
+
const ASPECT_RATIO = 4 / 13;
|
|
9
|
+
|
|
10
|
+
export function MoreHorizontalIcon({
|
|
11
|
+
size = 13,
|
|
12
|
+
color = colors.white,
|
|
13
|
+
strokeWidth = 2,
|
|
14
|
+
}: IconProps) {
|
|
15
|
+
return (
|
|
16
|
+
<Svg width={size} height={size * ASPECT_RATIO} viewBox="0 0 13 4" fill="none">
|
|
17
|
+
<Path
|
|
18
|
+
d={MORE_HORIZONTAL_PATH}
|
|
19
|
+
stroke={color}
|
|
20
|
+
strokeWidth={strokeWidth}
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
|
+
/>
|
|
24
|
+
</Svg>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { colors } from "../../theme";
|
|
2
|
+
import type { IconProps } from "../types";
|
|
3
|
+
import { MORE_HORIZONTAL_PATH } from "./moreHorizontalPath";
|
|
4
|
+
|
|
5
|
+
export { MORE_HORIZONTAL_PATH } from "./moreHorizontalPath";
|
|
6
|
+
|
|
7
|
+
const ASPECT_RATIO = 4 / 13;
|
|
8
|
+
|
|
9
|
+
export function MoreHorizontalIcon({
|
|
10
|
+
size = 13,
|
|
11
|
+
color = colors.white,
|
|
12
|
+
strokeWidth = 2,
|
|
13
|
+
}: IconProps) {
|
|
14
|
+
return (
|
|
15
|
+
<svg width={size} height={size * ASPECT_RATIO} viewBox="0 0 13 4" fill="none" aria-hidden>
|
|
16
|
+
<path
|
|
17
|
+
d={MORE_HORIZONTAL_PATH}
|
|
18
|
+
stroke={color}
|
|
19
|
+
strokeWidth={strokeWidth}
|
|
20
|
+
strokeLinecap="round"
|
|
21
|
+
strokeLinejoin="round"
|
|
22
|
+
/>
|
|
23
|
+
</svg>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MoreHorizontalIcon, MORE_HORIZONTAL_PATH } from "./MoreHorizontalIcon";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export const MORE_HORIZONTAL_PATH =
|
|
2
|
+
"M6.33333 2.33333C6.70152 2.33333 7 2.03486 7 1.66667C7 1.29848 6.70152 1 6.33333 1C5.96514 1 5.66667 1.29848 5.66667 1.66667C5.66667 2.03486 5.96514 2.33333 6.33333 2.33333ZM11 2.33333C11.3682 2.33333 11.6667 2.03486 11.6667 1.66667C11.6667 1.29848 11.3682 1 11 1C10.6318 1 10.3333 1.29848 10.3333 1.66667C10.3333 2.03486 10.6318 2.33333 11 2.33333ZM1.66667 2.33333C2.03486 2.33333 2.33333 2.03486 2.33333 1.66667C2.33333 1.29848 2.03486 1 1.66667 1C1.29848 1 1 1.29848 1 1.66667C1 2.03486 1.29848 2.33333 1.66667 2.33333Z";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Svg, { Path } from "react-native-svg";
|
|
2
|
+
import { colors } from "../../theme";
|
|
3
|
+
import type { IconProps } from "../types";
|
|
4
|
+
import { TABLE_VIEW_PATH } from "./tableViewPath";
|
|
5
|
+
|
|
6
|
+
export { TABLE_VIEW_PATH } from "./tableViewPath";
|
|
7
|
+
|
|
8
|
+
export function TableViewIcon({ size = 17, color = colors.grey400, strokeWidth = 2 }: IconProps) {
|
|
9
|
+
return (
|
|
10
|
+
<Svg width={size} height={size} viewBox="0 0 17 17" fill="none">
|
|
11
|
+
<Path
|
|
12
|
+
d={TABLE_VIEW_PATH}
|
|
13
|
+
stroke={color}
|
|
14
|
+
strokeWidth={strokeWidth}
|
|
15
|
+
strokeLinecap="round"
|
|
16
|
+
strokeLinejoin="round"
|
|
17
|
+
/>
|
|
18
|
+
</Svg>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { colors } from "../../theme";
|
|
2
|
+
import type { IconProps } from "../types";
|
|
3
|
+
import { TABLE_VIEW_PATH } from "./tableViewPath";
|
|
4
|
+
|
|
5
|
+
export { TABLE_VIEW_PATH } from "./tableViewPath";
|
|
6
|
+
|
|
7
|
+
export function TableViewIcon({ size = 17, color = colors.grey400, strokeWidth = 2 }: IconProps) {
|
|
8
|
+
return (
|
|
9
|
+
<svg
|
|
10
|
+
width={size}
|
|
11
|
+
height={size}
|
|
12
|
+
viewBox="0 0 17 17"
|
|
13
|
+
fill="none"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
+
aria-hidden
|
|
16
|
+
>
|
|
17
|
+
<path
|
|
18
|
+
d={TABLE_VIEW_PATH}
|
|
19
|
+
stroke={color}
|
|
20
|
+
strokeWidth={strokeWidth}
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
|
+
/>
|
|
24
|
+
</svg>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TableViewIcon, TABLE_VIEW_PATH } from "./TableViewIcon";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export const TABLE_VIEW_PATH =
|
|
2
|
+
"M1 6L16 6M6 1L6 16M5 1H12C13.4001 1 14.1002 1 14.635 1.27248C15.1054 1.51217 15.4878 1.89462 15.7275 2.36502C16 2.8998 16 3.59987 16 5V12C16 13.4001 16 14.1002 15.7275 14.635C15.4878 15.1054 15.1054 15.4878 14.635 15.7275C14.1002 16 13.4001 16 12 16H5C3.59987 16 2.8998 16 2.36502 15.7275C1.89462 15.4878 1.51217 15.1054 1.27248 14.635C1 14.1002 1 13.4001 1 12V5C1 3.59987 1 2.8998 1.27248 2.36502C1.51217 1.89462 1.89462 1.51217 2.36502 1.27248C2.8998 1 3.59987 1 5 1Z";
|
package/src/icons/index.ts
CHANGED
|
@@ -70,6 +70,7 @@ export { MapCollapseIcon, MapExpandIcon } from "./MapControls";
|
|
|
70
70
|
export { MenuIcon } from "./Menu";
|
|
71
71
|
export type { MenuIconProps } from "./Menu";
|
|
72
72
|
export { MenuLinesIcon } from "./MenuLines";
|
|
73
|
+
export { MoreHorizontalIcon } from "./MoreHorizontal";
|
|
73
74
|
export { NavigateIcon } from "./Navigate";
|
|
74
75
|
export { PhoneIcon } from "./Phone";
|
|
75
76
|
export { PlusIcon } from "./Plus";
|
|
@@ -83,6 +84,7 @@ export { SidebarIcon } from "./Sidebar";
|
|
|
83
84
|
export { SortIcon } from "./Sort";
|
|
84
85
|
export { StarIcon } from "./Star";
|
|
85
86
|
export { StarFilledIcon } from "./StarFilled";
|
|
87
|
+
export { TableViewIcon } from "./TableView";
|
|
86
88
|
export { UserIcon } from "./User";
|
|
87
89
|
export { UsersAltIcon } from "./UsersAlt";
|
|
88
90
|
export { VideoIcon } from "./Video";
|
package/src/icons/registry.ts
CHANGED
|
@@ -60,6 +60,7 @@ import { MapCollapseIcon, MapExpandIcon } from "./MapControls";
|
|
|
60
60
|
import { MenuIcon } from "./Menu";
|
|
61
61
|
import { MenuLinesIcon } from "./MenuLines";
|
|
62
62
|
import { MinusIcon } from "./Minus";
|
|
63
|
+
import { MoreHorizontalIcon } from "./MoreHorizontal";
|
|
63
64
|
import { NavigateIcon } from "./Navigate";
|
|
64
65
|
import { PhoneIcon } from "./Phone";
|
|
65
66
|
import { PlusIcon } from "./Plus";
|
|
@@ -72,6 +73,7 @@ import { SidebarIcon } from "./Sidebar";
|
|
|
72
73
|
import { SortIcon } from "./Sort";
|
|
73
74
|
import { StarIcon } from "./Star";
|
|
74
75
|
import { StarFilledIcon } from "./StarFilled";
|
|
76
|
+
import { TableViewIcon } from "./TableView";
|
|
75
77
|
import { UserIcon } from "./User";
|
|
76
78
|
import { UsersAltIcon } from "./UsersAlt";
|
|
77
79
|
import { VideoIcon } from "./Video";
|
|
@@ -133,6 +135,7 @@ export const icons = {
|
|
|
133
135
|
menu: MenuIcon,
|
|
134
136
|
menuLines: MenuLinesIcon,
|
|
135
137
|
minus: MinusIcon,
|
|
138
|
+
moreHorizontal: MoreHorizontalIcon,
|
|
136
139
|
navigate: NavigateIcon,
|
|
137
140
|
noSmoking: NoSmokingIcon,
|
|
138
141
|
paw: PawIcon,
|
|
@@ -152,6 +155,7 @@ export const icons = {
|
|
|
152
155
|
sort: SortIcon,
|
|
153
156
|
star: StarIcon,
|
|
154
157
|
starFilled: StarFilledIcon,
|
|
158
|
+
tableView: TableViewIcon,
|
|
155
159
|
tooltipArrow: TooltipArrowIcon,
|
|
156
160
|
trash: TrashIcon,
|
|
157
161
|
user: UserIcon,
|
|
@@ -181,6 +185,7 @@ export const iconGroups = {
|
|
|
181
185
|
"menu",
|
|
182
186
|
"menuLines",
|
|
183
187
|
"navigate",
|
|
188
|
+
"tableView",
|
|
184
189
|
],
|
|
185
190
|
actions: [
|
|
186
191
|
"show",
|
|
@@ -211,6 +216,7 @@ export const iconGroups = {
|
|
|
211
216
|
"star",
|
|
212
217
|
"starFilled",
|
|
213
218
|
"minus",
|
|
219
|
+
"moreHorizontal",
|
|
214
220
|
"plus",
|
|
215
221
|
"refresh",
|
|
216
222
|
"refundStatus",
|
package/src/index.ts
CHANGED
|
@@ -94,6 +94,8 @@ export {
|
|
|
94
94
|
BRAND_LOGO_DEFAULT_HEIGHT,
|
|
95
95
|
BRAND_LOGO_DEFAULT_WIDTH,
|
|
96
96
|
FavoritesButton,
|
|
97
|
+
IconStatusBadge,
|
|
98
|
+
InfoCardV2,
|
|
97
99
|
MenuItem,
|
|
98
100
|
} from "./primitives";
|
|
99
101
|
export type {
|
|
@@ -102,6 +104,8 @@ export type {
|
|
|
102
104
|
BrandLogoProps,
|
|
103
105
|
BrandLogoVariant,
|
|
104
106
|
FavoritesButtonProps,
|
|
107
|
+
IconStatusBadgeProps,
|
|
108
|
+
InfoCardV2Props,
|
|
105
109
|
MenuItemProps,
|
|
106
110
|
} from "./primitives";
|
|
107
111
|
|
|
@@ -137,6 +141,7 @@ export {
|
|
|
137
141
|
GuestsIcon,
|
|
138
142
|
RatingStarIcon,
|
|
139
143
|
SaveHeartIcon,
|
|
144
|
+
MoreHorizontalIcon,
|
|
140
145
|
AreaExpandIcon,
|
|
141
146
|
CheckSuccessIcon,
|
|
142
147
|
ClockFilledIcon,
|
|
@@ -188,6 +193,7 @@ export {
|
|
|
188
193
|
SortIcon,
|
|
189
194
|
StarIcon,
|
|
190
195
|
StarFilledIcon,
|
|
196
|
+
TableViewIcon,
|
|
191
197
|
UserIcon,
|
|
192
198
|
UsersAltIcon,
|
|
193
199
|
VideoIcon,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { LockIcon } from "../../icons";
|
|
3
|
+
import { IconStatusBadge } from "./IconStatusBadge";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Primitives/Icon Status Badge",
|
|
7
|
+
component: IconStatusBadge,
|
|
8
|
+
args: {
|
|
9
|
+
icon: LockIcon,
|
|
10
|
+
iconProps: { color: "#60C27A" },
|
|
11
|
+
label: "Available",
|
|
12
|
+
},
|
|
13
|
+
parameters: { backgrounds: { default: "black" } },
|
|
14
|
+
} satisfies Meta<typeof IconStatusBadge>;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
export const Armenian: Story = { args: { label: "Ազատ" } };
|
|
20
|
+
export const English: Story = {};
|
|
21
|
+
export const Russian: Story = { args: { label: "Свободен" } };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { forwardRef, useMemo, useRef, type ComponentRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Platform,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
Text,
|
|
6
|
+
View,
|
|
7
|
+
type StyleProp,
|
|
8
|
+
type ViewProps,
|
|
9
|
+
type ViewStyle,
|
|
10
|
+
} from "react-native";
|
|
11
|
+
import type { IconComponent, IconProps } from "../../icons";
|
|
12
|
+
import { colors, fonts } from "../../theme";
|
|
13
|
+
import { mergeRefs } from "../../utils/mergeRefs";
|
|
14
|
+
import { useApplyWebClassName } from "../../utils/useApplyWebClassName";
|
|
15
|
+
|
|
16
|
+
export interface IconStatusBadgeProps extends Omit<ViewProps, "style" | "children"> {
|
|
17
|
+
label: string;
|
|
18
|
+
icon: IconComponent;
|
|
19
|
+
iconProps?: Omit<IconProps, "size">;
|
|
20
|
+
iconSize?: number;
|
|
21
|
+
style?: StyleProp<ViewStyle>;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const webBlurStyle: ViewStyle =
|
|
26
|
+
Platform.OS === "web"
|
|
27
|
+
? ({
|
|
28
|
+
backdropFilter: "blur(10px)",
|
|
29
|
+
WebkitBackdropFilter: "blur(10px)",
|
|
30
|
+
} as ViewStyle)
|
|
31
|
+
: {};
|
|
32
|
+
|
|
33
|
+
export const IconStatusBadge = forwardRef<ComponentRef<typeof View>, IconStatusBadgeProps>(
|
|
34
|
+
function IconStatusBadge(
|
|
35
|
+
{ label, icon: Icon, iconProps, iconSize = 16, style, className, ...rest },
|
|
36
|
+
forwardedRef,
|
|
37
|
+
) {
|
|
38
|
+
const badgeRef = useRef<ComponentRef<typeof View>>(null);
|
|
39
|
+
const setBadgeRef = useMemo(() => mergeRefs(badgeRef, forwardedRef), [forwardedRef]);
|
|
40
|
+
|
|
41
|
+
useApplyWebClassName(badgeRef, className);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<View {...rest} ref={setBadgeRef} style={[styles.root, webBlurStyle, style]}>
|
|
45
|
+
<Icon {...iconProps} size={iconSize} />
|
|
46
|
+
<Text numberOfLines={1} style={styles.label}>
|
|
47
|
+
{label}
|
|
48
|
+
</Text>
|
|
49
|
+
</View>
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const styles = StyleSheet.create({
|
|
55
|
+
root: {
|
|
56
|
+
minHeight: 34,
|
|
57
|
+
paddingHorizontal: 12,
|
|
58
|
+
paddingVertical: 8,
|
|
59
|
+
flexDirection: "row",
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
justifyContent: "center",
|
|
62
|
+
gap: 10,
|
|
63
|
+
alignSelf: "flex-start",
|
|
64
|
+
borderRadius: 39,
|
|
65
|
+
borderWidth: 1,
|
|
66
|
+
borderColor: colors.whiteAlpha10,
|
|
67
|
+
backgroundColor: "#09090966",
|
|
68
|
+
},
|
|
69
|
+
label: {
|
|
70
|
+
color: colors.white,
|
|
71
|
+
fontFamily: fonts.sans,
|
|
72
|
+
fontSize: 12,
|
|
73
|
+
fontWeight: "700",
|
|
74
|
+
lineHeight: 15,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
|
+
import { BagIcon, HomeIcon, LockIcon } from "../../icons";
|
|
4
|
+
import { colors } from "../../theme";
|
|
5
|
+
import { InfoCardV2 } from "./InfoCardV2";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Primitives/InfoCardV2",
|
|
9
|
+
component: InfoCardV2,
|
|
10
|
+
args: {
|
|
11
|
+
label: "Ընդհանուր քոթեջներ",
|
|
12
|
+
value: "12",
|
|
13
|
+
icon: HomeIcon,
|
|
14
|
+
},
|
|
15
|
+
parameters: {
|
|
16
|
+
backgrounds: { default: "black" },
|
|
17
|
+
},
|
|
18
|
+
} satisfies Meta<typeof InfoCardV2>;
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
export const Default: Story = {
|
|
24
|
+
render: (args) => (
|
|
25
|
+
<View style={styles.frame}>
|
|
26
|
+
<InfoCardV2 {...args} />
|
|
27
|
+
</View>
|
|
28
|
+
),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const OverviewRow: Story = {
|
|
32
|
+
render: () => (
|
|
33
|
+
<View style={styles.row}>
|
|
34
|
+
<InfoCardV2 label="Ընդհանուր քոթեջներ" value="12" icon={HomeIcon} />
|
|
35
|
+
<InfoCardV2 label="Զբաղված" value="8" icon={LockIcon} />
|
|
36
|
+
<InfoCardV2 label="Ազատ" value="4" icon={BagIcon} />
|
|
37
|
+
</View>
|
|
38
|
+
),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const WhiteIcon: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
label: "Label",
|
|
44
|
+
value: "description",
|
|
45
|
+
icon: LockIcon,
|
|
46
|
+
iconProps: { color: colors.white },
|
|
47
|
+
},
|
|
48
|
+
render: (args) => (
|
|
49
|
+
<View style={styles.frame}>
|
|
50
|
+
<InfoCardV2 {...args} />
|
|
51
|
+
</View>
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const styles = StyleSheet.create({
|
|
56
|
+
frame: {
|
|
57
|
+
width: 411,
|
|
58
|
+
},
|
|
59
|
+
row: {
|
|
60
|
+
width: 1280,
|
|
61
|
+
flexDirection: "row",
|
|
62
|
+
gap: 24,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { forwardRef, useMemo, useRef, type ComponentRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
Text,
|
|
5
|
+
View,
|
|
6
|
+
type StyleProp,
|
|
7
|
+
type ViewProps,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from "react-native";
|
|
10
|
+
import type { IconComponent, IconProps } from "../../icons";
|
|
11
|
+
import { colors, fonts } from "../../theme";
|
|
12
|
+
import { mergeRefs } from "../../utils/mergeRefs";
|
|
13
|
+
import { useApplyWebClassName } from "../../utils/useApplyWebClassName";
|
|
14
|
+
|
|
15
|
+
export interface InfoCardV2Props extends Omit<ViewProps, "style" | "children"> {
|
|
16
|
+
label: string;
|
|
17
|
+
value: string;
|
|
18
|
+
icon: IconComponent;
|
|
19
|
+
iconProps?: Omit<IconProps, "size">;
|
|
20
|
+
iconSize?: number;
|
|
21
|
+
style?: StyleProp<ViewStyle>;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const ICON_SLOT_SIZE = 41;
|
|
26
|
+
const ICON_SIZE = 20;
|
|
27
|
+
|
|
28
|
+
/** Dashboard metric card with a leading icon, muted label, and emphasized value. */
|
|
29
|
+
export const InfoCardV2 = forwardRef<ComponentRef<typeof View>, InfoCardV2Props>(
|
|
30
|
+
function InfoCardV2(
|
|
31
|
+
{
|
|
32
|
+
label,
|
|
33
|
+
value,
|
|
34
|
+
icon: Icon,
|
|
35
|
+
iconProps,
|
|
36
|
+
iconSize = ICON_SIZE,
|
|
37
|
+
style,
|
|
38
|
+
className,
|
|
39
|
+
accessibilityLabel,
|
|
40
|
+
...rest
|
|
41
|
+
},
|
|
42
|
+
forwardedRef,
|
|
43
|
+
) {
|
|
44
|
+
const containerRef = useRef<ComponentRef<typeof View>>(null);
|
|
45
|
+
const setContainerRef = useMemo(() => mergeRefs(containerRef, forwardedRef), [forwardedRef]);
|
|
46
|
+
|
|
47
|
+
useApplyWebClassName(containerRef, className?.trim() || undefined);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<View
|
|
51
|
+
{...rest}
|
|
52
|
+
ref={setContainerRef}
|
|
53
|
+
accessibilityRole="text"
|
|
54
|
+
accessibilityLabel={accessibilityLabel ?? `${label}. ${value}`}
|
|
55
|
+
style={[styles.root, style]}
|
|
56
|
+
>
|
|
57
|
+
<View style={styles.iconSlot}>
|
|
58
|
+
<Icon {...iconProps} size={iconSize} color={iconProps?.color ?? colors.primary} />
|
|
59
|
+
</View>
|
|
60
|
+
<View style={styles.content}>
|
|
61
|
+
<Text numberOfLines={1} style={styles.label}>
|
|
62
|
+
{label}
|
|
63
|
+
</Text>
|
|
64
|
+
<Text numberOfLines={1} style={styles.value}>
|
|
65
|
+
{value}
|
|
66
|
+
</Text>
|
|
67
|
+
</View>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const styles = StyleSheet.create({
|
|
74
|
+
root: {
|
|
75
|
+
minHeight: 65,
|
|
76
|
+
padding: 12,
|
|
77
|
+
flexDirection: "row",
|
|
78
|
+
alignItems: "center",
|
|
79
|
+
flexGrow: 1,
|
|
80
|
+
flexShrink: 0,
|
|
81
|
+
flexBasis: 0,
|
|
82
|
+
gap: 16,
|
|
83
|
+
borderRadius: 16,
|
|
84
|
+
backgroundColor: colors.grey700,
|
|
85
|
+
},
|
|
86
|
+
iconSlot: {
|
|
87
|
+
width: ICON_SLOT_SIZE,
|
|
88
|
+
height: ICON_SLOT_SIZE,
|
|
89
|
+
borderRadius: 10,
|
|
90
|
+
alignItems: "center",
|
|
91
|
+
justifyContent: "center",
|
|
92
|
+
flexShrink: 0,
|
|
93
|
+
backgroundColor: colors.grey600,
|
|
94
|
+
},
|
|
95
|
+
content: {
|
|
96
|
+
minWidth: 0,
|
|
97
|
+
flexShrink: 1,
|
|
98
|
+
gap: 6,
|
|
99
|
+
},
|
|
100
|
+
label: {
|
|
101
|
+
fontFamily: fonts.sans,
|
|
102
|
+
fontSize: 14,
|
|
103
|
+
fontWeight: "500",
|
|
104
|
+
lineHeight: 16,
|
|
105
|
+
letterSpacing: 0,
|
|
106
|
+
color: colors.lightGrey,
|
|
107
|
+
},
|
|
108
|
+
value: {
|
|
109
|
+
fontFamily: fonts.sans,
|
|
110
|
+
fontSize: 16,
|
|
111
|
+
fontWeight: "700",
|
|
112
|
+
lineHeight: 19,
|
|
113
|
+
letterSpacing: 0,
|
|
114
|
+
color: colors.white,
|
|
115
|
+
},
|
|
116
|
+
});
|
package/src/primitives/index.ts
CHANGED
|
@@ -3,9 +3,16 @@ export type { AmenityProps, AmenityVariant } from "./Amenity";
|
|
|
3
3
|
|
|
4
4
|
export { MenuItem } from "./MenuItem";
|
|
5
5
|
export type { MenuItemProps } from "./MenuItem";
|
|
6
|
+
|
|
7
|
+
export { InfoCardV2 } from "./InfoCardV2";
|
|
8
|
+
export type { InfoCardV2Props } from "./InfoCardV2";
|
|
9
|
+
|
|
6
10
|
export { FavoritesButton } from "./FavoritesButton";
|
|
7
11
|
export type { FavoritesButtonProps } from "./FavoritesButton";
|
|
8
12
|
|
|
13
|
+
export { IconStatusBadge } from "./IconStatusBadge";
|
|
14
|
+
export type { IconStatusBadgeProps } from "./IconStatusBadge";
|
|
15
|
+
|
|
9
16
|
export {
|
|
10
17
|
BrandLogo,
|
|
11
18
|
BRAND_LOGO_COLORS,
|