@ctrl-ui/react 0.8.10 → 0.8.12

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 (98) hide show
  1. package/dist/action-bar.js +2 -2
  2. package/dist/activity.js +1 -1
  3. package/dist/blocks/design-canvas-inspector.js +2 -2
  4. package/dist/blocks/design-canvas.js +2 -2
  5. package/dist/blocks/discussion.js +1 -1
  6. package/dist/blocks/file-explorer.js +2 -2
  7. package/dist/blocks/settings.js +3 -3
  8. package/dist/chat-composer-editor/extensions/mention.js +1 -1
  9. package/dist/chat-composer.js +1 -1
  10. package/dist/chat-layout.js +1 -1
  11. package/dist/context.js +1 -1
  12. package/dist/dynamic-notification.js +1 -1
  13. package/dist/email/theme.js +1 -1
  14. package/dist/filter-bar/parts.js +1 -1
  15. package/dist/filter-bar.js +1 -1
  16. package/dist/inline-citation.js +1 -1
  17. package/dist/knob-contracts/emoji-picker-knobs.d.ts +1 -1
  18. package/dist/knob-contracts/emoji-picker-knobs.js +1 -0
  19. package/dist/knob-contracts/icon-picker-knobs.d.ts +4 -0
  20. package/dist/knob-contracts/icon-picker-knobs.js +9 -0
  21. package/dist/knob-contracts/markdown-knobs.d.ts +1 -1
  22. package/dist/knob-contracts/markdown-knobs.js +3 -1
  23. package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
  24. package/dist/knob-contracts/tabs-knobs.js +2 -0
  25. package/dist/lib/phone-input-format.js +1 -1
  26. package/dist/skin.d.ts +2 -0
  27. package/dist/styles/index.css +3 -1
  28. package/dist/styles/recipes/accordion.css +13 -1
  29. package/dist/styles/recipes/badge.css +1 -0
  30. package/dist/styles/recipes/button.css +20 -4
  31. package/dist/styles/recipes/code.css +0 -15
  32. package/dist/styles/recipes/collapsible.css +15 -0
  33. package/dist/styles/recipes/emoji-picker.css +84 -1
  34. package/dist/styles/recipes/field.css +15 -2
  35. package/dist/styles/recipes/icon-picker.css +101 -0
  36. package/dist/styles/recipes/markdown.css +66 -0
  37. package/dist/styles/recipes/popup-motion.css +10 -0
  38. package/dist/styles/recipes/scroll-area.css +53 -27
  39. package/dist/styles/recipes/tabs-motion.css +99 -0
  40. package/dist/styles/recipes/tabs.css +38 -10
  41. package/dist/styles/recipes/tree.css +13 -1
  42. package/dist/ui/alert-dialog.js +1 -1
  43. package/dist/ui/alert.js +1 -1
  44. package/dist/ui/autocomplete.js +1 -1
  45. package/dist/ui/breadcrumb.js +1 -1
  46. package/dist/ui/button.d.ts +6 -3
  47. package/dist/ui/button.js +10 -6
  48. package/dist/ui/card.js +1 -1
  49. package/dist/ui/code-diff.js +1 -1
  50. package/dist/ui/code.js +2 -2
  51. package/dist/ui/collapsible.js +1 -2
  52. package/dist/ui/color-picker.js +1 -1
  53. package/dist/ui/combobox.js +1 -1
  54. package/dist/ui/context-menu.js +1 -1
  55. package/dist/ui/dialog.js +1 -1
  56. package/dist/ui/drawer.js +1 -1
  57. package/dist/ui/dropdown-menu.js +1 -1
  58. package/dist/ui/emoji-icon-picker.d.ts +13 -0
  59. package/dist/ui/emoji-icon-picker.js +50 -0
  60. package/dist/ui/emoji-picker.d.ts +14 -3
  61. package/dist/ui/emoji-picker.js +194 -15
  62. package/dist/ui/empty.js +1 -1
  63. package/dist/ui/hover-card.js +1 -1
  64. package/dist/ui/icon-picker.d.ts +35 -0
  65. package/dist/ui/icon-picker.js +140 -0
  66. package/dist/ui/input-group.js +1 -1
  67. package/dist/ui/item.js +1 -1
  68. package/dist/ui/markdown-elements.js +6 -10
  69. package/dist/ui/markdown.d.ts +6 -5
  70. package/dist/ui/markdown.js +12 -4
  71. package/dist/ui/menubar.js +1 -1
  72. package/dist/ui/morphing-panel.js +1 -1
  73. package/dist/ui/navigation-menu.js +1 -1
  74. package/dist/ui/phone-input.js +2 -2
  75. package/dist/ui/popover.d.ts +3 -0
  76. package/dist/ui/popover.js +37 -2
  77. package/dist/ui/rich-tooltip.js +1 -1
  78. package/dist/ui/scroll-area.d.ts +4 -1
  79. package/dist/ui/scroll-area.js +21 -6
  80. package/dist/ui/select.js +1 -1
  81. package/dist/ui/sheet.js +1 -1
  82. package/dist/ui/sidebar-menu.js +1 -1
  83. package/dist/ui/sidebar-provider.js +2 -2
  84. package/dist/ui/sidebar-resize-rail.js +1 -1
  85. package/dist/ui/sidebar.js +1 -1
  86. package/dist/ui/tabs.d.ts +4 -0
  87. package/dist/ui/tabs.js +69 -23
  88. package/dist/ui/timeline.js +1 -1
  89. package/dist/ui/toast.js +1 -1
  90. package/dist/ui/toggle.d.ts +1 -1
  91. package/dist/ui/toggle.js +2 -1
  92. package/dist/ui/toolbar.d.ts +1 -1
  93. package/dist/ui/toolbar.js +1 -1
  94. package/dist/ui/tooltip.js +1 -1
  95. package/dist/ui/tree.js +1 -1
  96. package/dist/ui/trigger-menu.js +1 -1
  97. package/dist/user-ask.js +2 -2
  98. package/package.json +1 -1
