@scripso-homepad/ui 0.4.33 → 0.4.35
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 +91 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +91 -61
- package/dist/index.js.map +1 -1
- package/dist/web/index.cjs +15 -4
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +3 -1
- package/dist/web/index.d.ts +3 -1
- package/dist/web/index.js +15 -4
- package/dist/web/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DatePicker.tsx +41 -6
- package/src/web/components/TableActionsMenu.tsx +20 -3
package/package.json
CHANGED
|
@@ -61,6 +61,10 @@ type DatePickerFieldProps = {
|
|
|
61
61
|
hintClassName?: string;
|
|
62
62
|
/** Opens the calendar popup on mount (useful for Storybook previews). */
|
|
63
63
|
defaultOpen?: boolean;
|
|
64
|
+
/** Controlled open state for the calendar popup. */
|
|
65
|
+
open?: boolean;
|
|
66
|
+
/** Called when the calendar popup opens or closes. */
|
|
67
|
+
onOpenChange?: (open: boolean) => void;
|
|
64
68
|
/** Closes the popup after a complete range is selected. Defaults to true in range mode. */
|
|
65
69
|
closeOnRangeComplete?: boolean;
|
|
66
70
|
};
|
|
@@ -108,6 +112,8 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
108
112
|
errorClassName,
|
|
109
113
|
hintClassName,
|
|
110
114
|
defaultOpen = false,
|
|
115
|
+
open: controlledOpen,
|
|
116
|
+
onOpenChange,
|
|
111
117
|
} = props;
|
|
112
118
|
const mode = props.mode ?? "single";
|
|
113
119
|
const closeOnRangeComplete =
|
|
@@ -119,7 +125,9 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
119
125
|
const wrapperRef = useRef<ComponentRef<typeof View>>(null);
|
|
120
126
|
const triggerRef = useRef<ComponentRef<typeof Pressable>>(null);
|
|
121
127
|
const helperRef = useRef<ComponentRef<typeof Text>>(null);
|
|
122
|
-
const
|
|
128
|
+
const isControlled = controlledOpen !== undefined;
|
|
129
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
130
|
+
const open = isControlled ? controlledOpen : uncontrolledOpen;
|
|
123
131
|
const [anchor, setAnchor] = useState<{
|
|
124
132
|
x: number;
|
|
125
133
|
y: number;
|
|
@@ -131,6 +139,12 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
131
139
|
useApplyWebClassName(triggerRef, fieldClassName);
|
|
132
140
|
useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
|
|
133
141
|
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (!open) {
|
|
144
|
+
setAnchor(null);
|
|
145
|
+
}
|
|
146
|
+
}, [open]);
|
|
147
|
+
|
|
134
148
|
useEffect(() => {
|
|
135
149
|
if (!defaultOpen || disabled) {
|
|
136
150
|
return;
|
|
@@ -139,7 +153,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
139
153
|
const frame = requestAnimationFrame(() => {
|
|
140
154
|
triggerRef.current?.measureInWindow((x, y, width, height) => {
|
|
141
155
|
setAnchor({ x, y, width, height });
|
|
142
|
-
|
|
156
|
+
setOpenState(true);
|
|
143
157
|
});
|
|
144
158
|
});
|
|
145
159
|
|
|
@@ -195,8 +209,16 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
195
209
|
: 0;
|
|
196
210
|
const dropdownTop = anchor ? resolveCalendarDropdownTop(anchor) : 0;
|
|
197
211
|
|
|
212
|
+
function setOpenState(next: boolean) {
|
|
213
|
+
if (!isControlled) {
|
|
214
|
+
setUncontrolledOpen(next);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
onOpenChange?.(next);
|
|
218
|
+
}
|
|
219
|
+
|
|
198
220
|
function closePicker() {
|
|
199
|
-
|
|
221
|
+
setOpenState(false);
|
|
200
222
|
setAnchor(null);
|
|
201
223
|
}
|
|
202
224
|
|
|
@@ -207,7 +229,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
207
229
|
|
|
208
230
|
triggerRef.current?.measureInWindow((x, y, width, height) => {
|
|
209
231
|
setAnchor({ x, y, width, height });
|
|
210
|
-
|
|
232
|
+
setOpenState(true);
|
|
211
233
|
});
|
|
212
234
|
}
|
|
213
235
|
|
|
@@ -292,7 +314,14 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
292
314
|
</Text>
|
|
293
315
|
) : null}
|
|
294
316
|
|
|
295
|
-
<Modal
|
|
317
|
+
<Modal
|
|
318
|
+
visible={open}
|
|
319
|
+
transparent
|
|
320
|
+
animationType="fade"
|
|
321
|
+
onRequestClose={closePicker}
|
|
322
|
+
statusBarTranslucent
|
|
323
|
+
{...(Platform.OS === "ios" ? { presentationStyle: "overFullScreen" as const } : null)}
|
|
324
|
+
>
|
|
296
325
|
<View style={styles.modalRoot}>
|
|
297
326
|
<Pressable
|
|
298
327
|
style={styles.backdrop}
|
|
@@ -302,6 +331,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
302
331
|
/>
|
|
303
332
|
{anchor ? (
|
|
304
333
|
<View
|
|
334
|
+
pointerEvents="box-none"
|
|
305
335
|
style={[
|
|
306
336
|
styles.panelPosition,
|
|
307
337
|
{
|
|
@@ -312,6 +342,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
312
342
|
},
|
|
313
343
|
]}
|
|
314
344
|
>
|
|
345
|
+
<View pointerEvents="auto">
|
|
315
346
|
{props.mode === "range" ? (
|
|
316
347
|
<Calendar
|
|
317
348
|
mode="range"
|
|
@@ -343,6 +374,7 @@ export function DatePicker(props: DatePickerProps) {
|
|
|
343
374
|
className={panelClassName}
|
|
344
375
|
/>
|
|
345
376
|
)}
|
|
377
|
+
</View>
|
|
346
378
|
</View>
|
|
347
379
|
) : null}
|
|
348
380
|
</View>
|
|
@@ -387,10 +419,13 @@ const styles = StyleSheet.create({
|
|
|
387
419
|
},
|
|
388
420
|
modalRoot: {
|
|
389
421
|
flex: 1,
|
|
422
|
+
width: "100%",
|
|
423
|
+
height: "100%",
|
|
390
424
|
},
|
|
391
425
|
backdrop: {
|
|
392
426
|
...StyleSheet.absoluteFillObject,
|
|
393
|
-
backgroundColor:
|
|
427
|
+
backgroundColor: "rgba(0, 0, 0, 0.35)",
|
|
428
|
+
zIndex: 0,
|
|
394
429
|
},
|
|
395
430
|
panelPosition: {
|
|
396
431
|
position: "absolute",
|
|
@@ -31,6 +31,8 @@ export type TableActionsMenuProps = {
|
|
|
31
31
|
triggerAriaLabel: string;
|
|
32
32
|
className?: string;
|
|
33
33
|
menuClassName?: string;
|
|
34
|
+
/** Optional custom trigger icon. Defaults to TableMoreIcon. */
|
|
35
|
+
triggerIcon?: ReactNode;
|
|
34
36
|
/** Dropdown menu width in pixels. Defaults to 231. Ignored when menuFitContent is true. */
|
|
35
37
|
menuWidth?: number;
|
|
36
38
|
/** Size the menu to its content width instead of a fixed pixel width. Defaults to true so labels stay on one line. */
|
|
@@ -73,6 +75,7 @@ export function TableActionsMenu({
|
|
|
73
75
|
triggerAriaLabel,
|
|
74
76
|
className,
|
|
75
77
|
menuClassName,
|
|
78
|
+
triggerIcon,
|
|
76
79
|
menuWidth = MENU_WIDTH_PX,
|
|
77
80
|
menuFitContent = true,
|
|
78
81
|
}: TableActionsMenuProps) {
|
|
@@ -193,13 +196,27 @@ export function TableActionsMenu({
|
|
|
193
196
|
item.onSelect();
|
|
194
197
|
}}
|
|
195
198
|
className={cn(
|
|
196
|
-
'flex h-[51px] w-full cursor-pointer items-center gap-2.5 px-3 text-left typography-14 font-medium
|
|
199
|
+
'flex h-[51px] w-full cursor-pointer items-center gap-2.5 px-3 text-left typography-14 font-medium transition-colors hover:bg-storm-gray-0',
|
|
197
200
|
index > 0 && 'border-t border-storm-gray-50',
|
|
198
201
|
item.disabled && 'cursor-not-allowed opacity-50',
|
|
202
|
+
item.tone === 'danger'
|
|
203
|
+
? 'text-[#AE0011]'
|
|
204
|
+
: item.tone === 'success'
|
|
205
|
+
? 'text-green-600'
|
|
206
|
+
: 'text-storm-gray-900',
|
|
199
207
|
)}
|
|
200
208
|
>
|
|
201
209
|
{icon ? (
|
|
202
|
-
<span
|
|
210
|
+
<span
|
|
211
|
+
className={cn(
|
|
212
|
+
'inline-flex size-5 shrink-0 items-center justify-center',
|
|
213
|
+
item.tone === 'danger'
|
|
214
|
+
? 'text-[#AE0011]'
|
|
215
|
+
: item.tone === 'success'
|
|
216
|
+
? 'text-green-600'
|
|
217
|
+
: 'text-storm-gray-200',
|
|
218
|
+
)}
|
|
219
|
+
>
|
|
203
220
|
{icon}
|
|
204
221
|
</span>
|
|
205
222
|
) : null}
|
|
@@ -215,7 +232,7 @@ export function TableActionsMenu({
|
|
|
215
232
|
<TableActionButton
|
|
216
233
|
ref={triggerRef}
|
|
217
234
|
variant="menu"
|
|
218
|
-
icon={<TableMoreIcon className="size-5" />}
|
|
235
|
+
icon={triggerIcon ?? <TableMoreIcon className="size-5" />}
|
|
219
236
|
ariaLabel={triggerAriaLabel}
|
|
220
237
|
onClick={() => setOpen((current) => !current)}
|
|
221
238
|
aria-expanded={open}
|