@zuzjs/ui 0.10.4 → 0.10.5

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.
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
3
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
4
4
  import { useBase, useShortcuts } from "../../hooks";
5
5
  import { DRAWER_SIDE, KeyCode, TRANSITION_CURVES } from "../../types/enums";
6
6
  import Box from "../Box";
7
+ import { layerManager } from "../layer_manager";
7
8
  import Overlay from "../Overlay";
8
9
  const Drawer = forwardRef((props, ref) => {
9
10
  const { from, speed, children, margin, animation, prerender, onClose, ...pops } = props;
@@ -12,17 +13,32 @@ const Drawer = forwardRef((props, ref) => {
12
13
  const divRef = useRef(null);
13
14
  const [content, setContent] = useState(children);
14
15
  const { className, style, rest } = useBase(pops);
15
- useShortcuts([
16
- { keys: [KeyCode.Escape], callback: () => {
17
- if (visible) {
18
- onClose?.();
19
- setVisible(false);
20
- }
21
- } }
22
- ]);
16
+ const shortcutsConfig = useMemo(() => [
17
+ {
18
+ keys: [KeyCode.Escape],
19
+ callback: () => {
20
+ if (layerManager.isTop(closeDrawer))
21
+ closeDrawer();
22
+ }
23
+ }
24
+ ], [visible]);
25
+ useShortcuts(shortcutsConfig);
26
+ const closeDrawer = useCallback(() => {
27
+ setVisible(false);
28
+ onClose?.();
29
+ }, []);
23
30
  useEffect(() => {
24
31
  setContent(children);
25
32
  }, [children]);
33
+ useEffect(() => {
34
+ if (visible) {
35
+ layerManager.push(closeDrawer);
36
+ }
37
+ else {
38
+ layerManager.pop(closeDrawer);
39
+ }
40
+ return () => layerManager.pop(closeDrawer);
41
+ }, [visible]);
26
42
  const _style = useMemo(() => {
27
43
  switch (from) {
28
44
  case DRAWER_SIDE.Left:
@@ -41,21 +57,15 @@ const Drawer = forwardRef((props, ref) => {
41
57
  open(child) {
42
58
  if (child)
43
59
  setContent(child);
44
- if (!window.document.body.classList.contains(`--no-scroll`))
45
- window.document.body.classList.add(`--no-scroll`);
46
60
  setVisible(true);
47
61
  },
48
62
  close() {
49
- onClose?.();
50
- if (window.document.body.classList.contains(`--no-scroll`))
51
- window.document.body.classList.remove(`--no-scroll`);
52
- setVisible(false);
63
+ closeDrawer();
53
64
  }
54
65
  }));
55
66
  return _jsxs(_Fragment, { children: [_jsx(Overlay, { onClick: (e) => {
56
67
  if (visible) {
57
- onClose?.();
58
- setVisible(false);
68
+ closeDrawer();
59
69
  }
60
70
  }, when: visible }), _jsxs(Box, { ref: divRef, style: {
61
71
  ...style,
@@ -0,0 +1,13 @@
1
+ export type CloseHandler = () => void;
2
+ declare class LayerManager {
3
+ private stack;
4
+ private readonly SCROLL_CLASS;
5
+ private updateScrollLock;
6
+ isTop(closeFn: CloseHandler): boolean;
7
+ push(closeFn: CloseHandler): void;
8
+ pop(closeFn: CloseHandler): void;
9
+ handleEscape(): boolean;
10
+ get count(): number;
11
+ }
12
+ export declare const layerManager: LayerManager;
13
+ export {};
@@ -0,0 +1,42 @@
1
+ class LayerManager {
2
+ stack = [];
3
+ SCROLL_CLASS = "--no-scroll";
4
+ updateScrollLock() {
5
+ if (typeof window === "undefined")
6
+ return;
7
+ if (this.stack.length > 0) {
8
+ document.body.classList.add(this.SCROLL_CLASS);
9
+ }
10
+ else {
11
+ document.body.classList.remove(this.SCROLL_CLASS);
12
+ }
13
+ }
14
+ isTop(closeFn) {
15
+ return this.stack[this.stack.length - 1] === closeFn;
16
+ }
17
+ // Register a component and return a function to unregister it
18
+ push(closeFn) {
19
+ // Prevent duplicate registration of the same instance
20
+ if (!this.stack.includes(closeFn)) {
21
+ this.stack.push(closeFn);
22
+ this.updateScrollLock();
23
+ }
24
+ }
25
+ pop(closeFn) {
26
+ this.stack = this.stack.filter(fn => fn !== closeFn);
27
+ this.updateScrollLock();
28
+ }
29
+ // Attempt to close the top-most layer
30
+ handleEscape() {
31
+ const top = this.stack[this.stack.length - 1];
32
+ if (top) {
33
+ top();
34
+ return true; // We handled the event
35
+ }
36
+ return false;
37
+ }
38
+ get count() {
39
+ return this.stack.length;
40
+ }
41
+ }
42
+ export const layerManager = new LayerManager();
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
3
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
4
4
  import { useBase, useShortcuts } from "../../hooks";
5
5
  import { DRAWER_SIDE, KeyCode, TRANSITION_CURVES } from "../../types/enums";
6
6
  import Box from "../Box";
7
+ import { layerManager } from "../layer_manager";
7
8
  import Overlay from "../Overlay";
8
9
  const Drawer = forwardRef((props, ref) => {
9
10
  const { from, speed, children, margin, animation, prerender, onClose, ...pops } = props;
@@ -12,17 +13,32 @@ const Drawer = forwardRef((props, ref) => {
12
13
  const divRef = useRef(null);
13
14
  const [content, setContent] = useState(children);
14
15
  const { className, style, rest } = useBase(pops);
15
- useShortcuts([
16
- { keys: [KeyCode.Escape], callback: () => {
17
- if (visible) {
18
- onClose?.();
19
- setVisible(false);
20
- }
21
- } }
22
- ]);
16
+ const shortcutsConfig = useMemo(() => [
17
+ {
18
+ keys: [KeyCode.Escape],
19
+ callback: () => {
20
+ if (layerManager.isTop(closeDrawer))
21
+ closeDrawer();
22
+ }
23
+ }
24
+ ], [visible]);
25
+ useShortcuts(shortcutsConfig);
26
+ const closeDrawer = useCallback(() => {
27
+ setVisible(false);
28
+ onClose?.();
29
+ }, []);
23
30
  useEffect(() => {
24
31
  setContent(children);
25
32
  }, [children]);
33
+ useEffect(() => {
34
+ if (visible) {
35
+ layerManager.push(closeDrawer);
36
+ }
37
+ else {
38
+ layerManager.pop(closeDrawer);
39
+ }
40
+ return () => layerManager.pop(closeDrawer);
41
+ }, [visible]);
26
42
  const _style = useMemo(() => {
27
43
  switch (from) {
28
44
  case DRAWER_SIDE.Left:
@@ -41,21 +57,15 @@ const Drawer = forwardRef((props, ref) => {
41
57
  open(child) {
42
58
  if (child)
43
59
  setContent(child);
44
- if (!window.document.body.classList.contains(`--no-scroll`))
45
- window.document.body.classList.add(`--no-scroll`);
46
60
  setVisible(true);
47
61
  },
48
62
  close() {
49
- onClose?.();
50
- if (window.document.body.classList.contains(`--no-scroll`))
51
- window.document.body.classList.remove(`--no-scroll`);
52
- setVisible(false);
63
+ closeDrawer();
53
64
  }
54
65
  }));
55
66
  return _jsxs(_Fragment, { children: [_jsx(Overlay, { onClick: (e) => {
56
67
  if (visible) {
57
- onClose?.();
58
- setVisible(false);
68
+ closeDrawer();
59
69
  }
60
70
  }, when: visible }), _jsxs(Box, { ref: divRef, style: {
61
71
  ...style,
@@ -0,0 +1,13 @@
1
+ export type CloseHandler = () => void;
2
+ declare class LayerManager {
3
+ private stack;
4
+ private readonly SCROLL_CLASS;
5
+ private updateScrollLock;
6
+ isTop(closeFn: CloseHandler): boolean;
7
+ push(closeFn: CloseHandler): void;
8
+ pop(closeFn: CloseHandler): void;
9
+ handleEscape(): boolean;
10
+ get count(): number;
11
+ }
12
+ export declare const layerManager: LayerManager;
13
+ export {};
@@ -0,0 +1,42 @@
1
+ class LayerManager {
2
+ stack = [];
3
+ SCROLL_CLASS = "--no-scroll";
4
+ updateScrollLock() {
5
+ if (typeof window === "undefined")
6
+ return;
7
+ if (this.stack.length > 0) {
8
+ document.body.classList.add(this.SCROLL_CLASS);
9
+ }
10
+ else {
11
+ document.body.classList.remove(this.SCROLL_CLASS);
12
+ }
13
+ }
14
+ isTop(closeFn) {
15
+ return this.stack[this.stack.length - 1] === closeFn;
16
+ }
17
+ // Register a component and return a function to unregister it
18
+ push(closeFn) {
19
+ // Prevent duplicate registration of the same instance
20
+ if (!this.stack.includes(closeFn)) {
21
+ this.stack.push(closeFn);
22
+ this.updateScrollLock();
23
+ }
24
+ }
25
+ pop(closeFn) {
26
+ this.stack = this.stack.filter(fn => fn !== closeFn);
27
+ this.updateScrollLock();
28
+ }
29
+ // Attempt to close the top-most layer
30
+ handleEscape() {
31
+ const top = this.stack[this.stack.length - 1];
32
+ if (top) {
33
+ top();
34
+ return true; // We handled the event
35
+ }
36
+ return false;
37
+ }
38
+ get count() {
39
+ return this.stack.length;
40
+ }
41
+ }
42
+ export const layerManager = new LayerManager();