@underverse-ui/underverse 1.0.34 → 1.0.36

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,34 +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
55
- enabled
56
- theme="os-theme-underverse"
57
- autoHide="leave"
58
- />
59
- {/* app */}
60
- </>
53
+ <OverlayScrollbarProvider theme="os-theme-underverse" autoHide="leave">
54
+ <ScrollArea className="h-56" useOverlayScrollbar />
55
+ <DataTable columns={columns} data={rows} useOverlayScrollbar />
56
+ </OverlayScrollbarProvider>
61
57
  );
62
58
  }
63
59
  ```
64
60
 
65
61
  Behavior:
66
62
 
67
- - Provider initializes globally by default on common scroll selectors (`.overflow-*`, `textarea`) and `[data-os-scrollbar]`.
68
- - Provider can run globally via custom `selector` (for example: `.overflow-auto, .overflow-y-auto, .overflow-x-auto, [data-os-scrollbar]`).
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]`.
69
66
  - Use `data-os-ignore` on a node to opt out.
70
67
 
68
+ Useful APIs:
69
+
70
+ - `OverlayScrollArea` (dedicated heavy-scroll wrapper)
71
+ - `useOverlayScrollbarTarget(ref, options)` for custom component internals
72
+
71
73
  ## i18n Notes
72
74
 
73
75
  - Components work without `next-intl` using fallback translations.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to `@underverse-ui/underverse` are documented in this file.
4
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
+
5
27
  ## [1.0.32] - 2026-02-24
6
28
 
7
29
  ### Changed
package/README.md CHANGED
@@ -137,34 +137,36 @@ 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.
141
- See release notes in `CHANGELOG.md` for migration details by version.
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.
142
142
 
143
143
  ```tsx
144
144
  import "overlayscrollbars/overlayscrollbars.css";
145
- import { OverlayScrollbarProvider } from "@underverse-ui/underverse";
145
+ import { OverlayScrollbarProvider, ScrollArea, DataTable } from "@underverse-ui/underverse";
146
146
 
147
147
  function App() {
148
148
  return (
149
- <>
150
- <OverlayScrollbarProvider
151
- enabled
152
- theme="os-theme-underverse"
153
- autoHide="leave"
154
- 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
155
158
  />
156
- {/* your app */}
157
- </>
159
+ </OverlayScrollbarProvider>
158
160
  );
159
161
  }
160
162
  ```
161
163
 
162
164
  Provider behavior:
163
165
 
164
- - Initializes globally by default on common scroll containers (`.overflow-*`, `textarea`) and `[data-os-scrollbar]`.
165
- - Does **not** initialize on `document.body` / `document.documentElement`.
166
- - Skips portal/dialog trees (`[data-radix-portal]`, `[role="dialog"]`, `[aria-modal="true"]`, `[data-sonner-toaster]`).
167
- - 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`.
168
170
 
169
171
  Provider props:
170
172
 
@@ -175,23 +177,30 @@ Provider props:
175
177
  - `autoHideDelay?: number`
176
178
  - `dragScroll?: boolean`
177
179
  - `clickScroll?: boolean`
178
- - `selector?: string` default: `.overflow-auto, .overflow-y-auto, .overflow-x-auto, .overflow-scroll, .overflow-y-scroll, .overflow-x-scroll, textarea, [data-os-scrollbar]`
179
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)
180
182
 
181
- Custom selector mode example:
183
+ Component-level enable flags:
182
184
 
183
- ```tsx
184
- <OverlayScrollbarProvider
185
- selector=".overflow-auto, .overflow-y-auto, .overflow-x-auto, [data-os-scrollbar]"
186
- />
187
- ```
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
188
198
 
189
- Migration notes:
199
+ When not to use:
190
200
 
191
- - Remove any local DOM-scanning scrollbar provider in your app.
192
- - Keep a single `OverlayScrollbarProvider` mounted once at app root.
193
- - You no longer need to add `data-os-scrollbar` to every Underverse component manually.
194
- - Use `data-os-scrollbar` only for custom scroll nodes that are not covered by your selector.
201
+ - Normal form fields
202
+ - Short modal/dialog content
203
+ - Full page root scrolling
195
204
 
196
205
  ### Standalone React (Vite, CRA, etc.)
197
206
 
@@ -253,7 +262,7 @@ function App() {
253
262
 
254
263
  ### Navigation & Structure
255
264
 
256
- - `Breadcrumb`, `Tabs` (includes `SimpleTabs`, `PillTabs`, `VerticalTabs`), `DropdownMenu`, `Pagination`, `Section`, `ScrollArea`
265
+ - `Breadcrumb`, `Tabs` (includes `SimpleTabs`, `PillTabs`, `VerticalTabs`), `DropdownMenu`, `Pagination`, `Section`, `ScrollArea`, `OverlayScrollArea`
257
266
 
258
267
  ### Data Display
259
268
 
@@ -25,13 +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
30
  },
31
31
  {
32
- "id": "overlay-scrollbar-global-selector",
33
- "title": "Enable global selector mode",
34
- "code": "import \"overlayscrollbars/overlayscrollbars.css\";\nimport { OverlayScrollbarProvider } from \"@underverse-ui/underverse\";\n\nexport function App(){\n return <><OverlayScrollbarProvider selector=\".overflow-auto, .overflow-y-auto, .overflow-x-auto, [data-os-scrollbar]\" />{/* app */}</>;\n}\n"
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"
35
35
  },
36
36
  {
37
37
  "id": "api-discovery-order",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "package": "@underverse-ui/underverse",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
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",