@bearmenu/ui 0.8.38 → 0.8.40
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-FVSKGCK3.js → chunk-DZHKUUYV.js} +15 -1
- 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/card.d.ts +2 -2
- package/dist/components/card.js +1 -1
- 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 +38 -1
- package/dist/components/empty-state.js +48 -18
- 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/dist/components/venue-events-block.js +1 -1
- package/package.json +1 -1
- package/src/components/card.stories.tsx +20 -1
- package/src/components/card.test.tsx +27 -0
- package/src/components/card.tsx +14 -0
- package/src/components/drawer.test.tsx +55 -0
- package/src/components/drawer.tsx +33 -11
- package/src/components/empty-state.stories.tsx +31 -0
- package/src/components/empty-state.test.tsx +78 -0
- package/src/components/empty-state.tsx +80 -21
- package/src/components/floor-tokens.stories.tsx +223 -0
- package/src/components/responsive-overlay.test.tsx +40 -0
- package/src/components/responsive-overlay.tsx +13 -10
- package/src/globals.css +161 -0
|
@@ -36,7 +36,16 @@ var cardVariants = cva(
|
|
|
36
36
|
// several-hundred-pixel slab that translates under the cursor is a
|
|
37
37
|
// wobble rather than a lift. A panel that size delegates interaction to
|
|
38
38
|
// its children.
|
|
39
|
-
elevatedPanel: "bg-card border border-border shadow-[var(--shadow-panel)]"
|
|
39
|
+
elevatedPanel: "bg-card border border-border shadow-[var(--shadow-panel)]",
|
|
40
|
+
// The booking frames' settings/report SECTION card (Settings Rules U0,
|
|
41
|
+
// Reports P0): a smaller, page-content-scale radius than every other
|
|
42
|
+
// variant's `rounded-3xl` — 14px on a phone, 16px from `sm` — carried
|
|
43
|
+
// entirely by `--shadow-card` with no border at all. Not a bigger
|
|
44
|
+
// `elevated`: that variant is fixed at 24px and keeps its hairline in
|
|
45
|
+
// both themes on purpose (see its note); this one is for the specific
|
|
46
|
+
// page-section shape the booking design draws, not a general
|
|
47
|
+
// border-dropping replacement for `elevated`.
|
|
48
|
+
section: "rounded-[14px] bg-card shadow-[var(--shadow-card)] sm:rounded-[16px]"
|
|
40
49
|
},
|
|
41
50
|
size: {
|
|
42
51
|
sm: "[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:p-4 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-4 [&_[data-slot=card-footer]]:pt-0",
|
|
@@ -68,6 +77,11 @@ var cardVariants = cva(
|
|
|
68
77
|
variant: "elevated",
|
|
69
78
|
interactive: true,
|
|
70
79
|
class: "hover:shadow-[var(--shadow-card-hover)]"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
variant: "section",
|
|
83
|
+
interactive: true,
|
|
84
|
+
class: "hover:shadow-[var(--shadow-card-hover)]"
|
|
71
85
|
}
|
|
72
86
|
],
|
|
73
87
|
defaultVariants: {
|
|
@@ -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?: "secondary" | "default" | "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?: "secondary" | "default" | "link" | "warning" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
|
|
7
|
+
size?: "default" | "icon" | "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> {
|
|
@@ -3,12 +3,12 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const cardVariants: (props?: ({
|
|
6
|
-
variant?: "outline" | "glass" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
|
|
6
|
+
variant?: "outline" | "glass" | "section" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
interactive?: boolean | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
11
|
-
variant?: "outline" | "glass" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
|
|
11
|
+
variant?: "outline" | "glass" | "section" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
|
|
12
12
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
13
13
|
interactive?: boolean | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
|
package/dist/components/card.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cardVariants } from '../chunk-
|
|
1
|
+
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cardVariants } from '../chunk-DZHKUUYV.js';
|
|
2
2
|
import '../chunk-ZLMRVBD7.js';
|
|
3
3
|
import '../chunk-FEK5XGZW.js';
|
|
4
4
|
import '../chunk-MMUBH76A.js';
|
|
@@ -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>>, "onChange" | "value" | "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">, "heading" | "value"> & {
|
|
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">, "onSelect" | "value" | "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';
|
|
@@ -3,7 +3,14 @@ import * as React from 'react';
|
|
|
3
3
|
type EmptyStateAction = {
|
|
4
4
|
label: string;
|
|
5
5
|
onClick: () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Rendered before the label, sized like the DS button's own icons (the
|
|
8
|
+
* `Button` base class forces every child `<svg>` to 16px) — "Try again"
|
|
9
|
+
* carries a refresh glyph, "New reservation" a plus.
|
|
10
|
+
*/
|
|
11
|
+
icon?: React.ReactNode;
|
|
6
12
|
};
|
|
13
|
+
type EmptyStateVariant = "default" | "search" | "error";
|
|
7
14
|
interface EmptyStateProps {
|
|
8
15
|
title: string;
|
|
9
16
|
description: string;
|
|
@@ -11,10 +18,40 @@ interface EmptyStateProps {
|
|
|
11
18
|
illustration?: React.ReactNode;
|
|
12
19
|
action?: EmptyStateAction;
|
|
13
20
|
secondaryAction?: EmptyStateAction;
|
|
14
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The primary action's style. Defaults by variant: `outline` for `error`
|
|
23
|
+
* (try again) and `search` (clear filters) — a recovery step, not the page's
|
|
24
|
+
* main call to action — and a filled `default` for the plain empty state,
|
|
25
|
+
* where the action is usually "create the first one".
|
|
26
|
+
*/
|
|
27
|
+
actionVariant?: "default" | "outline";
|
|
28
|
+
variant?: EmptyStateVariant;
|
|
15
29
|
size?: "sm" | "md" | "lg";
|
|
30
|
+
/**
|
|
31
|
+
* `card` draws the booking pages' whole-body state card (reports/02-p4,
|
|
32
|
+
* calendar/02-c2): a 14px-radius card surface (16px from `sm`) with the
|
|
33
|
+
* resting card shadow and no border. `none` (the default) leaves the
|
|
34
|
+
* surface to the container it sits in.
|
|
35
|
+
*/
|
|
36
|
+
surface?: "none" | "card";
|
|
16
37
|
className?: string;
|
|
17
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* EmptyState — an icon tile, a title, one line of body and an optional action,
|
|
41
|
+
* spaced as the booking frames draw them (reports/02-p4, calendar/02-c2): a
|
|
42
|
+
* 64px tile (72px from `sm`) with a 28px glyph, 16px to the title, 12px from
|
|
43
|
+
* title to body, 16px from body to the action. The action is full-width on a
|
|
44
|
+
* phone and hugs its label from `sm`.
|
|
45
|
+
*
|
|
46
|
+
* The tile is 20px-radius (22px from `sm`); the title is 16px on a phone,
|
|
47
|
+
* 18px from `sm`. On `surface="card"` the card itself is 14px-radius (16px
|
|
48
|
+
* from `sm`), no border, with 20px side padding to the action row — measured
|
|
49
|
+
* off the frames' DOM (reports/02-p4, calendar/02-c2), not eyeballed.
|
|
50
|
+
*
|
|
51
|
+
* The error variant says "error" with its glyph and its tile's wash, not by
|
|
52
|
+
* painting the title and body red: red body copy is both harder to read and
|
|
53
|
+
* louder than a load failure the user can retry.
|
|
54
|
+
*/
|
|
18
55
|
declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
|
|
19
56
|
declare const SearchEmptyState: React.ForwardRefExoticComponent<Omit<EmptyStateProps, "icon" | "variant"> & React.RefAttributes<HTMLDivElement>>;
|
|
20
57
|
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,16 +58,43 @@ 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-[14px] bg-card px-5 shadow-[var(--shadow-card)] sm:rounded-[16px]",
|
|
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
|
-
|
|
67
|
-
|
|
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-[20px] border border-border shadow-sm sm:size-18 sm:rounded-[22px] [&_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-base sm: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__ */ jsxs(
|
|
83
|
+
Button,
|
|
84
|
+
{
|
|
85
|
+
onClick: action.onClick,
|
|
86
|
+
variant: actionVariant != null ? actionVariant : DEFAULT_ACTION_VARIANT[variant],
|
|
87
|
+
className: "glass-hover",
|
|
88
|
+
children: [
|
|
89
|
+
action.icon,
|
|
90
|
+
action.label
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
secondaryAction && /* @__PURE__ */ jsxs(Button, { onClick: secondaryAction.onClick, variant: "outline", className: "glass-hover", children: [
|
|
95
|
+
secondaryAction.icon,
|
|
96
|
+
secondaryAction.label
|
|
97
|
+
] })
|
|
68
98
|
] })
|
|
69
99
|
]
|
|
70
100
|
})
|
|
@@ -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?: "primary" | "default" | "inherit" | "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?: "primary" | "default" | "inherit" | "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?: "primary" | "default" | "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?: "primary" | "default" | "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?: "small" | "body" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
|
|
26
|
+
color?: "primary" | "default" | "inherit" | "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;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Separator } from '../chunk-NWZGSLPU.js';
|
|
2
2
|
import { Skeleton } from '../chunk-XBBEX4SF.js';
|
|
3
|
-
import { Card } from '../chunk-
|
|
3
|
+
import { Card } from '../chunk-DZHKUUYV.js';
|
|
4
4
|
import '../chunk-ZLMRVBD7.js';
|
|
5
5
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
6
|
import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ const meta = {
|
|
|
11
11
|
argTypes: {
|
|
12
12
|
variant: {
|
|
13
13
|
control: "select",
|
|
14
|
-
options: ["glass", "surface"],
|
|
14
|
+
options: ["glass", "surface", "outline", "muted", "elevated", "elevatedPanel", "section"],
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
17
|
} satisfies Meta<typeof Card>;
|
|
@@ -47,6 +47,25 @@ export const Surface: Story = {
|
|
|
47
47
|
),
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The booking frames' settings/report section shape (Settings Rules U0,
|
|
52
|
+
* Reports P0): 14px radius on a phone, 16px from `sm`, shadow only, no
|
|
53
|
+
* border. Distinct from `elevated`, which is a fixed 24px with a hairline.
|
|
54
|
+
*/
|
|
55
|
+
export const Section: Story = {
|
|
56
|
+
render: () => (
|
|
57
|
+
<Card variant="section" className="w-[350px]">
|
|
58
|
+
<CardHeader>
|
|
59
|
+
<CardTitle>Booking rules</CardTitle>
|
|
60
|
+
<CardDescription>How far ahead guests can book, and the slot length.</CardDescription>
|
|
61
|
+
</CardHeader>
|
|
62
|
+
<CardContent>
|
|
63
|
+
<p className="text-sm text-muted-foreground">Section content goes here.</p>
|
|
64
|
+
</CardContent>
|
|
65
|
+
</Card>
|
|
66
|
+
),
|
|
67
|
+
};
|
|
68
|
+
|
|
50
69
|
export const WithForm: Story = {
|
|
51
70
|
render: () => (
|
|
52
71
|
<Card className="w-[350px]">
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { Card } from "./card";
|
|
4
|
+
|
|
5
|
+
describe("Card", () => {
|
|
6
|
+
it("draws the section variant borderless, at the booking frames' radius", () => {
|
|
7
|
+
render(<Card variant="section">Content</Card>);
|
|
8
|
+
const card = screen.getByText("Content");
|
|
9
|
+
expect(card).toHaveClass("rounded-[14px]", "sm:rounded-[16px]", "bg-card");
|
|
10
|
+
expect(card).not.toHaveClass("border", "border-border");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("keeps elevated's fixed radius and hairline, unaffected by the new variant", () => {
|
|
14
|
+
render(<Card variant="elevated">Content</Card>);
|
|
15
|
+
const card = screen.getByText("Content");
|
|
16
|
+
expect(card).toHaveClass("rounded-3xl", "border", "border-border");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("steps section's shadow up on hover when interactive", () => {
|
|
20
|
+
render(
|
|
21
|
+
<Card variant="section" interactive>
|
|
22
|
+
Content
|
|
23
|
+
</Card>
|
|
24
|
+
);
|
|
25
|
+
expect(screen.getByText("Content")).toHaveClass("hover:shadow-[var(--shadow-card-hover)]");
|
|
26
|
+
});
|
|
27
|
+
});
|
package/src/components/card.tsx
CHANGED
|
@@ -35,6 +35,15 @@ const cardVariants = cva(
|
|
|
35
35
|
// wobble rather than a lift. A panel that size delegates interaction to
|
|
36
36
|
// its children.
|
|
37
37
|
elevatedPanel: "bg-card border border-border shadow-[var(--shadow-panel)]",
|
|
38
|
+
// The booking frames' settings/report SECTION card (Settings Rules U0,
|
|
39
|
+
// Reports P0): a smaller, page-content-scale radius than every other
|
|
40
|
+
// variant's `rounded-3xl` — 14px on a phone, 16px from `sm` — carried
|
|
41
|
+
// entirely by `--shadow-card` with no border at all. Not a bigger
|
|
42
|
+
// `elevated`: that variant is fixed at 24px and keeps its hairline in
|
|
43
|
+
// both themes on purpose (see its note); this one is for the specific
|
|
44
|
+
// page-section shape the booking design draws, not a general
|
|
45
|
+
// border-dropping replacement for `elevated`.
|
|
46
|
+
section: "rounded-[14px] bg-card shadow-[var(--shadow-card)] sm:rounded-[16px]",
|
|
38
47
|
},
|
|
39
48
|
size: {
|
|
40
49
|
sm: "[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:p-4 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-4 [&_[data-slot=card-footer]]:pt-0",
|
|
@@ -68,6 +77,11 @@ const cardVariants = cva(
|
|
|
68
77
|
interactive: true,
|
|
69
78
|
class: "hover:shadow-[var(--shadow-card-hover)]",
|
|
70
79
|
},
|
|
80
|
+
{
|
|
81
|
+
variant: "section",
|
|
82
|
+
interactive: true,
|
|
83
|
+
class: "hover:shadow-[var(--shadow-card-hover)]",
|
|
84
|
+
},
|
|
71
85
|
],
|
|
72
86
|
defaultVariants: {
|
|
73
87
|
variant: "surface",
|