@scripso-homepad/ui 0.4.28 → 0.4.29

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": "@scripso-homepad/ui",
3
- "version": "0.4.28",
3
+ "version": "0.4.29",
4
4
  "type": "module",
5
5
  "description": "Cross-platform UI components for Homepad (React Web + React Native)",
6
6
  "license": "MIT",
@@ -74,7 +74,7 @@ export function ConfirmModal({
74
74
  aria-labelledby="homepad-confirm-modal-title"
75
75
  aria-describedby="homepad-confirm-modal-description"
76
76
  className={cn(
77
- 'flex w-full max-w-md flex-col gap-8 rounded-2xl bg-white p-4 opacity-100 md:p-6',
77
+ 'flex w-full max-w-md flex-col gap-8 rounded-3xl bg-white p-6 opacity-100 md:p-8',
78
78
  containerClassName,
79
79
  )}
80
80
  onClick={(event) => {
@@ -71,10 +71,12 @@ export function Drawer({
71
71
  }: DrawerProps) {
72
72
  const [isPresent, setIsPresent] = useState(open);
73
73
  const [isAnimatedIn, setIsAnimatedIn] = useState(false);
74
+ const [isTransformSettled, setIsTransformSettled] = useState(open);
74
75
 
75
76
  useEffect(() => {
76
77
  if (open) {
77
78
  setIsPresent(true);
79
+ setIsTransformSettled(false);
78
80
 
79
81
  const frame = window.requestAnimationFrame(() => {
80
82
  window.requestAnimationFrame(() => {
@@ -82,18 +84,32 @@ export function Drawer({
82
84
  });
83
85
  });
84
86
 
87
+ const settleTimeout = window.setTimeout(() => {
88
+ setIsTransformSettled(true);
89
+ }, DRAWER_TRANSITION_MS);
90
+
85
91
  return () => {
86
92
  window.cancelAnimationFrame(frame);
93
+ window.clearTimeout(settleTimeout);
87
94
  };
88
95
  }
89
96
 
90
- setIsAnimatedIn(false);
97
+ // Re-enable transform at the open position, then slide out.
98
+ setIsTransformSettled(false);
99
+ setIsAnimatedIn(true);
100
+
101
+ const frame = window.requestAnimationFrame(() => {
102
+ window.requestAnimationFrame(() => {
103
+ setIsAnimatedIn(false);
104
+ });
105
+ });
91
106
 
92
107
  const timeout = window.setTimeout(() => {
93
108
  setIsPresent(false);
94
109
  }, DRAWER_TRANSITION_MS);
95
110
 
96
111
  return () => {
112
+ window.cancelAnimationFrame(frame);
97
113
  window.clearTimeout(timeout);
98
114
  };
99
115
  }, [open]);
@@ -144,8 +160,14 @@ export function Drawer({
144
160
  aria-labelledby="homepad-drawer-title"
145
161
  {...(subtitle ? { 'aria-describedby': 'homepad-drawer-subtitle' } : {})}
146
162
  className={cn(
147
- 'relative z-10 flex h-[calc(100dvh-16px)] min-h-0 flex-col overflow-hidden rounded-[16px] bg-white shadow-2xl transition-transform duration-300 ease-in-out will-change-transform max-md:h-dvh max-md:rounded-none',
148
- isAnimatedIn ? 'translate-x-0' : 'translate-x-full',
163
+ 'relative z-10 flex h-[calc(100dvh-16px)] min-h-0 flex-col overflow-hidden rounded-[16px] bg-white shadow-2xl transition-transform duration-300 ease-in-out max-md:h-dvh max-md:rounded-none',
164
+ // Keep GPU transform only while animating — settled translate-x-0 blurs text.
165
+ !isTransformSettled && 'will-change-transform',
166
+ isAnimatedIn
167
+ ? isTransformSettled
168
+ ? 'transform-none'
169
+ : 'translate-x-0'
170
+ : 'translate-x-full',
149
171
  widthClassName,
150
172
  className,
151
173
  )}
@@ -25,6 +25,8 @@ export type AppHeaderProps = {
25
25
  notificationsIcon?: ReactNode;
26
26
  searchIcon?: ReactNode;
27
27
  buildingChevronIcon?: ReactNode;
28
+ /** Rendered before the building select (e.g. month period control). */
29
+ actions?: ReactNode;
28
30
  buildingSelectDisabled?: boolean;
29
31
  searchDisabled?: boolean;
30
32
  notificationsDisabled?: boolean;
@@ -60,6 +62,7 @@ export function AppHeader({
60
62
  notificationsIcon,
61
63
  searchIcon,
62
64
  buildingChevronIcon,
65
+ actions,
63
66
  buildingSelectDisabled = false,
64
67
  searchDisabled = false,
65
68
  notificationsDisabled = false,
@@ -77,6 +80,8 @@ export function AppHeader({
77
80
  <h1 className="truncate typography-title text-slate-blue">{title}</h1>
78
81
 
79
82
  <div className="flex shrink-0 items-center gap-3">
83
+ {actions}
84
+
80
85
  {hasBuildingSelect ? (
81
86
  <BuildingSelect
82
87
  options={buildingOptions}