@scripso-homepad/ui 0.4.15 → 0.4.17

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.js CHANGED
@@ -1,5 +1,5 @@
1
- import { spacing, colors, fontWeight, fontSize, fonts, radii, INPUT_ICON_GAP, useApplyWebClassName, resolveInputVisualState, Label, getInputFieldStyles, inputFieldMetrics } from './chunk-3G3ZKFHX.js';
2
- export { Button, Input, Label, brand, buttonTypography, colors, emeraldGreen, fontSize, fontWeight, fonts, labelTypography, navy, radii, rubyRed, shadows, spacing, stormGray, typographyScale } from './chunk-3G3ZKFHX.js';
1
+ import { spacing, colors, fontWeight, fontSize, fonts, radii, INPUT_ICON_GAP, useApplyWebClassName, resolveInputVisualState, Label, getInputFieldStyles, inputFieldMetrics } from './chunk-U7OSCJKA.js';
2
+ export { Button, Input, Label, brand, buttonTypography, colors, emeraldGreen, fontSize, fontWeight, fonts, labelTypography, navy, radii, rubyRed, shadows, spacing, stormGray, typographyScale } from './chunk-U7OSCJKA.js';
3
3
  import { createContext, useRef, useState, useMemo, useEffect, useLayoutEffect, useContext, isValidElement, cloneElement } from 'react';
4
4
  import { Platform, StyleSheet, Animated, Easing, View, Pressable, Text, Modal, ScrollView, TextInput, Dimensions } from 'react-native';
5
5
  import Svg2, { Path } from 'react-native-svg';
@@ -7,7 +7,6 @@ var Svg = require('react-native-svg');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var clsx = require('clsx');
9
9
  var tailwindMerge = require('tailwind-merge');
10
- var reactRouterDom = require('react-router-dom');
11
10
  var sonner = require('sonner');
12
11
  require('sonner/dist/styles.css');
13
12
 