@@ -0,0 +1,140 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { Input } from "./input.js";
4
+ import { Toolbar } from "@base-ui/react/toolbar";
5
+ import { createContext, useContext, useRef, useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { Radio } from "@base-ui/react/radio";
8
+ import { RadioGroup } from "@base-ui/react/radio-group";
9
+ //#region src/ui/icon-picker.tsx
10
+ const IconPickerContext = createContext(null);
11
+ function useIconPicker() {
12
+ const picker = useContext(IconPickerContext);
13
+ if (!picker) throw new Error("IconPicker parts must be rendered inside <IconPicker>.");
14
+ return picker;
15
+ }
16
+ function IconPicker({ items, columns = 8, value, defaultValue, onValueChange, className, style, children, ...props }) {
17
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
18
+ const [search, setSearch] = useState("");
19
+ const selectIcon = (selectedValue) => {
20
+ if (value === void 0) setUncontrolledValue(selectedValue);
21
+ onValueChange?.(selectedValue);
22
+ };
23
+ const pickerStyle = {
24
+ "--_icon-picker-columns": columns,
25
+ ...style
26
+ };
27
+ return /* @__PURE__ */ jsx(IconPickerContext.Provider, {
28
+ value: {
29
+ items,
30
+ columns,
31
+ selectedValue: value ?? uncontrolledValue,
32
+ selectIcon,
33
+ search,
34
+ setSearch
35
+ },
36
+ children: /* @__PURE__ */ jsx("div", {
37
+ "data-control-ui": "icon-picker",
38
+ "data-control-family": "icon-picker",
39
+ "data-slot": "root",
40
+ className,
41
+ style: pickerStyle,
42
+ ...props,
43
+ children
44
+ })
45
+ });
46
+ }
47
+ function IconPickerSearch({ placeholder = "Search icons…", "aria-label": ariaLabel = "Search icons", className, onChange, ...props }) {
48
+ const picker = useIconPicker();
49
+ return /* @__PURE__ */ jsx(Input, {
50
+ type: "search",
51
+ size: "sm",
52
+ placeholder,
53
+ "aria-label": ariaLabel,
54
+ autoComplete: "off",
55
+ spellCheck: false,
56
+ className: cn("mx-2 mt-2 w-[calc(100%-var(--spacing)*4)]", className),
57
+ ...props,
58
+ value: picker.search,
59
+ onChange: (event) => {
60
+ onChange?.(event);
61
+ if (!event.defaultPrevented) picker.setSearch(event.target.value);
62
+ }
63
+ });
64
+ }
65
+ function IconPickerContent({ className, empty = "No icons found.", "aria-label": ariaLabel = "Icons", ...props }) {
66
+ const picker = useIconPicker();
67
+ const buttonsRef = useRef(/* @__PURE__ */ new Map());
68
+ const normalizedSearch = picker.search.trim().toLocaleLowerCase();
69
+ const filteredItems = picker.items.filter((item) => [item.label, ...item.keywords ?? []].some((text) => text.toLocaleLowerCase().includes(normalizedSearch)));
70
+ const moveGridFocus = (event) => {
71
+ if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
72
+ const currentIndex = filteredItems.findIndex((item) => buttonsRef.current.get(item.value) === event.target);
73
+ if (currentIndex < 0) return;
74
+ event.preventDefault();
75
+ const direction = event.key === "ArrowDown" ? 1 : -1;
76
+ const nextIndex = Math.max(0, Math.min(filteredItems.length - 1, currentIndex + direction * picker.columns));
77
+ buttonsRef.current.get(filteredItems[nextIndex].value)?.focus();
78
+ };
79
+ return /* @__PURE__ */ jsx("div", {
80
+ "data-control-ui": "icon-picker",
81
+ "data-control-family": "icon-picker",
82
+ "data-slot": "content",
83
+ className,
84
+ ...props,
85
+ children: filteredItems.length === 0 ? /* @__PURE__ */ jsx("div", {
86
+ "data-control-ui": "icon-picker",
87
+ "data-control-family": "icon-picker",
88
+ "data-slot": "empty",
89
+ role: "status",
90
+ children: empty
91
+ }) : /* @__PURE__ */ jsx(Toolbar.Root, {
92
+ "data-control-ui": "icon-picker",
93
+ "data-control-family": "icon-picker",
94
+ "data-slot": "grid",
95
+ "aria-label": ariaLabel,
96
+ loopFocus: false,
97
+ onKeyDownCapture: moveGridFocus,
98
+ children: filteredItems.map((item) => /* @__PURE__ */ jsx(Toolbar.Button, {
99
+ type: "button",
100
+ "aria-label": item.label,
101
+ "aria-pressed": picker.selectedValue === item.value,
102
+ "data-control-ui": "icon-picker",
103
+ "data-control-family": "icon-picker",
104
+ "data-slot": "icon",
105
+ ref: (button) => {
106
+ if (!button) return;
107
+ buttonsRef.current.set(item.value, button);
108
+ return () => {
109
+ buttonsRef.current.delete(item.value);
110
+ };
111
+ },
112
+ onClick: () => picker.selectIcon(item.value),
113
+ children: /* @__PURE__ */ jsx("span", {
114
+ "aria-hidden": "true",
115
+ children: item.icon
116
+ })
117
+ }, item.value))
118
+ })
119
+ });
120
+ }
121
+ function IconPickerColors({ colors, "aria-label": ariaLabel = "Icon color", ...props }) {
122
+ return /* @__PURE__ */ jsx(RadioGroup, {
123
+ "data-control-ui": "icon-picker",
124
+ "data-control-family": "icon-picker",
125
+ "data-slot": "colors",
126
+ "aria-label": ariaLabel,
127
+ ...props,
128
+ children: colors.map((color) => /* @__PURE__ */ jsx(Radio.Root, {
129
+ value: color.value,
130
+ "aria-label": color.label,
131
+ "data-control-ui": "icon-picker",
132
+ "data-control-family": "icon-picker",
133
+ "data-slot": "color",
134
+ style: { color: color.color },
135
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true" })
136
+ }, color.value))
137
+ });
138
+ }
139
+ //#endregion
140
+ export { IconPicker, IconPickerColors, IconPickerContent, IconPickerSearch };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { createContext, use } from "react";
4
- import { jsx } from "react/jsx-runtime";
5
4
  import { useRender } from "@base-ui/react/use-render";
5
+ import { jsx } from "react/jsx-runtime";
6
6
  //#region src/ui/input-group.tsx
7
7
  const InputGroupSurfaceContext = createContext(false);
8
8
  function useIsInsideInputGroup() {
package/dist/ui/item.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { Separator } from "./separator.js";
4
- import { jsx } from "react/jsx-runtime";
5
4
  import { useRender } from "@base-ui/react/use-render";
5
+ import { jsx } from "react/jsx-runtime";
6
6
  //#region src/ui/item.tsx
7
7
  const itemVariants = [
8
8
  "default",
@@ -35,17 +35,13 @@ function MarkdownCode({ className, children, node: _node, ...props }) {
35
35
  if (lang === "diff" && value.includes("@@")) return /* @__PURE__ */ jsx(CodeDiff, {
36
36
  patch: value,
37
37
  lang: "diff",
38
- diffStyle: "unified",
39
- className: "my-4"
40
- });
41
- return /* @__PURE__ */ jsxs(Code, {
42
- className: "my-4",
43
- children: [/* @__PURE__ */ jsxs(CodeHeader, { children: [lang ? /* @__PURE__ */ jsx(CodeTitle, { children: lang }) : null, /* @__PURE__ */ jsx(CodeActions, { children: /* @__PURE__ */ jsx(CodeCopy, { value }) })] }), /* @__PURE__ */ jsx(CodeContent, {
44
- code: value,
45
- lang,
46
- highlight: lang ? "auto" : "none"
47
- })]
38
+ diffStyle: "unified"
48
39
  });
40
+ return /* @__PURE__ */ jsxs(Code, { children: [/* @__PURE__ */ jsxs(CodeHeader, { children: [lang ? /* @__PURE__ */ jsx(CodeTitle, { children: lang }) : null, /* @__PURE__ */ jsx(CodeActions, { children: /* @__PURE__ */ jsx(CodeCopy, { value }) })] }), /* @__PURE__ */ jsx(CodeContent, {
41
+ code: value,
42
+ lang,
43
+ highlight: lang ? "auto" : "none"
44
+ })] });
49
45
  }
50
46
  function MarkdownH1({ className, node: _node, ...props }) {
51
47
  return /* @__PURE__ */ jsx("h1", {
@@ -1,13 +1,14 @@
1
1
  import { MarkdownKnobStyle } from "../knob-contracts/markdown-knobs.js";
2
2
  import { CSSProperties, ComponentProps } from "react";
3
3
  //#region src/ui/markdown.d.ts
4
- export type MarkdownProps = Omit<ComponentProps<"div">, "children" | "style"> & {
5
- content: string;
4
+ export type MarkdownRootProps = Omit<ComponentProps<"div">, "style"> & {
6
5
  style?: CSSProperties & MarkdownKnobStyle;
7
6
  };
8
- export declare function MarkdownRoot({ className, ...props }: Omit<ComponentProps<"div">, "style"> & {
9
- style?: CSSProperties & MarkdownKnobStyle;
10
- }): import("react").JSX.Element;
7
+ export type MarkdownProps = Omit<MarkdownRootProps, "children"> & {
8
+ content: string;
9
+ };
10
+ export declare function MarkdownRoot({ className, ...props }: MarkdownRootProps): import("react").JSX.Element;
11
+ export declare function MarkdownFlow(props: MarkdownRootProps): import("react").JSX.Element;
11
12
  export declare function Markdown({ content, className, ...props }: MarkdownProps): import("react").JSX.Element;
12
13
  export type MarkdownComponentProps = ComponentProps<typeof Markdown>;
13
14
  //#endregion
@@ -13,19 +13,27 @@ function MarkdownRoot({ className, ...props }) {
13
13
  ...props
14
14
  });
15
15
  }
16
+ function MarkdownFlow(props) {
17
+ return /* @__PURE__ */ jsx("div", {
18
+ "data-control-ui": "markdown",
19
+ "data-control-family": "markdown",
20
+ "data-slot": "flow",
21
+ ...props
22
+ });
23
+ }
16
24
  function Markdown({ content, className, ...props }) {
17
25
  return /* @__PURE__ */ jsx(MarkdownRoot, {
18
26
  className,
19
27
  ...props,
20
- children: /* @__PURE__ */ jsx(Streamdown, {
28
+ children: /* @__PURE__ */ jsx(MarkdownFlow, { children: /* @__PURE__ */ jsx(Streamdown, {
21
29
  mode: "streaming",
22
30
  parseIncompleteMarkdown: true,
23
31
  controls: false,
24
32
  components: markdownComponents,
25
- className: "space-y-4 whitespace-normal [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
33
+ className: "cui-markdown-streamdown [&>[data-control-family]]:[margin-block:revert-layer]",
26
34
  children: content
27
- })
35
+ }) })
28
36
  });
29
37
  }
30
38
  //#endregion
31
- export { Markdown, MarkdownRoot };
39
+ export { Markdown, MarkdownFlow, MarkdownRoot };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { controlEffectsAttribute } from "../skin.js";
3
2
  import { cn } from "../lib/cn.js";
3
+ import { controlEffectsAttribute } from "../skin.js";
4
4
  import { useSkin } from "../skin-provider.js";
5
5
  import { popupItemStructureClasses } from "../surface-variants.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { jsx } from "react/jsx-runtime";
4
3
  import { useRender } from "@base-ui/react/use-render";
4
+ import { jsx } from "react/jsx-runtime";
5
5
  import { Collapsible } from "@base-ui/react/collapsible";
6
6
  //#region src/ui/morphing-panel.tsx
7
7
  function MorphingPanelTriggerElement({ triggerProps, open, render, className, children }) {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { controlEffectsAttribute } from "../skin.js";
3
2
  import { cn } from "../lib/cn.js";
3
+ import { controlEffectsAttribute } from "../skin.js";
4
4
  import { useSkin } from "../skin-provider.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { NavigationMenu as NavigationMenu$1 } from "@base-ui/react/navigation-menu";
@@ -3,12 +3,12 @@ import { cn } from "../lib/cn.js";
3
3
  import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
4
4
  import { InputGroup, InputGroupAddon } from "./input-group.js";
5
5
  import { Input } from "./input.js";
6
- import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "./command.js";
7
6
  import { normalizePhoneInputText, normalizePhoneInputValue } from "../lib/phone-input-format.js";
7
+ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "./command.js";
8
8
  import { useState } from "react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import flags from "react-phone-number-input/flags";
11
10
  import PhoneNumberInput, { getCountryCallingCode, parsePhoneNumber } from "react-phone-number-input/max";
11
+ import flags from "react-phone-number-input/flags";
12
12
  //#region src/ui/phone-input.tsx
13
13
  const FLAG_COMPONENTS = flags;
14
14
  const PhoneNumberInputWithRef = PhoneNumberInput;
@@ -18,6 +18,9 @@ export declare function PopoverTrigger({ className, ...props }: ComponentProps<t
18
18
  }): import("react").JSX.Element;
19
19
  export declare function PopoverAnchor(props: ComponentProps<typeof Popover$1.Trigger>): import("react").JSX.Element;
20
20
  export declare function PopoverContent({ className, children, side, align, sideOffset, collisionPadding, padding, ...props }: PopoverPopupProps): import("react").JSX.Element;
21
+ export declare function PopoverViewport({ children, ref, ...props }: ComponentProps<"div"> & {
22
+ style?: CSSProperties & PopupKnobStyle;
23
+ }): import("react").JSX.Element;
21
24
  export declare function PopoverHeader({ className, ...props }: ComponentProps<"div"> & {
22
25
  style?: CSSProperties & PopupKnobStyle;
23
26
  }): import("react").JSX.Element;
@@ -1,7 +1,8 @@
1
1
  "use client";
2
- import { controlEffectsAttribute } from "../skin.js";
3
2
  import { cn } from "../lib/cn.js";
3
+ import { controlEffectsAttribute } from "../skin.js";
4
4
  import { useSkin } from "../skin-provider.js";
5
+ import { useImperativeHandle, useLayoutEffect, useRef } from "react";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  import { Popover as Popover$1 } from "@base-ui/react/popover";
7
8
  //#region src/ui/popover.tsx
@@ -45,6 +46,40 @@ function PopoverContent({ className, children, side = "bottom", align = "center"
45
46
  })
46
47
  }) });
47
48
  }
