@botiverse/raft-ui 0.83.0 → 0.85.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 +125 -0
- package/dist/cn.d.mts +2 -0
- package/dist/cn.mjs +21 -1
- package/dist/components/alert-dialog/alert-dialog.mjs +2 -2
- package/dist/components/app-link-card/app-link-card.mjs +19 -37
- package/dist/components/app-shell/app-shell.mjs +2 -2
- package/dist/components/avatar/avatar.mjs +1 -1
- package/dist/components/banner/banner.mjs +15 -2
- package/dist/components/button/button-split.mjs +2 -2
- package/dist/components/button/button.mjs +2 -2
- package/dist/components/choice-list/choice-list.recipe.mjs +1 -1
- package/dist/components/code-block/code-block.recipe.mjs +2 -2
- package/dist/components/combobox/combobox.mjs +1 -1
- package/dist/components/combobox-select/combobox-select.css +1 -1
- package/dist/components/comment/comment.recipe.mjs +2 -2
- package/dist/components/composer/composer-attachment.recipe.mjs +5 -5
- package/dist/components/composer/composer-drop-overlay.mjs +2 -2
- package/dist/components/composer/composer-drop-overlay.recipe.mjs +1 -1
- package/dist/components/composer/sortable-composer-attachments.mjs +1 -1
- package/dist/components/context-menu/context-menu.mjs +1 -1
- package/dist/components/conversation-panel/conversation-panel-empty-state.mjs +1 -1
- package/dist/components/dialog/dialog.mjs +4 -4
- package/dist/components/drag/drag-lift.d.mts +3 -2
- package/dist/components/drag/drag-lift.mjs +3 -2
- package/dist/components/drag/drag.recipe.mjs +1 -1
- package/dist/components/drawer/drawer.recipe.mjs +4 -4
- package/dist/components/dropdown-menu/dropdown-menu.mjs +1 -1
- package/dist/components/file-preview/file-preview.recipe.mjs +1 -1
- package/dist/components/fit-toolbar/fit-toolbar.d.mts +63 -8
- package/dist/components/fit-toolbar/fit-toolbar.mjs +310 -43
- package/dist/components/fit-toolbar/fit-toolbar.recipe.mjs +21 -7
- package/dist/components/fit-toolbar/index.d.mts +2 -2
- package/dist/components/inbox-item/inbox-item.recipe.mjs +7 -7
- 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 +12 -0
- package/dist/components/list-row/list-row.recipe.mjs +19 -7
- 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-attachment/message-image-gallery.recipe.mjs +1 -1
- 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-item/message-item.recipe.mjs +2 -2
- package/dist/components/message-list/message-list.recipe.mjs +2 -2
- 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.mjs +2 -2
- package/dist/components/notification-center/notification-center.mjs +1 -1
- package/dist/components/panel/panel-header.recipe.mjs +1 -1
- package/dist/components/panel/panel-split-action.recipe.mjs +2 -2
- 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 +25 -28
- package/dist/components/pull-to-refresh/pull-to-refresh-indicator.mjs +1 -1
- package/dist/components/resizable/resizable.recipe.mjs +1 -1
- package/dist/components/save-status/save-status.d.mts +16 -9
- package/dist/components/save-status/save-status.mjs +19 -30
- package/dist/components/scroll-area/scroll-area.css +1 -0
- package/dist/components/segmented-control/segmented-control.mjs +45 -8
- package/dist/components/select/select.mjs +2 -2
- package/dist/components/selection-toolbar/selection-toolbar.recipe.mjs +1 -1
- package/dist/components/sidebar/sidebar.recipe.mjs +1 -1
- package/dist/components/tabs/tabs.mjs +4 -4
- 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/task-dnd/task-dnd.recipe.mjs +2 -2
- package/dist/components/thread-panel/thread-panel.recipe.mjs +1 -1
- package/dist/components/toast/toast.mjs +5 -5
- package/dist/components/tooltip/tooltip.mjs +2 -2
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/lib/laid-out-children.mjs +32 -0
- package/dist/lib/list-cell.mjs +1 -1
- package/dist/lib/stacked-actions.mjs +7 -4
- package/dist/lint/no-raw-z-index.mjs +142 -0
- package/dist/lint/prefer-scroll-area.mjs +1 -1
- package/dist/lint/recommended.json +2 -1
- package/dist/lint.d.mts +8 -2
- package/dist/lint.mjs +16 -3
- package/dist/styles.css +28 -0
- package/dist/wip.d.mts +4 -2
- package/dist/wip.mjs +3 -2
- package/package.json +1 -1
- package/skills/raft-ui-guide/SKILL.md +1 -0
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
import { tv } from "../../lib/tv.mjs";
|
|
2
2
|
import { useThemeScopeProps } from "../../lib/theme/theme-scope.mjs";
|
|
3
3
|
import { usePopupCollision } from "../../lib/frame-insets.mjs";
|
|
4
|
+
import { messageCard } from "../message-embed/message-embed.recipe.mjs";
|
|
5
|
+
import { createContext, useContext } from "react";
|
|
4
6
|
import { jsx } from "react/jsx-runtime";
|
|
5
7
|
import { Popover } from "@base-ui/react/popover";
|
|
6
8
|
//#region src/components/popover/popover.tsx
|
|
7
|
-
const popover = tv({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
9
|
+
const popover = tv({
|
|
10
|
+
slots: {
|
|
11
|
+
trigger: ["select-none"],
|
|
12
|
+
positioner: ["isolate z-popup outline-none"],
|
|
13
|
+
content: [
|
|
14
|
+
"max-h-(--available-height) min-w-[220px] overflow-hidden",
|
|
15
|
+
"outline-none",
|
|
16
|
+
"rounded-container bg-layer-popover text-foreground",
|
|
17
|
+
"shadow-float ring-1 ring-line-seam"
|
|
18
|
+
],
|
|
19
|
+
header: ["flex items-center justify-between px-3", "min-h-11 gap-2 py-1.5 pr-1.5 pl-4"],
|
|
20
|
+
body: ["flex min-w-0 flex-col gap-1.5", "px-4 pt-4 pb-3 last:pb-4"],
|
|
21
|
+
actions: ["flex flex-wrap items-center justify-end gap-2", "px-4 pb-3 last:pb-4"],
|
|
22
|
+
separator: ["border-t", "border-line-hairline"],
|
|
23
|
+
title: ["m-0", "font-sans text-headline font-bold text-foreground"],
|
|
24
|
+
description: ["m-0", "font-sans text-footnote text-foreground-muted"],
|
|
25
|
+
close: [
|
|
26
|
+
"inline-flex items-center justify-center",
|
|
27
|
+
"outline-none transition-colors",
|
|
28
|
+
"h-8 min-w-8 rounded-chip px-1.5",
|
|
29
|
+
"font-sans text-footnote font-bold text-foreground",
|
|
30
|
+
"hover:bg-fill-medium active:bg-fill-medium",
|
|
31
|
+
"focus-visible:shadow-focus",
|
|
32
|
+
"[&_svg]:size-4.5"
|
|
33
|
+
],
|
|
34
|
+
arrow: ["size-2 rotate-45", "border-l border-t border-line-seam bg-layer-popover"],
|
|
35
|
+
backdrop: ["fixed inset-0", "bg-transparent"],
|
|
36
|
+
viewport: ["block"]
|
|
37
|
+
},
|
|
38
|
+
variants: { size: {
|
|
39
|
+
default: {},
|
|
40
|
+
item: { content: messageCard().popover() }
|
|
41
|
+
} }
|
|
42
|
+
});
|
|
43
|
+
const PopoverSizeContext = createContext("default");
|
|
35
44
|
function Popover$1(props) {
|
|
36
45
|
return /* @__PURE__ */ jsx(Popover.Root, {
|
|
37
46
|
"data-slot": "popover",
|
|
@@ -67,8 +76,8 @@ function PopoverFramePositioner({ collisionBoundary, collisionPadding, container
|
|
|
67
76
|
...props
|
|
68
77
|
});
|
|
69
78
|
}
|
|
70
|
-
function PopoverContent({ align = "start", alignOffset = 0, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking, positionMethod = "fixed", side = "bottom", sideOffset = 4, sticky, container, portalProps, className, ...props }) {
|
|
71
|
-
const { positioner, content } = popover();
|
|
79
|
+
function PopoverContent({ align = "start", alignOffset = 0, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking, positionMethod = "fixed", side = "bottom", sideOffset = 4, sticky, container, portalProps, size = "default", className, ...props }) {
|
|
80
|
+
const { positioner, content } = popover({ size });
|
|
72
81
|
const portalContainer = container !== void 0 ? container : portalProps?.container;
|
|
73
82
|
return /* @__PURE__ */ jsx(PopoverPortal, {
|
|
74
83
|
...portalProps,
|
|
@@ -88,10 +97,14 @@ function PopoverContent({ align = "start", alignOffset = 0, anchor, arrowPadding
|
|
|
88
97
|
sideOffset,
|
|
89
98
|
sticky,
|
|
90
99
|
className: positioner(),
|
|
91
|
-
children: /* @__PURE__ */ jsx(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
children: /* @__PURE__ */ jsx(PopoverSizeContext.Provider, {
|
|
101
|
+
value: size,
|
|
102
|
+
children: /* @__PURE__ */ jsx(Popover.Popup, {
|
|
103
|
+
"data-slot": "popover-content",
|
|
104
|
+
"data-size": size,
|
|
105
|
+
className: content({ className }),
|
|
106
|
+
...props
|
|
107
|
+
})
|
|
95
108
|
})
|
|
96
109
|
})
|
|
97
110
|
});
|
|
@@ -123,7 +136,7 @@ function PopoverSeparator({ className, ...props }) {
|
|
|
123
136
|
});
|
|
124
137
|
}
|
|
125
138
|
function PopoverTitle({ className, ...props }) {
|
|
126
|
-
const
|
|
139
|
+
const title = useContext(PopoverSizeContext) === "item" ? messageCard().title : popover().title;
|
|
127
140
|
return /* @__PURE__ */ jsx(Popover.Title, {
|
|
128
141
|
"data-slot": "popover-title",
|
|
129
142
|
className: title({ className }),
|
|
@@ -162,9 +175,9 @@ function PopoverBackdrop({ className, ...props }) {
|
|
|
162
175
|
...props
|
|
163
176
|
});
|
|
164
177
|
}
|
|
165
|
-
/** The panel's text: a `PopoverTitle` and a `PopoverDescription`, 16px in from its edges. */
|
|
178
|
+
/** The panel's text: a `PopoverTitle` and a `PopoverDescription`, 16px in from its edges (12px in a `size="item"` popover). */
|
|
166
179
|
function PopoverBody({ className, ...props }) {
|
|
167
|
-
const
|
|
180
|
+
const body = useContext(PopoverSizeContext) === "item" ? messageCard().body : popover().body;
|
|
168
181
|
return /* @__PURE__ */ jsx("div", {
|
|
169
182
|
"data-slot": "popover-body",
|
|
170
183
|
className: body({ className }),
|
|
@@ -173,7 +186,7 @@ function PopoverBody({ className, ...props }) {
|
|
|
173
186
|
}
|
|
174
187
|
/** The panel's buttons, at its end, under `PopoverBody`: the way out first, then the confirm button. */
|
|
175
188
|
function PopoverActions({ className, ...props }) {
|
|
176
|
-
const
|
|
189
|
+
const actions = useContext(PopoverSizeContext) === "item" ? messageCard().actions : popover().actions;
|
|
177
190
|
return /* @__PURE__ */ jsx("div", {
|
|
178
191
|
"data-slot": "popover-actions",
|
|
179
192
|
className: actions({ className }),
|
|
@@ -28,7 +28,11 @@ export declare function PreviewCardDescription({ className, ...props }: PreviewC
|
|
|
28
28
|
export type PreviewCardArrowProps = StyledProps<PreviewCard.Arrow.Props>;
|
|
29
29
|
export declare function PreviewCardArrow({ className, ...props }: PreviewCardArrowProps): import("react").JSX.Element;
|
|
30
30
|
export type PreviewCardBodyProps = ComponentPropsWithRef<"div">;
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* The item card's block: the id line, the title and the details row, in that
|
|
33
|
+
* order. Its parts are a card's in a message (AppLinkCard), so the two read
|
|
34
|
+
* the same.
|
|
35
|
+
*/
|
|
32
36
|
export declare function PreviewCardBody({ className, ...props }: PreviewCardBodyProps): import("react").JSX.Element;
|
|
33
37
|
export type PreviewCardEyebrowProps = ComponentPropsWithRef<"p">;
|
|
34
38
|
/** The muted line above the title that identifies the item, such as its id. One line, truncated. */
|
|
@@ -2,13 +2,15 @@ import { tv } from "../../lib/tv.mjs";
|
|
|
2
2
|
import { useTheme } from "../../lib/theme/use-theme.mjs";
|
|
3
3
|
import { resolveThemeScopeProps, useThemeScopeProps } from "../../lib/theme/theme-scope.mjs";
|
|
4
4
|
import { usePopupCollision } from "../../lib/frame-insets.mjs";
|
|
5
|
+
import { messageCard } from "../message-embed/message-embed.recipe.mjs";
|
|
6
|
+
import { createContext, useContext } from "react";
|
|
5
7
|
import { jsx } from "react/jsx-runtime";
|
|
6
8
|
import { PreviewCard } from "@base-ui/react/preview-card";
|
|
7
9
|
//#region src/components/preview-card/preview-card.tsx
|
|
8
10
|
const previewCard = tv({
|
|
9
11
|
slots: {
|
|
10
12
|
trigger: [],
|
|
11
|
-
positioner: ["isolate z-
|
|
13
|
+
positioner: ["isolate z-popup outline-none"],
|
|
12
14
|
popup: [
|
|
13
15
|
"max-h-(--available-height) min-w-[220px] overflow-hidden",
|
|
14
16
|
"outline-none",
|
|
@@ -24,24 +26,11 @@ const previewCard = tv({
|
|
|
24
26
|
separator: ["border-t", "border-line-hairline"],
|
|
25
27
|
title: ["m-0 truncate", "font-sans text-headline font-bold text-foreground"],
|
|
26
28
|
description: ["m-0 truncate", "px-4 py-3 last:pb-4 font-sans text-callout text-foreground-muted"],
|
|
27
|
-
arrow: ["size-2 rotate-45", "border-l border-t border-line-seam bg-layer-popover"]
|
|
28
|
-
body: [
|
|
29
|
-
"flex min-w-0 flex-col gap-1.5",
|
|
30
|
-
"px-4 pt-4 pb-3 last:pb-4",
|
|
31
|
-
"*:data-[slot=preview-card-title]:line-clamp-2 *:data-[slot=preview-card-title]:whitespace-normal"
|
|
32
|
-
],
|
|
33
|
-
eyebrow: ["m-0 truncate", "font-mono text-mono-meta text-foreground-muted"],
|
|
34
|
-
meta: ["flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", "m-0 font-sans text-callout text-foreground-muted"],
|
|
35
|
-
actions: ["flex flex-wrap items-center justify-end gap-2", "px-4 pb-3 last:pb-4"],
|
|
36
|
-
footer: [
|
|
37
|
-
"m-0 truncate",
|
|
38
|
-
"border-t border-line-hairline px-4 py-2",
|
|
39
|
-
"font-sans text-caption text-foreground-muted"
|
|
40
|
-
]
|
|
29
|
+
arrow: ["size-2 rotate-45", "border-l border-t border-line-seam bg-layer-popover"]
|
|
41
30
|
},
|
|
42
31
|
variants: { size: {
|
|
43
32
|
profile: { popup: "w-[300px]" },
|
|
44
|
-
item: { popup:
|
|
33
|
+
item: { popup: messageCard().popover() }
|
|
45
34
|
} },
|
|
46
35
|
defaultVariants: { size: "profile" }
|
|
47
36
|
});
|
|
@@ -132,8 +121,9 @@ function PreviewCardSeparator({ className, ...props }) {
|
|
|
132
121
|
...props
|
|
133
122
|
});
|
|
134
123
|
}
|
|
124
|
+
const InItemBody = createContext(false);
|
|
135
125
|
function PreviewCardTitle({ className, ...props }) {
|
|
136
|
-
const
|
|
126
|
+
const title = useContext(InItemBody) ? messageCard().title : previewCard().title;
|
|
137
127
|
return /* @__PURE__ */ jsx("p", {
|
|
138
128
|
"data-slot": "preview-card-title",
|
|
139
129
|
className: title({ className }),
|
|
@@ -156,18 +146,25 @@ function PreviewCardArrow({ className, ...props }) {
|
|
|
156
146
|
...props
|
|
157
147
|
});
|
|
158
148
|
}
|
|
159
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* The item card's block: the id line, the title and the details row, in that
|
|
151
|
+
* order. Its parts are a card's in a message (AppLinkCard), so the two read
|
|
152
|
+
* the same.
|
|
153
|
+
*/
|
|
160
154
|
function PreviewCardBody({ className, ...props }) {
|
|
161
|
-
const { body } =
|
|
162
|
-
return /* @__PURE__ */ jsx(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
const { body } = messageCard();
|
|
156
|
+
return /* @__PURE__ */ jsx(InItemBody.Provider, {
|
|
157
|
+
value: true,
|
|
158
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
159
|
+
"data-slot": "preview-card-body",
|
|
160
|
+
className: body({ className }),
|
|
161
|
+
...props
|
|
162
|
+
})
|
|
166
163
|
});
|
|
167
164
|
}
|
|
168
165
|
/** The muted line above the title that identifies the item, such as its id. One line, truncated. */
|
|
169
166
|
function PreviewCardEyebrow({ className, ...props }) {
|
|
170
|
-
const { eyebrow } =
|
|
167
|
+
const { eyebrow } = messageCard();
|
|
171
168
|
return /* @__PURE__ */ jsx("p", {
|
|
172
169
|
"data-slot": "preview-card-eyebrow",
|
|
173
170
|
className: eyebrow({ className }),
|
|
@@ -176,7 +173,7 @@ function PreviewCardEyebrow({ className, ...props }) {
|
|
|
176
173
|
}
|
|
177
174
|
/** The row under the title: one state chip, then muted details. Wraps when it runs out of room. */
|
|
178
175
|
function PreviewCardMeta({ className, ...props }) {
|
|
179
|
-
const { meta } =
|
|
176
|
+
const { meta } = messageCard();
|
|
180
177
|
return /* @__PURE__ */ jsx("div", {
|
|
181
178
|
"data-slot": "preview-card-meta",
|
|
182
179
|
className: meta({ className }),
|
|
@@ -185,7 +182,7 @@ function PreviewCardMeta({ className, ...props }) {
|
|
|
185
182
|
}
|
|
186
183
|
/** The row of at most two buttons. */
|
|
187
184
|
function PreviewCardActions({ className, ...props }) {
|
|
188
|
-
const { actions } =
|
|
185
|
+
const { actions } = messageCard();
|
|
189
186
|
return /* @__PURE__ */ jsx("div", {
|
|
190
187
|
"data-slot": "preview-card-actions",
|
|
191
188
|
className: actions({ className }),
|
|
@@ -194,10 +191,10 @@ function PreviewCardActions({ className, ...props }) {
|
|
|
194
191
|
}
|
|
195
192
|
/** The caption under a hairline at the bottom of the card: where the item comes from. */
|
|
196
193
|
function PreviewCardFooter({ className, ...props }) {
|
|
197
|
-
const {
|
|
194
|
+
const { sourceFooter } = messageCard();
|
|
198
195
|
return /* @__PURE__ */ jsx("p", {
|
|
199
196
|
"data-slot": "preview-card-footer",
|
|
200
|
-
className:
|
|
197
|
+
className: sourceFooter({ className }),
|
|
201
198
|
...props
|
|
202
199
|
});
|
|
203
200
|
}
|
|
@@ -45,7 +45,7 @@ const pullToRefreshIndicator = tv({
|
|
|
45
45
|
surface: ["size-full"]
|
|
46
46
|
},
|
|
47
47
|
android: {
|
|
48
|
-
root: ["sticky top-0 z-
|
|
48
|
+
root: ["sticky top-0 z-sticky h-0 overflow-visible"],
|
|
49
49
|
surface: [
|
|
50
50
|
"absolute inset-x-0 top-0 mx-auto size-10 rounded-full bg-layer-popover shadow-float",
|
|
51
51
|
"translate-y-[calc(var(--pull-distance)-100%)]",
|
|
@@ -4,7 +4,7 @@ const resizable = tv({ slots: {
|
|
|
4
4
|
group: ["flex size-full min-h-0 min-w-0", "data-[orientation=vertical]:flex-col"],
|
|
5
5
|
panel: ["min-h-0 min-w-0"],
|
|
6
6
|
handle: [
|
|
7
|
-
"right-0 z-
|
|
7
|
+
"right-0 z-control cursor-ew-resize touch-none select-none",
|
|
8
8
|
"relative -mr-3 flex w-3 shrink-0 items-center justify-center pointer-coarse:-mr-6 pointer-coarse:w-6",
|
|
9
9
|
"before:pointer-events-none before:absolute before:transition-colors before:content-['']",
|
|
10
10
|
"focus-visible:outline-none focus-visible:before:outline-2 focus-visible:before:outline-offset-2 focus-visible:before:outline-foreground",
|
|
@@ -2,22 +2,29 @@ import { ComponentPropsWithRef } from "react";
|
|
|
2
2
|
//#region src/components/save-status/save-status.d.ts
|
|
3
3
|
export type SaveStatusProps = ComponentPropsWithRef<"span">;
|
|
4
4
|
/**
|
|
5
|
-
* The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The line under a setting that applies at once. Render it whatever the
|
|
6
|
+
* setting's state, with `SaveStatusError` inside when the change failed and
|
|
7
|
+
* nothing inside otherwise: empty, it is hidden and takes no height. A `span`
|
|
8
|
+
* (shown as a block), like every ListRow part, so it stays valid inside a
|
|
9
|
+
* row's body; give it an `id` for the control's `aria-describedby`.
|
|
8
10
|
*/
|
|
9
11
|
export declare function SaveStatus({ className, ...props }: SaveStatusProps): import("react").JSX.Element;
|
|
10
12
|
export type SaveStatusSavedProps = ComponentPropsWithRef<"span">;
|
|
11
13
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* @deprecated A setting that applies at once no longer says "Saved": the
|
|
15
|
+
* control showing its new value is the confirmation (Forms, settings that
|
|
16
|
+
* apply at once). Renders nothing, whatever its children, so its
|
|
17
|
+
* `SaveStatus` stays empty and takes no height. Leave it out: render
|
|
18
|
+
* `SaveStatusError` when the change failed and nothing otherwise. It drops
|
|
19
|
+
* every prop, its `id` too: point a control's `aria-describedby` at the
|
|
20
|
+
* `SaveStatus` instead.
|
|
15
21
|
*/
|
|
16
|
-
export declare function SaveStatusSaved(
|
|
22
|
+
export declare function SaveStatusSaved(_props: SaveStatusSavedProps): null;
|
|
17
23
|
export type SaveStatusErrorProps = ComponentPropsWithRef<"span">;
|
|
18
24
|
/**
|
|
19
|
-
* What failed
|
|
20
|
-
*
|
|
25
|
+
* What failed. It is an alert, announced when it appears, and stays until
|
|
26
|
+
* the next change. Its line appears with it, so the setting grows by one
|
|
27
|
+
* line while it shows.
|
|
21
28
|
*/
|
|
22
29
|
export declare function SaveStatusError({ className, role, ...props }: SaveStatusErrorProps): import("react").JSX.Element;
|
|
23
30
|
//#endregion
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
import { tv } from "../../lib/tv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
3
|
//#region src/components/save-status/save-status.tsx
|
|
5
4
|
const saveStatus = tv({ slots: {
|
|
6
5
|
root: [
|
|
7
|
-
"block min-
|
|
6
|
+
"block min-w-0 empty:hidden",
|
|
8
7
|
"mt-1 [[data-slot=field]>&]:-mt-0.5 [[data-slot=list-row-body]>&]:mt-0.5",
|
|
9
8
|
"text-footnote"
|
|
10
9
|
],
|
|
11
|
-
saved: [
|
|
12
|
-
"flex min-w-0 items-center gap-1",
|
|
13
|
-
"text-foreground-muted",
|
|
14
|
-
"[&>svg]:size-3 [&>svg]:shrink-0"
|
|
15
|
-
],
|
|
16
10
|
error: ["block wrap-anywhere", "text-danger-strong"]
|
|
17
11
|
} });
|
|
18
12
|
/**
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
13
|
+
* The line under a setting that applies at once. Render it whatever the
|
|
14
|
+
* setting's state, with `SaveStatusError` inside when the change failed and
|
|
15
|
+
* nothing inside otherwise: empty, it is hidden and takes no height. A `span`
|
|
16
|
+
* (shown as a block), like every ListRow part, so it stays valid inside a
|
|
17
|
+
* row's body; give it an `id` for the control's `aria-describedby`.
|
|
22
18
|
*/
|
|
23
19
|
function SaveStatus({ className, ...props }) {
|
|
24
20
|
const { root } = saveStatus();
|
|
@@ -29,28 +25,21 @@ function SaveStatus({ className, ...props }) {
|
|
|
29
25
|
});
|
|
30
26
|
}
|
|
31
27
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
28
|
+
* @deprecated A setting that applies at once no longer says "Saved": the
|
|
29
|
+
* control showing its new value is the confirmation (Forms, settings that
|
|
30
|
+
* apply at once). Renders nothing, whatever its children, so its
|
|
31
|
+
* `SaveStatus` stays empty and takes no height. Leave it out: render
|
|
32
|
+
* `SaveStatusError` when the change failed and nothing otherwise. It drops
|
|
33
|
+
* every prop, its `id` too: point a control's `aria-describedby` at the
|
|
34
|
+
* `SaveStatus` instead.
|
|
35
35
|
*/
|
|
36
|
-
function SaveStatusSaved(
|
|
37
|
-
|
|
38
|
-
const hasContent = children !== null && children !== void 0 && children !== false && children !== "";
|
|
39
|
-
return /* @__PURE__ */ jsxs("span", {
|
|
40
|
-
"data-slot": "save-status-saved",
|
|
41
|
-
role: "status",
|
|
42
|
-
"aria-live": "polite",
|
|
43
|
-
className: saved({ className }),
|
|
44
|
-
...props,
|
|
45
|
-
children: [hasContent ? /* @__PURE__ */ jsx(CircleCheck, {
|
|
46
|
-
"aria-hidden": "true",
|
|
47
|
-
"data-slot": "save-status-icon"
|
|
48
|
-
}) : null, children]
|
|
49
|
-
});
|
|
36
|
+
function SaveStatusSaved(_props) {
|
|
37
|
+
return null;
|
|
50
38
|
}
|
|
51
39
|
/**
|
|
52
|
-
* What failed
|
|
53
|
-
*
|
|
40
|
+
* What failed. It is an alert, announced when it appears, and stays until
|
|
41
|
+
* the next change. Its line appears with it, so the setting grows by one
|
|
42
|
+
* line while it shows.
|
|
54
43
|
*/
|
|
55
44
|
function SaveStatusError({ className, role = "alert", ...props }) {
|
|
56
45
|
const { error } = saveStatus();
|
|
@@ -469,6 +469,7 @@
|
|
|
469
469
|
.r-scroll-area > .r-scroll-area__gutters {
|
|
470
470
|
pointer-events: none;
|
|
471
471
|
user-select: none;
|
|
472
|
+
/* raft-ui: z-index the gutters paint over every layer inside the area (its root is isolate) until slock's layers inside its ScrollAreas are named (#218 step 2); then var(--z-index-scrollbar). */
|
|
472
473
|
z-index: 2147483647;
|
|
473
474
|
}
|
|
474
475
|
/*
|
|
@@ -3,8 +3,9 @@ import { useMergedRef } from "../../lib/use-merged-ref.mjs";
|
|
|
3
3
|
import { useTapActivation } from "../../lib/tap-activation.mjs";
|
|
4
4
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip.mjs";
|
|
5
5
|
import { useInFitToolbar } from "../fit-toolbar/fit-toolbar.mjs";
|
|
6
|
-
import { createContext, use, useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
6
|
+
import { cloneElement, createContext, use, useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Toolbar } from "@base-ui/react/toolbar";
|
|
8
9
|
import { Radio } from "@base-ui/react/radio";
|
|
9
10
|
import { RadioGroup } from "@base-ui/react/radio-group";
|
|
10
11
|
//#region src/components/segmented-control/segmented-control.tsx
|
|
@@ -73,6 +74,11 @@ function isIconsOnlyPreset(value) {
|
|
|
73
74
|
}
|
|
74
75
|
const SegmentedControlIconsOnlyContext = createContext(false);
|
|
75
76
|
/**
|
|
77
|
+
* In a FitToolbar: whether the control holds the toolbar's one tab stop
|
|
78
|
+
* (`undefined` outside a toolbar, where the radio group keeps its own).
|
|
79
|
+
*/
|
|
80
|
+
const SegmentedControlToolbarStopContext = createContext(void 0);
|
|
81
|
+
/**
|
|
76
82
|
* A length threshold in CSS pixels, or `undefined` for a value that isn't a
|
|
77
83
|
* `px`, `rem` or `em` length. `em` is the container's font size, as in a
|
|
78
84
|
* container query.
|
|
@@ -250,21 +256,51 @@ function SegmentedControl({ disabled = false, iconsOnlyBelow: iconsOnlyBelowProp
|
|
|
250
256
|
if (start < track.scrollLeft) track.scrollLeft = start;
|
|
251
257
|
else if (end > track.scrollLeft + track.clientWidth) track.scrollLeft = end - track.clientWidth;
|
|
252
258
|
}, [overflowing, value]);
|
|
259
|
+
const group = /* @__PURE__ */ jsx(RadioGroup, {
|
|
260
|
+
ref: setRef,
|
|
261
|
+
disabled,
|
|
262
|
+
"data-slot": "segmented-control",
|
|
263
|
+
"data-overflowing": overflowing ? "" : void 0,
|
|
264
|
+
"data-fit-needs-icon": inFitToolbar ? "" : void 0,
|
|
265
|
+
className: root({ className }),
|
|
266
|
+
...props
|
|
267
|
+
});
|
|
253
268
|
return /* @__PURE__ */ jsx(SegmentedControlIconsOnlyContext, {
|
|
254
269
|
value: inFitToolbar || iconsOnlyBelow !== void 0,
|
|
255
|
-
children: /* @__PURE__ */ jsx(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
270
|
+
children: inFitToolbar ? /* @__PURE__ */ jsx(ToolbarItem, { group }) : group
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* In a FitToolbar the control is one item of the toolbar's list (Base UI
|
|
275
|
+
* Toolbar), so the toolbar keeps one tab stop: its segments are reachable by
|
|
276
|
+
* Tab only while the control holds it, and the toolbar's arrow keys reach
|
|
277
|
+
* them. Registered through `Toolbar.Link`'s render function, the one toolbar
|
|
278
|
+
* part that adds no role or keys of its own: the radio group is the item. Its
|
|
279
|
+
* own tab stop is the segments', never the group's.
|
|
280
|
+
*/
|
|
281
|
+
function ToolbarItem({ group }) {
|
|
282
|
+
const render = useCallback(({ ref, tabIndex, ...itemProps }) => /* @__PURE__ */ jsx(ToolbarItemGroup, {
|
|
283
|
+
group,
|
|
284
|
+
itemProps,
|
|
285
|
+
itemRef: ref,
|
|
286
|
+
stop: tabIndex === 0
|
|
287
|
+
}), [group]);
|
|
288
|
+
return /* @__PURE__ */ jsx(Toolbar.Link, { render });
|
|
289
|
+
}
|
|
290
|
+
function ToolbarItemGroup({ group, itemProps, itemRef, stop }) {
|
|
291
|
+
const [setRef] = useMergedRef(itemRef, group.props.ref);
|
|
292
|
+
return /* @__PURE__ */ jsx(SegmentedControlToolbarStopContext, {
|
|
293
|
+
value: stop,
|
|
294
|
+
children: cloneElement(group, {
|
|
295
|
+
...itemProps,
|
|
296
|
+
ref: setRef
|
|
262
297
|
})
|
|
263
298
|
});
|
|
264
299
|
}
|
|
265
300
|
function SegmentedControlItem({ className, ref, ...props }) {
|
|
266
301
|
const { item } = segmentedControl();
|
|
267
302
|
const iconsOnly = use(SegmentedControlIconsOnlyContext);
|
|
303
|
+
const toolbarStop = use(SegmentedControlToolbarStopContext);
|
|
268
304
|
const tapRef = useTapActivation();
|
|
269
305
|
const [setRef] = useMergedRef(tapRef, ref);
|
|
270
306
|
const radio = /* @__PURE__ */ jsx(Radio.Root, {
|
|
@@ -273,6 +309,7 @@ function SegmentedControlItem({ className, ref, ...props }) {
|
|
|
273
309
|
nativeButton: true,
|
|
274
310
|
"data-slot": "segmented-control-item",
|
|
275
311
|
className: item({ className: `group/segmented-control-item ${className ?? ""}`.trim() }),
|
|
312
|
+
...toolbarStop === false ? { tabIndex: -1 } : {},
|
|
276
313
|
...props
|
|
277
314
|
});
|
|
278
315
|
return iconsOnly ? /* @__PURE__ */ jsx(SegmentedControlItemTooltip, { children: radio }) : radio;
|
|
@@ -39,7 +39,7 @@ const select = tv({
|
|
|
39
39
|
"[&>svg]:size-4 [&>svg]:stroke-2 [&>svg_*]:stroke-2"
|
|
40
40
|
],
|
|
41
41
|
value: ["flex min-w-0 flex-1 truncate text-left"],
|
|
42
|
-
positioner: ["isolate z-
|
|
42
|
+
positioner: ["isolate z-popup outline-none"],
|
|
43
43
|
content: [
|
|
44
44
|
"relative max-h-(--available-height) min-w-[max(var(--anchor-width),220px)] overflow-hidden",
|
|
45
45
|
"max-w-[min(var(--available-width),max(var(--anchor-width),24rem))]",
|
|
@@ -92,7 +92,7 @@ const select = tv({
|
|
|
92
92
|
groupLabel: ["py-2", "px-2.5 pt-2 pb-1 text-caption font-bold text-foreground-hint"],
|
|
93
93
|
separator: ["h-px shrink-0 border-0", "-mx-1 my-1 bg-line-hairline"],
|
|
94
94
|
scrollArrow: [
|
|
95
|
-
"absolute inset-x-0 z-
|
|
95
|
+
"absolute inset-x-0 z-raised flex h-6 w-full cursor-default items-center justify-center",
|
|
96
96
|
"outline-none transition-colors",
|
|
97
97
|
"data-[direction=up]:top-0 data-[direction=down]:bottom-0",
|
|
98
98
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
@@ -3,7 +3,7 @@ import { tv } from "../../lib/tv.mjs";
|
|
|
3
3
|
const selectionToolbar = tv({
|
|
4
4
|
slots: {
|
|
5
5
|
dock: [
|
|
6
|
-
"pointer-events-none absolute inset-x-0 bottom-0 z-
|
|
6
|
+
"pointer-events-none absolute inset-x-0 bottom-0 z-float flex justify-center",
|
|
7
7
|
"px-5 pb-[calc(--spacing(3)+env(safe-area-inset-bottom))]",
|
|
8
8
|
"*:pointer-events-auto"
|
|
9
9
|
],
|
|
@@ -16,7 +16,7 @@ const sidebarRecipe = tv({ slots: {
|
|
|
16
16
|
headEdgePull,
|
|
17
17
|
"[@media(max-height:600px)]:h-(--header-height-short)"
|
|
18
18
|
],
|
|
19
|
-
sidebarHeaderMask: ["pointer-events-none absolute inset-x-0 top-0
|
|
19
|
+
sidebarHeaderMask: ["pointer-events-none absolute inset-x-0 top-0 z-below hidden"],
|
|
20
20
|
sidebarHeaderMaskLayer: ["absolute inset-x-0 top-0"],
|
|
21
21
|
sidebarHeaderTitle: ["truncate font-bold", "font-sans text-headline text-foreground max-md:text-foreground-on-frame"],
|
|
22
22
|
sidebarGroupLabel: ["px-5 pt-4 pb-0 md:pointer-fine:px-(--sidebar-glyph-axis) md:pointer-fine:pt-2", "font-sans text-footnote font-bold normal-case tracking-normal text-foreground-hint"],
|
|
@@ -22,7 +22,7 @@ const tabs = tv({
|
|
|
22
22
|
],
|
|
23
23
|
background: ["", "hidden"],
|
|
24
24
|
tab: [
|
|
25
|
-
"relative
|
|
25
|
+
"relative isolate flex shrink-0 cursor-pointer touch-manipulation select-none [-webkit-touch-callout:none] items-center gap-1.5 whitespace-nowrap outline-none",
|
|
26
26
|
"data-[reorderable=true]:cursor-pointer data-[dragging-source=true]:cursor-grabbing",
|
|
27
27
|
"font-sans text-callout font-semibold text-foreground-muted",
|
|
28
28
|
"transition-[background-color,box-shadow,color] duration-100 ease-out",
|
|
@@ -31,7 +31,7 @@ const tabs = tv({
|
|
|
31
31
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:stroke-2 [&_svg:not([class*='size-'])]:size-4",
|
|
32
32
|
"data-disabled:pointer-events-none data-disabled:text-foreground-disabled"
|
|
33
33
|
],
|
|
34
|
-
content: ["relative z-
|
|
34
|
+
content: ["relative z-raised inline-flex items-center gap-[inherit]"],
|
|
35
35
|
label: [""],
|
|
36
36
|
panel: ["outline-none"],
|
|
37
37
|
indicator: ["", "hidden"]
|
|
@@ -416,7 +416,7 @@ function SortableTabsTab({ value, ...props }) {
|
|
|
416
416
|
...baseStyle,
|
|
417
417
|
transform: translate === void 0 ? void 0 : vertical ? `translate3d(0, ${translate}px, 0)` : `translate3d(${translate}px, 0, 0)`,
|
|
418
418
|
transition,
|
|
419
|
-
zIndex: isDragging ?
|
|
419
|
+
zIndex: isDragging ? "var(--z-index-raised)" : baseStyle?.zIndex,
|
|
420
420
|
cursor: isDragging ? "grabbing" : "pointer",
|
|
421
421
|
...isDragging && !home ? PLACE_STYLE : null
|
|
422
422
|
}), [
|
|
@@ -483,7 +483,7 @@ function TabsTabButton({ value, sortableRef, dropPlace = false, className, child
|
|
|
483
483
|
"data-slot": "tabs-tab-content",
|
|
484
484
|
className: content({ className: dropPlace ? "invisible" : void 0 }),
|
|
485
485
|
children
|
|
486
|
-
}), dropPlace ? /* @__PURE__ */ jsx(DropPlaceholder, { className: "absolute inset-0 z-
|
|
486
|
+
}), dropPlace ? /* @__PURE__ */ jsx(DropPlaceholder, { className: "absolute inset-0 z-raised rounded-control" }) : null]
|
|
487
487
|
});
|
|
488
488
|
}
|
|
489
489
|
function TabsLabel({ className, ...props }) {
|
|
@@ -22,6 +22,11 @@ export declare function TaskBoardColumnBadge({ status, children, className, rend
|
|
|
22
22
|
export type TaskBoardColumnCountProps = useRender.ComponentProps<"span">;
|
|
23
23
|
export declare function TaskBoardColumnCount({ className, render, ...props }: TaskBoardColumnCountProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
24
24
|
export type TaskBoardColumnChevronProps = useRender.ComponentProps<"span">;
|
|
25
|
+
/**
|
|
26
|
+
* The arrow that shows whether the column is open: right while it is collapsed, down while it is open. It draws a
|
|
27
|
+
* `ChevronDown` when given no children, so a column heading always has it: a collapsed column shows only its heading,
|
|
28
|
+
* and without the arrow "Closed 2" over an empty space reads as two tasks that failed to load.
|
|
29
|
+
*/
|
|
25
30
|
export declare function TaskBoardColumnChevron({ className, render, ...props }: TaskBoardColumnChevronProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
26
31
|
export type TaskBoardColumnPanelProps = Omit<ComponentProps<typeof Collapsible.Panel>, "className"> & {
|
|
27
32
|
className?: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../cn.mjs";
|
|
2
2
|
import { TaskStatusIcon } from "../tasks/task-status-icon.mjs";
|
|
3
3
|
import { taskBoardColumn } from "./task-board-column.recipe.mjs";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
4
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
import { mergeProps } from "@base-ui/react/merge-props";
|
|
6
7
|
import { useRender } from "@base-ui/react/use-render";
|
|
@@ -71,11 +72,17 @@ function TaskBoardColumnCount({ className, render, ...props }) {
|
|
|
71
72
|
props: mergeProps(defaultProps, props)
|
|
72
73
|
});
|
|
73
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* The arrow that shows whether the column is open: right while it is collapsed, down while it is open. It draws a
|
|
77
|
+
* `ChevronDown` when given no children, so a column heading always has it: a collapsed column shows only its heading,
|
|
78
|
+
* and without the arrow "Closed 2" over an empty space reads as two tasks that failed to load.
|
|
79
|
+
*/
|
|
74
80
|
function TaskBoardColumnChevron({ className, render, ...props }) {
|
|
75
81
|
const { chevron } = taskBoardColumn();
|
|
76
82
|
const defaultProps = {
|
|
77
83
|
"data-slot": "task-board-column-chevron",
|
|
78
|
-
className: chevron({ className })
|
|
84
|
+
className: chevron({ className }),
|
|
85
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true })
|
|
79
86
|
};
|
|
80
87
|
return useRender({
|
|
81
88
|
defaultTagName: "span",
|
|
@@ -52,8 +52,17 @@ export type TaskDropZoneProps = useRender.ComponentProps<"div", TaskDropZoneStat
|
|
|
52
52
|
id: UniqueIdentifier;
|
|
53
53
|
disabled?: boolean;
|
|
54
54
|
data?: TaskDropData;
|
|
55
|
+
/**
|
|
56
|
+
* The zone is itself the place, as a column sorted by a field is: its
|
|
57
|
+
* cards carry no `dropId` and no placeholder opens between them. While a
|
|
58
|
+
* card it allows is over it, it carries `data-drag-into` and takes
|
|
59
|
+
* `fill-subtle`; never at rest, and never while it refuses the card.
|
|
60
|
+
* Without it the zone is never filled, and only a `TaskDropPlaceholder`
|
|
61
|
+
* says where the card lands.
|
|
62
|
+
*/
|
|
63
|
+
dragInto?: boolean;
|
|
55
64
|
};
|
|
56
|
-
export declare function TaskDropZone({ id, data, disabled, render, ...props }: TaskDropZoneProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
65
|
+
export declare function TaskDropZone({ id, data, disabled, dragInto, render, ...props }: TaskDropZoneProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
57
66
|
export type TaskDropPlaceholderProps = useRender.ComponentProps<"div", TaskDropZoneState> & {
|
|
58
67
|
id: UniqueIdentifier;
|
|
59
68
|
placement?: TaskDropPlacement;
|