@bearmenu/ui 0.8.37 → 0.8.39
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/{chunk-XLHMF6F5.js → chunk-NF5UMLSL.js} +17 -6
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/command.d.ts +3 -3
- package/dist/components/drawer.d.ts +8 -1
- package/dist/components/drawer.js +1 -1
- package/dist/components/empty-state.d.ts +26 -1
- package/dist/components/empty-state.js +41 -17
- package/dist/components/pan-zoom-viewport.d.ts +25 -3
- package/dist/components/pan-zoom-viewport.js +43 -21
- package/dist/components/responsive-overlay.js +16 -20
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/drawer.test.tsx +55 -0
- package/src/components/drawer.tsx +33 -11
- package/src/components/empty-state.stories.tsx +14 -0
- package/src/components/empty-state.test.tsx +60 -0
- package/src/components/empty-state.tsx +66 -21
- package/src/components/floor-tokens.stories.tsx +223 -0
- package/src/components/pan-zoom-viewport.stories.tsx +21 -1
- package/src/components/pan-zoom-viewport.test.tsx +63 -14
- package/src/components/pan-zoom-viewport.tsx +82 -27
- package/src/components/responsive-overlay.test.tsx +40 -0
- package/src/components/responsive-overlay.tsx +13 -10
- package/src/globals.css +161 -0
|
@@ -4,20 +4,30 @@ import * as React from 'react';
|
|
|
4
4
|
import { Drawer as Drawer$1 } from 'vaul';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var DrawerContext = React.createContext({
|
|
8
|
+
direction: "bottom",
|
|
9
|
+
modal: true
|
|
10
|
+
});
|
|
8
11
|
var Drawer = (_a) => {
|
|
9
12
|
var _b = _a, {
|
|
10
13
|
shouldScaleBackground = false,
|
|
11
|
-
direction = "bottom"
|
|
14
|
+
direction = "bottom",
|
|
15
|
+
modal = true,
|
|
16
|
+
autoFocus = true
|
|
12
17
|
} = _b, props = __objRest(_b, [
|
|
13
18
|
"shouldScaleBackground",
|
|
14
|
-
"direction"
|
|
19
|
+
"direction",
|
|
20
|
+
"modal",
|
|
21
|
+
"autoFocus"
|
|
15
22
|
]);
|
|
16
|
-
|
|
23
|
+
const context = React.useMemo(() => ({ direction, modal }), [direction, modal]);
|
|
24
|
+
return /* @__PURE__ */ jsx(DrawerContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
|
|
17
25
|
Drawer$1.Root,
|
|
18
26
|
__spreadValues({
|
|
19
27
|
shouldScaleBackground,
|
|
20
|
-
direction
|
|
28
|
+
direction,
|
|
29
|
+
modal,
|
|
30
|
+
autoFocus
|
|
21
31
|
}, props)
|
|
22
32
|
) });
|
|
23
33
|
};
|
|
@@ -39,7 +49,7 @@ var DrawerOverlay = React.forwardRef((_a, ref) => {
|
|
|
39
49
|
DrawerOverlay.displayName = Drawer$1.Overlay.displayName;
|
|
40
50
|
var DrawerContent = React.forwardRef((_a, ref) => {
|
|
41
51
|
var _b = _a, { className, variant = "flush", showHandle, overlayClassName, children } = _b, props = __objRest(_b, ["className", "variant", "showHandle", "overlayClassName", "children"]);
|
|
42
|
-
const direction = React.useContext(
|
|
52
|
+
const { direction, modal } = React.useContext(DrawerContext);
|
|
43
53
|
const isVertical = direction === "top" || direction === "bottom";
|
|
44
54
|
const handleEnabled = showHandle != null ? showHandle : direction === "bottom";
|
|
45
55
|
const positionClasses = direction === "bottom" ? "inset-x-0 bottom-0 flex-col rounded-t-2xl border-t [padding-bottom:max(env(safe-area-inset-bottom),0px)]" : direction === "top" ? "inset-x-0 top-0 flex-col rounded-b-2xl border-b [padding-top:max(env(safe-area-inset-top),0px)]" : direction === "left" ? "inset-y-0 left-0 h-full w-3/4 max-w-sm flex-col rounded-r-2xl border-r [padding-left:max(env(safe-area-inset-left),0px)]" : "inset-y-0 right-0 h-full w-3/4 max-w-sm flex-col rounded-l-2xl border-l [padding-right:max(env(safe-area-inset-right),0px)]";
|
|
@@ -50,6 +60,7 @@ var DrawerContent = React.forwardRef((_a, ref) => {
|
|
|
50
60
|
__spreadProps(__spreadValues({
|
|
51
61
|
ref,
|
|
52
62
|
"data-slot": "drawer-content",
|
|
63
|
+
"aria-modal": modal ? true : void 0,
|
|
53
64
|
className: cn(
|
|
54
65
|
"fixed z-[1000] flex border-border bg-card shadow-[var(--shadow-overlay)]",
|
|
55
66
|
positionClasses,
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "default" | "secondary" | "success" | "warning" | "destructive" | "outline" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | "completed" | "assignee" | "softSuccess" | "softWarning" | "softDestructive" | "softNeutral" | null | undefined;
|
|
8
8
|
size?: "status" | "chip" | null | undefined;
|
|
9
9
|
live?: boolean | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -3,8 +3,8 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
7
|
-
size?: "
|
|
6
|
+
variant?: "default" | "link" | "secondary" | "warning" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
|
|
7
|
+
size?: "icon" | "default" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
8
8
|
fullWidth?: boolean | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -28,7 +28,7 @@ declare const CommandInput: React.ForwardRefExoticComponent<Omit<Omit<Pick<Pick<
|
|
|
28
28
|
ref?: React.Ref<HTMLInputElement>;
|
|
29
29
|
} & {
|
|
30
30
|
asChild?: boolean;
|
|
31
|
-
}, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "
|
|
31
|
+
}, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "value" | "onChange" | "type"> & {
|
|
32
32
|
value?: string;
|
|
33
33
|
onValueChange?: (search: string) => void;
|
|
34
34
|
} & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -64,7 +64,7 @@ declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
|
|
|
64
64
|
ref?: React.Ref<HTMLDivElement>;
|
|
65
65
|
} & {
|
|
66
66
|
asChild?: boolean;
|
|
67
|
-
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "
|
|
67
|
+
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "value" | "heading"> & {
|
|
68
68
|
heading?: React.ReactNode;
|
|
69
69
|
value?: string;
|
|
70
70
|
forceMount?: boolean;
|
|
@@ -82,7 +82,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
|
|
|
82
82
|
ref?: React.Ref<HTMLDivElement>;
|
|
83
83
|
} & {
|
|
84
84
|
asChild?: boolean;
|
|
85
|
-
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "
|
|
85
|
+
}, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "value" | "onSelect" | "disabled"> & {
|
|
86
86
|
disabled?: boolean;
|
|
87
87
|
onSelect?: (value: string) => void;
|
|
88
88
|
value?: string;
|
|
@@ -4,8 +4,15 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* `autoFocus` defaults to `true` here, where vaul defaults it to `false`.
|
|
9
|
+
* vaul's default cancels Radix's open auto-focus, so focus never enters the
|
|
10
|
+
* sheet, Radix's FocusScope never engages, and Tab walks the page behind a
|
|
11
|
+
* modal drawer. A caller that must not move focus on open passes
|
|
12
|
+
* `autoFocus={false}`.
|
|
13
|
+
*/
|
|
7
14
|
declare const Drawer: {
|
|
8
|
-
({ shouldScaleBackground, direction, ...props }: React.ComponentProps<typeof Drawer$1.Root>): react_jsx_runtime.JSX.Element;
|
|
15
|
+
({ shouldScaleBackground, direction, modal, autoFocus, ...props }: React.ComponentProps<typeof Drawer$1.Root>): react_jsx_runtime.JSX.Element;
|
|
9
16
|
displayName: string;
|
|
10
17
|
};
|
|
11
18
|
declare const DrawerTrigger: React.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from '../chunk-
|
|
1
|
+
export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from '../chunk-NF5UMLSL.js';
|
|
2
2
|
import '../chunk-FEK5XGZW.js';
|
|
3
3
|
import '../chunk-MMUBH76A.js';
|
|
@@ -4,6 +4,7 @@ type EmptyStateAction = {
|
|
|
4
4
|
label: string;
|
|
5
5
|
onClick: () => void;
|
|
6
6
|
};
|
|
7
|
+
type EmptyStateVariant = "default" | "search" | "error";
|
|
7
8
|
interface EmptyStateProps {
|
|
8
9
|
title: string;
|
|
9
10
|
description: string;
|
|
@@ -11,10 +12,34 @@ interface EmptyStateProps {
|
|
|
11
12
|
illustration?: React.ReactNode;
|
|
12
13
|
action?: EmptyStateAction;
|
|
13
14
|
secondaryAction?: EmptyStateAction;
|
|
14
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The primary action's style. Defaults by variant: `outline` for `error`
|
|
17
|
+
* (try again) and `search` (clear filters) — a recovery step, not the page's
|
|
18
|
+
* main call to action — and a filled `default` for the plain empty state,
|
|
19
|
+
* where the action is usually "create the first one".
|
|
20
|
+
*/
|
|
21
|
+
actionVariant?: "default" | "outline";
|
|
22
|
+
variant?: EmptyStateVariant;
|
|
15
23
|
size?: "sm" | "md" | "lg";
|
|
24
|
+
/**
|
|
25
|
+
* `card` draws the booking pages' whole-body state card (reports/02-p4,
|
|
26
|
+
* calendar/02-c2): a 16px-radius card surface with the resting card shadow.
|
|
27
|
+
* `none` (the default) leaves the surface to the container it sits in.
|
|
28
|
+
*/
|
|
29
|
+
surface?: "none" | "card";
|
|
16
30
|
className?: string;
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* EmptyState — an icon tile, a title, one line of body and an optional action,
|
|
34
|
+
* spaced as the booking frames draw them (reports/02-p4, calendar/02-c2): a
|
|
35
|
+
* 64px tile (72px from `sm`) with a 28px glyph, 16px to the title, 12px from
|
|
36
|
+
* title to body, 16px from body to the action. The action is full-width on a
|
|
37
|
+
* phone and hugs its label from `sm`.
|
|
38
|
+
*
|
|
39
|
+
* The error variant says "error" with its glyph and its tile's wash, not by
|
|
40
|
+
* painting the title and body red: red body copy is both harder to read and
|
|
41
|
+
* louder than a load failure the user can retry.
|
|
42
|
+
*/
|
|
18
43
|
declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
|
|
19
44
|
declare const SearchEmptyState: React.ForwardRefExoticComponent<Omit<EmptyStateProps, "icon" | "variant"> & React.RefAttributes<HTMLDivElement>>;
|
|
20
45
|
declare const ErrorEmptyState: React.ForwardRefExoticComponent<Omit<EmptyStateProps, "icon" | "variant"> & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -5,7 +5,7 @@ import { Text } from '../chunk-ZLMRVBD7.js';
|
|
|
5
5
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
6
|
import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
7
7
|
import * as React from 'react';
|
|
8
|
-
import {
|
|
8
|
+
import { AlertCircle, Search, FileX } from 'lucide-react';
|
|
9
9
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
10
10
|
|
|
11
11
|
var sizeStyles = {
|
|
@@ -13,6 +13,16 @@ var sizeStyles = {
|
|
|
13
13
|
md: "py-12 px-6",
|
|
14
14
|
lg: "py-16 px-8"
|
|
15
15
|
};
|
|
16
|
+
var DEFAULT_ACTION_VARIANT = {
|
|
17
|
+
default: "default",
|
|
18
|
+
search: "outline",
|
|
19
|
+
error: "outline"
|
|
20
|
+
};
|
|
21
|
+
var DEFAULT_ICON = {
|
|
22
|
+
default: /* @__PURE__ */ jsx(FileX, { className: "text-muted-foreground", "aria-hidden": true }),
|
|
23
|
+
search: /* @__PURE__ */ jsx(Search, { className: "text-muted-foreground", "aria-hidden": true }),
|
|
24
|
+
error: /* @__PURE__ */ jsx(AlertCircle, { className: "text-destructive", "aria-hidden": true })
|
|
25
|
+
};
|
|
16
26
|
var EmptyState = React.forwardRef(
|
|
17
27
|
(_a, ref) => {
|
|
18
28
|
var _b = _a, {
|
|
@@ -22,8 +32,10 @@ var EmptyState = React.forwardRef(
|
|
|
22
32
|
illustration,
|
|
23
33
|
action,
|
|
24
34
|
secondaryAction,
|
|
35
|
+
actionVariant,
|
|
25
36
|
variant = "default",
|
|
26
37
|
size = "md",
|
|
38
|
+
surface = "none",
|
|
27
39
|
className
|
|
28
40
|
} = _b, props = __objRest(_b, [
|
|
29
41
|
"title",
|
|
@@ -32,21 +44,12 @@ var EmptyState = React.forwardRef(
|
|
|
32
44
|
"illustration",
|
|
33
45
|
"action",
|
|
34
46
|
"secondaryAction",
|
|
47
|
+
"actionVariant",
|
|
35
48
|
"variant",
|
|
36
49
|
"size",
|
|
50
|
+
"surface",
|
|
37
51
|
"className"
|
|
38
52
|
]);
|
|
39
|
-
const getDefaultIcon = () => {
|
|
40
|
-
switch (variant) {
|
|
41
|
-
case "search":
|
|
42
|
-
return /* @__PURE__ */ jsx(Search, { className: "h-12 w-12 text-muted-foreground/50" });
|
|
43
|
-
case "error":
|
|
44
|
-
return /* @__PURE__ */ jsx(AlertCircle, { className: "h-12 w-12 text-destructive/50" });
|
|
45
|
-
default:
|
|
46
|
-
return /* @__PURE__ */ jsx(FileX, { className: "h-12 w-12 text-muted-foreground/50" });
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
const textColor = variant === "error" ? "destructive" : "muted";
|
|
50
53
|
return /* @__PURE__ */ jsxs(
|
|
51
54
|
"div",
|
|
52
55
|
__spreadProps(__spreadValues({
|
|
@@ -55,15 +58,36 @@ var EmptyState = React.forwardRef(
|
|
|
55
58
|
className: cn(
|
|
56
59
|
"flex flex-col items-center justify-center text-center",
|
|
57
60
|
sizeStyles[size],
|
|
61
|
+
surface === "card" && "rounded-2xl border border-border bg-card shadow-[var(--shadow-card)]",
|
|
58
62
|
className
|
|
59
63
|
)
|
|
60
64
|
}, props), {
|
|
61
65
|
children: [
|
|
62
|
-
illustration ? /* @__PURE__ */ jsx("div", { className: "mb-6", children: illustration }) : /* @__PURE__ */ jsx(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
illustration ? /* @__PURE__ */ jsx("div", { className: "mb-6", children: illustration }) : /* @__PURE__ */ jsx(
|
|
67
|
+
"span",
|
|
68
|
+
{
|
|
69
|
+
"data-slot": "empty-state-icon",
|
|
70
|
+
className: cn(
|
|
71
|
+
// The glyph size is the tile's, whatever size the caller's icon
|
|
72
|
+
// node asked for — a 40px icon in a 64px tile has no margin.
|
|
73
|
+
"mb-4 flex size-16 shrink-0 items-center justify-center rounded-2xl border border-border shadow-sm sm:size-18 [&_svg]:size-7",
|
|
74
|
+
variant === "error" ? "bg-destructive/5" : "bg-card"
|
|
75
|
+
),
|
|
76
|
+
children: icon != null ? icon : DEFAULT_ICON[variant]
|
|
77
|
+
}
|
|
78
|
+
),
|
|
79
|
+
/* @__PURE__ */ jsx(Text, { as: "h3", weight: "semibold", className: "text-lg", children: title }),
|
|
80
|
+
description ? /* @__PURE__ */ jsx(Text, { as: "p", color: "muted", className: "mt-3 max-w-md text-sm", children: description }) : null,
|
|
81
|
+
(action || secondaryAction) && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex w-full flex-col gap-3 sm:w-auto sm:flex-row sm:items-center", children: [
|
|
82
|
+
action && /* @__PURE__ */ jsx(
|
|
83
|
+
Button,
|
|
84
|
+
{
|
|
85
|
+
onClick: action.onClick,
|
|
86
|
+
variant: actionVariant != null ? actionVariant : DEFAULT_ACTION_VARIANT[variant],
|
|
87
|
+
className: "glass-hover",
|
|
88
|
+
children: action.label
|
|
89
|
+
}
|
|
90
|
+
),
|
|
67
91
|
secondaryAction && /* @__PURE__ */ jsx(Button, { onClick: secondaryAction.onClick, variant: "outline", className: "glass-hover", children: secondaryAction.label })
|
|
68
92
|
] })
|
|
69
93
|
]
|
|
@@ -23,7 +23,9 @@ import * as React from 'react';
|
|
|
23
23
|
* - Keyboard, with the viewport focused: arrows pan (Shift for four times the
|
|
24
24
|
* step); `+` / `-` zoom and `0` fits, from anywhere inside it. Tabbing onto
|
|
25
25
|
* a table that sits off screen pans it into view.
|
|
26
|
-
* - The + / − / Fit controls
|
|
26
|
+
* - The + / − / Fit controls: a raised card 12px in from the bottom-right
|
|
27
|
+
* corner, 44 × 44 per button. Fit and the pan bounds keep the content clear
|
|
28
|
+
* of them.
|
|
27
29
|
*
|
|
28
30
|
* The min-scale floor: `Fit` never shrinks below `minScale`. On a phone the
|
|
29
31
|
* plan would otherwise fit at a size no finger can hit, so below the floor it
|
|
@@ -96,8 +98,18 @@ type PanZoomViewportProps = Omit<React.HTMLAttributes<HTMLDivElement>, "children
|
|
|
96
98
|
zoomStep?: number;
|
|
97
99
|
/** One arrow press, in viewport px. Default 48. */
|
|
98
100
|
panStep?: number;
|
|
99
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* The air Fit leaves around the content, and how far past it a pan may go.
|
|
103
|
+
* Default 24. With `controls` on, the side the control stack would cover
|
|
104
|
+
* (right or bottom, whichever costs the fit less) is widened to clear it.
|
|
105
|
+
*/
|
|
100
106
|
fitPadding?: number;
|
|
107
|
+
/**
|
|
108
|
+
* Where fitted content sits vertically when it is shorter than the
|
|
109
|
+
* viewport: `center` (default), or `top` — pinned under the top padding,
|
|
110
|
+
* as a phone shows a plan.
|
|
111
|
+
*/
|
|
112
|
+
fitAlign?: "center" | "top";
|
|
101
113
|
/** Render the + / − / Fit controls. Default true. */
|
|
102
114
|
controls?: boolean;
|
|
103
115
|
/** Called with every transform — gestures included, so keep it cheap. */
|
|
@@ -122,8 +134,18 @@ declare const PanZoomViewport: React.ForwardRefExoticComponent<Omit<React.HTMLAt
|
|
|
122
134
|
zoomStep?: number;
|
|
123
135
|
/** One arrow press, in viewport px. Default 48. */
|
|
124
136
|
panStep?: number;
|
|
125
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* The air Fit leaves around the content, and how far past it a pan may go.
|
|
139
|
+
* Default 24. With `controls` on, the side the control stack would cover
|
|
140
|
+
* (right or bottom, whichever costs the fit less) is widened to clear it.
|
|
141
|
+
*/
|
|
126
142
|
fitPadding?: number;
|
|
143
|
+
/**
|
|
144
|
+
* Where fitted content sits vertically when it is shorter than the
|
|
145
|
+
* viewport: `center` (default), or `top` — pinned under the top padding,
|
|
146
|
+
* as a phone shows a plan.
|
|
147
|
+
*/
|
|
148
|
+
fitAlign?: "center" | "top";
|
|
127
149
|
/** Render the + / − / Fit controls. Default true. */
|
|
128
150
|
controls?: boolean;
|
|
129
151
|
/** Called with every transform — gestures included, so keep it cheap. */
|
|
@@ -12,12 +12,21 @@ var DRAG_THRESHOLD = 4;
|
|
|
12
12
|
var MAX_WHEEL_ZOOM_DELTA = 25;
|
|
13
13
|
var WHEEL_ZOOM_SPEED = 0.01;
|
|
14
14
|
var EPSILON = 1e-3;
|
|
15
|
+
var CONTROLS_RESERVE_X = 12 + 44 + 8;
|
|
16
|
+
var CONTROLS_RESERVE_Y = 12 + 130 + 8;
|
|
15
17
|
function clamp(value, min, max) {
|
|
16
18
|
return Math.min(max, Math.max(min, value));
|
|
17
19
|
}
|
|
18
|
-
function clampAxis(offset, content, viewport,
|
|
19
|
-
|
|
20
|
-
return
|
|
20
|
+
function clampAxis(offset, content, viewport, start, end, align) {
|
|
21
|
+
const room = viewport - start - end;
|
|
22
|
+
if (content <= room) return align === "start" ? start : start + (room - content) / 2;
|
|
23
|
+
return clamp(offset, viewport - content - end, start);
|
|
24
|
+
}
|
|
25
|
+
function fitScale(viewport, insets, contentWidth, contentHeight) {
|
|
26
|
+
return Math.min(
|
|
27
|
+
(viewport.width - insets.left - insets.right) / contentWidth,
|
|
28
|
+
(viewport.height - insets.top - insets.bottom) / contentHeight
|
|
29
|
+
);
|
|
21
30
|
}
|
|
22
31
|
function distance(a, b) {
|
|
23
32
|
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
@@ -40,6 +49,7 @@ var PanZoomViewport = React.forwardRef(
|
|
|
40
49
|
zoomStep = 1.25,
|
|
41
50
|
panStep = 48,
|
|
42
51
|
fitPadding = 24,
|
|
52
|
+
fitAlign = "center",
|
|
43
53
|
controls = true,
|
|
44
54
|
onTransformChange,
|
|
45
55
|
apiRef,
|
|
@@ -55,6 +65,7 @@ var PanZoomViewport = React.forwardRef(
|
|
|
55
65
|
"zoomStep",
|
|
56
66
|
"panStep",
|
|
57
67
|
"fitPadding",
|
|
68
|
+
"fitAlign",
|
|
58
69
|
"controls",
|
|
59
70
|
"onTransformChange",
|
|
60
71
|
"apiRef",
|
|
@@ -79,26 +90,37 @@ var PanZoomViewport = React.forwardRef(
|
|
|
79
90
|
onTransformChangeRef.current = onTransformChange;
|
|
80
91
|
zoomLevelRef.current = labels.zoomLevel;
|
|
81
92
|
});
|
|
93
|
+
const insets = React.useMemo(() => {
|
|
94
|
+
const base = { top: fitPadding, right: fitPadding, bottom: fitPadding, left: fitPadding };
|
|
95
|
+
if (!controls || !viewport) return base;
|
|
96
|
+
const right = __spreadProps(__spreadValues({}, base), { right: Math.max(fitPadding, CONTROLS_RESERVE_X) });
|
|
97
|
+
const bottom = __spreadProps(__spreadValues({}, base), { bottom: Math.max(fitPadding, CONTROLS_RESERVE_Y) });
|
|
98
|
+
return fitScale(viewport, bottom, contentWidth, contentHeight) > fitScale(viewport, right, contentWidth, contentHeight) ? bottom : right;
|
|
99
|
+
}, [controls, viewport, fitPadding, contentWidth, contentHeight]);
|
|
82
100
|
const clampTransform = React.useCallback(
|
|
83
101
|
(next) => {
|
|
84
102
|
if (!viewport || viewport.width <= 0 || viewport.height <= 0) return next;
|
|
85
103
|
const scale = clamp(next.scale, minScale, maxScale);
|
|
86
104
|
return {
|
|
87
105
|
scale,
|
|
88
|
-
x: clampAxis(next.x, contentWidth * scale, viewport.width,
|
|
89
|
-
y: clampAxis(
|
|
106
|
+
x: clampAxis(next.x, contentWidth * scale, viewport.width, insets.left, insets.right, "center"),
|
|
107
|
+
y: clampAxis(
|
|
108
|
+
next.y,
|
|
109
|
+
contentHeight * scale,
|
|
110
|
+
viewport.height,
|
|
111
|
+
insets.top,
|
|
112
|
+
insets.bottom,
|
|
113
|
+
fitAlign === "top" ? "start" : "center"
|
|
114
|
+
)
|
|
90
115
|
};
|
|
91
116
|
},
|
|
92
|
-
[viewport, minScale, maxScale, contentWidth, contentHeight,
|
|
117
|
+
[viewport, minScale, maxScale, contentWidth, contentHeight, insets, fitAlign]
|
|
93
118
|
);
|
|
94
119
|
const fitted = React.useCallback(() => {
|
|
95
120
|
if (!viewport || viewport.width <= 0 || viewport.height <= 0) return null;
|
|
96
|
-
const scale =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
);
|
|
100
|
-
return clampTransform({ scale, x: fitPadding, y: fitPadding });
|
|
101
|
-
}, [viewport, fitPadding, contentWidth, contentHeight, clampTransform]);
|
|
121
|
+
const scale = fitScale(viewport, insets, contentWidth, contentHeight);
|
|
122
|
+
return clampTransform({ scale, x: insets.left, y: insets.top });
|
|
123
|
+
}, [viewport, insets, contentWidth, contentHeight, clampTransform]);
|
|
102
124
|
const commit = React.useCallback(
|
|
103
125
|
(next, options) => {
|
|
104
126
|
var _a2;
|
|
@@ -382,13 +404,13 @@ var PanZoomViewport = React.forwardRef(
|
|
|
382
404
|
if (pressing.current || event.target === event.currentTarget) return;
|
|
383
405
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
384
406
|
const rect = event.target.getBoundingClientRect();
|
|
385
|
-
const margin = fitPadding;
|
|
386
407
|
let dx = 0;
|
|
387
408
|
let dy = 0;
|
|
388
|
-
if (rect.left < bounds.left +
|
|
389
|
-
else if (rect.right > bounds.right -
|
|
390
|
-
if (rect.top < bounds.top +
|
|
391
|
-
else if (rect.bottom > bounds.bottom -
|
|
409
|
+
if (rect.left < bounds.left + insets.left) dx = bounds.left + insets.left - rect.left;
|
|
410
|
+
else if (rect.right > bounds.right - insets.right) dx = bounds.right - insets.right - rect.right;
|
|
411
|
+
if (rect.top < bounds.top + insets.top) dy = bounds.top + insets.top - rect.top;
|
|
412
|
+
else if (rect.bottom > bounds.bottom - insets.bottom)
|
|
413
|
+
dy = bounds.bottom - insets.bottom - rect.bottom;
|
|
392
414
|
if (dx !== 0 || dy !== 0) panBy(dx, dy);
|
|
393
415
|
};
|
|
394
416
|
const scaledWidth = contentWidth * transform.scale;
|
|
@@ -479,14 +501,14 @@ var PanZoomViewport = React.forwardRef(
|
|
|
479
501
|
orientation: "vertical",
|
|
480
502
|
"aria-label": labels.controls,
|
|
481
503
|
"data-slot": "pan-zoom-viewport-controls",
|
|
482
|
-
className: "absolute bottom-3 right-3 rounded-xl bg-card shadow-
|
|
504
|
+
className: "absolute bottom-3 right-3 rounded-xl bg-card shadow-[var(--shadow-card)]",
|
|
483
505
|
children: [
|
|
484
506
|
/* @__PURE__ */ jsx(
|
|
485
507
|
Button,
|
|
486
508
|
{
|
|
487
509
|
type: "button",
|
|
488
510
|
variant: "outline",
|
|
489
|
-
size: "icon
|
|
511
|
+
size: "icon",
|
|
490
512
|
"aria-label": labels.zoomIn,
|
|
491
513
|
disabled: atMax,
|
|
492
514
|
onClick: zoomIn,
|
|
@@ -498,7 +520,7 @@ var PanZoomViewport = React.forwardRef(
|
|
|
498
520
|
{
|
|
499
521
|
type: "button",
|
|
500
522
|
variant: "outline",
|
|
501
|
-
size: "icon
|
|
523
|
+
size: "icon",
|
|
502
524
|
"aria-label": labels.zoomOut,
|
|
503
525
|
disabled: atMin,
|
|
504
526
|
onClick: zoomOut,
|
|
@@ -510,7 +532,7 @@ var PanZoomViewport = React.forwardRef(
|
|
|
510
532
|
{
|
|
511
533
|
type: "button",
|
|
512
534
|
variant: "outline",
|
|
513
|
-
size: "icon
|
|
535
|
+
size: "icon",
|
|
514
536
|
className: "text-xs font-semibold",
|
|
515
537
|
onClick: fit,
|
|
516
538
|
children: labels.fit
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMediaQuery, DESKTOP_MEDIA_QUERY } from '../chunk-OPVKL4VS.js';
|
|
2
2
|
import { Sheet, SheetContent, SheetTitle, SheetDescription } from '../chunk-LAEVMNJN.js';
|
|
3
|
-
import { Drawer, DrawerContent, DrawerTitle, DrawerDescription } from '../chunk-
|
|
3
|
+
import { Drawer, DrawerContent, DrawerTitle, DrawerDescription } from '../chunk-NF5UMLSL.js';
|
|
4
4
|
import { Dialog, DialogContent, DialogTitle, DialogDescription } from '../chunk-IQIJCMG2.js';
|
|
5
5
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
6
|
import { __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
@@ -59,15 +59,14 @@ var ResponsiveOverlay = React.forwardRef(
|
|
|
59
59
|
}, ref) => {
|
|
60
60
|
const isWide = useMediaQuery(wideFrom === "lg" ? DESKTOP_MEDIA_QUERY : MD_MEDIA_QUERY);
|
|
61
61
|
const container = isWide ? desktop : "drawer";
|
|
62
|
-
const titleId = React.useId();
|
|
63
|
-
const subtitleId = React.useId();
|
|
64
62
|
useFocusReturn(open);
|
|
63
|
+
const describedBy = subtitle ? {} : { "aria-describedby": void 0 };
|
|
65
64
|
const Title = CONTAINER_TITLE[container];
|
|
66
65
|
const Description = CONTAINER_DESCRIPTION[container];
|
|
67
66
|
const header = /* @__PURE__ */ jsxs("div", { "data-slot": "responsive-overlay-header", className: "flex items-start gap-3 px-5 pt-5", children: [
|
|
68
67
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
69
|
-
/* @__PURE__ */ jsx(Title, {
|
|
70
|
-
subtitle ? /* @__PURE__ */ jsx(Description, {
|
|
68
|
+
/* @__PURE__ */ jsx(Title, { className: "text-[19px] font-bold leading-tight", children: title }),
|
|
69
|
+
subtitle ? /* @__PURE__ */ jsx(Description, { className: "mt-1 text-[13px] text-muted-foreground", children: subtitle }) : null
|
|
71
70
|
] }),
|
|
72
71
|
/* @__PURE__ */ jsxs(
|
|
73
72
|
"button",
|
|
@@ -102,17 +101,16 @@ var ResponsiveOverlay = React.forwardRef(
|
|
|
102
101
|
if (container === "sheet") {
|
|
103
102
|
return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, modal, children: /* @__PURE__ */ jsxs(
|
|
104
103
|
SheetContent,
|
|
105
|
-
__spreadProps(__spreadValues({
|
|
104
|
+
__spreadProps(__spreadValues(__spreadProps(__spreadValues({
|
|
106
105
|
ref,
|
|
107
106
|
side: "right",
|
|
108
107
|
attachment: "inset",
|
|
109
108
|
hideClose: true,
|
|
110
|
-
overlayClassName: "bg-scrim-overlay backdrop-blur-none"
|
|
111
|
-
|
|
112
|
-
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
109
|
+
overlayClassName: "bg-scrim-overlay backdrop-blur-none"
|
|
110
|
+
}, describedBy), {
|
|
113
111
|
"data-slot": "responsive-overlay-sheet",
|
|
114
112
|
"data-modal": modal ? "true" : "false"
|
|
115
|
-
}, modal ? {} : { onInteractOutside: (event) => event.preventDefault() }), {
|
|
113
|
+
}), modal ? {} : { onInteractOutside: (event) => event.preventDefault() }), {
|
|
116
114
|
className: cn(
|
|
117
115
|
"flex w-[420px] max-w-[calc(100vw-1.5rem)] flex-col gap-0 bg-card p-0",
|
|
118
116
|
className
|
|
@@ -128,13 +126,12 @@ var ResponsiveOverlay = React.forwardRef(
|
|
|
128
126
|
if (container === "dialog") {
|
|
129
127
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
|
|
130
128
|
DialogContent,
|
|
131
|
-
{
|
|
129
|
+
__spreadProps(__spreadValues({
|
|
132
130
|
ref,
|
|
133
131
|
size,
|
|
134
132
|
showCloseButton: false,
|
|
135
|
-
overlayClassName: "bg-scrim-overlay backdrop-blur-none"
|
|
136
|
-
|
|
137
|
-
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
133
|
+
overlayClassName: "bg-scrim-overlay backdrop-blur-none"
|
|
134
|
+
}, describedBy), {
|
|
138
135
|
className: cn(
|
|
139
136
|
// The dialog's own `grid gap-4 p-6` would put air between the
|
|
140
137
|
// header, the body and the band the frames draw flush.
|
|
@@ -146,23 +143,22 @@ var ResponsiveOverlay = React.forwardRef(
|
|
|
146
143
|
body,
|
|
147
144
|
foot
|
|
148
145
|
]
|
|
149
|
-
}
|
|
146
|
+
})
|
|
150
147
|
) });
|
|
151
148
|
}
|
|
152
149
|
return /* @__PURE__ */ jsx(Drawer, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
|
|
153
150
|
DrawerContent,
|
|
154
|
-
{
|
|
151
|
+
__spreadProps(__spreadValues({
|
|
155
152
|
ref,
|
|
156
|
-
overlayClassName: "bg-scrim-overlay"
|
|
157
|
-
|
|
158
|
-
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
153
|
+
overlayClassName: "bg-scrim-overlay"
|
|
154
|
+
}, describedBy), {
|
|
159
155
|
className: cn("flex max-h-[85vh] flex-col p-0", className),
|
|
160
156
|
children: [
|
|
161
157
|
header,
|
|
162
158
|
body,
|
|
163
159
|
foot
|
|
164
160
|
]
|
|
165
|
-
}
|
|
161
|
+
})
|
|
166
162
|
) });
|
|
167
163
|
}
|
|
168
164
|
);
|
|
@@ -4,11 +4,11 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
4
4
|
|
|
5
5
|
declare const spinnerVariants: (props?: ({
|
|
6
6
|
size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
|
|
7
|
-
tone?: "
|
|
7
|
+
tone?: "default" | "inherit" | "primary" | "destructive" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Spinner: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
10
|
size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
|
|
11
|
-
tone?: "
|
|
11
|
+
tone?: "default" | "inherit" | "primary" | "destructive" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
/** Visually-hidden label for screen readers. Defaults to "Loading". */
|
|
14
14
|
label?: string;
|
package/dist/components/tag.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const tagVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "default" | "primary" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Tag: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
|
-
variant?: "
|
|
10
|
+
variant?: "default" | "primary" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
|
|
11
11
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
onRemove?: () => void;
|
|
@@ -22,8 +22,8 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
22
22
|
* Weights are 400 / 600 / 700. 500 is not in the system.
|
|
23
23
|
*/
|
|
24
24
|
declare const textVariants: (props?: ({
|
|
25
|
-
variant?: "
|
|
26
|
-
color?: "
|
|
25
|
+
variant?: "body" | "small" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
|
|
26
|
+
color?: "default" | "inherit" | "primary" | "destructive" | "muted" | "primary-foreground" | null | undefined;
|
|
27
27
|
weight?: "bold" | "medium" | "normal" | "semibold" | null | undefined;
|
|
28
28
|
leading?: "none" | "normal" | "tight" | "snug" | "relaxed" | "loose" | null | undefined;
|
|
29
29
|
tracking?: "normal" | "tight" | "wide" | "wider" | null | undefined;
|