49
+ function PopoverViewport({ children, ref, ...props }) {
50
+ const viewportRef = useRef(null);
51
+ const contentRef = useRef(null);
52
+ useImperativeHandle(ref, () => {
53
+ if (!viewportRef.current) throw new Error("PopoverViewport is not mounted.");
54
+ return viewportRef.current;
55
+ }, []);
56
+ useLayoutEffect(() => {
57
+ const viewport = viewportRef.current;
58
+ const content = contentRef.current;
59
+ if (!viewport || !content) return;
60
+ const updateHeight = () => viewport.style.setProperty("--_popover-viewport-height", `${content.offsetHeight}px`);
61
+ updateHeight();
62
+ const observer = new ResizeObserver(updateHeight);
63
+ observer.observe(content);
64
+ return () => observer.disconnect();
65
+ }, []);
66
+ return /* @__PURE__ */ jsx("div", {
67
+ "data-control-ui": "popover",
68
+ "data-control-family": "popup",
69
+ "data-popup-kind": "popover",
70
+ "data-slot": "viewport",
71
+ ...props,
72
+ ref: viewportRef,
73
+ children: /* @__PURE__ */ jsx("div", {
74
+ "data-control-ui": "popover",
75
+ "data-control-family": "popup",
76
+ "data-popup-kind": "popover",
77
+ "data-slot": "viewport-content",
78
+ ref: contentRef,
79
+ children
80
+ })
81
+ });
82
+ }
48
83
  function PopoverHeader({ className, ...props }) {
49
84
  return /* @__PURE__ */ jsx("div", {
50
85
  "data-control-ui": "popover",
@@ -86,4 +121,4 @@ function PopoverClose({ className, ...props }) {
86
121
  });
87
122
  }
88
123
  //#endregion
89
- export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, popoverContentPaddings };
124
+ export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, PopoverViewport, popoverContentPaddings };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { controlEffectsAttribute } from "../skin.js";
3
2
  import { cn } from "../lib/cn.js";
