@ecohouse/ui 0.1.50 → 0.1.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecohouse/ui",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Cross-platform presentation-only UI components for EcoHouse (React Native + React Native Web)",
@@ -83,12 +83,17 @@
83
83
  "devDependencies": {
84
84
  "@commitlint/cli": "^21.2.1",
85
85
  "@commitlint/config-conventional": "^21.2.0",
86
+ "@csstools/css-parser-algorithms": "4.0.0",
87
+ "@csstools/css-tokenizer": "4.0.0",
88
+ "@emnapi/core": "1.11.2",
89
+ "@emnapi/runtime": "1.11.2",
86
90
  "@eslint/js": "^9.17.0",
87
91
  "@storybook/react-vite": "^10.5.6",
88
92
  "@tailwindcss/postcss": "^4.1.13",
89
93
  "@tailwindcss/vite": "^4.1.13",
90
94
  "@types/react": "^18.3.18",
91
95
  "@types/react-dom": "^18.3.7",
96
+ "css-tree": "3.2.1",
92
97
  "eslint": "^9.17.0",
93
98
  "eslint-config-prettier": "^10.1.8",
94
99
  "eslint-plugin-react-hooks": "^5.1.0",
@@ -265,11 +265,14 @@ const styles = StyleSheet.create({
265
265
  borderColor: colors.grey700,
266
266
  borderRadius: 16,
267
267
  backgroundColor: colors.grey700,
268
- shadowColor: colors.black,
269
- shadowOffset: { width: 0, height: 8 },
270
- shadowOpacity: 0.4,
271
- shadowRadius: 18,
272
- elevation: 12,
268
+ ...Platform.select({
269
+ web: {
270
+ boxShadow: `0 8px 18px ${colors.black}66`,
271
+ },
272
+ default: {
273
+ elevation: 12,
274
+ },
275
+ }),
273
276
  },
274
277
  list: {
275
278
  maxHeight: MENU_MAX_HEIGHT,
@@ -74,6 +74,7 @@ export const Drawer = forwardRef<ComponentRef<typeof View>, DrawerProps>(functio
74
74
  forwardedRef,
75
75
  ) {
76
76
  const panelRef = useRef<ComponentRef<typeof View>>(null);
77
+ const shellRef = useRef<HTMLDivElement | null>(null);
77
78
  const setPanelRef = useMemo(() => mergeRefs(panelRef, forwardedRef), [forwardedRef]);
78
79
  const resolvedClassName = className?.trim() || undefined;
79
80
  const closeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -102,6 +103,27 @@ export const Drawer = forwardRef<ComponentRef<typeof View>, DrawerProps>(functio
102
103
  };
103
104
  }, [mounted, onClose]);
104
105
 
106
+ const targetWidth = Math.min(width, typeof window !== "undefined" ? window.innerWidth : width);
107
+
108
+ const playWidth = useCallback(
109
+ (target: number) => {
110
+ const shell = shellRef.current;
111
+ if (!shell) return;
112
+ const reduced =
113
+ typeof window !== "undefined" &&
114
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches;
115
+ const duration = reduced ? 0 : animationDuration;
116
+ const from = shell.getBoundingClientRect().width;
117
+ shell.style.transition = "none";
118
+ shell.style.width = `${from}px`;
119
+ // Flush layout so the transition starts from the current width, not the final one.
120
+ void shell.offsetWidth;
121
+ shell.style.transition = `width ${duration}ms cubic-bezier(0.32, 0.72, 0, 1)`;
122
+ shell.style.width = `${target}px`;
123
+ },
124
+ [animationDuration],
125
+ );
126
+
105
127
  // Web: mount at width 0, then expand; on close collapse then unmount.
106
128
  useEffect(() => {
107
129
  if (Platform.OS !== "web") return undefined;
@@ -113,13 +135,11 @@ export const Drawer = forwardRef<ComponentRef<typeof View>, DrawerProps>(functio
113
135
 
114
136
  if (open) {
115
137
  setMounted(true);
116
- const frame = requestAnimationFrame(() => {
117
- requestAnimationFrame(() => setEntered(true));
118
- });
119
- return () => cancelAnimationFrame(frame);
138
+ return undefined;
120
139
  }
121
140
 
122
141
  setEntered(false);
142
+ playWidth(0);
123
143
  // Fallback if transitionend is skipped (e.g. reduced motion / tab background).
124
144
  closeTimeoutRef.current = setTimeout(() => {
125
145
  setMounted(false);
@@ -132,7 +152,27 @@ export const Drawer = forwardRef<ComponentRef<typeof View>, DrawerProps>(functio
132
152
  closeTimeoutRef.current = null;
133
153
  }
134
154
  };
135
- }, [open, animationDuration]);
155
+ }, [open, animationDuration, playWidth]);
156
+
157
+ // Portal exists only after mounted flips. Animate from 0 on the next frame.
158
+ useEffect(() => {
159
+ if (Platform.OS !== "web" || !mounted || !open) return undefined;
160
+
161
+ const shell = shellRef.current;
162
+ if (shell) {
163
+ shell.style.transition = "none";
164
+ shell.style.width = "0px";
165
+ }
166
+
167
+ const frame = requestAnimationFrame(() => {
168
+ requestAnimationFrame(() => {
169
+ setEntered(true);
170
+ playWidth(targetWidth);
171
+ });
172
+ });
173
+
174
+ return () => cancelAnimationFrame(frame);
175
+ }, [mounted, open, targetWidth, playWidth]);
136
176
 
137
177
  // Native: animate width + backdrop opacity.
138
178
  useEffect(() => {
@@ -267,28 +307,28 @@ export const Drawer = forwardRef<ComponentRef<typeof View>, DrawerProps>(functio
267
307
  minWidth:0 is required — flex defaults would otherwise lock width to content.
268
308
  */}
269
309
  <div
310
+ ref={shellRef}
270
311
  onTransitionEnd={handleWebTransitionEnd}
271
312
  style={{
272
313
  position: "relative",
273
314
  zIndex: 1,
274
315
  height: "100%",
275
- width: entered
276
- ? Math.min(width, typeof window !== "undefined" ? window.innerWidth : width)
277
- : 0,
316
+ flex: "0 0 auto",
278
317
  minWidth: 0,
279
318
  maxWidth: "100%",
280
319
  overflow: "hidden",
281
- transition: `width ${animationDuration}ms cubic-bezier(0.32, 0.72, 0, 1)`,
282
320
  willChange: "width",
283
321
  boxSizing: "border-box",
284
322
  }}
285
323
  >
286
324
  <div
287
325
  style={{
288
- width,
326
+ position: "absolute",
327
+ top: 0,
328
+ right: 0,
329
+ bottom: 0,
330
+ width: targetWidth,
289
331
  maxWidth: "100%",
290
- height: "100%",
291
- marginLeft: "auto",
292
332
  display: "flex",
293
333
  flexDirection: "column",
294
334
  }}