@@ -7409,7 +7408,7 @@ var require_react_dom_development = __commonJS({
7409
7408
  var HostPortal = 4;
7410
7409
  var HostComponent = 5;
7411
7410
  var HostText = 6;
7412
- var Fragment5 = 7;
7411
+ var Fragment4 = 7;
7413
7412
  var Mode = 8;
7414
7413
  var ContextConsumer = 9;
7415
7414
  var ContextProvider = 10;
@@ -8564,7 +8563,7 @@ var require_react_dom_development = __commonJS({
8564
8563
  return "DehydratedFragment";
8565
8564
  case ForwardRef:
8566
8565
  return getWrappedName$1(type, type.render, "ForwardRef");
8567
- case Fragment5:
8566
+ case Fragment4:
8568
8567
  return "Fragment";
8569
8568
  case HostComponent:
8570
8569
  return type;
@@ -16989,7 +16988,7 @@ var require_react_dom_development = __commonJS({
16989
16988
  }
16990
16989
  }
16991
16990
  function updateFragment2(returnFiber, current2, fragment, lanes, key) {
16992
- if (current2 === null || current2.tag !== Fragment5) {
16991
+ if (current2 === null || current2.tag !== Fragment4) {
16993
16992
  var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);
16994
16993
  created.return = returnFiber;
16995
16994
  return created;
@@ -17392,7 +17391,7 @@ var require_react_dom_development = __commonJS({
17392
17391
  if (child.key === key) {
17393
17392
  var elementType = element.type;
17394
17393
  if (elementType === REACT_FRAGMENT_TYPE) {
17395
- if (child.tag === Fragment5) {
17394
+ if (child.tag === Fragment4) {
17396
17395
  deleteRemainingChildren(returnFiber, child.sibling);
17397
17396
  var existing = useFiber(child, element.props.children);
17398
17397
  existing.return = returnFiber;
@@ -22866,7 +22865,7 @@ var require_react_dom_development = __commonJS({
22866
22865
  var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
22867
22866
  return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2);
22868
22867
  }
22869
- case Fragment5:
22868
+ case Fragment4:
22870
22869
  return updateFragment(current2, workInProgress2, renderLanes2);
22871
22870
  case Mode:
22872
22871
  return updateMode(current2, workInProgress2, renderLanes2);
@@ -23138,7 +23137,7 @@ var require_react_dom_development = __commonJS({
23138
23137
  case SimpleMemoComponent:
23139
23138
  case FunctionComponent:
23140
23139
  case ForwardRef:
23141
- case Fragment5:
23140
+ case Fragment4:
23142
23141
  case Mode:
23143
23142
  case Profiler:
23144
23143
  case ContextConsumer:
@@ -27390,7 +27389,7 @@ var require_react_dom_development = __commonJS({
27390
27389
  return fiber;
27391
27390
  }
27392
27391
  function createFiberFromFragment(elements, mode, lanes, key) {
27393
- var fiber = createFiber(Fragment5, elements, key, mode);
27392
+ var fiber = createFiber(Fragment4, elements, key, mode);
27394
27393
  fiber.lanes = lanes;
27395
27394
  return fiber;
27396
27395
  }
@@ -28808,12 +28807,25 @@ function resolveWebElement(ref) {
28808
28807
  function useApplyWebClassName(ref, className, enabled = true) {
28809
28808
  react.useLayoutEffect(() => {
28810
28809
  if (!enabled || reactNative.Platform.OS !== "web" || !className?.trim()) return;
28811
- const element = resolveWebElement(ref);
28812
- if (!element) return;
28810
+ let cancelled = false;
28811
+ let rafId = 0;
28812
+ let appliedElement = null;
28813
28813
  const classes = className.trim().split(/\s+/);
28814
- element.classList.add(...classes);
28814
+ const apply = () => {
28815
+ if (cancelled) return;
28816
+ const element = resolveWebElement(ref);
28817
+ if (!element) {
28818
+ rafId = requestAnimationFrame(apply);
28819
+ return;
28820
+ }
28821
+ appliedElement = element;
28822
+ element.classList.add(...classes);
28823
+ };
28824
+ apply();
28815
28825
  return () => {
28816
- element.classList.remove(...classes);
28826
+ cancelled = true;
28827
+ if (rafId) cancelAnimationFrame(rafId);
28828
+ appliedElement?.classList.remove(...classes);
28817
28829
  };
28818
28830
  }, [ref, className, enabled]);
28819
28831
  }
@@ -28989,6 +29001,7 @@ function Input({
28989
29001
  var styles2 = reactNative.StyleSheet.create({
28990
29002
  wrapper: {
28991
29003
  width: "100%",
29004
+ minWidth: 0,
28992
29005
  gap: spacing.sm
28993
29006
  },
28994
29007
  iconSlot: {
@@ -29410,29 +29423,42 @@ function useMediaQuery(query) {
29410
29423
  }, [query]);
29411
29424
  return matches;
29412
29425
  }
29413
- function SidebarNavItem({ item, isOpen, onNavigate }) {
29426
+
29427
+ // src/web/layout/nav-active.ts
29428
+ function isNavItemActive(pathname, item) {
29429
+ if (item.end) {
29430
+ return pathname === item.to;
29431
+ }
29432
+ return pathname === item.to || pathname.startsWith(`${item.to}/`);
29433
+ }
29434
+ function SidebarNavItem({ item, isOpen, isActive, onNavigate }) {
29414
29435
  if (item.hidden) {
29415
29436
  return null;
29416
29437
  }
29417
- const handleClick = () => {
29438
+ const handleClick = (event) => {
29439
+ event.preventDefault();
29440
+ if (item.disabled) {
29441
+ return;
29442
+ }
29418
29443
  item.onClick?.();
29419
29444
  onNavigate?.(item);
29420
29445
  };
29421
- return /* @__PURE__ */ jsxRuntime.jsx(
29422
- reactRouterDom.NavLink,
29446
+ return /* @__PURE__ */ jsxRuntime.jsxs(
29447
+ "button",
29423
29448
  {
29424
- to: item.to,
29425
- end: item.end,
29449
+ type: "button",
29426
29450
  onClick: handleClick,
29451
+ "aria-current": isActive ? "page" : void 0,
29427
29452
  "aria-disabled": item.disabled,
29453
+ disabled: item.disabled,
29428
29454
  tabIndex: item.disabled ? -1 : void 0,
29429
- className: ({ isActive }) => cn(
29455
+ className: cn(
29430
29456
  "relative flex items-center rounded-xl px-4 py-3 transition-[background-color,color,gap,padding] duration-300 ease-in-out",
29431
29457
  isOpen ? "w-full gap-4" : "justify-center gap-0 px-3",
29432
29458
  item.disabled && "pointer-events-none opacity-50",
29433
29459
  isActive ? "bg-black/12 text-white" : "text-navy-100 hover:bg-white/5"
29434
29460
  ),
29435
- children: ({ isActive }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29461
+ children: [
29436
29462
  /* @__PURE__ */ jsxRuntime.jsx(
29437
29463
  "span",
29438
29464
  {
@@ -29454,7 +29480,7 @@ function SidebarNavItem({ item, isOpen, onNavigate }) {
29454
29480
  children: item.label
29455
29481
  }
29456
29482
  )
29457
- ] })
29483
+ ]
29458
29484
  }
29459
29485
  );
29460
29486
  }
@@ -29529,6 +29555,7 @@ function Sidebar({
29529
29555
  branding,
29530
29556
  labels,
29531
29557
  sidebarStorageKey,
29558
+ pathname,
29532
29559
  user,
29533
29560
  onLogout,
29534
29561
  className,
@@ -29542,7 +29569,6 @@ function Sidebar({
29542
29569
  collapsed,
29543
29570
  onCollapsedChange
29544
29571
  }) {
29545
- const location = reactRouterDom.useLocation();
29546
29572
  const isDesktop = useMediaQuery("(min-width: 768px)");
29547
29573
  const [internalCollapsed, setInternalCollapsed] = react.useState(
29548
29574
  () => readInitialCollapsedState(sidebarStorageKey, initialCollapsed)
@@ -29578,16 +29604,16 @@ function Sidebar({
29578
29604
  },
29579
29605
  [isDesktop, onMobileClose, onNavItemClick]
29580
29606
  );
29581
- const pathnameRef = react.useRef(location.pathname);
29607
+ const pathnameRef = react.useRef(pathname);
29582
29608
  react.useEffect(() => {
29583
- if (pathnameRef.current === location.pathname) {
29609
+ if (pathnameRef.current === pathname) {
29584
29610
  return;
29585
29611
  }
29586
- pathnameRef.current = location.pathname;
29612
+ pathnameRef.current = pathname;
29587
29613
  if (!isDesktop) {
29588
29614
  onMobileClose?.();
29589
29615
  }
29590
- }, [location.pathname, isDesktop, onMobileClose]);
29616
+ }, [pathname, isDesktop, onMobileClose]);
29591
29617
  react.useEffect(() => {
29592
29618
  if (!mobileOpen || isDesktop) {
29593
29619
  return;
@@ -29668,6 +29694,7 @@ function Sidebar({
29668
29694
  {
29669
29695
  item,
29670
29696
  isOpen: isExpanded,
29697
+ isActive: isNavItemActive(pathname, item),
29671
29698
  onNavigate: handleNavItemNavigate
29672
29699
  },
29673
29700
  item.to
@@ -29678,6 +29705,7 @@ function Sidebar({
29678
29705
  {
29679
29706
  item,
29680
29707
  isOpen: isExpanded,
29708
+ isActive: isNavItemActive(pathname, item),
29681
29709
  onNavigate: handleNavItemNavigate
29682
29710
  },
29683
29711
  item.to
@@ -30440,7 +30468,7 @@ function TableActionsMenu({
30440
30468
  className,
30441
30469
  menuClassName,
30442
30470
  menuWidth = MENU_WIDTH_PX,
30443
- menuFitContent = false
30471
+ menuFitContent = true
30444
30472
  }) {
30445
30473
  const [open, setOpen] = react.useState(false);
30446
30474
  const [menuPosition, setMenuPosition] = react.useState(null);
@@ -30453,11 +30481,14 @@ function TableActionsMenu({
30453
30481
  }, []);
30454
30482
  const updateMenuPosition = react.useCallback(() => {
30455
30483
  const trigger = triggerRef.current;
30484
+ const menuEl = menuRef.current;
30456
30485
  if (!trigger) {
30457
30486
  return;
30458
30487
  }
30459
30488
  const rect = trigger.getBoundingClientRect();
30460
- const resolvedMenuWidth = menuFitContent ? menuRef.current?.getBoundingClientRect().width ?? menuWidth : menuWidth;
30489
+ const viewportMaxWidth = typeof window === "undefined" ? menuWidth : Math.max(menuWidth, window.innerWidth - MENU_VIEWPORT_MARGIN_PX * 2);
30490
+ const measuredWidth = menuFitContent ? menuEl?.offsetWidth || menuEl?.getBoundingClientRect().width || menuWidth : menuWidth;
30491
+ const resolvedMenuWidth = Math.min(Math.max(measuredWidth, 1), viewportMaxWidth);
30461
30492
  setMenuPosition({
30462
30493
  top: rect.bottom + MENU_OFFSET_PX,
30463
30494
  left: clampMenuLeft(rect.right - resolvedMenuWidth, resolvedMenuWidth)
@@ -30470,13 +30501,7 @@ function TableActionsMenu({
30470
30501
  return;
30471
30502
  }
30472
30503
  updateMenuPosition();
30473
- }, [open, updateMenuPosition]);
30474
- useIsomorphicLayoutEffect(() => {
30475
- if (!open || !menuFitContent) {
30476
- return;
30477
- }
30478
- updateMenuPosition();
30479
- }, [items, menuFitContent, open, updateMenuPosition]);
30504
+ }, [open, items, menuFitContent, updateMenuPosition]);
30480
30505
  react.useEffect(() => {
30481
30506
  if (!open) {
30482
30507
  return;
@@ -30502,7 +30527,7 @@ function TableActionsMenu({
30502
30527
  if (items.length === 0) {
30503
30528
  return null;
30504
30529
  }
30505
- const menu = open && menuPosition != null ? /* @__PURE__ */ jsxRuntime.jsx(
30530
+ const menu = open ? /* @__PURE__ */ jsxRuntime.jsx(
30506
30531
  "div",
30507
30532
  {
30508
30533
  ref: menuRef,
@@ -30510,9 +30535,13 @@ function TableActionsMenu({
30510
30535
  role: "menu",
30511
30536
  style: {
30512
30537
  position: "fixed",
30513
- top: menuPosition.top,
30514
- left: menuPosition.left,
30515
- ...menuFitContent ? { width: "max-content" } : { width: menuWidth }
30538
+ top: menuPosition?.top ?? 0,
30539
+ left: menuPosition?.left ?? 0,
30540
+ maxWidth: `calc(100vw - ${MENU_VIEWPORT_MARGIN_PX * 2}px)`,
30541
+ ...menuFitContent ? { width: "max-content" } : { width: menuWidth },
30542
+ // Hide until we have a measured viewport-safe position.
30543
+ visibility: menuPosition != null ? "visible" : "hidden",
30544
+ pointerEvents: menuPosition != null ? "auto" : "none"
30516
30545
  },
30517
30546
  className: cn(
30518
30547
  "z-50 overflow-hidden rounded-2xl border border-storm-gray-50 bg-white shadow-[0_4px_20px_0_rgba(0,0,0,0.05)]",
@@ -30534,14 +30563,13 @@ function TableActionsMenu({
30534
30563
  item.onSelect();
30535
30564
  },
30536
30565
  className: cn(
30537
- "flex h-[51px] cursor-pointer items-center gap-2.5 px-3 text-left typography-14 font-medium text-storm-gray-900 transition-colors hover:bg-storm-gray-0",
30538
- menuFitContent ? "w-auto" : "w-full",
30566
+ "flex h-[51px] w-full cursor-pointer items-center gap-2.5 px-3 text-left typography-14 font-medium text-storm-gray-900 transition-colors hover:bg-storm-gray-0",
30539
30567
  index > 0 && "border-t border-storm-gray-50",
30540
30568
  item.disabled && "cursor-not-allowed opacity-50"
30541
30569
  ),
30542
30570
  children: [
30543
30571
  icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex size-5 shrink-0 items-center justify-center text-storm-gray-200", children: icon }) : null,
30544
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: item.label })
30572
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap", children: item.label })
30545
30573
  ]
30546
30574
  },
30547
30575
  item.id
@@ -30845,6 +30873,8 @@ var variantConfig = {
30845
30873
  };
30846
30874
  var sizeConfig = {
30847
30875
  lg: {
30876
+ /** Matches Tailwind `h-13` so size stays stable before web classNames attach. */
30877
+ minHeight: 52,
30848
30878
  borderRadius: 16,
30849
30879
  paddingTop: 8,
30850
30880
  paddingRight: 8,
@@ -30858,6 +30888,7 @@ var sizeConfig = {
30858
30888
  iconSize: 20
30859
30889
  },
30860
30890
  sm: {
30891
+ minHeight: 40,
30861
30892
  borderRadius: 12,
30862
30893
  paddingTop: 8,
30863
30894
  paddingRight: 8,
@@ -30903,6 +30934,7 @@ function Button({
30903
30934
  const containerStyle = [
30904
30935
  styles3.base,
30905
30936
  {
30937
+ minHeight: metrics.minHeight,
30906
30938
  borderRadius: metrics.borderRadius,
30907
30939
  backgroundColor: preset.backgroundColor,
30908
30940
  paddingTop: metrics.paddingTop,
@@ -31138,6 +31170,28 @@ function Modal({
31138
31170
  return typeof document !== "undefined" ? (0, import_react_dom2.createPortal)(modal, document.body) : modal;
31139
31171
  }
31140
31172
  var DRAWER_TRANSITION_MS = 300;
31173
+ var bodyScrollLockCount = 0;
31174
+ var previousBodyOverflow = "";
31175
+ function lockBodyScroll() {
31176
+ if (typeof document === "undefined") {
31177
+ return;
31178
+ }
31179
+ if (bodyScrollLockCount === 0) {
31180
+ previousBodyOverflow = document.body.style.overflow;
31181
+ document.body.style.overflow = "hidden";
31182
+ }
31183
+ bodyScrollLockCount += 1;
31184
+ }
31185
+ function unlockBodyScroll() {
31186
+ if (typeof document === "undefined") {
31187
+ return;
31188
+ }
31189
+ bodyScrollLockCount = Math.max(0, bodyScrollLockCount - 1);
31190
+ if (bodyScrollLockCount === 0) {
31191
+ document.body.style.overflow = previousBodyOverflow;
31192
+ previousBodyOverflow = "";
31193
+ }
31194
+ }
31141
31195
  function Drawer({
31142
31196
  open,
31143
31197
  title,
@@ -31178,8 +31232,7 @@ function Drawer({
31178
31232
  if (!isPresent) {
31179
31233
  return;
31180
31234
  }
31181
- const previousOverflow = document.body.style.overflow;
31182
- document.body.style.overflow = "hidden";
31235
+ lockBodyScroll();
31183
31236
  const handleKeyDown = (event) => {
31184
31237
  if (event.key === "Escape") {
31185
31238
  onClose();
@@ -31187,7 +31240,7 @@ function Drawer({
31187
31240
  };
31188
31241
  window.addEventListener("keydown", handleKeyDown);
31189
31242
  return () => {
31190
- document.body.style.overflow = previousOverflow;
31243
+ unlockBodyScroll();
31191
31244
  window.removeEventListener("keydown", handleKeyDown);
31192
31245
  };
31193
31246
  }, [isPresent, onClose]);
@@ -31533,6 +31586,7 @@ function ConfirmModal({
31533
31586
  confirmText,
31534
31587
  onCancel,
31535
31588
  onConfirm,
31589
+ icon,
31536
31590
  cancelDisabled = false,
31537
31591
  confirmDisabled = false,
31538
31592
  closeOnBackdrop = true,
@@ -31578,7 +31632,8 @@ function ConfirmModal({
31578
31632
  event.stopPropagation();
31579
31633
  },
31580
31634
  children: [
31581
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-3 text-center", children: [
31635
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col items-center gap-3 text-center", children: [
31636
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-14 items-center justify-center rounded-2xl bg-storm-gray-50 text-storm-gray-500", children: icon }) : null,
31582
31637
  /* @__PURE__ */ jsxRuntime.jsx(
31583
31638
  "h2",
31584
31639
  {
@@ -31739,6 +31794,7 @@ exports.cn = cn;
31739
31794
  exports.getPaginationRange = getPaginationRange;
31740
31795
  exports.getTotalPages = getTotalPages;
31741
31796
  exports.getVisiblePageNumbers = getVisiblePageNumbers;
31797
+ exports.isNavItemActive = isNavItemActive;
31742
31798
  exports.runMutationWithToast = runMutationWithToast;
31743
31799
  exports.tableRowDisabledCellClassName = tableRowDisabledCellClassName;
31744
31800
  exports.useMediaQuery = useMediaQuery;