@gridui/overlay 1.1.2 → 1.2.2

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @gridui/overlay
2
2
 
3
- Core family. Public API: `OverlayOpen`, `RetainedLayer`, `RetainedLayerProps`, `useOverlayState`, `overlaySurfaceStyles`, `overlayBackdropStyles`.
3
+ Core family. Public API: `interactionLayerProps`, `useInteractionOutline`, `InteractionOutlineOptions`, `useScrollbars`, `ScrollbarsOptions`, `scrollbarInteractionRef`, `OverlayOpen`, `RetainedLayer`, `RetainedLayerProps`, `useOverlayState`, `overlaySurfaceStyles`, `overlayBackdropStyles`.
4
4
 
5
5
  Import components from `@gridui/overlay` and load `@gridui/overlay/styles.css` after Theme.
6
6
  Load styles for any composed dependency used by this family. Applications own routes, labels, state persistence, and branding.
@@ -20,3 +20,62 @@ item-aligned Select. Open/closed and Tooltip's instant/delayed open states are
20
20
  supported. Families keep dimensions, stacking, positioning, portals, focus,
21
21
  and dismissal. Drawer retains its directional panel motion and uses only the
22
22
  shared backdrop. Theme continues to own motion tokens and keyframes.
23
+
24
+ ## Interaction outlines
25
+
26
+ `useInteractionOutline({ ref, selector })` returns a composed React ref for a
27
+ scrolling viewport. Forward the caller's optional ref and select the native
28
+ interactive descendants owned by that viewport. Theme styles own the indicator
29
+ paint; the hook does not require an additional stylesheet.
30
+ The hook mirrors each active Theme outline into an aria-hidden, input-transparent
31
+ document plane using its resolved color, width, offset, and radius.
32
+ Spread `interactionLayerProps` on a custom popup or dialog surface to define its
33
+ interaction boundary. Built-in menu, selection, popover, and dialog surfaces
34
+ already do this. Viewports share one isolated plane per boundary, or the page
35
+ plane when there is no surface. The plane follows its surface's stacking level
36
+ and source order; descendant z-index values remain local. Nested DOM surfaces
37
+ retain their parent interaction boundary. Focus paints above hover within the
38
+ same plane, while newer menus and dialogs can cover the underlying outlines.
39
+ Inert and aria-hidden background viewports suppress both native and mirrored indicators.
40
+ Nested viewports own their own targets. It preserves native focus and selection,
41
+ tracks scroll, resize, theme, DOM changes and surface motion, and removes
42
+ invisible or unmounted targets. Clipping bounds limit offscreen paint while
43
+ allowing the outline's full outward extent. The layer never receives input.
44
+
45
+ ## Scrollbars
46
+
47
+ `useScrollbars({ ref })` returns a composed React ref for one native scrolling
48
+ viewport. Bind each owned viewport explicitly, including independently scrolling
49
+ dialog sections. `useInteractionOutline` remains independent; compose its ref
50
+ with this hook when a viewport needs both behaviors. Theme owns the paint, so
51
+ no additional stylesheet is required for this hook.
52
+
53
+ The hook keeps native content scrolling and renders square, proportional thumbs
54
+ in an aria-hidden local layer. The transparent 10px track overlays the viewport
55
+ edge. Its 4px thumb becomes 6px on hover or drag without changing content geometry.
56
+ Track clicks, wheel input, and captured pointer dragging update the real viewport;
57
+ keyboard focus remains on the real content. RTL horizontal scrolling and reversed
58
+ vertical flex layouts retain their native coordinate behavior.
59
+
60
+ The layer lives inside the viewport and follows its native scrolling, clipping,
61
+ palette, transforms, and stacking context. It remains part of hover-opened panels.
62
+ There is no document-level scrollbar portal, ancestor z-index reconstruction,
63
+ descendant discovery, or permanent document input listener. Resize observation
64
+ covers every direct content element; captured load events also update asynchronous
65
+ media. Native refs, content DOM, and focus semantics remain intact.
66
+
67
+ Textarea uses a local sibling layer in its parent because it cannot render child
68
+ elements. The adapter measures the existing containing block without changing the
69
+ parent's positioning, adding a wrapper, or adjusting padding and margins. It
70
+ observes the parent and its direct children, preserves control-level palette
71
+ overrides, and mirrors the native control's inert state. Native form reset refreshes
72
+ the indicator after the default action, including canceled resets and live form
73
+ reassociation. Coarse pointers pan the native viewport; forced colors use square
74
+ system-colored thumbs.
75
+
76
+ `scrollbarInteractionRef` binds Theme's hover and dragging state to a scrollbar
77
+ element without owning scroll position, sizing, or pointer capture. It is a stable
78
+ React 19 callback ref with cleanup, also usable as an imperative binding that
79
+ returns a disposer. Native viewports and Sidebar's Radix scrollbar share this
80
+ binding. Ref composition uses Radix's cleanup-aware implementation. Both layout
81
+ hooks ignore mutations inside their decorative layers and observe real content.
package/dist/index.d.ts CHANGED
@@ -7,5 +7,11 @@
7
7
  export type { RetainedLayerProps } from "./retained-layer/retained-layer";
8
8
  export { OverlayOpen } from "./retained-layer/retained-layer";
9
9
  export { RetainedLayer } from "./retained-layer/retained-layer";
10
+ export { interactionLayerProps } from "./shared/interaction-layer";
11
+ export { scrollbarInteractionRef } from "./shared/scrollbar-interaction-ref";
10
12
  export { overlayBackdropStyles, overlaySurfaceStyles } from "./shared/style";
13
+ export type { InteractionOutlineOptions } from "./shared/use-interaction-outline";
14
+ export { useInteractionOutline } from "./shared/use-interaction-outline";
11
15
  export { useOverlayState } from "./shared/use-overlay-state";
16
+ export type { ScrollbarsOptions } from "./shared/use-scrollbars";
17
+ export { useScrollbars } from "./shared/use-scrollbars";
package/dist/index.js CHANGED
@@ -14,6 +14,120 @@ var RetainedLayer = (props) => {
14
14
  );
15
15
  };
16
16
 
17
+ // src/shared/interaction-layer.ts
18
+ var interactionLayerProps = { "data-gridui-interaction-layer": "" };
19
+ var selector = "[data-gridui-interaction-layer]";
20
+ var planes = /* @__PURE__ */ new WeakMap();
21
+ var planeElements = /* @__PURE__ */ new WeakMap();
22
+ var interactionLayerOwner = (viewport) => {
23
+ return viewport.closest(selector) ?? viewport.ownerDocument.body;
24
+ };
25
+ var refreshOutlinePlane = (plane) => {
26
+ const { owner, element, parent } = plane;
27
+ const document = owner.ownerDocument;
28
+ const style = document.defaultView.getComputedStyle(owner);
29
+ element.style.zIndex = owner === document.body || style.zIndex === "auto" ? style.getPropertyValue("--gridui-z-interaction") || "3" : style.zIndex;
30
+ if (parent) {
31
+ refreshOutlinePlane(parent);
32
+ const next = Array.from(parent.element.children).find((child) => {
33
+ const sibling = planeElements.get(child);
34
+ return sibling && sibling !== plane && Boolean(owner.compareDocumentPosition(sibling.owner) & Node.DOCUMENT_POSITION_FOLLOWING);
35
+ });
36
+ parent.element.insertBefore(element, next ?? null);
37
+ } else if (owner === document.body) {
38
+ if (!element.isConnected) {
39
+ document.body.append(element);
40
+ }
41
+ } else {
42
+ let anchor = owner;
43
+ while (anchor.parentElement && anchor.parentElement !== document.body) {
44
+ anchor = anchor.parentElement;
45
+ }
46
+ let next = anchor.nextElementSibling;
47
+ while (next) {
48
+ const sibling = planeElements.get(next);
49
+ if (!sibling || sibling === plane || !(sibling.owner.compareDocumentPosition(owner) & Node.DOCUMENT_POSITION_FOLLOWING)) {
50
+ break;
51
+ }
52
+ next = next.nextElementSibling;
53
+ }
54
+ document.body.insertBefore(element, next);
55
+ }
56
+ };
57
+ var acquireOutlinePlane = (owner) => {
58
+ const existing = planes.get(owner);
59
+ if (existing) {
60
+ existing.references++;
61
+ return existing;
62
+ }
63
+ const parentOwner = owner.parentElement?.closest(selector);
64
+ const parent = parentOwner ? acquireOutlinePlane(parentOwner) : void 0;
65
+ const element = owner.ownerDocument.createElement("div");
66
+ element.className = "gridui-interaction-outline-layer";
67
+ element.setAttribute("aria-hidden", "true");
68
+ const plane = {
69
+ owner,
70
+ element,
71
+ parent,
72
+ references: 1
73
+ };
74
+ planes.set(owner, plane);
75
+ planeElements.set(element, plane);
76
+ refreshOutlinePlane(plane);
77
+ return plane;
78
+ };
79
+ var releaseOutlinePlane = (plane) => {
80
+ if (--plane.references) {
81
+ return;
82
+ }
83
+ plane.element.remove();
84
+ planes.delete(plane.owner);
85
+ planeElements.delete(plane.element);
86
+ if (plane.parent) {
87
+ releaseOutlinePlane(plane.parent);
88
+ }
89
+ };
90
+
91
+ // src/shared/scrollbar-interaction-ref.ts
92
+ var scrollbarInteractionRef = (element) => {
93
+ if (!element) {
94
+ return;
95
+ }
96
+ const hover = (event) => {
97
+ const box = element.getBoundingClientRect();
98
+ element.toggleAttribute("data-gridui-hovered", event.clientX >= box.left && event.clientX < box.right && event.clientY >= box.top && event.clientY < box.bottom);
99
+ };
100
+ const leave = () => {
101
+ element.removeAttribute("data-gridui-hovered");
102
+ };
103
+ const down = (event) => {
104
+ if (event.button === 0) {
105
+ element.setAttribute("data-gridui-dragging", "");
106
+ }
107
+ };
108
+ const finish = () => {
109
+ element.removeAttribute("data-gridui-dragging");
110
+ };
111
+ element.addEventListener("pointerenter", hover);
112
+ element.addEventListener("pointermove", hover);
113
+ element.addEventListener("pointerleave", leave);
114
+ element.addEventListener("pointerdown", down);
115
+ element.addEventListener("pointerup", finish);
116
+ element.addEventListener("pointercancel", finish);
117
+ element.addEventListener("lostpointercapture", finish);
118
+ return () => {
119
+ element.removeEventListener("pointerenter", hover);
120
+ element.removeEventListener("pointermove", hover);
121
+ element.removeEventListener("pointerleave", leave);
122
+ element.removeEventListener("pointerdown", down);
123
+ element.removeEventListener("pointerup", finish);
124
+ element.removeEventListener("pointercancel", finish);
125
+ element.removeEventListener("lostpointercapture", finish);
126
+ leave();
127
+ finish();
128
+ };
129
+ };
130
+
17
131
  // src/shared/style.ts
