@djangocfg/ui-core 2.1.528 → 2.1.531
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": "@djangocfg/ui-core",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.531",
|
|
4
4
|
"description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-components",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"check:contrast": "node scripts/check-preset-contrast.mjs"
|
|
129
129
|
},
|
|
130
130
|
"peerDependencies": {
|
|
131
|
-
"@djangocfg/i18n": "^2.1.
|
|
131
|
+
"@djangocfg/i18n": "^2.1.531",
|
|
132
132
|
"consola": "^3.4.2",
|
|
133
133
|
"lucide-react": "^0.545.0",
|
|
134
134
|
"moment": "^2.30.1",
|
|
@@ -206,8 +206,8 @@
|
|
|
206
206
|
"@chenglou/pretext": "^0.0.8"
|
|
207
207
|
},
|
|
208
208
|
"devDependencies": {
|
|
209
|
-
"@djangocfg/i18n": "^2.1.
|
|
210
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
209
|
+
"@djangocfg/i18n": "^2.1.531",
|
|
210
|
+
"@djangocfg/typescript-config": "^2.1.531",
|
|
211
211
|
"@types/node": "^24.13.3",
|
|
212
212
|
"@types/react": "19.2.15",
|
|
213
213
|
"@types/react-dom": "19.2.3",
|
|
@@ -80,7 +80,11 @@ const DialogContent = React.forwardRef<
|
|
|
80
80
|
? "left-0 top-0 grid grid-rows-[minmax(0,1fr)] h-[100dvh] w-screen max-w-none gap-0 border-0 p-0 shadow-none data-[state=closed]:zoom-out-[0.98] data-[state=open]:zoom-in-[0.98]"
|
|
81
81
|
// Rounded on ALL sizes — the radius used to be `sm:`-gated, which left
|
|
82
82
|
// phone dialogs with hard square corners. Centered, soft-cornered card.
|
|
83
|
-
|
|
83
|
+
// Width by MEASUREMENT, not breakpoint: `min()` keeps the card off
|
|
84
|
+
// both edges at any viewport. A `sm:` gate reads the window, so a
|
|
85
|
+
// narrow desktop pane lost its margins and rendered as a sheet with
|
|
86
|
+
// its rounding cropped.
|
|
87
|
+
: "left-1/2 top-1/2 grid w-[min(32rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-[var(--radius-dialog)] border p-6 shadow-lg data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
84
88
|
className
|
|
85
89
|
)}
|
|
86
90
|
{...props}
|
|
@@ -105,7 +109,9 @@ const DialogHeader = ({
|
|
|
105
109
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
106
110
|
<div
|
|
107
111
|
className={cn(
|
|
108
|
-
|
|
112
|
+
// Start-aligned at every width: the `sm:` gate centred the title in a
|
|
113
|
+
// narrow pane only, so one dialog read as two different components.
|
|
114
|
+
"flex flex-col space-y-1.5 text-start",
|
|
109
115
|
className
|
|
110
116
|
)}
|
|
111
117
|
{...props}
|
|
@@ -119,7 +125,10 @@ const DialogFooter = ({
|
|
|
119
125
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
120
126
|
<div
|
|
121
127
|
className={cn(
|
|
122
|
-
|
|
128
|
+
// One row, buttons sized to their labels. The `sm:`-gated stack read the
|
|
129
|
+
// window, so a narrow pane got two full-bleed buttons — Cancel as loud as
|
|
130
|
+
// Confirm. `flex-wrap` handles a long label by measurement instead.
|
|
131
|
+
"flex flex-wrap items-center justify-end gap-2",
|
|
123
132
|
className
|
|
124
133
|
)}
|
|
125
134
|
{...props}
|
|
@@ -97,7 +97,11 @@ const verticalSizePx: Record<DrawerSize, number> = {
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
const directionStyles = {
|
|
100
|
-
|
|
100
|
+
// `max-h-[85dvh]` belongs to the panel, not to a caller: with `height:auto`
|
|
101
|
+
// a tall panel would otherwise run off the top of a phone. A caller's own
|
|
102
|
+
// `max-h` cannot do this job — as a flex column the panel FILLS it, so the
|
|
103
|
+
// cap becomes a fixed height around short content.
|
|
104
|
+
bottom: "inset-x-0 bottom-0 mt-24 max-h-[85dvh] rounded-t-lg border-t",
|
|
101
105
|
top: "inset-x-0 top-0 mb-24 rounded-b-lg border-b",
|
|
102
106
|
right: "inset-y-0 right-0 h-full border-l",
|
|
103
107
|
left: "inset-y-0 left-0 h-full border-r",
|
|
@@ -297,7 +301,25 @@ const DrawerContent = React.forwardRef<
|
|
|
297
301
|
/>
|
|
298
302
|
)}
|
|
299
303
|
{isVertical && <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />}
|
|
300
|
-
{
|
|
304
|
+
{/*
|
|
305
|
+
Content padding lives HERE, not on each caller. `DialogContent` has
|
|
306
|
+
its own; this did not, so every surface that renders as a Dialog on
|
|
307
|
+
desktop and a Drawer on a phone lost its inset at the breakpoint —
|
|
308
|
+
section headings and values sat flush against the panel edge and read
|
|
309
|
+
as clipped. A default each caller must remember is a default nobody
|
|
310
|
+
applies.
|
|
311
|
+
|
|
312
|
+
The bottom inset is larger than the sides on purpose: it is what tells
|
|
313
|
+
a reader whether the list has ended or continues under the edge, and
|
|
314
|
+
on a phone it also clears the home indicator.
|
|
315
|
+
|
|
316
|
+
It owns the SCROLL but never the height: `flex-1` here filled the
|
|
317
|
+
panel and left the last row hundreds of pixels above the edge. Only
|
|
318
|
+
the panel's own `max-h` decides how tall the drawer gets.
|
|
319
|
+
*/}
|
|
320
|
+
<div className="min-h-0 overflow-y-auto overscroll-contain px-5 pb-[max(1.25rem,env(safe-area-inset-bottom))]">
|
|
321
|
+
{children}
|
|
322
|
+
</div>
|
|
301
323
|
</DrawerPrimitive.Content>
|
|
302
324
|
</DrawerPortal>
|
|
303
325
|
);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import * as React from 'react';
|
|
11
11
|
|
|
12
12
|
import { useIsMobile } from '../../../hooks';
|
|
13
|
+
import { cn } from '../../../lib/utils';
|
|
13
14
|
|
|
14
15
|
import {
|
|
15
16
|
Dialog,
|
|
@@ -74,20 +75,58 @@ ResponsiveSheet.displayName = "ResponsiveSheet"
|
|
|
74
75
|
// Content
|
|
75
76
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
76
77
|
|
|
78
|
+
/** Reading width of the panel. `md` suits a form or a detail card. */
|
|
79
|
+
type ResponsiveSheetWidth = "sm" | "md" | "lg" | "xl";
|
|
80
|
+
|
|
81
|
+
const WIDTH: Record<ResponsiveSheetWidth, string> = {
|
|
82
|
+
sm: "sm:max-w-sm",
|
|
83
|
+
md: "sm:max-w-md",
|
|
84
|
+
lg: "sm:max-w-lg",
|
|
85
|
+
xl: "sm:max-w-xl",
|
|
86
|
+
};
|
|
87
|
+
|
|
77
88
|
interface ResponsiveSheetContentProps {
|
|
78
89
|
children: React.ReactNode;
|
|
79
90
|
className?: string;
|
|
91
|
+
/** Panel width on a wide viewport. A phone always takes the full width. */
|
|
92
|
+
width?: ResponsiveSheetWidth;
|
|
80
93
|
}
|
|
81
94
|
|
|
82
|
-
|
|
95
|
+
/**
|
|
96
|
+
* The panel.
|
|
97
|
+
*
|
|
98
|
+
* It arrives sized, inset and centred — a caller passes CONTENT, not a layout.
|
|
99
|
+
* Every default here exists because a caller had to supply it by hand and the
|
|
100
|
+
* two callers we had disagreed: the same `w-[calc(100%-1rem)]` twice, one of
|
|
101
|
+
* them with a `flex flex-col` that made a short card stand full height.
|
|
102
|
+
*
|
|
103
|
+
* The phone case is where this matters. `DialogContent` carries its own
|
|
104
|
+
* padding and centring; `DrawerContent` does not, so anything that renders as
|
|
105
|
+
* both lost its layout at the breakpoint and nowhere else.
|
|
106
|
+
*/
|
|
107
|
+
function ResponsiveSheetContent({
|
|
108
|
+
children,
|
|
109
|
+
className,
|
|
110
|
+
width = "md",
|
|
111
|
+
}: ResponsiveSheetContentProps) {
|
|
83
112
|
const { isMobile } = React.useContext(ResponsiveSheetContext);
|
|
84
113
|
|
|
85
114
|
if (isMobile) {
|
|
86
|
-
//
|
|
87
|
-
|
|
115
|
+
// `height="auto"` hugs the content; the drawer's own `max-h` is the
|
|
116
|
+
// ceiling. A cap passed from here would become a fixed height instead,
|
|
117
|
+
// because the panel is a flex column and fills what it is given.
|
|
118
|
+
return (
|
|
119
|
+
<DrawerContent className={className} height="auto">
|
|
120
|
+
{children}
|
|
121
|
+
</DrawerContent>
|
|
122
|
+
);
|
|
88
123
|
}
|
|
89
124
|
|
|
90
|
-
return
|
|
125
|
+
return (
|
|
126
|
+
<DialogContent className={cn("w-[calc(100%-1rem)]", WIDTH[width], className)}>
|
|
127
|
+
{children}
|
|
128
|
+
</DialogContent>
|
|
129
|
+
);
|
|
91
130
|
}
|
|
92
131
|
ResponsiveSheetContent.displayName = "ResponsiveSheetContent"
|
|
93
132
|
|