@botiverse/raft-ui 0.64.0 → 0.66.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 (90) hide show
  1. package/CHANGELOG.md +43 -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.mjs +1 -1
  7. package/dist/components/app-rail/app-rail.recipe.mjs +12 -7
  8. package/dist/components/app-shell/app-shell.mjs +1 -1
  9. package/dist/components/avatar/avatar.mjs +1 -0
  10. package/dist/components/badge/badge.mjs +6 -1
  11. package/dist/components/banner/banner.mjs +1 -1
  12. package/dist/components/button/button-split.mjs +10 -3
  13. package/dist/components/button/button.mjs +13 -8
  14. package/dist/components/code-block/code-block.recipe.mjs +1 -1
  15. package/dist/components/combobox/combobox.mjs +4 -4
  16. package/dist/components/combobox-select/combobox-select.css +6 -3
  17. package/dist/components/composer/composer-suggestion-list.mjs +1 -1
  18. package/dist/components/composer/composer-toolbar-label.mjs +1 -1
  19. package/dist/components/composer/composer.mjs +1 -1
  20. package/dist/components/composer/composer.recipe.mjs +38 -26
  21. package/dist/components/conversation-panel/conversation-panel-empty-state.mjs +1 -1
  22. package/dist/components/conversation-panel/conversation-panel.recipe.mjs +3 -2
  23. package/dist/components/dialog/dialog-sheet-context.mjs +1 -1
  24. package/dist/components/dialog/dialog.mjs +7 -7
  25. package/dist/components/drawer/drawer.mjs +3 -2
  26. package/dist/components/drawer/drawer.recipe.mjs +5 -3
  27. package/dist/components/empty-state/empty-state.mjs +1 -1
  28. package/dist/components/field/field.mjs +1 -1
  29. package/dist/components/files/files.recipe.mjs +1 -1
  30. package/dist/components/filter-chip/filter-chip.mjs +1 -1
  31. package/dist/components/form-section/form-section.mjs +1 -1
  32. package/dist/components/icon-tile/icon-tile.mjs +3 -3
  33. package/dist/components/inbox-item/inbox-item.recipe.mjs +4 -2
  34. package/dist/components/input/input.recipe.mjs +1 -1
  35. package/dist/components/input-group/input-group.mjs +1 -1
  36. package/dist/components/lightbox/lightbox.mjs +1 -1
  37. package/dist/components/list-row/list-row.recipe.mjs +2 -2
  38. package/dist/components/message-action-card/message-action-card-content.recipe.mjs +1 -1
  39. package/dist/components/message-action-card/message-action-card.recipe.mjs +1 -1
  40. package/dist/components/message-item/index.d.mts +2 -2
  41. package/dist/components/message-item/message-item-content.d.mts +14 -0
  42. package/dist/components/message-item/message-item-content.mjs +146 -1
  43. package/dist/components/message-item/message-item.recipe.d.mts +3 -0
  44. package/dist/components/message-item/message-item.recipe.mjs +3 -2
  45. package/dist/components/message-item/message-reaction.recipe.mjs +4 -3
  46. package/dist/components/message-list/message-list.recipe.mjs +3 -1
  47. package/dist/components/mode-bar/mode-bar.mjs +1 -1
  48. package/dist/components/notification-center/notification-center.mjs +1 -1
  49. package/dist/components/panel/panel-action.recipe.mjs +5 -5
  50. package/dist/components/panel/panel-header.recipe.mjs +10 -9
  51. package/dist/components/panel/panel.recipe.mjs +2 -2
  52. package/dist/components/picker-trigger-button/picker-trigger-button.mjs +1 -1
  53. package/dist/components/profile-panel/profile-panel.recipe.mjs +1 -1
  54. package/dist/components/scroll-area/scroll-area.css +74 -33
  55. package/dist/components/search/search-entity.recipe.mjs +3 -2
  56. package/dist/components/search/search-message.recipe.mjs +1 -0
  57. package/dist/components/search/search-thread.recipe.mjs +1 -1
  58. package/dist/components/search/search-trigger.mjs +1 -1
  59. package/dist/components/search/search.recipe.mjs +7 -3
  60. package/dist/components/segmented-control/segmented-control.mjs +9 -8
  61. package/dist/components/select/select.mjs +2 -2
  62. package/dist/components/sidebar/index.d.mts +2 -2
  63. package/dist/components/sidebar/sidebar-item.recipe.mjs +5 -4
  64. package/dist/components/sidebar/sidebar-section.d.mts +11 -2
  65. package/dist/components/sidebar/sidebar-section.mjs +29 -3
  66. package/dist/components/sidebar/sidebar-section.recipe.mjs +7 -2
  67. package/dist/components/sidebar/sidebar.recipe.mjs +3 -3
  68. package/dist/components/switch/switch.mjs +3 -3
  69. package/dist/components/tabs/tabs.mjs +1 -1
  70. package/dist/components/task-board/task-board-column.recipe.mjs +1 -1
  71. package/dist/components/task-list/task-list-section.recipe.mjs +1 -1
  72. package/dist/components/tasks/tasks-panel.recipe.mjs +4 -3
  73. package/dist/components/text-selection-toolbar/text-selection-toolbar.recipe.mjs +1 -1
  74. package/dist/components/textarea/textarea.mjs +1 -1
  75. package/dist/components/thread-panel/thread-panel.recipe.mjs +3 -3
  76. package/dist/components/toggle-group/toggle-group.mjs +1 -1
  77. package/dist/components/web-top-bar/index.d.mts +2 -0
  78. package/dist/components/web-top-bar/web-top-bar.d.mts +20 -0
  79. package/dist/components/web-top-bar/web-top-bar.mjs +63 -0
  80. package/dist/components/web-top-bar/web-top-bar.recipe.mjs +23 -0
  81. package/dist/foundation.css +100 -5
  82. package/dist/index.d.mts +2 -2
  83. package/dist/index.mjs +2 -2
  84. package/dist/lib/head-edges.mjs +38 -8
  85. package/dist/lib/list-cell.mjs +1 -0
  86. package/dist/styles.css +54 -7
  87. package/dist/tokens.json +260 -4
  88. package/dist/wip.d.mts +4 -1
  89. package/dist/wip.mjs +3 -1
  90. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,46 @@
