@underverse-ui/underverse 1.0.33 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -40,30 +40,36 @@ export function Example() {
40
40
  }
41
41
  ```
42
42
 
43
- ## Overlay Scrollbars (recommended)
43
+ ## Overlay Scrollbars (opt-in)
44
44
 
45
- Use the exported provider to enable overlay scrollbars (no layout width loss):
45
+ Underverse uses component-level overlay scrollbars. No global selector scan and no app-wide MutationObserver.
46
46
 
47
47
  ```tsx
48
48
  import "overlayscrollbars/overlayscrollbars.css";
49
- import { OverlayScrollbarProvider } from "@underverse-ui/underverse";
49
+ import { OverlayScrollbarProvider, ScrollArea, DataTable } from "@underverse-ui/underverse";
50
50
 
51
51
  export function App() {
52
52
  return (
53
- <>
54
- <OverlayScrollbarProvider enabled theme="os-theme-underverse" autoHide="leave" />
55
- {/* app */}
56
- </>
53
+ <OverlayScrollbarProvider theme="os-theme-underverse" autoHide="leave">
54
+ <ScrollArea className="h-56" useOverlayScrollbar />
55
+ <DataTable columns={columns} data={rows} useOverlayScrollbar />
56
+ </OverlayScrollbarProvider>
57
57
  );
58
58
  }
59
59
  ```
60
60
 
61
61
  Behavior:
62
62
 
63
- - Provider initializes only on `[data-os-scrollbar]`.
64
- - Underverse components already mark their internal scroll containers.
63
+ - Provider is config-only (context defaults), not an auto-mount global scanner.
64
+ - Enable per component via `useOverlayScrollbar`.
65
+ - Hard skip: `html`, `body`, `[data-radix-portal]`, `[role="dialog"]`, `[aria-modal="true"]`, `[data-sonner-toaster]`.
65
66
  - Use `data-os-ignore` on a node to opt out.
66
67
 
68
+ Useful APIs:
69
+
70
+ - `OverlayScrollArea` (dedicated heavy-scroll wrapper)
71
+ - `useOverlayScrollbarTarget(ref, options)` for custom component internals
72
+
67
73
  ## i18n Notes
68
74
 
69
75
  - Components work without `next-intl` using fallback translations.
package/CHANGELOG.md ADDED
@@ -0,0 +1,79 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@underverse-ui/underverse` are documented in this file.
4
+
5
+ ## [1.0.34] - 2026-02-24
6
+
7
+ ### Changed
8
+
9
+ - Switched OverlayScrollbars architecture to strict component-level opt-in.
10
+ - `OverlayScrollbarProvider` is now config-only (no global DOM scan, no global MutationObserver).
11
+ - Added dedicated `OverlayScrollArea` wrapper for heavy scroll zones.
12
+ - Added `useOverlayScrollbar?: boolean` (default `false`) on:
13
+ - `ScrollArea`
14
+ - `Table`
15
+ - `DataTable`
16
+ - `Combobox`
17
+ - `MultiCombobox`
18
+ - `CategoryTreeSelect`
19
+ - Hard skip safety kept for:
20
+ - `html`, `body`
21
+ - `[data-radix-portal]`
22
+ - `[role=\"dialog\"]`
23
+ - `[aria-modal=\"true\"]`
24
+ - `[data-sonner-toaster]`
25
+ - Removed global selector behavior from docs/recipes and marked `selector` prop deprecated (ignored).
26
+
27
+ ## [1.0.32] - 2026-02-24
28
+
29
+ ### Changed
30
+
31
+ - Standardized OverlayScrollbars initialization to explicit marker targeting only:
32
+ - Provider now initializes only on `[data-os-scrollbar]`.
33
+ - Removed generic overflow class scanning (`.overflow-*`).
34
+ - Hardened provider behavior for production:
35
+ - No initialization on `document.body` / `document.documentElement`.
36
+ - Excludes portal / modal / toast trees:
37
+ - `[data-radix-portal]`
38
+ - `[role="dialog"]`
39
+ - `[aria-modal="true"]`
40
+ - `[data-sonner-toaster]`
41
+ - Supports node-level opt-out with `data-os-ignore`.
42
+ - Added provider configuration props:
43
+ - `enabled` (default `true`)
44
+ - `theme` (default `os-theme-underverse`)
45
+ - `visibility`
46
+ - `autoHide`
47
+ - `autoHideDelay`
48
+ - `dragScroll`
49
+ - `clickScroll`
50
+ - `selector` (default `.overflow-auto, .overflow-y-auto, .overflow-x-auto, .overflow-scroll, .overflow-y-scroll, .overflow-x-scroll, textarea, [data-os-scrollbar]`)
51
+ - `exclude` (default `html, body, [data-os-ignore], [data-radix-portal], [role='dialog'], [aria-modal='true'], [data-sonner-toaster]`)
52
+ - Exported provider prop type:
53
+ - `OverlayScrollbarProviderProps`
54
+
55
+ ### Updated Components
56
+
57
+ - Provider now covers common scrollable surfaces by default via global selector, so Underverse components do not require per-component manual marker wiring.
58
+
59
+ ### Internal
60
+
61
+ - `Popover` now sets `role="dialog"` only when `modal=true`, avoiding accidental exclusion for non-modal popovers.
62
+ - Moved to default global selector behavior, so apps no longer need to add `data-os-scrollbar` manually to each Underverse component.
63
+
64
+ ### Testing
65
+
66
+ - Added controller-level tests for:
67
+ - selector initialization
68
+ - exclude behavior
69
+ - dynamic add/remove cleanup
70
+ - portal safety with wide selectors
71
+ - destroy cleanup (memory leak prevention)
72
+
73
+ ### Migration
74
+
75
+ - Mount a single `OverlayScrollbarProvider` from the package at app root.
76
+ - Remove app-local DOM-scanning scrollbar providers.
77
+ - Keep `overlayscrollbars/overlayscrollbars.css` imported globally.
78
+ - Default is already global selector mode. Override `selector` only if you need custom scope.
79
+ - For app-specific opt-out nodes, use `data-os-ignore`.
package/README.md CHANGED
@@ -137,39 +137,70 @@ import { Form, FormField, FormItem, FormLabel, FormMessage } from "@underverse-u
137
137
 
