@syscore/ui-library 1.17.0 → 1.18.0

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/dist/index.es.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import React__default, { useState, useEffect, useCallback, useRef, createContext, useMemo, useContext } from "react";
3
+ import React__default, { useState, useEffect, useCallback, useRef, createContext, useMemo, useLayoutEffect, useContext } from "react";
4
4
  import { motion, AnimatePresence, useMotionValue, animate } from "motion/react";
5
5
  import { clsx } from "clsx";
6
6
  import { twMerge } from "tailwind-merge";
@@ -12410,10 +12410,7 @@ const MobileNavPanel = ({ className, children }) => {
12410
12410
  return (nav == null ? void 0 : nav.offsetHeight) ?? 0;
12411
12411
  };
12412
12412
  const getAvailableHeight = () => {
12413
- var _a;
12414
- const parent = (_a = panelRef.current) == null ? void 0 : _a.parentElement;
12415
- const container = (parent == null ? void 0 : parent.clientHeight) ?? window.innerHeight;
12416
- return container - getNavBarHeight();
12413
+ return window.innerHeight - getNavBarHeight();
12417
12414
  };
12418
12415
  const measureContentHeight = () => {
12419
12416
  const content = contentRef.current;
@@ -12432,67 +12429,94 @@ const MobileNavPanel = ({ className, children }) => {
12432
12429
  });
12433
12430
  stopAnimation.current = () => controls.stop();
12434
12431
  };