3
+ import { controlEffectsAttribute } from "../skin.js";
4
4
  import { useSkin } from "../skin-provider.js";
5
5
  import { prefersReducedMotion } from "../lib/motion.js";
6
6
  import { PopupArrowShape } from "../popup-parts.js";
@@ -5,6 +5,8 @@ import { ScrollArea as ScrollArea$1 } from "@base-ui/react/scroll-area";
5
5
  //#region src/ui/scroll-area.d.ts
6
6
  export declare const scrollAreaScrollbarVisibilities: readonly ["scroll", "hover", "always"];
7
7
  export type ScrollAreaScrollbarVisibility = (typeof scrollAreaScrollbarVisibilities)[number];
8
+ export declare const scrollAreaScrollbarGutters: readonly ["auto", "stable"];
9
+ export type ScrollAreaScrollbarGutter = (typeof scrollAreaScrollbarGutters)[number];
8
10
  export type ScrollAreaLockAxis = "x" | "y" | "both";
9
11
  export type ScrollAreaViewportProps = Omit<ComponentProps<"div">, "children" | "className" | "ref"> & {
10
12
  "data-control-ui"?: string;
@@ -25,6 +27,7 @@ export type ScrollAreaProps = Omit<ComponentProps<"div">, "style"> & {
25
27
  blurProps?: Pick<ProgressiveBlurProps, "style">;
26
28
  lockAxis?: ScrollAreaLockAxis;
27
29
  scrollbarVisibility?: ScrollAreaScrollbarVisibility;
30
+ scrollbarGutter?: ScrollAreaScrollbarGutter;
28
31
  };
29
- export declare function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask, blur, blurProps, lockAxis, scrollbarVisibility, children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }: ScrollAreaProps): import("react").JSX.Element;
32
+ export declare function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask, blur, blurProps, lockAxis, scrollbarVisibility, scrollbarGutter, children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }: ScrollAreaProps): import("react").JSX.Element;
30
33
  //#endregion