18
132
  import { cva } from "class-variance-authority";
19
133
  var overlaySurfaceStyles = cva("gridui-overlay-surface gridui-u-border gridui-u-border-solid gridui-u-border-border gridui-u-bg-background gridui-u-text-foreground", {
@@ -36,13 +150,252 @@ var overlayBackdropStyles = cva("gridui-overlay-backdrop", {
36
150
  defaultVariants: { pace: "normal" }
37
151
  });
38
152
 
153
+ // src/shared/content-mutation.ts
154
+ var decorativeSelector = ".gridui-scrollbar-layer, .gridui-interaction-outline-layer";
155
+ var isDecorative = (node) => {
156
+ const element = node.nodeType === 1 ? node : node.parentElement;
157
+ return !!element?.closest(decorativeSelector);
158
+ };
159
+ var hasContentMutation = (records) => {
160
+ return records.some((record) => {
161
+ return !isDecorative(record.target) && (record.type !== "childList" || [
162
+ ...record.addedNodes,
163
+ ...record.removedNodes
164
+ ].some((node) => {
165
+ return !isDecorative(node);
166
+ }));
167
+ });
168
+ };
169
+
170
+ // src/shared/use-interaction-outline.ts
171
+ import { useComposedRefs } from "@radix-ui/react-compose-refs";
172
+ import { useLayoutEffect, useState } from "react";
173
+ var useInteractionOutline = (options) => {
174
+ const { ref, selector: selector2 } = options;
175
+ const [
176
+ viewport,
177
+ setViewport
178
+ ] = useState(null);
179
+ useLayoutEffect(() => {
180
+ if (!viewport) {
181
+ return;
182
+ }
183
+ const document = viewport.ownerDocument;
184
+ const window = document.defaultView;
185
+ let plane;
186
+ viewport.setAttribute("data-gridui-outline-viewport", "");
187
+ const rings = /* @__PURE__ */ new Map();
188
+ let frame = 0;
189
+ let disposed = false;
190
+ const schedule = () => {
191
+ if (!disposed && !frame) {
192
+ frame = window.requestAnimationFrame(sync);
193
+ }
194
+ };
195
+ const resize = new ResizeObserver(schedule);
196
+ const sync = () => {
197
+ frame = 0;
198
+ for (const element of rings.keys()) {
199
+ element.removeAttribute("data-gridui-outline-rendered");
200
+ }
201
+ const owner = interactionLayerOwner(viewport);
202
+ if (plane && plane.owner !== owner) {
203
+ const previous = plane;
204
+ plane = acquireOutlinePlane(owner);
205
+ plane.element.append(...rings.values());
206
+ releaseOutlinePlane(previous);
207
+ }
208
+ if (plane) {
209
+ refreshOutlinePlane(plane);
210
+ }
211
+ const inactive = viewport.closest('[inert], [aria-hidden="true"]');
212
+ viewport.toggleAttribute("data-gridui-outline-inactive", !!inactive);
213
+ const candidates = inactive ? [] : Array.from(viewport.querySelectorAll(selector2)).filter((element) => {
214
+ return element.closest("[data-gridui-outline-viewport]") === viewport && element.matches(":hover, :active, :focus-visible, [data-highlighted]");
215
+ });
216
+ const current = /* @__PURE__ */ new Set();
217
+ let moving = false;
218
+ for (const element of candidates) {
219
+ const box = element.getBoundingClientRect();
220
+ const style = window.getComputedStyle(element);
221
+ if (!element.getClientRects().length || style.visibility !== "visible" || style.outlineStyle === "none" || parseFloat(style.outlineWidth) <= 0) {
222
+ continue;
223
+ }
224
+ let left = 0;
225
+ let top = 0;
226
+ let right = document.documentElement.clientWidth;
227
+ let bottom = document.documentElement.clientHeight;
228
+ let opacity = Number(style.opacity);
229
+ let clipped = false;
230
+ for (let ancestor = element.parentElement; ancestor; ancestor = ancestor.parentElement) {
231
+ const appearance = window.getComputedStyle(ancestor);
232
+ const bounds = ancestor.getBoundingClientRect();
233
+ opacity *= Number(appearance.opacity);
234
+ moving ||= ancestor.getAnimations().some((animation) => {
235
+ return animation.playState === "running";
236
+ });
237
+ if (appearance.overflowX !== "visible") {
238
+ clipped = true;
239
+ left = Math.max(left, bounds.left + ancestor.clientLeft);
240
+ right = Math.min(right, bounds.left + ancestor.clientLeft + ancestor.clientWidth);
241
+ }
242
+ if (appearance.overflowY !== "visible") {
243
+ clipped = true;
244
+ top = Math.max(top, bounds.top + ancestor.clientTop);
245
+ bottom = Math.min(bottom, bounds.top + ancestor.clientTop + ancestor.clientHeight);
246
+ }
247
+ }
248
+ if (!clipped || opacity === 0 || box.right <= left || box.left >= right || box.bottom <= top || box.top >= bottom) {
249
+ continue;
250
+ }
251
+ current.add(element);
252
+ let ring = rings.get(element);
253
+ if (!ring) {
254
+ ring = document.createElement("div");
255
+ ring.className = "gridui-interaction-outline";
256
+ plane ??= acquireOutlinePlane(owner);
257
+ plane.element.append(ring);
258
+ rings.set(element, ring);
259
+ resize.observe(element);
260
+ }
261
+ const extent = Math.max(0, parseFloat(style.outlineWidth) + parseFloat(style.outlineOffset));
262
+ Object.assign(ring.style, {
263
+ left: `${box.left}px`,
264
+ top: `${box.top}px`,
265
+ width: `${box.width}px`,
266
+ height: `${box.height}px`,
267
+ outline: style.outline,
268
+ outlineOffset: style.outlineOffset,
269
+ borderRadius: style.borderRadius,
270
+ opacity: String(opacity),
271
+ zIndex: element.matches(":focus-visible") ? "3" : "2",
272
+ clipPath: `inset(${Math.max(0, top - box.top) - extent}px ${Math.max(0, box.right - right) - extent}px ${Math.max(0, box.bottom - bottom) - extent}px ${Math.max(0, left - box.left) - extent}px)`
273
+ });
274
+ element.setAttribute("data-gridui-outline-rendered", "");
275
+ }
276
+ for (const [
277
+ element,
278
+ ring
279
+ ] of rings) {
280
+ if (!current.has(element)) {
281
+ element.removeAttribute("data-gridui-outline-rendered");
282
+ ring.remove();
283
+ rings.delete(element);
284
+ resize.unobserve(element);
285
+ }
286
+ }
287
+ if (!rings.size && plane) {
288
+ releaseOutlinePlane(plane);
289
+ plane = void 0;
290
+ }
291
+ if (moving) {
292
+ schedule();
293
+ }
294
+ };
295
+ const mutation = new MutationObserver((records) => {
296
+ if (hasContentMutation(records)) {
297
+ schedule();
298
+ }
299
+ });
300
+ mutation.observe(viewport, {
301
+ subtree: true,
302
+ childList: true,
303
+ characterData: true,
304
+ attributes: true,
305
+ attributeFilter: [
306
+ "class",
307
+ "style",
308
+ "hidden",
309
+ "disabled",
310
+ "aria-disabled",
311
+ "aria-readonly",
312
+ "readonly",
313
+ "data-disabled",
314
+ "data-readonly",
315
+ "data-state",
316
+ "data-highlighted",
317
+ "aria-selected"
318
+ ]
319
+ });
320
+ const ancestors = new MutationObserver(schedule);
321
+ for (let ancestor = viewport; ancestor; ancestor = ancestor.parentElement) {
322
+ ancestors.observe(ancestor, {
323
+ attributes: true,
324
+ attributeFilter: [
325
+ "class",
326
+ "style",
327
+ "hidden",
328
+ "dir",
329
+ "data-theme",
330
+ "data-state",
331
+ "data-gridui-interaction-layer",
332
+ "aria-hidden",
333
+ "inert"
334
+ ]
335
+ });
336
+ }
337
+ const events = [
338
+ "scroll",
339
+ "pointerover",
340
+ "pointerout",
341
+ "pointerdown",
342
+ "pointerup",
343
+ "pointercancel",
344
+ "focusin",
345
+ "focusout",
346
+ "keydown",
347
+ "keyup",
348
+ "animationstart",
349
+ "transitionrun"
350
+ ];
351
+ for (const event of events) {
352
+ document.addEventListener(event, schedule, {
353
+ capture: true,
354
+ passive: true
355
+ });
356
+ }
357
+ const scheme = window.matchMedia("(prefers-color-scheme: dark)");
358
+ scheme.addEventListener("change", schedule);
359
+ window.addEventListener("resize", schedule);
360
+ resize.observe(viewport);
361
+ sync();
362
+ return () => {
363
+ disposed = true;
364
+ window.cancelAnimationFrame(frame);
365
+ resize.disconnect();
366
+ mutation.disconnect();
367
+ ancestors.disconnect();
368
+ for (const event of events) {
369
+ document.removeEventListener(event, schedule, true);
370
+ }
371
+ scheme.removeEventListener("change", schedule);
372
+ window.removeEventListener("resize", schedule);
373
+ viewport.removeAttribute("data-gridui-outline-viewport");
374
+ viewport.removeAttribute("data-gridui-outline-inactive");
375
+ for (const element of rings.keys()) {
376
+ element.removeAttribute("data-gridui-outline-rendered");
377
+ }
378
+ for (const ring of rings.values()) {
379
+ ring.remove();
380
+ }
381
+ if (plane) {
382
+ releaseOutlinePlane(plane);
383
+ }
384
+ };
385
+ }, [
386
+ viewport,
387
+ selector2
388
+ ]);
389
+ return useComposedRefs(setViewport, ref);
390
+ };
391
+
39
392
  // src/shared/use-overlay-state.ts
40
- import { useState } from "react";
393
+ import { useState as useState2 } from "react";
41
394
  var useOverlayState = (options) => {
42
395
  const [
43
396
  localOpen,
44
397
  setLocalOpen
45
- ] = useState(options.defaultOpen ?? false);
398
+ ] = useState2(options.defaultOpen ?? false);
46
399
  return {
47
400
  open: options.open ?? localOpen,
48
401
  onOpenChange: (open) => {
@@ -53,11 +406,345 @@ var useOverlayState = (options) => {
53
406
  }
54
407
  };
55
408
  };
409
+
410
+ // src/shared/textarea-scrollbar.ts
411
+ var isTextarea = (element) => {
412
+ return element.tagName === "TEXTAREA";
413
+ };
414
+ var syncTextareaScrollbar = (viewport, layer, style) => {
415
+ const window = viewport.ownerDocument.defaultView;
416
+ layer.style.position = style.position === "fixed" ? "fixed" : "absolute";
417
+ const parent = layer.offsetParent;
418
+ const parentBox = parent?.getBoundingClientRect();
419
+ const parentScaleX = parent?.offsetWidth ? parentBox.width / parent.offsetWidth : 1;
420
+ const parentScaleY = parent?.offsetHeight ? parentBox.height / parent.offsetHeight : 1;
421
+ const box = viewport.getBoundingClientRect();
422
+ const controlScaleX = viewport.offsetWidth ? box.width / viewport.offsetWidth : 1;
423
+ const controlScaleY = viewport.offsetHeight ? box.height / viewport.offsetHeight : 1;
424
+ const current = layer.getBoundingClientRect();
425
+ const left = (parseFloat(layer.style.left) || 0) + (box.left + viewport.clientLeft * controlScaleX - current.left) / parentScaleX;
426
+ const top = (parseFloat(layer.style.top) || 0) + (box.top + viewport.clientTop * controlScaleY - current.top) / parentScaleY;
427
+ Object.assign(layer.style, {
428
+ left: `${left}px`,
429
+ top: `${top}px`,
430
+ transform: `scale(${controlScaleX / parentScaleX}, ${controlScaleY / parentScaleY})`,
431
+ transformOrigin: "0 0",
432
+ zIndex: style.zIndex === "auto" ? "var(--gridui-z-interaction)" : style.zIndex,
433
+ opacity: style.opacity,
434
+ visibility: style.visibility,
435
+ colorScheme: style.colorScheme
436
+ });
437
+ layer.inert = viewport.inert;
438
+ const inherited = window.getComputedStyle(viewport.parentElement);
439
+ for (const [
440
+ token,
441
+ fallback
442
+ ] of [
443
+ [
444
+ "--gridui-scrollbar-thumb",
445
+ "--gridui-muted"
446
+ ],
447
+ [
448
+ "--gridui-scrollbar-thumb-active",
449
+ "--gridui-foreground"
450
+ ],
451
+ [
452
+ "--gridui-scrollbar-track",
453
+ "--gridui-scrollbar-track"
454
+ ]
455
+ ]) {
456
+ const value = style.getPropertyValue(token) || style.getPropertyValue(fallback);
457
+ const parentValue = inherited.getPropertyValue(token) || inherited.getPropertyValue(fallback);
458
+ if (value && value !== parentValue) {
459
+ layer.style.setProperty(token, value);
460
+ } else {
461
+ layer.style.removeProperty(token);
462
+ }
463
+ }
464
+ };
465
+
466
+ // src/shared/use-scrollbars.ts
467
+ import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
468
+ import { useId, useLayoutEffect as useLayoutEffect2, useRef, useState as useState3 } from "react";
469
+ var useScrollbars = (options = {}) => {
470
+ const { ref } = options;
471
+ const owner = useId();
472
+ const [
473
+ viewport,
474
+ setViewport
475
+ ] = useState3(null);
476
+ const refresh = useRef(void 0);
477
+ useLayoutEffect2(() => {
478
+ if (!viewport) {
479
+ return;
480
+ }
481
+ const document = viewport.ownerDocument;
482
+ const window = document.defaultView;
483
+ const textarea = isTextarea(viewport) ? viewport : null;
484
+ const host = textarea ? viewport.parentElement : viewport;
485
+ const layer = document.createElement(viewport.matches("ol, ul") ? "li" : "span");
486
+ layer.className = "gridui-scrollbar-layer";
487
+ layer.setAttribute("aria-hidden", "true");
488
+ host.append(layer);
489
+ viewport.setAttribute("data-gridui-scrollbar-owner", owner);
490
+ viewport.setAttribute("data-gridui-scrollbar-id", owner);
491
+ const bars = /* @__PURE__ */ new Map();
492
+ const contents = /* @__PURE__ */ new Set();
493
+ let frame = 0;
494
+ let disposed = false;
495
+ let rtl = false;
496
+ let reverse = false;
497
+ const schedule = () => {
498
+ if (!disposed && !frame) {
499
+ frame = window.requestAnimationFrame(sync);
500
+ }
501
+ };
502
+ const extent = (vertical) => {
503
+ return vertical ? viewport.scrollHeight - viewport.clientHeight : viewport.scrollWidth - viewport.clientWidth;
504
+ };
505
+ const position = (vertical) => {
506
+ const value = vertical ? viewport.scrollTop : viewport.scrollLeft;
507
+ return (vertical ? reverse : rtl) ? extent(vertical) + value : value;
508
+ };
509
+ const write = (vertical, value) => {
510
+ if (viewport.inert) {
511
+ return;
512
+ }
513
+ const next = Math.max(0, Math.min(extent(vertical), value));
514
+ const native = (vertical ? reverse : rtl) ? next - extent(vertical) : next;
515
+ if (vertical) {
516
+ viewport.scrollTop = native;
517
+ } else {
518
+ viewport.scrollLeft = native;
519
+ }
520
+ sync();
521
+ };
522
+ const create = (vertical) => {
523
+ const track = document.createElement("span");
524
+ const thumb = document.createElement("span");
525
+ track.className = "gridui-scrollbar";
526
+ thumb.className = "gridui-scrollbar-thumb";
527
+ track.dataset.orientation = vertical ? "vertical" : "horizontal";
528
+ track.setAttribute("data-gridui-scrollbar-for", owner);
529
+ track.append(thumb);
530
+ layer.append(track);
531
+ const unbind = scrollbarInteractionRef(track);
532
+ const length = () => {
533
+ return vertical ? track.clientHeight : track.clientWidth;
534
+ };
535
+ const thumbLength = () => {
536
+ return vertical ? thumb.clientHeight : thumb.clientWidth;
537
+ };
538
+ const coordinate = (event) => {
539
+ const box = track.getBoundingClientRect();
540
+ const scale = (vertical ? box.height : box.width) / length();
541
+ return (vertical ? event.clientY - box.top : event.clientX - box.left) / scale;
542
+ };
543
+ let drag;
544
+ const finish = () => {
545
+ drag = void 0;
546
+ };
547
+ track.addEventListener("pointerdown", (event) => {
548
+ if (event.button !== 0) {
549
+ return;
550
+ }
551
+ event.preventDefault();
552
+ const max = extent(vertical);
553
+ const offset = max ? position(vertical) / max * (length() - thumbLength()) : 0;
554
+ const cursor = coordinate(event);
555
+ drag = {
556
+ pointerId: event.pointerId,
557
+ grab: event.target === thumb ? cursor - offset : thumbLength() / 2
558
+ };
559
+ track.setPointerCapture(event.pointerId);
560
+ write(vertical, (cursor - drag.grab) / Math.max(1, length() - thumbLength()) * max);
561
+ });
562
+ track.addEventListener("pointermove", (event) => {
563
+ if (drag?.pointerId === event.pointerId) {
564
+ write(vertical, (coordinate(event) - drag.grab) / Math.max(1, length() - thumbLength()) * extent(vertical));
565
+ }
566
+ });
567
+ track.addEventListener("pointerup", finish);
568
+ track.addEventListener("pointercancel", finish);
569
+ track.addEventListener("lostpointercapture", finish);
570
+ track.addEventListener("click", (event) => {
571
+ event.preventDefault();
572
+ event.stopPropagation();
573
+ });
574
+ track.addEventListener("wheel", (event) => {
575
+ if (event.ctrlKey) {
576
+ return;
577
+ }
578
+ const style = window.getComputedStyle(viewport);
579
+ let unit = 1;
580
+ if (event.deltaMode === 1) {
581
+ unit = parseFloat(style.lineHeight) || 16;
582
+ } else if (event.deltaMode === 2) {
583
+ unit = vertical ? viewport.clientHeight : viewport.clientWidth;
584
+ }
585
+ const next = Math.max(0, Math.min(extent(vertical), position(vertical) + (vertical ? event.deltaY : event.deltaX || event.deltaY) * unit));
586
+ if (next !== position(vertical)) {
587
+ event.preventDefault();
588
+ write(vertical, next);
589
+ }
590
+ }, { passive: false });
591
+ return {
592
+ track,
593
+ thumb,
594
+ dispose() {
595
+ finish();
596
+ unbind();
597
+ track.remove();
598
+ }
599
+ };
600
+ };
601
+ const sync = () => {
602
+ if (disposed) {
603
+ return;
604
+ }
605
+ window.cancelAnimationFrame(frame);
606
+ frame = 0;
607
+ const style = window.getComputedStyle(viewport);
608
+ rtl = style.direction === "rtl";
609
+ reverse = style.flexDirection === "column-reverse";
610
+ const visible = viewport.clientWidth > 0 && viewport.clientHeight > 0;
611
+ const vertical = visible && /^(auto|scroll)$/.test(style.overflowY) && extent(true) > 1;
612
+ const horizontal = visible && /^(auto|scroll)$/.test(style.overflowX) && extent(false) > 1;
613
+ if (textarea) {
614
+ syncTextareaScrollbar(textarea, layer, style);
615
+ } else {
616
+ layer.style.transform = `translate(${viewport.scrollLeft}px, ${viewport.scrollTop}px)`;
617
+ }
618
+ for (const axis of [
619
+ true,
620
+ false
621
+ ]) {
622
+ if (!(axis ? vertical : horizontal)) {
623
+ const bar2 = bars.get(axis);
624
+ if (bar2) {
625
+ bar2.dispose();
626
+ bars.delete(axis);
627
+ }
628
+ continue;
629
+ }
630
+ let bar = bars.get(axis);
631
+ if (!bar) {
632
+ bar = create(axis);
633
+ bars.set(axis, bar);
634
+ }
635
+ const size = 10;
636
+ const width = axis ? size : viewport.clientWidth - (vertical ? size : 0);
637
+ const height = axis ? viewport.clientHeight - (horizontal ? size : 0) : size;
638
+ const length = axis ? height : width;
639
+ const view = axis ? viewport.clientHeight : viewport.clientWidth;
640
+ const thumb = Math.min(length, Math.max(24, length * view / (extent(axis) + view)));
641
+ Object.assign(bar.track.style, {
642
+ left: `${axis ? viewport.clientWidth - size : 0}px`,
643
+ top: `${axis ? 0 : viewport.clientHeight - size}px`,
644
+ width: `${width}px`,
645
+ height: `${height}px`
646
+ });
647
+ Object.assign(bar.thumb.style, axis ? {
648
+ height: `${thumb}px`,
649
+ transform: `translateY(${position(axis) / extent(axis) * (length - thumb)}px)`
650
+ } : {
651
+ width: `${thumb}px`,
652
+ transform: `translateX(${position(axis) / extent(axis) * (length - thumb)}px)`
653
+ });
654
+ }
655
+ };
656
+ const resize = new ResizeObserver(schedule);
657
+ const observeContents = () => {
658
+ const current = new Set(Array.from(host.children).filter((element) => {
659
+ return !element.classList.contains("gridui-scrollbar-layer");
660
+ }));
661
+ for (const content of contents) {
662
+ if (!current.has(content)) {
663
+ resize.unobserve(content);
664
+ contents.delete(content);
665
+ }
666
+ }
667
+ for (const content of current) {
668
+ if (!contents.has(content)) {
669
+ resize.observe(content);
670
+ contents.add(content);
671
+ }
672
+ }
673
+ };
674
+ const mutation = new MutationObserver((records) => {
675
+ if (hasContentMutation(records)) {
676
+ observeContents();
677
+ schedule();
678
+ }
679
+ });
680
+ mutation.observe(host, {
681
+ subtree: true,
682
+ childList: true,
683
+ characterData: true,
684
+ attributes: true,
685
+ attributeFilter: [
686
+ "class",
687
+ "style",
688
+ "hidden",
689
+ "inert",
690
+ "aria-hidden",
691
+ "dir",
692
+ "data-state"
693
+ ]
694
+ });
695
+ viewport.addEventListener("scroll", schedule, { passive: true });
696
+ viewport.addEventListener("input", schedule);
697
+ viewport.addEventListener("load", schedule, true);
698
+ resize.observe(viewport);
699
+ const reset = (event) => {
700
+ if (event.target === textarea?.form) {
701
+ schedule();
702
+ }
703
+ };
704
+ if (textarea) {
705
+ resize.observe(host);
706
+ document.addEventListener("reset", reset, true);
707
+ }
708
+ observeContents();
709
+ refresh.current = schedule;
710
+ sync();
711
+ return () => {
712
+ disposed = true;
713
+ refresh.current = void 0;
714
+ window.cancelAnimationFrame(frame);
715
+ for (const bar of bars.values()) {
716
+ bar.dispose();
717
+ }
718
+ resize.disconnect();
719
+ mutation.disconnect();
720
+ viewport.removeEventListener("scroll", schedule);
721
+ viewport.removeEventListener("input", schedule);
722
+ viewport.removeEventListener("load", schedule, true);
723
+ viewport.removeAttribute("data-gridui-scrollbar-owner");
724
+ viewport.removeAttribute("data-gridui-scrollbar-id");
725
+ if (textarea) {
726
+ document.removeEventListener("reset", reset, true);
727
+ }
728
+ layer.remove();
729
+ };
730
+ }, [
731
+ viewport,
732
+ owner
733
+ ]);
734
+ useLayoutEffect2(() => {
735
+ refresh.current?.();
736
+ });
737
+ return useComposedRefs2(setViewport, ref);
738
+ };
56
739
  export {
57
740
  OverlayOpen,
58
741
  RetainedLayer,
742
+ interactionLayerProps,
59
743
  overlayBackdropStyles,
60
744
  overlaySurfaceStyles,
61
- useOverlayState
745
+ scrollbarInteractionRef,
746
+ useInteractionOutline,
747
+ useOverlayState,
748
+ useScrollbars
62
749
  };
63
750
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/retained-layer/retained-layer.tsx", "../src/shared/style.ts", "../src/shared/use-overlay-state.ts"],
4
- "sourcesContent": ["/**\n * @author WMXPY\n * @package Overlay\n * @namespace RetainedLayer\n * @description Retained Layer\n */\n\nimport { Activity, createContext, type FC, type ReactNode, useContext } from \"react\";\n\nexport const OverlayOpen = createContext(false);\n\nexport type RetainedLayerProps = {\n readonly children: ReactNode;\n};\n\nexport const RetainedLayer: FC<RetainedLayerProps> = (props: RetainedLayerProps) => {\n const { children } = props;\n const open = useContext(OverlayOpen);\n return (<Activity\n mode={!open ? \"hidden\" : \"visible\"}\n >\n {children}\n </Activity>);\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Style\n */\n\nimport { cva } from \"class-variance-authority\";\n\nexport const overlaySurfaceStyles = cva(\"gridui-overlay-surface gridui-u-border gridui-u-border-solid gridui-u-border-border gridui-u-bg-background gridui-u-text-foreground\", {\n variants: {\n kind: {\n popup: \"gridui-overlay-floating gridui-u-rounded-control\",\n tooltip: \"gridui-overlay-tooltip gridui-u-rounded-control\",\n dialog: \"gridui-overlay-dialog\",\n },\n },\n defaultVariants: { kind: \"popup\" },\n});\n\nexport const overlayBackdropStyles = cva(\"gridui-overlay-backdrop\", {\n variants: {\n pace: {\n normal: null,\n deliberate: \"gridui-overlay-backdrop-deliberate\",\n },\n },\n defaultVariants: { pace: \"normal\" },\n});\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Use Overlay State\n */\n\nimport { useState } from \"react\";\n\ntype OverlayStateOptions = {\n readonly open?: boolean | undefined;\n readonly defaultOpen?: boolean | undefined;\n readonly onOpenChange?: ((open: boolean) => void) | undefined;\n};\n\nexport const useOverlayState = (options: OverlayStateOptions) => {\n const [\n localOpen,\n setLocalOpen,\n ] = useState(options.defaultOpen ?? false);\n return {\n open: options.open ?? localOpen,\n onOpenChange: (open: boolean): void => {\n if (options.open === undefined) {\n setLocalOpen(open);\n }\n options.onOpenChange?.(open);\n },\n };\n};\n"],
5
- "mappings": ";AAOA,SAAS,UAAU,eAAwC,kBAAkB;AAWjE;AATL,IAAM,cAAc,cAAc,KAAK;AAMvC,IAAM,gBAAwC,CAAC,UAA8B;AAChF,QAAM,EAAE,SAAS,IAAI;AACrB,QAAM,OAAO,WAAW,WAAW;AACnC,SAAQ;AAAA,IAAC;AAAA;AAAA,MACL,MAAM,CAAC,OAAO,WAAW;AAAA,MAExB;AAAA;AAAA,EACL;AACJ;;;AChBA,SAAS,WAAW;AAEb,IAAM,uBAAuB,IAAI,uIAAuI;AAAA,EAC3K,UAAU;AAAA,IACN,MAAM;AAAA,MACF,OAAO;AAAA,MACP,SAAS;AAAA,MACT,QAAQ;AAAA,IACZ;AAAA,EACJ;AAAA,EACA,iBAAiB,EAAE,MAAM,QAAQ;AACrC,CAAC;AAEM,IAAM,wBAAwB,IAAI,2BAA2B;AAAA,EAChE,UAAU;AAAA,IACN,MAAM;AAAA,MACF,QAAQ;AAAA,MACR,YAAY;AAAA,IAChB;AAAA,EACJ;AAAA,EACA,iBAAiB,EAAE,MAAM,SAAS;AACtC,CAAC;;;ACrBD,SAAS,gBAAgB;AAQlB,IAAM,kBAAkB,CAAC,YAAiC;AAC7D,QAAM;AAAA,IACF;AAAA,IACA;AAAA,EACJ,IAAI,SAAS,QAAQ,eAAe,KAAK;AACzC,SAAO;AAAA,IACH,MAAM,QAAQ,QAAQ;AAAA,IACtB,cAAc,CAAC,SAAwB;AACnC,UAAI,QAAQ,SAAS,QAAW;AAC5B,qBAAa,IAAI;AAAA,MACrB;AACA,cAAQ,eAAe,IAAI;AAAA,IAC/B;AAAA,EACJ;AACJ;",
6
- "names": []
3
+ "sources": ["../src/retained-layer/retained-layer.tsx", "../src/shared/interaction-layer.ts", "../src/shared/scrollbar-interaction-ref.ts", "../src/shared/style.ts", "../src/shared/content-mutation.ts", "../src/shared/use-interaction-outline.ts", "../src/shared/use-overlay-state.ts", "../src/shared/textarea-scrollbar.ts", "../src/shared/use-scrollbars.ts"],
4
+ "sourcesContent": ["/**\n * @author WMXPY\n * @package Overlay\n * @namespace RetainedLayer\n * @description Retained Layer\n */\n\nimport { Activity, createContext, type FC, type ReactNode, useContext } from \"react\";\n\nexport const OverlayOpen = createContext(false);\n\nexport type RetainedLayerProps = {\n readonly children: ReactNode;\n};\n\nexport const RetainedLayer: FC<RetainedLayerProps> = (props: RetainedLayerProps) => {\n const { children } = props;\n const open = useContext(OverlayOpen);\n return (<Activity\n mode={!open ? \"hidden\" : \"visible\"}\n >\n {children}\n </Activity>);\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Interaction Layer\n */\n\n/** Marks a popup or dialog surface as an independent interaction paint boundary. */\nexport const interactionLayerProps = { \"data-gridui-interaction-layer\": \"\" } as const;\n\nconst selector = \"[data-gridui-interaction-layer]\";\nconst planes = new WeakMap<HTMLElement, OutlinePlane>();\nconst planeElements = new WeakMap<Element, OutlinePlane>();\n\ntype OutlinePlane = {\n readonly owner: HTMLElement;\n readonly element: HTMLDivElement;\n readonly parent: OutlinePlane | undefined;\n references: number;\n};\n\nexport const interactionLayerOwner = (viewport: HTMLElement): HTMLElement => {\n return viewport.closest<HTMLElement>(selector) ?? viewport.ownerDocument.body;\n};\n\nexport const refreshOutlinePlane = (plane: OutlinePlane): void => {\n const { owner, element, parent } = plane;\n const document = owner.ownerDocument;\n const style = document.defaultView!.getComputedStyle(owner);\n element.style.zIndex = owner === document.body || style.zIndex === \"auto\"\n ? style.getPropertyValue(\"--gridui-z-interaction\") || \"3\"\n : style.zIndex;\n if (parent) {\n refreshOutlinePlane(parent);\n const next = Array.from(parent.element.children).find(child => {\n const sibling = planeElements.get(child);\n return sibling && sibling !== plane && Boolean(owner.compareDocumentPosition(sibling.owner) & Node.DOCUMENT_POSITION_FOLLOWING);\n });\n parent.element.insertBefore(element, next ?? null);\n } else if (owner === document.body) {\n if (!element.isConnected) {\n document.body.append(element);\n }\n } else {\n // Follow the source surface in paint order, including multiple surfaces in one portal container.\n let anchor = owner;\n while (anchor.parentElement && anchor.parentElement !== document.body) {\n anchor = anchor.parentElement;\n }\n let next = anchor.nextElementSibling;\n while (next) {\n const sibling = planeElements.get(next);\n if (!sibling || sibling === plane || !(sibling.owner.compareDocumentPosition(owner) & Node.DOCUMENT_POSITION_FOLLOWING)) {\n break;\n }\n next = next.nextElementSibling;\n }\n document.body.insertBefore(element, next);\n }\n};\n\nexport const acquireOutlinePlane = (owner: HTMLElement): OutlinePlane => {\n const existing = planes.get(owner);\n if (existing) {\n existing.references++;\n return existing;\n }\n const parentOwner = owner.parentElement?.closest<HTMLElement>(selector);\n const parent = parentOwner ? acquireOutlinePlane(parentOwner) : undefined;\n const element = owner.ownerDocument.createElement(\"div\");\n element.className = \"gridui-interaction-outline-layer\";\n element.setAttribute(\"aria-hidden\", \"true\");\n const plane: OutlinePlane = {\n owner,\n element,\n parent,\n references: 1,\n };\n planes.set(owner, plane);\n planeElements.set(element, plane);\n refreshOutlinePlane(plane);\n return plane;\n};\n\nexport const releaseOutlinePlane = (plane: OutlinePlane): void => {\n if (--plane.references) {\n return;\n }\n plane.element.remove();\n planes.delete(plane.owner);\n planeElements.delete(plane.element);\n if (plane.parent) {\n releaseOutlinePlane(plane.parent);\n }\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Scrollbar Interaction Ref\n */\n\n/** Share pointer paint with native scrollbars and Radix without owning scrolling. */\nexport const scrollbarInteractionRef = (element: HTMLElement | null): (() => void) | undefined => {\n if (!element) {\n return;\n }\n const hover = (event: PointerEvent) => {\n const box = element.getBoundingClientRect();\n element.toggleAttribute(\"data-gridui-hovered\", event.clientX >= box.left && event.clientX < box.right\n && event.clientY >= box.top && event.clientY < box.bottom);\n };\n const leave = () => {\n element.removeAttribute(\"data-gridui-hovered\");\n };\n const down = (event: PointerEvent) => {\n if (event.button === 0) {\n element.setAttribute(\"data-gridui-dragging\", \"\");\n }\n };\n const finish = () => {\n element.removeAttribute(\"data-gridui-dragging\");\n };\n element.addEventListener(\"pointerenter\", hover);\n element.addEventListener(\"pointermove\", hover);\n element.addEventListener(\"pointerleave\", leave);\n element.addEventListener(\"pointerdown\", down);\n element.addEventListener(\"pointerup\", finish);\n element.addEventListener(\"pointercancel\", finish);\n element.addEventListener(\"lostpointercapture\", finish);\n return () => {\n element.removeEventListener(\"pointerenter\", hover);\n element.removeEventListener(\"pointermove\", hover);\n element.removeEventListener(\"pointerleave\", leave);\n element.removeEventListener(\"pointerdown\", down);\n element.removeEventListener(\"pointerup\", finish);\n element.removeEventListener(\"pointercancel\", finish);\n element.removeEventListener(\"lostpointercapture\", finish);\n leave();\n finish();\n };\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Style\n */\n\nimport { cva } from \"class-variance-authority\";\n\nexport const overlaySurfaceStyles = cva(\"gridui-overlay-surface gridui-u-border gridui-u-border-solid gridui-u-border-border gridui-u-bg-background gridui-u-text-foreground\", {\n variants: {\n kind: {\n popup: \"gridui-overlay-floating gridui-u-rounded-control\",\n tooltip: \"gridui-overlay-tooltip gridui-u-rounded-control\",\n dialog: \"gridui-overlay-dialog\",\n },\n },\n defaultVariants: { kind: \"popup\" },\n});\n\nexport const overlayBackdropStyles = cva(\"gridui-overlay-backdrop\", {\n variants: {\n pace: {\n normal: null,\n deliberate: \"gridui-overlay-backdrop-deliberate\",\n },\n },\n defaultVariants: { pace: \"normal\" },\n});\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Content Mutation\n */\n\nconst decorativeSelector = \".gridui-scrollbar-layer, .gridui-interaction-outline-layer\";\n\nconst isDecorative = (node: Node): boolean => {\n const element = node.nodeType === 1 ? node as Element : node.parentElement;\n return !!element?.closest(decorativeSelector);\n};\n\n/** Ignore owned indicator paint while retaining mutations of the real content. */\nexport const hasContentMutation = (records: readonly MutationRecord[]): boolean => {\n return records.some(record => {\n return !isDecorative(record.target) && (record.type !== \"childList\"\n || [\n ...record.addedNodes,\n ...record.removedNodes,\n ].some(node => {\n return !isDecorative(node);\n }));\n });\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Use Interaction Outline\n */\n\nimport { hasContentMutation } from \"./content-mutation\";\nimport { acquireOutlinePlane, interactionLayerOwner, refreshOutlinePlane, releaseOutlinePlane } from \"./interaction-layer\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { type Ref, type RefCallback, useLayoutEffect, useState } from \"react\";\n\nexport type InteractionOutlineOptions<T extends HTMLElement> = {\n readonly ref?: Ref<T> | undefined;\n readonly selector: string;\n};\n\n/** Mirror Theme's resolved outline outside a scrolling viewport's clipping ancestors. */\nexport const useInteractionOutline = <T extends HTMLElement>(options: InteractionOutlineOptions<T>): RefCallback<T> => {\n const { ref, selector } = options;\n const [\n viewport,\n setViewport,\n ] = useState<T | null>(null);\n useLayoutEffect(() => {\n if (!viewport) {\n return;\n }\n const document = viewport.ownerDocument;\n const window = document.defaultView!;\n let plane: ReturnType<typeof acquireOutlinePlane> | undefined;\n viewport.setAttribute(\"data-gridui-outline-viewport\", \"\");\n const rings = new Map<HTMLElement, HTMLDivElement>();\n let frame = 0;\n let disposed = false;\n const schedule = () => {\n if (!disposed && !frame) {\n frame = window.requestAnimationFrame(sync);\n }\n };\n const resize = new ResizeObserver(schedule);\n const sync = () => {\n frame = 0;\n for (const element of rings.keys()) {\n element.removeAttribute(\"data-gridui-outline-rendered\");\n }\n const owner = interactionLayerOwner(viewport);\n if (plane && plane.owner !== owner) {\n const previous = plane;\n plane = acquireOutlinePlane(owner);\n plane.element.append(...rings.values());\n releaseOutlinePlane(previous);\n }\n if (plane) {\n refreshOutlinePlane(plane);\n }\n const inactive = viewport.closest('[inert], [aria-hidden=\"true\"]');\n viewport.toggleAttribute(\"data-gridui-outline-inactive\", !!inactive);\n const candidates = inactive ? [] : Array.from(viewport.querySelectorAll<HTMLElement>(selector)).filter(element => {\n return element.closest(\"[data-gridui-outline-viewport]\") === viewport\n && element.matches(\":hover, :active, :focus-visible, [data-highlighted]\");\n });\n const current = new Set<HTMLElement>();\n let moving = false;\n for (const element of candidates) {\n const box = element.getBoundingClientRect();\n const style = window.getComputedStyle(element);\n if (!element.getClientRects().length || style.visibility !== \"visible\"\n || style.outlineStyle === \"none\" || parseFloat(style.outlineWidth) <= 0) {\n continue;\n }\n let left = 0;\n let top = 0;\n let right = document.documentElement.clientWidth;\n let bottom = document.documentElement.clientHeight;\n let opacity = Number(style.opacity);\n let clipped = false;\n for (let ancestor = element.parentElement; ancestor; ancestor = ancestor.parentElement) {\n const appearance = window.getComputedStyle(ancestor);\n const bounds = ancestor.getBoundingClientRect();\n opacity *= Number(appearance.opacity);\n moving ||= ancestor.getAnimations().some(animation => {\n return animation.playState === \"running\";\n });\n if (appearance.overflowX !== \"visible\") {\n clipped = true;\n left = Math.max(left, bounds.left + ancestor.clientLeft);\n right = Math.min(right, bounds.left + ancestor.clientLeft + ancestor.clientWidth);\n }\n if (appearance.overflowY !== \"visible\") {\n clipped = true;\n top = Math.max(top, bounds.top + ancestor.clientTop);\n bottom = Math.min(bottom, bounds.top + ancestor.clientTop + ancestor.clientHeight);\n }\n }\n if (!clipped || opacity === 0 || box.right <= left || box.left >= right || box.bottom <= top || box.top >= bottom) {\n continue;\n }\n current.add(element);\n let ring = rings.get(element);\n if (!ring) {\n ring = document.createElement(\"div\");\n ring.className = \"gridui-interaction-outline\";\n plane ??= acquireOutlinePlane(owner);\n plane.element.append(ring);\n rings.set(element, ring);\n resize.observe(element);\n }\n const extent = Math.max(0, parseFloat(style.outlineWidth) + parseFloat(style.outlineOffset));\n Object.assign(ring.style, {\n left: `${box.left}px`,\n top: `${box.top}px`,\n width: `${box.width}px`,\n height: `${box.height}px`,\n outline: style.outline,\n outlineOffset: style.outlineOffset,\n borderRadius: style.borderRadius,\n opacity: String(opacity),\n zIndex: element.matches(\":focus-visible\") ? \"3\" : \"2\",\n clipPath: `inset(${Math.max(0, top - box.top) - extent}px ${Math.max(0, box.right - right) - extent}px ${Math.max(0, box.bottom - bottom) - extent}px ${Math.max(0, left - box.left) - extent}px)`,\n });\n element.setAttribute(\"data-gridui-outline-rendered\", \"\");\n }\n for (const [\n element,\n ring,\n ] of rings) {\n if (!current.has(element)) {\n element.removeAttribute(\"data-gridui-outline-rendered\");\n ring.remove();\n rings.delete(element);\n resize.unobserve(element);\n }\n }\n if (!rings.size && plane) {\n releaseOutlinePlane(plane);\n plane = undefined;\n }\n if (moving) {\n schedule();\n }\n };\n const mutation = new MutationObserver(records => {\n if (hasContentMutation(records)) {\n schedule();\n }\n });\n mutation.observe(viewport, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n attributeFilter: [\n \"class\",\n \"style\",\n \"hidden\",\n \"disabled\",\n \"aria-disabled\",\n \"aria-readonly\",\n \"readonly\",\n \"data-disabled\",\n \"data-readonly\",\n \"data-state\",\n \"data-highlighted\",\n \"aria-selected\",\n ],\n });\n const ancestors = new MutationObserver(schedule);\n for (let ancestor: HTMLElement | null = viewport; ancestor; ancestor = ancestor.parentElement) {\n ancestors.observe(ancestor, {\n attributes: true,\n attributeFilter: [\n \"class\",\n \"style\",\n \"hidden\",\n \"dir\",\n \"data-theme\",\n \"data-state\",\n \"data-gridui-interaction-layer\",\n \"aria-hidden\",\n \"inert\",\n ],\n });\n }\n const events = [\n \"scroll\",\n \"pointerover\",\n \"pointerout\",\n \"pointerdown\",\n \"pointerup\",\n \"pointercancel\",\n \"focusin\",\n \"focusout\",\n \"keydown\",\n \"keyup\",\n \"animationstart\",\n \"transitionrun\",\n ];\n for (const event of events) {\n document.addEventListener(event, schedule, {\n capture: true,\n passive: true,\n });\n }\n const scheme = window.matchMedia(\"(prefers-color-scheme: dark)\");\n scheme.addEventListener(\"change\", schedule);\n window.addEventListener(\"resize\", schedule);\n resize.observe(viewport);\n sync();\n return () => {\n disposed = true;\n window.cancelAnimationFrame(frame);\n resize.disconnect();\n mutation.disconnect();\n ancestors.disconnect();\n for (const event of events) {\n document.removeEventListener(event, schedule, true);\n }\n scheme.removeEventListener(\"change\", schedule);\n window.removeEventListener(\"resize\", schedule);\n viewport.removeAttribute(\"data-gridui-outline-viewport\");\n viewport.removeAttribute(\"data-gridui-outline-inactive\");\n for (const element of rings.keys()) {\n element.removeAttribute(\"data-gridui-outline-rendered\");\n }\n for (const ring of rings.values()) {\n ring.remove();\n }\n if (plane) {\n releaseOutlinePlane(plane);\n }\n };\n }, [\n viewport,\n selector,\n ]);\n return useComposedRefs(setViewport, ref);\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Use Overlay State\n */\n\nimport { useState } from \"react\";\n\ntype OverlayStateOptions = {\n readonly open?: boolean | undefined;\n readonly defaultOpen?: boolean | undefined;\n readonly onOpenChange?: ((open: boolean) => void) | undefined;\n};\n\nexport const useOverlayState = (options: OverlayStateOptions) => {\n const [\n localOpen,\n setLocalOpen,\n ] = useState(options.defaultOpen ?? false);\n return {\n open: options.open ?? localOpen,\n onOpenChange: (open: boolean): void => {\n if (options.open === undefined) {\n setLocalOpen(open);\n }\n options.onOpenChange?.(open);\n },\n };\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Textarea Scrollbar\n */\n\nexport const isTextarea = (element: HTMLElement): element is HTMLTextAreaElement => {\n return element.tagName === \"TEXTAREA\";\n};\n\n/** Position a sibling indicator in its actual containing block without changing it. */\nexport const syncTextareaScrollbar = (viewport: HTMLTextAreaElement, layer: HTMLElement, style: CSSStyleDeclaration): void => {\n const window = viewport.ownerDocument.defaultView!;\n layer.style.position = style.position === \"fixed\" ? \"fixed\" : \"absolute\";\n const parent = layer.offsetParent as HTMLElement | null;\n const parentBox = parent?.getBoundingClientRect();\n const parentScaleX = parent?.offsetWidth ? parentBox!.width / parent.offsetWidth : 1;\n const parentScaleY = parent?.offsetHeight ? parentBox!.height / parent.offsetHeight : 1;\n const box = viewport.getBoundingClientRect();\n const controlScaleX = viewport.offsetWidth ? box.width / viewport.offsetWidth : 1;\n const controlScaleY = viewport.offsetHeight ? box.height / viewport.offsetHeight : 1;\n const current = layer.getBoundingClientRect();\n const left = (parseFloat(layer.style.left) || 0)\n + (box.left + viewport.clientLeft * controlScaleX - current.left) / parentScaleX;\n const top = (parseFloat(layer.style.top) || 0)\n + (box.top + viewport.clientTop * controlScaleY - current.top) / parentScaleY;\n Object.assign(layer.style, {\n left: `${left}px`,\n top: `${top}px`,\n transform: `scale(${controlScaleX / parentScaleX}, ${controlScaleY / parentScaleY})`,\n transformOrigin: \"0 0\",\n zIndex: style.zIndex === \"auto\" ? \"var(--gridui-z-interaction)\" : style.zIndex,\n opacity: style.opacity,\n visibility: style.visibility,\n colorScheme: style.colorScheme,\n });\n layer.inert = viewport.inert;\n const inherited = window.getComputedStyle(viewport.parentElement!);\n for (const [\n token,\n fallback,\n ] of [\n [\n \"--gridui-scrollbar-thumb\",\n \"--gridui-muted\",\n ],\n [\n \"--gridui-scrollbar-thumb-active\",\n \"--gridui-foreground\",\n ],\n [\n \"--gridui-scrollbar-track\",\n \"--gridui-scrollbar-track\",\n ],\n ] as const) {\n const value = style.getPropertyValue(token) || style.getPropertyValue(fallback);\n const parentValue = inherited.getPropertyValue(token) || inherited.getPropertyValue(fallback);\n if (value && value !== parentValue) {\n layer.style.setProperty(token, value);\n } else {\n layer.style.removeProperty(token);\n }\n }\n};\n", "/**\n * @author WMXPY\n * @package Overlay\n * @namespace Shared\n * @description Use Scrollbars\n */\n\nimport { hasContentMutation } from \"./content-mutation\";\nimport { scrollbarInteractionRef } from \"./scrollbar-interaction-ref\";\nimport { isTextarea, syncTextareaScrollbar } from \"./textarea-scrollbar\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { type Ref, type RefCallback, useId, useLayoutEffect, useRef, useState } from \"react\";\n\nexport type ScrollbarsOptions<T extends HTMLElement> = {\n readonly ref?: Ref<T> | undefined;\n};\n\ntype Scrollbar = {\n readonly track: HTMLElement;\n readonly thumb: HTMLElement;\n readonly dispose: () => void;\n};\n\n/** Attach square scrollbars to one native viewport, within its local DOM owner. */\nexport const useScrollbars = <T extends HTMLElement>(options: ScrollbarsOptions<T> = {}): RefCallback<T> => {\n const { ref } = options;\n const owner = useId();\n const [\n viewport,\n setViewport,\n ] = useState<T | null>(null);\n const refresh = useRef<(() => void) | undefined>(undefined);\n useLayoutEffect(() => {\n if (!viewport) {\n return;\n }\n const document = viewport.ownerDocument;\n const window = document.defaultView!;\n // Textarea cannot render descendants. Its indicator is a local sibling.\n const textarea = isTextarea(viewport) ? viewport : null;\n const host = textarea ? viewport.parentElement! : viewport;\n const layer = document.createElement(viewport.matches(\"ol, ul\") ? \"li\" : \"span\");\n layer.className = \"gridui-scrollbar-layer\";\n layer.setAttribute(\"aria-hidden\", \"true\");\n host.append(layer);\n viewport.setAttribute(\"data-gridui-scrollbar-owner\", owner);\n viewport.setAttribute(\"data-gridui-scrollbar-id\", owner);\n const bars = new Map<boolean, Scrollbar>();\n const contents = new Set<Element>();\n let frame = 0;\n let disposed = false;\n let rtl = false;\n let reverse = false;\n const schedule = () => {\n if (!disposed && !frame) {\n frame = window.requestAnimationFrame(sync);\n }\n };\n const extent = (vertical: boolean): number => {\n return vertical ? viewport.scrollHeight - viewport.clientHeight : viewport.scrollWidth - viewport.clientWidth;\n };\n const position = (vertical: boolean): number => {\n const value = vertical ? viewport.scrollTop : viewport.scrollLeft;\n return (vertical ? reverse : rtl) ? extent(vertical) + value : value;\n };\n const write = (vertical: boolean, value: number) => {\n if (viewport.inert) {\n return;\n }\n const next = Math.max(0, Math.min(extent(vertical), value));\n const native = (vertical ? reverse : rtl) ? next - extent(vertical) : next;\n if (vertical) {\n viewport.scrollTop = native;\n } else {\n viewport.scrollLeft = native;\n }\n sync();\n };\n const create = (vertical: boolean): Scrollbar => {\n const track = document.createElement(\"span\");\n const thumb = document.createElement(\"span\");\n track.className = \"gridui-scrollbar\";\n thumb.className = \"gridui-scrollbar-thumb\";\n track.dataset.orientation = vertical ? \"vertical\" : \"horizontal\";\n track.setAttribute(\"data-gridui-scrollbar-for\", owner);\n track.append(thumb);\n layer.append(track);\n const unbind = scrollbarInteractionRef(track)!;\n const length = () => {\n return vertical ? track.clientHeight : track.clientWidth;\n };\n const thumbLength = () => {\n return vertical ? thumb.clientHeight : thumb.clientWidth;\n };\n const coordinate = (event: PointerEvent) => {\n const box = track.getBoundingClientRect();\n const scale = (vertical ? box.height : box.width) / length();\n return (vertical ? event.clientY - box.top : event.clientX - box.left) / scale;\n };\n let drag: {\n readonly pointerId: number;\n readonly grab: number;\n } | undefined;\n const finish = () => {\n drag = undefined;\n };\n track.addEventListener(\"pointerdown\", event => {\n if (event.button !== 0) {\n return;\n }\n event.preventDefault();\n const max = extent(vertical);\n const offset = max ? position(vertical) / max * (length() - thumbLength()) : 0;\n const cursor = coordinate(event);\n drag = {\n pointerId: event.pointerId,\n grab: event.target === thumb ? cursor - offset : thumbLength() / 2,\n };\n track.setPointerCapture(event.pointerId);\n write(vertical, (cursor - drag.grab) / Math.max(1, length() - thumbLength()) * max);\n });\n track.addEventListener(\"pointermove\", event => {\n if (drag?.pointerId === event.pointerId) {\n write(vertical, (coordinate(event) - drag.grab) / Math.max(1, length() - thumbLength()) * extent(vertical));\n }\n });\n track.addEventListener(\"pointerup\", finish);\n track.addEventListener(\"pointercancel\", finish);\n track.addEventListener(\"lostpointercapture\", finish);\n track.addEventListener(\"click\", event => {\n event.preventDefault();\n event.stopPropagation();\n });\n track.addEventListener(\"wheel\", event => {\n if (event.ctrlKey) {\n return;\n }\n const style = window.getComputedStyle(viewport);\n let unit = 1;\n if (event.deltaMode === 1) {\n unit = parseFloat(style.lineHeight) || 16;\n } else if (event.deltaMode === 2) {\n unit = vertical ? viewport.clientHeight : viewport.clientWidth;\n }\n const next = Math.max(0, Math.min(extent(vertical), position(vertical) + (vertical ? event.deltaY : event.deltaX || event.deltaY) * unit));\n if (next !== position(vertical)) {\n event.preventDefault();\n write(vertical, next);\n }\n }, { passive: false });\n return {\n track,\n thumb,\n dispose() {\n finish();\n unbind();\n track.remove();\n },\n };\n };\n const sync = () => {\n if (disposed) {\n return;\n }\n window.cancelAnimationFrame(frame);\n frame = 0;\n const style = window.getComputedStyle(viewport);\n rtl = style.direction === \"rtl\";\n reverse = style.flexDirection === \"column-reverse\";\n const visible = viewport.clientWidth > 0 && viewport.clientHeight > 0;\n const vertical = visible && /^(auto|scroll)$/.test(style.overflowY) && extent(true) > 1;\n const horizontal = visible && /^(auto|scroll)$/.test(style.overflowX) && extent(false) > 1;\n if (textarea) {\n syncTextareaScrollbar(textarea, layer, style);\n } else {\n // Compensate native content scrolling inside the viewport's own clip and layer.\n layer.style.transform = `translate(${viewport.scrollLeft}px, ${viewport.scrollTop}px)`;\n }\n for (const axis of [\n true,\n false,\n ]) {\n if (!(axis ? vertical : horizontal)) {\n const bar = bars.get(axis);\n if (bar) {\n bar.dispose();\n bars.delete(axis);\n }\n continue;\n }\n let bar = bars.get(axis);\n if (!bar) {\n bar = create(axis);\n bars.set(axis, bar);\n }\n const size = 10;\n const width = axis ? size : viewport.clientWidth - (vertical ? size : 0);\n const height = axis ? viewport.clientHeight - (horizontal ? size : 0) : size;\n const length = axis ? height : width;\n const view = axis ? viewport.clientHeight : viewport.clientWidth;\n const thumb = Math.min(length, Math.max(24, length * view / (extent(axis) + view)));\n Object.assign(bar.track.style, {\n left: `${axis ? viewport.clientWidth - size : 0}px`,\n top: `${axis ? 0 : viewport.clientHeight - size}px`,\n width: `${width}px`,\n height: `${height}px`,\n });\n Object.assign(bar.thumb.style, axis\n ? {\n height: `${thumb}px`,\n transform: `translateY(${position(axis) / extent(axis) * (length - thumb)}px)`,\n }\n : {\n width: `${thumb}px`,\n transform: `translateX(${position(axis) / extent(axis) * (length - thumb)}px)`,\n });\n }\n };\n const resize = new ResizeObserver(schedule);\n const observeContents = () => {\n const current = new Set(Array.from(host.children).filter(element => {\n return !element.classList.contains(\"gridui-scrollbar-layer\");\n }));\n for (const content of contents) {\n if (!current.has(content)) {\n resize.unobserve(content);\n contents.delete(content);\n }\n }\n for (const content of current) {\n if (!contents.has(content)) {\n resize.observe(content);\n contents.add(content);\n }\n }\n };\n const mutation = new MutationObserver(records => {\n if (hasContentMutation(records)) {\n observeContents();\n schedule();\n }\n });\n mutation.observe(host, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n attributeFilter: [\n \"class\",\n \"style\",\n \"hidden\",\n \"inert\",\n \"aria-hidden\",\n \"dir\",\n \"data-state\",\n ],\n });\n viewport.addEventListener(\"scroll\", schedule, { passive: true });\n viewport.addEventListener(\"input\", schedule);\n viewport.addEventListener(\"load\", schedule, true);\n resize.observe(viewport);\n const reset = (event: Event) => {\n if (event.target === textarea?.form) {\n schedule();\n }\n };\n if (textarea) {\n resize.observe(host);\n document.addEventListener(\"reset\", reset, true);\n }\n observeContents();\n refresh.current = schedule;\n sync();\n return () => {\n disposed = true;\n refresh.current = undefined;\n window.cancelAnimationFrame(frame);\n for (const bar of bars.values()) { bar.dispose(); }\n resize.disconnect();\n mutation.disconnect();\n viewport.removeEventListener(\"scroll\", schedule);\n viewport.removeEventListener(\"input\", schedule);\n viewport.removeEventListener(\"load\", schedule, true);\n viewport.removeAttribute(\"data-gridui-scrollbar-owner\");\n viewport.removeAttribute(\"data-gridui-scrollbar-id\");\n if (textarea) {\n document.removeEventListener(\"reset\", reset, true);\n }\n layer.remove();\n };\n }, [\n viewport,\n owner,\n ]);\n useLayoutEffect(() => {\n refresh.current?.();\n });\n return useComposedRefs(setViewport, ref);\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["selector", "useState", "useComposedRefs", "useLayoutEffect", "useState", "bar"]
7
7
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @author WMXPY
3
+ * @package Overlay
4
+ * @namespace Shared
5
+ * @description Content Mutation
6
+ */
7
+ /** Ignore owned indicator paint while retaining mutations of the real content. */
8
+ export declare const hasContentMutation: (records: readonly MutationRecord[]) => boolean;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @author WMXPY
3
+ * @package Overlay
4
+ * @namespace Shared
5
+ * @description Interaction Layer
6
+ */
7
+ /** Marks a popup or dialog surface as an independent interaction paint boundary. */
8
+ export declare const interactionLayerProps: {
9
+ readonly "data-gridui-interaction-layer": "";
10
+ };
11
+ type OutlinePlane = {
12
+ readonly owner: HTMLElement;
13
+ readonly element: HTMLDivElement;
14
+ readonly parent: OutlinePlane | undefined;
15
+ references: number;
16
+ };
17
+ export declare const interactionLayerOwner: (viewport: HTMLElement) => HTMLElement;
18
+ export declare const refreshOutlinePlane: (plane: OutlinePlane) => void;
19
+ export declare const acquireOutlinePlane: (owner: HTMLElement) => OutlinePlane;
20
+ export declare const releaseOutlinePlane: (plane: OutlinePlane) => void;
21
+ export {};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @author WMXPY
3
+ * @package Overlay
4
+ * @namespace Shared
5
+ * @description Scrollbar Interaction Ref
6
+ */
7
+ /** Share pointer paint with native scrollbars and Radix without owning scrolling. */
8
+ export declare const scrollbarInteractionRef: (element: HTMLElement | null) => (() => void) | undefined;
@@ -5,7 +5,7 @@
5
5
  * @description Style
6
6
  */
7
7
  export declare const overlaySurfaceStyles: (props?: ({
8
- kind?: "popup" | "tooltip" | "dialog" | null | undefined;
8
+ kind?: "dialog" | "popup" | "tooltip" | null | undefined;
9
9
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
10
10
  export declare const overlayBackdropStyles: (props?: ({
11
11
  pace?: "normal" | "deliberate" | null | undefined;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @author WMXPY
3
+ * @package Overlay
4
+ * @namespace Shared
5
+ * @description Textarea Scrollbar
6
+ */
7
+ export declare const isTextarea: (element: HTMLElement) => element is HTMLTextAreaElement;
8
+ /** Position a sibling indicator in its actual containing block without changing it. */
9
+ export declare const syncTextareaScrollbar: (viewport: HTMLTextAreaElement, layer: HTMLElement, style: CSSStyleDeclaration) => void;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @author WMXPY
3
+ * @package Overlay
4
+ * @namespace Shared
5
+ * @description Use Interaction Outline
6
+ */
7
+ import { type Ref, type RefCallback } from "react";
8
+ export type InteractionOutlineOptions<T extends HTMLElement> = {
9
+ readonly ref?: Ref<T> | undefined;
10
+ readonly selector: string;
11
+ };
12
+ /** Mirror Theme's resolved outline outside a scrolling viewport's clipping ancestors. */
13
+ export declare const useInteractionOutline: <T extends HTMLElement>(options: InteractionOutlineOptions<T>) => RefCallback<T>;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @author WMXPY
3
+ * @package Overlay
4
+ * @namespace Shared
5
+ * @description Use Scrollbars
6
+ */
7
+ import { type Ref, type RefCallback } from "react";
8
+ export type ScrollbarsOptions<T extends HTMLElement> = {
9
+ readonly ref?: Ref<T> | undefined;
10
+ };
11
+ /** Attach square scrollbars to one native viewport, within its local DOM owner. */
12
+ export declare const useScrollbars: <T extends HTMLElement>(options?: ScrollbarsOptions<T>) => RefCallback<T>;
package/dist/styles.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
1
+ /*! tailwindcss v4.3.4 | MIT License | https://tailwindcss.com */
2
2
  @layer properties;
3
3
  @layer theme, base, components, utilities;
4
4
  @layer utilities {
@@ -87,7 +87,7 @@
87
87
  initial-value: solid;
88
88
  }
89
89
  @layer properties {
90
- @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
90
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: block))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
91
91
  *, ::before, ::after, ::backdrop {
92
92
  --tw-border-style: solid;
93
93
  }
@@ -0,0 +1,78 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "name": "@gridui/overlay",
4
+ "version": "1.2.2",
5
+ "category": "core",
6
+ "description": "GridUI React overlay",
7
+ "usage": "`overlaySurfaceStyles({ kind })` shares the surface border, colors, motion, and reduced-motion behavior. `kind` is `popup` (default), `tooltip`, or `dialog`. `overlayBackdropStyles({ pace })` shares backdrop fades at `normal` (default) or `deliberate` pace. Load this stylesheet before the consuming family.",
8
+ "documentation": [
9
+ "README.md"
10
+ ],
11
+ "exports": [
12
+ {
13
+ "name": "interactionLayerProps",
14
+ "kind": "value",
15
+ "importPath": "@gridui/overlay"
16
+ },
17
+ {
18
+ "name": "InteractionOutlineOptions",
19
+ "kind": "type",
20
+ "importPath": "@gridui/overlay"
21
+ },
22
+ {
23
+ "name": "overlayBackdropStyles",
24
+ "kind": "value",
25
+ "importPath": "@gridui/overlay"
26
+ },
27
+ {
28
+ "name": "OverlayOpen",
29
+ "kind": "value",
30
+ "importPath": "@gridui/overlay"
31
+ },
32
+ {
33
+ "name": "overlaySurfaceStyles",
34
+ "kind": "value",
35
+ "importPath": "@gridui/overlay"
36
+ },
37
+ {
38
+ "name": "RetainedLayer",
39
+ "kind": "component",
40
+ "importPath": "@gridui/overlay"
41
+ },
42
+ {
43
+ "name": "RetainedLayerProps",
44
+ "kind": "type",
45
+ "importPath": "@gridui/overlay"
46
+ },
47
+ {
48
+ "name": "scrollbarInteractionRef",
49
+ "kind": "function",
50
+ "importPath": "@gridui/overlay"
51
+ },
52
+ {
53
+ "name": "ScrollbarsOptions",
54
+ "kind": "type",
55
+ "importPath": "@gridui/overlay"
56
+ },
57
+ {
58
+ "name": "useInteractionOutline",
59
+ "kind": "function",
60
+ "importPath": "@gridui/overlay"
61
+ },
62
+ {
63
+ "name": "useOverlayState",
64
+ "kind": "function",
65
+ "importPath": "@gridui/overlay"
66
+ },
67
+ {
68
+ "name": "useScrollbars",
69
+ "kind": "function",
70
+ "importPath": "@gridui/overlay"
71
+ }
72
+ ],
73
+ "styles": [
74
+ "@gridui/theme/styles.css",
75
+ "@gridui/overlay/styles.css"
76
+ ],
77
+ "examples": []
78
+ }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@gridui/overlay",
3
- "version": "1.1.2",
3
+ "version": "1.2.2",
4
4
  "description": "GridUI React overlay",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "files": [
8
8
  "dist",
9
- "README.md"
9
+ "README.md",
10
+ "docs"
10
11
  ],
11
12
  "sideEffects": [
12
13
  "**/*.css"
@@ -26,7 +27,8 @@
26
27
  "react-dom": "^19.2.0"
27
28
  },
28
29
  "dependencies": {
29
- "@gridui/theme": "^2.3.2",
30
+ "@gridui/theme": "^2.5.3",
31
+ "@radix-ui/react-compose-refs": "1.1.5",
30
32
  "class-variance-authority": "0.7.1"
31
33
  },
32
34
  "devDependencies": {
@@ -43,8 +45,6 @@
43
45
  },
44
46
  "scripts": {
45
47
  "build": "node ../../scripts/compilation/package.ts",
46
- "compile": "tsc --project tsconfig.json",
47
- "test": "jest --passWithNoTests",
48
- "coverage": "jest --coverage --passWithNoTests"
48
+ "compile": "tsc --project tsconfig.json"
49
49
  }
50
50
  }