12435
- useEffect(() => {
12436
- let cancelled = false;
12432
+ useLayoutEffect(() => {
12437
12433
  if (open) {
12438
12434
  stateRef.current = "initial";
12439
- requestAnimationFrame(() => {
12440
- if (cancelled) return;
12441
- const h = measureContentHeight();
12442
- cachedInitialHeight.current = h;
12443
- springTo(h);
12444
- });
12435
+ const h = measureContentHeight();
12436
+ cachedInitialHeight.current = h;
12437
+ springTo(h);
12445
12438
  } else {
12446
12439
  stateRef.current = "closed";
12447
12440
  cachedInitialHeight.current = 0;
12448
12441
  springTo(0);
12449
12442
  }
12450
- return () => {
12451
- cancelled = true;
12452
- };
12453
12443
  }, [open]);
12444
+ useLayoutEffect(() => {
12445
+ if (!open) return;
12446
+ const h = measureContentHeight();
12447
+ cachedInitialHeight.current = h;
12448
+ if (stateRef.current !== "full") {
12449
+ stateRef.current = "initial";
12450
+ springTo(h);
12451
+ }
12452
+ }, [activeKey]);
12454
12453
  useEffect(() => {
12455
12454
  if (!open) return;
12456
- let cancelled = false;
12457
- requestAnimationFrame(() => {
12458
- requestAnimationFrame(() => {
12459
- if (cancelled) return;
12460
- const h = measureContentHeight();
12461
- cachedInitialHeight.current = h;
12462
- if (stateRef.current === "initial" || stateRef.current === "closed") {
12463
- stateRef.current = "initial";
12464
- springTo(h);
12465
- }
12466
- });
12467
- });
12468
- return () => {
12469
- cancelled = true;
12455
+ const handleKeyDown = (e) => {
12456
+ if (e.key === "Escape") close();
12470
12457
  };
12471
- }, [activeKey]);
12472
- const dragDirection = useRef(null);
12473
- const handlePanStart = () => {
12474
- dragDirection.current = null;
12458
+ document.addEventListener("keydown", handleKeyDown);
12459
+ return () => document.removeEventListener("keydown", handleKeyDown);
12460
+ }, [open, close]);
12461
+ const isDragging = useRef(false);
12462
+ const lastY = useRef(0);
12463
+ const dragStartY = useRef(0);
12464
+ const dragStartTime = useRef(0);
12465
+ const dragMaxHeight = useRef(0);
12466
+ const handlePointerDown = (e) => {
12467
+ var _a;
12468
+ e.currentTarget.setPointerCapture(e.pointerId);
12469
+ (_a = stopAnimation.current) == null ? void 0 : _a.call(stopAnimation);
12470
+ isDragging.current = true;
12471
+ lastY.current = e.clientY;
12472
+ dragStartY.current = e.clientY;
12473
+ dragStartTime.current = Date.now();
12474
+ dragMaxHeight.current = getAvailableHeight();
12475
12475
  };
12476
- const handlePan = (_, info) => {
12477
- dragDirection.current = info.offset.y < 0 ? "up" : "down";
12476
+ const handlePointerMove = (e) => {
12477
+ if (!isDragging.current) return;
12478
+ const dy = e.clientY - lastY.current;
12479
+ lastY.current = e.clientY;
12480
+ const current = heightMV.get();
12481
+ const next = Math.max(0, current - dy);
12482
+ heightMV.set(Math.min(next, dragMaxHeight.current));
12478
12483
  };
12479
- const handlePanEnd = () => {
12480
- const dir = dragDirection.current;
12481
- if (!dir) return;
12482
- if (dir === "up") {
12483
- if (stateRef.current === "initial") {
12484
- stateRef.current = "full";
12485
- springTo(getAvailableHeight());
12486
- }
12487
- } else {
12484
+ const handlePointerUp = (e) => {
12485
+ if (!isDragging.current) return;
12486
+ isDragging.current = false;
12487
+ const currentHeight = heightMV.get();
12488
+ const initial = cachedInitialHeight.current;
12489
+ const full = dragMaxHeight.current;
12490
+ const elapsed = Date.now() - dragStartTime.current;
12491
+ const totalDy = e.clientY - dragStartY.current;
12492
+ const velocity = elapsed > 0 ? totalDy / elapsed * 1e3 : 0;
12493
+ const VELOCITY_THRESHOLD = 500;
12494
+ if (velocity > VELOCITY_THRESHOLD) {
12488
12495
  if (stateRef.current === "full") {
12489
12496
  stateRef.current = "initial";
12490
- springTo(cachedInitialHeight.current);
12491
- } else if (stateRef.current === "initial") {
12497
+ springTo(initial);
12498
+ } else {
12492
12499
  stateRef.current = "closed";
12493
12500
  springTo(0);
12494
12501
  close();
12495
12502
  }
12503
+ } else if (velocity < -VELOCITY_THRESHOLD) {
12504
+ stateRef.current = "full";
12505
+ springTo(full);
12506
+ } else {
12507
+ const midInitial = initial / 2;
12508
+ const midFull = (initial + full) / 2;
12509
+ if (currentHeight < midInitial) {
12510
+ stateRef.current = "closed";
12511
+ springTo(0);
12512
+ close();
12513
+ } else if (currentHeight < midFull) {
12514
+ stateRef.current = "initial";
12515
+ springTo(initial);
12516
+ } else {
12517
+ stateRef.current = "full";
12518
+ springTo(full);
12519
+ }
12496
12520
  }
12497
12521
  };
12498
12522
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -12506,12 +12530,13 @@ const MobileNavPanel = ({ className, children }) => {
12506
12530
  style: { height: heightMV },
12507
12531
  children: [
12508
12532
  /* @__PURE__ */ jsx(
12509
- motion.div,
12533
+ "div",
12510
12534
  {
12511
12535
  className: "mobile-nav-handle",
12512
- onPanStart: handlePanStart,
12513
- onPan: handlePan,
12514
- onPanEnd: handlePanEnd,
12536
+ onPointerDown: handlePointerDown,
12537
+ onPointerMove: handlePointerMove,
12538
+ onPointerUp: handlePointerUp,
12539
+ onPointerCancel: handlePointerUp,
12515
12540
  children: /* @__PURE__ */ jsx("div", { className: "mobile-nav-handle-bar" })
12516
12541
  }
12517
12542
  ),
@@ -12545,6 +12570,7 @@ const MobileNavTrigger = ({
12545
12570
  onClick: handleClick,
12546
12571
  disabled,
12547
12572
  "data-active": activeKey === value || void 0,
12573
+ "aria-expanded": activeKey === value && open,
12548
12574
  className: cn("mobile-nav-trigger group", className),
12549
12575
  "aria-label": label,
12550
12576
  children
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syscore/ui-library",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "A comprehensive React component library built with Radix UI, Tailwind CSS, and TypeScript",
5
5
  "private": false,
6
6
  "type": "module",