@podoba/react 0.0.25 → 0.0.27
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": "@podoba/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "podoba React components — React Aria Components + Tailwind primitives + layout, built with uic.",
|
|
6
6
|
"repository": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"typecheck": "tsc --build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@podoba/tokens": "^0.0.
|
|
29
|
-
"@podoba/tailwind": "^0.0.
|
|
28
|
+
"@podoba/tokens": "^0.0.27",
|
|
29
|
+
"@podoba/tailwind": "^0.0.27",
|
|
30
30
|
"react-aria-components": "1.18.0",
|
|
31
31
|
"class-variance-authority": "0.7.1",
|
|
32
32
|
"clsx": "2.1.1",
|
|
@@ -94,8 +94,8 @@ export function BrandPageHeader({
|
|
|
94
94
|
.filter(Boolean)
|
|
95
95
|
.join(' ')}
|
|
96
96
|
>
|
|
97
|
-
<div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:
|
|
98
|
-
<div className="flex min-w-0 flex-col gap-1">
|
|
97
|
+
<div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:gap-4">
|
|
98
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
99
99
|
{breadcrumbs && breadcrumbs.length > 0 ? (
|
|
100
100
|
<nav aria-label="Breadcrumb" className="flex flex-wrap items-center gap-1 text-compact text-fg-muted">
|
|
101
101
|
{breadcrumbs.map((crumb, i) => (
|
|
@@ -133,7 +133,8 @@ export function BrandPageHeader({
|
|
|
133
133
|
</div>
|
|
134
134
|
|
|
135
135
|
{cta ? (
|
|
136
|
-
|
|
136
|
+
// Hero CTA spans 4 of 12 columns (one third) — the greeting takes the rest.
|
|
137
|
+
<div className="w-full shrink-0 sm:w-1/3">{cta}</div>
|
|
137
138
|
) : ctaLabel ? (
|
|
138
139
|
<div className="shrink-0">
|
|
139
140
|
{hasExpandable ? (
|
|
@@ -95,6 +95,34 @@ interface ContextMenuWrapperProps {
|
|
|
95
95
|
className?: string
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Lock page scroll while the menu is open — an open action menu should pin the view
|
|
100
|
+
* (gs `ContextActionPanel` behaviour), not let the content scroll out from under the
|
|
101
|
+
* cursor-anchored panel. Wheel + touch scrolling is prevented everywhere EXCEPT inside
|
|
102
|
+
* `allowRef` (the panel itself, so a long/overflowing menu still scrolls). No dep on
|
|
103
|
+
* react-aria's `usePreventScroll` (not a direct dependency here).
|
|
104
|
+
*/
|
|
105
|
+
function useScrollLock(active: boolean, allowRef: React.RefObject<HTMLElement | null>): void {
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!active) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
const prevent = (e: Event) => {
|
|
111
|
+
const target = e.target as Node | null
|
|
112
|
+
if (target && allowRef.current?.contains(target)) {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
e.preventDefault()
|
|
116
|
+
}
|
|
117
|
+
document.addEventListener('wheel', prevent, { passive: false })
|
|
118
|
+
document.addEventListener('touchmove', prevent, { passive: false })
|
|
119
|
+
return () => {
|
|
120
|
+
document.removeEventListener('wheel', prevent)
|
|
121
|
+
document.removeEventListener('touchmove', prevent)
|
|
122
|
+
}
|
|
123
|
+
}, [active, allowRef])
|
|
124
|
+
}
|
|
125
|
+
|
|
98
126
|
const itemId = (item: ContextMenuItem, fallback: number): string => item.id ?? item.key ?? String(fallback)
|
|
99
127
|
const groupId = (group: ContextMenuGroup, fallback: number): string => group.id ?? group.key ?? String(fallback)
|
|
100
128
|
|
|
@@ -202,7 +230,10 @@ function ControlledContextMenu({
|
|
|
202
230
|
className,
|
|
203
231
|
}: ContextMenuProps): React.JSX.Element | null {
|
|
204
232
|
const anchorRef = useRef<HTMLSpanElement>(null)
|
|
233
|
+
const popoverRef = useRef<HTMLElement>(null)
|
|
205
234
|
const visibleGroups = visibleGroupsOf(groups)
|
|
235
|
+
// Lock scroll while open (hook runs unconditionally — before the empty-groups return).
|
|
236
|
+
useScrollLock(isOpen && visibleGroups.length > 0, popoverRef)
|
|
206
237
|
if (visibleGroups.length === 0) {
|
|
207
238
|
return null
|
|
208
239
|
}
|
|
@@ -219,6 +250,7 @@ function ControlledContextMenu({
|
|
|
219
250
|
/>
|
|
220
251
|
<RACPopover
|
|
221
252
|
key={`${pos.x}:${pos.y}`}
|
|
253
|
+
ref={popoverRef}
|
|
222
254
|
isOpen={isOpen}
|
|
223
255
|
onOpenChange={(open) => {
|
|
224
256
|
if (!open) {
|
|
@@ -315,6 +347,8 @@ function WrapperContextMenu({
|
|
|
315
347
|
|
|
316
348
|
const sourceGroups = typeof groups === 'function' ? resolved : groups
|
|
317
349
|
const visibleGroups = visibleGroupsOf(sourceGroups)
|
|
350
|
+
// Lock scroll while the panel is open (still scrollable inside a long menu).
|
|
351
|
+
useScrollLock(isOpen && visibleGroups.length > 0, popoverRef)
|
|
318
352
|
|
|
319
353
|
return (
|
|
320
354
|
<div ref={wrapperRef} className={className} onContextMenu={onContextMenu}>
|
|
@@ -26,8 +26,8 @@ export interface CtaPillProps {
|
|
|
26
26
|
|
|
27
27
|
export function CtaPill({ lead, emphasis, tail, children }: CtaPillProps) {
|
|
28
28
|
return (
|
|
29
|
-
<div className="flex
|
|
30
|
-
<p className="text-heading4 font-medium leading-[22px] tracking-normal text-fg">
|
|
29
|
+
<div className="flex w-full items-center justify-between gap-4 rounded-lg bg-brand-secondary px-6 py-4">
|
|
30
|
+
<p className="min-w-0 text-heading4 font-medium leading-[22px] tracking-normal text-fg">
|
|
31
31
|
{lead} <span className="font-semibold text-white">{emphasis}</span> {tail}
|
|
32
32
|
</p>
|
|
33
33
|
<div className="shrink-0">{children}</div>
|