@sohanemon/utils 5.2.1 → 5.2.3

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.
@@ -2,3 +2,4 @@ export { Icon as Iconify } from '@iconify/react';
2
2
  export { HtmlInjector } from './html-injector';
3
3
  export { MediaWrapper } from './media-wrapper';
4
4
  export { ResponsiveIndicator, ResponsiveIndicator as TailwindIndicator, } from './responsive-indicator';
5
+ export { ScrollableMarker } from './scrollable-marker';
@@ -1,5 +1,7 @@
1
1
  'use client';
2
+ //NOTE: It's currently unsupported to use "export *" in a client boundary
2
3
  export { Icon as Iconify } from '@iconify/react';
3
4
  export { HtmlInjector } from './html-injector';
4
5
  export { MediaWrapper } from './media-wrapper';
5
6
  export { ResponsiveIndicator, ResponsiveIndicator as TailwindIndicator, } from './responsive-indicator';
7
+ export { ScrollableMarker } from './scrollable-marker';
@@ -0,0 +1 @@
1
+ export declare function ScrollableMarker(): any;
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+ import { useScheduledEffect } from '../hooks/schedule';
3
+ export function ScrollableMarker() {
4
+ useScheduledEffect(() => {
5
+ const root = document.body;
6
+ if (!root)
7
+ return;
8
+ const isScrollable = (el) => {
9
+ const style = getComputedStyle(el);
10
+ if (style.overflow === 'hidden' &&
11
+ style.overflowY === 'hidden' &&
12
+ style.overflowX === 'hidden')
13
+ return false;
14
+ const canScrollY = (style.overflowY === 'auto' || style.overflowY === 'scroll') &&
15
+ el.scrollHeight > el.clientHeight;
16
+ const canScrollX = (style.overflowX === 'auto' || style.overflowX === 'scroll') &&
17
+ el.scrollWidth > el.clientWidth;
18
+ return canScrollY || canScrollX;
19
+ };
20
+ const markScrollable = (el) => {
21
+ if (isScrollable(el))
22
+ el.dataset.scrollable = 'true';
23
+ else
24
+ delete el.dataset.scrollable;
25
+ };
26
+ const scanTree = (node) => {
27
+ markScrollable(node);
28
+ for (let i = 0; i < node.children.length; i++) {
29
+ const child = node.children[i];
30
+ scanTree(child);
31
+ }
32
+ };
33
+ requestIdleCallback(() => scanTree(root));
34
+ const observer = new MutationObserver((mutations) => {
35
+ for (const m of mutations) {
36
+ if (m.type === 'childList') {
37
+ m.addedNodes.forEach((n) => {
38
+ if (n instanceof HTMLElement)
39
+ scanTree(n);
40
+ });
41
+ }
42
+ else if (m.type === 'attributes' && m.target instanceof HTMLElement) {
43
+ markScrollable(m.target);
44
+ }
45
+ }
46
+ });
47
+ observer.observe(root, {
48
+ subtree: true,
49
+ childList: true,
50
+ attributes: true,
51
+ attributeFilter: ['style', 'class'],
52
+ });
53
+ return () => observer.disconnect();
54
+ }, []);
55
+ return null;
56
+ }
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  export * from './action';
3
+ export * from './schedule';
3
4
  /**
4
5
  * Hook to detect clicks outside of a referenced element.
5
6
  * @param callback - A function to invoke when a click outside is detected.
@@ -2,6 +2,7 @@
2
2
  import * as React from 'react';
3
3
  import { copyToClipboard } from '../functions';
4
4
  export * from './action';
5
+ export * from './schedule';
5
6
  /**
6
7
  * Hook to detect clicks outside of a referenced element.
7
8
  * @param callback - A function to invoke when a click outside is detected.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sohanemon/utils",
3
- "version": "5.2.1",
3
+ "version": "5.2.3",
4
4
  "author": "Sohan Emon <sohanemon@outlook.com>",
5
5
  "description": "",
6
6
  "type": "module",