1
+ ## [0.66.0](https://github.com/botiverse/raft-design/compare/v0.65.0...v0.66.0) (2026-11-05)
2
+
3
+ ### Added
4
+
5
+ - **SidebarSectionEndChevron**, and `chevronAtEnd` on **SidebarSectionHeader**: the section's chevron as the last of its controls with a mouse on a desktop, as sidebar.md has described since 0.65.0. It is a second trigger of the section (it toggles it and turns with it), out of the tab order and the accessibility tree, and a press leaves focus where it was; the title stays the one toggle for the keyboard and a screen reader. `chevronAtEnd` only hides the chevron before the title with a mouse; on a touch screen it shows as before.
6
+ - Why: the Raft web app drew its own end chevron (Kirby's review of slock #12730, 2026-11-05).
7
+ - Affects: nothing until a header opts in.
8
+ - Docs: https://raft-design.botiverse.build/components/sidebar/
9
+ - **WebTopBarRoot**, **WebTopBarStart**, **WebTopBarCenter** and **WebTopBarEnd** (`@botiverse/raft-ui/wip`): the web top bar (page-structure.md, "The web top bar") as a component: 44px with a mouse and 48px on touch (`--frame-item-height` + 2 × `--header-air`), the frame surface with its seam inside that height, its start on the rail's items, its center on the window and its end on the column margin. ([#1021](https://github.com/botiverse/raft-design/pull/1021))
10
+ - Why: the bar was hand-built in the app-shell composition (#proj-raft-ui:#199).
11
+ - Affects: nothing until an app moves its bar onto it.
12
+
13
+ ## [0.65.0](https://github.com/botiverse/raft-design/compare/v0.64.0...v0.65.0) (2026-11-05)
14
+
15
+ ### Added
16
+
17
+ - **MessageItemTrailing** (`@botiverse/raft-ui/wip`): a slot that ends a message's last line, the body's last child, such as the faces of the agents that read it. It takes no column: the last line keeps room for it and the text wraps under it only when that line is full; under a code block, a table or an image it has a line of its own.
18
+ - Why: the read faces kept a 63-77px column beside every message (stdrc, 2026-11-05).
19
+ - Docs: https://raft-design.botiverse.build/components/message-item/#trailing
20
+
21
+ ### Changed
22
+
23
+ - **Size chain tokens**: control, row, option and header heights are now one chain of variables in `tokens.json` and `foundation.css`, built on the existing `--control-height`, `--control-hit-inset` and `--control-embedded-size`; components read them instead of fixed sizes. New: `--row-height`, `--option-height`, `--control-air`, `--field-gap`, `--header-air`, `--header-height`, `--header-height-short`, `--bar-button-size`, `--bar-button-radius`, `--frame-item-height`, `--switch-width`, `--switch-height`, `--settings-row-inset`, `--section-gap`, `--page-inset`, `--rail-width`, `--rail-item`.
24
+ - Why: the desktop sizing review (stdrc, sizing option A, 2026-11-04) set one size per role; a component that hard-coded 32 or 56 drifted from the rest.
25
+ - Affects: nothing visible on its own; #973 and #974 set the desktop and touch values.
26
+ - Docs: https://raft-design.botiverse.build/foundations/spacing/
27
+ - **Desktop density** (with a mouse from 768px; touch is unchanged): one 34px control height for buttons, fields, selects, tabs, menu items and rows; 44px heads (34 + 2 × 5); 28px bar buttons with a 44px hit area; content 16px from a surface's edges (`--page-inset`, `--surface-inset`), 12px under a head (`--page-top`); settings cards 20 inside, 16 apart; sidebar rows and titles on two axes (glyphs at 16, text at 40) with a section's chevron at the end of its header; quick reactions a control high; empty states 16 from their sides. Also visible with a mouse: the rail is 49px wide with 36px items (was 57 and 40; `--rail-width-short`, `--rail-item-short`); a Switch is 38 × 22 (was 50 × 30); an IconTile takes its corner by size (27 chip, 35 control, 51 container) and an interactive badge is 20px high with the sticker corner; the hover toolbar is 42px (34px buttons) and floats half its height above the row; the Lightbox head is the header height.
28
+ - Why: stdrc's sizing review, rounds 3–9 (2026-11-04/05); the rules are in design/foundations/desktop-density.md.
29
+ - Affects: every desktop surface with a mouse. Apps that pad inside a raft-ui dialog, drawer or panel section with their own `md:` classes should drop them: the surface inset now replaces a caller's `px-*` again.
30
+ - Migrate: read `--surface-inset` / `--page-inset` instead of `px-5` for a surface's own padding; browser tests that measured 32px controls or 36px toolbars on a desktop now see 34 and 42.
31
+ - New variables: `--page-top`, `--rail-width-short`, `--rail-item-short` (tokens); `--surface-inset`, `--sidebar-glyph-axis`, `--sidebar-text-axis` (styles.css, next to `--column-margin`).
32
+ - Docs: https://raft-design.botiverse.build/foundations/desktop-density/
33
+ - **Touch density** (a phone width, and a touch screen at any width): 44px controls with a 10px radius (`--control-radius`; below 768px a mouse gets it too), denser rich rows (56px Activity, Inbox and person rows), a small ComboboxSelect keeps 8; icon tiles by size on touch.
34
+ - Why: the sizing audit's touch column (stdrc, 2026-11-04).
35
+ - Affects: phone widths and touch screens; a desktop with a mouse from 768px is unchanged.
36
+ - Docs: https://raft-design.botiverse.build/foundations/spacing/#hit-targets
37
+
38
+ ### Fixed
39
+
40
+ - **ScrollArea** and **InboxItem**: hover rules apply only with a pointer that can hover. On a touch screen the last thing tapped stays `:hover`, which left scrollbars shown, the thumb thick, a hidden gutter catching taps, and an Inbox row's action room open. ([#1017](https://github.com/botiverse/raft-design/pull/1017))
41
+ - Affects: touch screens only; mouse behavior is unchanged.
42
+ - **MessageActionCard**: the agent's reason is an upright quote (Space Grotesk has no italic), and a long permission list caps at 136px so the cut runs through a line of text at either description length. ([#1018](https://github.com/botiverse/raft-design/pull/1018))
43
+
1
44
  ## [0.64.0](https://github.com/botiverse/raft-design/compare/v0.63.1...v0.64.0) (2026-11-05)
2
45
 
3
46
  ### Added
@@ -12,7 +12,7 @@ const activityInboxSidebar = tv({ slots: {
12
12
  "py-0",
13
13
  "[&_[data-slot=sidebar-group-label]]:mt-3 [&_[data-slot=sidebar-group-label]]:mb-0",
14
14
  "**:data-[slot=sidebar-group-label]:flex **:data-[slot=sidebar-group-label]:items-center [&_[data-slot=sidebar-group-label]]:gap-2",
15
- "[&_[data-slot=sidebar-group-label]]:px-5 [&_[data-slot=sidebar-group-label]]:py-0",
15
+ "[&_[data-slot=sidebar-group-label]]:px-5 [&_[data-slot=sidebar-group-label]]:py-0 md:pointer-fine:[&_[data-slot=sidebar-group-label]]:px-2",
16
16
  "**:data-[slot=sidebar-group-label]:font-sans **:data-[slot=sidebar-group-label]:text-footnote [&_[data-slot=sidebar-group-label]]:font-bold",
17
17
  "**:data-[slot=sidebar-group-label]:text-foreground-hint **:data-[slot=sidebar-group-label]:normal-case [&_[data-slot=sidebar-group-label]]:tracking-normal",
18
18
  "**:data-activity-inbox-show-all:whitespace-nowrap"
@@ -1,9 +1,14 @@
1
1
  import { tv } from "../../lib/tv.mjs";
2
2
  //#region src/components/activity-inbox/activity-inbox-toolbar.recipe.ts
3
3
  const activityInboxToolbar = tv({ slots: {
4
- controls: ["flex shrink-0 flex-nowrap items-center gap-2", "bg-layer-canvas px-(--column-margin) py-3"],
4
+ controls: [
5
+ "flex shrink-0 flex-nowrap items-center gap-2",
6
+ "bg-layer-canvas px-(--column-margin) py-3",
7
+ "md:pointer-fine:py-[calc((var(--header-height)-var(--control-height))/2)]"
8
+ ],
5
9
  selectionToolbar: [
6
10
  "flex min-h-11 shrink-0 flex-wrap items-center gap-2 pt-1.5 pb-[5px]",
11
+ "md:pointer-fine:pt-1 md:pointer-fine:pb-[5px]",
7
12
  "border-b border-line-hairline bg-layer-canvas px-(--column-margin)",
8
13
  "**:data-[activity-inbox-action=sort]:text-foreground-muted",
9
14
  "**:data-[activity-inbox-action=sort]:hover:text-foreground"
@@ -22,18 +22,18 @@ const alertDialog = tv({
22
22
  ],
23
23
  header: [
24
24
  "grid grid-cols-[minmax(0,1fr)_max-content] items-center min-w-0",
25
- "gap-2 px-5 pt-5",
25
+ "gap-2 px-(--surface-inset) pt-(--surface-inset)",
26
26
  headEdgePull
27
27
  ],
28
28
  body: [
29
29
  "min-w-0",
30
- "px-5 pt-1.5 pb-5 first:pt-5",
30
+ "px-(--surface-inset) pt-1.5 pb-(--surface-inset) first:pt-(--surface-inset)",
31
31
  "font-sans text-subhead text-foreground-muted"
32
32
  ],
33
33
  footer: [
34
34
  "flex min-w-0 items-center justify-end",
35
35
  ...stackedActions,
36
- "gap-2 px-5 pb-5 first:pt-5 [[data-slot=alert-dialog-header]+&]:pt-5"
36
+ "gap-2 px-(--surface-inset) pb-(--surface-inset) first:pt-(--surface-inset) [[data-slot=alert-dialog-header]+&]:pt-(--surface-inset)"
37
37
  ],
38
38
  title: ["m-0 min-w-0 text-foreground", "font-sans text-headline font-bold"],
39
39
  description: ["m-0", "font-sans text-subhead text-foreground-muted"]
@@ -9,7 +9,7 @@ const announcement = tv({ slots: {
9
9
  body: [
10
10
  "min-h-0 max-h-[70dvh] overflow-y-auto pb-5",
11
11
  "[&_[data-slot=announcement-picture]+[data-slot=announcement-text]]:mt-5",
12
- "px-5 pt-5"
12
+ "px-(--surface-inset) pt-(--surface-inset)"
13
13
  ],
14
14
  header: ["flex min-w-0 items-center justify-between gap-3"],
15
15
  label: ["flex min-w-0 items-center gap-2 wrap-break-word", "text-caption text-foreground-muted"],
@@ -21,7 +21,7 @@ const announcement = tv({ slots: {
21
21
  "[&_ul]:list-disc [&_ol]:list-decimal [&_ul]:pl-5 [&_ol]:pl-5 [&_h1]:text-xl [&_h2]:text-lg [&_h3]:text-base [&_h1]:font-bold [&_h2]:font-bold [&_h3]:font-bold [&_pre]:max-w-full [&_pre]:overflow-x-auto",
22
22
  "text-subhead text-foreground-muted"
23
23
  ],
24
- footer: ["flex shrink-0 flex-wrap items-center justify-between gap-3 border-line-hairline py-4 @max-[28rem]/announcement:flex-col", "border-t-0 px-5 pt-0 pb-5"],
24
+ footer: ["flex shrink-0 flex-wrap items-center justify-between gap-3 border-line-hairline py-4 @max-[28rem]/announcement:flex-col", "border-t-0 px-(--surface-inset) pt-0 pb-(--surface-inset)"],
25
25
  action: ["ml-auto h-auto min-h-8 min-w-0 max-w-full py-1 whitespace-normal text-center font-bold @max-[28rem]/announcement:ml-0 @max-[28rem]/announcement:w-full"],
26
26
  secondary: ["min-w-0 max-w-full whitespace-normal @max-[28rem]/announcement:w-full"]
27
27
  } });
@@ -25,7 +25,7 @@ const appLinkCard = tv({ slots: {
25
25
  meta: ["flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", "m-0 font-sans text-callout text-foreground-muted"],
26
26
  actions: ["flex flex-wrap items-center justify-end gap-2", "px-4 pb-3 last:pb-4"],
27
27
  placeholderLine: ["flex h-lh items-center"],
28
- placeholderButton: ["h-8 w-28 rounded-control"]
28
+ placeholderButton: ["h-8 md:pointer-fine:h-control w-28 rounded-control"]
29
29
  } });
30
30
  function frame(className) {
31
31
  const { root } = appLinkCard();
@@ -3,35 +3,40 @@ import { tv } from "../../lib/tv.mjs";
3
3
  const appRail = tv({ slots: {
4
4
  root: [
5
5
  "flex size-full flex-col items-center select-none",
6
- "w-[calc(var(--shell-header-height,56px)+1px)] border-r border-line-seam",
6
+ "w-(--rail-width) border-r border-line-seam",
7
7
  "bg-layer-frame text-foreground-on-frame",
8
- "[@media(max-height:600px)]:w-[49px]"
8
+ "[@media(max-height:600px)]:w-(--rail-width-short)"
9
9
  ],
10
10
  header: [
11
11
  "relative flex w-full shrink-0 items-center justify-center",
12
- "h-(--shell-header-height,56px) border-b border-line-seam",
13
- "[@media(max-height:600px)]:h-12"
12
+ "h-(--shell-header-height,var(--header-height)) border-b border-line-seam",
13
+ "[@media(max-height:600px)]:h-(--header-height-short)"
14
14
  ],
15
15
  nav: [
16
16
  "flex w-full flex-1 flex-col items-center py-2",
17
17
  "gap-1.5 pt-2.5 pb-2 first:pt-2",
18
18
  "[@media(max-height:600px)]:pt-1.5 [@media(max-height:600px)]:first:pt-1.5",
19
+ "md:pointer-fine:gap-1 md:pointer-fine:pt-1.5 md:pointer-fine:first:pt-1.5",
19
20
  "after:mt-auto after:h-28 after:min-h-0 after:w-12 after:shrink after:content-[''] after:frame-decor-rail"
20
21
  ],
21
- footer: ["flex w-full shrink-0 flex-col items-center justify-center", "h-auto gap-1.5 pb-2 [@media(max-height:600px)]:pb-1.5"],
22
+ footer: [
23
+ "flex w-full shrink-0 flex-col items-center justify-center",
24
+ "h-auto gap-1.5 pb-2 [@media(max-height:600px)]:pb-1.5",
25
+ "md:pointer-fine:gap-1 md:pointer-fine:pb-1.5"
26
+ ],
22
27
  item: [
23
28
  "relative inline-flex shrink-0 items-center justify-center",
24
29
  "outline-none",
25
30
  "disabled:pointer-events-none disabled:opacity-45",
26
31
  "[&_svg]:shrink-0",
27
- "size-10 rounded-control border-[1.5px] border-transparent",
32
+ "size-(--rail-item) rounded-control border-[1.5px] border-transparent",
28
33
  "text-foreground-on-frame [&_svg]:size-5",
29
34
  "hover:bg-fill-frame-medium active:bg-fill-frame-medium",
30
35
  "data-[selected=true]:border-line-frame-active data-[selected=true]:bg-layer-frame-active",
31
36
  "data-[selected=true]:ring-[1.5px] data-[selected=true]:ring-sticker-edge",
32
37
  "data-[selected=true]:text-foreground-on-frame-active",
33
38
  "focus-visible:shadow-focus",
34
- "[@media(max-height:600px)]:size-9"
39
+ "[@media(max-height:600px)]:size-(--rail-item-short)"
35
40
  ],
36
41
  itemIcon: ["relative inline-flex items-center justify-center"],
37
42
  itemLabel: ["sr-only"],
@@ -12,7 +12,7 @@ const appShell = tv({
12
12
  "flex min-h-0 w-full overflow-visible md:overflow-clip",
13
13
  "max-md:flex-col max-md:pt-[env(safe-area-inset-top,0px)]",
14
14
  "font-sans",
15
- "[--shell-header-height:56px] [@media(max-height:600px)]:[--shell-header-height:48px]",
15
+ "[--shell-header-height:var(--header-height)] [@media(max-height:600px)]:[--shell-header-height:var(--header-height-short)]",
16
16
  "bg-layer-canvas text-foreground"
17
17
  ],
18
18
  railSlot: ["hidden h-full shrink-0 flex-col md:flex"],
@@ -64,6 +64,7 @@ const avatar = tv({
64
64
  groupButton: [
65
65
  "relative inline-flex shrink-0 cursor-pointer items-center p-1",
66
66
  "rounded-chip border-0 bg-transparent",
67
+ "md:pointer-fine:h-(--bar-button-size) md:pointer-fine:justify-center md:pointer-fine:rounded-(--bar-button-radius) md:pointer-fine:py-0",
67
68
  "transition-colors enabled:hover:bg-fill-medium enabled:active:bg-fill-medium",
68
69
  "outline-none focus-visible:shadow-focus",
69
70
  "disabled:cursor-default"
@@ -24,8 +24,13 @@ const badge = tv({
24
24
  "[&_svg]:size-[13px]",
25
25
  "enabled:hover:overlay-sticker-medium enabled:active:overlay-sticker-medium"
26
26
  ] },
27
- soft: { root: ["text-foreground", "enabled:hover:overlay-medium enabled:active:overlay-medium"] },
27
+ soft: { root: [
28
+ "md:pointer-fine:h-5 md:pointer-fine:rounded-sticker",
29
+ "text-foreground",
30
+ "enabled:hover:overlay-medium enabled:active:overlay-medium"
31
+ ] },
28
32
  outline: { root: [
33
+ "md:pointer-fine:h-5 md:pointer-fine:rounded-sticker",
29
34
  "font-mono text-mono-meta font-normal",
30
35
  "bg-transparent text-foreground-muted inset-ring inset-ring-line-hairline",
31
36
  "enabled:hover:bg-fill-medium enabled:active:bg-fill-medium"
@@ -67,7 +67,7 @@ const banner = tv({
67
67
  defaultVariants: { size: "md" },
68
68
  compoundVariants: [{
69
69
  size: "sm",
70
- class: { root: "has-[>[data-slot=banner-action],>[data-banner-close]]:py-[calc((--spacing(8)-1lh)/2+--spacing(1))]" }
70
+ class: { root: ["[--banner-button:--spacing(8)] md:pointer-fine:[--banner-button:var(--control-height)]", "has-[>[data-slot=banner-action],>[data-banner-close]]:py-[calc((var(--banner-button)-1lh)/2+--spacing(1))]"] }
71
71
  }]
72
72
  });
73
73
  /**
@@ -7,7 +7,8 @@ import { jsx } from "react/jsx-runtime";
7
7
  const buttonSplit = tv({ base: [
8
8
  "relative isolate inline-flex shrink-0 items-stretch",
9
9
  "rounded-control ring-sticker-edge",
10
- "data-sticker-edge:ring-[1.5px]"
10
+ "data-sticker-edge:ring-[1.5px]",
11
+ "data-[size=lg]:rounded-(--control-radius)"
11
12
  ] });
12
13
  const buttonSplitMain = tv({ base: ["rounded-e-none border-e-0", "ring-0 focus-visible:z-1"] });
13
14
  const buttonSplitMenu = tv({
@@ -40,7 +41,8 @@ const STICKERS = /* @__PURE__ */ new Set([
40
41
  ]);
41
42
  const ButtonSplitContext = createContext({
42
43
  disabled: false,
43
- registerStickerPart: () => () => {}
44
+ registerStickerPart: () => () => {},
45
+ setSize: () => {}
44
46
  });
45
47
  /** An enabled sticker part asks its group to draw the die-cut edge while it is mounted. */
46
48
  function useStickerEdge(active) {
@@ -60,9 +62,11 @@ function ButtonSplit({ disabled = false, className, ...props }) {
60
62
  setStickerParts((count) => count + 1);
61
63
  return () => setStickerParts((count) => count - 1);
62
64
  }, []);
65
+ const [size, setSize] = useState("md");
63
66
  const context = useMemo(() => ({
64
67
  disabled,
65
- registerStickerPart
68
+ registerStickerPart,
69
+ setSize
66
70
  }), [disabled, registerStickerPart]);
67
71
  return /* @__PURE__ */ jsx(ButtonSplitContext.Provider, {
68
72
  value: context,
@@ -71,6 +75,7 @@ function ButtonSplit({ disabled = false, className, ...props }) {
71
75
  ...props,
72
76
  "data-slot": "button-split",
73
77
  "data-sticker-edge": stickerParts > 0 ? "" : void 0,
78
+ "data-size": size,
74
79
  className: buttonSplit({ className })
75
80
  })
76
81
  });
@@ -80,6 +85,8 @@ function ButtonSplitMain({ variant = "default", size = "md", disabled, className
80
85
  const group = useContext(ButtonSplitContext);
81
86
  const isDisabled = disabled || group.disabled;
82
87
  useStickerEdge(STICKERS.has(variant) && !isDisabled && !props.loading);
88
+ const { setSize } = group;
89
+ useLayoutEffect(() => setSize(size), [setSize, size]);
83
90
  return /* @__PURE__ */ jsx(Button, {
84
91
  ...props,
85
92
  variant,
@@ -8,12 +8,17 @@ import { Button } from "@base-ui/react/button";
8
8
  const sticker = (fill) => [`border-sticker-ink ${fill} text-sticker-ink ring-[1.5px] ring-sticker-edge`, "hover:overlay-sticker-medium active:overlay-sticker-medium"];
9
9
  const outline = (ink) => [`border-line-strong bg-layer-card ${ink}`, "hover:overlay-medium active:overlay-medium"];
10
10
  const textMd = [
11
- "h-8 gap-2 rounded-control px-3 py-0 text-control",
11
+ "h-8 md:pointer-fine:h-control gap-2 rounded-control px-3 py-0 text-control",
12
12
  "has-data-[icon=inline-start]:pl-2.5 has-data-[icon=inline-end]:pr-2.5",
13
13
  "[&_svg:not([class*='size-'])]:size-4 **:data-icon:size-[1em]",
14
- "after:absolute after:inset-x-0 after:-inset-y-[calc(--spacing(1.5)+1.5px)]"
14
+ "after:absolute after:inset-x-0 after:-inset-y-[calc(--spacing(1.5)+1.5px)]",
15
+ "md:pointer-fine:after:-inset-y-[calc(var(--control-hit-inset)+1.5px)]"
16
+ ];
17
+ const iconMd = [
18
+ "size-8 md:pointer-fine:size-control rounded-control p-0 [&_svg:not([class*='size-'])]:size-[18px]",
19
+ "after:absolute after:-inset-[calc(--spacing(1.5)+1.5px)]",
20
+ "md:pointer-fine:after:-inset-[calc(var(--control-hit-inset)+1.5px)]"
15
21
  ];
16
- const iconMd = ["size-8 rounded-control p-0 [&_svg:not([class*='size-'])]:size-[18px]", "after:absolute after:-inset-[calc(--spacing(1.5)+1.5px)]"];
17
22
  const buttonVariants = tv({
18
23
  slots: {
19
24
  root: [
@@ -63,7 +68,7 @@ const buttonVariants = tv({
63
68
  sm: { root: textMd },
64
69
  md: { root: textMd },
65
70
  lg: { root: [
66
- "h-control gap-2 rounded-control px-4 py-0 text-subhead",
71
+ "h-control gap-2 rounded-(--control-radius) px-4 py-0 text-subhead",
67
72
  "has-data-[icon=inline-start]:pl-3.5 has-data-[icon=inline-end]:pr-3.5",
68
73
  "[&_svg:not([class*='size-'])]:size-[18px] **:data-icon:size-[1em]",
69
74
  "after:absolute after:inset-x-0 after:-inset-y-[calc(var(--spacing-control-hit)+1.5px)]"
@@ -72,7 +77,7 @@ const buttonVariants = tv({
72
77
  "icon-xs": { root: iconMd },
73
78
  "icon-sm": { root: iconMd },
74
79
  "icon-md": { root: iconMd },
75
- "icon-lg": { root: ["size-control rounded-control p-0 [&_svg:not([class*='size-'])]:size-control-icon", "after:absolute after:-inset-[calc(var(--spacing-control-hit)+1.5px)]"] }
80
+ "icon-lg": { root: ["size-control rounded-(--control-radius) p-0 [&_svg:not([class*='size-'])]:size-control-icon", "after:absolute after:-inset-[calc(var(--spacing-control-hit)+1.5px)]"] }
76
81
  }
77
82
  },
78
83
  defaultVariants: {
@@ -117,7 +122,7 @@ const buttonVariants = tv({
117
122
  "icon-sm",
118
123
  "icon-md"
119
124
  ],
120
- class: { root: "[--icon-inset:calc((--spacing(8)-18px)/2)]" }
125
+ class: { root: "[--icon-inset:calc((--spacing(8)-18px)/2)] md:pointer-fine:[--icon-inset:calc((var(--control-height)-18px)/2)]" }
121
126
  },
122
127
  {
123
128
  variant: "on-frame",
@@ -126,7 +131,7 @@ const buttonVariants = tv({
126
131
  "sm",
127
132
  "md"
128
133
  ],
129
- class: { root: "h-9 px-2.5 text-subhead after:-inset-y-[calc(--spacing(1)+1.5px)]" }
134
+ class: { root: "h-(--frame-item-height) px-2.5 text-subhead after:-inset-y-[calc((44px-var(--frame-item-height))/2+1.5px)]" }
130
135
  },
131
136
  {
132
137
  variant: "on-frame",
@@ -135,7 +140,7 @@ const buttonVariants = tv({
135
140
  "icon-sm",
136
141
  "icon-md"
137
142
  ],
138
- class: { root: ["size-9 after:-inset-[calc(--spacing(1)+1.5px)] [&_svg:not([class*='size-'])]:size-5", "[--icon-inset:calc((--spacing(9)-20px)/2)]"] }
143
+ class: { root: ["size-(--frame-item-height) after:-inset-[calc((44px-var(--frame-item-height))/2+1.5px)] [&_svg:not([class*='size-'])]:size-5", "[--icon-inset:calc((var(--frame-item-height)-20px)/2)]"] }
139
144
  }
140
145
  ]
141
146
  });
@@ -37,7 +37,7 @@ const codeBlock = tv({ slots: {
37
37
  "inline-flex shrink-0 items-center justify-center",
38
38
  "transition-[color,background-color,opacity]",
39
39
  "focus-visible:outline-none",
40
- "size-8 rounded-chip text-foreground",
40
+ "size-8 rounded-chip md:pointer-fine:size-control md:pointer-fine:rounded-control text-foreground",
41
41
  "hover:bg-fill-medium active:bg-fill-medium",
42
42
  "focus-visible:ring-0 focus-visible:shadow-focus",
43
43
  "[&_svg:not([class*='size-'])]:size-4.5"
@@ -17,7 +17,7 @@ const combobox = tv({
17
17
  "**:data-[slot='button-content']:w-full **:data-[slot='button-content']:justify-between",
18
18
  "[&>span[data-slot='combobox-trigger-content']]:min-w-0 [&>span[data-slot='combobox-trigger-content']]:flex-1",
19
19
  "[&>span[data-slot='combobox-trigger-content']>svg]:shrink-0",
20
- "h-8 gap-1.5 rounded-control border-transparent bg-transparent px-2.5",
20
+ "h-8 md:pointer-fine:h-control gap-1.5 rounded-control border-transparent bg-transparent px-2.5",
21
21
  "text-control font-semibold text-foreground-muted",
22
22
  "inset-ring inset-ring-line-seam hover:bg-transparent",
23
23
  "data-has-value:bg-info-soft data-has-value:text-foreground data-has-value:inset-ring-0 data-has-value:hover:bg-info-soft",
@@ -42,7 +42,7 @@ const combobox = tv({
42
42
  "[&>[data-slot=combobox-clear]:last-child]:me-[calc(var(--control-embedded-inset)-0.75rem-1px)]",
43
43
  "[&_[data-slot='combobox-trigger-indicator']]:size-4",
44
44
  "[&_[data-slot='combobox-trigger-indicator']>svg]:shrink-0",
45
- "min-h-control rounded-control border-[1.5px] border-line-field bg-layer-card px-3 py-0",
45
+ "min-h-control rounded-(--control-radius) border-[1.5px] border-line-field bg-layer-card px-3 py-0",
46
46
  "font-sans text-body text-foreground",
47
47
  "transition-shadow duration-90 ease-out has-focus-visible:shadow-focus",
48
48
  "[&>svg]:text-foreground-hint [&>svg:not([class*='size-'])]:size-4.5",
@@ -51,7 +51,7 @@ const combobox = tv({
51
51
  ],
52
52
  inputGroup: [
53
53
  "flex items-center border-b",
54
- "h-10 gap-2 border-line-hairline bg-transparent px-3 py-0",
54
+ "h-10 md:pointer-fine:h-control gap-2 border-line-hairline bg-transparent px-3 py-0",
55
55
  "text-callout text-foreground-hint",
56
56
  "[&>svg]:size-4 [&>svg]:shrink-0",
57
57
  "first:rounded-t-container has-focus-visible:keyboard:inset-ring-2 has-focus-visible:keyboard:inset-ring-foreground"
@@ -96,7 +96,7 @@ const combobox = tv({
96
96
  groupLabel: ["py-2", "px-2.5 pt-2 pb-1 text-caption font-bold text-foreground-hint"],
97
97
  chips: [
98
98
  "flex flex-wrap items-center",
99
- "min-h-control gap-1.5 rounded-control border-[1.5px] border-line-field bg-layer-card py-[calc(var(--control-embedded-inset)-1.5px)] pr-3 pl-[calc(var(--control-embedded-inset)-1px)]",
99
+ "min-h-control gap-1.5 rounded-(--control-radius) border-[1.5px] border-line-field bg-layer-card py-[calc(var(--control-embedded-inset)-1.5px)] pr-3 pl-[calc(var(--control-embedded-inset)-1px)]",
100
100
  "*:data-[slot=combobox-input]:h-control-embedded",
101
101
  "transition-shadow duration-90 ease-out has-focus-visible:shadow-focus"
102
102
  ],
@@ -20,7 +20,7 @@
20
20
  gap: var(--control-embedded-inset);
21
21
  padding: 0 calc(var(--control-embedded-inset) - 1px) 0 12px;
22
22
  border: 1.5px solid var(--line-field);
23
- border-radius: var(--radius-control);
23
+ border-radius: var(--control-radius);
24
24
  outline: 0;
25
25
  background: var(--layer-card);
26
26
  color: var(--foreground);
@@ -194,8 +194,8 @@
194
194
  width: 100%;
195
195
  /* The option inset (styles.css, --spacing-option-inset): one line is 36px,
196
196
  and a second line adds only its own height (forms.md#option-height). */
197
- min-height: 36px;
198
- padding: calc((36px - 1lh) / 2) 10px;
197
+ min-height: var(--option-height);
198
+ padding: calc((var(--option-height) - 1lh) / 2) 10px;
199
199
  display: flex;
200
200
  align-items: center;
201
201
  justify-content: space-between;
@@ -277,6 +277,9 @@
277
277
  }
278
278
  .r-combobox-select--sm.r-combobox-select__control {
279
279
  --control-height: 1.75rem;
280
+ /* A 28px field keeps the 32px control's corner on every input: the root's
281
+ control-radius (10 on a touch screen) belongs to 44px fields. */
282
+ --control-radius: var(--radius-control);
280
283
  --control-embedded-inset: 3px;
281
284
  --control-embedded-size: 22px;
282
285
  font-size: var(--text-control);
@@ -13,7 +13,7 @@ const composerSuggestionList = tv({
13
13
  groupLabel: ["py-1.5", "px-2.5 pt-2 pb-1 font-sans text-caption font-bold text-foreground-hint"],
14
14
  item: [
15
15
  "flex w-full items-center text-left",
16
- "min-h-9 cursor-pointer gap-2.5 rounded-chip px-2.5 py-1",
16
+ "min-h-option cursor-pointer gap-2.5 rounded-chip px-2.5 py-1",
17
17
  "font-sans text-callout font-medium text-foreground",
18
18
  "hover:bg-brand-soft data-[highlighted=true]:bg-brand-soft",
19
19
  "data-[disabled=true]:cursor-default data-[disabled=true]:text-foreground-disabled",
@@ -4,7 +4,7 @@ import { useRender } from "@base-ui/react/use-render";
4
4
  //#region src/components/composer/composer-toolbar-label.tsx
5
5
  const composerToolbarLabel = tv({ slots: { root: [
6
6
  "inline-flex cursor-pointer select-none items-center",
7
- "min-h-8 gap-2",
7
+ "min-h-8 md:pointer-fine:min-h-(--bar-button-size) gap-2",
8
8
  "font-sans text-callout font-semibold text-foreground",
9
9
  "has-data-disabled:cursor-not-allowed has-data-disabled:text-foreground-disabled"
10
10
  ] } });
@@ -74,7 +74,7 @@ function ComposerIconButton({ className, ...props }) {
74
74
  });
75
75
  }
76
76
  function ComposerSubmit({ type = "submit", className, ...props }) {
77
- const { submit } = composer();
77
+ const { submit } = composer({ icon: props.size?.startsWith("icon") ?? false });
78
78
  return /* @__PURE__ */ jsx(Button, {
79
79
  ...props,
80
80
  className: submit({ className }),
@@ -1,30 +1,42 @@
1
+ import { barButtonDesktop } from "../../lib/head-edges.mjs";
1
2
  import { tv } from "../../lib/tv.mjs";
2
3
  //#region src/components/composer/composer.recipe.ts
3
- const composer = tv({ slots: {
4
- root: [
5
- "flex w-full flex-col gap-2 p-2",
6
- "rounded-container border-[1.5px] px-3 pt-3 pb-[calc(var(--control-embedded-inset)-1px)]",
7
- "border-line-field bg-layer-card text-foreground shadow-none",
8
- "has-focus-visible:shadow-focus"
9
- ],
10
- inputFrame: ["w-full min-w-0", "[--r-scroll-area-resize-grip-size:0px]"],
11
- input: [
12
- "max-h-32 w-full resize-none bg-transparent outline-none",
13
- "field-sizing-content overflow-y-auto",
14
- "min-h-6 px-0.5",
15
- "font-sans text-body font-normal text-foreground",
16
- "placeholder:text-foreground-hint"
17
- ],
18
- toolbar: ["flex items-center justify-between", "mx-[calc(var(--control-embedded-inset)-0.75rem-1px)] gap-embedded-inset"],
19
- actions: ["flex items-center gap-embedded-inset"],
20
- meta: ["flex items-center", "gap-embedded-inset"],
21
- iconButton: [
22
- "size-8 rounded-chip text-foreground-muted",
23
- "disabled:border-transparent disabled:bg-transparent",
24
- "aria-disabled:border-transparent aria-disabled:bg-transparent",
25
- "[&_svg:not([class*='size-'])]:size-4.5"
26
- ],
27
- submit: ["rounded-chip"]
28
- } });
4
+ const composer = tv({
5
+ slots: {
6
+ root: [
7
+ "flex w-full flex-col gap-2 p-2",
8
+ "rounded-container border-[1.5px] px-3 pt-3 pb-[calc(var(--control-embedded-inset)-1px)]",
9
+ "border-line-field bg-layer-card text-foreground shadow-none",
10
+ "has-focus-visible:shadow-focus"
11
+ ],
12
+ inputFrame: ["w-full min-w-0", "[--r-scroll-area-resize-grip-size:0px]"],
13
+ input: [
14
+ "max-h-32 w-full resize-none bg-transparent outline-none",
15
+ "field-sizing-content overflow-y-auto",
16
+ "min-h-6 px-0.5",
17
+ "font-sans text-body font-normal text-foreground",
18
+ "placeholder:text-foreground-hint"
19
+ ],
20
+ toolbar: [
21
+ "flex items-center justify-between",
22
+ "mx-[calc(var(--control-embedded-inset)-0.75rem-1px)] gap-embedded-inset",
23
+ "md:pointer-fine:mx-[calc((var(--control-icon-size)-var(--bar-button-size))/2)]"
24
+ ],
25
+ actions: ["flex items-center gap-embedded-inset"],
26
+ meta: ["flex items-center", "gap-embedded-inset"],
27
+ iconButton: [
28
+ "size-8 rounded-chip text-foreground-muted",
29
+ barButtonDesktop,
30
+ "disabled:border-transparent disabled:bg-transparent",
31
+ "aria-disabled:border-transparent aria-disabled:bg-transparent",
32
+ "[&_svg:not([class*='size-'])]:size-4.5"
33
+ ],
34
+ submit: ["rounded-chip"]
35
+ },
36
+ variants: { icon: {
37
+ true: { submit: barButtonDesktop },
38
+ false: {}
39
+ } }
40
+ });
29
41
  //#endregion
30
42
  export { composer };
@@ -6,7 +6,7 @@ const conversationPanelEmptyState = tv({ slots: {
6
6
  root: [
7
7
  "flex h-full min-h-0 min-w-0 flex-1 flex-col items-center justify-center",
8
8
  "text-center",
9
- "gap-2 px-5 py-6",
9
+ "gap-2 px-(--surface-inset) py-6",
10
10
  "font-sans text-headline font-bold normal-case text-foreground-muted"
11
11
  ],
12
12
  brand: ["shrink-0", "mb-1 inline-flex rounded-none p-0 text-foreground-hint"],
@@ -6,8 +6,9 @@ const conversationPanel = tv({ slots: {
6
6
  tabs: [
7
7
  "shrink-0",
8
8
  "border-b border-line-seam bg-layer-canvas",
9
- "*:data-[slot=tabs-list]:w-full *:data-[slot=tabs-list]:px-5 max-md:*:data-[slot=tabs-list]:px-4",
10
- "*:data-[slot=tabs-list]:data-[variant=default]:py-2"
9
+ "*:data-[slot=tabs-list]:w-full *:data-[slot=tabs-list]:px-5 max-md:*:data-[slot=tabs-list]:px-4 md:pointer-fine:*:data-[slot=tabs-list]:px-(--page-inset)",
10
+ "*:data-[slot=tabs-list]:data-[variant=default]:py-2",
11
+ "md:pointer-fine:*:data-[slot=tabs-list]:data-[variant=default]:py-[calc((var(--header-height)-1px-var(--control-height))/2)]"
11
12
  ],
12
13
  footer: ["pt-0", "bg-layer-canvas"]
13
14
  } });
@@ -47,7 +47,7 @@ const dialogSheet = tv({ slots: {
47
47
  "data-starting-style:opacity-0 data-ending-style:opacity-0",
48
48
  "motion-reduce:transition-none"
49
49
  ],
50
- header: ["flex h-14 shrink-0 items-center gap-2 px-4 pt-0", "border-b border-line-seam"],
50
+ header: ["flex h-(--header-height) shrink-0 items-center gap-2 px-4 pt-0", "border-b border-line-seam"],
51
51
  title: ["min-w-0 flex-1 truncate"],
52
52
  commitSlot: ["flex shrink-0 items-center empty:hidden"],
53
53
  body: ["min-h-0 content-start", "px-4 pt-4 first:pt-4 pb-[max(16px,env(safe-area-inset-bottom,0px))]"],
@@ -1,6 +1,6 @@
1
1
  import { cn } from "../../cn.mjs";
2
2
  import { decisionWidth } from "../../lib/decision-width.mjs";
3
- import { headEdgePull } from "../../lib/head-edges.mjs";
3
+ import { barButtonDesktop, headEdgePull } from "../../lib/head-edges.mjs";
4
4
  import { stackedActions, useStackedActions } from "../../lib/stacked-actions.mjs";
5
5
  import { tv } from "../../lib/tv.mjs";
6
6
  import { useThemeScopeProps } from "../../lib/theme/theme-scope.mjs";
@@ -28,18 +28,18 @@ const dialog = tv({
28
28
  ],
29
29
  header: [
30
30
  "grid shrink-0 grid-cols-[minmax(0,1fr)_max-content] items-center min-w-0",
31
- "gap-2 px-5 pt-5",
31
+ "gap-2 px-(--surface-inset) pt-(--surface-inset)",
32
32
  headEdgePull
33
33
  ],
34
34
  body: [
35
35
  "min-w-0 flex-1 overflow-y-auto",
36
- "px-5 pt-1.5 pb-5 first:pt-5",
36
+ "px-(--surface-inset) pt-1.5 pb-(--surface-inset) first:pt-(--surface-inset)",
37
37
  "font-sans text-subhead text-foreground-muted"
38
38
  ],
39
39
  footer: [
40
40
  "flex shrink-0 items-center justify-end",
41
41
  ...stackedActions,
42
- "gap-2 px-5 pb-5 first:pt-5 [[data-slot=dialog-header]+&]:pt-5",
42
+ "gap-2 px-(--surface-inset) pb-(--surface-inset) first:pt-(--surface-inset) [[data-slot=dialog-header]+&]:pt-(--surface-inset)",
43
43
  "*:data-[slot=text-link]:text-footnote"
44
44
  ],
45
45
  footerNote: ["m-0 md:me-2 md:flex-1", "text-start font-sans text-footnote text-pretty text-foreground-muted md:whitespace-nowrap"],
@@ -61,9 +61,9 @@ const dialog = tv({
61
61
  bar: {
62
62
  false: {},
63
63
  true: {
64
- header: ["flex h-14 shrink-0 items-center gap-2 border-b px-5 py-0", "border-line-seam pt-0 [&>[data-slot=dialog-close]]:my-0"],
64
+ header: ["flex h-(--header-height) shrink-0 items-center gap-2 border-b px-(--surface-inset) py-0", "border-line-seam pt-0 [&>[data-slot=dialog-close]]:my-0"],
65
65
  body: ["flex min-h-0 flex-1 overflow-hidden p-0", "px-0 pt-0 pb-0 first:pt-0 text-foreground"],
66
- footer: ["shrink-0 border-t px-5 py-3", "border-line-seam pt-3 pb-3 first:pt-3 [[data-slot=dialog-header]+&]:pt-3"]
66
+ footer: ["shrink-0 border-t px-(--surface-inset) py-3", "border-line-seam pt-3 pb-3 first:pt-3 [[data-slot=dialog-header]+&]:pt-3"]
67
67
  }
68
68
  },
69
69
  layer: {
@@ -170,7 +170,7 @@ function DialogClose({ className, variant, size, children, render, "aria-label":
170
170
  variant: variant ?? "ghost",
171
171
  size: size ?? "icon-md",
172
172
  "aria-label": ariaLabel ?? "Close",
173
- className: cn("-my-1.5", className)
173
+ className: cn("-my-1.5", size ? void 0 : barButtonDesktop, className)
174
174
  }),
175
175
  ...props,
176
176
  children: children ?? /* @__PURE__ */ jsx(X, { className: "size-4.5" })
@@ -107,7 +107,7 @@ function DrawerContent({ className, children, portalProps, ...props }) {
107
107
  });
108
108
  }
109
109
  function DrawerClose({ className, variant, size, children, render, "aria-label": ariaLabel, ...props }) {
110
- const { close, closeIcon } = drawer();
110
+ const { close, closeButton, closeIcon } = drawer();
111
111
  if (render) return /* @__PURE__ */ jsx(Drawer.Close, {
112
112
  "data-slot": "drawer-close",
113
113
  className,
@@ -121,7 +121,8 @@ function DrawerClose({ className, variant, size, children, render, "aria-label":
121
121
  render: /* @__PURE__ */ jsx(Button, {
122
122
  variant: variant ?? "ghost",
123
123
  size: size ?? "icon-lg",
124
- "aria-label": ariaLabel ?? "Close"
124
+ "aria-label": ariaLabel ?? "Close",
125
+ className: size ? void 0 : closeButton()
125
126
  }),
126
127
  className: close({ className }),
127
128
  ...props,