@@ -10,14 +10,20 @@ const scrollAreaScrollbarVisibilities = [
10
10
  "hover",
11
11
  "always"
12
12
  ];
13
- function Scrollbar({ orientation, visibility, thumbStyle }) {
13
+ const scrollAreaScrollbarGutters = ["auto", "stable"];
14
+ function Scrollbar({ orientation, visibility, gutter, thumbStyle }) {
14
15
  return /* @__PURE__ */ jsx(ScrollArea$1.Scrollbar, {
15
16
  orientation,
17
+ keepMounted: gutter === "stable",
16
18
  "data-control-ui": "scroll-area",
17
19
  "data-control-family": "scroll-area",
18
20
  "data-slot": "scrollbar",
19
21
  "data-visibility": visibility,
20
22
  className: cn("m-px flex touch-none select-none", orientation === "vertical" ? "justify-center" : "flex-col"),
23
+ style: gutter === "stable" ? {
24
+ position: "relative",
25
+ inset: "auto"
26
+ } : void 0,
21
27
  children: /* @__PURE__ */ jsx(ScrollArea$1.Thumb, {
22
28
  "data-control-ui": "scroll-area",
23
29
  "data-control-family": "scroll-area",
@@ -68,9 +74,11 @@ function EdgeBlurs({ blurProps, lockX, lockY }) {
68
74
  })
69
75
  ] });
70
76
  }
71
- function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask = true, blur, blurProps, lockAxis, scrollbarVisibility = "hover", children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }) {
77
+ function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask = true, blur, blurProps, lockAxis, scrollbarVisibility, scrollbarGutter, children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }) {
72
78
  const skin = useSkin();
73
79
  const resolvedBlur = blur ?? skin.scrollAreaBlur ?? false;
80
+ const resolvedVisibility = scrollbarVisibility ?? skin.scrollAreaScrollbarVisibility ?? "hover";
81
+ const resolvedGutter = scrollbarGutter ?? skin.scrollAreaScrollbarGutter ?? "auto";
74
82
  const lockX = lockAxis === "x" || lockAxis === "both";
75
83
  const lockY = lockAxis === "y" || lockAxis === "both";
76
84
  const { style: viewportPropsStyle, ...resolvedViewportProps } = viewportProps ?? {};
@@ -85,6 +93,7 @@ function ScrollArea({ className, viewportClassName, contentClassName, viewportPr
85
93
  "data-mask": mask || void 0,
86
94
  "data-blur": resolvedBlur || void 0,
87
95
  "data-lock-axis": lockAxis,
96
+ "data-scrollbar-gutter": resolvedGutter,
88
97
  className: cn("relative overflow-hidden", className),
89
98
  style,
90
99
  children: [
@@ -114,22 +123,28 @@ function ScrollArea({ className, viewportClassName, contentClassName, viewportPr
114
123
  }),
115
124
  !lockY && /* @__PURE__ */ jsx(Scrollbar, {
116
125
  orientation: "vertical",
117
- visibility: scrollbarVisibility,
126
+ visibility: resolvedVisibility,
127
+ gutter: resolvedGutter,
118
128
  thumbStyle
119
129
  }),
120
130
  !lockX && /* @__PURE__ */ jsx(Scrollbar, {
121
131
  orientation: "horizontal",
122
- visibility: scrollbarVisibility,
132
+ visibility: resolvedVisibility,
133
+ gutter: resolvedGutter,
123
134
  thumbStyle
124
135
  }),
125
136
  !lockX && !lockY && /* @__PURE__ */ jsx(ScrollArea$1.Corner, {
126
137
  "data-control-ui": "scroll-area",
127
138
  "data-control-family": "scroll-area",
128
139
  "data-slot": "corner",
129
- style: cornerStyle
140
+ style: resolvedGutter === "stable" ? {
141
+ ...cornerStyle,
142
+ position: "relative",
143
+ inset: "auto"
144
+ } : cornerStyle
130
145
  })
131
146
  ]
132
147
  });
133
148
  }
