@pk-design/react-tailwind 1.9.0 → 1.10.1

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.
Files changed (45) hide show
  1. package/dist/cjs/components/BottomNavigation/BottomNavigation.js +14 -5
  2. package/dist/cjs/components/BottomNavigation/BottomNavigation.js.map +1 -1
  3. package/dist/cjs/components/Drawer/Drawer.js +6 -2
  4. package/dist/cjs/components/Drawer/Drawer.js.map +1 -1
  5. package/dist/cjs/components/MobileHeader/MobileHeader.js +23 -4
  6. package/dist/cjs/components/MobileHeader/MobileHeader.js.map +1 -1
  7. package/dist/cjs/components/PullToRefresh/PullToRefresh.js +145 -57
  8. package/dist/cjs/components/PullToRefresh/PullToRefresh.js.map +1 -1
  9. package/dist/cjs/components/StickyActionBar/StickyActionBar.js +2 -2
  10. package/dist/cjs/components/StickyActionBar/StickyActionBar.js.map +1 -1
  11. package/dist/cjs/hooks/use-breakpoint.js +48 -0
  12. package/dist/cjs/hooks/use-breakpoint.js.map +1 -0
  13. package/dist/cjs/index.js +5 -0
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/es/components/BottomNavigation/BottomNavigation.js +14 -5
  16. package/dist/es/components/BottomNavigation/BottomNavigation.js.map +1 -1
  17. package/dist/es/components/Drawer/Drawer.js +6 -2
  18. package/dist/es/components/Drawer/Drawer.js.map +1 -1
  19. package/dist/es/components/MobileHeader/MobileHeader.js +23 -4
  20. package/dist/es/components/MobileHeader/MobileHeader.js.map +1 -1
  21. package/dist/es/components/PullToRefresh/PullToRefresh.js +146 -58
  22. package/dist/es/components/PullToRefresh/PullToRefresh.js.map +1 -1
  23. package/dist/es/components/StickyActionBar/StickyActionBar.js +2 -2
  24. package/dist/es/components/StickyActionBar/StickyActionBar.js.map +1 -1
  25. package/dist/es/hooks/use-breakpoint.js +43 -0
  26. package/dist/es/hooks/use-breakpoint.js.map +1 -0
  27. package/dist/es/index.js +1 -0
  28. package/dist/es/index.js.map +1 -1
  29. package/dist/react-tailwind.cjs.js +231 -70
  30. package/dist/react-tailwind.cjs.js.map +1 -1
  31. package/dist/react-tailwind.es.js +229 -72
  32. package/dist/react-tailwind.es.js.map +1 -1
  33. package/dist/types/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  34. package/dist/types/components/BottomNavigation/BottomNavigation.types.d.ts +28 -3
  35. package/dist/types/components/Drawer/Drawer.types.d.ts +8 -4
  36. package/dist/types/components/MobileHeader/MobileHeader.d.ts +1 -1
  37. package/dist/types/components/MobileHeader/MobileHeader.types.d.ts +13 -0
  38. package/dist/types/components/PullToRefresh/PullToRefresh.d.ts +1 -1
  39. package/dist/types/components/PullToRefresh/PullToRefresh.types.d.ts +45 -6
  40. package/dist/types/components/StickyActionBar/StickyActionBar.types.d.ts +12 -0
  41. package/dist/types/hooks/use-breakpoint.d.ts +27 -0
  42. package/dist/types/hooks/use-breakpoint.test.d.ts +1 -0
  43. package/dist/types/index.d.ts +1 -0
  44. package/dist/types/test-utils/mock-viewport.d.ts +7 -0
  45. package/package.json +1 -1
@@ -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, { useId, useMemo, useState, forwardRef, useEffect, Children, isValidElement, cloneElement, useRef, useImperativeHandle, useCallback, Fragment as Fragment$1, createContext, useContext, useLayoutEffect } from 'react';
3
+ import React__default, { useId, useMemo, useState, forwardRef, useEffect, useCallback, useSyncExternalStore, Children, isValidElement, cloneElement, useRef, useImperativeHandle, Fragment as Fragment$1, createContext, useContext, useLayoutEffect } from 'react';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import { Dialog, DialogBackdrop, DialogPanel, DialogTitle, Menu, MenuButton, MenuItems, MenuItem, Combobox, ComboboxInput, ComboboxButton, ComboboxOptions, ComboboxOption, TabGroup, TabList, Tab, TabPanels, TabPanel, Transition } from '@headlessui/react';
6
6
  import { FixedSizeList } from 'react-window';
@@ -321,6 +321,45 @@ var SvgX = function SvgX(props) {
321
321
  })));
322
322
  };
323
323
 
