@botiverse/raft-ui 0.82.0 → 0.84.0
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/CHANGELOG.md +147 -0
- package/dist/components/app-link-card/app-link-card.mjs +19 -37
- package/dist/components/banner/banner.mjs +15 -2
- package/dist/components/dialog/dialog-sheet-context.mjs +7 -2
- package/dist/components/dialog/dialog-sheet.d.mts +3 -2
- package/dist/components/dialog/dialog-sheet.mjs +29 -43
- package/dist/components/dialog/dialog.d.mts +12 -1
- package/dist/components/dialog/dialog.mjs +50 -10
- package/dist/components/drag/drag.recipe.mjs +1 -1
- package/dist/components/fit-toolbar/fit-toolbar.d.mts +165 -0
- package/dist/components/fit-toolbar/fit-toolbar.mjs +736 -0
- package/dist/components/fit-toolbar/fit-toolbar.recipe.mjs +35 -0
- package/dist/components/fit-toolbar/index.d.mts +2 -0
- package/dist/components/lightbox/index.d.mts +2 -2
- package/dist/components/lightbox/lightbox.d.mts +70 -4
- package/dist/components/lightbox/lightbox.mjs +285 -91
- package/dist/components/list-row/list-row.d.mts +14 -1
- package/dist/components/list-row/list-row.mjs +4 -2
- package/dist/components/list-row/list-row.recipe.d.mts +15 -3
- package/dist/components/list-row/list-row.recipe.mjs +18 -1
- package/dist/components/message-action-card/message-action-card-content.recipe.mjs +3 -3
- package/dist/components/message-action-card/message-action-card.mjs +7 -3
- package/dist/components/message-action-card/message-action-card.recipe.mjs +2 -6
- package/dist/components/message-embed/index.d.mts +2 -1
- package/dist/components/message-embed/message-embed.d.mts +8 -1
- package/dist/components/message-embed/message-embed.mjs +2 -2
- package/dist/components/message-embed/message-embed.recipe.d.mts +160 -0
- package/dist/components/message-embed/message-embed.recipe.mjs +49 -10
- package/dist/components/message-forwarded-bundle/message-forwarded-bundle.mjs +1 -0
- package/dist/components/message-forwarded-bundle/message-forwarded-bundle.recipe.mjs +1 -1
- package/dist/components/message-quoted-preview/message-quoted-preview.mjs +2 -0
- package/dist/components/message-replies/message-replies.mjs +1 -1
- package/dist/components/message-replies/message-replies.recipe.mjs +1 -1
- package/dist/components/mobile-nav/mobile-nav-server.d.mts +21 -8
- package/dist/components/mobile-nav/mobile-nav-server.mjs +142 -13
- package/dist/components/popover/popover.d.mts +11 -2
- package/dist/components/popover/popover.mjs +51 -38
- package/dist/components/preview-card/preview-card.d.mts +5 -1
- package/dist/components/preview-card/preview-card.mjs +24 -27
- package/dist/components/save-status/save-status.d.mts +16 -9
- package/dist/components/save-status/save-status.mjs +19 -30
- package/dist/components/segmented-control/segmented-control.d.mts +1 -1
- package/dist/components/segmented-control/segmented-control.mjs +56 -10
- package/dist/components/selection-toolbar/index.d.mts +2 -0
- package/dist/components/selection-toolbar/selection-toolbar.d.mts +100 -0
- package/dist/components/selection-toolbar/selection-toolbar.mjs +217 -0
- package/dist/components/selection-toolbar/selection-toolbar.recipe.mjs +42 -0
- package/dist/components/task-board/task-board.d.mts +5 -0
- package/dist/components/task-board/task-board.mjs +8 -1
- package/dist/components/task-dnd/task-dnd.d.mts +10 -1
- package/dist/components/task-dnd/task-dnd.mjs +2 -1
- package/dist/components/toast/toast.mjs +2 -2
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +4 -2
- package/dist/lib/label-value-fit.mjs +33 -6
- package/dist/lib/laid-out-children.mjs +32 -0
- package/dist/lib/stacked-actions.mjs +7 -4
- package/dist/lib/use-mobile-viewport.mjs +5 -2
- package/dist/lib/use-soft-keyboard.mjs +72 -0
- package/dist/wip.d.mts +8 -3
- package/dist/wip.mjs +5 -3
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { tv } from "../../lib/tv.mjs";
|
|
2
|
+
//#region src/components/fit-toolbar/fit-toolbar.recipe.ts
|
|
3
|
+
const fitToolbar = tv({
|
|
4
|
+
slots: {
|
|
5
|
+
root: ["flex min-w-0 max-w-full flex-nowrap items-center", "data-fit-wrapping:flex-wrap data-fit-wrapping:gap-y-0"],
|
|
6
|
+
group: ["group/fit-group flex shrink-0 flex-nowrap items-center", "data-fit-wrap:mt-(--fit-gap)"],
|
|
7
|
+
full: ["contents group-data-fit-collapse/fit-group:hidden"],
|
|
8
|
+
short: ["hidden group-data-fit-collapse/fit-group:contents"],
|
|
9
|
+
button: [
|
|
10
|
+
"data-fit-label:w-8 data-fit-label:px-0 md:pointer-fine:data-fit-label:w-(--control-height)",
|
|
11
|
+
"data-fit-plus:w-8 data-fit-plus:px-0 md:pointer-fine:data-fit-plus:w-(--control-height)",
|
|
12
|
+
"data-fit-more:hidden"
|
|
13
|
+
],
|
|
14
|
+
label: ["in-data-fit-label:sr-only in-data-fit-plus:sr-only"],
|
|
15
|
+
icon: ["contents in-data-fit-plus:hidden"],
|
|
16
|
+
fullIcon: ["contents in-data-fit-label:hidden"],
|
|
17
|
+
collapsedIcon: ["hidden in-data-fit-label:contents"],
|
|
18
|
+
picker: ["data-fit-label:gap-1 data-fit-label:px-2", "data-fit-more:hidden"],
|
|
19
|
+
pickerValue: [],
|
|
20
|
+
chevron: ["inline-flex"],
|
|
21
|
+
plus: ["hidden in-data-fit-plus:block"],
|
|
22
|
+
scroller: [],
|
|
23
|
+
scrollContent: []
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
count: { true: { pickerValue: ["font-mono text-mono-meta"] } },
|
|
27
|
+
scroll: { true: {
|
|
28
|
+
group: ["block min-w-0 flex-1 shrink basis-0"],
|
|
29
|
+
scroller: ["-my-1.5 w-full gap-[inherit] scroll-px-6 mask-fade-x"],
|
|
30
|
+
scrollContent: ["flex w-max items-center gap-[inherit] py-1.5"]
|
|
31
|
+
} }
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
//#endregion
|
|
35
|
+
export { fitToolbar };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { FitItemOptions, FitStep, FitSteps, FitToolbar, FitToolbarButton, FitToolbarButtonProps, FitToolbarGroup, FitToolbarGroupProps, FitToolbarMoreItems, FitToolbarPicker, FitToolbarPickerProps, FitToolbarProps, useFitItem, useFitMore, useInFitToolbar } from "./fit-toolbar.mjs";
|
|
2
|
+
export { type FitItemOptions, type FitStep, type FitSteps, FitToolbar, FitToolbarButton, type FitToolbarButtonProps, FitToolbarGroup, type FitToolbarGroupProps, FitToolbarMoreItems, FitToolbarPicker, type FitToolbarPickerProps, type FitToolbarProps, useFitItem, useFitMore, useInFitToolbar };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Lightbox, LightboxActions, LightboxActionsProps, LightboxClose, LightboxCloseProps, LightboxContent, LightboxContentProps, LightboxHeader, LightboxHeaderLabel, LightboxHeaderLabelProps, LightboxHeaderMeta, LightboxHeaderMetaProps, LightboxHeaderProps, LightboxInfoActions, LightboxInfoActionsProps, LightboxInfoBar, LightboxInfoBarProps, LightboxInfoDock, LightboxInfoDockProps, LightboxInfoTitle, LightboxInfoTitleProps, LightboxMedia, LightboxMediaProps, LightboxNavigationButton, LightboxNavigationButtonProps, LightboxPortal, LightboxPortalProps, LightboxProps, LightboxStage, LightboxStageProps, LightboxThumbnail, LightboxThumbnailProps, LightboxThumbnailStrip, LightboxThumbnailStripProps, LightboxTitle, LightboxTitleProps, LightboxToolbar, LightboxToolbarProps, LightboxTrigger, LightboxTriggerProps } from "./lightbox.mjs";
|
|
2
|
-
export { Lightbox, LightboxActions, type LightboxActionsProps, LightboxClose, type LightboxCloseProps, LightboxContent, type LightboxContentProps, LightboxHeader, LightboxHeaderLabel, type LightboxHeaderLabelProps, LightboxHeaderMeta, type LightboxHeaderMetaProps, type LightboxHeaderProps, LightboxInfoActions, type LightboxInfoActionsProps, LightboxInfoBar, type LightboxInfoBarProps, LightboxInfoDock, type LightboxInfoDockProps, LightboxInfoTitle, type LightboxInfoTitleProps, LightboxMedia, type LightboxMediaProps, LightboxNavigationButton, type LightboxNavigationButtonProps, LightboxPortal, type LightboxPortalProps, type LightboxProps, LightboxStage, type LightboxStageProps, LightboxThumbnail, type LightboxThumbnailProps, LightboxThumbnailStrip, type LightboxThumbnailStripProps, LightboxTitle, type LightboxTitleProps, LightboxToolbar, type LightboxToolbarProps, LightboxTrigger, type LightboxTriggerProps };
|
|
1
|
+
import { Lightbox, LightboxActions, LightboxActionsProps, LightboxBody, LightboxBodyProps, LightboxClose, LightboxCloseProps, LightboxContent, LightboxContentProps, LightboxHeader, LightboxHeaderLabel, LightboxHeaderLabelProps, LightboxHeaderMeta, LightboxHeaderMetaProps, LightboxHeaderProps, LightboxInfoActions, LightboxInfoActionsProps, LightboxInfoBar, LightboxInfoBarProps, LightboxInfoDock, LightboxInfoDockProps, LightboxInfoTitle, LightboxInfoTitleProps, LightboxMedia, LightboxMediaProps, LightboxNavigationButton, LightboxNavigationButtonProps, LightboxPortal, LightboxPortalProps, LightboxProps, LightboxStage, LightboxStageProps, LightboxThumbnail, LightboxThumbnailProps, LightboxThumbnailStrip, LightboxThumbnailStripProps, LightboxTitle, LightboxTitleProps, LightboxToolbar, LightboxToolbarProps, LightboxTrigger, LightboxTriggerProps } from "./lightbox.mjs";
|
|
2
|
+
export { Lightbox, LightboxActions, type LightboxActionsProps, LightboxBody, type LightboxBodyProps, LightboxClose, type LightboxCloseProps, LightboxContent, type LightboxContentProps, LightboxHeader, LightboxHeaderLabel, type LightboxHeaderLabelProps, LightboxHeaderMeta, type LightboxHeaderMetaProps, type LightboxHeaderProps, LightboxInfoActions, type LightboxInfoActionsProps, LightboxInfoBar, type LightboxInfoBarProps, LightboxInfoDock, type LightboxInfoDockProps, LightboxInfoTitle, type LightboxInfoTitleProps, LightboxMedia, type LightboxMediaProps, LightboxNavigationButton, type LightboxNavigationButtonProps, LightboxPortal, type LightboxPortalProps, type LightboxProps, LightboxStage, type LightboxStageProps, LightboxThumbnail, type LightboxThumbnailProps, LightboxThumbnailStrip, type LightboxThumbnailStripProps, LightboxTitle, type LightboxTitleProps, LightboxToolbar, type LightboxToolbarProps, LightboxTrigger, type LightboxTriggerProps };
|
|
@@ -1,20 +1,68 @@
|
|
|
1
1
|
import { StyledProps } from "../../lib/styled-props.mjs";
|
|
2
2
|
import { ButtonProps } from "../button/button.mjs";
|
|
3
|
+
import { ScrollAreaProps } from "../scroll-area/types.mjs";
|
|
3
4
|
import { Dialog } from "@base-ui/react/dialog";
|
|
4
5
|
import { ReactNode } from "react";
|
|
5
6
|
import { useRender } from "@base-ui/react/use-render";
|
|
6
7
|
//#region src/components/lightbox/lightbox.d.ts
|
|
7
|
-
export type LightboxProps<Payload = unknown> = Omit<Dialog.Root.Props<Payload>, "actionsRef" | "children" | "handle"> & {
|
|
8
|
+
export type LightboxProps<Payload = unknown> = Omit<Dialog.Root.Props<Payload>, "actionsRef" | "children" | "handle" | "modal"> & {
|
|
8
9
|
children?: ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Whether Cmd+W (Ctrl+W) closes the lightbox instead of the browser tab.
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
9
14
|
closeOnModW?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* How the lightbox holds the page while it is open.
|
|
17
|
+
* - `true`: focus is trapped in it and the page's scroll is locked. For an
|
|
18
|
+
* image or a preview that fits the window.
|
|
19
|
+
* - `"trap-focus"`: document mode, for a file read top to bottom (a PDF, a
|
|
20
|
+
* document, a diagram). Focus is still trapped, but the page's scroll is
|
|
21
|
+
* not locked: the document's own body scrolls, and Base UI's lock would
|
|
22
|
+
* only rewrite the page's `<html>` and `<body>` styles under it, again on
|
|
23
|
+
* every resize. The scrim still covers the page.
|
|
24
|
+
* - `false`: nothing is held; focus can leave the lightbox.
|
|
25
|
+
*
|
|
26
|
+
* In every mode the content is neither `inert` nor hidden, so the browser's
|
|
27
|
+
* find in page reaches it.
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
modal?: boolean | "trap-focus";
|
|
10
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* A full-screen viewer over the scrim for images and attachment previews,
|
|
34
|
+
* with previous and next, thumbnails and one button to close. Pass
|
|
35
|
+
* `modal="trap-focus"` for a file read top to bottom (document mode).
|
|
36
|
+
*/
|
|
11
37
|
export declare function Lightbox<Payload = unknown>({ closeOnModW, defaultOpen, modal, onOpenChange, open, children, ...props }: LightboxProps<Payload>): import("react").JSX.Element;
|
|
12
38
|
export type LightboxTriggerProps = Dialog.Trigger.Props;
|
|
13
39
|
export declare function LightboxTrigger(props: LightboxTriggerProps): import("react").JSX.Element;
|
|
14
|
-
export type LightboxPortalProps = Dialog.Portal.Props
|
|
15
|
-
|
|
40
|
+
export type LightboxPortalProps = StyledProps<Dialog.Portal.Props>;
|
|
41
|
+
/**
|
|
42
|
+
* The lightbox's own stacking context, at `z-70` above the page's dialogs
|
|
43
|
+
* and popups: the scrim, the content, and every Base UI popup opened from
|
|
44
|
+
* inside, which Base UI portals into this element by default, in DOM order.
|
|
45
|
+
* A popup's own `z-50` then counts inside the lightbox, so it is drawn above
|
|
46
|
+
* the content instead of under the scrim, and a press on it is a press inside
|
|
47
|
+
* the lightbox.
|
|
48
|
+
*/
|
|
49
|
+
export declare function LightboxPortal({ className, ...props }: LightboxPortalProps): import("react").JSX.Element;
|
|
16
50
|
export type LightboxContentProps = StyledProps<Dialog.Popup.Props>;
|
|
17
|
-
|
|
51
|
+
/**
|
|
52
|
+
* The full-screen layer, with the scrim behind it. Popups opened inside it
|
|
53
|
+
* are drawn above it (`LightboxPortal`). `initialFocus` and `finalFocus` are
|
|
54
|
+
* `false` by default, so focus doesn't move when it opens or closes, except
|
|
55
|
+
* in document mode (`modal="trap-focus"`): focus moves into the lightbox when
|
|
56
|
+
* it opens and back to `LightboxTrigger` when it closes. It lands on
|
|
57
|
+
* `LightboxBody`, so the keys that scroll scroll the document at once; on the
|
|
58
|
+
* first control when there is no body; and on the lightbox itself after a
|
|
59
|
+
* tap, so a phone shows no ring and opens no keyboard. A key that would
|
|
60
|
+
* scroll the page under the scrim scrolls the body instead.
|
|
61
|
+
*
|
|
62
|
+
* A lightbox opened from state passes `finalFocus={openerRef}` so focus goes
|
|
63
|
+
* back to what opened it.
|
|
64
|
+
*/
|
|
65
|
+
export declare function LightboxContent({ className, initialFocus, finalFocus, onKeyDown, ref, ...props }: LightboxContentProps): import("react").JSX.Element;
|
|
18
66
|
export type LightboxHeaderProps = useRender.ComponentProps<"div">;
|
|
19
67
|
export declare function LightboxHeader({ render, className, ...props }: LightboxHeaderProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
20
68
|
export type LightboxToolbarProps = useRender.ComponentProps<"div">;
|
|
@@ -27,6 +75,24 @@ export type LightboxTitleProps = useRender.ComponentProps<"div">;
|
|
|
27
75
|
export declare function LightboxTitle({ render, className, ...props }: LightboxTitleProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
28
76
|
export type LightboxActionsProps = useRender.ComponentProps<"div">;
|
|
29
77
|
export declare function LightboxActions({ render, className, ...props }: LightboxActionsProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
78
|
+
export type LightboxBodyProps = Omit<ScrollAreaProps, "overscroll">;
|
|
79
|
+
/**
|
|
80
|
+
* The scrolling body of a document-mode lightbox (`modal="trap-focus"`),
|
|
81
|
+
* under `LightboxToolbar`: a ScrollArea that fills the rest of the content
|
|
82
|
+
* (`min-h-0 flex-1`) on `layer-canvas`, the toolbar's surface. Pass a
|
|
83
|
+
* `className` for another surface (`bg-layer-sidebar`). It takes the pointer
|
|
84
|
+
* back from `LightboxContent`, which lets it through to the scrim, and never
|
|
85
|
+
* passes a scroll on to the page under the scrim (`overscroll-contain`, also
|
|
86
|
+
* while it has nothing to scroll; `overscroll-none` in `className` also stops
|
|
87
|
+
* the bounce). Every other ScrollArea prop, `render` included, is the area's.
|
|
88
|
+
*
|
|
89
|
+
* It is a tab stop even when it has nothing to scroll (`tabIndex={0}`), as it
|
|
90
|
+
* takes focus when the lightbox opens, and draws its focus ring inside its
|
|
91
|
+
* edge, which is the window's. Its content keeps clear of a phone's safe
|
|
92
|
+
* areas at the bottom and the sides, around the caller's own content box
|
|
93
|
+
* (`contentClassName`), so the scrollbar stays at the edge.
|
|
94
|
+
*/
|
|
95
|
+
export declare function LightboxBody({ children, className, contentClassName, contentStyle, ...props }: LightboxBodyProps): import("react").JSX.Element;
|
|
30
96
|
export type LightboxStageProps = useRender.ComponentProps<"div">;
|
|
31
97
|
export declare function LightboxStage({ render, className, ...props }: LightboxStageProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
32
98
|
export type LightboxMediaProps = useRender.ComponentProps<"div">;
|
|
@@ -2,96 +2,115 @@ import { cn } from "../../cn.mjs";
|
|
|
2
2
|
import { headEdgePull } from "../../lib/head-edges.mjs";
|
|
3
3
|
import { tv } from "../../lib/tv.mjs";
|
|
4
4
|
import { useThemeScopeProps } from "../../lib/theme/theme-scope.mjs";
|
|
5
|
+
import { OverlayLayerProvider, useParentOverlayKind } from "../../lib/overlay-depth.mjs";
|
|
5
6
|
import { Button } from "../button/button.mjs";
|
|
7
|
+
import { useMergedRef } from "../../lib/use-merged-ref.mjs";
|
|
8
|
+
import { ScrollArea } from "../scroll-area/scroll-area.mjs";
|
|
6
9
|
import { Dialog } from "@base-ui/react/dialog";
|
|
7
|
-
import { useCallback, useRef, useState } from "react";
|
|
10
|
+
import { createContext, useCallback, useContext, useRef, useState } from "react";
|
|
8
11
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
12
|
import { mergeProps } from "@base-ui/react/merge-props";
|
|
10
13
|
import { useRender } from "@base-ui/react/use-render";
|
|
11
14
|
import { useHotkey } from "@tanstack/react-hotkeys";
|
|
12
15
|
//#region src/components/lightbox/lightbox.tsx
|
|
13
|
-
const lightbox = tv({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"flex
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"[
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
16
|
+
const lightbox = tv({
|
|
17
|
+
slots: {
|
|
18
|
+
portal: ["relative isolate z-70"],
|
|
19
|
+
backdrop: ["fixed inset-0 bg-layer-backdrop data-closed:hidden"],
|
|
20
|
+
content: [
|
|
21
|
+
"pointer-events-none fixed inset-0 flex flex-col data-closed:hidden",
|
|
22
|
+
"*:data-lightbox-close:pointer-events-auto *:data-lightbox-close:absolute *:data-lightbox-close:z-20",
|
|
23
|
+
"*:data-lightbox-close:top-[calc(16px+env(safe-area-inset-top,0px))] *:data-lightbox-close:right-[calc(16px+env(safe-area-inset-right,0px))]"
|
|
24
|
+
],
|
|
25
|
+
header: [
|
|
26
|
+
"pointer-events-auto shrink-0",
|
|
27
|
+
"flex items-center gap-3 pb-3",
|
|
28
|
+
"pt-[calc(env(safe-area-inset-top,0px)+--spacing(3))]",
|
|
29
|
+
"pl-[calc(env(safe-area-inset-left,0px)+--spacing(4))]",
|
|
30
|
+
"pr-[calc(env(safe-area-inset-right,0px)+--spacing(4))]",
|
|
31
|
+
"bg-transparent shadow-none",
|
|
32
|
+
headEdgePull
|
|
33
|
+
],
|
|
34
|
+
toolbar: [
|
|
35
|
+
"pointer-events-auto shrink-0 flex items-center gap-3",
|
|
36
|
+
"h-[calc(var(--header-height)+env(safe-area-inset-top,0px))] pt-[env(safe-area-inset-top,0px)]",
|
|
37
|
+
"pl-[calc(16px+env(safe-area-inset-left,0px))] pr-[calc(16px+env(safe-area-inset-right,0px))]",
|
|
38
|
+
"**:data-lightbox-close:static **:data-lightbox-close:inset-auto",
|
|
39
|
+
"**:data-lightbox-close:top-auto **:data-lightbox-close:right-auto",
|
|
40
|
+
"border-b border-line-seam bg-layer-canvas shadow-none",
|
|
41
|
+
headEdgePull
|
|
42
|
+
],
|
|
43
|
+
headerMeta: ["flex min-w-0 flex-1 items-center gap-1.5"],
|
|
44
|
+
headerLabel: [
|
|
45
|
+
"inline-flex shrink-0 items-center px-1.5",
|
|
46
|
+
"h-[22px] rounded-chip bg-fill-muted py-0",
|
|
47
|
+
"font-sans text-caption font-semibold normal-case tracking-normal text-foreground-muted"
|
|
48
|
+
],
|
|
49
|
+
title: ["min-w-0 flex-1 truncate", "py-0 font-sans text-headline font-bold text-foreground"],
|
|
50
|
+
actions: [
|
|
51
|
+
"flex shrink-0 items-center",
|
|
52
|
+
"gap-1",
|
|
53
|
+
"[&>[data-icon-inset]:nth-last-child(1_of_:not([data-base-ui-focus-guard],[aria-owns]))]:-mr-icon-inset"
|
|
54
|
+
],
|
|
55
|
+
body: [
|
|
56
|
+
"pointer-events-auto min-h-0 flex-1 overscroll-contain",
|
|
57
|
+
"bg-layer-canvas",
|
|
58
|
+
"focus-visible:shadow-none focus-visible:keyboard:outline-2 focus-visible:keyboard:-outline-offset-2 focus-visible:keyboard:outline-foreground"
|
|
59
|
+
],
|
|
60
|
+
bodyContent: ["pr-[env(safe-area-inset-right,0px)] pb-[env(safe-area-inset-bottom,0px)] pl-[env(safe-area-inset-left,0px)]"],
|
|
61
|
+
stage: ["pointer-events-none relative flex min-h-0 flex-1 items-center justify-center overflow-hidden"],
|
|
62
|
+
media: ["pointer-events-auto max-h-[80vh] max-w-[86vw] border-0 bg-transparent shadow-none"],
|
|
63
|
+
navigationButton: [
|
|
64
|
+
"pointer-events-auto absolute z-10 inline-flex items-center justify-center",
|
|
65
|
+
"transition-[background-color,color,opacity,box-shadow,transform] duration-150",
|
|
66
|
+
"outline-[1px] outline-offset-2 outline-transparent",
|
|
67
|
+
"data-[disabled=true]:cursor-default",
|
|
68
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
69
|
+
"size-11 rounded-control border-[1.5px] border-line-strong bg-layer-card text-foreground shadow-none",
|
|
70
|
+
"hover:overlay-medium active:overlay-medium",
|
|
71
|
+
"focus-visible:outline-transparent focus-visible:shadow-focus",
|
|
72
|
+
"[&_svg]:size-5.5"
|
|
73
|
+
],
|
|
74
|
+
infoDock: ["pointer-events-none absolute right-6 bottom-20 left-6 z-10 flex justify-center"],
|
|
75
|
+
infoBar: [
|
|
76
|
+
"pointer-events-auto flex items-center",
|
|
77
|
+
"w-[clamp(144px,20vw,224px)] max-w-[calc(100vw-48px)] min-w-36",
|
|
78
|
+
"gap-2 rounded-container py-1 pr-1 pl-2.5",
|
|
79
|
+
"bg-layer-popover text-foreground shadow-float ring-1 ring-line-seam"
|
|
80
|
+
],
|
|
81
|
+
infoTitle: ["min-w-0 flex-1 truncate", "font-sans text-footnote font-semibold text-foreground"],
|
|
82
|
+
infoActions: [
|
|
83
|
+
"flex shrink-0 items-center",
|
|
84
|
+
"gap-1",
|
|
85
|
+
"*:data-[slot=button]:h-7 *:data-[slot=button]:w-auto *:data-[slot=button]:min-w-7",
|
|
86
|
+
"*:data-[slot=button]:rounded-chip",
|
|
87
|
+
"*:data-[slot=button]:after:inset-x-[-3px] *:data-[slot=button]:first:after:left-[-9.5px] *:data-[slot=button]:last:after:right-[-9.5px]",
|
|
88
|
+
"pointer-coarse:*:data-[slot=button]:after:inset-y-[-9.5px]"
|
|
89
|
+
],
|
|
90
|
+
thumbnailStrip: ["pointer-events-none absolute right-0 bottom-4 left-0 z-10", "flex items-center justify-center gap-1.5"],
|
|
91
|
+
thumbnail: [
|
|
92
|
+
"group/lightbox-thumb pointer-events-auto relative size-12 overflow-hidden",
|
|
93
|
+
"transition-[border-color,opacity,box-shadow] duration-150",
|
|
94
|
+
"[&_img]:pointer-events-none [&_img]:size-full [&_img]:object-cover",
|
|
95
|
+
"rounded-control border-[1.5px] opacity-100 shadow-none",
|
|
96
|
+
"border-sticker-paper/40 hover:border-sticker-paper/80",
|
|
97
|
+
"data-active:border-sticker-paper"
|
|
98
|
+
],
|
|
99
|
+
thumbnailOverlay: [
|
|
100
|
+
"pointer-events-none absolute inset-0 block transition-colors duration-150",
|
|
101
|
+
"bg-layer-backdrop-nested group-hover/lightbox-thumb:bg-layer-backdrop-nested/70",
|
|
102
|
+
"group-data-active/lightbox-thumb:bg-transparent"
|
|
103
|
+
],
|
|
104
|
+
close: ["pointer-events-auto"]
|
|
105
|
+
},
|
|
106
|
+
variants: { nested: { true: { backdrop: ["bg-layer-backdrop-nested"] } } }
|
|
107
|
+
});
|
|
108
|
+
const LightboxModalContext = createContext(true);
|
|
109
|
+
/**
|
|
110
|
+
* A full-screen viewer over the scrim for images and attachment previews,
|
|
111
|
+
* with previous and next, thumbnails and one button to close. Pass
|
|
112
|
+
* `modal="trap-focus"` for a file read top to bottom (document mode).
|
|
113
|
+
*/
|
|
95
114
|
function Lightbox({ closeOnModW = true, defaultOpen = false, modal = true, onOpenChange, open, children, ...props }) {
|
|
96
115
|
const dialogRef = useRef(null);
|
|
97
116
|
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
@@ -108,7 +127,14 @@ function Lightbox({ closeOnModW = true, defaultOpen = false, modal = true, onOpe
|
|
|
108
127
|
onOpenChange: handleOpenChange,
|
|
109
128
|
open,
|
|
110
129
|
...props,
|
|
111
|
-
children: [modWClose,
|
|
130
|
+
children: [modWClose, /* @__PURE__ */ jsx(OverlayLayerProvider, {
|
|
131
|
+
kind: "dialog",
|
|
132
|
+
modal: true,
|
|
133
|
+
children: /* @__PURE__ */ jsx(LightboxModalContext.Provider, {
|
|
134
|
+
value: modal,
|
|
135
|
+
children
|
|
136
|
+
})
|
|
137
|
+
})]
|
|
112
138
|
});
|
|
113
139
|
}
|
|
114
140
|
function LightboxModWClose({ dialogRef }) {
|
|
@@ -128,22 +154,158 @@ function LightboxTrigger(props) {
|
|
|
128
154
|
...props
|
|
129
155
|
});
|
|
130
156
|
}
|
|
131
|
-
|
|
157
|
+
/**
|
|
158
|
+
* The lightbox's own stacking context, at `z-70` above the page's dialogs
|
|
159
|
+
* and popups: the scrim, the content, and every Base UI popup opened from
|
|
160
|
+
* inside, which Base UI portals into this element by default, in DOM order.
|
|
161
|
+
* A popup's own `z-50` then counts inside the lightbox, so it is drawn above
|
|
162
|
+
* the content instead of under the scrim, and a press on it is a press inside
|
|
163
|
+
* the lightbox.
|
|
164
|
+
*/
|
|
165
|
+
function LightboxPortal({ className, ...props }) {
|
|
166
|
+
const { portal } = lightbox();
|
|
132
167
|
return /* @__PURE__ */ jsx(Dialog.Portal, {
|
|
133
168
|
"data-slot": "lightbox-portal",
|
|
134
|
-
...useThemeScopeProps(
|
|
169
|
+
...useThemeScopeProps({
|
|
170
|
+
...props,
|
|
171
|
+
className: portal({ className })
|
|
172
|
+
})
|
|
135
173
|
});
|
|
136
174
|
}
|
|
137
|
-
|
|
138
|
-
|
|
175
|
+
const BODY_SELECTOR = "[data-slot=\"lightbox-body\"]";
|
|
176
|
+
/** The browser's own steps: an arrow key's line, and the share of the view a page keeps. */
|
|
177
|
+
const LINE_STEP = 40;
|
|
178
|
+
const PAGE_FRACTION = .875;
|
|
179
|
+
/**
|
|
180
|
+
* Where a key the browser scrolls with takes the body, or `null` for a key
|
|
181
|
+
* that doesn't scroll (or is the browser's own shortcut, such as Ctrl+Page Down).
|
|
182
|
+
*/
|
|
183
|
+
function scrollKeyTarget(event, body) {
|
|
184
|
+
const { altKey, ctrlKey, key, metaKey, shiftKey } = event;
|
|
185
|
+
if (altKey) return null;
|
|
186
|
+
const page = body.clientHeight * PAGE_FRACTION;
|
|
187
|
+
const { scrollLeft: left, scrollTop: top } = body;
|
|
188
|
+
const start = {
|
|
189
|
+
left,
|
|
190
|
+
top: 0
|
|
191
|
+
};
|
|
192
|
+
const end = {
|
|
193
|
+
left,
|
|
194
|
+
top: body.scrollHeight
|
|
195
|
+
};
|
|
196
|
+
if (ctrlKey || metaKey) {
|
|
197
|
+
if (key === "ArrowUp" || key === "Home") return start;
|
|
198
|
+
if (key === "ArrowDown" || key === "End") return end;
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
switch (key) {
|
|
202
|
+
case "ArrowUp": return {
|
|
203
|
+
left,
|
|
204
|
+
top: top - LINE_STEP
|
|
205
|
+
};
|
|
206
|
+
case "ArrowDown": return {
|
|
207
|
+
left,
|
|
208
|
+
top: top + LINE_STEP
|
|
209
|
+
};
|
|
210
|
+
case "ArrowLeft": return {
|
|
211
|
+
left: left - LINE_STEP,
|
|
212
|
+
top
|
|
213
|
+
};
|
|
214
|
+
case "ArrowRight": return {
|
|
215
|
+
left: left + LINE_STEP,
|
|
216
|
+
top
|
|
217
|
+
};
|
|
218
|
+
case "PageUp": return {
|
|
219
|
+
left,
|
|
220
|
+
top: top - page
|
|
221
|
+
};
|
|
222
|
+
case "PageDown": return {
|
|
223
|
+
left,
|
|
224
|
+
top: top + page
|
|
225
|
+
};
|
|
226
|
+
case " ": return {
|
|
227
|
+
left,
|
|
228
|
+
top: shiftKey ? top - page : top + page
|
|
229
|
+
};
|
|
230
|
+
case "Home": return start;
|
|
231
|
+
case "End": return end;
|
|
232
|
+
default: return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/** Whether `element` takes the key itself: a text field edits with it, a button presses with Space. */
|
|
236
|
+
function takesKey(element, key) {
|
|
237
|
+
if (element instanceof HTMLElement && element.isContentEditable) return true;
|
|
238
|
+
if (element.closest("input, textarea, select")) return true;
|
|
239
|
+
return key === " " && element.closest("button, summary, [role=\"button\"]") !== null;
|
|
240
|
+
}
|
|
241
|
+
/** Whether `element`, or a parent of it inside `popup`, scrolls: the browser scrolls that one. */
|
|
242
|
+
function inScroller(element, popup) {
|
|
243
|
+
for (let node = element; node && node !== popup; node = node.parentElement) {
|
|
244
|
+
const { overflowX, overflowY } = getComputedStyle(node);
|
|
245
|
+
if (/auto|scroll/.test(overflowY) && node.scrollHeight > node.clientHeight) return true;
|
|
246
|
+
if (/auto|scroll/.test(overflowX) && node.scrollWidth > node.clientWidth) return true;
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Document mode doesn't lock the page, so a key that would scroll it from
|
|
252
|
+
* outside the body (focus on a toolbar button, or on the content after a tap)
|
|
253
|
+
* scrolls `LightboxBody` instead, and never the page under the scrim. A key
|
|
254
|
+
* from inside a scroller is that scroller's; a key a control uses, or one a
|
|
255
|
+
* handler already took (a menu's arrows), is left alone. A popup opened
|
|
256
|
+
* inside is portaled beside the content, so its keys never come here.
|
|
257
|
+
*/
|
|
258
|
+
function routeScrollKey(event) {
|
|
259
|
+
const popup = event.currentTarget;
|
|
260
|
+
const target = event.target;
|
|
261
|
+
if (event.defaultPrevented || !popup.contains(target)) return;
|
|
262
|
+
if (takesKey(target, event.key) || inScroller(target, popup)) return;
|
|
263
|
+
const body = popup.querySelector(BODY_SELECTOR);
|
|
264
|
+
const to = scrollKeyTarget(event, body ?? popup);
|
|
265
|
+
if (to === null) return;
|
|
266
|
+
event.preventDefault();
|
|
267
|
+
body?.scrollTo(to);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* The full-screen layer, with the scrim behind it. Popups opened inside it
|
|
271
|
+
* are drawn above it (`LightboxPortal`). `initialFocus` and `finalFocus` are
|
|
272
|
+
* `false` by default, so focus doesn't move when it opens or closes, except
|
|
273
|
+
* in document mode (`modal="trap-focus"`): focus moves into the lightbox when
|
|
274
|
+
* it opens and back to `LightboxTrigger` when it closes. It lands on
|
|
275
|
+
* `LightboxBody`, so the keys that scroll scroll the document at once; on the
|
|
276
|
+
* first control when there is no body; and on the lightbox itself after a
|
|
277
|
+
* tap, so a phone shows no ring and opens no keyboard. A key that would
|
|
278
|
+
* scroll the page under the scrim scrolls the body instead.
|
|
279
|
+
*
|
|
280
|
+
* A lightbox opened from state passes `finalFocus={openerRef}` so focus goes
|
|
281
|
+
* back to what opened it.
|
|
282
|
+
*/
|
|
283
|
+
function LightboxContent({ className, initialFocus, finalFocus, onKeyDown, ref, ...props }) {
|
|
284
|
+
const documentMode = useContext(LightboxModalContext) === "trap-focus";
|
|
285
|
+
const nested = useParentOverlayKind() != null;
|
|
286
|
+
const { backdrop, content } = lightbox({ nested });
|
|
287
|
+
const [setRef, getRef] = useMergedRef(ref);
|
|
288
|
+
const documentInitialFocus = useCallback((openType) => {
|
|
289
|
+
const popup = getRef();
|
|
290
|
+
if (openType === "touch") return popup;
|
|
291
|
+
return popup?.querySelector(BODY_SELECTOR) ?? true;
|
|
292
|
+
}, [getRef]);
|
|
293
|
+
const handleKeyDown = useCallback((event) => {
|
|
294
|
+
onKeyDown?.(event);
|
|
295
|
+
if (documentMode) routeScrollKey(event);
|
|
296
|
+
}, [documentMode, onKeyDown]);
|
|
139
297
|
return /* @__PURE__ */ jsxs(LightboxPortal, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
140
298
|
"data-slot": "lightbox-backdrop",
|
|
299
|
+
"data-nested": nested ? "" : void 0,
|
|
300
|
+
forceRender: true,
|
|
141
301
|
className: backdrop()
|
|
142
302
|
}), /* @__PURE__ */ jsx(Dialog.Popup, {
|
|
143
303
|
"data-slot": "lightbox-content",
|
|
144
|
-
|
|
145
|
-
|
|
304
|
+
ref: setRef,
|
|
305
|
+
initialFocus: initialFocus ?? (documentMode ? documentInitialFocus : false),
|
|
306
|
+
finalFocus: finalFocus ?? documentMode,
|
|
146
307
|
className: content({ className }),
|
|
308
|
+
onKeyDown: handleKeyDown,
|
|
147
309
|
...props
|
|
148
310
|
})] });
|
|
149
311
|
}
|
|
@@ -207,6 +369,38 @@ function LightboxActions({ render, className, ...props }) {
|
|
|
207
369
|
state: { slot: "lightbox-actions" }
|
|
208
370
|
});
|
|
209
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* The scrolling body of a document-mode lightbox (`modal="trap-focus"`),
|
|
374
|
+
* under `LightboxToolbar`: a ScrollArea that fills the rest of the content
|
|
375
|
+
* (`min-h-0 flex-1`) on `layer-canvas`, the toolbar's surface. Pass a
|
|
376
|
+
* `className` for another surface (`bg-layer-sidebar`). It takes the pointer
|
|
377
|
+
* back from `LightboxContent`, which lets it through to the scrim, and never
|
|
378
|
+
* passes a scroll on to the page under the scrim (`overscroll-contain`, also
|
|
379
|
+
* while it has nothing to scroll; `overscroll-none` in `className` also stops
|
|
380
|
+
* the bounce). Every other ScrollArea prop, `render` included, is the area's.
|
|
381
|
+
*
|
|
382
|
+
* It is a tab stop even when it has nothing to scroll (`tabIndex={0}`), as it
|
|
383
|
+
* takes focus when the lightbox opens, and draws its focus ring inside its
|
|
384
|
+
* edge, which is the window's. Its content keeps clear of a phone's safe
|
|
385
|
+
* areas at the bottom and the sides, around the caller's own content box
|
|
386
|
+
* (`contentClassName`), so the scrollbar stays at the edge.
|
|
387
|
+
*/
|
|
388
|
+
function LightboxBody({ children, className, contentClassName, contentStyle, ...props }) {
|
|
389
|
+
const { body, bodyContent } = lightbox();
|
|
390
|
+
return /* @__PURE__ */ jsx(ScrollArea, {
|
|
391
|
+
"data-slot": "lightbox-body",
|
|
392
|
+
tabIndex: 0,
|
|
393
|
+
...props,
|
|
394
|
+
className: body({ className }),
|
|
395
|
+
contentClassName: bodyContent(),
|
|
396
|
+
children: contentClassName !== void 0 || contentStyle !== void 0 ? /* @__PURE__ */ jsx("div", {
|
|
397
|
+
"data-slot": "lightbox-body-content",
|
|
398
|
+
className: contentClassName,
|
|
399
|
+
style: contentStyle,
|
|
400
|
+
children
|
|
401
|
+
}) : children
|
|
402
|
+
});
|
|
403
|
+
}
|
|
210
404
|
function LightboxStage({ render, className, ...props }) {
|
|
211
405
|
const { stage } = lightbox();
|
|
212
406
|
const defaultProps = { className: stage({ className }) };
|
|
@@ -333,4 +527,4 @@ function LightboxClose({ className, render, ...props }) {
|
|
|
333
527
|
});
|
|
334
528
|
}
|
|
335
529
|
//#endregion
|
|
336
|
-
export { Lightbox, LightboxActions, LightboxClose, LightboxContent, LightboxHeader, LightboxHeaderLabel, LightboxHeaderMeta, LightboxInfoActions, LightboxInfoBar, LightboxInfoDock, LightboxInfoTitle, LightboxMedia, LightboxNavigationButton, LightboxPortal, LightboxStage, LightboxThumbnail, LightboxThumbnailStrip, LightboxTitle, LightboxToolbar, LightboxTrigger };
|
|
530
|
+
export { Lightbox, LightboxActions, LightboxBody, LightboxClose, LightboxContent, LightboxHeader, LightboxHeaderLabel, LightboxHeaderMeta, LightboxInfoActions, LightboxInfoBar, LightboxInfoDock, LightboxInfoTitle, LightboxMedia, LightboxNavigationButton, LightboxPortal, LightboxStage, LightboxThumbnail, LightboxThumbnailStrip, LightboxTitle, LightboxToolbar, LightboxTrigger };
|
|
@@ -24,6 +24,19 @@ export type ListRowProps = useRender.ComponentProps<"button"> & Pick<VariantProp
|
|
|
24
24
|
* `flex flex-col gap-0.5 py-2` column. A settings card keeps the default
|
|
25
25
|
* look, with its lines. */
|
|
26
26
|
cell?: boolean;
|
|
27
|
+
/** The row belongs to the setting in the row above it, in the same
|
|
28
|
+
* `ListRowGroup`: quiet hours' start and end times under Quiet hours, a
|
|
29
|
+
* server's channel overrides under its notification level. It draws no
|
|
30
|
+
* hairline above it (a hairline says "another setting"), and a `plain`
|
|
31
|
+
* row has no top padding, so it follows the row it belongs to. The row
|
|
32
|
+
* above keeps its own height and its switch, centred on its own title
|
|
33
|
+
* and description, doesn't move. The row after it draws its hairline as
|
|
34
|
+
* usual. An interactive one keeps the control height as its least, so
|
|
35
|
+
* it stays a 44px target on a phone and a touch screen. Carries
|
|
36
|
+
* `data-attached`. Tie it to its setting for assistive technology: a
|
|
37
|
+
* display-only one takes `role="group"` and `aria-labelledby` the
|
|
38
|
+
* setting's title id; an interactive one, `aria-describedby` that id. */
|
|
39
|
+
attached?: boolean;
|
|
27
40
|
};
|
|
28
41
|
/**
|
|
29
42
|
* One row of a list. It renders a `button` by default; pass `render={<a />}`
|
|
@@ -31,7 +44,7 @@ export type ListRowProps = useRender.ComponentProps<"button"> & Pick<VariantProp
|
|
|
31
44
|
* block (an avatar, a channel or icon tile, `ListRowIcon`), `ListRowBody`, and
|
|
32
45
|
* anything trailing (a value, a badge, a switch, `ListRowChevron`).
|
|
33
46
|
*/
|
|
34
|
-
export declare function ListRow({ variant, tone, selected, interactive, cell, className, render, ...props }: ListRowProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
47
|
+
export declare function ListRow({ variant, tone, selected, interactive, cell, attached, className, render, ...props }: ListRowProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
35
48
|
export type ListRowIconProps = useRender.ComponentProps<"span">;
|
|
36
49
|
/** A 20px leading icon in ink-3: entry rows and settings. */
|
|
37
50
|
export declare function ListRowIcon({ className, render, ...props }: ListRowIconProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
@@ -23,17 +23,19 @@ function ListRowGroup({ className, render, ...props }) {
|
|
|
23
23
|
* block (an avatar, a channel or icon tile, `ListRowIcon`), `ListRowBody`, and
|
|
24
24
|
* anything trailing (a value, a badge, a switch, `ListRowChevron`).
|
|
25
25
|
*/
|
|
26
|
-
function ListRow({ variant = "default", tone = "default", selected = false, interactive = true, cell = false, className, render, ...props }) {
|
|
26
|
+
function ListRow({ variant = "default", tone = "default", selected = false, interactive = true, cell = false, attached = false, className, render, ...props }) {
|
|
27
27
|
const { root } = listRow({
|
|
28
28
|
variant,
|
|
29
29
|
interactive,
|
|
30
|
-
cell
|
|
30
|
+
cell,
|
|
31
|
+
attached
|
|
31
32
|
});
|
|
32
33
|
const defaultProps = {
|
|
33
34
|
"data-slot": "list-row",
|
|
34
35
|
"data-variant": variant,
|
|
35
36
|
"data-tone": tone === "default" ? void 0 : tone,
|
|
36
37
|
"data-selected": selected ? "" : void 0,
|
|
38
|
+
"data-attached": attached ? "" : void 0,
|
|
37
39
|
className: root({ className }),
|
|
38
40
|
...interactive && !render ? { type: "button" } : {}
|
|
39
41
|
};
|