134
149
  //#endregion
135
- export { ScrollArea, scrollAreaScrollbarVisibilities };
150
+ export { ScrollArea, scrollAreaScrollbarGutters, scrollAreaScrollbarVisibilities };
package/dist/ui/select.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { controlEffectsAttribute } from "../skin.js";
3
2
  import { cn } from "../lib/cn.js";
3
+ import { controlEffectsAttribute } from "../skin.js";
4
4
  import { useSkin } from "../skin-provider.js";
5
5
  import { Button } from "./button.js";
6
6
  import { ScrollArea } from "./scroll-area.js";
package/dist/ui/sheet.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { controlEffectsAttribute } from "../skin.js";
3
2
  import { cn } from "../lib/cn.js";
3
+ import { controlEffectsAttribute } from "../skin.js";
4
4
  import { useSkin } from "../skin-provider.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Dialog } from "@base-ui/react/dialog";
@@ -5,8 +5,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
5
5
  import { SidebarSurfaceContext, useSidebar } from "./sidebar-provider.js";
6
6
  import { TrackHighlight } from "../extensions/track-highlight.js";
7
7
  import { createContext, useContext, useRef, useState } from "react";
8
- import { jsx, jsxs } from "react/jsx-runtime";
9
8
  import { useRender } from "@base-ui/react/use-render";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/ui/sidebar-menu.tsx