324
+ const BREAKPOINT_QUERIES = {
325
+ medium: '(min-width: 768px)',
326
+ expanded: '(min-width: 1024px)',
327
+ };
328
+ // jsdom and some embedded webviews have no matchMedia; treat every query as
329
+ // unmatched there (the compact layout) rather than throwing.
330
+ const hasMatchMedia = () => typeof window !== 'undefined' && typeof window.matchMedia === 'function';
331
+ /** Live result of a CSS media query. `false` during server rendering or without `matchMedia`. */
332
+ const useMediaQuery = (query) => {
333
+ const subscribe = useCallback((onChange) => {
334
+ if (!hasMatchMedia())
335
+ return () => { };
336
+ const list = window.matchMedia(query);
337
+ list.addEventListener('change', onChange);
338
+ return () => list.removeEventListener('change', onChange);
339
+ }, [query]);
340
+ return useSyncExternalStore(subscribe, () => hasMatchMedia() && window.matchMedia(query).matches, () => false);
341
+ };
342
+ /** Current layout range; `compact` during server rendering. */
343
+ const useBreakpoint = () => {
344
+ const isMedium = useMediaQuery(BREAKPOINT_QUERIES.medium);
345
+ const isExpanded = useMediaQuery(BREAKPOINT_QUERIES.expanded);
346
+ if (isExpanded)
347
+ return 'expanded';
348
+ return isMedium ? 'medium' : 'compact';
349
+ };
350
+ /** Resolves a `ResponsiveValue` for the current viewport. */
351
+ const useResponsiveValue = (value) => {
352
+ var _a, _b, _c;
353
+ const breakpoint = useBreakpoint();
354
+ if (typeof value !== 'object' || value === null || !('base' in value))
355
+ return value;
356
+ if (breakpoint === 'expanded')
357
+ return (_b = (_a = value.lg) !== null && _a !== void 0 ? _a : value.md) !== null && _b !== void 0 ? _b : value.base;
358
+ if (breakpoint === 'medium')
359
+ return (_c = value.md) !== null && _c !== void 0 ? _c : value.base;
360
+ return value.base;
361
+ };
362
+
324
363
  const alignmentMap = {
325
364
  center: 'items-center justify-center h-full',
326
365
  start: 'justify-start h-full',
@@ -333,7 +372,8 @@ const panelAlignmentMap = {
333
372
  start: 'data-[closed]:-translate-x-1/2 rounded-r-2xl',
334
373
  end: 'data-[closed]:translate-x-1/2 rounded-l-2xl',
335
374
  top: 'data-[closed]:-translate-y-1/2 rounded-b-2xl',
336
- bottom: 'data-[closed]:translate-y-full rounded-t-2xl md:rounded-t-3xl max-h-[88vh] max-h-[88dvh]',
375
+ // Bottom sheets clear the home indicator on notched phones (0 elsewhere).
376
+ bottom: 'data-[closed]:translate-y-full rounded-t-2xl md:rounded-t-3xl max-h-[88vh] max-h-[88dvh] pb-[env(safe-area-inset-bottom,0px)]',
337
377
  };
338
378
  const panelSizeMap = {
339
379
  xs: 'max-w-xs',
@@ -344,7 +384,9 @@ const panelSizeMap = {
344
384
  '2xl': 'max-w-2xl',
345
385
  full: 'w-full',
346
386
  };
347
- const Drawer = ({ isOpen, onClose = () => { }, closeOnOutsideClick = true, align = 'end', size = 'md', backdrop = true, title, description, children, footer, footerSticky = false, panelClass = '', contentClass = '', titleClass = '', descriptionClass = '', titleSticky = false, showBackButton = false, showCloseButton = true, dragHandle, }) => {
387
+ const Drawer = ({ isOpen, onClose = () => { }, closeOnOutsideClick = true, align: alignProp = 'end', size: sizeProp = 'md', backdrop = true, title, description, children, footer, footerSticky = false, panelClass = '', contentClass = '', titleClass = '', descriptionClass = '', titleSticky = false, showBackButton = false, showCloseButton = true, dragHandle, }) => {
388
+ const align = useResponsiveValue(alignProp);
389
+ const size = useResponsiveValue(sizeProp);
348
390
  const showTitleSection = Boolean(title || description || showBackButton || showCloseButton);
349
391
  const shouldShowDragHandle = dragHandle !== null && dragHandle !== void 0 ? dragHandle : align === 'bottom';
350
392
  const [viewportHeight, setViewportHeight] = React__default.useState(null);
@@ -659,20 +701,23 @@ const BodyText = forwardRef((props, ref) => {
659
701
  });
660
702
  BodyText.displayName = 'BodyText';
661
703
 
662
- function BottomNavigation({ items, activeId, onChange, fixed = true, showLabels = 'always', theme = 'light', activeIndicatorStyle = 'line', containerClass = '', itemClass = '', }) {
704
+ function BottomNavigation({ items, activeId, onChange, fixed = true, showLabels = 'always', theme = 'light', activeIndicatorStyle = 'line', containerClass = '', itemClass = '', linkAs = 'a', linkHrefProp = 'href', ariaLabel = 'Bottom Navigation', hidden = false, }) {
663
705
  const handleTabClick = (item) => {
664
706
  var _a;
665
707
  if (item.disabled)
666
708
  return;
667
709
  (_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item);
668
- onChange(item.id);
710
+ onChange === null || onChange === void 0 ? void 0 : onChange(item.id);
669
711
  };
712
+ // Removed from the tree, not just covered, so hidden tabs can't take focus.
713
+ if (hidden)
714
+ return null;
670
715
  const themeStyles = {
671
716
  light: 'bg-white dark:bg-gray-900 border-t border-[var(--ui-border)] text-gray-600 dark:text-gray-400',
672
717
  dark: 'bg-gray-900 text-gray-400 border-t border-gray-800',
673
718
  primary: 'bg-blue-600 text-blue-100 border-t border-blue-700',
674
719
  }[theme];
675
- return (jsx("nav", { "aria-label": "Bottom Navigation", className: buildClassName('w-full flex items-center justify-around select-none shadow-lg transition-colors relative', fixed && 'fixed bottom-0 left-0 right-0 z-40', 'pb-[env(safe-area-inset-bottom,6px)] px-2', themeStyles, containerClass), "data-testid": "bottom-navigation", children: items.map((item) => {
720
+ return (jsx("nav", { "aria-label": ariaLabel, className: buildClassName('w-full flex items-center justify-around select-none shadow-lg transition-colors relative', fixed && 'fixed bottom-0 left-0 right-0 z-40', 'pb-[env(safe-area-inset-bottom,6px)] px-2', themeStyles, containerClass), "data-testid": "bottom-navigation", children: items.map((item) => {
676
721
  const isActive = item.id === activeId;
677
722
  const showLabelText = showLabels === 'always' || (showLabels === 'active' && isActive);
678
723
  const activeItemColor = {
@@ -695,11 +740,17 @@ function BottomNavigation({ items, activeId, onChange, fixed = true, showLabels
695
740
  info: 'bg-blue-500 text-white',
696
741
  success: 'bg-emerald-500 text-white',
697
742
  }[item.badgeVariant || 'danger'];
698
- return (jsxs("button", { type: "button", disabled: item.disabled, onClick: () => handleTabClick(item), className: buildClassName('flex-1 flex flex-col items-center justify-center pt-2 pb-1.5 px-1 transition-all duration-200 relative cursor-pointer group', item.disabled && 'opacity-40 cursor-not-allowed pointer-events-none', isActive ? activeItemColor : inactiveItemColor, itemClass), "data-testid": `bottom-nav-item-${item.id}`, "aria-selected": isActive, children: [activeIndicatorStyle === 'line' && isActive && (jsx("span", { className: buildClassName('absolute -top-[1px] h-0.75 w-9 rounded-full transition-all duration-200 z-10', theme === 'primary' ? 'bg-white' : 'bg-blue-600 dark:bg-blue-400') })), jsxs("div", { className: buildClassName('relative inline-flex items-center justify-center transition-all duration-200', activeIndicatorStyle === 'pill'
743
+ // A disabled item stays a button: a link can't be disabled.
744
+ const isLink = Boolean(item.href) && !item.disabled;
745
+ const ItemElement = isLink ? linkAs : 'button';
746
+ const elementProps = isLink
747
+ ? { [linkHrefProp]: item.href }
748
+ : { type: 'button', disabled: item.disabled };
749
+ return (jsxs(ItemElement, { ...elementProps, onClick: () => handleTabClick(item), className: buildClassName('flex-1 flex flex-col items-center justify-center pt-2 pb-1.5 px-1 transition-all duration-200 relative cursor-pointer group', item.disabled && 'opacity-40 cursor-not-allowed pointer-events-none', isActive ? activeItemColor : inactiveItemColor, itemClass), "data-testid": `bottom-nav-item-${item.id}`, "aria-current": isActive ? 'page' : undefined, "aria-label": !showLabelText && typeof item.label === 'string' ? item.label : undefined, children: [activeIndicatorStyle === 'line' && isActive && (jsx("span", { className: buildClassName('absolute -top-[1px] h-0.75 w-9 rounded-full transition-all duration-200 z-10', theme === 'primary' ? 'bg-white' : 'bg-blue-600 dark:bg-blue-400') })), jsxs("div", { className: buildClassName('relative inline-flex items-center justify-center transition-all duration-200', activeIndicatorStyle === 'pill'
699
750
  ? buildClassName('px-4 py-1 rounded-full', isActive
700
751
  ? pillActiveStyles
701
752
  : 'group-hover:bg-gray-100/50 dark:group-hover:bg-gray-800/40')
702
- : 'px-1 py-0.5'), children: [jsx("span", { className: "text-xl transition-transform duration-150 group-active:scale-95", children: isActive && item.activeIcon ? item.activeIcon : item.icon }), item.badge !== undefined && item.badge !== null && (jsx("span", { className: buildClassName('absolute -top-1 -right-1 min-w-[16px] h-4 px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs z-10', badgeColor), "data-testid": `bottom-nav-badge-${item.id}`, children: item.badge }))] }), showLabelText && (jsx("span", { className: buildClassName('text-[11px] leading-tight mt-1 truncate max-w-full transition-colors duration-150', isActive ? 'font-bold' : 'font-medium opacity-90'), children: item.label })), activeIndicatorStyle === 'dot' && isActive && (jsx("span", { className: buildClassName('size-1.5 rounded-full mt-1 transition-all duration-200', theme === 'primary' ? 'bg-white' : 'bg-blue-600 dark:bg-blue-400') }))] }, item.id));
753
+ : 'px-1 py-0.5'), children: [jsx("span", { className: "text-xl transition-transform duration-150 group-active:scale-95", "aria-hidden": "true", children: isActive && item.activeIcon ? item.activeIcon : item.icon }), item.badge !== undefined && item.badge !== null && (jsx("span", { className: buildClassName('absolute -top-1 -right-1 min-w-[16px] h-4 px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs z-10', badgeColor), "data-testid": `bottom-nav-badge-${item.id}`, children: item.badge }))] }), showLabelText && (jsx("span", { className: buildClassName('text-[11px] leading-tight mt-1 truncate max-w-full transition-colors duration-150', isActive ? 'font-bold' : 'font-medium opacity-90'), children: item.label })), activeIndicatorStyle === 'dot' && isActive && (jsx("span", { className: buildClassName('size-1.5 rounded-full mt-1 transition-all duration-200', theme === 'primary' ? 'bg-white' : 'bg-blue-600 dark:bg-blue-400') }))] }, item.id));
703
754
  }) }));
704
755
  }
705
756
  BottomNavigation.displayName = 'BottomNavigation';
@@ -2343,77 +2394,165 @@ function PinInput({ length = 4, value: externalValue, onChange, onComplete, mask
2343
2394
  }
2344
2395
  PinInput.displayName = 'PinInput';
2345
2396
 
2346
- function PullArrowIcon({ progress }) {
2347
- const rotation = Math.min(180, progress * 180);
2348
- return (jsx("svg", { className: "size-4 text-blue-600 dark:text-blue-400 transition-transform duration-150", style: { transform: `rotate(${rotation}deg)` }, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 14l-7 7m0 0l-7-7m7 7V3" }) }));
2397
+ // Resistance applied to the finger's travel, so the pull feels elastic.
2398
+ const RESISTANCE = 0.45;
2399
+ // Finger travel (px) before deciding whether a gesture is a pull or a sideways swipe.
2400
+ const AXIS_LOCK_SLOP = 8;
2401
+ // Overlay badge size and the gap it rests at below the container's top edge.
2402
+ const BADGE_SIZE = 40;
2403
+ const BADGE_TOP_GAP = 10;
2404
+ function PullArrowIcon({ progress, className }) {
2405
+ return (jsx("svg", { className: className, style: { transform: `rotate(${Math.min(180, progress * 180)}deg)` }, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", "aria-hidden": "true", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 14l-7 7m0 0l-7-7m7 7V3" }) }));
2349
2406
  }
2350
- function PullToRefresh({ onRefresh, pullThreshold = 70, maxPullDistance = 120, disabled = false, refreshing: externalRefreshing, pullingContent, refreshingContent, children, className = '', contentClass = '', }) {
2407
+ function PullToRefresh({ onRefresh, onError, variant = 'push', pullThreshold = 70, maxPullDistance = 120, disabled = false, refreshing: externalRefreshing, pullingContent, refreshingContent, pullLabel = 'Pull down to refresh', releaseLabel = 'Release to refresh', refreshingLabel = 'Refreshing...', refreshedLabel = 'Content refreshed', children, className = '', contentClass = '', }) {
2351
2408
  const containerRef = useRef(null);
2352
- const startYRef = useRef(0);
2353
- const isPullingRef = useRef(false);
2354
2409
  const [pullDistance, setPullDistance] = useState(0);
2410
+ const [isDragging, setIsDragging] = useState(false);
2355
2411
  const [internalRefreshing, setInternalRefreshing] = useState(false);
2412
+ const [announcement, setAnnouncement] = useState('');
2356
2413
  const isRefreshing = externalRefreshing !== undefined ? externalRefreshing : internalRefreshing;
2357
- const handleTouchStart = useCallback((e) => {
2358
- if (disabled || isRefreshing)
2359
- return;
2360
- const container = containerRef.current;
2361
- if (container && container.scrollTop === 0) {
2362
- startYRef.current = e.touches[0].clientY;
2363
- isPullingRef.current = true;
2364
- }
2365
- }, [disabled, isRefreshing]);
2366
- const handleTouchMove = useCallback((e) => {
2367
- if (!isPullingRef.current || disabled || isRefreshing)
2368
- return;
2414
+ // The touch listeners are attached once, natively (see below), so they read
2415
+ // the latest props and state through this ref instead of stale closures.
2416
+ const latest = useRef({
2417
+ disabled,
2418
+ isRefreshing,
2419
+ pullThreshold,
2420
+ maxPullDistance,
2421
+ onRefresh,
2422
+ onError,
2423
+ refreshedLabel,
2424
+ });
2425
+ useLayoutEffect(() => {
2426
+ latest.current = {
2427
+ disabled,
2428
+ isRefreshing,
2429
+ pullThreshold,
2430
+ maxPullDistance,
2431
+ onRefresh,
2432
+ onError,
2433
+ refreshedLabel,
2434
+ };
2435
+ });
2436
+ useEffect(() => {
2369
2437
  const container = containerRef.current;
2370
- if (!container || container.scrollTop > 0)
2371
- return;
2372
- const currentY = e.touches[0].clientY;
2373
- const rawDistance = currentY - startYRef.current;
2374
- if (rawDistance > 0) {
2375
- // Rubber-band resistance formula
2376
- const dampened = Math.min(maxPullDistance, rawDistance * 0.45);
2377
- setPullDistance(dampened);
2378
- if (e.cancelable) {
2379
- e.preventDefault();
2380
- }
2381
- }
2382
- else {
2383
- setPullDistance(0);
2384
- }
2385
- }, [disabled, isRefreshing, maxPullDistance]);
2386
- const handleTouchEnd = useCallback(async () => {
2387
- if (!isPullingRef.current || disabled || isRefreshing)
2438
+ if (!container)
2388
2439
  return;
2389
- isPullingRef.current = false;
2390
- if (pullDistance >= pullThreshold) {
2391
- setPullDistance(pullThreshold);
2440
+ let mounted = true;
2441
+ let pulling = false;
2442
+ let axis = 'pending';
2443
+ let startX = 0;
2444
+ let startY = 0;
2445
+ let distance = 0;
2446
+ const setDistance = (next) => {
2447
+ distance = next;
2448
+ setPullDistance(next);
2449
+ };
2450
+ // Ends a gesture without refreshing: a cancelled touch, a sideways swipe,
2451
+ // or content that scrolled away from the top.
2452
+ const reset = () => {
2453
+ pulling = false;
2454
+ setIsDragging(false);
2455
+ setDistance(0);
2456
+ };
2457
+ const refresh = async () => {
2458
+ const { pullThreshold: threshold, onRefresh: run, onError: report } = latest.current;
2459
+ setDistance(threshold);
2392
2460
  setInternalRefreshing(true);
2393
2461
  try {
2394
- await onRefresh();
2462
+ await run();
2463
+ if (mounted)
2464
+ setAnnouncement(latest.current.refreshedLabel);
2465
+ }
2466
+ catch (error) {
2467
+ report === null || report === void 0 ? void 0 : report(error);
2395
2468
  }
2396
2469
  finally {
2397
- setInternalRefreshing(false);
2398
- setPullDistance(0);
2470
+ if (mounted) {
2471
+ setInternalRefreshing(false);
2472
+ setDistance(0);
2473
+ }
2399
2474
  }
2400
- }
2401
- else {
2402
- setPullDistance(0);
2403
- }
2404
- }, [disabled, isRefreshing, onRefresh, pullDistance, pullThreshold]);
2475
+ };
2476
+ const handleTouchStart = (e) => {
2477
+ var _a, _b;
2478
+ const { disabled: isDisabled, isRefreshing: busy } = latest.current;
2479
+ if (isDisabled || busy || container.scrollTop > 0 || e.touches.length !== 1)
2480
+ return;
2481
+ startX = (_a = e.touches[0].clientX) !== null && _a !== void 0 ? _a : 0;
2482
+ startY = (_b = e.touches[0].clientY) !== null && _b !== void 0 ? _b : 0;
2483
+ axis = 'pending';
2484
+ pulling = true;
2485
+ setAnnouncement('');
2486
+ setIsDragging(true);
2487
+ setDistance(0);
2488
+ };
2489
+ const handleTouchMove = (e) => {
2490
+ var _a, _b, _c, _d;
2491
+ if (!pulling)
2492
+ return;
2493
+ if (latest.current.disabled || latest.current.isRefreshing || container.scrollTop > 0) {
2494
+ reset();
2495
+ return;
2496
+ }
2497
+ const dx = ((_b = (_a = e.touches[0]) === null || _a === void 0 ? void 0 : _a.clientX) !== null && _b !== void 0 ? _b : 0) - startX;
2498
+ const dy = ((_d = (_c = e.touches[0]) === null || _c === void 0 ? void 0 : _c.clientY) !== null && _d !== void 0 ? _d : 0) - startY;
2499
+ if (axis === 'pending') {
2500
+ if (Math.abs(dx) < AXIS_LOCK_SLOP && Math.abs(dy) < AXIS_LOCK_SLOP)
2501
+ return;
2502
+ axis = dy > 0 && Math.abs(dy) > Math.abs(dx) ? 'vertical' : 'horizontal';
2503
+ // A sideways swipe or an upward scroll belongs to the content, not to us.
2504
+ if (axis === 'horizontal') {
2505
+ reset();
2506
+ return;
2507
+ }
2508
+ }
2509
+ const next = Math.min(latest.current.maxPullDistance, Math.max(0, dy) * RESISTANCE);
2510
+ setDistance(next);
2511
+ // Needs the non-passive listener: stops the browser's own pull-to-refresh/overscroll.
2512
+ if (next > 0 && e.cancelable)
2513
+ e.preventDefault();
2514
+ };
2515
+ const handleTouchEnd = () => {
2516
+ if (!pulling)
2517
+ return;
2518
+ pulling = false;
2519
+ setIsDragging(false);
2520
+ if (distance >= latest.current.pullThreshold)
2521
+ void refresh();
2522
+ else
2523
+ setDistance(0);
2524
+ };
2525
+ // React registers touch listeners as passive, where preventDefault() is
2526
+ // ignored, so these are attached natively with touchmove non-passive.
2527
+ container.addEventListener('touchstart', handleTouchStart, { passive: true });
2528
+ container.addEventListener('touchmove', handleTouchMove, { passive: false });
2529
+ container.addEventListener('touchend', handleTouchEnd);
2530
+ container.addEventListener('touchcancel', reset);
2531
+ return () => {
2532
+ mounted = false;
2533
+ container.removeEventListener('touchstart', handleTouchStart);
2534
+ container.removeEventListener('touchmove', handleTouchMove);
2535
+ container.removeEventListener('touchend', handleTouchEnd);
2536
+ container.removeEventListener('touchcancel', reset);
2537
+ };
2538
+ }, []);
2405
2539
  const progress = Math.min(1, pullDistance / pullThreshold);
2406
2540
  const isReady = pullDistance >= pullThreshold;
2407
- return (jsxs("div", { ref: containerRef, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, className: buildClassName('relative overflow-y-auto overscroll-none', className), "data-testid": "pull-to-refresh-container", children: [jsx("div", { className: "left-0 right-0 top-0 flex items-center justify-center pointer-events-none transition-all duration-150 z-20", style: {
2408
- height: isRefreshing ? `${pullThreshold}px` : `${pullDistance}px`,
2409
- opacity: pullDistance > 0 || isRefreshing ? 1 : 0,
2410
- }, "data-testid": "pull-to-refresh-indicator", children: jsx("div", { className: "flex items-center gap-2 px-3.5 py-1.5 rounded-full bg-white dark:bg-gray-800 border border-[var(--ui-border)] shadow-md text-xs font-semibold text-gray-700 dark:text-gray-200", children: isRefreshing ? (refreshingContent || (jsxs(Fragment, { children: [jsx(Loader, { size: "sm" }), jsx("span", { children: "Refreshing..." })] }))) : pullingContent ? (pullingContent) : (jsxs(Fragment, { children: [jsx(PullArrowIcon, { progress: progress }), jsx("span", { children: isReady ? 'Release to refresh' : 'Pull down to refresh' })] })) }) }), jsx("div", { className: buildClassName('transition-transform duration-150', contentClass), style: {
2411
- transform: isRefreshing
2412
- ? `translateY(${pullThreshold}px)`
2413
- : pullDistance > 0
2414
- ? `translateY(${pullDistance}px)`
2415
- : 'translateY(0px)',
2416
- }, "data-testid": "pull-to-refresh-content", children: children })] }));
2541
+ const offset = isRefreshing ? pullThreshold : pullDistance;
2542
+ // Follow the finger exactly while dragging; animate only the settle afterwards.
2543
+ const motionClass = isDragging
2544
+ ? 'transition-none'
2545
+ : 'transition-transform duration-200 ease-out motion-reduce:transition-none';
2546
+ return (jsxs("div", { ref: containerRef, className: buildClassName('relative overflow-y-auto overscroll-none', className), "data-testid": "pull-to-refresh-container", children: [jsx("span", { role: "status", "aria-live": "polite", className: "sr-only", children: isRefreshing ? refreshingLabel : announcement }), variant === 'overlay' ? (jsx("div", { className: buildClassName('pointer-events-none absolute inset-x-0 top-0 z-20 flex justify-center', motionClass), style: {
2547
+ transform: `translateY(${offset - BADGE_SIZE + BADGE_TOP_GAP}px)`,
2548
+ opacity: offset > 0 ? 1 : 0,
2549
+ }, "aria-hidden": "true", "data-testid": "pull-to-refresh-indicator", children: jsx("div", { className: "grid size-10 place-items-center rounded-full bg-[var(--ui-primary)] text-white shadow-lg", children: isRefreshing
2550
+ ? (refreshingContent !== null && refreshingContent !== void 0 ? refreshingContent : jsx(Loader, { size: "xs", className: "text-white" }))
2551
+ : (pullingContent !== null && pullingContent !== void 0 ? pullingContent : jsx(PullArrowIcon, { progress: progress, className: "size-4" })) }) })) : (
2552
+ // Absolutely positioned, so the content's own translate is the only shift.
2553
+ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 z-20 flex items-center justify-center overflow-hidden", style: { height: `${offset}px`, opacity: offset > 0 ? 1 : 0 }, "aria-hidden": "true", "data-testid": "pull-to-refresh-indicator", children: jsx("div", { className: "flex items-center gap-2 px-3.5 py-1.5 rounded-full bg-white dark:bg-gray-800 border border-[var(--ui-border)] shadow-md text-xs font-semibold text-gray-700 dark:text-gray-200", children: isRefreshing
2554
+ ? (refreshingContent !== null && refreshingContent !== void 0 ? refreshingContent : (jsxs(Fragment, { children: [jsx(Loader, { size: "sm" }), jsx("span", { children: refreshingLabel })] })))
2555
+ : (pullingContent !== null && pullingContent !== void 0 ? pullingContent : (jsxs(Fragment, { children: [jsx(PullArrowIcon, { progress: progress, className: "size-4 text-[var(--ui-primary)] dark:text-blue-400" }), jsx("span", { children: isReady ? releaseLabel : pullLabel })] }))) }) })), jsx("div", { className: buildClassName(variant === 'push' && motionClass, contentClass), style: variant === 'push' ? { transform: `translateY(${offset}px)` } : undefined, "data-testid": "pull-to-refresh-content", children: children })] }));
2417
2556
  }
2418
2557
  PullToRefresh.displayName = 'PullToRefresh';
2419
2558
 
@@ -3326,12 +3465,24 @@ function ChevronLeftIcon$1() {
3326
3465
  function SearchIcon$1() {
3327
3466
  return (jsx("svg", { className: "size-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }));
3328
3467
  }
3468
+ function MoreIcon() {
3469
+ return (jsxs("svg", { className: "size-5", fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: [jsx("circle", { cx: "12", cy: "5", r: "1.75" }), jsx("circle", { cx: "12", cy: "12", r: "1.75" }), jsx("circle", { cx: "12", cy: "19", r: "1.75" })] }));
3470
+ }
3329
3471
  function ClearIcon() {
3330
3472
  return (jsx("svg", { className: "size-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }));
3331
3473
  }
3332
- function MobileHeader({ title, subtitle, titleAlign = 'center', onBack, backLabel = 'Back', leading, actions, searchable = false, searchValue: externalSearchValue, onSearchChange, searchPlaceholder = 'Search...', sticky = true, transparent = false, bottomSlot, className = '', }) {
3474
+ function MobileHeader({ title, subtitle, titleAlign = 'center', onBack, backLabel = 'Back', leading, actions, maxVisibleActions, overflowLabel = 'More actions', trailing, searchable = false, searchValue: externalSearchValue, onSearchChange, searchPlaceholder = 'Search...', sticky = true, transparent = false, bottomSlot, className = '', }) {
3333
3475
  const [isSearchActive, setIsSearchActive] = useState(false);
3334
3476
  const [internalSearchValue, setInternalSearchValue] = useState('');
3477
+ const [isOverflowOpen, setIsOverflowOpen] = useState(false);
3478
+ const hasLeadingSlot = Boolean(onBack || leading) || titleAlign === 'center';
3479
+ // The overflow button takes one of the visible slots.
3480
+ const allActions = actions !== null && actions !== void 0 ? actions : [];
3481
+ const shouldOverflow = maxVisibleActions !== undefined && allActions.length > maxVisibleActions;
3482
+ const visibleActions = shouldOverflow
3483
+ ? allActions.slice(0, Math.max(maxVisibleActions - 1, 0))
3484
+ : allActions;
3485
+ const overflowActions = shouldOverflow ? allActions.slice(visibleActions.length) : [];
3335
3486
  const searchValue = externalSearchValue !== undefined ? externalSearchValue : internalSearchValue;
3336
3487
  const handleSearchInput = (e) => {
3337
3488
  const val = e.target.value;
@@ -3344,16 +3495,22 @@ function MobileHeader({ title, subtitle, titleAlign = 'center', onBack, backLabe
3344
3495
  };
3345
3496
  return (jsxs("header", { className: buildClassName('w-full transition-colors select-none z-30', sticky && 'sticky top-0', transparent
3346
3497
  ? 'bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border-b border-[var(--ui-border-muted)]'
3347
- : 'bg-white dark:bg-gray-900 border-b border-[var(--ui-border)] shadow-xs', 'pt-[env(safe-area-inset-top,0px)]', className), "data-testid": "mobile-header", children: [jsx("div", { className: "h-14 px-3.5 flex items-center justify-between gap-3 relative", children: searchable && isSearchActive ? (jsxs("div", { className: "flex-1 flex items-center gap-2", "data-testid": "mobile-header-search-container", children: [jsxs("div", { className: "relative flex-1 flex items-center", children: [jsx("span", { className: "absolute left-3 pointer-events-none", children: jsx(SearchIcon$1, {}) }), jsx("input", { type: "text", value: searchValue, onChange: handleSearchInput, placeholder: searchPlaceholder, autoFocus: true, className: "w-full pl-9 pr-8 py-1.5 text-xs bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white rounded-full border border-transparent focus:border-blue-500 focus:outline-hidden transition-all", "data-testid": "mobile-header-search-input" }), searchValue && (jsx("button", { type: "button", onClick: handleClearSearch, "aria-label": "Clear search", className: "absolute right-2.5 p-0.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 cursor-pointer", children: jsx(ClearIcon, {}) }))] }), jsx("button", { type: "button", onClick: () => setIsSearchActive(false), className: "text-xs font-semibold text-blue-600 dark:text-blue-400 px-2 py-1.5 rounded-lg hover:bg-blue-50 dark:hover:bg-blue-950/40 cursor-pointer", children: "Cancel" })] })) : (jsxs(Fragment, { children: [jsx("div", { className: "flex items-center gap-1 min-w-[40px] shrink-0 z-10", children: onBack ? (jsxs("button", { type: "button", onClick: onBack, "aria-label": backLabel, className: "flex items-center gap-0.5 text-blue-600 dark:text-blue-400 hover:text-blue-700 p-1 -ml-1 rounded-xl transition-colors cursor-pointer", "data-testid": "mobile-header-back-btn", children: [jsx(ChevronLeftIcon$1, {}), jsx("span", { className: "text-xs font-semibold hidden sm:inline", children: backLabel })] })) : (leading) }), jsxs("div", { className: buildClassName('flex-1 min-w-0 px-2', titleAlign === 'center'
3498
+ : 'bg-white dark:bg-gray-900 border-b border-[var(--ui-border)] shadow-xs', 'pt-[env(safe-area-inset-top,0px)]', className), "data-testid": "mobile-header", children: [jsx("div", { className: "h-14 px-4 flex items-center justify-between gap-3 relative", children: searchable && isSearchActive ? (jsxs("div", { className: "flex-1 flex items-center gap-2", "data-testid": "mobile-header-search-container", children: [jsxs("div", { className: "relative flex-1 flex items-center", children: [jsx("span", { className: "absolute left-3 pointer-events-none", children: jsx(SearchIcon$1, {}) }), jsx("input", { type: "text", value: searchValue, onChange: handleSearchInput, placeholder: searchPlaceholder, autoFocus: true, className: "w-full pl-9 pr-8 py-1.5 text-xs bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white rounded-full border border-transparent focus:border-blue-500 focus:outline-hidden transition-all", "data-testid": "mobile-header-search-input" }), searchValue && (jsx("button", { type: "button", onClick: handleClearSearch, "aria-label": "Clear search", className: "absolute right-2.5 p-0.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 cursor-pointer", children: jsx(ClearIcon, {}) }))] }), jsx("button", { type: "button", onClick: () => setIsSearchActive(false), className: "text-xs font-semibold text-blue-600 dark:text-blue-400 px-2 py-1.5 rounded-lg hover:bg-blue-50 dark:hover:bg-blue-950/40 cursor-pointer", children: "Cancel" })] })) : (jsxs(Fragment, { children: [hasLeadingSlot && (jsx("div", { className: "flex items-center gap-1 min-w-[40px] shrink-0 z-10", "data-testid": "mobile-header-leading", children: onBack ? (jsxs("button", { type: "button", onClick: onBack, "aria-label": backLabel, className: "flex items-center gap-0.5 text-blue-600 dark:text-blue-400 hover:text-blue-700 p-1 -ml-1 rounded-xl transition-colors cursor-pointer", "data-testid": "mobile-header-back-btn", children: [jsx(ChevronLeftIcon$1, {}), jsx("span", { className: "text-xs font-semibold hidden sm:inline", children: backLabel })] })) : (leading) })), jsxs("div", { className: buildClassName('flex-1 min-w-0', hasLeadingSlot ? 'px-2' : 'pr-2', titleAlign === 'center'
3348
3499
  ? 'absolute inset-x-12 text-center pointer-events-none flex flex-col items-center justify-center'
3349
- : 'text-left'), children: [title && (jsx("div", { className: "text-sm font-bold text-gray-900 dark:text-white truncate pointer-events-auto", "data-testid": "mobile-header-title", children: title })), subtitle && (jsx("div", { className: "text-[11px] text-gray-500 dark:text-gray-400 truncate pointer-events-auto", "data-testid": "mobile-header-subtitle", children: subtitle }))] }), jsxs("div", { className: "flex items-center gap-1 min-w-[40px] shrink-0 justify-end z-10", children: [searchable && (jsx("button", { type: "button", onClick: () => setIsSearchActive(true), "aria-label": "Search", className: "p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-xl transition-colors cursor-pointer", "data-testid": "mobile-header-search-toggle", children: jsx(SearchIcon$1, {}) })), actions === null || actions === void 0 ? void 0 : actions.map((action) => {
3500
+ : 'text-left'), children: [title && (jsx("div", { className: "text-sm font-bold text-gray-900 dark:text-white truncate pointer-events-auto", "data-testid": "mobile-header-title", children: title })), subtitle && (jsx("div", { className: "text-[11px] text-gray-500 dark:text-gray-400 truncate pointer-events-auto", "data-testid": "mobile-header-subtitle", children: subtitle }))] }), jsxs("div", { className: "flex items-center gap-1 min-w-[40px] shrink-0 justify-end z-10", children: [searchable && (jsx("button", { type: "button", onClick: () => setIsSearchActive(true), "aria-label": "Search", className: "p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-xl transition-colors cursor-pointer", "data-testid": "mobile-header-search-toggle", children: jsx(SearchIcon$1, {}) })), visibleActions.map((action) => {
3350
3501
  const badgeColor = {
3351
3502
  danger: 'bg-red-500 text-white',
3352
3503
  info: 'bg-blue-500 text-white',
3353
3504
  success: 'bg-emerald-500 text-white',
3354
3505
  }[action.badgeVariant || 'danger'];
3355
3506
  return (jsxs("button", { type: "button", disabled: action.disabled, onClick: action.onClick, "aria-label": action.label, className: buildClassName('p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-xl transition-colors relative cursor-pointer', action.disabled && 'opacity-40 cursor-not-allowed pointer-events-none'), "data-testid": `mobile-header-action-${action.id}`, children: [jsx("span", { className: "text-base", children: action.icon }), action.badge !== undefined && action.badge !== null && (jsx("span", { className: buildClassName('absolute top-1 right-1 min-w-[14px] h-3.5 px-0.5 rounded-full text-[9px] font-bold flex items-center justify-center shadow-xs', badgeColor), "data-testid": `mobile-header-badge-${action.id}`, children: action.badge }))] }, action.id));
3356
- })] })] })) }), bottomSlot && (jsx("div", { className: "px-3 py-2 border-t border-[var(--ui-border-muted)]", "data-testid": "mobile-header-bottom-slot", children: bottomSlot }))] }));
3507
+ }), overflowActions.length > 0 && (jsx("button", { type: "button", onClick: () => setIsOverflowOpen(true), "aria-label": overflowLabel, "aria-haspopup": "dialog", "aria-expanded": isOverflowOpen, className: "p-2 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-xl transition-colors cursor-pointer", "data-testid": "mobile-header-overflow", children: jsx(MoreIcon, {}) })), trailing] })] })) }), overflowActions.length > 0 && (jsx(ActionSheet, { isOpen: isOverflowOpen, onClose: () => setIsOverflowOpen(false), actions: overflowActions.map((action) => ({
3508
+ id: action.id,
3509
+ label: action.label,
3510
+ icon: action.icon,
3511
+ disabled: action.disabled,
3512
+ onClick: action.onClick,
3513
+ })) })), bottomSlot && (jsx("div", { className: "px-3 py-2 border-t border-[var(--ui-border-muted)]", "data-testid": "mobile-header-bottom-slot", children: bottomSlot }))] }));
3357
3514
  }
3358
3515
  MobileHeader.displayName = 'MobileHeader';
3359
3516
 
@@ -4329,14 +4486,14 @@ StatusPill.displayName = 'StatusPill';
4329
4486
 
4330
4487
  const ChevronUpIcon = ({ className }) => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, "aria-hidden": "true", children: jsx("polyline", { points: "18 15 12 9 6 15" }) }));
4331
4488
  const StickyActionBar = forwardRef((props, ref) => {
4332
- const { summaryContent, actionsContent, drawerContent, drawerTitle = 'Summary Details', position = 'fixed', containerMaxWidth = 'max-w-5xl', className, ...restProps } = props;
4489
+ const { summaryContent, actionsContent, drawerContent, drawerTitle = 'Summary Details', position = 'fixed', containerMaxWidth = 'max-w-5xl', safeArea = true, bottomOffset, className, style, ...restProps } = props;
4333
4490
  const [isDrawerOpen, setIsDrawerOpen] = useState(false);
4334
4491
  const positionClass = position === 'fixed'
4335
4492
  ? 'fixed bottom-0 left-0 right-0 z-30'
4336
4493
  : position === 'sticky'
4337
4494
  ? 'sticky bottom-0 z-30'
4338
4495
  : 'relative z-10';
4339
- return (jsxs(Fragment, { children: [jsx("div", { ref: ref, className: buildClassName(positionClass, 'border-t border-[var(--ui-border)] bg-white/90 p-3.5 backdrop-blur-md shadow-lg dark:bg-gray-900/90 transition-all', className), "data-testid": "sticky-action-bar", ...restProps, children: jsxs("div", { className: buildClassName('mx-auto flex items-center justify-between gap-3', containerMaxWidth), children: [summaryContent && (jsx("div", { className: "flex items-center gap-2", children: drawerContent ? (jsxs("button", { type: "button", onClick: () => setIsDrawerOpen(true), className: "flex items-center gap-2 text-left transition-opacity hover:opacity-80 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)] rounded-lg p-1 -m-1", "aria-label": "Expand summary details", "data-testid": "summary-trigger", children: [jsx("div", { children: summaryContent }), jsx(ChevronUpIcon, { className: "size-4 text-[var(--ui-primary)] dark:text-blue-400 shrink-0" })] })) : (jsx("div", { children: summaryContent })) })), actionsContent && (jsx("div", { className: "flex items-center gap-2 shrink-0 ml-auto", "data-testid": "actions-stack", children: actionsContent }))] }) }), drawerContent && (jsx(Drawer, { isOpen: isDrawerOpen, onClose: () => setIsDrawerOpen(false), align: "bottom", size: "full", title: drawerTitle, showBackButton: true, contentClass: "px-4 pb-6 max-h-[calc(100svh-6rem)] overflow-y-auto", children: drawerContent }))] }));
4496
+ return (jsxs(Fragment, { children: [jsx("div", { ref: ref, className: buildClassName(positionClass, 'border-t border-[var(--ui-border)] bg-white/90 p-3.5 backdrop-blur-md shadow-lg dark:bg-gray-900/90 transition-all', safeArea && 'pb-[calc(0.875rem+env(safe-area-inset-bottom,0px))]', className), style: bottomOffset && position !== 'relative' ? { bottom: bottomOffset, ...style } : style, "data-testid": "sticky-action-bar", ...restProps, children: jsxs("div", { className: buildClassName('mx-auto flex items-center justify-between gap-3', containerMaxWidth), children: [summaryContent && (jsx("div", { className: "flex items-center gap-2", children: drawerContent ? (jsxs("button", { type: "button", onClick: () => setIsDrawerOpen(true), className: "flex items-center gap-2 text-left transition-opacity hover:opacity-80 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)] rounded-lg p-1 -m-1", "aria-label": "Expand summary details", "data-testid": "summary-trigger", children: [jsx("div", { children: summaryContent }), jsx(ChevronUpIcon, { className: "size-4 text-[var(--ui-primary)] dark:text-blue-400 shrink-0" })] })) : (jsx("div", { children: summaryContent })) })), actionsContent && (jsx("div", { className: "flex items-center gap-2 shrink-0 ml-auto", "data-testid": "actions-stack", children: actionsContent }))] }) }), drawerContent && (jsx(Drawer, { isOpen: isDrawerOpen, onClose: () => setIsDrawerOpen(false), align: "bottom", size: "full", title: drawerTitle, showBackButton: true, contentClass: "px-4 pb-6 max-h-[calc(100svh-6rem)] overflow-y-auto", children: drawerContent }))] }));
4340
4497
  });
4341
4498
  StickyActionBar.displayName = 'StickyActionBar';
4342
4499
 
@@ -4929,5 +5086,5 @@ const useIsTabletOrMobile = () => {
4929
5086
  return isMobile || isTablet;
4930
5087
  };
4931
5088
 
4932
- export { Accordion, ActionSheet, Alert, Badge, Banner, BodyText, BottomNavigation, Breadcrumb, Button, ButtonGroup, Card, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, Checkbox, CheckboxGroup, DOTS, DataList, DataTable, DetailedInformation, Dot, Drawer, Dropdown, EmptyState, EmptyTableRow, Flex, FlexItem, FloatingActionButton, Grid, GridCol, HeadingText, Input, Label, Loader, MobileHeader, MobilePicker, MobileStepper, PASSWORD_PLACEHOLDER, PASSWORD_TYPE, Pagination, PasswordInput, PinInput, PullToRefresh, QuantityStepper, Radio, RadioGroup, RadioSwitch, RangeInput, RangeSlider, SegmentedControl, SelectBox, Skeleton, SortIconMap, StatusPill, StickyActionBar, SwipeableRow, SwipeableTabs, Table, TableBody, TableCell, TableFoot, TableHead, TableHeaderCell, TableRow, Tabs, TextContent, Textarea, Toast, ToastProvider, VirtualizedDataTable, WheelPicker, buildClassName, buildInputClass, evaluatePasswordStrength, get, getSortIcon, isArray, isEmpty, nextSortDirection, updateSortQuery, useDebounce, useDebounceFn, useIsMobile, useIsTablet, useIsTabletOrMobile, usePagination, useRowSelection, useToast };
5089
+ export { Accordion, ActionSheet, Alert, BREAKPOINT_QUERIES, Badge, Banner, BodyText, BottomNavigation, Breadcrumb, Button, ButtonGroup, Card, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, Checkbox, CheckboxGroup, DOTS, DataList, DataTable, DetailedInformation, Dot, Drawer, Dropdown, EmptyState, EmptyTableRow, Flex, FlexItem, FloatingActionButton, Grid, GridCol, HeadingText, Input, Label, Loader, MobileHeader, MobilePicker, MobileStepper, PASSWORD_PLACEHOLDER, PASSWORD_TYPE, Pagination, PasswordInput, PinInput, PullToRefresh, QuantityStepper, Radio, RadioGroup, RadioSwitch, RangeInput, RangeSlider, SegmentedControl, SelectBox, Skeleton, SortIconMap, StatusPill, StickyActionBar, SwipeableRow, SwipeableTabs, Table, TableBody, TableCell, TableFoot, TableHead, TableHeaderCell, TableRow, Tabs, TextContent, Textarea, Toast, ToastProvider, VirtualizedDataTable, WheelPicker, buildClassName, buildInputClass, evaluatePasswordStrength, get, getSortIcon, isArray, isEmpty, nextSortDirection, updateSortQuery, useBreakpoint, useDebounce, useDebounceFn, useIsMobile, useIsTablet, useIsTabletOrMobile, useMediaQuery, usePagination, useResponsiveValue, useRowSelection, useToast };
4933
5090
  //# sourceMappingURL=react-tailwind.es.js.map