@ecohouse/ui 0.1.38 → 0.1.40
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/dist/index.cjs +639 -338
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -73
- package/dist/index.d.ts +8 -73
- package/dist/index.js +567 -262
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/components/DatePicker/DatePicker.tsx +2 -1
- package/src/components/Drawer/Drawer.stories.tsx +79 -0
- package/src/components/Drawer/Drawer.tsx +392 -0
- package/src/components/Drawer/index.ts +2 -0
- package/src/components/StatusBadge/StatusBadge.tsx +1 -1
- package/src/components/index.ts +3 -0
- package/src/icons/CalendarMinus/CalendarMinusIcon.tsx +25 -0
- package/src/icons/CalendarMinus/CalendarMinusIcon.web.tsx +31 -0
- package/src/icons/CalendarMinus/calendarMinusPath.ts +3 -0
- package/src/icons/CalendarMinus/index.ts +1 -0
- package/src/icons/index.ts +1 -2
- package/src/icons/registry.ts +3 -6
- package/src/index.ts +1 -9
- package/src/theme/colors.ts +1 -0
- package/src/web/styles/account-header.css +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecohouse/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Cross-platform presentation-only UI components for EcoHouse (React Native + React Native Web)",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"default": "./src/index.ts"
|
|
27
27
|
},
|
|
28
28
|
"./web/fonts.css": "./src/web/styles/fonts.css",
|
|
29
|
-
"./web/typography.css": "./src/web/styles/typography.css"
|
|
29
|
+
"./web/typography.css": "./src/web/styles/typography.css",
|
|
30
|
+
"./web/account-header.css": "./src/web/styles/account-header.css"
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"dist",
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
"storybook": "storybook dev -p 6006",
|
|
55
56
|
"storybook:clean": "rm -rf node_modules/.cache/storybook node_modules/.vite storybook-static && storybook dev -p 6006",
|
|
56
57
|
"build-storybook": "storybook build",
|
|
57
|
-
"prepare": "husky"
|
|
58
|
+
"prepare": "node -e \"if (process.env.CI !== 'true' && process.env.HUSKY !== '0') require('child_process').execSync('husky', { stdio: 'inherit' })\""
|
|
58
59
|
},
|
|
59
60
|
"lint-staged": {
|
|
60
61
|
"*.{js,jsx,ts,tsx,mjs}": [
|
|
@@ -716,9 +716,10 @@ const styles = StyleSheet.create({
|
|
|
716
716
|
},
|
|
717
717
|
rangeValueRow: {
|
|
718
718
|
minWidth: 0,
|
|
719
|
+
width: "100%",
|
|
719
720
|
flexDirection: "row",
|
|
720
721
|
alignItems: "center",
|
|
721
|
-
justifyContent: "
|
|
722
|
+
justifyContent: "space-between",
|
|
722
723
|
flexWrap: "nowrap",
|
|
723
724
|
gap: 10,
|
|
724
725
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
3
|
+
import { Pressable, StyleSheet, Text, View } from "react-native";
|
|
4
|
+
import { colors, fonts } from "../../theme";
|
|
5
|
+
import { Drawer } from "./Drawer";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Components/Drawer",
|
|
9
|
+
component: Drawer,
|
|
10
|
+
parameters: {
|
|
11
|
+
backgrounds: { default: "black" },
|
|
12
|
+
},
|
|
13
|
+
} satisfies Meta<typeof Drawer>;
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
type Story = StoryObj<typeof meta>;
|
|
17
|
+
|
|
18
|
+
function DrawerDemo() {
|
|
19
|
+
const [open, setOpen] = useState(true);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<View style={styles.page}>
|
|
23
|
+
<Pressable onPress={() => setOpen(true)} style={styles.openButton}>
|
|
24
|
+
<Text style={styles.openLabel}>Open drawer</Text>
|
|
25
|
+
</Pressable>
|
|
26
|
+
|
|
27
|
+
<Drawer
|
|
28
|
+
open={open}
|
|
29
|
+
onClose={() => setOpen(false)}
|
|
30
|
+
title="Չեղարկված ամրագրումներ"
|
|
31
|
+
closeAccessibilityLabel="Close drawer"
|
|
32
|
+
>
|
|
33
|
+
<View style={styles.body}>
|
|
34
|
+
<Text style={styles.bodyText}>Drawer body content</Text>
|
|
35
|
+
</View>
|
|
36
|
+
</Drawer>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const Default: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
open: true,
|
|
44
|
+
onClose: () => undefined,
|
|
45
|
+
children: null,
|
|
46
|
+
},
|
|
47
|
+
render: () => <DrawerDemo />,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const styles = StyleSheet.create({
|
|
51
|
+
page: {
|
|
52
|
+
minHeight: 360,
|
|
53
|
+
alignItems: "center",
|
|
54
|
+
justifyContent: "center",
|
|
55
|
+
padding: 24,
|
|
56
|
+
},
|
|
57
|
+
openButton: {
|
|
58
|
+
paddingHorizontal: 16,
|
|
59
|
+
paddingVertical: 10,
|
|
60
|
+
borderRadius: 40,
|
|
61
|
+
backgroundColor: colors.primary,
|
|
62
|
+
},
|
|
63
|
+
openLabel: {
|
|
64
|
+
fontFamily: fonts.sans,
|
|
65
|
+
fontSize: 14,
|
|
66
|
+
fontWeight: "600",
|
|
67
|
+
color: colors.white,
|
|
68
|
+
},
|
|
69
|
+
body: {
|
|
70
|
+
flex: 1,
|
|
71
|
+
padding: 24,
|
|
72
|
+
gap: 24,
|
|
73
|
+
},
|
|
74
|
+
bodyText: {
|
|
75
|
+
fontFamily: fonts.sans,
|
|
76
|
+
fontSize: 14,
|
|
77
|
+
color: colors.lightGrey,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
type ComponentRef,
|
|
9
|
+
type ReactNode,
|
|
10
|
+
type TransitionEvent,
|
|
11
|
+
} from "react";
|
|
12
|
+
import { createPortal } from "react-dom";
|
|
13
|
+
import {
|
|
14
|
+
Animated,
|
|
15
|
+
Easing,
|
|
16
|
+
Modal as RNModal,
|
|
17
|
+
Platform,
|
|
18
|
+
Pressable,
|
|
19
|
+
StyleSheet,
|
|
20
|
+
Text,
|
|
21
|
+
View,
|
|
22
|
+
type StyleProp,
|
|
23
|
+
type ViewStyle,
|
|
24
|
+
} from "react-native";
|
|
25
|
+
import { CloseIcon } from "../../icons";
|
|
26
|
+
import { colors, fonts } from "../../theme";
|
|
27
|
+
import { mergeRefs } from "../../utils/mergeRefs";
|
|
28
|
+
import { useApplyWebClassName } from "../../utils/useApplyWebClassName";
|
|
29
|
+
|
|
30
|
+
export interface DrawerProps {
|
|
31
|
+
/** Controls visibility. */
|
|
32
|
+
open: boolean;
|
|
33
|
+
/** Called on backdrop press, Escape / Android back, or header close. */
|
|
34
|
+
onClose: () => void;
|
|
35
|
+
children: ReactNode;
|
|
36
|
+
/** Header title. When set, the standard drawer header is rendered. */
|
|
37
|
+
title?: string;
|
|
38
|
+
/** Panel width in px. Defaults to `652`. */
|
|
39
|
+
width?: number;
|
|
40
|
+
/** Open/close width transition duration in ms. Defaults to `320`. */
|
|
41
|
+
animationDuration?: number;
|
|
42
|
+
/** Close when the dimmed backdrop is pressed. Defaults to `true`. */
|
|
43
|
+
closeOnBackdropPress?: boolean;
|
|
44
|
+
/** Accessible name for the backdrop control. Defaults to `"Close"`. */
|
|
45
|
+
backdropAccessibilityLabel?: string;
|
|
46
|
+
/** Accessible name for the header close control. Defaults to `"Close"`. */
|
|
47
|
+
closeAccessibilityLabel?: string;
|
|
48
|
+
/** Style for the drawer panel. */
|
|
49
|
+
style?: StyleProp<ViewStyle>;
|
|
50
|
+
/** Web CSS class applied to the drawer panel. */
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const BACKDROP_COLOR = "#09090933";
|
|
55
|
+
const DEFAULT_WIDTH = 652;
|
|
56
|
+
const DEFAULT_DURATION = 320;
|
|
57
|
+
const WEB_Z_INDEX = 500;
|
|
58
|
+
const CLOSE_ICON_SIZE = 24;
|
|
59
|
+
|
|
60
|
+
export const Drawer = forwardRef<ComponentRef<typeof View>, DrawerProps>(function Drawer(
|
|
61
|
+
{
|
|
62
|
+
open,
|
|
63
|
+
onClose,
|
|
64
|
+
children,
|
|
65
|
+
title,
|
|
66
|
+
width = DEFAULT_WIDTH,
|
|
67
|
+
animationDuration = DEFAULT_DURATION,
|
|
68
|
+
closeOnBackdropPress = true,
|
|
69
|
+
backdropAccessibilityLabel = "Close",
|
|
70
|
+
closeAccessibilityLabel = "Close",
|
|
71
|
+
style,
|
|
72
|
+
className,
|
|
73
|
+
},
|
|
74
|
+
forwardedRef,
|
|
75
|
+
) {
|
|
76
|
+
const panelRef = useRef<ComponentRef<typeof View>>(null);
|
|
77
|
+
const setPanelRef = useMemo(() => mergeRefs(panelRef, forwardedRef), [forwardedRef]);
|
|
78
|
+
const resolvedClassName = className?.trim() || undefined;
|
|
79
|
+
const closeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
80
|
+
|
|
81
|
+
const [mounted, setMounted] = useState(open);
|
|
82
|
+
const [entered, setEntered] = useState(false);
|
|
83
|
+
const animatedWidth = useRef(new Animated.Value(open ? width : 0)).current;
|
|
84
|
+
const animatedBackdrop = useRef(new Animated.Value(open ? 1 : 0)).current;
|
|
85
|
+
|
|
86
|
+
useApplyWebClassName(panelRef, resolvedClassName, mounted && Platform.OS === "web");
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (!mounted || Platform.OS !== "web") return undefined;
|
|
90
|
+
|
|
91
|
+
const previousOverflow = document.body.style.overflow;
|
|
92
|
+
document.body.style.overflow = "hidden";
|
|
93
|
+
|
|
94
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
95
|
+
if (event.key === "Escape") onClose();
|
|
96
|
+
};
|
|
97
|
+
document.addEventListener("keydown", onKeyDown);
|
|
98
|
+
|
|
99
|
+
return () => {
|
|
100
|
+
document.body.style.overflow = previousOverflow;
|
|
101
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
102
|
+
};
|
|
103
|
+
}, [mounted, onClose]);
|
|
104
|
+
|
|
105
|
+
// Web: mount at width 0, then expand; on close collapse then unmount.
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (Platform.OS !== "web") return undefined;
|
|
108
|
+
|
|
109
|
+
if (closeTimeoutRef.current) {
|
|
110
|
+
clearTimeout(closeTimeoutRef.current);
|
|
111
|
+
closeTimeoutRef.current = null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (open) {
|
|
115
|
+
setMounted(true);
|
|
116
|
+
const frame = requestAnimationFrame(() => {
|
|
117
|
+
requestAnimationFrame(() => setEntered(true));
|
|
118
|
+
});
|
|
119
|
+
return () => cancelAnimationFrame(frame);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setEntered(false);
|
|
123
|
+
// Fallback if transitionend is skipped (e.g. reduced motion / tab background).
|
|
124
|
+
closeTimeoutRef.current = setTimeout(() => {
|
|
125
|
+
setMounted(false);
|
|
126
|
+
closeTimeoutRef.current = null;
|
|
127
|
+
}, animationDuration + 50);
|
|
128
|
+
|
|
129
|
+
return () => {
|
|
130
|
+
if (closeTimeoutRef.current) {
|
|
131
|
+
clearTimeout(closeTimeoutRef.current);
|
|
132
|
+
closeTimeoutRef.current = null;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}, [open, animationDuration]);
|
|
136
|
+
|
|
137
|
+
// Native: animate width + backdrop opacity.
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (Platform.OS === "web") return undefined;
|
|
140
|
+
|
|
141
|
+
if (open) {
|
|
142
|
+
setMounted(true);
|
|
143
|
+
Animated.parallel([
|
|
144
|
+
Animated.timing(animatedWidth, {
|
|
145
|
+
toValue: width,
|
|
146
|
+
duration: animationDuration,
|
|
147
|
+
easing: Easing.out(Easing.cubic),
|
|
148
|
+
useNativeDriver: false,
|
|
149
|
+
}),
|
|
150
|
+
Animated.timing(animatedBackdrop, {
|
|
151
|
+
toValue: 1,
|
|
152
|
+
duration: animationDuration,
|
|
153
|
+
easing: Easing.out(Easing.cubic),
|
|
154
|
+
useNativeDriver: true,
|
|
155
|
+
}),
|
|
156
|
+
]).start();
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
Animated.parallel([
|
|
161
|
+
Animated.timing(animatedWidth, {
|
|
162
|
+
toValue: 0,
|
|
163
|
+
duration: animationDuration,
|
|
164
|
+
easing: Easing.in(Easing.cubic),
|
|
165
|
+
useNativeDriver: false,
|
|
166
|
+
}),
|
|
167
|
+
Animated.timing(animatedBackdrop, {
|
|
168
|
+
toValue: 0,
|
|
169
|
+
duration: animationDuration,
|
|
170
|
+
easing: Easing.in(Easing.cubic),
|
|
171
|
+
useNativeDriver: true,
|
|
172
|
+
}),
|
|
173
|
+
]).start(({ finished }) => {
|
|
174
|
+
if (finished) setMounted(false);
|
|
175
|
+
});
|
|
176
|
+
return undefined;
|
|
177
|
+
}, [open, width, animationDuration, animatedWidth, animatedBackdrop]);
|
|
178
|
+
|
|
179
|
+
const handleWebTransitionEnd = useCallback(
|
|
180
|
+
(event: TransitionEvent<HTMLDivElement>) => {
|
|
181
|
+
if (event.target !== event.currentTarget) return;
|
|
182
|
+
if (event.propertyName !== "width") return;
|
|
183
|
+
if (!open) {
|
|
184
|
+
if (closeTimeoutRef.current) {
|
|
185
|
+
clearTimeout(closeTimeoutRef.current);
|
|
186
|
+
closeTimeoutRef.current = null;
|
|
187
|
+
}
|
|
188
|
+
setMounted(false);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
[open],
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const header =
|
|
195
|
+
title != null && title !== "" ? (
|
|
196
|
+
<View style={styles.header}>
|
|
197
|
+
<Text style={styles.title} numberOfLines={1}>
|
|
198
|
+
{title}
|
|
199
|
+
</Text>
|
|
200
|
+
<Pressable
|
|
201
|
+
accessibilityRole="button"
|
|
202
|
+
accessibilityLabel={closeAccessibilityLabel}
|
|
203
|
+
hitSlop={8}
|
|
204
|
+
onPress={onClose}
|
|
205
|
+
style={styles.closeButton}
|
|
206
|
+
>
|
|
207
|
+
<CloseIcon color={colors.white} size={CLOSE_ICON_SIZE} />
|
|
208
|
+
</Pressable>
|
|
209
|
+
</View>
|
|
210
|
+
) : null;
|
|
211
|
+
|
|
212
|
+
const panelContent = (
|
|
213
|
+
<View
|
|
214
|
+
ref={setPanelRef}
|
|
215
|
+
accessibilityViewIsModal
|
|
216
|
+
style={[styles.panelInner, { width }, style]}
|
|
217
|
+
onStartShouldSetResponder={() => true}
|
|
218
|
+
>
|
|
219
|
+
{header}
|
|
220
|
+
<View style={styles.body}>{children}</View>
|
|
221
|
+
</View>
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
if (Platform.OS === "web") {
|
|
225
|
+
if (!mounted || typeof document === "undefined") return null;
|
|
226
|
+
|
|
227
|
+
return createPortal(
|
|
228
|
+
<div
|
|
229
|
+
style={{
|
|
230
|
+
position: "fixed",
|
|
231
|
+
top: 0,
|
|
232
|
+
right: 0,
|
|
233
|
+
bottom: 0,
|
|
234
|
+
left: 0,
|
|
235
|
+
zIndex: WEB_Z_INDEX,
|
|
236
|
+
display: "flex",
|
|
237
|
+
justifyContent: "flex-end",
|
|
238
|
+
pointerEvents: "auto",
|
|
239
|
+
}}
|
|
240
|
+
role="presentation"
|
|
241
|
+
>
|
|
242
|
+
<button
|
|
243
|
+
type="button"
|
|
244
|
+
aria-label={backdropAccessibilityLabel}
|
|
245
|
+
disabled={!closeOnBackdropPress}
|
|
246
|
+
onClick={closeOnBackdropPress ? onClose : undefined}
|
|
247
|
+
style={{
|
|
248
|
+
position: "absolute",
|
|
249
|
+
top: 0,
|
|
250
|
+
right: 0,
|
|
251
|
+
bottom: 0,
|
|
252
|
+
left: 0,
|
|
253
|
+
backgroundColor: BACKDROP_COLOR,
|
|
254
|
+
backdropFilter: "blur(18px)",
|
|
255
|
+
WebkitBackdropFilter: "blur(18px)",
|
|
256
|
+
border: "none",
|
|
257
|
+
padding: 0,
|
|
258
|
+
margin: 0,
|
|
259
|
+
cursor: closeOnBackdropPress ? "pointer" : "default",
|
|
260
|
+
opacity: entered ? 1 : 0,
|
|
261
|
+
transition: `opacity ${animationDuration}ms ease`,
|
|
262
|
+
}}
|
|
263
|
+
/>
|
|
264
|
+
{/*
|
|
265
|
+
Shell width animates 0 ↔ panel width. Inner stays fixed-width and
|
|
266
|
+
right-aligned so content isn't crushed and appears to slide in.
|
|
267
|
+
minWidth:0 is required — flex defaults would otherwise lock width to content.
|
|
268
|
+
*/}
|
|
269
|
+
<div
|
|
270
|
+
onTransitionEnd={handleWebTransitionEnd}
|
|
271
|
+
style={{
|
|
272
|
+
position: "relative",
|
|
273
|
+
zIndex: 1,
|
|
274
|
+
height: "100%",
|
|
275
|
+
width: entered
|
|
276
|
+
? Math.min(width, typeof window !== "undefined" ? window.innerWidth : width)
|
|
277
|
+
: 0,
|
|
278
|
+
minWidth: 0,
|
|
279
|
+
maxWidth: "100%",
|
|
280
|
+
overflow: "hidden",
|
|
281
|
+
transition: `width ${animationDuration}ms cubic-bezier(0.32, 0.72, 0, 1)`,
|
|
282
|
+
willChange: "width",
|
|
283
|
+
boxSizing: "border-box",
|
|
284
|
+
}}
|
|
285
|
+
>
|
|
286
|
+
<div
|
|
287
|
+
style={{
|
|
288
|
+
width,
|
|
289
|
+
maxWidth: "100%",
|
|
290
|
+
height: "100%",
|
|
291
|
+
marginLeft: "auto",
|
|
292
|
+
display: "flex",
|
|
293
|
+
flexDirection: "column",
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
296
|
+
{panelContent}
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
</div>,
|
|
300
|
+
document.body,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!mounted) return null;
|
|
305
|
+
|
|
306
|
+
return (
|
|
307
|
+
<RNModal
|
|
308
|
+
visible={mounted}
|
|
309
|
+
transparent
|
|
310
|
+
animationType="none"
|
|
311
|
+
onRequestClose={onClose}
|
|
312
|
+
statusBarTranslucent
|
|
313
|
+
>
|
|
314
|
+
<View style={styles.root} accessibilityViewIsModal>
|
|
315
|
+
<Animated.View
|
|
316
|
+
pointerEvents="none"
|
|
317
|
+
style={[styles.backdrop, { opacity: animatedBackdrop }]}
|
|
318
|
+
/>
|
|
319
|
+
<Pressable
|
|
320
|
+
accessibilityRole="button"
|
|
321
|
+
accessibilityLabel={backdropAccessibilityLabel}
|
|
322
|
+
disabled={!closeOnBackdropPress}
|
|
323
|
+
onPress={closeOnBackdropPress ? onClose : undefined}
|
|
324
|
+
style={StyleSheet.absoluteFill}
|
|
325
|
+
/>
|
|
326
|
+
<Animated.View style={[styles.panelShell, { width: animatedWidth }]}>
|
|
327
|
+
{panelContent}
|
|
328
|
+
</Animated.View>
|
|
329
|
+
</View>
|
|
330
|
+
</RNModal>
|
|
331
|
+
);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const styles = StyleSheet.create({
|
|
335
|
+
root: {
|
|
336
|
+
flex: 1,
|
|
337
|
+
flexDirection: "row",
|
|
338
|
+
justifyContent: "flex-end",
|
|
339
|
+
},
|
|
340
|
+
backdrop: {
|
|
341
|
+
...StyleSheet.absoluteFillObject,
|
|
342
|
+
backgroundColor: BACKDROP_COLOR,
|
|
343
|
+
},
|
|
344
|
+
panelShell: {
|
|
345
|
+
zIndex: 1,
|
|
346
|
+
height: "100%",
|
|
347
|
+
maxWidth: "100%",
|
|
348
|
+
overflow: "hidden",
|
|
349
|
+
alignItems: "flex-end",
|
|
350
|
+
minWidth: 0,
|
|
351
|
+
},
|
|
352
|
+
panelInner: {
|
|
353
|
+
height: "100%",
|
|
354
|
+
maxWidth: "100%",
|
|
355
|
+
backgroundColor: colors.grey800,
|
|
356
|
+
flexShrink: 0,
|
|
357
|
+
},
|
|
358
|
+
header: {
|
|
359
|
+
height: 65,
|
|
360
|
+
flexDirection: "row",
|
|
361
|
+
alignItems: "center",
|
|
362
|
+
justifyContent: "space-between",
|
|
363
|
+
paddingTop: 20,
|
|
364
|
+
paddingRight: 24,
|
|
365
|
+
paddingBottom: 20,
|
|
366
|
+
paddingLeft: 24,
|
|
367
|
+
borderBottomWidth: 1,
|
|
368
|
+
borderBottomColor: colors.grey650,
|
|
369
|
+
},
|
|
370
|
+
title: {
|
|
371
|
+
flex: 1,
|
|
372
|
+
fontFamily: fonts.sans,
|
|
373
|
+
fontSize: 16,
|
|
374
|
+
fontWeight: "600",
|
|
375
|
+
lineHeight: 22,
|
|
376
|
+
letterSpacing: 0,
|
|
377
|
+
color: colors.white,
|
|
378
|
+
marginRight: 12,
|
|
379
|
+
overflow: "visible",
|
|
380
|
+
},
|
|
381
|
+
closeButton: {
|
|
382
|
+
width: CLOSE_ICON_SIZE,
|
|
383
|
+
height: CLOSE_ICON_SIZE,
|
|
384
|
+
alignItems: "center",
|
|
385
|
+
justifyContent: "center",
|
|
386
|
+
flexShrink: 0,
|
|
387
|
+
},
|
|
388
|
+
body: {
|
|
389
|
+
flex: 1,
|
|
390
|
+
minHeight: 0,
|
|
391
|
+
},
|
|
392
|
+
});
|
package/src/components/index.ts
CHANGED
|
@@ -77,6 +77,9 @@ export type { FloatingActionButtonProps } from "./FloatingActionButton";
|
|
|
77
77
|
export { Modal } from "./Modal";
|
|
78
78
|
export type { ModalProps } from "./Modal";
|
|
79
79
|
|
|
80
|
+
export { Drawer } from "./Drawer";
|
|
81
|
+
export type { DrawerProps } from "./Drawer";
|
|
82
|
+
|
|
80
83
|
export { Input } from "./Input";
|
|
81
84
|
export type { InputIcon, InputProps, InputSize } from "./Input";
|
|
82
85
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Svg, { Path } from "react-native-svg";
|
|
2
|
+
import { CALENDAR_MINUS_PATH } from "./calendarMinusPath";
|
|
3
|
+
import { colors } from "../../theme";
|
|
4
|
+
import type { IconProps } from "../types";
|
|
5
|
+
|
|
6
|
+
export { CALENDAR_MINUS_PATH } from "./calendarMinusPath";
|
|
7
|
+
|
|
8
|
+
/** Native — react-native-svg (peer dependency). */
|
|
9
|
+
export function CalendarMinusIcon({
|
|
10
|
+
size = 20,
|
|
11
|
+
color = colors.grey200,
|
|
12
|
+
strokeWidth = 2,
|
|
13
|
+
}: IconProps) {
|
|
14
|
+
return (
|
|
15
|
+
<Svg width={size} height={size} viewBox="0 0 20 20" fill="none">
|
|
16
|
+
<Path
|
|
17
|
+
d={CALENDAR_MINUS_PATH}
|
|
18
|
+
stroke={color}
|
|
19
|
+
strokeWidth={strokeWidth}
|
|
20
|
+
strokeLinecap="round"
|
|
21
|
+
strokeLinejoin="round"
|
|
22
|
+
/>
|
|
23
|
+
</Svg>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CALENDAR_MINUS_PATH } from "./calendarMinusPath";
|
|
2
|
+
import { colors } from "../../theme";
|
|
3
|
+
import type { IconProps } from "../types";
|
|
4
|
+
|
|
5
|
+
/** Web / Storybook — plain SVG (no react-native-svg). */
|
|
6
|
+
export function CalendarMinusIcon({
|
|
7
|
+
size = 20,
|
|
8
|
+
color = colors.grey200,
|
|
9
|
+
strokeWidth = 2,
|
|
10
|
+
}: IconProps) {
|
|
11
|
+
return (
|
|
12
|
+
<svg
|
|
13
|
+
width={size}
|
|
14
|
+
height={size}
|
|
15
|
+
viewBox="0 0 20 20"
|
|
16
|
+
fill="none"
|
|
17
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
18
|
+
aria-hidden
|
|
19
|
+
>
|
|
20
|
+
<path
|
|
21
|
+
d={CALENDAR_MINUS_PATH}
|
|
22
|
+
stroke={color}
|
|
23
|
+
strokeWidth={strokeWidth}
|
|
24
|
+
strokeLinecap="round"
|
|
25
|
+
strokeLinejoin="round"
|
|
26
|
+
/>
|
|
27
|
+
</svg>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { CALENDAR_MINUS_PATH } from "./calendarMinusPath";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Calendar with minus mark — 20×20 viewBox. */
|
|
2
|
+
export const CALENDAR_MINUS_PATH =
|
|
3
|
+
"M12.5 14.9998H17.5M17.5 9.58317V7.33317C17.5 5.93304 17.5 5.23297 17.2275 4.69819C16.9878 4.22779 16.6054 3.84534 16.135 3.60565C15.6002 3.33317 14.9001 3.33317 13.5 3.33317H6.5C5.09987 3.33317 4.3998 3.33317 3.86502 3.60565C3.39462 3.84534 3.01217 4.22779 2.77248 4.69819C2.5 5.23297 2.5 5.93304 2.5 7.33317V14.3332C2.5 15.7333 2.5 16.4334 2.77248 16.9681C3.01217 17.4386 3.39462 17.821 3.86502 18.0607C4.3998 18.3332 5.09987 18.3332 6.5 18.3332H10.4167M17.5 8.33317H2.5M13.3333 1.6665V4.99984M6.66667 1.6665V4.99984";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CalendarMinusIcon, CALENDAR_MINUS_PATH } from "./CalendarMinusIcon";
|
package/src/icons/index.ts
CHANGED
|
@@ -9,13 +9,13 @@ export { AmenityIcon } from "./Amenity";
|
|
|
9
9
|
export type { AmenityIconProps, AmenityName } from "./Amenity";
|
|
10
10
|
export { AlertTriangleIcon } from "./AlertTriangle";
|
|
11
11
|
export { AppleIcon } from "./Store";
|
|
12
|
-
export { ArrowLeftIcon } from "./ArrowLeft";
|
|
13
12
|
export { ArrowRightIcon } from "./ArrowRight";
|
|
14
13
|
export { BagIcon } from "./Bag";
|
|
15
14
|
export { BanIcon } from "./Ban";
|
|
16
15
|
export { BellIcon } from "./Bell";
|
|
17
16
|
export { BuildingIcon } from "./Building";
|
|
18
17
|
export { CalendarIcon } from "./Calendar";
|
|
18
|
+
export { CalendarMinusIcon } from "./CalendarMinus";
|
|
19
19
|
export { CalendarOutlineIcon } from "./CalendarOutline";
|
|
20
20
|
export { CameraIcon } from "./Camera";
|
|
21
21
|
export { CameraFilledIcon } from "./CameraFilled";
|
|
@@ -25,7 +25,6 @@ export { ChevronDownIcon } from "./ChevronDown";
|
|
|
25
25
|
export { ChevronLeftIcon } from "./ChevronLeft";
|
|
26
26
|
export { ClockIcon } from "./Clock";
|
|
27
27
|
export { CloseIcon } from "./Close";
|
|
28
|
-
export { CurrentLocationIcon } from "./CurrentLocation";
|
|
29
28
|
export { EditIcon } from "./Edit";
|
|
30
29
|
export {
|
|
31
30
|
BathroomsIcon,
|
package/src/icons/registry.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ArrowRightIcon } from "./ArrowRight";
|
|
2
|
-
import { ArrowLeftIcon } from "./ArrowLeft";
|
|
3
2
|
import { AlertTriangleIcon } from "./AlertTriangle";
|
|
4
3
|
import { AppleIcon, GooglePlayIcon } from "./Store";
|
|
5
4
|
import { BagIcon } from "./Bag";
|
|
@@ -7,6 +6,7 @@ import { BanIcon } from "./Ban";
|
|
|
7
6
|
import { BellIcon } from "./Bell";
|
|
8
7
|
import { BuildingIcon } from "./Building";
|
|
9
8
|
import { CalendarIcon } from "./Calendar";
|
|
9
|
+
import { CalendarMinusIcon } from "./CalendarMinus";
|
|
10
10
|
import { CalendarOutlineIcon } from "./CalendarOutline";
|
|
11
11
|
import { CameraIcon } from "./Camera";
|
|
12
12
|
import { CameraFilledIcon } from "./CameraFilled";
|
|
@@ -16,7 +16,6 @@ import { ChevronDownIcon } from "./ChevronDown";
|
|
|
16
16
|
import { ChevronLeftIcon } from "./ChevronLeft";
|
|
17
17
|
import { ClockIcon } from "./Clock";
|
|
18
18
|
import { CloseIcon } from "./Close";
|
|
19
|
-
import { CurrentLocationIcon } from "./CurrentLocation";
|
|
20
19
|
import { EditIcon } from "./Edit";
|
|
21
20
|
import {
|
|
22
21
|
BathroomsIcon,
|
|
@@ -87,13 +86,13 @@ export const icons = {
|
|
|
87
86
|
alertTriangle: AlertTriangleIcon,
|
|
88
87
|
areaExpand: AreaExpandIcon,
|
|
89
88
|
apple: AppleIcon,
|
|
90
|
-
arrowLeft: ArrowLeftIcon,
|
|
91
89
|
arrowRight: ArrowRightIcon,
|
|
92
90
|
bag: BagIcon,
|
|
93
91
|
ban: BanIcon,
|
|
94
92
|
bell: BellIcon,
|
|
95
93
|
building: BuildingIcon,
|
|
96
94
|
calendar: CalendarIcon,
|
|
95
|
+
calendarMinus: CalendarMinusIcon,
|
|
97
96
|
calendarOutline: CalendarOutlineIcon,
|
|
98
97
|
camera: CameraIcon,
|
|
99
98
|
cameraFilled: CameraFilledIcon,
|
|
@@ -104,7 +103,6 @@ export const icons = {
|
|
|
104
103
|
chevronLeft: ChevronLeftIcon,
|
|
105
104
|
clock: ClockIcon,
|
|
106
105
|
close: CloseIcon,
|
|
107
|
-
currentLocation: CurrentLocationIcon,
|
|
108
106
|
edit: EditIcon,
|
|
109
107
|
clockFilled: ClockFilledIcon,
|
|
110
108
|
copy: CopyIcon,
|
|
@@ -176,11 +174,9 @@ export const iconNames = Object.keys(icons) as IconName[];
|
|
|
176
174
|
|
|
177
175
|
export const iconGroups = {
|
|
178
176
|
navigation: [
|
|
179
|
-
"arrowLeft",
|
|
180
177
|
"arrowRight",
|
|
181
178
|
"chevronDown",
|
|
182
179
|
"chevronLeft",
|
|
183
|
-
"currentLocation",
|
|
184
180
|
"home",
|
|
185
181
|
"listView",
|
|
186
182
|
"locationPin",
|
|
@@ -208,6 +204,7 @@ export const iconGroups = {
|
|
|
208
204
|
"download",
|
|
209
205
|
"search",
|
|
210
206
|
"calendar",
|
|
207
|
+
"calendarMinus",
|
|
211
208
|
"calendarOutline",
|
|
212
209
|
"close",
|
|
213
210
|
"edit",
|