@botiverse/raft-ui 0.63.1 → 0.65.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/components/activity-inbox/activity-inbox-sidebar.recipe.mjs +1 -1
  3. package/dist/components/activity-inbox/activity-inbox-toolbar.recipe.mjs +6 -1
  4. package/dist/components/alert-dialog/alert-dialog.mjs +3 -3
  5. package/dist/components/announcement-dialog/announcement-dialog.mjs +2 -2
  6. package/dist/components/app-link-card/app-link-card.d.mts +56 -0
  7. package/dist/components/app-link-card/app-link-card.mjs +207 -0
  8. package/dist/components/app-link-card/index.d.mts +2 -0
  9. package/dist/components/app-rail/app-rail.recipe.mjs +12 -7
  10. package/dist/components/app-shell/app-shell.mjs +1 -1
  11. package/dist/components/avatar/avatar.mjs +1 -0
  12. package/dist/components/badge/badge.mjs +6 -1
  13. package/dist/components/banner/banner.mjs +1 -1
  14. package/dist/components/button/button-split.d.mts +38 -0
  15. package/dist/components/button/button-split.mjs +126 -0
  16. package/dist/components/button/button.mjs +13 -8
  17. package/dist/components/button/index.d.mts +2 -1
  18. package/dist/components/code-block/code-block.recipe.mjs +1 -1
  19. package/dist/components/combobox/combobox.mjs +4 -4
  20. package/dist/components/combobox-select/combobox-select.css +6 -3
  21. package/dist/components/comment/comment-margin.mjs +2 -1
  22. package/dist/components/composer/composer-suggestion-list.mjs +1 -1
  23. package/dist/components/composer/composer-toolbar-label.mjs +1 -1
  24. package/dist/components/composer/composer.mjs +1 -1
  25. package/dist/components/composer/composer.recipe.mjs +38 -26
  26. package/dist/components/conversation-panel/conversation-panel-empty-state.mjs +1 -1
  27. package/dist/components/conversation-panel/conversation-panel.recipe.mjs +3 -2
  28. package/dist/components/dialog/dialog-sheet-context.mjs +1 -1
  29. package/dist/components/dialog/dialog.mjs +7 -7
  30. package/dist/components/drawer/drawer.mjs +3 -2
  31. package/dist/components/drawer/drawer.recipe.mjs +5 -3
  32. package/dist/components/empty-state/empty-state.mjs +1 -1
  33. package/dist/components/field/field.mjs +1 -1
  34. package/dist/components/files/files.recipe.mjs +1 -1
  35. package/dist/components/filter-chip/filter-chip.mjs +1 -1
  36. package/dist/components/form-section/form-section.mjs +1 -1
  37. package/dist/components/icon-tile/icon-tile.mjs +3 -3
  38. package/dist/components/inbox-item/inbox-item.recipe.mjs +4 -2
  39. package/dist/components/input/input.recipe.mjs +1 -1
  40. package/dist/components/input-group/input-group.mjs +1 -1
  41. package/dist/components/lightbox/lightbox.mjs +1 -1
  42. package/dist/components/list-row/list-row.recipe.mjs +2 -2
  43. package/dist/components/message-action-card/message-action-card-content.recipe.mjs +1 -1
  44. package/dist/components/message-action-card/message-action-card.recipe.mjs +1 -1
  45. package/dist/components/message-item/index.d.mts +2 -2
  46. package/dist/components/message-item/message-item-content.d.mts +14 -0
  47. package/dist/components/message-item/message-item-content.mjs +146 -1
  48. package/dist/components/message-item/message-item.recipe.d.mts +3 -0
  49. package/dist/components/message-item/message-item.recipe.mjs +3 -2
  50. package/dist/components/message-item/message-reaction.recipe.mjs +4 -3
  51. package/dist/components/message-list/message-list.recipe.mjs +3 -1
  52. package/dist/components/mode-bar/mode-bar.mjs +1 -1
  53. package/dist/components/notification-center/notification-center.mjs +1 -1
  54. package/dist/components/panel/panel-action.recipe.mjs +5 -5
  55. package/dist/components/panel/panel-header.recipe.mjs +10 -9
  56. package/dist/components/panel/panel.recipe.mjs +2 -2
  57. package/dist/components/picker-trigger-button/picker-trigger-button.mjs +1 -1
  58. package/dist/components/profile-panel/profile-panel.recipe.mjs +1 -1
  59. package/dist/components/scroll-area/scroll-area.css +74 -33
  60. package/dist/components/search/search-entity.recipe.mjs +3 -2
  61. package/dist/components/search/search-message.recipe.mjs +1 -0
  62. package/dist/components/search/search-thread.recipe.mjs +1 -1
  63. package/dist/components/search/search-trigger.mjs +1 -1
  64. package/dist/components/search/search.recipe.mjs +7 -3
  65. package/dist/components/segmented-control/segmented-control.mjs +9 -8
  66. package/dist/components/select/select.mjs +2 -2
  67. package/dist/components/sidebar/sidebar-item.recipe.mjs +5 -4
  68. package/dist/components/sidebar/sidebar-section.recipe.mjs +5 -2
  69. package/dist/components/sidebar/sidebar.recipe.mjs +3 -3
  70. package/dist/components/switch/switch.mjs +3 -3
  71. package/dist/components/tabs/tabs.mjs +1 -1
  72. package/dist/components/task-board/task-board-column.recipe.mjs +1 -1
  73. package/dist/components/task-list/task-list-section.recipe.mjs +1 -1
  74. package/dist/components/tasks/tasks-panel.recipe.mjs +4 -3
  75. package/dist/components/text-selection-toolbar/text-selection-toolbar.recipe.mjs +1 -1
  76. package/dist/components/textarea/textarea.mjs +1 -1
  77. package/dist/components/thread-panel/thread-panel.recipe.mjs +3 -3
  78. package/dist/components/toggle-group/toggle-group.mjs +1 -1
  79. package/dist/foundation.css +100 -5
  80. package/dist/lib/head-edges.mjs +38 -8
  81. package/dist/lib/list-cell.mjs +1 -0
  82. package/dist/styles.css +54 -7
  83. package/dist/tokens.json +260 -4
  84. package/dist/wip.d.mts +6 -1
  85. package/dist/wip.mjs +4 -1
  86. package/package.json +1 -1
