@jinaan/uikit 0.1.30 → 0.1.32
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/dialog.d.ts +12 -1
- package/dist/dialog.d.ts.map +1 -1
- package/dist/index.js +696 -666
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/dialog.tsx +112 -64
- package/styles.css +87 -0
package/package.json
CHANGED
package/src/dialog.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
useRef,
|
|
10
10
|
useState,
|
|
11
11
|
type ComponentPropsWithoutRef,
|
|
12
|
+
type CSSProperties,
|
|
12
13
|
type ElementRef,
|
|
13
14
|
type HTMLAttributes,
|
|
14
15
|
} from "react";
|
|
@@ -256,77 +257,124 @@ function startDialogMotion(content: HTMLDivElement, retry = true) {
|
|
|
256
257
|
content.addEventListener("animationend", onEnd);
|
|
257
258
|
}
|
|
258
259
|
|
|
260
|
+
export interface DialogContentProps
|
|
261
|
+
extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
|
|
262
|
+
/** Vertical placement: centered (default) or anchored near the viewport top. */
|
|
263
|
+
placement?: "center" | "top";
|
|
264
|
+
/** Top edge offset for top placement. Defaults to 11dvh. */
|
|
265
|
+
topOffset?: string;
|
|
266
|
+
/**
|
|
267
|
+
* Entry/exit motion. `auto` flies from the caller when one is known, while
|
|
268
|
+
* `command` uses the compact spring used by command palettes.
|
|
269
|
+
*/
|
|
270
|
+
motion?: "auto" | "command";
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function dialogTopFallback(offset: string): string {
|
|
274
|
+
return offset.replace(/dvh\b/g, "vh");
|
|
275
|
+
}
|
|
276
|
+
|
|
259
277
|
export const DialogContent = forwardRef<
|
|
260
278
|
ElementRef<typeof DialogPrimitive.Content>,
|
|
261
|
-
|
|
262
|
-
>(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (ref) {
|
|
275
|
-
(ref as { current: HTMLDivElement | null }).current = node;
|
|
276
|
-
}
|
|
279
|
+
DialogContentProps
|
|
280
|
+
>(
|
|
281
|
+
(
|
|
282
|
+
{
|
|
283
|
+
className,
|
|
284
|
+
children,
|
|
285
|
+
placement = "center",
|
|
286
|
+
topOffset = "11dvh",
|
|
287
|
+
motion = "auto",
|
|
288
|
+
style,
|
|
289
|
+
onEscapeKeyDown,
|
|
290
|
+
onPointerDownOutside,
|
|
291
|
+
...props
|
|
277
292
|
},
|
|
278
|
-
|
|
279
|
-
)
|
|
293
|
+
ref,
|
|
294
|
+
) => {
|
|
295
|
+
const closing = useContext(DialogClosingContext);
|
|
296
|
+
const top = placement === "top";
|
|
297
|
+
const placementStyle: CSSProperties | undefined = top
|
|
298
|
+
? ({
|
|
299
|
+
"--dialog-top-offset": topOffset,
|
|
300
|
+
"--dialog-top-offset-fallback": dialogTopFallback(topOffset),
|
|
301
|
+
} as CSSProperties)
|
|
302
|
+
: undefined;
|
|
303
|
+
const requestClose = useContext(DialogRequestCloseContext);
|
|
304
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
305
|
+
const setRef = useCallback(
|
|
306
|
+
(node: HTMLDivElement | null) => {
|
|
307
|
+
contentRef.current = node;
|
|
308
|
+
if (node && motion === "auto") startDialogMotion(node);
|
|
309
|
+
if (typeof ref === "function") {
|
|
310
|
+
ref(node);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (ref) {
|
|
314
|
+
(ref as { current: HTMLDivElement | null }).current = node;
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
[motion, ref],
|
|
318
|
+
);
|
|
280
319
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
className={cn(
|
|
285
|
-
"fixed inset-0 z-50 overflow-hidden bg-overlay backdrop-blur-[3px] data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
286
|
-
!closing &&
|
|
287
|
-
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
288
|
-
closing && "opacity-0 transition-opacity duration-200",
|
|
289
|
-
)}
|
|
290
|
-
>
|
|
291
|
-
<span
|
|
292
|
-
aria-hidden="true"
|
|
293
|
-
className="dialog-noise pointer-events-none absolute inset-0"
|
|
294
|
-
/>
|
|
295
|
-
</DialogPrimitive.Overlay>
|
|
296
|
-
<div className="pointer-events-none fixed inset-0 z-50 flex items-center justify-center overflow-y-auto p-4">
|
|
297
|
-
<DialogPrimitive.Content
|
|
298
|
-
ref={setRef}
|
|
320
|
+
return (
|
|
321
|
+
<DialogPrimitive.Portal>
|
|
322
|
+
<DialogPrimitive.Overlay
|
|
299
323
|
className={cn(
|
|
300
|
-
"
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
"
|
|
304
|
-
className,
|
|
324
|
+
"fixed inset-0 z-50 overflow-hidden bg-overlay backdrop-blur-[3px] data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
325
|
+
!closing &&
|
|
326
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
327
|
+
closing && "opacity-0 transition-opacity duration-200",
|
|
305
328
|
)}
|
|
306
|
-
onEscapeKeyDown={(event) => {
|
|
307
|
-
onEscapeKeyDown?.(event);
|
|
308
|
-
if (event.defaultPrevented) return;
|
|
309
|
-
event.preventDefault();
|
|
310
|
-
requestClose();
|
|
311
|
-
}}
|
|
312
|
-
onPointerDownOutside={(event) => {
|
|
313
|
-
onPointerDownOutside?.(event);
|
|
314
|
-
if (event.defaultPrevented) return;
|
|
315
|
-
event.preventDefault();
|
|
316
|
-
requestClose();
|
|
317
|
-
}}
|
|
318
|
-
{...props}
|
|
319
329
|
>
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
+
<span
|
|
331
|
+
aria-hidden="true"
|
|
332
|
+
className="dialog-noise pointer-events-none absolute inset-0"
|
|
333
|
+
/>
|
|
334
|
+
</DialogPrimitive.Overlay>
|
|
335
|
+
<div
|
|
336
|
+
className={cn(
|
|
337
|
+
"pointer-events-none fixed inset-0 z-50 flex justify-center overflow-y-auto p-4",
|
|
338
|
+
top ? "items-start" : "items-center",
|
|
339
|
+
)}
|
|
340
|
+
>
|
|
341
|
+
<DialogPrimitive.Content
|
|
342
|
+
ref={setRef}
|
|
343
|
+
style={placementStyle ? { ...placementStyle, ...style } : style}
|
|
344
|
+
className={cn(
|
|
345
|
+
"dialog-content pointer-events-auto relative flex max-h-[min(85vh,44rem)] w-full max-w-[22.4rem] flex-col gap-0 overflow-hidden will-change-[transform,opacity]",
|
|
346
|
+
"rounded-2xl border border-(--dialog-shell-border) bg-(--dialog-shell-bg) pb-3 shadow-(--dialog-shell-shadow) sm:pb-4",
|
|
347
|
+
top && "dialog-anchor-top",
|
|
348
|
+
motion === "command" && "dialog-command-motion",
|
|
349
|
+
closing && "dialog-closing",
|
|
350
|
+
"focus:outline-none",
|
|
351
|
+
className,
|
|
352
|
+
)}
|
|
353
|
+
onEscapeKeyDown={(event) => {
|
|
354
|
+
onEscapeKeyDown?.(event);
|
|
355
|
+
if (event.defaultPrevented) return;
|
|
356
|
+
event.preventDefault();
|
|
357
|
+
requestClose();
|
|
358
|
+
}}
|
|
359
|
+
onPointerDownOutside={(event) => {
|
|
360
|
+
onPointerDownOutside?.(event);
|
|
361
|
+
if (event.defaultPrevented) return;
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
requestClose();
|
|
364
|
+
}}
|
|
365
|
+
{...props}
|
|
366
|
+
>
|
|
367
|
+
{children}
|
|
368
|
+
<DialogPrimitive.Close className="absolute right-3.5 top-3.5 z-10 rounded-sm text-subtle transition-colors hover:text-fg focus-visible:outline-none">
|
|
369
|
+
<X className="size-4" />
|
|
370
|
+
<span className="sr-only">Close</span>
|
|
371
|
+
</DialogPrimitive.Close>
|
|
372
|
+
</DialogPrimitive.Content>
|
|
373
|
+
</div>
|
|
374
|
+
</DialogPrimitive.Portal>
|
|
375
|
+
);
|
|
376
|
+
},
|
|
377
|
+
);
|
|
330
378
|
DialogContent.displayName = "DialogContent";
|
|
331
379
|
|
|
332
380
|
/**
|
package/styles.css
CHANGED
|
@@ -402,6 +402,24 @@
|
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
+
/*
|
|
406
|
+
* Dialog top anchoring: the panel's top edge stays at the requested offset
|
|
407
|
+
* (11dvh by default) regardless of content height. Older browsers without dvh
|
|
408
|
+
* fall back to the equivalent vh value. Unlayered so it wins over the default
|
|
409
|
+
* utility max-height.
|
|
410
|
+
*/
|
|
411
|
+
.dialog-anchor-top {
|
|
412
|
+
margin-top: calc(var(--dialog-top-offset-fallback, 11vh) - 1rem);
|
|
413
|
+
max-height: calc(100vh - var(--dialog-top-offset-fallback, 11vh) - 1rem);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
@supports (height: 100dvh) {
|
|
417
|
+
.dialog-anchor-top {
|
|
418
|
+
margin-top: calc(var(--dialog-top-offset, 11dvh) - 1rem);
|
|
419
|
+
max-height: calc(100dvh - var(--dialog-top-offset, 11dvh) - 1rem);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
405
423
|
/* Dialog motion + texture: caller-origin flight, centered fallback, noise. */
|
|
406
424
|
@keyframes dialog-fly-in {
|
|
407
425
|
from {
|
|
@@ -462,6 +480,75 @@
|
|
|
462
480
|
will-change: transform, opacity;
|
|
463
481
|
}
|
|
464
482
|
|
|
483
|
+
/*
|
|
484
|
+
* Command-palette motion: the panel springs from a smaller, slightly
|
|
485
|
+
* up-and-left pose. Kept separate from the caller-flight so command dialogs
|
|
486
|
+
* do not visibly travel from the trigger.
|
|
487
|
+
*/
|
|
488
|
+
@keyframes dialog-command-in {
|
|
489
|
+
from {
|
|
490
|
+
opacity: 1;
|
|
491
|
+
transform: translate(-27.4%, -6.3%) scale(0.85);
|
|
492
|
+
}
|
|
493
|
+
to {
|
|
494
|
+
opacity: 1;
|
|
495
|
+
transform: translate(0, 0) scale(1);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
@keyframes dialog-command-out {
|
|
500
|
+
from {
|
|
501
|
+
opacity: 1;
|
|
502
|
+
transform: translate(0, 0) scale(1);
|
|
503
|
+
}
|
|
504
|
+
to {
|
|
505
|
+
opacity: 1;
|
|
506
|
+
transform: translate(-26.6%, -11.1%) scale(0.85);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.dialog-command-motion {
|
|
511
|
+
transform-origin: center;
|
|
512
|
+
animation: dialog-command-in 500ms
|
|
513
|
+
linear(
|
|
514
|
+
0 0%,
|
|
515
|
+
0.1495 6.25%,
|
|
516
|
+
0.3955 12.5%,
|
|
517
|
+
0.6061 18.75%,
|
|
518
|
+
0.7562 25%,
|
|
519
|
+
0.8542 31.25%,
|
|
520
|
+
0.9148 37.5%,
|
|
521
|
+
0.9512 43.75%,
|
|
522
|
+
0.9724 50%,
|
|
523
|
+
0.9846 56.25%,
|
|
524
|
+
0.9914 62.5%,
|
|
525
|
+
0.9953 68.75%,
|
|
526
|
+
0.9974 75%,
|
|
527
|
+
0.9986 81.25%,
|
|
528
|
+
0.9992 87.5%,
|
|
529
|
+
1 93.75%,
|
|
530
|
+
1 100%
|
|
531
|
+
)
|
|
532
|
+
both;
|
|
533
|
+
backface-visibility: hidden;
|
|
534
|
+
will-change: transform;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.dialog-command-motion.dialog-closing {
|
|
538
|
+
animation: dialog-command-out 250ms
|
|
539
|
+
linear(
|
|
540
|
+
0 0%,
|
|
541
|
+
0.4615 14.2857%,
|
|
542
|
+
0.8176 28.5714%,
|
|
543
|
+
0.9471 42.8571%,
|
|
544
|
+
0.9858 57.1429%,
|
|
545
|
+
0.9964 71.4286%,
|
|
546
|
+
0.9991 85.7143%,
|
|
547
|
+
1 100%
|
|
548
|
+
)
|
|
549
|
+
both;
|
|
550
|
+
}
|
|
551
|
+
|
|
465
552
|
.dialog-noise {
|
|
466
553
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
|
|
467
554
|
background-size: 160px 160px;
|