138
138
  ### Overlay Scrollbars (Optional, Recommended)
139
139
 
140
- Use `OverlayScrollbarProvider` to get overlay scrollbars (no layout space taken) across your app and Underverse components.
140
+ Underverse now uses **opt-in, component-level** OverlayScrollbars.
141
+ There is no global DOM scanning, no default global mount, and no app-wide MutationObserver.
141
142
 
142
143
  ```tsx
143
144
  import "overlayscrollbars/overlayscrollbars.css";
144
- import { OverlayScrollbarProvider } from "@underverse-ui/underverse";
145
+ import { OverlayScrollbarProvider, ScrollArea, DataTable } from "@underverse-ui/underverse";
145
146
 
146
147
  function App() {
147
148
  return (
148
- <>
149
- <OverlayScrollbarProvider
150
- enabled
151
- theme="os-theme-underverse"
152
- autoHide="leave"
153
- autoHideDelay={600}
149
+ <OverlayScrollbarProvider theme="os-theme-underverse" autoHide="leave">
150
+ <ScrollArea className="h-56" useOverlayScrollbar>
151
+ {/* long content */}
152
+ </ScrollArea>
153
+
154
+ <DataTable
155
+ columns={columns}
156
+ data={rows}
157
+ useOverlayScrollbar
154
158
  />
155
- {/* your app */}
156
- </>
159
+ </OverlayScrollbarProvider>
157
160
  );
158
161
  }
159
162
  ```
160
163
 
161
164
  Provider behavior:
162
165
 
163
- - Initializes **only** on elements marked with `data-os-scrollbar`.
164
- - Does **not** initialize on `document.body` / `document.documentElement`.
165
- - Skips portal/dialog trees (`[data-radix-portal]`, `[role="dialog"]`, `[aria-modal="true"]`, `[data-sonner-toaster]`).
166
- - Per-node opt-out is available via `data-os-ignore`.
166
+ - Provider is **configuration only** (theme/options context).
167
+ - Scrollbars initialize only on components explicitly enabled via `useOverlayScrollbar`.
168
+ - Hard skip targets: `html`, `body`, `[data-radix-portal]`, `[role="dialog"]`, `[aria-modal="true"]`, `[data-sonner-toaster]`.
169
+ - Per-node opt-out remains available via `data-os-ignore`.
167
170
 
168
- Migration notes:
171
+ Provider props:
169
172
 
170
- - Remove any local DOM-scanning scrollbar provider in your app.
171
- - Keep a single `OverlayScrollbarProvider` mounted once at app root.
172
- - If you have custom app-level scroll containers outside Underverse components, add `data-os-scrollbar` to those nodes.
173
+ - `enabled?: boolean`
174
+ - `theme?: string`
175
+ - `visibility?: "visible" | "hidden" | "auto"`
176
+ - `autoHide?: "never" | "scroll" | "leave" | "move"`
177
+ - `autoHideDelay?: number`
178
+ - `dragScroll?: boolean`
179
+ - `clickScroll?: boolean`
180
+ - `exclude?: string` default: `html, body, [data-os-ignore], [data-radix-portal], [role='dialog'], [aria-modal='true'], [data-sonner-toaster]`
181
+ - `selector?: string` (deprecated, ignored; kept for backward compatibility)
182
+
183
+ Component-level enable flags:
184
+
185
+ - `ScrollArea`: `useOverlayScrollbar?: boolean` (default `false`)
186
+ - `Table`: `useOverlayScrollbar?: boolean` (default `false`)
187
+ - `DataTable`: `useOverlayScrollbar?: boolean` (default `false`)
188
+ - `Combobox`: `useOverlayScrollbar?: boolean` (default `false`)
189
+ - `MultiCombobox`: `useOverlayScrollbar?: boolean` (default `false`)
190
+ - `CategoryTreeSelect`: `useOverlayScrollbar?: boolean` (default `false`)
191
+ - `Textarea`: `useOverlayScrollbar?: boolean` (default `false`)
192
+ - `OverlayScrollArea`: dedicated wrapper for heavy scroll zones (`enabled` default `true`)
193
+
194
+ When to use:
195
+
196
+ - Long virtualized/table/list panels
197
+ - Fixed-height navigation panels and log viewers
198
+
199
+ When not to use:
200
+
201
+ - Normal form fields
202
+ - Short modal/dialog content
203
+ - Full page root scrolling
173
204
 