@@ -8,7 +8,7 @@ const inputGroup = tv({
8
8
  root: [
9
9
  "group/input-group relative flex w-full min-w-0 items-center",
10
10
  "has-data-[input-group-trim=inline-end]:[--ig-control-pr:0]",
11
- "h-control overflow-hidden rounded-control border-[1.5px] border-line-field bg-layer-card text-foreground",
11
+ "h-control overflow-hidden rounded-(--control-radius) border-[1.5px] border-line-field bg-layer-card text-foreground",
12
12
  "shadow-none transition-shadow duration-90 ease-out has-focus-visible:shadow-focus",
13
13
  "has-[[data-slot=input-group-control][data-invalid]]:border-danger-strong",
14
14
  "has-[[data-slot=input-group-control]:disabled]:cursor-not-allowed has-[[data-slot=input-group-control]:disabled]:border-line-hairline has-[[data-slot=input-group-control]:disabled]:bg-fill-muted",
@@ -28,7 +28,7 @@ const lightbox = tv({ slots: {
28
28
  ],
29
29
  toolbar: [
30
30
  "pointer-events-auto shrink-0 flex items-center gap-3",
31
- "h-[calc(56px+env(safe-area-inset-top,0px))] pt-[env(safe-area-inset-top,0px)]",
31
+ "h-[calc(var(--header-height)+env(safe-area-inset-top,0px))] pt-[env(safe-area-inset-top,0px)]",
32
32
  "pl-[calc(16px+env(safe-area-inset-left,0px))] pr-[calc(16px+env(safe-area-inset-right,0px))]",
33
33
  "**:data-lightbox-close:static **:data-lightbox-close:inset-auto",
34
34
  "**:data-lightbox-close:top-auto **:data-lightbox-close:right-auto",
@@ -32,8 +32,8 @@ const listRow = tv({
32
32
  },
33
33
  variants: {
34
34
  variant: {
35
- default: { root: "min-h-16 [--list-row-rule-start:63px]" },
36
- plain: { root: "[--list-row-rule-start:16px]" },
35
+ default: { root: "min-h-16 pointer-coarse:min-h-14 pointer-coarse:py-2 [--list-row-rule-start:63px]" },
36
+ plain: { root: "py-(--settings-row-inset) [--list-row-rule-start:16px]" },
37
37
  entry: { root: "" }
38
38
  },
39
39
  interactive: {
@@ -24,7 +24,7 @@ const messageActionCardContent = tv({ slots: {
24
24
  "@max-sm/action-card:min-h-0 @max-sm/action-card:py-0"
25
25
  ],
26
26
  scopeList: ["mt-0 stack-y-1.5"],
27
- scopeListViewport: ["overflow-y-auto overscroll-contain", "max-h-[164px] stack-y-1.5 pr-1"],
27
+ scopeListViewport: ["overflow-y-auto overscroll-contain", "max-h-[136px] stack-y-1.5 pr-1"],
28
28
  scopeListLabel: ["text-footnote font-medium text-foreground-hint"],
29
29
  scope: ["min-w-0 border p-1.5", "rounded-control border-line-hairline bg-layer-card px-2.5 py-2"],
30
30
  scopeName: ["break-all font-mono", "text-mono-meta font-normal text-foreground"],
@@ -11,7 +11,7 @@ const messageActionCard = tv({
11
11
  headerIcon: [
12
12
  "flex shrink-0 items-center justify-center",
13
13
  "[&>svg]:shrink-0",
14
- "size-[27px] rounded-sticker bg-fill-muted text-foreground-muted",
14
+ "size-[27px] rounded-chip bg-fill-muted text-foreground-muted",
15
15
  "[&>svg]:size-3.5"
16
16
  ],
17
17
  headerTitle: ["min-w-0 flex-1", "pt-[calc((27px-1lh)/2)]"],
@@ -1,6 +1,6 @@
1
1
  import { MessageItem, MessageItemProps } from "./message-item-root.mjs";
2
2
  import { MessageItemAvatarSlot, MessageItemAvatarSlotProps, MessageItemContinuationTime, MessageItemContinuationTimeProps, MessageItemGutter, MessageItemGutterProps } from "./message-item-gutter.mjs";
3
- import { MessageItemAttachments, MessageItemAttachmentsProps, MessageItemBody, MessageItemBodyProps, MessageItemContent, MessageItemContentProps, MessageItemEdited, MessageItemEditedProps, MessageItemEmbedded, MessageItemEmbeddedProps, MessageItemFooter, MessageItemFooterProps, MessageItemSearchMatch, MessageItemSearchMatchProps } from "./message-item-content.mjs";
3
+ import { MessageItemAttachments, MessageItemAttachmentsProps, MessageItemBody, MessageItemBodyProps, MessageItemContent, MessageItemContentProps, MessageItemEdited, MessageItemEditedProps, MessageItemEmbedded, MessageItemEmbeddedProps, MessageItemFooter, MessageItemFooterProps, MessageItemSearchMatch, MessageItemSearchMatchProps, MessageItemTrailing, MessageItemTrailingProps } from "./message-item-content.mjs";
4
4
  import { MessageItemHeader, MessageItemHeaderProps, MessageItemInlineStatus, MessageItemInlineStatusProps, MessageItemMeta, MessageItemMetaProps, MessageItemSender, MessageItemSenderBadges, MessageItemSenderBadgesProps, MessageItemSenderButton, MessageItemSenderButtonProps, MessageItemSenderGroup, MessageItemSenderGroupProps, MessageItemSenderProps, MessageItemTime, MessageItemTimeProps } from "./message-item-header.mjs";
5
5
  import { MessageItemDelegatedAvatar, MessageItemDelegatedAvatarProps, MessageItemDelegatedBy, MessageItemDelegatedByButton, MessageItemDelegatedByButtonProps, MessageItemDelegatedByName, MessageItemDelegatedByNameProps, MessageItemDelegatedByProps } from "./message-item-delegated.mjs";
6
6
  import { MessageItemToolbar, MessageItemToolbarButton, MessageItemToolbarButtonProps, MessageItemToolbarProps } from "./message-item-toolbar.mjs";
@@ -9,4 +9,4 @@ import { MessageReactionAddButton, MessageReactionAddButtonProps, MessageReactio
9
9
  import { MessageReferenceChipVariant, MessageReferenceTextVariant } from "./message-reference.recipe.mjs";
10
10
  import { MessageReferenceChip, MessageReferenceChipProps, MessageReferenceIcon, MessageReferenceIconProps, MessageReferenceIndicator, MessageReferenceIndicatorProps, MessageReferenceLabel, MessageReferenceLabelProps, MessageReferencePending, MessageReferencePendingProps, MessageReferenceReadMark, MessageReferenceReadMarkProps, MessageReferenceSuffix, MessageReferenceSuffixProps, MessageReferenceText, MessageReferenceTextProps, MessageReferenceUnavailable, MessageReferenceUnavailableProps } from "./message-reference.mjs";
11
11
  import { MessageMultiSelect, MessageMultiSelectCheckbox, MessageMultiSelectCheckboxProps, MessageMultiSelectProps, MessageMultiSelectToolbar, MessageMultiSelectToolbarActions, MessageMultiSelectToolbarActionsProps, MessageMultiSelectToolbarProps } from "./message-multi-select.mjs";
12
- export { MessageItem, MessageItemAttachments, type MessageItemAttachmentsProps, MessageItemAvatarSlot, type MessageItemAvatarSlotProps, MessageItemBadge, type MessageItemBadgeProps, MessageItemBadgeSeparator, type MessageItemBadgeSeparatorProps, type MessageItemBadgeStatus, MessageItemBody, type MessageItemBodyProps, MessageItemContent, type MessageItemContentProps, MessageItemContinuationTime, type MessageItemContinuationTimeProps, MessageItemDelegatedAvatar, type MessageItemDelegatedAvatarProps, MessageItemDelegatedBy, MessageItemDelegatedByButton, type MessageItemDelegatedByButtonProps, MessageItemDelegatedByName, type MessageItemDelegatedByNameProps, type MessageItemDelegatedByProps, MessageItemEdited, type MessageItemEditedProps, MessageItemEmbedded, type MessageItemEmbeddedProps, MessageItemFooter, type MessageItemFooterProps, MessageItemGutter, type MessageItemGutterProps, MessageItemHeader, type MessageItemHeaderProps, MessageItemInlineStatus, type MessageItemInlineStatusProps, MessageItemMeta, type MessageItemMetaProps, type MessageItemProps, MessageItemReadReceipt, type MessageItemReadReceiptProps, MessageItemSavedIndicator, type MessageItemSavedIndicatorProps, MessageItemSearchMatch, type MessageItemSearchMatchProps, MessageItemSender, MessageItemSenderBadges, type MessageItemSenderBadgesProps, MessageItemSenderButton, type MessageItemSenderButtonProps, MessageItemSenderGroup, type MessageItemSenderGroupProps, type MessageItemSenderProps, MessageItemTime, type MessageItemTimeProps, MessageItemToolbar, MessageItemToolbarButton, type MessageItemToolbarButtonProps, type MessageItemToolbarProps, MessageMultiSelect, MessageMultiSelectCheckbox, type MessageMultiSelectCheckboxProps, type MessageMultiSelectProps, MessageMultiSelectToolbar, MessageMultiSelectToolbarActions, type MessageMultiSelectToolbarActionsProps, type MessageMultiSelectToolbarProps, MessageReactionAddButton, type MessageReactionAddButtonProps, MessageReactionChip, type MessageReactionChipProps, MessageReactionCount, type MessageReactionCountProps, MessageReactionErrorIndicator, type MessageReactionErrorIndicatorProps, MessageReactionGlyph, type MessageReactionGlyphProps, MessageReactionPickerContent, type MessageReactionPickerContentProps, MessageReactionPickerStatic, type MessageReactionPickerStaticProps, MessageReactionQuickButton, type MessageReactionQuickButtonProps, MessageReactionQuickRow, type MessageReactionQuickRowProps, MessageReactionTooltipContent, type MessageReactionTooltipContentProps, MessageReactionTooltipMeta, type MessageReactionTooltipMetaProps, MessageReactionTooltipName, type MessageReactionTooltipNameProps, MessageReactionTooltipNameText, type MessageReactionTooltipNameTextProps, MessageReactionTooltipNames, type MessageReactionTooltipNamesProps, MessageReactionTooltipSeparator, type MessageReactionTooltipSeparatorProps, MessageReferenceChip, type MessageReferenceChipProps, type MessageReferenceChipVariant, MessageReferenceIcon, type MessageReferenceIconProps, MessageReferenceIndicator, type MessageReferenceIndicatorProps, MessageReferenceLabel, type MessageReferenceLabelProps, MessageReferencePending, type MessageReferencePendingProps, MessageReferenceReadMark, type MessageReferenceReadMarkProps, MessageReferenceSuffix, type MessageReferenceSuffixProps, MessageReferenceText, type MessageReferenceTextProps, type MessageReferenceTextVariant, MessageReferenceUnavailable, type MessageReferenceUnavailableProps };
12
+ export { MessageItem, MessageItemAttachments, type MessageItemAttachmentsProps, MessageItemAvatarSlot, type MessageItemAvatarSlotProps, MessageItemBadge, type MessageItemBadgeProps, MessageItemBadgeSeparator, type MessageItemBadgeSeparatorProps, type MessageItemBadgeStatus, MessageItemBody, type MessageItemBodyProps, MessageItemContent, type MessageItemContentProps, MessageItemContinuationTime, type MessageItemContinuationTimeProps, MessageItemDelegatedAvatar, type MessageItemDelegatedAvatarProps, MessageItemDelegatedBy, MessageItemDelegatedByButton, type MessageItemDelegatedByButtonProps, MessageItemDelegatedByName, type MessageItemDelegatedByNameProps, type MessageItemDelegatedByProps, MessageItemEdited, type MessageItemEditedProps, MessageItemEmbedded, type MessageItemEmbeddedProps, MessageItemFooter, type MessageItemFooterProps, MessageItemGutter, type MessageItemGutterProps, MessageItemHeader, type MessageItemHeaderProps, MessageItemInlineStatus, type MessageItemInlineStatusProps, MessageItemMeta, type MessageItemMetaProps, type MessageItemProps, MessageItemReadReceipt, type MessageItemReadReceiptProps, MessageItemSavedIndicator, type MessageItemSavedIndicatorProps, MessageItemSearchMatch, type MessageItemSearchMatchProps, MessageItemSender, MessageItemSenderBadges, type MessageItemSenderBadgesProps, MessageItemSenderButton, type MessageItemSenderButtonProps, MessageItemSenderGroup, type MessageItemSenderGroupProps, type MessageItemSenderProps, MessageItemTime, type MessageItemTimeProps, MessageItemToolbar, MessageItemToolbarButton, type MessageItemToolbarButtonProps, type MessageItemToolbarProps, MessageItemTrailing, type MessageItemTrailingProps, MessageMultiSelect, MessageMultiSelectCheckbox, type MessageMultiSelectCheckboxProps, type MessageMultiSelectProps, MessageMultiSelectToolbar, MessageMultiSelectToolbarActions, type MessageMultiSelectToolbarActionsProps, type MessageMultiSelectToolbarProps, MessageReactionAddButton, type MessageReactionAddButtonProps, MessageReactionChip, type MessageReactionChipProps, MessageReactionCount, type MessageReactionCountProps, MessageReactionErrorIndicator, type MessageReactionErrorIndicatorProps, MessageReactionGlyph, type MessageReactionGlyphProps, MessageReactionPickerContent, type MessageReactionPickerContentProps, MessageReactionPickerStatic, type MessageReactionPickerStaticProps, MessageReactionQuickButton, type MessageReactionQuickButtonProps, MessageReactionQuickRow, type MessageReactionQuickRowProps, MessageReactionTooltipContent, type MessageReactionTooltipContentProps, MessageReactionTooltipMeta, type MessageReactionTooltipMetaProps, MessageReactionTooltipName, type MessageReactionTooltipNameProps, MessageReactionTooltipNameText, type MessageReactionTooltipNameTextProps, MessageReactionTooltipNames, type MessageReactionTooltipNamesProps, MessageReactionTooltipSeparator, type MessageReactionTooltipSeparatorProps, MessageReferenceChip, type MessageReferenceChipProps, type MessageReferenceChipVariant, MessageReferenceIcon, type MessageReferenceIconProps, MessageReferenceIndicator, type MessageReferenceIndicatorProps, MessageReferenceLabel, type MessageReferenceLabelProps, MessageReferencePending, type MessageReferencePendingProps, MessageReferenceReadMark, type MessageReferenceReadMarkProps, MessageReferenceSuffix, type MessageReferenceSuffixProps, MessageReferenceText, type MessageReferenceTextProps, type MessageReferenceTextVariant, MessageReferenceUnavailable, type MessageReferenceUnavailableProps };
@@ -19,4 +19,18 @@ export type MessageItemAttachmentsProps = useRender.ComponentProps<"div">;
19
19
  export declare function MessageItemAttachments({ className, render, ...props }: MessageItemAttachmentsProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
20
20
  export type MessageItemFooterProps = useRender.ComponentProps<"div">;
21
21
  export declare function MessageItemFooter({ className, render, ...props }: MessageItemFooterProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
22
+ export type MessageItemTrailingProps = useRender.ComponentProps<"span">;
23
+ /**
24
+ * Something small that ends the message (the faces of the agents that read it,
25
+ * a read mark): the last child of `MessageItemBody`. It takes no column: it sits
26
+ * at the inline end of the body's last line, and the last line keeps room for it,
27
+ * so the text wraps under it only when that line is full. When the body ends with
28
+ * a block that isn't text (a code block, a table, an image), it sits on a line of
29
+ * its own under that block. Logical properties, so it is right in RTL too.
30
+ *
31
+ * It finds the body's last block itself and stamps it (`data-trailing-line`, or
32
+ * `data-trailing="block"` on the body), so the CSS needs no structural selector,
33
+ * and one shared ResizeObserver sets the room (`--message-trailing-width`).
34
+ */
35
+ export declare function MessageItemTrailing({ className, render, ref, ...props }: MessageItemTrailingProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
22
36
  //#endregion
@@ -1,4 +1,5 @@
1
1
  import { messageItem } from "./message-item.recipe.mjs";
2
+ import { useCallback, useLayoutEffect, useRef } from "react";
2
3
  import { mergeProps } from "@base-ui/react/merge-props";
3
4
  import { useRender } from "@base-ui/react/use-render";
4
5
  //#region src/components/message-item/message-item-content.tsx
@@ -77,5 +78,149 @@ function MessageItemFooter({ className, render, ...props }) {
77
78
  state: { slot: "message-item-footer" }
78
79
  });
79
80
  }
81
+ /** The space kept before a trailing slot on the body's last line. */
82
+ const TRAILING_GAP_PX = 8;
83
+ const BODY_SELECTOR = "[data-slot=\"message-item-body\"]";
84
+ const TEXT_BLOCKS = /* @__PURE__ */ new Set([
85
+ "P",
86
+ "H1",
87
+ "H2",
88
+ "H3",
89
+ "H4",
90
+ "H5",
91
+ "H6",
92
+ "SPAN"
93
+ ]);
94
+ const BLOCKS = /* @__PURE__ */ new Set([
95
+ ...TEXT_BLOCKS,
96
+ "UL",
97
+ "OL",
98
+ "BLOCKQUOTE",
99
+ "PRE",
100
+ "TABLE",
101
+ "DIV",
102
+ "FIGURE",
103
+ "IMG"
104
+ ]);
105
+ const slotOfBody = /* @__PURE__ */ new WeakMap();
106
+ const pendingWidths = /* @__PURE__ */ new Map();
107
+ const pendingStamps = /* @__PURE__ */ new Map();
108
+ let frame = 0;
109
+ function flush() {
110
+ frame = 0;
111
+ for (const [body, width] of pendingWidths) body.style.setProperty("--message-trailing-width", `${Math.ceil(width) + TRAILING_GAP_PX}px`);
112
+ for (const [body, slot] of pendingStamps) if (body.contains(slot)) stampLastLine(body, slot);
113
+ pendingWidths.clear();
114
+ pendingStamps.clear();
115
+ }
116
+ let sharedObserver = null;
117
+ function trailingObserver() {
118
+ if (typeof ResizeObserver === "undefined") return null;
119
+ sharedObserver ??= new ResizeObserver((entries) => {
120
+ for (const entry of entries) {
121
+ const target = entry.target;
122
+ const slot = slotOfBody.get(target);
123
+ if (slot) {
124
+ pendingStamps.set(target, slot);
125
+ continue;
126
+ }
127
+ const body = target.closest(BODY_SELECTOR);
128
+ if (!body) continue;
129
+ const box = entry.borderBoxSize?.[0];
130
+ pendingWidths.set(body, box ? box.inlineSize : entry.contentRect.width);
131
+ }
132
+ if (!frame) frame = requestAnimationFrame(flush);
133
+ });
134
+ return sharedObserver;
135
+ }
136
+ /** Marks the text block the slot ends (`data-trailing-line`), or the body as ending in a block. */
137
+ function stampLastLine(body, slot) {
138
+ const block = lastBlock(body, slot);
139
+ const line = block ? lastLine(block) : null;
140
+ const previous = body.querySelector("[data-trailing-line]");
141
+ if (previous && previous !== line) previous.removeAttribute("data-trailing-line");
142
+ if (line && !line.hasAttribute("data-trailing-line")) line.setAttribute("data-trailing-line", "");
143
+ const ending = line ? "line" : "block";
144
+ if (body.dataset.trailing !== ending) body.dataset.trailing = ending;
145
+ }
146
+ /** The body's last block before the slot, through wrappers that only hold blocks (a markdown root). */
147
+ function lastBlock(body, slot) {
148
+ let el = slot.previousElementSibling;
149
+ while (el && !BLOCKS.has(el.tagName)) el = el.previousElementSibling;
150
+ while (el && el.tagName === "DIV" && !el.hasAttribute("data-slot") && el.lastElementChild && BLOCKS.has(el.lastElementChild.tagName)) el = el.lastElementChild;
151
+ return el && body.contains(el) ? el : null;
152
+ }
153
+ /** The text block that ends a last block, or null when it ends with something else. */
154
+ function lastLine(block) {
155
+ if (TEXT_BLOCKS.has(block.tagName)) return block;
156
+ if (block.tagName === "UL" || block.tagName === "OL") {
157
+ const item = block.lastElementChild;
158
+ if (!item || item.tagName !== "LI") return null;
159
+ const inner = item.lastElementChild;
160
+ if (inner && inner.tagName === "P") return inner;
161
+ return inner && BLOCKS.has(inner.tagName) ? null : item;
162
+ }
163
+ if (block.tagName === "BLOCKQUOTE") {
164
+ const inner = block.lastElementChild;
165
+ return inner && inner.tagName === "P" ? inner : null;
166
+ }
167
+ return null;
168
+ }
169
+ /**
170
+ * Something small that ends the message (the faces of the agents that read it,
171
+ * a read mark): the last child of `MessageItemBody`. It takes no column: it sits
172
+ * at the inline end of the body's last line, and the last line keeps room for it,
173
+ * so the text wraps under it only when that line is full. When the body ends with
174
+ * a block that isn't text (a code block, a table, an image), it sits on a line of
175
+ * its own under that block. Logical properties, so it is right in RTL too.
176
+ *
177
+ * It finds the body's last block itself and stamps it (`data-trailing-line`, or
178
+ * `data-trailing="block"` on the body), so the CSS needs no structural selector,
179
+ * and one shared ResizeObserver sets the room (`--message-trailing-width`).
180
+ */
181
+ function MessageItemTrailing({ className, render, ref, ...props }) {
182
+ const { trailing } = messageItem();
183
+ const own = useRef(null);
184
+ useLayoutEffect(() => {
185
+ const slot = own.current;
186
+ const body = slot?.closest(BODY_SELECTOR);
187
+ if (slot && body) stampLastLine(body, slot);
188
+ });
189
+ useLayoutEffect(() => {
190
+ const slot = own.current;
191
+ const body = slot?.closest(BODY_SELECTOR);
192
+ const observer = trailingObserver();
193
+ if (slot && observer) observer.observe(slot);
194
+ if (slot && body && observer) {
195
+ slotOfBody.set(body, slot);
196
+ observer.observe(body);
197
+ }
198
+ return () => {
199
+ if (slot && observer) observer.unobserve(slot);
200
+ if (body) {
201
+ if (observer) observer.unobserve(body);
202
+ slotOfBody.delete(body);
203
+ body.querySelector("[data-trailing-line]")?.removeAttribute("data-trailing-line");
204
+ delete body.dataset.trailing;
205
+ body.style.removeProperty("--message-trailing-width");
206
+ }
207
+ };
208
+ }, []);
209
+ const setRef = useCallback((el) => {
210
+ own.current = el;
211
+ if (typeof ref === "function") ref(el);
212
+ else if (ref) ref.current = el;
213
+ }, [ref]);
214
+ const defaultProps = {
215
+ className: trailing({ className }),
216
+ ref: setRef
217
+ };
218
+ return useRender({
219
+ defaultTagName: "span",
220
+ render,
221
+ props: mergeProps(defaultProps, props),
222
+ state: { slot: "message-item-trailing" }
223
+ });
224
+ }
80
225
  //#endregion
81
- export { MessageItemAttachments, MessageItemBody, MessageItemContent, MessageItemEdited, MessageItemEmbedded, MessageItemFooter, MessageItemSearchMatch };
226
+ export { MessageItemAttachments, MessageItemBody, MessageItemContent, MessageItemEdited, MessageItemEmbedded, MessageItemFooter, MessageItemSearchMatch, MessageItemTrailing };
@@ -25,6 +25,7 @@ export declare const messageItem: import("tailwind-variants/lite").TVReturnType<
25
25
  delegatedByButton: string[];
26
26
  delegatedAvatar: string[];
27
27
  edited: string[];
28
+ trailing: string[];
28
29
  body: string[];
29
30
  searchMatch: string[];
30
31
  embedded: string[];
@@ -57,6 +58,7 @@ export declare const messageItem: import("tailwind-variants/lite").TVReturnType<
57
58
  delegatedByButton: string[];
58
59
  delegatedAvatar: string[];
59
60
  edited: string[];
61
+ trailing: string[];
60
62
  body: string[];
61
63
  searchMatch: string[];
62
64
  embedded: string[];
@@ -89,6 +91,7 @@ export declare const messageItem: import("tailwind-variants/lite").TVReturnType<
89
91
  delegatedByButton: string[];
90
92
  delegatedAvatar: string[];
91
93
  edited: string[];
94
+ trailing: string[];
92
95
  body: string[];
93
96
  searchMatch: string[];
94
97
  embedded: string[];
@@ -81,6 +81,7 @@ const messageItem = tv({
81
81
  "dark:shadow-[0_0_0_3px_var(--mi-row-fill,transparent),0_0_0_3px_var(--layer-canvas)]"
82
82
  ],
83
83
  edited: ["ms-1 whitespace-nowrap", "text-caption text-foreground-hint"],
84
+ trailing: ["absolute end-0 bottom-0 z-10 flex h-lh items-center", "select-none! **:select-none!"],
84
85
  body: [
85
86
  "wrap-break-word select-text",
86
87
  "**:select-text",
@@ -95,13 +96,13 @@ const messageItem = tv({
95
96
  "absolute z-20 flex items-center",
96
97
  "opacity-(--mi-toolbar-opacity,0)",
97
98
  "[pointer-events:var(--mi-toolbar-pe,none)]",
98
- "top-[-18px] right-3 gap-1 overflow-visible rounded-container p-1",
99
+ "top-[-18px] md:pointer-fine:top-[calc(-1*(var(--control-height)+8px)/2)] right-3 gap-1 overflow-visible rounded-container p-1",
99
100
  "bg-layer-popover ring-1 ring-line-seam ring-inset shadow-float"
100
101
  ],
101
102
  toolbarButton: [
102
103
  "inline-flex shrink-0 items-center justify-center",
103
104
  "[&_svg]:shrink-0",
104
- "size-7 rounded-chip border-0 bg-transparent p-0",
105
+ "size-7 rounded-chip md:pointer-fine:size-control md:pointer-fine:rounded-control border-0 bg-transparent p-0",
105
106
  "text-foreground-muted hover:bg-fill-medium active:bg-fill-medium",
106
107
  "data-popup-open:bg-fill-medium data-active:text-foreground",
107
108
  "outline-none focus-visible:shadow-focus",
@@ -45,20 +45,21 @@ const messageReaction = tv({ slots: {
45
45
  ],
46
46
  quickRow: [
47
47
  "flex shrink-0 items-center",
48
- "justify-between gap-0.5 bg-layer-popover px-0.75 py-0",
49
- "[&>[role=menuitem]]:size-9 [&>[role=menuitem]]:p-0 *:[[role=menuitem]]:justify-center"
48
+ "justify-start gap-0.5 bg-layer-popover p-0",
49
+ "[&>[role=menuitem]]:size-9 md:pointer-fine:[&>[role=menuitem]]:size-control [&>[role=menuitem]]:p-0 *:[[role=menuitem]]:justify-center"
50
50
  ],
51
51
  quickButton: [
52
52
  "flex items-center justify-center",
53
53
  "bg-transparent transition-colors",
54
54
  "size-9 rounded-chip p-0 text-xl leading-none text-foreground-muted",
55
+ "md:pointer-fine:size-control md:pointer-fine:rounded-control",
55
56
  "hover:bg-brand-soft data-highlighted:bg-brand-soft active:bg-brand-soft",
56
57
  "outline-none focus-visible:shadow-focus"
57
58
  ],
58
59
  pickerContent: [
59
60
  "inline-flex items-center",
60
61
  "min-w-0 flex-row gap-0.5 p-1",
61
- "[&>[role=menuitem]]:size-9 [&>[role=menuitem]]:p-0"
62
+ "[&>[role=menuitem]]:size-9 md:pointer-fine:[&>[role=menuitem]]:size-control [&>[role=menuitem]]:p-0"
62
63
  ],
63
64
  pickerStatic: [
64
65
  "inline-flex items-center",
@@ -41,7 +41,9 @@ const messageListJump = tv({
41
41
  "rounded-s-none border-s-0",
42
42
  "text-foreground-muted hover:text-foreground",
43
43
  "[&_svg:not([class*='size-'])]:size-4",
44
- "after:-inset-y-[calc(--spacing(1.5)+1.5px)] after:right-[calc(-0.75rem-1.5px)] after:left-0"
44
+ "after:-inset-y-[calc(--spacing(1.5)+1.5px)] after:right-[calc(-0.75rem-1.5px)] after:left-0",
45
+ "md:pointer-fine:after:-inset-y-[calc(var(--control-hit-inset)+1.5px)]",
46
+ "md:pointer-fine:after:right-[calc(-2*var(--control-hit-inset)-1.5px)] md:pointer-fine:after:left-0"
45
47
  ]
46
48
  },
47
49
  variants: { side: {
@@ -15,7 +15,7 @@ import { useRender } from "@base-ui/react/use-render";
15
15
  const modeBar = tv({ slots: {
16
16
  root: [
17
17
  "flex shrink-0 items-start",
18
- "min-h-10 gap-4 px-5 py-2.5 max-md:px-4",
18
+ "min-h-10 gap-4 px-(--surface-inset) py-2.5 max-md:px-4",
19
19
  "bg-layer-hud font-sans text-callout text-foreground-on-hud"
20
20
  ],
21
21
  content: ["min-w-0 flex-1 wrap-break-word"],
@@ -46,7 +46,7 @@ const notificationCenter = tv({
46
46
  itemRow: ["flex items-start", "gap-3"],
47
47
  itemIcon: [
48
48
  "flex shrink-0 items-center justify-center",
49
- "mt-0 size-[35px] rounded-sticker bg-fill-muted text-foreground-muted",
49
+ "mt-0 size-[35px] rounded-control bg-fill-muted text-foreground-muted",
50
50
  "[&_svg]:size-[18px]"
51
51
  ],
52
52
  itemContent: ["min-w-0 flex-1"],
@@ -1,4 +1,4 @@
1
- import { controlIconInset } from "../../lib/head-edges.mjs";
1
+ import { barButtonHit, barIconInset } from "../../lib/head-edges.mjs";
2
2
  import { tv } from "../../lib/tv.mjs";
3
3
  //#region src/components/panel/panel-action.recipe.ts
4
4
  const panelActionBase = tv({ base: [
@@ -6,14 +6,14 @@ const panelActionBase = tv({ base: [
6
6
  "overflow-visible font-sans leading-none tabular-nums select-none outline-none",
7
7
  "transition-all duration-100",
8
8
  "[&>svg]:pointer-events-none [&>svg]:shrink-0",
9
- "h-control min-w-control rounded-control border-[1.5px] border-transparent bg-transparent py-0",
10
- "px-2 md:pointer-fine:px-[5px]",
11
- "after:absolute after:-inset-[calc(var(--spacing-control-hit)+1.5px)]",
9
+ "h-(--bar-button-size) min-w-(--bar-button-size) rounded-(--bar-button-radius) border-[1.5px] border-transparent bg-transparent py-0",
10
+ "px-2 md:pointer-fine:px-[calc((var(--bar-button-size)-var(--control-icon-size)-3px)/2)]",
11
+ barButtonHit,
12
12
  "text-foreground",
13
13
  "hover:bg-fill-medium active:bg-fill-medium",
14
14
  "focus-visible:shadow-focus",
15
15
  "[&>svg]:size-control-icon",
16
- controlIconInset
16
+ barIconInset
17
17
  ] });
18
18
  const panelAction = tv({
19
19
  extend: panelActionBase,
@@ -1,14 +1,13 @@
1
- import { controlIconInset, headEdges } from "../../lib/head-edges.mjs";
1
+ import { barIconInset, headEdges } from "../../lib/head-edges.mjs";
2
2
  import { tv } from "../../lib/tv.mjs";
3
3
  //#region src/components/panel/panel-header.recipe.ts
4
4
  /**
5
5
  * Where a head's edge controls sit, shared by every head (panel, section,
6
6
  * drawer, thread): see lib/head-edges.ts. Both sides pad by the content
7
- * margin, 20px on a desktop and 16px on a phone, so a filled thing (a sticker,
7
+ * margin (16px on a phone, 20px from 768px by touch, 16px with a mouse), so a filled thing (a sticker,
8
8
  * a pill, a filled Button) puts its shape on it, and the first and last
9
9
  * frameless icon button are pulled out by their icon inset so their icon box
10
- * lands on it: 20px on a desktop and on a touch screen with the desktop
11
- * layout, 16px on a phone, mirrored at the two ends.
10
+ * lands on it, mirrored at the two ends.
12
11
  */
13
12
  const panelHeadEdges = headEdges;
14
13
  /**
@@ -17,10 +16,11 @@ const panelHeadEdges = headEdges;
17
16
  * button: an action hidden at some width (a thread's Close below 1024px) then
18
17
  * leaves the next one on the edge.
19
18
  */
20
- const panelHeadActions = ["flex shrink-0 items-center gap-0.5 md:pointer-fine:gap-1", controlIconInset];
19
+ const panelHeadActions = ["flex shrink-0 items-center gap-0.5 md:pointer-fine:gap-1", barIconInset];
21
20
  /**
22
21
  * `header` and `sectionHeader` share one bar, expressed through
23
- * `compoundSlots`: a 56px row (the shell header height) with a seam under it.
22
+ * `compoundSlots`: a header-height row (the shell header height, 56px on a
23
+ * phone and 44px on a desktop) with a seam under it.
24
24
  * On a phone the section head sits on the frame.
25
25
  */
26
26
  const panelHeader = tv({
@@ -29,14 +29,15 @@ const panelHeader = tv({
29
29
  sectionHeader: [],
30
30
  headerIcon: [
31
31
  "flex size-[27px] shrink-0 items-center justify-center",
32
+ "md:pointer-fine:size-(--bar-button-size) md:pointer-fine:rounded-(--bar-button-radius)",
32
33
  "rounded-sticker border-[1.5px] border-sticker-ink bg-brand text-sticker-ink ring-[1.5px] ring-sticker-edge",
33
34
  "not-data-[icon-kind=avatar]:[&_svg]:size-3.5 not-data-[icon-kind=avatar]:[&_svg]:stroke-2",
34
35
  "data-[icon-kind=avatar]:size-auto data-[icon-kind=avatar]:border-transparent data-[icon-kind=avatar]:bg-transparent"
35
36
  ],
36
- headerContent: "flex min-w-0 flex-1 flex-col justify-center",
37
+ headerContent: ["flex min-w-0 flex-1 flex-col justify-center", "md:pointer-fine:flex-row md:pointer-fine:items-baseline md:pointer-fine:justify-start md:pointer-fine:gap-2"],
37
38
  heading: "flex min-w-0 items-center gap-2",
38
39
  title: "truncate font-sans text-headline font-bold text-foreground",
39
- meta: "min-w-0 truncate font-sans text-caption text-foreground-hint",
40
+ meta: ["min-w-0 truncate font-sans text-caption text-foreground-hint", "md:pointer-fine:flex-1 md:pointer-fine:shrink-1000"],
40
41
  status: [
41
42
  "inline-flex shrink-0 items-center gap-1 border-0 bg-transparent p-0",
42
43
  "font-sans text-caption font-medium normal-case text-foreground-hint",
@@ -57,7 +58,7 @@ const panelHeader = tv({
57
58
  compoundSlots: [{
58
59
  slots: ["header", "sectionHeader"],
59
60
  class: [
60
- "flex h-(--shell-header-height,56px) shrink-0 items-center gap-3 max-md:gap-2",
61
+ "flex h-(--shell-header-height,var(--header-height)) shrink-0 items-center gap-3 max-md:gap-2",
61
62
  panelHeadEdges,
62
63
  "border-b border-line-seam bg-layer-canvas text-foreground",
63
64
  "max-md:sticky max-md:top-0 max-md:z-30"
@@ -3,11 +3,11 @@ import { tv } from "../../lib/tv.mjs";
3
3
  const panel = tv({
4
4
  slots: {
5
5
  root: ["[--panel-footer-clearance:10rem]", "bg-layer-canvas text-foreground"],
6
- header: ["[@media(max-height:600px)]:h-12"],
6
+ header: ["[@media(max-height:600px)]:h-(--header-height-short)"],
7
7
  body: ["relative min-h-0 flex-1 overflow-hidden"],
8
8
  scrollViewport: ["h-full min-h-0 overflow-y-auto overscroll-contain", "[overflow-anchor:auto] [-webkit-overflow-scrolling:touch]"],
9
9
  scrollContent: ["min-h-full"],
10
- section: ["border-t px-5 py-4", "border-line-hairline"],
10
+ section: ["border-t px-(--surface-inset) py-4", "border-line-hairline"],
11
11
  footer: [
12
12
  "relative flex shrink-0 items-center pt-3",
13
13
  "bg-layer-canvas",
@@ -4,7 +4,7 @@ import { jsx } from "react/jsx-runtime";
4
4
  import { Button } from "@base-ui/react/button";
5
5
  //#region src/components/picker-trigger-button/picker-trigger-button.tsx
6
6
  const pickerTriggerButton = tv({ base: [
7
- "relative inline-flex h-8 shrink-0 items-center justify-center",
7
+ "relative inline-flex h-8 md:pointer-fine:h-control shrink-0 items-center justify-center",
8
8
  "whitespace-nowrap select-none",
9
9
  "outline-[1px] outline-offset-2 outline-transparent transition-colors duration-100 focus-visible:outline-transparent",
10
10
  "disabled:pointer-events-none disabled:transform-none",
@@ -8,7 +8,7 @@ const profilePanel = tv({ slots: {
8
8
  ],
9
9
  header: [],
10
10
  headerContent: ["items-stretch gap-0"],
11
- section: ["border-line-hairline px-5 py-4"]
11
+ section: ["border-line-hairline px-(--surface-inset) py-4"]
12
12
  } });
13
13
  //#endregion
14
14
  export { profilePanel };
@@ -587,10 +587,7 @@
587
587
  block-size var(--r-scroll-area-duration) var(--r-scroll-area-easing);
588
588
  }
589
589
 
590
- /* Shown while hovered (trigger="hover"), always (trigger="none"), and while scrolling or dragging (every trigger). */
591
- .r-scroll-area.r-scroll-area--hover-trigger:hover
592
- > .r-scroll-area__gutters
593
- > .r-scroll-area__gutter,
590
+ /* Shown always (trigger="none"), and while scrolling or dragging (every trigger). */
594
591
  .r-scroll-area.r-scroll-area--none-trigger > .r-scroll-area__gutters > .r-scroll-area__gutter,
595
592
  .r-scroll-area
596
593
  > .r-scroll-area__gutters.r-scroll-area__gutters--scrolling
@@ -602,31 +599,7 @@
602
599
  transition-duration: var(--r-scroll-area-duration-fade-in);
603
600
  }
604
601
 
605
- /*
606
- * trigger="scroll": a hidden gutter doesn't catch presses meant for the
607
- * content under it. A gutter the pointer is already on (it was shown by
608
- * scrolling) stays visible and usable after `hideDelay`, until the pointer
609
- * leaves it; a hidden gutter can't become hovered, so it never shows on hover.
610
- */
611
- .r-scroll-area.r-scroll-area--scroll-trigger
612
- > .r-scroll-area__gutters
613
- > .r-scroll-area__gutter:hover {
614
- opacity: 1;
615
- transition-duration: var(--r-scroll-area-duration-fade-in);
616
- }
617
- .r-scroll-area.r-scroll-area--scroll-trigger
618
- > .r-scroll-area__gutters:not(.r-scroll-area__gutters--scrolling):not(
619
- .r-scroll-area__gutters--dragging
620
- )
621
- > .r-scroll-area__gutter:not(:hover) {
622
- pointer-events: none;
623
- }
624
-
625
- /* Pointed at, or while dragged: the thumb thickens and darkens. */
626
- .r-scroll-area
627
- > .r-scroll-area__gutters
628
- > .r-scroll-area__gutter--vertical:hover
629
- > .r-scroll-area__thumb,
602
+ /* While dragged: the thumb thickens and darkens. */
630
603
  .r-scroll-area
631
604
  > .r-scroll-area__gutters
632
605
  > .r-scroll-area__gutter--vertical.r-scroll-area__gutter--dragging
@@ -634,10 +607,6 @@
634
607
  background: var(--r-scroll-area-thumb-color-hover);
635
608
  inline-size: var(--r-scroll-area-thumb-size-hover);
636
609
  }
637
- .r-scroll-area
638
- > .r-scroll-area__gutters
639
- > .r-scroll-area__gutter--horizontal:hover
640
- > .r-scroll-area__thumb,
641
610
  .r-scroll-area
642
611
  > .r-scroll-area__gutters
643
612
  > .r-scroll-area__gutter--horizontal.r-scroll-area__gutter--dragging
@@ -646,6 +615,78 @@
646
615
  block-size: var(--r-scroll-area-thumb-size-hover);
647
616
  }
648
617
 
618
+ /*
619
+ * Hover only with a pointer that hovers (design/foundations/states.md): on a
620
+ * touch screen the last thing tapped stays `:hover`, which would leave the
621
+ * scrollbars shown, the thumb thick and a hidden gutter catching taps.
622
+ */
623
+ @media (hover: hover) {
624
+ /* trigger="hover": shown while the pointer is over the area. */
625
+ .r-scroll-area.r-scroll-area--hover-trigger:hover
626
+ > .r-scroll-area__gutters
627
+ > .r-scroll-area__gutter {
628
+ opacity: 1;
629
+ transition-duration: var(--r-scroll-area-duration-fade-in);
630
+ }
631
+
632
+ /*
633
+ * trigger="scroll": a hidden gutter doesn't catch presses meant for the
634
+ * content under it. A gutter the pointer is already on (it was shown by
635
+ * scrolling) stays visible and usable after `hideDelay`, until the pointer
636
+ * leaves it; a hidden gutter can't become hovered, so it never shows on hover.
637
+ */
638
+ .r-scroll-area.r-scroll-area--scroll-trigger
639
+ > .r-scroll-area__gutters
640
+ > .r-scroll-area__gutter:hover {
641
+ opacity: 1;
642
+ transition-duration: var(--r-scroll-area-duration-fade-in);
643
+ }
644
+ .r-scroll-area.r-scroll-area--scroll-trigger
645
+ > .r-scroll-area__gutters:not(.r-scroll-area__gutters--scrolling):not(
646
+ .r-scroll-area__gutters--dragging
647
+ )
648
+ > .r-scroll-area__gutter:not(:hover) {
649
+ pointer-events: none;
650
+ }
651
+
652
+ /* Pointed at: the thumb thickens and darkens, as while dragged. */
653
+ .r-scroll-area
654
+ > .r-scroll-area__gutters
655
+ > .r-scroll-area__gutter--vertical:hover
656
+ > .r-scroll-area__thumb {
657
+ background: var(--r-scroll-area-thumb-color-hover);
658
+ inline-size: var(--r-scroll-area-thumb-size-hover);
659
+ }
660
+ .r-scroll-area
661
+ > .r-scroll-area__gutters
662
+ > .r-scroll-area__gutter--horizontal:hover
663
+ > .r-scroll-area__thumb {
664
+ background: var(--r-scroll-area-thumb-color-hover);
665
+ block-size: var(--r-scroll-area-thumb-size-hover);
666
+ }
667
+ }
668
+
669
+ /*
670
+ * Where nothing hovers, trigger="hover" and "scroll" both show the scrollbars
671
+ * only while the area scrolls or a thumb is dragged, and a hidden gutter
672
+ * never catches a tap: it goes to the content under it. A scrollbar shown by
673
+ * scrolling takes the finger, so its thumb can be dragged; the drag keeps it.
674
+ */
675
+ @media (hover: none) {
676
+ .r-scroll-area.r-scroll-area--hover-trigger
677
+ > .r-scroll-area__gutters:not(.r-scroll-area__gutters--scrolling):not(
678
+ .r-scroll-area__gutters--dragging
679
+ )
680
+ > .r-scroll-area__gutter,
681
+ .r-scroll-area.r-scroll-area--scroll-trigger
682
+ > .r-scroll-area__gutters:not(.r-scroll-area__gutters--scrolling):not(
683
+ .r-scroll-area__gutters--dragging
684
+ )
685
+ > .r-scroll-area__gutter {
686
+ pointer-events: none;
687
+ }
688
+ }
689
+
649
690
  /*
650
691
  * Scroll-driven thumbs: the browser moves each thumb from the scroll itself,
651
692
  * on the compositor, with no script per scroll. The container names its
@@ -5,7 +5,8 @@ const searchEntity = tv({ slots: {
5
5
  entity: [
6
6
  "flex min-w-0 w-full items-center gap-3 text-left",
7
7
  "rounded-none border-0 py-3 text-foreground",
8
- "pointer-coarse:min-h-16",
8
+ "md:pointer-fine:py-2",
9
+ "pointer-coarse:min-h-14 pointer-coarse:py-2",
9
10
  listCell,
10
11
  listCellStates,
11
12
  "disabled:cursor-default",
@@ -15,7 +16,7 @@ const searchEntity = tv({ slots: {
15
16
  entityLeading: ["relative flex shrink-0"],
16
17
  entityIcon: [
17
18
  "flex items-center justify-center overflow-hidden",
18
- "size-[27px] rounded-sticker bg-fill-muted text-foreground-muted",
19
+ "size-[27px] rounded-chip bg-fill-muted text-foreground-muted",
19
20
  "[&_svg]:size-3.5"
20
21
  ],
21
22
  entityActivity: [