@jinaan/uikit 0.1.4 → 0.1.5
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/card.d.ts.map +1 -1
- package/dist/code-block.d.ts.map +1 -1
- package/dist/dialog-motion.d.ts +18 -0
- package/dist/dialog-motion.d.ts.map +1 -0
- package/dist/dialog.d.ts +4 -3
- package/dist/dialog.d.ts.map +1 -1
- package/dist/dropdown-menu.d.ts.map +1 -1
- package/dist/empty-state.d.ts.map +1 -1
- package/dist/index.js +1092 -903
- package/dist/index.js.map +1 -1
- package/dist/select.d.ts +6 -1
- package/dist/select.d.ts.map +1 -1
- package/dist/table-surface.d.ts +5 -1
- package/dist/table-surface.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent-prompt.tsx +1 -1
- package/src/button.tsx +1 -1
- package/src/card.tsx +83 -40
- package/src/checkbox.tsx +4 -4
- package/src/code-block.tsx +22 -21
- package/src/dialog-motion.ts +38 -0
- package/src/dialog.tsx +288 -33
- package/src/dropdown-menu.tsx +5 -3
- package/src/empty-state.tsx +15 -18
- package/src/label.tsx +1 -1
- package/src/radio-group.tsx +2 -2
- package/src/select.tsx +50 -27
- package/src/table-surface.tsx +23 -1
- package/styles.css +75 -0
package/dist/select.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
2
|
+
import { type ComponentPropsWithoutRef } from "react";
|
|
2
3
|
export declare const Select: import("react").FC<SelectPrimitive.SelectProps>;
|
|
3
4
|
export declare const SelectGroup: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
4
5
|
export declare const SelectValue: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
5
|
-
export
|
|
6
|
+
export interface SelectTriggerProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {
|
|
7
|
+
/** `field` fills a form; `inline` mimics the compact app dropdown. */
|
|
8
|
+
variant?: "field" | "inline";
|
|
9
|
+
}
|
|
10
|
+
export declare const SelectTrigger: import("react").ForwardRefExoticComponent<SelectTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
6
11
|
export declare const SelectContent: import("react").ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
7
12
|
export declare const SelectItem: import("react").ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
8
13
|
export declare const SelectLabel: import("react").ForwardRefExoticComponent<Omit<SelectPrimitive.SelectLabelProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
package/dist/select.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../src/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../src/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,OAAO,CAAC;AAIf,eAAO,MAAM,MAAM,iDAAuB,CAAC;AAC3C,eAAO,MAAM,WAAW,6HAAwB,CAAC;AACjD,eAAO,MAAM,WAAW,8HAAwB,CAAC;AAEjD,MAAM,WAAW,kBAAmB,SAAQ,wBAAwB,CAClE,OAAO,eAAe,CAAC,OAAO,CAC/B;IACC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,kHAuBxB,CAAC;AAGH,eAAO,MAAM,aAAa,4LA+BzB,CAAC;AAGF,eAAO,MAAM,UAAU,yLAmBrB,CAAC;AAGH,eAAO,MAAM,WAAW,0LAStB,CAAC"}
|
package/dist/table-surface.d.ts
CHANGED
|
@@ -9,6 +9,10 @@ export interface TableSurfaceAction {
|
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
}
|
|
11
11
|
interface TableSurfaceProps {
|
|
12
|
+
/** Title above the header row. */
|
|
13
|
+
title?: ReactNode;
|
|
14
|
+
/** Supporting text under the title. */
|
|
15
|
+
description?: ReactNode;
|
|
12
16
|
/** Header row content (a single row of column cells). */
|
|
13
17
|
header?: ReactNode;
|
|
14
18
|
/** Panel content: the body table, or an empty / loading / error state. */
|
|
@@ -33,6 +37,6 @@ interface TableSurfaceProps {
|
|
|
33
37
|
* Colors come from the `--table-*` tokens and can be adjusted per surface with
|
|
34
38
|
* `tone` plus `headerClassName` / `panelClassName`.
|
|
35
39
|
*/
|
|
36
|
-
export declare function TableSurface({ header, children, action, tone, className, headerClassName, panelClassName, minHeight, }: TableSurfaceProps): import("react").JSX.Element;
|
|
40
|
+
export declare function TableSurface({ title, description, header, children, action, tone, className, headerClassName, panelClassName, minHeight, }: TableSurfaceProps): import("react").JSX.Element;
|
|
37
41
|
export {};
|
|
38
42
|
//# sourceMappingURL=table-surface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-surface.d.ts","sourceRoot":"","sources":["../src/table-surface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;IAC1D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,iBAAiB;IACzB,yDAAyD;IACzD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,GAAG,kBAAkB,CAAC;IACxC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAgB,EAChB,SAAS,EACT,eAAe,EACf,cAAc,EACd,SAAS,GACV,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"table-surface.d.ts","sourceRoot":"","sources":["../src/table-surface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;IAC1D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,iBAAiB;IACzB,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uCAAuC;IACvC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,yDAAyD;IACzD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,GAAG,kBAAkB,CAAC;IACxC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAgB,EAChB,SAAS,EACT,eAAe,EACf,cAAc,EACd,SAAS,GACV,EAAE,iBAAiB,+BA8DnB"}
|
package/package.json
CHANGED
package/src/agent-prompt.tsx
CHANGED
|
@@ -41,7 +41,7 @@ export function AgentPrompt({
|
|
|
41
41
|
{icon ?? <Robot className="size-3.5" weight="fill" />}
|
|
42
42
|
{tag}
|
|
43
43
|
</span>
|
|
44
|
-
<div className="flex w-full items-center gap-2 rounded-xl border border-line bg-surface py-2 pl-3 pr-2 shadow-sm">
|
|
44
|
+
<div className="mt-2 flex w-full items-center gap-2 rounded-xl border border-line bg-surface py-2 pl-3 pr-2 shadow-sm">
|
|
45
45
|
<Terminal className="size-4 shrink-0 text-subtle" aria-hidden />
|
|
46
46
|
<span className="truncate font-mono text-sm text-fg">{command}</span>
|
|
47
47
|
<Button
|
package/src/button.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import { Spinner } from "./spinner";
|
|
|
6
6
|
import { cn } from "./utils";
|
|
7
7
|
|
|
8
8
|
const buttonVariants = cva(
|
|
9
|
-
"relative inline-flex select-none items-center justify-center gap-[var(--control-gap)] whitespace-nowrap rounded-[var(--control-radius)] border border-transparent font-medium transition-[color,background-color,border-color,box-shadow,transform] duration-[120ms] active:scale-[0.97] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-
|
|
9
|
+
"relative inline-flex select-none items-center justify-center gap-[var(--control-gap)] whitespace-nowrap rounded-[var(--control-radius)] border border-transparent font-medium transition-[color,background-color,border-color,box-shadow,transform] duration-[120ms] active:scale-[0.97] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-line-strong disabled:pointer-events-none disabled:opacity-50",
|
|
10
10
|
{
|
|
11
11
|
variants: {
|
|
12
12
|
variant: {
|
package/src/card.tsx
CHANGED
|
@@ -1,61 +1,104 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
forwardRef,
|
|
4
|
+
isValidElement,
|
|
5
|
+
type HTMLAttributes,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
} from "react";
|
|
2
8
|
|
|
9
|
+
import { TableSurface } from "./table-surface";
|
|
3
10
|
import { cn } from "./utils";
|
|
4
11
|
|
|
12
|
+
function splitCardChildren(children: ReactNode): {
|
|
13
|
+
header: ReactNode;
|
|
14
|
+
body: ReactNode;
|
|
15
|
+
} {
|
|
16
|
+
const nodes = Children.toArray(children);
|
|
17
|
+
const headers = nodes.filter(
|
|
18
|
+
(child) => isValidElement(child) && child.type === CardHeader,
|
|
19
|
+
);
|
|
20
|
+
return {
|
|
21
|
+
header: headers.length > 0 ? <>{headers}</> : undefined,
|
|
22
|
+
body: nodes.filter((child) => !headers.includes(child)),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
5
26
|
export const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
6
|
-
({ className, ...props }, ref) =>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
({ className, children, ...props }, ref) => {
|
|
28
|
+
const { header, body } = splitCardChildren(children);
|
|
29
|
+
return (
|
|
30
|
+
<div ref={ref} {...props}>
|
|
31
|
+
<TableSurface className={cn("shadow-xs", className)} header={header}>
|
|
32
|
+
{body}
|
|
33
|
+
</TableSurface>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
},
|
|
16
37
|
);
|
|
17
38
|
Card.displayName = "Card";
|
|
18
39
|
|
|
19
|
-
export const CardHeader = forwardRef<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
export const CardHeader = forwardRef<
|
|
41
|
+
HTMLDivElement,
|
|
42
|
+
HTMLAttributes<HTMLDivElement>
|
|
43
|
+
>(({ className, ...props }, ref) => (
|
|
44
|
+
<div
|
|
45
|
+
ref={ref}
|
|
46
|
+
className={cn(
|
|
47
|
+
"flex flex-col gap-1 px-5 py-4",
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
));
|
|
28
53
|
CardHeader.displayName = "CardHeader";
|
|
29
54
|
|
|
30
|
-
export const CardTitle = forwardRef<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
55
|
+
export const CardTitle = forwardRef<
|
|
56
|
+
HTMLHeadingElement,
|
|
57
|
+
HTMLAttributes<HTMLHeadingElement>
|
|
58
|
+
>(({ className, ...props }, ref) => (
|
|
59
|
+
<h2
|
|
60
|
+
ref={ref}
|
|
61
|
+
className={cn("text-sm font-semibold text-fg", className)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
));
|
|
35
65
|
CardTitle.displayName = "CardTitle";
|
|
36
66
|
|
|
37
67
|
export const CardDescription = forwardRef<
|
|
38
68
|
HTMLParagraphElement,
|
|
39
69
|
HTMLAttributes<HTMLParagraphElement>
|
|
40
70
|
>(({ className, ...props }, ref) => (
|
|
41
|
-
<p
|
|
71
|
+
<p
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn(
|
|
74
|
+
"mt-1 border-t border-card-divider pt-2 text-sm text-muted",
|
|
75
|
+
"first:mt-0 first:border-t-0 first:pt-0",
|
|
76
|
+
className,
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
42
80
|
));
|
|
43
81
|
CardDescription.displayName = "CardDescription";
|
|
44
82
|
|
|
45
|
-
export const CardContent = forwardRef<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
83
|
+
export const CardContent = forwardRef<
|
|
84
|
+
HTMLDivElement,
|
|
85
|
+
HTMLAttributes<HTMLDivElement>
|
|
86
|
+
>(({ className, ...props }, ref) => (
|
|
87
|
+
<div ref={ref} className={cn("px-5 py-4", className)} {...props} />
|
|
88
|
+
));
|
|
50
89
|
CardContent.displayName = "CardContent";
|
|
51
90
|
|
|
52
|
-
export const CardFooter = forwardRef<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
91
|
+
export const CardFooter = forwardRef<
|
|
92
|
+
HTMLDivElement,
|
|
93
|
+
HTMLAttributes<HTMLDivElement>
|
|
94
|
+
>(({ className, ...props }, ref) => (
|
|
95
|
+
<div
|
|
96
|
+
ref={ref}
|
|
97
|
+
className={cn(
|
|
98
|
+
"flex items-center gap-3 border-t border-line px-5 py-3",
|
|
99
|
+
className,
|
|
100
|
+
)}
|
|
101
|
+
{...props}
|
|
102
|
+
/>
|
|
103
|
+
));
|
|
61
104
|
CardFooter.displayName = "CardFooter";
|
package/src/checkbox.tsx
CHANGED
|
@@ -11,16 +11,16 @@ export const Checkbox = forwardRef<
|
|
|
11
11
|
<CheckboxPrimitive.Root
|
|
12
12
|
ref={ref}
|
|
13
13
|
className={cn(
|
|
14
|
-
"peer size-4 shrink-0 rounded border border-line-strong bg-
|
|
14
|
+
"peer size-4 shrink-0 rounded border border-line-strong bg-transparent transition-colors",
|
|
15
15
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus/40",
|
|
16
16
|
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
17
|
-
"data-[state=checked]:border-primary
|
|
18
|
-
"data-[state=indeterminate]:border-primary
|
|
17
|
+
"data-[state=checked]:border-primary",
|
|
18
|
+
"data-[state=indeterminate]:border-primary",
|
|
19
19
|
className,
|
|
20
20
|
)}
|
|
21
21
|
{...props}
|
|
22
22
|
>
|
|
23
|
-
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-
|
|
23
|
+
<CheckboxPrimitive.Indicator className="btn-fill btn-inner-border flex size-full items-center justify-center rounded-[3px] border-0 bg-[var(--button-primary-bg)] text-[var(--button-primary-fg)] [--button-inner:var(--button-primary-inner)]">
|
|
24
24
|
{props.checked === "indeterminate" ? (
|
|
25
25
|
<Minus className="size-3" weight="bold" />
|
|
26
26
|
) : (
|
package/src/code-block.tsx
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Check, Copy } from "@phosphor-icons/react";
|
|
2
2
|
import { useState, type ReactNode } from "react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { cn } from "./utils";
|
|
4
|
+
import { TableSurface } from "./table-surface";
|
|
6
5
|
|
|
7
6
|
interface CodeBlockProps {
|
|
8
7
|
code: string;
|
|
@@ -26,28 +25,30 @@ export function CodeBlock({ code, label, className }: CodeBlockProps) {
|
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
return (
|
|
29
|
-
<
|
|
30
|
-
className={
|
|
31
|
-
|
|
32
|
-
className
|
|
33
|
-
|
|
28
|
+
<TableSurface
|
|
29
|
+
className={className}
|
|
30
|
+
header={
|
|
31
|
+
<div className="flex h-(--table-header-h) items-center px-(--table-pad-x) pr-28">
|
|
32
|
+
<span className="truncate text-[13px] font-medium text-table-header">
|
|
33
|
+
{label}
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
36
|
+
}
|
|
37
|
+
action={{
|
|
38
|
+
label: copied ? "Copied" : "Copy",
|
|
39
|
+
icon: copied ? (
|
|
40
|
+
<Check className="text-success" weight="bold" />
|
|
41
|
+
) : (
|
|
42
|
+
<Copy />
|
|
43
|
+
),
|
|
44
|
+
variant: "ghost",
|
|
45
|
+
onClick: copy,
|
|
46
|
+
}}
|
|
47
|
+
panelClassName="min-w-0"
|
|
34
48
|
>
|
|
35
|
-
<div className="flex items-center justify-between gap-2 border-b border-line px-3 py-2">
|
|
36
|
-
<span className="truncate text-xs font-medium text-subtle">{label}</span>
|
|
37
|
-
<Button
|
|
38
|
-
variant="ghost"
|
|
39
|
-
size="sm"
|
|
40
|
-
leadingIcon={
|
|
41
|
-
copied ? <Check className="text-success" weight="bold" /> : <Copy />
|
|
42
|
-
}
|
|
43
|
-
onClick={copy}
|
|
44
|
-
>
|
|
45
|
-
{copied ? "Copied" : "Copy"}
|
|
46
|
-
</Button>
|
|
47
|
-
</div>
|
|
48
49
|
<pre className="overflow-x-auto p-4 font-mono text-xs leading-relaxed text-fg">
|
|
49
50
|
<code>{code}</code>
|
|
50
51
|
</pre>
|
|
51
|
-
</
|
|
52
|
+
</TableSurface>
|
|
52
53
|
);
|
|
53
54
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface DialogOriginRect {
|
|
2
|
+
left: number;
|
|
3
|
+
top: number;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface DialogFlight {
|
|
9
|
+
dx: number;
|
|
10
|
+
dy: number;
|
|
11
|
+
sx: number;
|
|
12
|
+
sy: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function usable(rect: DialogOriginRect): boolean {
|
|
16
|
+
return rect.width > 0 && rect.height > 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function clampScale(value: number): number {
|
|
20
|
+
return Math.min(1, Math.max(0.1, value));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Computes the transform that places a centered dialog over its caller.
|
|
25
|
+
* `dx`/`dy` are viewport deltas; `sx`/`sy` scale the dialog down to the caller.
|
|
26
|
+
*/
|
|
27
|
+
export function computeDialogFlight(
|
|
28
|
+
origin: DialogOriginRect,
|
|
29
|
+
target: DialogOriginRect,
|
|
30
|
+
): DialogFlight | null {
|
|
31
|
+
if (!usable(origin) || !usable(target)) return null;
|
|
32
|
+
return {
|
|
33
|
+
dx: origin.left + origin.width / 2 - (target.left + target.width / 2),
|
|
34
|
+
dy: origin.top + origin.height / 2 - (target.top + target.height / 2),
|
|
35
|
+
sx: clampScale(origin.width / target.width),
|
|
36
|
+
sy: clampScale(origin.height / target.height),
|
|
37
|
+
};
|
|
38
|
+
}
|