174
205
  ### Standalone React (Vite, CRA, etc.)
175
206
 
@@ -231,7 +262,7 @@ function App() {
231
262
 
232
263
  ### Navigation & Structure
233
264
 
234
- - `Breadcrumb`, `Tabs` (includes `SimpleTabs`, `PillTabs`, `VerticalTabs`), `DropdownMenu`, `Pagination`, `Section`, `ScrollArea`
265
+ - `Breadcrumb`, `Tabs` (includes `SimpleTabs`, `PillTabs`, `VerticalTabs`), `DropdownMenu`, `Pagination`, `Section`, `ScrollArea`, `OverlayScrollArea`
235
266
 
236
267
  ### Data Display
237
268
 
@@ -25,8 +25,13 @@
25
25
  },
26
26
  {
27
27
  "id": "overlay-scrollbar-provider",
28
- "title": "Enable overlay scrollbars",
29
- "code": "import \"overlayscrollbars/overlayscrollbars.css\";\nimport { OverlayScrollbarProvider } from \"@underverse-ui/underverse\";\n\nexport function App(){\n return <><OverlayScrollbarProvider enabled theme=\"os-theme-underverse\" autoHide=\"leave\" />{/* app */}</>;\n}\n"
28
+ "title": "Enable overlay scrollbars (opt-in)",
29
+ "code": "import \"overlayscrollbars/overlayscrollbars.css\";\nimport { OverlayScrollbarProvider, ScrollArea } from \"@underverse-ui/underverse\";\n\nexport function App(){\n return (\n <OverlayScrollbarProvider theme=\"os-theme-underverse\" autoHide=\"leave\">\n <ScrollArea className=\"h-56\" useOverlayScrollbar>{/* content */}</ScrollArea>\n </OverlayScrollbarProvider>\n );\n}\n"
30
+ },
31
+ {
32
+ "id": "overlay-scrollbar-custom-component",
33
+ "title": "Custom component with overlay scrollbar hook",
34
+ "code": "import { useRef } from \"react\";\nimport { useOverlayScrollbarTarget } from \"@underverse-ui/underverse\";\n\nexport function LogPanel(){\n const ref = useRef<HTMLDivElement>(null);\n useOverlayScrollbarTarget(ref, { enabled: true });\n\n return <div ref={ref} className=\"h-64 overflow-y-auto\">...</div>;\n}\n"
30
35
  },
31
36
  {
32
37
  "id": "api-discovery-order",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "package": "@underverse-ui/underverse",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "sourceEntry": "src/index.ts",
5
- "totalExports": 207,
5
+ "totalExports": 211,
6
6
  "exports": [
7
7
  {
8
8
  "name": "*",
@@ -854,6 +854,20 @@
854
854
  "local": false,
855
855
  "aliasOf": "default"
856
856
  },
857
+ {
858
+ "name": "OverlayScrollArea",
859
+ "kind": "value",
860
+ "source": "../../../components/ui/OverlayScrollArea",
861
+ "reexport": true,
862
+ "local": false
863
+ },
864
+ {
865
+ "name": "OverlayScrollAreaProps",
866
+ "kind": "type",
867
+ "source": "../../../components/ui/OverlayScrollArea",
868
+ "reexport": true,
869
+ "local": false
870
+ },
857
871
  {
858
872
  "name": "OverlayScrollbarProvider",
859
873
  "kind": "value",
@@ -1408,6 +1422,20 @@
1408
1422
  "reexport": true,
1409
1423
  "local": false
1410
1424
  },
1425
+ {
1426
+ "name": "useOverlayScrollbarTarget",
1427
+ "kind": "value",
1428
+ "source": "../../../components/ui/OverlayScrollbarProvider",
1429
+ "reexport": true,
1430
+ "local": false
1431
+ },
1432
+ {
1433
+ "name": "UseOverlayScrollbarTargetOptions",
1434
+ "kind": "type",
1435
+ "source": "../../../components/ui/OverlayScrollbarProvider",
1436
+ "reexport": true,
1437
+ "local": false
1438
+ },
1411
1439
  {
1412
1440
  "name": "useShadCNAnimations",
1413
1441
  "kind": "value",