11
11
  const sidebarMenuButtonVariants = ["default", "outline"];
12
12
  const sidebarMenuButtonSizes = [
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { useSkin } from "../skin-provider.js";
4
- import { TooltipProvider } from "./tooltip.js";
5
4
  import { SIDEBAR_COOKIE_NAME } from "../control-props.js";
5
+ import { TooltipProvider } from "./tooltip.js";
6
6
  import { useIsMobile } from "../hooks/use-mobile.js";
7
7
  import { createContext, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
8
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
8
  import { useRender } from "@base-ui/react/use-render";
9
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/ui/sidebar-provider.tsx
11
11
  const SIDEBAR_COOKIE_MAX_AGE = 604800;
12
12
  const SIDEBAR_WIDTH = "16rem";
@@ -2,8 +2,8 @@
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { useSidebar, useSidebarElements, useSidebarSurface } from "./sidebar-provider.js";
4
4
  import { useEffect, useLayoutEffect, useRef, useState } from "react";
5
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
5
  import { useRender } from "@base-ui/react/use-render";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/ui/sidebar-resize-rail.tsx
8
8
  const DRAG_THRESHOLD_PX = 5;
9
9
  const KEYBOARD_STEP_PX = 10;
@@ -8,9 +8,9 @@ import { SidebarProvider, SidebarSurfaceContext, useSidebar, useSidebarElements,
8
8
  import { SidebarResizeRail } from "./sidebar-resize-rail.js";
9
9
  import { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, sidebarMenuButtonSizes, sidebarMenuButtonVariants } from "./sidebar-menu.js";
10
10
  import { useState } from "react";
11
+ import { useRender } from "@base-ui/react/use-render";
11
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
13
  import { PanelLeftIcon } from "lucide-react";
13
- import { useRender } from "@base-ui/react/use-render";
14
14
  import { createPortal } from "react-dom";
15
15
  //#region src/ui/sidebar.tsx
16
16
  const SIDEBAR_WIDTH_MOBILE = "18rem";
package/dist/ui/tabs.d.ts CHANGED
@@ -32,6 +32,10 @@ export type TabsPanelProps = Omit<ComponentProps<"div">, "style"> & {
32
32
  value: string;
33
33
  keepMounted?: boolean;
34
34
  };
35
+ export type TabsSurfaceProps = Omit<ComponentProps<"div">, "style"> & {
36
+ style?: CSSProperties & TabsKnobStyle;
37
+ };
38
+ export declare function TabsSurface({ className, ...props }: TabsSurfaceProps): import("react").JSX.Element;
35
39
  export declare function Tabs<TValue extends string = string>({ className, onValueChange, children, ...props }: TabsProps<TValue>): import("react").JSX.Element;
36
40
  export declare function TabsList({ size, variant, className, children, style, ...props }: TabsListProps): import("react").JSX.Element;
37
41
  export declare function TabsTab({ className, ...props }: TabsTabProps): import("react").JSX.Element;