@scripso-homepad/ui 0.4.16 → 0.4.18
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/web/index.cjs +62 -42
- 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 +62 -42
- package/dist/web/index.js.map +1 -1
- package/package.json +1 -1
- package/src/web/components/Drawer.tsx +67 -29
- package/src/web/icons/TableSortIcon.tsx +1 -3
- package/src/web/layout/SidebarNavItem.tsx +7 -16
package/package.json
CHANGED
|
@@ -7,10 +7,41 @@ import './drawer-scroll.css';
|
|
|
7
7
|
|
|
8
8
|
const DRAWER_TRANSITION_MS = 300;
|
|
9
9
|
|
|
10
|
+
let bodyScrollLockCount = 0;
|
|
11
|
+
let previousBodyOverflow = '';
|
|
12
|
+
|
|
13
|
+
function lockBodyScroll() {
|
|
14
|
+
if (typeof document === 'undefined') {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (bodyScrollLockCount === 0) {
|
|
19
|
+
previousBodyOverflow = document.body.style.overflow;
|
|
20
|
+
document.body.style.overflow = 'hidden';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
bodyScrollLockCount += 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function unlockBodyScroll() {
|
|
27
|
+
if (typeof document === 'undefined') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
bodyScrollLockCount = Math.max(0, bodyScrollLockCount - 1);
|
|
32
|
+
|
|
33
|
+
if (bodyScrollLockCount === 0) {
|
|
34
|
+
document.body.style.overflow = previousBodyOverflow;
|
|
35
|
+
previousBodyOverflow = '';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
10
39
|
export type DrawerProps = {
|
|
11
40
|
open: boolean;
|
|
12
41
|
title: string;
|
|
13
42
|
subtitle?: string;
|
|
43
|
+
subtitleClassName?: string;
|
|
44
|
+
headerBottom?: ReactNode;
|
|
14
45
|
children: ReactNode;
|
|
15
46
|
footer?: ReactNode;
|
|
16
47
|
onClose: () => void;
|
|
@@ -26,6 +57,8 @@ export function Drawer({
|
|
|
26
57
|
open,
|
|
27
58
|
title,
|
|
28
59
|
subtitle,
|
|
60
|
+
subtitleClassName,
|
|
61
|
+
headerBottom,
|
|
29
62
|
children,
|
|
30
63
|
footer,
|
|
31
64
|
onClose,
|
|
@@ -70,8 +103,7 @@ export function Drawer({
|
|
|
70
103
|
return;
|
|
71
104
|
}
|
|
72
105
|
|
|
73
|
-
|
|
74
|
-
document.body.style.overflow = 'hidden';
|
|
106
|
+
lockBodyScroll();
|
|
75
107
|
|
|
76
108
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
77
109
|
if (event.key === 'Escape') {
|
|
@@ -82,7 +114,7 @@ export function Drawer({
|
|
|
82
114
|
window.addEventListener('keydown', handleKeyDown);
|
|
83
115
|
|
|
84
116
|
return () => {
|
|
85
|
-
|
|
117
|
+
unlockBodyScroll();
|
|
86
118
|
window.removeEventListener('keydown', handleKeyDown);
|
|
87
119
|
};
|
|
88
120
|
}, [isPresent, onClose]);
|
|
@@ -119,36 +151,42 @@ export function Drawer({
|
|
|
119
151
|
)}
|
|
120
152
|
>
|
|
121
153
|
<header
|
|
122
|
-
className={cn(
|
|
123
|
-
'flex h-[87px] shrink-0 items-start justify-between border-b border-storm-gray-50 pt-6 pr-6 pb-4 pl-6',
|
|
124
|
-
headerClassName,
|
|
125
|
-
)}
|
|
154
|
+
className={cn('shrink-0 border-b border-storm-gray-50', headerClassName)}
|
|
126
155
|
>
|
|
127
|
-
<div className="
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
{title}
|
|
133
|
-
</h2>
|
|
134
|
-
{subtitle ? (
|
|
135
|
-
<p
|
|
136
|
-
id="homepad-drawer-subtitle"
|
|
137
|
-
className="typography-body tracking-normal text-storm-gray-400"
|
|
156
|
+
<div className="flex items-start justify-between pt-6 pr-6 pb-4 pl-6">
|
|
157
|
+
<div className="min-w-0 flex flex-col gap-1">
|
|
158
|
+
<h2
|
|
159
|
+
id="homepad-drawer-title"
|
|
160
|
+
className="typography-title-sm tracking-normal text-black"
|
|
138
161
|
>
|
|
139
|
-
{
|
|
140
|
-
</
|
|
141
|
-
|
|
162
|
+
{title}
|
|
163
|
+
</h2>
|
|
164
|
+
{subtitle ? (
|
|
165
|
+
<p
|
|
166
|
+
id="homepad-drawer-subtitle"
|
|
167
|
+
className={cn(
|
|
168
|
+
'typography-body tracking-normal text-storm-gray-400',
|
|
169
|
+
subtitleClassName,
|
|
170
|
+
)}
|
|
171
|
+
>
|
|
172
|
+
{subtitle}
|
|
173
|
+
</p>
|
|
174
|
+
) : null}
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<button
|
|
178
|
+
type="button"
|
|
179
|
+
aria-label={closeAriaLabel}
|
|
180
|
+
className="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-lg text-storm-gray-400 transition-colors hover:bg-storm-gray-50 hover:text-storm-gray-600"
|
|
181
|
+
onClick={onClose}
|
|
182
|
+
>
|
|
183
|
+
<X className="size-5" strokeWidth={1.75} />
|
|
184
|
+
</button>
|
|
142
185
|
</div>
|
|
143
186
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
className="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-lg text-storm-gray-400 transition-colors hover:bg-storm-gray-50 hover:text-storm-gray-600"
|
|
148
|
-
onClick={onClose}
|
|
149
|
-
>
|
|
150
|
-
<X className="size-5" strokeWidth={1.75} />
|
|
151
|
-
</button>
|
|
187
|
+
{headerBottom ? (
|
|
188
|
+
<div className="border-t border-storm-gray-50 px-6">{headerBottom}</div>
|
|
189
|
+
) : null}
|
|
152
190
|
</header>
|
|
153
191
|
|
|
154
192
|
<div
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { cn } from '../utils/cn';
|
|
2
|
-
|
|
3
1
|
export type TableSortDirection = 'asc' | 'desc';
|
|
4
2
|
|
|
5
3
|
type TableSortIconProps = {
|
|
@@ -22,7 +20,7 @@ export function TableSortIcon({ direction = null, className }: TableSortIconProp
|
|
|
22
20
|
fill="none"
|
|
23
21
|
xmlns="http://www.w3.org/2000/svg"
|
|
24
22
|
aria-hidden
|
|
25
|
-
className={
|
|
23
|
+
className={className}
|
|
26
24
|
>
|
|
27
25
|
<path
|
|
28
26
|
d="M9.70277 11.4541L6.42668 15.2773C6.37387 15.3389 6.30837 15.3883 6.23466 15.4222C6.16095 15.4561 6.08078 15.4736 5.99965 15.4736C5.91852 15.4736 5.83835 15.4561 5.76464 15.4222C5.69093 15.3883 5.62542 15.3389 5.57262 15.2773L2.29652 11.4541C1.98387 11.0892 2.24309 10.5255 2.72355 10.5255H9.27668C9.75715 10.5255 10.0164 11.0892 9.70277 11.4541Z"
|
|
@@ -10,38 +10,29 @@ export type SidebarNavItemProps = {
|
|
|
10
10
|
onNavigate?: (item: AdminNavItem) => void;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
function isModifiedClick(event: MouseEvent<HTMLAnchorElement>): boolean {
|
|
14
|
-
return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
13
|
export function SidebarNavItem({ item, isOpen, isActive, onNavigate }: SidebarNavItemProps) {
|
|
18
14
|
if (item.hidden) {
|
|
19
15
|
return null;
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
const handleClick = (event: MouseEvent<
|
|
23
|
-
|
|
24
|
-
event.preventDefault();
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
18
|
+
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
|
|
19
|
+
event.preventDefault();
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
// published UI copies never fight over duplicate router contexts.
|
|
30
|
-
if (event.defaultPrevented || isModifiedClick(event)) {
|
|
21
|
+
if (item.disabled) {
|
|
31
22
|
return;
|
|
32
23
|
}
|
|
33
24
|
|
|
34
|
-
event.preventDefault();
|
|
35
25
|
item.onClick?.();
|
|
36
26
|
onNavigate?.(item);
|
|
37
27
|
};
|
|
38
28
|
|
|
39
29
|
return (
|
|
40
|
-
<
|
|
41
|
-
|
|
30
|
+
<button
|
|
31
|
+
type="button"
|
|
42
32
|
onClick={handleClick}
|
|
43
33
|
aria-current={isActive ? 'page' : undefined}
|
|
44
34
|
aria-disabled={item.disabled}
|
|
35
|
+
disabled={item.disabled}
|
|
45
36
|
tabIndex={item.disabled ? -1 : undefined}
|
|
46
37
|
className={cn(
|
|
47
38
|
'relative flex items-center rounded-xl px-4 py-3 transition-[background-color,color,gap,padding] duration-300 ease-in-out',
|
|
@@ -66,6 +57,6 @@ export function SidebarNavItem({ item, isOpen, isActive, onNavigate }: SidebarNa
|
|
|
66
57
|
>
|
|
67
58
|
{item.label}
|
|
68
59
|
</span>
|
|
69
|
-
</
|
|
60
|
+
</button>
|
|
70
61
|
);
|
|
71
62
|
}
|