@platform-blocks/ui 0.5.0 → 0.6.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 (53) hide show
  1. package/lib/cjs/index.js +670 -1744
  2. package/lib/cjs/index.js.map +1 -1
  3. package/lib/components/Carousel/types.d.ts +14 -0
  4. package/lib/components/Dialog/Dialog.d.ts +1 -1
  5. package/lib/components/Dialog/types.d.ts +23 -2
  6. package/lib/components/HoverCard/types.d.ts +5 -3
  7. package/lib/components/Image/Image.d.ts +1 -1
  8. package/lib/components/Image/types.d.ts +3 -3
  9. package/lib/components/Input/styles.d.ts +1 -12
  10. package/lib/components/Layout/Layout.d.ts +1 -0
  11. package/lib/components/Menu/types.d.ts +2 -2
  12. package/lib/components/Popover/types.d.ts +7 -5
  13. package/lib/components/Select/Select.types.d.ts +1 -1
  14. package/lib/components/Skeleton/types.d.ts +2 -2
  15. package/lib/components/Switch/styles.d.ts +1 -1
  16. package/lib/components/Table/Table.d.ts +4 -4
  17. package/lib/components/TextArea/styles.d.ts +1 -1
  18. package/lib/components/TextArea/types.d.ts +2 -2
  19. package/lib/components/Timeline/types.d.ts +20 -0
  20. package/lib/components/Video/types.d.ts +2 -2
  21. package/lib/components/Waveform/WaveformSkeleton.d.ts +2 -2
  22. package/lib/components/Waveform/types.d.ts +2 -2
  23. package/lib/components/index.d.ts +0 -4
  24. package/lib/components/types.d.ts +0 -1
  25. package/lib/core/providers/OverlayProvider.d.ts +1 -1
  26. package/lib/core/theme/PlatformBlocksProvider.d.ts +1 -5
  27. package/lib/core/utils/layout.d.ts +13 -16
  28. package/lib/core/utils/positioning-enhanced.d.ts +2 -0
  29. package/lib/esm/index.js +672 -1725
  30. package/lib/esm/index.js.map +1 -1
  31. package/lib/index.d.ts +0 -11
  32. package/package.json +67 -57
  33. package/lib/components/Can/Can.d.ts +0 -30
  34. package/lib/components/Can/PermissionDemo.d.ts +0 -2
  35. package/lib/components/Can/ability.d.ts +0 -89
  36. package/lib/components/Can/builder.d.ts +0 -113
  37. package/lib/components/Can/context.d.ts +0 -25
  38. package/lib/components/Can/index.d.ts +0 -6
  39. package/lib/components/Can/types.d.ts +0 -230
  40. package/lib/components/HoverCard/index.d.ts +0 -2
  41. package/lib/components/Lottie/Lottie.d.ts +0 -30
  42. package/lib/components/Lottie/index.d.ts +0 -2
  43. package/lib/components/NavigationProgress/NavigationProgress.d.ts +0 -4
  44. package/lib/components/NavigationProgress/defaults.d.ts +0 -8
  45. package/lib/components/NavigationProgress/hooks/useNavigationProgressState.d.ts +0 -1
  46. package/lib/components/NavigationProgress/index.d.ts +0 -2
  47. package/lib/components/NavigationProgress/styles/resolver.d.ts +0 -1
  48. package/lib/components/NavigationProgress/tokens.d.ts +0 -4
  49. package/lib/components/NavigationProgress/types.d.ts +0 -30
  50. package/lib/components/RichTextEditor/RichTextEditor.d.ts +0 -3
  51. package/lib/components/RichTextEditor/index.d.ts +0 -2
  52. package/lib/components/RichTextEditor/styles.d.ts +0 -61
  53. package/lib/components/RichTextEditor/types.d.ts +0 -150
package/lib/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import React__default, { createContext, useContext, useMemo, useEffect, useState, useRef, useCallback, forwardRef, memo, useReducer, isValidElement, cloneElement, useImperativeHandle } from 'react';
4
- import { Platform, Modal, StyleSheet, View, Pressable, I18nManager, Keyboard, Dimensions, Text as Text$1, AccessibilityInfo, findNodeHandle, Animated as Animated$1, Easing, AppState, useWindowDimensions, PanResponder, BackHandler, Appearance, PixelRatio, NativeModules, TextInput, ScrollView, KeyboardAvoidingView, TouchableOpacity, FlatList, Linking, Image as Image$1, InteractionManager, StatusBar as StatusBar$1, UIManager } from 'react-native';
4
+ import { Platform, Modal, StyleSheet, View, Pressable, I18nManager, Keyboard, Dimensions, Text as Text$1, AccessibilityInfo, findNodeHandle, Animated as Animated$1, Easing, AppState, useWindowDimensions, PanResponder, BackHandler, Appearance, PixelRatio, NativeModules, TextInput, ScrollView, KeyboardAvoidingView, TouchableOpacity, FlatList, Linking, Image as Image$1, InteractionManager, StatusBar as StatusBar$1 } from 'react-native';
5
5
  import Animated, { useSharedValue, withRepeat, withTiming, cancelAnimation, useAnimatedStyle, interpolate, Extrapolation, withSpring, Easing as Easing$1, runOnJS, withSequence, withDelay, interpolateColor, useDerivedValue, ReduceMotion } from 'react-native-reanimated';
6
6
  import { useSafeAreaInsets, SafeAreaInsetsContext, SafeAreaView, SafeAreaProvider } from 'react-native-safe-area-context';
7
7
  import Svg, { Path, Defs, LinearGradient, Stop, Circle, Line, G, Text as Text$2, Rect, RadialGradient, ClipPath } from 'react-native-svg';
@@ -706,16 +706,16 @@ const DARK_THEME = {
706
706
  '#F2F2F7'
707
707
  ],
708
708
  highlight: [
709
- '#2A2313',
710
- '#3D3320',
711
- '#4F422D',
712
- '#61523A',
713
- '#736247',
714
- '#FBBF24', // Keep same base as light mode for consistency
715
- '#FCD34D',
716
- '#FDE68A',
717
- '#FEF3C7',
718
- '#FFFBEB'
709
+ '#1E3A5F', // Deep blue
710
+ '#1E4976', //
711
+ '#1D5A8F', //
712
+ '#2563EB', // Bright blue
713
+ '#3B82F6', // Primary blue
714
+ '#60A5FA', // Light blue
715
+ '#93C5FD', //
716
+ '#BFDBFE', //
717
+ '#DBEAFE', //
718
+ '#EFF6FF' // Very light blue
719
719
  ],
720
720
  pink: [
721
721
  '#831843', '#9D174D', '#BE185D', '#DB2777', '#EC4899',
@@ -771,9 +771,9 @@ const DARK_THEME = {
771
771
  },
772
772
  states: {
773
773
  focusRing: 'rgba(10,132,255,0.55)',
774
- textSelection: 'rgba(251, 191, 36, 0.2)', // Slightly more subtle for dark mode
775
- highlightText: '#FDE68A', // highlight[7] for good contrast on dark
776
- highlightBackground: 'rgba(97, 82, 58, 0.8)' // Darker highlight[3] with more opacity
774
+ textSelection: 'rgba(10, 132, 255, 0.25)', // Primary blue for selection
775
+ highlightText: '#60A5FA', // primary[4] - bright blue for good contrast on dark
776
+ highlightBackground: 'rgba(59, 130, 246, 0.35)' // primary[5] with transparency
777
777
  },
778
778
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
779
779
  fontSizes: {
@@ -862,6 +862,8 @@ const DARK_THEME = {
862
862
  const optionalModuleCache = new Map();
863
863
  const isDev = typeof __DEV__ !== 'undefined' ? __DEV__ : process.env.NODE_ENV !== 'production';
864
864
  // Metro bundler requires static string literals for require; keep all optional modules here.
865
+ // NOTE: Do NOT add react-syntax-highlighter here - it causes Metro to fail on native
866
+ // when the package isn't installed. Instead, pass the loader dynamically from web-only code.
865
867
  const optionalModuleLoaders = {
866
868
  'react-native': () => require('react-native'),
867
869
  'expo-clipboard': () => require('expo-clipboard'),
@@ -870,21 +872,9 @@ const optionalModuleLoaders = {
870
872
  'expo-document-picker': () => require('expo-document-picker'),
871
873
  'react-native-webview': () => require('react-native-webview'),
872
874
  'lodash.debounce': () => require('lodash.debounce'),
873
- 'react-syntax-highlighter': () => require('react-syntax-highlighter'),
874
- 'react-syntax-highlighter/dist/esm/languages/prism/jsx': () => require('react-syntax-highlighter/dist/esm/languages/prism/jsx'),
875
- 'react-syntax-highlighter/dist/esm/languages/prism/tsx': () => require('react-syntax-highlighter/dist/esm/languages/prism/tsx'),
876
- 'react-syntax-highlighter/dist/esm/languages/prism/typescript': () => require('react-syntax-highlighter/dist/esm/languages/prism/typescript'),
877
- 'react-syntax-highlighter/dist/esm/languages/prism/javascript': () => require('react-syntax-highlighter/dist/esm/languages/prism/javascript'),
878
- 'react-syntax-highlighter/dist/esm/languages/prism/json': () => require('react-syntax-highlighter/dist/esm/languages/prism/json'),
879
- 'react-syntax-highlighter/dist/esm/languages/prism/bash': () => require('react-syntax-highlighter/dist/esm/languages/prism/bash'),
880
- 'react-syntax-highlighter/dist/esm/styles/prism/prism': () => require('react-syntax-highlighter/dist/esm/styles/prism/prism'),
881
- 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus': () => require('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus'),
882
875
  'expo-audio': () => require('expo-audio'),
883
876
  'react-native-gesture-handler': () => require('react-native-gesture-handler'),
884
877
  'expo-status-bar': () => require('expo-status-bar'),
885
- 'lottie-react': () => require('lottie-react'),
886
- '@lottiefiles/dotlottie-react': () => require('@lottiefiles/dotlottie-react'),
887
- 'lottie-react-native': () => require('lottie-react-native'),
888
878
  'expo-navigation-bar': () => require('expo-navigation-bar'),
889
879
  };
890
880
  /**
@@ -1164,25 +1154,50 @@ function OverlayRenderer({ style } = {}) {
1164
1154
  }) }));
1165
1155
  }
1166
1156
  function OverlayContent({ overlay, isTopmost, onBackdropPress }) {
1167
- var _a, _b, _c;
1157
+ var _a, _b, _c, _d, _e, _f;
1168
1158
  useTheme();
1169
1159
  const DEBUG = overlay.debug === true;
1170
1160
  if (DEBUG) {
1171
1161
  console.log('Rendering overlay content:');
1172
1162
  console.log('- anchor:', overlay.anchor);
1163
+ console.log('- placement:', overlay.placement);
1173
1164
  console.log('- strategy:', overlay.strategy);
1174
1165
  console.log('- zIndex:', overlay.zIndex);
1175
1166
  }
1167
+ // Check if this is a top-positioned overlay
1168
+ const isTopPlacement = (_a = overlay.placement) === null || _a === void 0 ? void 0 : _a.startsWith('top');
1169
+ // For top placements, we need to anchor from the bottom of the overlay
1170
+ // The anchor.y represents where the bottom of the overlay should be (top of the trigger minus offset)
1171
+ // So we use the estimated height to calculate where the top of the overlay would be
1176
1172
  const overlayStyle = {
1177
1173
  // Use fixed positioning on web for viewport-anchored overlays
1178
1174
  position: (Platform.OS === 'web' && overlay.strategy === 'fixed') ? 'fixed' : 'absolute',
1179
- top: ((_a = overlay.anchor) === null || _a === void 0 ? void 0 : _a.y) || 0,
1180
1175
  left: ((_b = overlay.anchor) === null || _b === void 0 ? void 0 : _b.x) || 0,
1181
1176
  zIndex: overlay.zIndex,
1182
1177
  width: overlay.width || (((_c = overlay.anchor) === null || _c === void 0 ? void 0 : _c.width) ? overlay.anchor.width : undefined),
1183
1178
  maxWidth: overlay.maxWidth,
1184
1179
  maxHeight: overlay.maxHeight,
1185
1180
  };
1181
+ if (isTopPlacement && Platform.OS === 'web') {
1182
+ // For top placements, position from the bottom of the overlay
1183
+ // anchor.y is where the top of the overlay should be, but we want to anchor from the bottom
1184
+ // so the overlay can grow upward naturally
1185
+ // The "bottom" of the anchor point is: viewport.height - (anchor.y + estimatedHeight)
1186
+ // But since we don't know actual height, use bottom anchoring relative to the trigger
1187
+ // Actually, anchor.y already accounts for the estimated height, so:
1188
+ // anchor.y = trigger.y - estimatedHeight - offset
1189
+ // We want the overlay's bottom edge to be at: trigger.y - offset
1190
+ // Which means: bottom = viewport.height - (trigger.y - offset) = viewport.height - anchor.y - estimatedHeight
1191
+ // Simpler: just set top and let it render, but the issue is the estimate is wrong
1192
+ // Better approach: use the anchor.y + anchor.height as the "bottom anchor point"
1193
+ // This is where the bottom of the overlay should be
1194
+ const bottomAnchorPoint = (((_d = overlay.anchor) === null || _d === void 0 ? void 0 : _d.y) || 0) + (((_e = overlay.anchor) === null || _e === void 0 ? void 0 : _e.height) || 0);
1195
+ overlayStyle.top = undefined;
1196
+ overlayStyle.bottom = `calc(100vh - ${bottomAnchorPoint}px)`;
1197
+ }
1198
+ else {
1199
+ overlayStyle.top = ((_f = overlay.anchor) === null || _f === void 0 ? void 0 : _f.y) || 0;
1200
+ }
1186
1201
  if (DEBUG) {
1187
1202
  console.log('- overlayStyle:', overlayStyle);
1188
1203
  }
@@ -1947,7 +1962,6 @@ function resolveComponentSize(value, scale, options = {}) {
1947
1962
  }
1948
1963
  const firstAvailable = allowed.find(key => scale[key] !== undefined);
1949
1964
  if (firstAvailable && scale[firstAvailable] !== undefined) {
1950
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1951
1965
  return scale[firstAvailable];
1952
1966
  }
1953
1967
  throw new Error('resolveComponentSize: no matching size found in provided scale.');
@@ -2309,18 +2323,17 @@ function extractSpacingProps(props) {
2309
2323
  *
2310
2324
  * @param props - The layout properties object
2311
2325
  * @param props.fullWidth - When true, sets width to 100%
2312
- * @param props.w - Shorthand width property (overrides fullWidth)
2313
- * @param props.width - Specific width value (overrides fullWidth and w)
2314
- * @param props.height - Height value
2315
- * @param props.maxWidth - Maximum width constraint
2316
- * @param props.minWidth - Minimum width constraint
2317
- * @param props.maxHeight - Maximum height constraint
2318
- * @param props.minHeight - Minimum height constraint
2326
+ * @param props.w - Width property (overrides fullWidth)
2327
+ * @param props.h - Height value
2328
+ * @param props.maxW - Maximum width constraint
2329
+ * @param props.minW - Minimum width constraint
2330
+ * @param props.maxH - Maximum height constraint
2331
+ * @param props.minH - Minimum height constraint
2319
2332
  *
2320
2333
  * @returns A partial ViewStyle object containing the computed layout styles
2321
2334
  *
2322
2335
  * @remarks
2323
- * Property precedence for width: width > w > fullWidth
2336
+ * Property precedence for width: w > fullWidth
2324
2337
  * The function processes width properties in order of specificity, with more specific
2325
2338
  * properties overriding more general ones.
2326
2339
  */
@@ -2330,43 +2343,38 @@ function getLayoutStyles(props) {
2330
2343
  if (props.fullWidth) {
2331
2344
  styles.width = '100%';
2332
2345
  }
2333
- // Handle shorthand width prop first
2346
+ // Handle width prop (overrides fullWidth)
2334
2347
  if (props.w !== undefined) {
2335
2348
  styles.width = props.w;
2336
2349
  }
2337
- // Handle specific dimensions (override fullWidth and w if specified)
2338
- if (props.width !== undefined) {
2339
- styles.width = props.width;
2340
- }
2341
- if (props.height !== undefined) {
2342
- styles.height = props.height;
2350
+ if (props.h !== undefined) {
2351
+ styles.height = props.h;
2343
2352
  }
2344
- if (props.maxWidth !== undefined) {
2345
- styles.maxWidth = props.maxWidth;
2353
+ if (props.maxW !== undefined) {
2354
+ styles.maxWidth = props.maxW;
2346
2355
  }
2347
- if (props.minWidth !== undefined) {
2348
- styles.minWidth = props.minWidth;
2356
+ if (props.minW !== undefined) {
2357
+ styles.minWidth = props.minW;
2349
2358
  }
2350
- if (props.maxHeight !== undefined) {
2351
- styles.maxHeight = props.maxHeight;
2359
+ if (props.maxH !== undefined) {
2360
+ styles.maxHeight = props.maxH;
2352
2361
  }
2353
- if (props.minHeight !== undefined) {
2354
- styles.minHeight = props.minHeight;
2362
+ if (props.minH !== undefined) {
2363
+ styles.minHeight = props.minH;
2355
2364
  }
2356
2365
  return styles;
2357
2366
  }
2358
2367
  // Helper to extract layout props from component props
2359
2368
  function extractLayoutProps(props) {
2360
- const { fullWidth, w, width, height, maxWidth, minWidth, maxHeight, minHeight, ...otherProps } = props;
2369
+ const { fullWidth, w, h, maxW, minW, maxH, minH, ...otherProps } = props;
2361
2370
  const layoutProps = {
2362
2371
  fullWidth,
2363
2372
  w,
2364
- width,
2365
- height,
2366
- maxWidth,
2367
- minWidth,
2368
- maxHeight,
2369
- minHeight
2373
+ h,
2374
+ maxW,
2375
+ minW,
2376
+ maxH,
2377
+ minH
2370
2378
  };
2371
2379
  return { layoutProps, otherProps };
2372
2380
  }
@@ -2635,7 +2643,7 @@ async function measureAsyncPerformance(name, fn) {
2635
2643
  const OVERLAY_CACHE_LIMIT = 200;
2636
2644
  const overlayPositionCache = new Map();
2637
2645
  const formatNumber = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : 0;
2638
- const createOverlayCacheKey = (anchorX, anchorY, anchorWidth, anchorHeight, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary) => {
2646
+ const createOverlayCacheKey = (anchorX, anchorY, anchorWidth, anchorHeight, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary, matchAnchorWidth) => {
2639
2647
  return [
2640
2648
  formatNumber(anchorX),
2641
2649
  formatNumber(anchorY),
@@ -2652,6 +2660,7 @@ const createOverlayCacheKey = (anchorX, anchorY, anchorWidth, anchorHeight, over
2652
2660
  flip ? '1' : '0',
2653
2661
  shift ? '1' : '0',
2654
2662
  formatNumber(boundary),
2663
+ matchAnchorWidth ? '1' : '0',
2655
2664
  Platform.OS,
2656
2665
  ].join('|');
2657
2666
  };
@@ -2697,11 +2706,12 @@ registerViewportListeners();
2697
2706
  * Enhanced overlay positioning that prevents off-screen rendering with intelligent caching
2698
2707
  */
2699
2708
  function calculateOverlayPositionEnhanced(anchor, overlay, options = {}) {
2700
- const { placement = 'auto', offset = 8, viewport = getViewport(), strategy = 'fixed', flip = true, shift = true, boundary = 8, fallbackPlacements = ['bottom', 'top', 'right', 'left'] } = options;
2709
+ const { placement = 'auto', offset = 8, viewport = getViewport(), strategy = 'fixed', flip = true, shift = true, boundary = 8, fallbackPlacements = ['bottom', 'top', 'right', 'left'], matchAnchorWidth = false, } = options;
2701
2710
  // If overlay height is unknown/small (pre-measure), use a heuristic height for decision-making
2702
2711
  // This helps avoid choosing "bottom" when near the bottom of the viewport.
2703
2712
  const heuristicHeight = Math.max(overlay.height || 0, 240);
2704
- const overlayWidth = overlay.width;
2713
+ // When matchAnchorWidth is true, use anchor width for overlay width calculations
2714
+ const overlayWidth = matchAnchorWidth ? anchor.width : overlay.width;
2705
2715
  const overlayHeight = overlay.height > 0 ? overlay.height : heuristicHeight;
2706
2716
  // Account for scroll if using absolute positioning
2707
2717
  const scrollX = (Platform.OS === 'web' && strategy === 'absolute')
@@ -2712,7 +2722,7 @@ function calculateOverlayPositionEnhanced(anchor, overlay, options = {}) {
2712
2722
  const anchorX = anchor.x + scrollX;
2713
2723
  const anchorY = anchor.y + scrollY;
2714
2724
  // Check cache first
2715
- const cacheKey = createOverlayCacheKey(anchorX, anchorY, anchor.width, anchor.height, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary);
2725
+ const cacheKey = createOverlayCacheKey(anchorX, anchorY, anchor.width, anchor.height, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary, matchAnchorWidth);
2716
2726
  const cached = getCachedOverlayPosition(cacheKey);
2717
2727
  if (cached) {
2718
2728
  return cached;
@@ -2780,10 +2790,14 @@ function calculateOverlayPositionEnhanced(anchor, overlay, options = {}) {
2780
2790
  // If enforcement moved the overlay to the opposite vertical side to avoid covering the anchor,
2781
2791
  // reflect that in the returned placement so arrows/styles are consistent.
2782
2792
  const resolvedPlacement = adjustPlacementIfMoved(finalPlacement, result, anchorRect);
2793
+ // When matchAnchorWidth is true, preserve anchor width without constraining to maxWidth
2794
+ const computedFinalWidth = matchAnchorWidth
2795
+ ? anchor.width
2796
+ : Math.min(result.finalWidth || overlay.width, result.maxWidth || overlay.width);
2783
2797
  const finalResult = {
2784
2798
  ...result,
2785
2799
  placement: resolvedPlacement,
2786
- finalWidth: Math.min(result.finalWidth || overlay.width, result.maxWidth || overlay.width),
2800
+ finalWidth: computedFinalWidth,
2787
2801
  finalHeight: Math.min(result.finalHeight || overlay.height, result.maxHeight || overlay.height),
2788
2802
  };
2789
2803
  // Cache the result
@@ -3540,9 +3554,14 @@ const Text = (allProps) => {
3540
3554
  }
3541
3555
  // Platform-specific rendering
3542
3556
  if (Platform.OS === 'web' && isHTMLVariant(htmlTag)) {
3543
- const webStyles = convertToWebStyles([textStyles, spacingStyles, style,
3544
- // make sure text is side to side
3545
- { display: 'inline' }
3557
+ const styleArray = Array.isArray(style) ? style : [style];
3558
+ const hasDisplayOverride = styleArray.some((item) => item && ((item.display !== undefined) || (item.whiteSpace !== undefined)));
3559
+ const webStyles = convertToWebStyles([
3560
+ textStyles,
3561
+ spacingStyles,
3562
+ style,
3563
+ // default to inline unless caller explicitly requests display/whitespace behavior
3564
+ ...(hasDisplayOverride ? [] : [{ display: 'inline' }]),
3546
3565
  ]);
3547
3566
  // Handle text selection for web
3548
3567
  if (!selectable) {
@@ -6153,31 +6172,29 @@ const Button = (allProps) => {
6153
6172
  const { getDuration } = useReducedMotion$1();
6154
6173
  const { announce } = useAnnouncer();
6155
6174
  const { ref: focusRef} = useFocus(`button-${title || 'button'}`);
6175
+ // Track measured width for loading state preservation
6176
+ const [measuredWidth, setMeasuredWidth] = useState(null);
6177
+ const wasLoadingRef = useRef(loading);
6178
+ // When loading starts, we want to preserve the current measured width
6179
+ // When loading ends, clear the preserved width so it can resize naturally
6180
+ useEffect(() => {
6181
+ if (!loading && wasLoadingRef.current) {
6182
+ // Loading just ended, allow width to be recalculated
6183
+ setMeasuredWidth(null);
6184
+ }
6185
+ wasLoadingRef.current = loading;
6186
+ }, [loading]);
6187
+ const handleLayout = useCallback((event) => {
6188
+ // Only update measured width when not loading, so we capture the natural content width
6189
+ if (!loading) {
6190
+ const { width } = event.nativeEvent.layout;
6191
+ setMeasuredWidth(width);
6192
+ }
6193
+ // Call user's onLayout if provided
6194
+ onLayout === null || onLayout === void 0 ? void 0 : onLayout(event);
6195
+ }, [loading, onLayout]);
6156
6196
  // Determine button content - children takes precedence over title
6157
6197
  const buttonContent = children !== null && children !== void 0 ? children : title;
6158
- // Calculate minimum width for loading state based on content and size
6159
- const calculateMinWidth = () => {
6160
- if (!buttonContent || typeof buttonContent !== 'string')
6161
- return undefined;
6162
- // Base character width estimates based on size
6163
- const charWidthBySize = {
6164
- xs: 6,
6165
- sm: 7,
6166
- md: 8,
6167
- lg: 9,
6168
- xl: 10,
6169
- '2xl': 11,
6170
- '3xl': 12
6171
- };
6172
- const sizeKey = typeof size === 'string' ? size : 'md';
6173
- const charWidth = charWidthBySize[sizeKey] || 8;
6174
- const horizontalPadding = getSpacing(size) * 2; // Left + right padding
6175
- // Estimate content width: character count * average char width + padding
6176
- const contentWidth = buttonContent.length * charWidth + horizontalPadding;
6177
- // Add space for loader and gap when loading
6178
- const loaderWidth = getFontSize$1(size) + getSpacing(size) / 2; // Loader + margin
6179
- return Math.max(contentWidth, contentWidth + loaderWidth);
6180
- };
6181
6198
  // Determine what content to show based on loading state
6182
6199
  const displayContent = loading
6183
6200
  ? (loadingTitle !== undefined ? loadingTitle : '')
@@ -6216,12 +6233,12 @@ const Button = (allProps) => {
6216
6233
  const shadowStyles = getShadowStyles({ shadow: effectiveShadow }, theme, 'button');
6217
6234
  const spacingStyles = getSpacingStyles(spacingProps);
6218
6235
  const baseLayoutStyles = getLayoutStyles(layoutProps);
6219
- // Apply minimum width when loading to prevent size changes
6220
- const calculatedMinWidth = calculateMinWidth();
6236
+ // Apply measured width when loading to prevent size changes
6237
+ // Use the actual measured width instead of character-based estimates
6221
6238
  const layoutStyles = {
6222
6239
  ...baseLayoutStyles,
6223
- ...(loading && calculatedMinWidth && !layoutProps.width && !layoutProps.w && !layoutProps.fullWidth
6224
- ? { minWidth: calculatedMinWidth }
6240
+ ...(loading && measuredWidth && !layoutProps.w && !layoutProps.fullWidth
6241
+ ? { width: measuredWidth, minWidth: measuredWidth }
6225
6242
  : {})
6226
6243
  };
6227
6244
  const iconSpacing = getSpacing(size) / 2;
@@ -6414,7 +6431,7 @@ const Button = (allProps) => {
6414
6431
  ...(Platform.OS !== 'web' ? { transform: [{ translateY: 1 }] } : {})
6415
6432
  } : null,
6416
6433
  style,
6417
- ], onPress: handleInternalPress, onLayout: onLayout, onPressIn: handlePressIn, onPressOut: handlePressOut, onHoverIn: onHoverIn, onHoverOut: onHoverOut, onLongPress: onLongPress, disabled: isInteractionDisabled, children: [variant === 'gradient' && hasLinearGradient$4 && (jsx(OptionalLinearGradient$6, { colors: resolvedCustomColor
6434
+ ], onPress: handleInternalPress, onLayout: handleLayout, onPressIn: handlePressIn, onPressOut: handlePressOut, onHoverIn: onHoverIn, onHoverOut: onHoverOut, onLongPress: onLongPress, disabled: isInteractionDisabled, children: [variant === 'gradient' && hasLinearGradient$4 && (jsx(OptionalLinearGradient$6, { colors: resolvedCustomColor
6418
6435
  ? [resolvedCustomColor, theme.colors.primary[7]]
6419
6436
  : [theme.colors.primary[5], theme.colors.primary[7]], style: { position: 'absolute', zIndex: -1, top: 0, left: 0, right: 0, bottom: 0, borderRadius: radiusStyles.borderRadius }, start: { x: 0, y: 0 }, end: { x: 1, y: 0 } })), loading ? (jsxs(Fragment, { children: [jsx(Loader, { size: size, color: getLoaderColor(), style: !isIconButton ? { marginRight: iconSpacing } : undefined }), !isIconButton && renderButtonContent(displayContent)] })) : isIconButton ? (
6420
6437
  // Icon-only button
@@ -6654,18 +6671,22 @@ const useSafeSafeAreaInsets = () => {
6654
6671
  return { top: 0, bottom: 0, left: 0, right: 0 };
6655
6672
  }
6656
6673
  };
6657
- function Dialog({ visible, variant = 'modal', title, children, closable = true, backdrop = true, backdropClosable = true, shouldClose = false, onClose, width, height, style, bottomSheetSwipeZone = 'container', }) {
6674
+ function Dialog({ visible, variant = 'modal', title, children, closable = true, backdrop = true, backdropClosable = true, shouldClose = false, onClose, w, h, radius, style, showHeader = true, bottomSheetSwipeZone = 'container', }) {
6658
6675
  const theme = useTheme();
6659
6676
  const { isRTL } = useDirection();
6660
6677
  const insets = useSafeSafeAreaInsets();
6661
6678
  const { width: screenWidth, height: screenHeight } = useWindowDimensions();
6662
6679
  const horizontalMargin = 32; // safety margin so dialog never touches edges
6663
6680
  const isNativePlatform = Platform.OS === 'ios' || Platform.OS === 'android';
6664
- const defaultModalMaxWidth = Math.min((width || 500), Math.max(200, screenWidth - horizontalMargin));
6681
+ const defaultModalMaxWidth = Math.min((w || 500), Math.max(200, screenWidth - horizontalMargin));
6665
6682
  const modalEffectiveWidth = variant !== 'modal'
6666
6683
  ? undefined
6667
6684
  : Math.min(defaultModalMaxWidth, screenWidth - horizontalMargin);
6668
- const bottomSheetMaxWidth = Math.min(width ? width : (isNativePlatform ? 720 : Math.min(600, screenWidth - horizontalMargin)), screenWidth);
6685
+ const bottomSheetMaxWidth = Math.min(w ? w : (isNativePlatform ? 720 : Math.min(600, screenWidth - horizontalMargin)), screenWidth);
6686
+ const resolvedRadius = radius !== null && radius !== void 0 ? radius : (variant === 'bottomsheet' ? 20 : 16);
6687
+ const resolvedMaxHeight = variant === 'bottomsheet'
6688
+ ? (h !== null && h !== void 0 ? h : Math.max(200, screenHeight - insets.top - 24))
6689
+ : (variant === 'fullscreen' ? '100%' : (h || '90%'));
6669
6690
  const invokeOnClose = useCallback(() => {
6670
6691
  onClose === null || onClose === void 0 ? void 0 : onClose();
6671
6692
  }, [onClose]);
@@ -6721,20 +6742,12 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6721
6742
  event.preventDefault();
6722
6743
  }
6723
6744
  }
6724
- // Allow dragging in both directions but apply rubber band for upward movement
6725
- const dragDistance = gestureState.dy;
6726
- if (dragDistance >= 0) {
6727
- // Downward movement - apply subtle resistance for better feel
6728
- const resistance = 0.8;
6729
- const resistedDistance = dragDistance * resistance + (dragDistance > 100 ? (dragDistance - 100) * 0.2 : 0);
6730
- slideAnim.value = resistedDistance;
6731
- }
6732
- else {
6733
- // Upward movement - apply rubber band effect
6734
- const upwardResistance = 0.3;
6735
- const rubberBandDistance = dragDistance * upwardResistance;
6736
- slideAnim.value = rubberBandDistance;
6737
- }
6745
+ // Only allow downward movement (dismiss gesture)
6746
+ const dragDistance = Math.max(0, gestureState.dy);
6747
+ // Downward movement - apply subtle resistance for better feel
6748
+ const resistance = 0.8;
6749
+ const resistedDistance = dragDistance * resistance + (dragDistance > 100 ? (dragDistance - 100) * 0.2 : 0);
6750
+ slideAnim.value = resistedDistance;
6738
6751
  }
6739
6752
  },
6740
6753
  onPanResponderRelease: (_, gestureState) => {
@@ -6891,8 +6904,8 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6891
6904
  }, [shouldClose]);
6892
6905
  const isDark = theme.colorScheme === 'dark';
6893
6906
  const surfaceColor = isDark ? theme.backgrounds.surface : '#FFFFFF';
6894
- const borderColor = isDark ? theme.colors.gray[6] : '#E1E3E6';
6895
- const headerBg = isDark ? theme.backgrounds.subtle : surfaceColor;
6907
+ isDark ? theme.colors.gray[6] : '#E1E3E6';
6908
+ const headerBg = surfaceColor;
6896
6909
  const contentBg = surfaceColor;
6897
6910
  const dynamicStyles = StyleSheet.create({
6898
6911
  backdrop: {
@@ -6903,24 +6916,28 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6903
6916
  }, // Allow backdropFilter on web
6904
6917
  modalContainer: {
6905
6918
  backgroundColor: contentBg,
6906
- borderRadius: variant === 'fullscreen' ? 0 : (variant === 'bottomsheet' ? 20 : 16),
6907
- borderBottomLeftRadius: variant === 'bottomsheet' ? 0 : undefined,
6908
- borderBottomRightRadius: variant === 'bottomsheet' ? 0 : undefined,
6919
+ borderRadius: variant === 'fullscreen' ? 0 : resolvedRadius,
6920
+ ...(variant === 'bottomsheet' ? {
6921
+ borderBottomLeftRadius: 0,
6922
+ borderBottomRightRadius: 0,
6923
+ } : {}),
6924
+ overflow: 'hidden', // Clip content to border radius
6909
6925
  // Clamp width to viewport (minus margins) while respecting provided width
6910
6926
  maxWidth: variant === 'fullscreen'
6911
6927
  ? '100%'
6912
6928
  : variant === 'bottomsheet'
6913
6929
  ? bottomSheetMaxWidth
6914
6930
  : defaultModalMaxWidth,
6915
- maxHeight: variant === 'fullscreen' ? '100%' : (height || '90%'),
6931
+ maxHeight: resolvedMaxHeight,
6916
6932
  width: variant === 'fullscreen'
6917
6933
  ? '100%'
6918
6934
  : variant === 'modal'
6919
6935
  ? modalEffectiveWidth || 'auto'
6920
6936
  : '100%',
6921
- height: variant === 'fullscreen' ? '100%' : (variant === 'modal' ? undefined : undefined),
6922
- // For modal variant, remove flex to allow fit-content behavior
6923
- ...(variant === 'modal' ? {} : { flex: 1 }),
6937
+ // Fullscreen uses 100% height, others auto-size to content
6938
+ height: variant === 'fullscreen' ? '100%' : undefined,
6939
+ // Only fullscreen should stretch to fill
6940
+ ...(variant === 'fullscreen' ? { flex: 1 } : {}),
6924
6941
  // Ensure minWidth never exceeds viewport clamp
6925
6942
  minWidth: variant === 'modal' ? Math.min(300, Math.max(200, screenWidth - horizontalMargin)) : undefined,
6926
6943
  alignSelf: variant === 'bottomsheet' ? 'center' : 'center',
@@ -6946,24 +6963,27 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6946
6963
  }
6947
6964
  : Platform.OS === 'android' && variant !== 'fullscreen'
6948
6965
  ? { elevation: 16, }
6949
- : {
6950
- boxShadow: 'none',
6951
- height: '100%',
6952
- position: 'absolute',
6953
- }),
6966
+ : variant === 'fullscreen'
6967
+ ? {
6968
+ boxShadow: 'none',
6969
+ height: '100%',
6970
+ position: 'absolute',
6971
+ }
6972
+ : { boxShadow: 'none' }),
6954
6973
  }, // Allow boxShadow on web
6955
6974
  header: {
6956
6975
  alignItems: 'center',
6957
- backgroundColor: headerBg,
6958
- borderBottomColor: borderColor,
6959
- borderBottomWidth: variant === 'fullscreen' ? 0 : 1,
6976
+ backgroundColor: showHeader ? headerBg : 'transparent',
6977
+ // borderBottomColor: showHeader ? borderColor : 'transparent',
6978
+ // borderBottomWidth: showHeader && variant !== 'fullscreen' ? 1 : 0,
6960
6979
  flexDirection: isRTL ? 'row-reverse' : 'row',
6961
6980
  justifyContent: 'space-between',
6962
6981
  padding: 20,
6982
+ paddingBottom: title ? 0 : 20,
6963
6983
  },
6964
6984
  content: {
6965
- // For modal variant, remove flex to allow fit-content behavior
6966
- ...(variant === 'modal' ? {} : { flex: 1 }),
6985
+ // Only fullscreen content should stretch
6986
+ ...(variant === 'fullscreen' ? { flex: 1 } : {}),
6967
6987
  alignSelf: 'stretch',
6968
6988
  backgroundColor: contentBg,
6969
6989
  padding: variant === 'fullscreen' ? 0 : 20,
@@ -7019,8 +7039,10 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
7019
7039
  });
7020
7040
  const bottomSheetAnimatedStyle = useAnimatedStyle(() => {
7021
7041
  if (variant === 'bottomsheet') {
7042
+ // Clamp to 0 minimum to prevent seeing "under" the sheet
7043
+ const clampedY = Math.max(0, slideAnim.value);
7022
7044
  return {
7023
- transform: [{ translateY: slideAnim.value }],
7045
+ transform: [{ translateY: clampedY }],
7024
7046
  };
7025
7047
  }
7026
7048
  return {};
@@ -7037,7 +7059,7 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
7037
7059
  animatedStyle = bottomSheetAnimatedStyle;
7038
7060
  }
7039
7061
  return (jsxs(Animated.View, { style: [dynamicStyles.modalContainer, animatedStyle], ...(variant === 'bottomsheet' && bottomSheetSwipeZone === 'container' && panHandlers ? panHandlers : {}), children: [variant === 'bottomsheet' && (jsx(View, { style: dynamicStyles.dragHandleContainer, ...(bottomSheetSwipeZone === 'handle' && panHandlers ? panHandlers : {}), children: jsx(View, { style: dynamicStyles.dragHandle }) })), (title !== null &&
7040
- title && closable) && (jsxs(View, { style: dynamicStyles.header, children: [jsx(Text, { variant: "h3", color: "text", children: title || '' }), closable && (jsx(Button, { variant: "ghost", onPress: handleClose, style: dynamicStyles.closeButton, children: jsx(Icon, { name: "x", size: "md" }) }))] })), jsx(View, { style: [dynamicStyles.content, style], children: children })] }));
7062
+ title && closable) && (jsxs(View, { style: dynamicStyles.header, children: [jsx(Text, { variant: "h3", color: "text", children: title || '' }), closable && variant !== 'bottomsheet' && (jsx(Button, { variant: "ghost", onPress: handleClose, style: dynamicStyles.closeButton, children: jsx(Icon, { name: "x", size: "md" }) }))] })), jsx(View, { style: [dynamicStyles.content, style], children: children })] }));
7041
7063
  };
7042
7064
  return (jsx(Modal, { visible: visible, transparent: true, animationType: "none", statusBarTranslucent: variant === 'fullscreen', children: jsxs(Animated.View, { style: [
7043
7065
  dynamicStyles.backdrop,
@@ -7246,7 +7268,7 @@ function DialogRenderer() {
7246
7268
  return null;
7247
7269
  // Render the topmost dialog
7248
7270
  const topDialog = dialogs[dialogs.length - 1];
7249
- return (jsx(Dialog, { visible: true, variant: topDialog.variant, title: topDialog.title, closable: topDialog.closable, backdrop: topDialog.backdrop, backdropClosable: topDialog.backdropClosable, shouldClose: topDialog.isClosing, onClose: () => removeDialog(topDialog.id), children: topDialog.content }));
7271
+ return (jsx(Dialog, { visible: true, variant: topDialog.variant, title: topDialog.title, closable: topDialog.closable, backdrop: topDialog.backdrop, backdropClosable: topDialog.backdropClosable, shouldClose: topDialog.isClosing, onClose: () => removeDialog(topDialog.id), w: topDialog.w, h: topDialog.h, radius: topDialog.radius, style: topDialog.style, showHeader: topDialog.showHeader, children: topDialog.content }));
7250
7272
  }
7251
7273
 
7252
7274
  const Flex = factory((props, ref) => {
@@ -8331,7 +8353,14 @@ const getContrastPreference = () => {
8331
8353
  return 'less';
8332
8354
  return 'no-preference';
8333
8355
  };
8334
- const getColorScheme = () => { var _a, _b; return (_b = (_a = Appearance === null || Appearance === void 0 ? void 0 : Appearance.getColorScheme) === null || _a === void 0 ? void 0 : _a.call(Appearance)) !== null && _b !== void 0 ? _b : 'no-preference'; };
8356
+ const getColorScheme = () => {
8357
+ var _a;
8358
+ const scheme = (_a = Appearance === null || Appearance === void 0 ? void 0 : Appearance.getColorScheme) === null || _a === void 0 ? void 0 : _a.call(Appearance);
8359
+ // Handle 'unspecified' from newer React Native versions
8360
+ if (scheme === 'light' || scheme === 'dark')
8361
+ return scheme;
8362
+ return 'no-preference';
8363
+ };
8335
8364
  const getReducedMotion = async () => {
8336
8365
  if (Platform.OS === 'web') {
8337
8366
  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function')
@@ -8556,7 +8585,13 @@ function useDeviceInfo(options = {}) {
8556
8585
  useEffect(() => {
8557
8586
  var _a;
8558
8587
  const colorSubscription = (_a = Appearance === null || Appearance === void 0 ? void 0 : Appearance.addChangeListener) === null || _a === void 0 ? void 0 : _a.call(Appearance, ({ colorScheme: scheme }) => {
8559
- setColorScheme(scheme !== null && scheme !== void 0 ? scheme : 'no-preference');
8588
+ // Handle 'unspecified' from newer React Native versions
8589
+ if (scheme === 'light' || scheme === 'dark') {
8590
+ setColorScheme(scheme);
8591
+ }
8592
+ else {
8593
+ setColorScheme('no-preference');
8594
+ }
8560
8595
  });
8561
8596
  const mediaListeners = [];
8562
8597
  let boldSubscription;
@@ -9101,7 +9136,7 @@ function SpotlightRoot({ query, onQueryChange, children, opened = false, onClose
9101
9136
  const targetWidth = Math.min(560, Math.max(280, screenWidth - horizontalMargin));
9102
9137
  // (Hotkey registration moved to main Spotlight component for access to store.toggle())
9103
9138
  const fullscreen = shouldUseModal;
9104
- return (jsx(Dialog, { visible: opened, onClose: onClose, variant: fullscreen ? 'fullscreen' : 'modal', backdrop: true, backdropClosable: true, width: fullscreen ? undefined : targetWidth, title: null, style: [
9139
+ return (jsx(Dialog, { visible: opened, onClose: onClose, variant: fullscreen ? 'fullscreen' : 'modal', backdrop: true, backdropClosable: true, w: fullscreen ? undefined : targetWidth, title: null, style: [
9105
9140
  styles$e.spotlightModal,
9106
9141
  fullscreen && { width: '100%', height: '100%', maxHeight: '100%', borderRadius: 0, position: 'fixed', top: 0, left: 0 },
9107
9142
  !fullscreen && {
@@ -9663,6 +9698,23 @@ function generateUniversalCSS() {
9663
9698
  xl: '88em'
9664
9699
  };
9665
9700
  const universalCSS = `
9701
+ /* Reset browser default input styles to prevent double borders */
9702
+ input, textarea, select {
9703
+ outline: none !important;
9704
+ -webkit-appearance: none !important;
9705
+ -moz-appearance: none !important;
9706
+ appearance: none !important;
9707
+ }
9708
+
9709
+ input:focus, textarea:focus, select:focus {
9710
+ outline: none !important;
9711
+ }
9712
+
9713
+ /* Ensure React Native Web focusable elements don't show browser outlines */
9714
+ [data-focusable="true"]:focus {
9715
+ outline: none !important;
9716
+ }
9717
+
9666
9718
  /* Color scheme based visibility */
9667
9719
  .platform-blocks-light-hidden {
9668
9720
  display: none !important;
@@ -9709,12 +9761,14 @@ function UniversalCSS() {
9709
9761
  return;
9710
9762
  }
9711
9763
  // Check if styles are already injected
9712
- const existingStyle = document.getElementById('platform-blocks-universal-css');
9713
- if (existingStyle) {
9764
+ let styleElement = document.getElementById('platform-blocks-universal-css');
9765
+ if (styleElement) {
9766
+ // Update content if it exists (in case CSS changed)
9767
+ styleElement.textContent = css;
9714
9768
  return;
9715
9769
  }
9716
9770
  // Create and inject styles
9717
- const styleElement = document.createElement('style');
9771
+ styleElement = document.createElement('style');
9718
9772
  styleElement.id = 'platform-blocks-universal-css';
9719
9773
  styleElement.textContent = css;
9720
9774
  document.head.appendChild(styleElement);
@@ -9732,593 +9786,6 @@ function UniversalCSS() {
9732
9786
  return null;
9733
9787
  }
9734
9788
 
9735
- /**
9736
- * Core Ability class for managing permissions
9737
- */
9738
- class AbilityCore {
9739
- constructor(rules = []) {
9740
- this.rules = [];
9741
- this.cache = new Map();
9742
- this.rules = [...rules];
9743
- }
9744
- /**
9745
- * Check if action is allowed on subject
9746
- */
9747
- can(action, subject, field) {
9748
- return this.check(action, subject, field).allowed;
9749
- }
9750
- /**
9751
- * Check if action is forbidden on subject
9752
- */
9753
- cannot(action, subject, field) {
9754
- return !this.can(action, subject, field);
9755
- }
9756
- /**
9757
- * Get detailed permission check result
9758
- */
9759
- check(action, subject, field) {
9760
- const cacheKey = this.getCacheKey(action, subject, field);
9761
- if (this.cache.has(cacheKey)) {
9762
- return this.cache.get(cacheKey);
9763
- }
9764
- const result = this.performCheck(action, subject, field);
9765
- this.cache.set(cacheKey, result);
9766
- return result;
9767
- }
9768
- /**
9769
- * Update ability rules and clear cache
9770
- */
9771
- update(rules) {
9772
- this.rules = [...rules];
9773
- this.cache.clear();
9774
- }
9775
- /**
9776
- * Get all current rules
9777
- */
9778
- getRules() {
9779
- return [...this.rules];
9780
- }
9781
- /**
9782
- * Clear all rules and cache
9783
- */
9784
- clear() {
9785
- this.rules = [];
9786
- this.cache.clear();
9787
- }
9788
- /**
9789
- * Perform the actual permission check
9790
- */
9791
- performCheck(action, subject, field) {
9792
- // Start with denied by default
9793
- let result = {
9794
- allowed: false,
9795
- reason: 'No matching permission rule found'
9796
- };
9797
- // Check rules in order (later rules can override earlier ones)
9798
- for (const rule of this.rules) {
9799
- if (this.ruleMatches(rule, action, subject, field)) {
9800
- result = {
9801
- allowed: !rule.inverted,
9802
- reason: rule.reason || (rule.inverted ? 'Access denied by rule' : 'Access granted by rule'),
9803
- rule
9804
- };
9805
- }
9806
- }
9807
- return result;
9808
- }
9809
- /**
9810
- * Check if a rule matches the current permission check
9811
- */
9812
- ruleMatches(rule, action, subject, field) {
9813
- // Check action match
9814
- const actions = Array.isArray(rule.action) ? rule.action : [rule.action];
9815
- if (!actions.includes(action) && !actions.includes('*')) {
9816
- return false;
9817
- }
9818
- // Check subject match
9819
- const subjects = Array.isArray(rule.subject) ? rule.subject : [rule.subject];
9820
- if (!this.subjectMatches(subjects, subject)) {
9821
- return false;
9822
- }
9823
- // Check field match (if specified)
9824
- if (field && rule.fields && !rule.fields.includes(field)) {
9825
- return false;
9826
- }
9827
- // Check conditions (if subject is an object)
9828
- if (rule.conditions && typeof subject === 'object' && subject !== null) {
9829
- return this.conditionsMatch(rule.conditions, subject);
9830
- }
9831
- return true;
9832
- }
9833
- /**
9834
- * Check if subject matches any of the rule subjects
9835
- */
9836
- subjectMatches(ruleSubjects, checkSubject) {
9837
- for (const ruleSubject of ruleSubjects) {
9838
- if (ruleSubject === '*')
9839
- return true;
9840
- if (ruleSubject === checkSubject)
9841
- return true;
9842
- // Handle class/constructor matching
9843
- if (typeof ruleSubject === 'function' && typeof checkSubject === 'object') {
9844
- if (checkSubject instanceof ruleSubject)
9845
- return true;
9846
- if (checkSubject.constructor === ruleSubject)
9847
- return true;
9848
- }
9849
- // Handle string matching for object types
9850
- if (typeof ruleSubject === 'string' && typeof checkSubject === 'object') {
9851
- if (checkSubject.__type === ruleSubject)
9852
- return true;
9853
- if (checkSubject.type === ruleSubject)
9854
- return true;
9855
- if (checkSubject.constructor.name === ruleSubject)
9856
- return true;
9857
- }
9858
- }
9859
- return false;
9860
- }
9861
- /**
9862
- * Check if conditions match the subject object
9863
- */
9864
- conditionsMatch(conditions, subject) {
9865
- for (const [key, expectedValue] of Object.entries(conditions)) {
9866
- const actualValue = subject[key];
9867
- if (!this.valuesMatch(actualValue, expectedValue)) {
9868
- return false;
9869
- }
9870
- }
9871
- return true;
9872
- }
9873
- /**
9874
- * Check if two values match (handles various comparison types)
9875
- */
9876
- valuesMatch(actual, expected) {
9877
- // Exact match
9878
- if (actual === expected)
9879
- return true;
9880
- // Array contains check
9881
- if (Array.isArray(expected) && expected.includes(actual))
9882
- return true;
9883
- if (Array.isArray(actual) && actual.includes(expected))
9884
- return true;
9885
- // Function/predicate check
9886
- if (typeof expected === 'function') {
9887
- return expected(actual);
9888
- }
9889
- // Regex match for strings
9890
- if (expected instanceof RegExp && typeof actual === 'string') {
9891
- return expected.test(actual);
9892
- }
9893
- // Object comparison (shallow)
9894
- if (typeof expected === 'object' && typeof actual === 'object' && expected !== null && actual !== null) {
9895
- return Object.keys(expected).every(key => this.valuesMatch(actual[key], expected[key]));
9896
- }
9897
- return false;
9898
- }
9899
- /**
9900
- * Generate cache key for permission check
9901
- */
9902
- getCacheKey(action, subject, field) {
9903
- const subjectKey = typeof subject === 'object'
9904
- ? JSON.stringify(subject)
9905
- : String(subject);
9906
- return `${action}:${subjectKey}:${field || ''}`;
9907
- }
9908
- }
9909
- /**
9910
- * Create a new Ability instance
9911
- */
9912
- function createAbility(rules = []) {
9913
- return new AbilityCore(rules);
9914
- }
9915
-
9916
- /**
9917
- * Permission Context
9918
- */
9919
- const PermissionContext = createContext(null);
9920
- /**
9921
- * Permission Provider Component
9922
- */
9923
- const PermissionProvider = ({ rules = [], user, children, dev = {} }) => {
9924
- const [ability] = useState(() => createAbility(rules));
9925
- const [currentUser, setCurrentUser] = useState(user);
9926
- const updateAbility = useCallback((newRules) => {
9927
- ability.update(newRules);
9928
- }, [ability]);
9929
- const can = useCallback((action, subject, field) => {
9930
- const result = ability.can(action, subject, field);
9931
- if (dev.logChecks) {
9932
- console.log(`[Permissions] Can ${action} ${subject}${field ? `.${field}` : ''}:`, result);
9933
- }
9934
- return result;
9935
- }, [ability, dev.logChecks]);
9936
- const cannot = useCallback((action, subject, field) => {
9937
- const result = ability.cannot(action, subject, field);
9938
- if (dev.logChecks) {
9939
- console.log(`[Permissions] Cannot ${action} ${subject}${field ? `.${field}` : ''}:`, result);
9940
- }
9941
- return result;
9942
- }, [ability, dev.logChecks]);
9943
- const setUser = useCallback((newUser) => {
9944
- setCurrentUser(newUser);
9945
- }, []);
9946
- const contextValue = useMemo(() => ({
9947
- ability,
9948
- updateAbility,
9949
- can,
9950
- cannot,
9951
- user: currentUser,
9952
- setUser
9953
- }), [ability, updateAbility, can, cannot, currentUser, setUser]);
9954
- return React__default.createElement(PermissionContext.Provider, { value: contextValue }, children);
9955
- };
9956
- /**
9957
- * Hook to access permission context
9958
- */
9959
- const usePermissions = (options = {}) => {
9960
- const context = useContext(PermissionContext);
9961
- if (!context) {
9962
- if (options.required) {
9963
- throw new Error('usePermissions must be used within a PermissionProvider');
9964
- }
9965
- if (options.debug) {
9966
- console.warn('[Permissions] usePermissions called outside of PermissionProvider');
9967
- }
9968
- // Return a fallback context that allows everything
9969
- return {
9970
- ability: createAbility([{ action: '*', subject: '*' }]),
9971
- updateAbility: () => { },
9972
- can: () => true,
9973
- cannot: () => false,
9974
- user: null,
9975
- setUser: () => { }
9976
- };
9977
- }
9978
- return context;
9979
- };
9980
- /**
9981
- * Hook to get the current ability instance
9982
- */
9983
- const useAbility = () => {
9984
- const { ability } = usePermissions();
9985
- return ability;
9986
- };
9987
-
9988
- /**
9989
- * Can Component - Renders children if permission is granted
9990
- */
9991
- const Can = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
9992
- const { ability: contextAbility } = usePermissions();
9993
- const ability = customAbility || contextAbility;
9994
- // Development passthrough
9995
- if (passthrough && __DEV__) {
9996
- return React__default.createElement(View, { style, testID }, children);
9997
- }
9998
- const hasPermission = subject
9999
- ? ability.can(action, subject, field)
10000
- : ability.can(action, '*', field);
10001
- if (hasPermission) {
10002
- return React__default.createElement(View, { style, testID }, children);
10003
- }
10004
- return React__default.createElement(View, { style, testID }, fallback);
10005
- };
10006
- /**
10007
- * Can Component with conditions - For object-level permissions
10008
- */
10009
- const CanWithConditions = ({ I: action, this: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
10010
- const { ability: contextAbility } = usePermissions();
10011
- const ability = customAbility || contextAbility;
10012
- // Development passthrough
10013
- if (passthrough && __DEV__) {
10014
- return React__default.createElement(View, { style, testID }, children);
10015
- }
10016
- const hasPermission = ability.can(action, subject, field);
10017
- if (hasPermission) {
10018
- return React__default.createElement(View, { style, testID }, children);
10019
- }
10020
- return React__default.createElement(View, { style, testID }, fallback);
10021
- };
10022
- /**
10023
- * Cannot Component - Renders children if permission is NOT granted
10024
- */
10025
- const Cannot = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
10026
- const { ability: contextAbility } = usePermissions();
10027
- const ability = customAbility || contextAbility;
10028
- // Development passthrough
10029
- if (passthrough && __DEV__) {
10030
- return React__default.createElement(View, { style, testID }, fallback);
10031
- }
10032
- const hasPermission = subject
10033
- ? ability.can(action, subject, field)
10034
- : ability.can(action, '*', field);
10035
- if (!hasPermission) {
10036
- return React__default.createElement(View, { style, testID }, children);
10037
- }
10038
- return React__default.createElement(View, { style, testID }, fallback);
10039
- };
10040
- /**
10041
- * Permission Gate - Requires ALL permissions to pass
10042
- */
10043
- const PermissionGate = ({ permissions, children, fallback = null, ability: customAbility, onUnauthorized }) => {
10044
- const { ability: contextAbility } = usePermissions();
10045
- const ability = customAbility || contextAbility;
10046
- const allPermissionsGranted = permissions.every(({ action, subject, field }) => ability.can(action, subject, field));
10047
- React__default.useEffect(() => {
10048
- if (!allPermissionsGranted && onUnauthorized) {
10049
- onUnauthorized();
10050
- }
10051
- }, [allPermissionsGranted, onUnauthorized]);
10052
- if (allPermissionsGranted) {
10053
- return React__default.createElement(React__default.Fragment, null, children);
10054
- }
10055
- return React__default.createElement(React__default.Fragment, null, fallback);
10056
- };
10057
- /**
10058
- * Higher-Order Component for permission checking
10059
- */
10060
- function withCan(action, subject, field) {
10061
- return function CanHOC(Component) {
10062
- const WrappedComponent = (props) => {
10063
- const { fallback, ...componentProps } = props;
10064
- return React__default.createElement(Can, { I: action, a: subject, field, fallback }, React__default.createElement(Component, componentProps));
10065
- };
10066
- WrappedComponent.displayName = `withCan(${Component.displayName || Component.name})`;
10067
- return WrappedComponent;
10068
- };
10069
- }
10070
- /**
10071
- * Higher-Order Component for permission denial checking
10072
- */
10073
- function withCannot(action, subject, field) {
10074
- return function CannotHOC(Component) {
10075
- const WrappedComponent = (props) => {
10076
- const { fallback, ...componentProps } = props;
10077
- return React__default.createElement(Cannot, { I: action, a: subject, field, fallback }, React__default.createElement(Component, componentProps));
10078
- };
10079
- WrappedComponent.displayName = `withCannot(${Component.displayName || Component.name})`;
10080
- return WrappedComponent;
10081
- };
10082
- }
10083
-
10084
- /**
10085
- * Fluent API for building permissions
10086
- */
10087
- class PermissionBuilder {
10088
- constructor() {
10089
- this.rules = [];
10090
- }
10091
- /**
10092
- * Grant permission
10093
- */
10094
- allow(action, subject, field) {
10095
- this.rules.push({
10096
- action,
10097
- subject: subject || '*',
10098
- fields: field ? [field] : undefined,
10099
- inverted: false
10100
- });
10101
- return this;
10102
- }
10103
- /**
10104
- * Deny permission
10105
- */
10106
- forbid(action, subject, field) {
10107
- this.rules.push({
10108
- action,
10109
- subject: subject || '*',
10110
- fields: field ? [field] : undefined,
10111
- inverted: true
10112
- });
10113
- return this;
10114
- }
10115
- /**
10116
- * Conditional permission
10117
- */
10118
- allowIf(action, subject, conditions, field) {
10119
- this.rules.push({
10120
- action,
10121
- subject: subject || '*',
10122
- fields: field ? [field] : undefined,
10123
- inverted: false,
10124
- conditions
10125
- });
10126
- return this;
10127
- }
10128
- /**
10129
- * Conditional denial
10130
- */
10131
- forbidIf(action, subject, conditions, field) {
10132
- this.rules.push({
10133
- action,
10134
- subject: subject || '*',
10135
- fields: field ? [field] : undefined,
10136
- inverted: true,
10137
- conditions
10138
- });
10139
- return this;
10140
- }
10141
- /**
10142
- * Grant all actions on a subject
10143
- */
10144
- manage(subject) {
10145
- this.rules.push({
10146
- action: '*',
10147
- subject,
10148
- inverted: false
10149
- });
10150
- return this;
10151
- }
10152
- /**
10153
- * Forbid all actions on a subject
10154
- */
10155
- forbidAll(subject) {
10156
- this.rules.push({
10157
- action: '*',
10158
- subject,
10159
- inverted: true
10160
- });
10161
- return this;
10162
- }
10163
- /**
10164
- * Role-based permissions
10165
- */
10166
- role(roleName, callback) {
10167
- const roleBuilder = new RoleBuilder(roleName);
10168
- callback(roleBuilder);
10169
- this.rules.push(...roleBuilder.getRules());
10170
- return this;
10171
- }
10172
- /**
10173
- * Build the ability with all rules
10174
- */
10175
- build() {
10176
- return new AbilityCore(this.rules);
10177
- }
10178
- /**
10179
- * Get all rules
10180
- */
10181
- getRules() {
10182
- return [...this.rules];
10183
- }
10184
- /**
10185
- * Clear all rules
10186
- */
10187
- clear() {
10188
- this.rules = [];
10189
- return this;
10190
- }
10191
- /**
10192
- * Merge rules from another builder
10193
- */
10194
- merge(other) {
10195
- this.rules.push(...other.getRules());
10196
- return this;
10197
- }
10198
- }
10199
- /**
10200
- * Role-specific permission builder
10201
- */
10202
- class RoleBuilder {
10203
- constructor(roleName) {
10204
- this.roleName = roleName;
10205
- this.rules = [];
10206
- }
10207
- /**
10208
- * Grant permission for this role
10209
- */
10210
- can(action, subject, field) {
10211
- this.rules.push({
10212
- action,
10213
- subject: subject || '*',
10214
- fields: field ? [field] : undefined,
10215
- inverted: false,
10216
- conditions: { role: this.roleName }
10217
- });
10218
- return this;
10219
- }
10220
- /**
10221
- * Deny permission for this role
10222
- */
10223
- cannot(action, subject, field) {
10224
- this.rules.push({
10225
- action,
10226
- subject: subject || '*',
10227
- fields: field ? [field] : undefined,
10228
- inverted: true,
10229
- conditions: { role: this.roleName }
10230
- });
10231
- return this;
10232
- }
10233
- /**
10234
- * Manage all actions on subject for this role
10235
- */
10236
- manage(subject) {
10237
- this.rules.push({
10238
- action: '*',
10239
- subject,
10240
- inverted: false,
10241
- conditions: { role: this.roleName }
10242
- });
10243
- return this;
10244
- }
10245
- /**
10246
- * Get all rules for this role
10247
- */
10248
- getRules() {
10249
- return [...this.rules];
10250
- }
10251
- }
10252
- /**
10253
- * Common permission patterns
10254
- */
10255
- class PermissionPatterns {
10256
- /**
10257
- * Admin permissions - can do everything
10258
- */
10259
- static admin() {
10260
- return new PermissionBuilder()
10261
- .manage('*');
10262
- }
10263
- /**
10264
- * User permissions - basic CRUD on own resources
10265
- */
10266
- static user(userId) {
10267
- return new PermissionBuilder()
10268
- .allowIf('read', 'User', { id: userId })
10269
- .allowIf('update', 'User', { id: userId })
10270
- .allowIf('delete', 'User', { id: userId })
10271
- .allow('read', 'public');
10272
- }
10273
- /**
10274
- * Guest permissions - read-only public content
10275
- */
10276
- static guest() {
10277
- return new PermissionBuilder()
10278
- .allow('read', 'public');
10279
- }
10280
- /**
10281
- * Moderator permissions - manage content but not users
10282
- */
10283
- static moderator() {
10284
- return new PermissionBuilder()
10285
- .manage('Content')
10286
- .manage('Comment')
10287
- .allow('read', 'User')
10288
- .forbid('delete', 'User');
10289
- }
10290
- /**
10291
- * Owner permissions - full control over owned resources
10292
- */
10293
- static owner(ownerId) {
10294
- return new PermissionBuilder()
10295
- .allowIf('*', '*', { ownerId })
10296
- .allow('create', '*');
10297
- }
10298
- }
10299
- /**
10300
- * Helper function to create a new permission builder
10301
- */
10302
- function permissions() {
10303
- return new PermissionBuilder();
10304
- }
10305
- /**
10306
- * Helper function to create ability from rules array
10307
- */
10308
- function defineAbility(callback) {
10309
- const builder = new PermissionBuilder();
10310
- callback(builder);
10311
- return builder.build();
10312
- }
10313
- /**
10314
- * Helper function to create common role-based abilities
10315
- */
10316
- function defineRoleAbility(role, callback) {
10317
- const roleBuilder = new RoleBuilder(role);
10318
- callback(roleBuilder);
10319
- return new AbilityCore(roleBuilder.getRules());
10320
- }
10321
-
10322
9789
  const ThemeModeContext = createContext(null);
10323
9790
  // Default persistence using localStorage (web only)
10324
9791
  const defaultPersistence = {
@@ -10448,7 +9915,6 @@ const OverlayBoundary = React__default.memo(function OverlayBoundary({ enabled,
10448
9915
  const I18nBoundary = React__default.memo(function I18nBoundary({ locale, fallbackLocale, resources, children }) {
10449
9916
  return (jsx(I18nProvider, { initial: { locale, fallbackLocale, resources }, children: children }));
10450
9917
  });
10451
- const DEFAULT_PERMISSION_RULES = [{ action: '*', subject: '*' }];
10452
9918
  /**
10453
9919
  * Internal component that uses the enhanced theme mode when config is provided
10454
9920
  */
@@ -10486,30 +9952,20 @@ function PlatformBlocksContent({ children, theme, inherit = true, withCSSVariabl
10486
9952
  document.documentElement.setAttribute('data-platform-blocks-color-scheme', target);
10487
9953
  }
10488
9954
  }, [effectiveColorScheme, osColorScheme]);
10489
- const mainContent = (jsxs(ThemeBoundary, { theme: resolvedTheme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, withGlobalCSS: withGlobalCSS, children: [children, withSpotlight && jsx(SpotlightController, { config: spotlightConfig })] }));
10490
- return (jsx(OverlayBoundary, { enabled: withOverlays, children: mainContent }));
9955
+ const mainContent = (jsx(ThemeBoundary, { theme: resolvedTheme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, withGlobalCSS: withGlobalCSS, children: jsxs(OverlayBoundary, { enabled: withOverlays, children: [children, withSpotlight && jsx(SpotlightController, { config: spotlightConfig })] }) }));
9956
+ return mainContent;
10491
9957
  }
10492
9958
  /**
10493
9959
  * Main provider component for Platform Blocks library
10494
9960
  * Provides theme context and injects CSS variables
10495
9961
  */
10496
- function PlatformBlocksProvider({ children, theme, inherit = true, withCSSVariables = true, cssVariablesSelector = ':root', colorSchemeMode = 'auto', withOverlays = true, withSpotlight = false, withGlobalCSS = true, themeModeConfig, spotlightConfig, locale = 'en', fallbackLocale = 'en', i18nResources, direction, haptics, permissions }) {
9962
+ function PlatformBlocksProvider({ children, theme, inherit = true, withCSSVariables = true, cssVariablesSelector = ':root', colorSchemeMode = 'auto', withOverlays = true, withSpotlight = false, withGlobalCSS = true, themeModeConfig, spotlightConfig, locale = 'en', fallbackLocale = 'en', i18nResources, direction, haptics }) {
10497
9963
  const i18nStore = useMemo(() => i18nResources || { en: { translation: {} } }, [i18nResources]);
10498
9964
  const content = (jsx(PlatformBlocksContent, { theme: theme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, colorSchemeMode: colorSchemeMode, withOverlays: withOverlays, withSpotlight: withSpotlight, withGlobalCSS: withGlobalCSS, spotlightConfig: spotlightConfig, themeModeConfig: themeModeConfig, children: children }));
10499
9965
  const themedTree = themeModeConfig ? (jsx(ThemeModeProvider, { config: themeModeConfig, children: content })) : (content);
10500
9966
  const directionConfig = direction === false ? null : (direction !== null && direction !== void 0 ? direction : {});
10501
9967
  const hapticsConfig = haptics === false ? null : (haptics !== null && haptics !== void 0 ? haptics : {});
10502
- const permissionConfig = permissions === false ? null : (() => {
10503
- const base = { ...(permissions !== null && permissions !== void 0 ? permissions : {}) };
10504
- if (base.rules === undefined) {
10505
- base.rules = DEFAULT_PERMISSION_RULES;
10506
- }
10507
- return base;
10508
- })();
10509
9968
  let enhancedTree = themedTree;
10510
- if (permissionConfig) {
10511
- enhancedTree = (jsx(PermissionProvider, { ...permissionConfig, children: enhancedTree }));
10512
- }
10513
9969
  if (hapticsConfig) {
10514
9970
  enhancedTree = (jsx(HapticsProvider, { ...hapticsConfig, children: enhancedTree }));
10515
9971
  }
@@ -10999,14 +10455,18 @@ function usePopoverPositioning(isOpen, options = {}) {
10999
10455
  // Get popover dimensions
11000
10456
  // Always use measureElement for robustness across platforms (RNW refs may not expose getBoundingClientRect)
11001
10457
  let popoverDimensions = { width: 200, height: 100 }; // sensible defaults for initial calculation
10458
+ let hasMeasuredPopover = false;
11002
10459
  if (popoverRef.current) {
11003
10460
  const popoverRect = await measureElement(popoverRef);
11004
10461
  if (popoverRect.width > 0 && popoverRect.height > 0) {
11005
10462
  popoverDimensions = { width: popoverRect.width, height: popoverRect.height };
10463
+ hasMeasuredPopover = true;
11006
10464
  }
11007
10465
  }
11008
10466
  // Calculate optimal position
11009
10467
  const result = calculateOverlayPositionEnhanced(anchorRect, popoverDimensions, positioningOptionsRef.current);
10468
+ // Mark whether this position is based on actual measurements
10469
+ result._hasMeasuredPopover = hasMeasuredPopover;
11010
10470
  setPosition(result);
11011
10471
  }
11012
10472
  catch (error) {
@@ -12432,9 +11892,10 @@ const Row = ({ direction = 'row', gap = 'sm', ...props }) => {
12432
11892
  };
12433
11893
  /**
12434
11894
  * Column component - alias for Flex with direction="column"
11895
+ * Defaults to fullWidth={true} since vertical layouts typically fill available width
12435
11896
  */
12436
- const Column = ({ direction = 'column', gap = 'sm', ...props }) => {
12437
- return jsx(Flex, { direction: direction, gap: gap, ...props });
11897
+ const Column = ({ direction = 'column', gap = 'sm', fullWidth = true, ...props }) => {
11898
+ return jsx(Flex, { direction: direction, gap: gap, fullWidth: fullWidth, ...props });
12438
11899
  };
12439
11900
  Row.displayName = 'Row';
12440
11901
 
@@ -14549,35 +14010,101 @@ function createNativeHighlighter(theme, isDark, variant = 'code', overrides) {
14549
14010
  };
14550
14011
  }
14551
14012
 
14552
- // Prism light build for JSX/TSX (react-syntax-highlighter)
14013
+ // Syntax highlighter - only loaded on web, native uses built-in tokenizer
14014
+ // These are initialized lazily on first use to avoid Metro bundling issues
14553
14015
  let PrismSyntaxHighlighter = null;
14554
14016
  let prismLightTheme = null;
14555
14017
  let prismDarkTheme = null;
14556
- if (Platform.OS === 'web') {
14557
- PrismSyntaxHighlighter = resolveOptionalModule('react-syntax-highlighter', {
14558
- accessor: (module) => module.PrismLight,
14559
- devWarning: 'react-syntax-highlighter not found, CodeBlock will use basic formatting',
14560
- });
14561
- if (PrismSyntaxHighlighter) {
14562
- const registerLanguage = (moduleId, name) => {
14563
- const languageModule = resolveOptionalModule(moduleId, { accessor: (mod) => mod.default });
14564
- if (languageModule) {
14565
- PrismSyntaxHighlighter.registerLanguage(name, languageModule);
14018
+ let syntaxHighlighterInitialized = false;
14019
+ // Use indirect require via new Function to prevent Metro from statically analyzing imports
14020
+ // Metro bundles ALL require() calls it finds, even in try-catch blocks
14021
+ // new Function() creates a runtime-evaluated require that Metro can't see
14022
+ const safeRequire = (() => {
14023
+ try {
14024
+ // This creates: function(moduleName) { return require(moduleName); }
14025
+ // The string 'require' is not statically analyzable by Metro
14026
+ return new Function('moduleName', 'return require(moduleName)');
14027
+ }
14028
+ catch (_a) {
14029
+ return null;
14030
+ }
14031
+ })();
14032
+ function initSyntaxHighlighter() {
14033
+ if (syntaxHighlighterInitialized)
14034
+ return;
14035
+ syntaxHighlighterInitialized = true;
14036
+ // Only attempt to load on web
14037
+ if (Platform.OS !== 'web')
14038
+ return;
14039
+ if (!safeRequire)
14040
+ return;
14041
+ try {
14042
+ const rsh = safeRequire('react-syntax-highlighter');
14043
+ PrismSyntaxHighlighter = rsh.PrismLight;
14044
+ if (PrismSyntaxHighlighter) {
14045
+ // Register languages
14046
+ try {
14047
+ const jsx = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/jsx').default;
14048
+ PrismSyntaxHighlighter.registerLanguage('jsx', jsx);
14566
14049
  }
14567
- };
14568
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/jsx', 'jsx');
14569
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/tsx', 'tsx');
14570
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/typescript', 'typescript');
14571
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/javascript', 'javascript');
14572
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/json', 'json');
14573
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/bash', 'bash');
14574
- prismLightTheme = resolveOptionalModule('react-syntax-highlighter/dist/esm/styles/prism/prism', {
14575
- accessor: (mod) => mod.default,
14576
- });
14577
- prismDarkTheme = resolveOptionalModule('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus', {
14578
- accessor: (mod) => mod.default,
14579
- devWarning: 'Failed to load prism vsc-dark-plus theme, falling back to prism',
14580
- });
14050
+ catch (_a) {
14051
+ // Language not available
14052
+ }
14053
+ try {
14054
+ const tsx = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/tsx').default;
14055
+ PrismSyntaxHighlighter.registerLanguage('tsx', tsx);
14056
+ }
14057
+ catch (_b) {
14058
+ // Language not available
14059
+ }
14060
+ try {
14061
+ const ts = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/typescript').default;
14062
+ PrismSyntaxHighlighter.registerLanguage('typescript', ts);
14063
+ }
14064
+ catch (_c) {
14065
+ // Language not available
14066
+ }
14067
+ try {
14068
+ const js = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/javascript').default;
14069
+ PrismSyntaxHighlighter.registerLanguage('javascript', js);
14070
+ }
14071
+ catch (_d) {
14072
+ // Language not available
14073
+ }
14074
+ try {
14075
+ const json = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/json').default;
14076
+ PrismSyntaxHighlighter.registerLanguage('json', json);
14077
+ }
14078
+ catch (_e) {
14079
+ // Language not available
14080
+ }
14081
+ try {
14082
+ const bash = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/bash').default;
14083
+ PrismSyntaxHighlighter.registerLanguage('bash', bash);
14084
+ }
14085
+ catch (_f) {
14086
+ // Language not available
14087
+ }
14088
+ // Load themes
14089
+ try {
14090
+ prismLightTheme = safeRequire('react-syntax-highlighter/dist/esm/styles/prism/prism').default;
14091
+ }
14092
+ catch (_g) {
14093
+ // Theme not available
14094
+ }
14095
+ try {
14096
+ prismDarkTheme = safeRequire('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus').default;
14097
+ }
14098
+ catch (_h) {
14099
+ // Theme not available
14100
+ }
14101
+ }
14102
+ }
14103
+ catch (_j) {
14104
+ // react-syntax-highlighter not installed, will use native fallback
14105
+ if (__DEV__) {
14106
+ console.warn('[platform-blocks] react-syntax-highlighter not found, CodeBlock will use basic formatting');
14107
+ }
14581
14108
  }
14582
14109
  }
14583
14110
  const NO_HIGHLIGHTS = new Set();
@@ -14801,6 +14328,8 @@ const FloatingCopyControls = ({ visible, code, onCopy, topOffset, isWeb }) => (j
14801
14328
  }, children: jsx(CopyButton, { value: code, onCopy: onCopy, iconOnly: true, size: "sm", tooltip: "Copy code", tooltipPosition: "left", style: { minHeight: 32, minWidth: 32 } }) }));
14802
14329
  const CodeBlock = (props) => {
14803
14330
  var _a, _b, _c;
14331
+ // Initialize syntax highlighter on first render (web only)
14332
+ React__default.useMemo(() => initSyntaxHighlighter(), []);
14804
14333
  const { children, title, fileName, fileIcon, language = 'tsx', showLineNumbers = false, highlight = true, fullWidth = true, showCopyButton = true, onCopy, style, textStyle, titleStyle, highlightLines, spoiler = false, spoilerMaxHeight = 160, variant = 'code', promptSymbol = '$', githubUrl, fileHeader = false, colors, wrap = true, ...rest } = props;
14805
14334
  const { spacingProps, otherProps } = extractSpacingProps(rest);
14806
14335
  const spacingStyles = getSpacingStyles(spacingProps);
@@ -14815,6 +14344,7 @@ const CodeBlock = (props) => {
14815
14344
  const [hovered, setHovered] = React__default.useState(false);
14816
14345
  const [codeHeight, setCodeHeight] = React__default.useState(null);
14817
14346
  const isWeb = Platform.OS === 'web';
14347
+ const webWhitespaceStyle = React__default.useMemo(() => (isWeb ? { whiteSpace: wrap ? 'pre-wrap' : 'pre', display: 'block' } : null), [isWeb, wrap]);
14818
14348
  const showFloatingCopy = showCopyButton && !title && !fileName;
14819
14349
  const showCopyVisible = !isWeb ? showFloatingCopy : showFloatingCopy && hovered;
14820
14350
  const codeData = React__default.useMemo(() => {
@@ -14848,6 +14378,7 @@ const CodeBlock = (props) => {
14848
14378
  boxSizing: 'border-box',
14849
14379
  paddingLeft: showLineNumbers ? 0 : 12,
14850
14380
  paddingRight: showLineNumbers ? 0 : 12,
14381
+ whiteSpace: wrap ? 'pre-wrap' : 'pre',
14851
14382
  }), [showLineNumbers, wrap]);
14852
14383
  const highlightedLineStyle = React__default.useMemo(() => ({
14853
14384
  backgroundColor: highlightBackgroundColor,
@@ -14859,6 +14390,18 @@ const CodeBlock = (props) => {
14859
14390
  const tokenLines = React__default.useMemo(() => (highlight ? nativeHighlighter(codeData.transformed) : null), [highlight, nativeHighlighter, codeData.transformed]);
14860
14391
  const shouldVirtualizeNative = !isWeb && codeData.lineCount >= LONG_LIST_THRESHOLD;
14861
14392
  const lineHeight = (_c = styles.codeText.lineHeight) !== null && _c !== void 0 ? _c : 18;
14393
+ const normalizeTokenText = React__default.useCallback((text, tokenIndex) => {
14394
+ if (!isWeb || !text)
14395
+ return text;
14396
+ const replaceSpaces = (value) => value.replace(/\t/g, ' ').replace(/ /g, '\u00A0');
14397
+ if (tokenIndex === 0) {
14398
+ return text.replace(/^[\t ]+/, (match) => replaceSpaces(match));
14399
+ }
14400
+ if (text.trim().length === 0) {
14401
+ return replaceSpaces(text);
14402
+ }
14403
+ return text;
14404
+ }, [isWeb]);
14862
14405
  const buildNativeLine = React__default.useCallback((line, index, appendNewline, includeKey) => {
14863
14406
  var _a;
14864
14407
  const lineNumber = index + 1;
@@ -14867,13 +14410,14 @@ const CodeBlock = (props) => {
14867
14410
  const lineStyles = [
14868
14411
  styles.codeText,
14869
14412
  textStyle,
14413
+ webWhitespaceStyle,
14870
14414
  wrap ? { flexWrap: 'wrap' } : { flexWrap: 'nowrap', width: 'auto' },
14871
14415
  ];
14872
14416
  if (isLineHighlighted) {
14873
14417
  lineStyles.push(styles.highlightedLine(isDark, highlightColors));
14874
14418
  }
14875
- return (jsxs(Text, { selectable: true, style: lineStyles, children: [showLineNumbers ? (jsx(Text, { style: { color: lineNumberColor, opacity: 0.7 }, children: `${String(lineNumber).padStart(lineNumberWidth, ' ')} | ` })) : null, tokens.map((token, tokenIdx) => (jsx(Text, { style: { color: token.color }, children: token.text || ' ' }, `${lineNumber}-${tokenIdx}`))), appendNewline ? '\n' : null] }, includeKey ? `line-${lineNumber}` : undefined));
14876
- }, [fallbackColor, highlightColors, highlightSet, isDark, lineNumberColor, lineNumberWidth, showLineNumbers, styles.codeText, styles.highlightedLine, textStyle, tokenLines, wrap]);
14419
+ return (jsxs(Text, { selectable: true, style: lineStyles, children: [showLineNumbers ? (jsx(Text, { style: { color: lineNumberColor, opacity: 0.7 }, children: `${String(lineNumber).padStart(lineNumberWidth, ' ')} | ` })) : null, tokens.map((token, tokenIdx) => (jsx(Text, { style: { color: token.color }, children: normalizeTokenText(token.text || ' ', tokenIdx) }, `${lineNumber}-${tokenIdx}`))), appendNewline ? '\n' : null] }, includeKey ? `line-${lineNumber}` : undefined));
14420
+ }, [fallbackColor, highlightColors, highlightSet, isDark, lineNumberColor, lineNumberWidth, normalizeTokenText, showLineNumbers, styles.codeText, styles.highlightedLine, textStyle, tokenLines, webWhitespaceStyle, wrap]);
14877
14421
  const renderWebCode = React__default.useMemo(() => {
14878
14422
  if (!(isWeb && highlight && PrismSyntaxHighlighter)) {
14879
14423
  return null;
@@ -14887,7 +14431,13 @@ const CodeBlock = (props) => {
14887
14431
  lineHeight: '18px',
14888
14432
  display: 'block',
14889
14433
  width: '100%',
14890
- }, codeTagProps: { style: { fontFamily: styles.codeText.fontFamily } }, wrapLongLines: wrap, wrapLines: wrap, showLineNumbers: prismShowLineNumbers, lineNumberStyle: hideLineNumbersVisually
14434
+ whiteSpace: wrap ? 'pre-wrap' : 'pre',
14435
+ }, codeTagProps: {
14436
+ style: {
14437
+ fontFamily: styles.codeText.fontFamily,
14438
+ whiteSpace: wrap ? 'pre-wrap' : 'pre',
14439
+ },
14440
+ }, wrapLongLines: wrap, wrapLines: wrap, showLineNumbers: prismShowLineNumbers, lineNumberStyle: hideLineNumbersVisually
14891
14441
  ? { display: 'none' }
14892
14442
  : { opacity: 0.55, paddingRight: 12, userSelect: 'none' }, lineProps: (lineNumber) => {
14893
14443
  const style = { ...baseLineStyle };
@@ -14920,13 +14470,13 @@ const CodeBlock = (props) => {
14920
14470
  ]);
14921
14471
  const renderNativeCode = React__default.useMemo(() => {
14922
14472
  if (!codeData.lineCount) {
14923
- return (jsx(Text, { selectable: true, style: [styles.codeText, textStyle], children: ' ' }));
14473
+ return (jsx(Text, { selectable: true, style: [styles.codeText, textStyle, webWhitespaceStyle], children: ' ' }));
14924
14474
  }
14925
14475
  if (shouldVirtualizeNative) {
14926
14476
  return (jsx(FlatList, { data: codeData.lines, keyExtractor: (_, index) => `line-${index}`, renderItem: ({ item, index }) => buildNativeLine(item, index, false, false), initialNumToRender: 20, maxToRenderPerBatch: 40, windowSize: 7, removeClippedSubviews: true, getItemLayout: (_, index) => ({ length: lineHeight, offset: lineHeight * index, index }) }));
14927
14477
  }
14928
- return (jsx(Text, { selectable: true, style: [styles.codeText, textStyle], children: codeData.lines.map((line, idx) => buildNativeLine(line, idx, idx < codeData.lineCount - 1, true)) }));
14929
- }, [buildNativeLine, codeData.lineCount, codeData.lines, lineHeight, shouldVirtualizeNative, styles.codeText, textStyle]);
14478
+ return (jsx(Text, { selectable: true, style: [styles.codeText, textStyle, webWhitespaceStyle], children: codeData.lines.map((line, idx) => buildNativeLine(line, idx, idx < codeData.lineCount - 1, true)) }));
14479
+ }, [buildNativeLine, codeData.lineCount, codeData.lines, lineHeight, shouldVirtualizeNative, styles.codeText, textStyle, webWhitespaceStyle]);
14930
14480
  const codeContent = renderWebCode !== null && renderWebCode !== void 0 ? renderWebCode : renderNativeCode;
14931
14481
  const scrollableCodeContent = wrap ? (codeContent) : (jsx(ScrollView, { horizontal: true, bounces: false, showsHorizontalScrollIndicator: true, showsVerticalScrollIndicator: false, contentContainerStyle: { flexGrow: 1 }, style: { width: '100%' }, children: jsx(View, { style: { flexGrow: 1 }, children: codeContent }) }));
14932
14482
  let wrappedCodeContent = scrollableCodeContent;
@@ -16531,11 +16081,13 @@ const BrandButton = (props) => {
16531
16081
  return {
16532
16082
  backgroundColor: 'transparent',
16533
16083
  borderColor: brandConfig.borderColor || brandConfig.backgroundColor,
16084
+ paddingHorizontal: 16,
16534
16085
  };
16535
16086
  case 'ghost':
16536
16087
  return {
16537
16088
  backgroundColor: 'transparent',
16538
16089
  borderColor: 'transparent',
16090
+ paddingHorizontal: 16,
16539
16091
  };
16540
16092
  case 'link':
16541
16093
  return { backgroundColor: 'transparent', borderColor: 'transparent' };
@@ -16543,7 +16095,7 @@ const BrandButton = (props) => {
16543
16095
  return {
16544
16096
  backgroundColor: 'white',
16545
16097
  borderColor: 'transparent',
16546
- paddingHorizontal: 0,
16098
+ paddingHorizontal: 16,
16547
16099
  minWidth: 0,
16548
16100
  height: 'auto',
16549
16101
  color: 'black'
@@ -16552,6 +16104,7 @@ const BrandButton = (props) => {
16552
16104
  return {
16553
16105
  backgroundColor: brandConfig.backgroundColor,
16554
16106
  borderColor: brandConfig.borderColor || brandConfig.backgroundColor,
16107
+ paddingHorizontal: 16,
16555
16108
  };
16556
16109
  }
16557
16110
  })();
@@ -17128,8 +16681,12 @@ const createInputStyles = (theme, isRTL = false) => {
17128
16681
  // Remove any web-specific styling that could interfere
17129
16682
  ...(typeof window !== 'undefined' && {
17130
16683
  outlineWidth: 0,
16684
+ outlineStyle: 'none',
17131
16685
  border: 'none',
16686
+ borderWidth: 0,
16687
+ boxShadow: 'none',
17132
16688
  backgroundColor: 'transparent',
16689
+ boxSizing: 'border-box',
17133
16690
  }),
17134
16691
  },
17135
16692
  inputContainer: {
@@ -17257,6 +16814,7 @@ const TextInputBase = factory((props, ref) => {
17257
16814
  const { value, onChangeText, onEnter, label, description, error, helperText, disabled, required, size = 'md', withAsterisk, placeholder, startSection, endSection, focused: focusedProp, accessibilityLabel, accessibilityHint, testID, textInputProps, style, radius, secureTextEntry, clearable, clearButtonLabel, onClear, inputRef, name, keyboardFocusId, ...rest } = otherProps;
17258
16815
  const renderDisclaimer = useDisclaimer(disclaimerData.disclaimer, disclaimerData.disclaimerProps);
17259
16816
  const [focused, setFocused] = useState(false);
16817
+ const [cursorVisible, setCursorVisible] = useState(true);
17260
16818
  const theme = useTheme();
17261
16819
  const { isRTL } = useDirection();
17262
16820
  const internalInputRef = useRef(null);
@@ -17328,6 +16886,16 @@ const TextInputBase = factory((props, ref) => {
17328
16886
  return '';
17329
16887
  return '•'.repeat(length);
17330
16888
  }, [isSecureEntry, normalizedValue]);
16889
+ // Blinking cursor for secure entry (simple interval toggle)
16890
+ useEffect(() => {
16891
+ if (focused && isSecureEntry) {
16892
+ setCursorVisible(true);
16893
+ const interval = setInterval(() => {
16894
+ setCursorVisible(v => !v);
16895
+ }, 530);
16896
+ return () => clearInterval(interval);
16897
+ }
16898
+ }, [focused, isSecureEntry]);
17331
16899
  const textColor = (_a = flattenedInputStyle === null || flattenedInputStyle === void 0 ? void 0 : flattenedInputStyle.color) !== null && _a !== void 0 ? _a : (styleProps.disabled ? theme.text.disabled : theme.text.primary);
17332
16900
  const resolvedInputStyle = useMemo(() => {
17333
16901
  const base = [styles.input];
@@ -17429,7 +16997,12 @@ const TextInputBase = factory((props, ref) => {
17429
16997
  }
17430
16998
  }, [keyboardManager, pendingFocusTarget, focusTargetId]);
17431
16999
  const disclaimerNode = renderDisclaimer();
17432
- return (jsxs(View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxs(View, { style: styles.inputContainer, children: [startSection && (jsx(View, { style: styles.startSection, children: startSection })), jsxs(View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsx(TextInput, { ref: assignInputRef, value: value, onChangeText: onChangeText, onFocus: handleFocus, onBlur: handleBlur, onSubmitEditing: handleSubmitEditing, editable: !disabled, placeholder: placeholder, placeholderTextColor: theme.text.muted, style: resolvedInputStyle, selectionColor: selectionColorProp !== null && selectionColorProp !== void 0 ? selectionColorProp : textColor, testID: testID, secureTextEntry: isSecureEntry, ...inputAccessibilityProps, ...restTextInputProps }), isSecureEntry && maskedValue.length > 0 && (jsx(Text$1, { pointerEvents: "none", accessible: false, style: overlayStyle, numberOfLines: 1, ellipsizeMode: "clip", children: maskedValue }))] }), (showClearButton || endSection) && (jsxs(View, { style: styles.endSection, children: [showClearButton && (jsx(ClearButton, { onPress: handleClear, size: size, accessibilityLabel: clearButtonLabelText, hasRightSection: !!endSection })), endSection] }))] }), disclaimerNode, error && (jsx(Text$1, { style: styles.error, role: "alert", accessibilityLiveRegion: "polite", children: error })), helperText && !error && (jsx(Text$1, { style: styles.helperText, children: helperText }))] }));
17000
+ return (jsxs(View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxs(View, { style: styles.inputContainer, children: [startSection && (jsx(View, { style: styles.startSection, children: startSection })), jsxs(View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsx(TextInput, { ref: assignInputRef, value: value, onChangeText: onChangeText, onFocus: handleFocus, onBlur: handleBlur, onSubmitEditing: handleSubmitEditing, editable: !disabled, placeholder: placeholder, placeholderTextColor: theme.text.muted, style: resolvedInputStyle, selectionColor: selectionColorProp !== null && selectionColorProp !== void 0 ? selectionColorProp : textColor, testID: testID, secureTextEntry: isSecureEntry, ...inputAccessibilityProps, ...restTextInputProps }), isSecureEntry && (jsxs(View, { pointerEvents: "none", style: [overlayStyle, { flexDirection: 'row', alignItems: 'center' }], children: [jsx(Text$1, { accessible: false, style: { color: textColor, fontSize: styles.input.fontSize, fontFamily: theme.fontFamily }, numberOfLines: 1, children: maskedValue }), focused && cursorVisible && (jsx(View, { style: {
17001
+ width: 1,
17002
+ height: styles.input.fontSize || 16,
17003
+ backgroundColor: textColor,
17004
+ marginLeft: 1,
17005
+ } }))] }))] }), (showClearButton || endSection) && (jsxs(View, { style: styles.endSection, children: [showClearButton && (jsx(ClearButton, { onPress: handleClear, size: size, accessibilityLabel: clearButtonLabelText, hasRightSection: !!endSection })), endSection] }))] }), disclaimerNode, error && (jsx(Text$1, { style: styles.error, role: "alert", accessibilityLiveRegion: "polite", children: error })), helperText && !error && (jsx(Text$1, { style: styles.helperText, children: helperText }))] }));
17433
17006
  });
17434
17007
 
17435
17008
  const getInputTypeConfig = (type) => {
@@ -17987,18 +17560,19 @@ const useTextAreaStyles = (props) => {
17987
17560
  ? theme.colors.error[5]
17988
17561
  : styleProps.focused
17989
17562
  ? theme.colors.primary[5]
17990
- : styleProps.disabled
17991
- ? theme.backgrounds.border
17992
- : 'transparent',
17563
+ : theme.backgrounds.border,
17993
17564
  borderRadius: DESIGN_TOKENS.radius.lg,
17994
- borderWidth: DESIGN_TOKENS.radius.xs,
17565
+ borderWidth: 2,
17995
17566
  paddingHorizontal: DESIGN_TOKENS.spacing.sm,
17996
17567
  paddingVertical: DESIGN_TOKENS.spacing.xs,
17568
+ // Match Input focus treatment on web
17997
17569
  ...(styleProps.focused && !styleProps.disabled && Platform.OS === 'web' && {
17998
17570
  boxShadow: `0 0 0 2px ${((_a = theme.states) === null || _a === void 0 ? void 0 : _a.focusRing) || theme.colors.primary[2]}`,
17999
17571
  }),
17572
+ // Light elevation similar to Input
18000
17573
  ...(!styleProps.disabled && theme.colorScheme === 'light' && {
18001
17574
  elevation: 1,
17575
+ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
18002
17576
  }),
18003
17577
  opacity: styleProps.disabled ? DESIGN_TOKENS.opacity.disabled : 1,
18004
17578
  },
@@ -18040,7 +17614,7 @@ const TextArea = factory((props, ref) => {
18040
17614
  const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
18041
17615
  const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
18042
17616
  const { value, defaultValue = '', onChangeText, label, disabled = false, required = false, placeholder, error, helperText, description, size = 'md', radius = 'md', rows = 3, minRows = 1, maxRows, autoResize = false, maxLength, showCharCounter = false, resize = 'none', textInputProps = {}, style, testID, clearable, clearButtonLabel, onClear, ...rest } = otherProps;
18043
- const { height } = layoutProps;
17617
+ const { h } = layoutProps;
18044
17618
  const theme = useTheme();
18045
17619
  const { getTextAreaStyles } = useTextAreaStyles({ theme });
18046
17620
  const [focused, setFocused] = useState(false);
@@ -18104,11 +17678,11 @@ const TextArea = factory((props, ref) => {
18104
17678
  const inputContainerStyles = [
18105
17679
  styles.inputContainer,
18106
17680
  radiusStyles,
18107
- { height }
17681
+ { height: h }
18108
17682
  ];
18109
17683
  const textInputStyles = [
18110
17684
  styles.textInput,
18111
- { height: height || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
17685
+ { height: h || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
18112
17686
  textAlignVertical: resize === 'none' ? 'top' : undefined,
18113
17687
  // Disable resizing by user if resize is 'none'
18114
17688
  ...(resize === 'none' ? { resizeMode: 'none' } : {})
@@ -18136,7 +17710,7 @@ const TextArea = factory((props, ref) => {
18136
17710
  const clearLabel = clearButtonLabel || 'Clear input';
18137
17711
  return (jsxs(View, { style: containerStyles, testID: testID, children: [(label || description) && (jsx(FieldHeader, { label: label, description: description, required: required, disabled: disabled, error: !!error })), jsxs(View, { style: [inputContainerStyles, { position: 'relative' }], children: [jsx(TextInput, { ref: assignRef,
18138
17712
  // style={]}
18139
- style: { height: height || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
17713
+ style: { height: h || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
18140
17714
  ...textInputStyles.reduce((acc, style) => ({ ...acc, ...style }), {}),
18141
17715
  textAlignVertical: resize === 'none' ? 'top' : undefined,
18142
17716
  // Disable resizing by user if resize is 'none'
@@ -19680,7 +19254,7 @@ const useSwitchStyles = (props) => {
19680
19254
  ...(Platform.OS === 'web' && { userSelect: 'none' }),
19681
19255
  },
19682
19256
  labelContainer: {
19683
- flex: 1,
19257
+ flexShrink: 1,
19684
19258
  justifyContent: 'center',
19685
19259
  },
19686
19260
  labelDisabled: {
@@ -19849,8 +19423,8 @@ const Switch = factory((rawProps, ref) => {
19849
19423
  const LayoutComponent = isVertical ? Column : Row;
19850
19424
  // For vertical layouts (top/bottom), we want tighter spacing and center alignment
19851
19425
  const layoutProps = isVertical
19852
- ? { gap: 'xs', style: { alignItems: 'center' } }
19853
- : { gap: 'sm', style: { alignItems: 'center' } };
19426
+ ? { gap: 'xs', align: 'center' }
19427
+ : { gap: 'sm', align: 'center' };
19854
19428
  const disclaimerNode = renderDisclaimer();
19855
19429
  return (jsxs(View, { style: spacingStyles, children: [jsxs(LayoutComponent, { ...layoutProps, children: [labelPosition === 'top' && labelElement, labelPosition === 'left' && labelElement, switchElement, labelPosition === 'right' && labelElement, labelPosition === 'bottom' && labelElement] }), disclaimerNode ? (jsx(View, { style: { width: '100%' }, children: disclaimerNode })) : null] }));
19856
19430
  });
@@ -24462,7 +24036,7 @@ const Select = factory((allProps, ref) => {
24462
24036
  var _a;
24463
24037
  const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(allProps);
24464
24038
  const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
24465
- const { value: valueProp, defaultValue, onChange, options, placeholder = 'Select…', size = 'md', radius = 'md', disabled, label, helperText, description, error, renderOption, fullWidth, maxHeight = 260, closeOnSelect = true, clearable, clearButtonLabel, onClear, refocusAfterSelect, keyboardAvoidance = true, } = otherProps;
24039
+ const { value: valueProp, defaultValue, onChange, options, placeholder = 'Select…', size = 'md', radius = 'md', disabled, label, helperText, description, error, renderOption, fullWidth, maxH = 260, closeOnSelect = true, clearable, clearButtonLabel, onClear, refocusAfterSelect, keyboardAvoidance = true, } = otherProps;
24466
24040
  const theme = useTheme();
24467
24041
  const { shouldUseModal, shouldUseOverlay } = useOverlayMode();
24468
24042
  const menuStyles = useMenuStyles();
@@ -24484,6 +24058,7 @@ const Select = factory((allProps, ref) => {
24484
24058
  keyboardAvoidance,
24485
24059
  closeOnClickOutside: true,
24486
24060
  closeOnEscape: true,
24061
+ matchAnchorWidth: true,
24487
24062
  onClose: () => setOpen(false),
24488
24063
  });
24489
24064
  const hasMeasuredDropdownRef = useRef(false);
@@ -24617,11 +24192,11 @@ const Select = factory((allProps, ref) => {
24617
24192
  }, [position === null || position === void 0 ? void 0 : position.finalWidth, triggerWidth]);
24618
24193
  const resolvedDropdownMaxHeight = useMemo(() => {
24619
24194
  const keyboardMax = typeof (position === null || position === void 0 ? void 0 : position.maxHeight) === 'number' ? position.maxHeight : undefined;
24620
- if (typeof maxHeight === 'number') {
24621
- return keyboardMax ? Math.min(maxHeight, keyboardMax) : maxHeight;
24195
+ if (typeof maxH === 'number') {
24196
+ return keyboardMax ? Math.min(maxH, keyboardMax) : maxH;
24622
24197
  }
24623
- return keyboardMax !== null && keyboardMax !== void 0 ? keyboardMax : maxHeight;
24624
- }, [maxHeight, position === null || position === void 0 ? void 0 : position.maxHeight]);
24198
+ return keyboardMax !== null && keyboardMax !== void 0 ? keyboardMax : maxH;
24199
+ }, [maxH, position === null || position === void 0 ? void 0 : position.maxHeight]);
24625
24200
  const handleSelect = useCallback((opt) => {
24626
24201
  if (opt.disabled)
24627
24202
  return;
@@ -24643,7 +24218,7 @@ const Select = factory((allProps, ref) => {
24643
24218
  close();
24644
24219
  }
24645
24220
  }, [closeOnSelect, close, onChange, valueProp, refocusAfterSelect, keyboardManager, focusTrigger, blurTrigger]);
24646
- const listMaxHeight = resolvedDropdownMaxHeight !== null && resolvedDropdownMaxHeight !== void 0 ? resolvedDropdownMaxHeight : maxHeight;
24221
+ const listMaxHeight = resolvedDropdownMaxHeight !== null && resolvedDropdownMaxHeight !== void 0 ? resolvedDropdownMaxHeight : maxH;
24647
24222
  const menu = useMemo(() => {
24648
24223
  const widthStyle = resolvedDropdownWidth && resolvedDropdownWidth > 0
24649
24224
  ? { width: resolvedDropdownWidth, minWidth: resolvedDropdownWidth }
@@ -24656,18 +24231,17 @@ const Select = factory((allProps, ref) => {
24656
24231
  ...(maxHeightStyle !== null && maxHeightStyle !== void 0 ? maxHeightStyle : {}),
24657
24232
  ...(widthStyle !== null && widthStyle !== void 0 ? widthStyle : {}),
24658
24233
  }, children: jsx(FlatList, { data: options, keyExtractor: o => String(o.value), renderItem: ({ item }) => {
24659
- var _a;
24660
24234
  const selected = item.value === value;
24661
24235
  if (renderOption) {
24662
24236
  return jsx(View, { children: renderOption(item, false, selected) });
24663
24237
  }
24664
24238
  const primaryPalette = theme.colors.primary || [];
24665
24239
  const highlightColor = theme.colorScheme === 'dark'
24666
- ? primaryPalette[2] || primaryPalette[3] || theme.text.onPrimary || theme.text.primary
24667
- : primaryPalette[6] || primaryPalette[5] || ((_a = theme.colors.secondary) === null || _a === void 0 ? void 0 : _a[6]) || '#6941C6';
24240
+ ? primaryPalette[5] || primaryPalette[4] || '#60A5FA'
24241
+ : primaryPalette[6] || primaryPalette[5] || '#3B82F6';
24668
24242
  const baseTextColor = item.disabled ? theme.text.disabled : theme.text.primary;
24669
- const accentTextColor = item.disabled ? theme.text.disabled : highlightColor;
24670
- return (jsx(MenuItemButton, { onPress: () => handleSelect(item), disabled: !!item.disabled, active: selected, tone: selected ? 'primary' : 'default', hoverTone: "primary", activeTone: "primary", textColor: baseTextColor, hoverTextColor: accentTextColor, activeTextColor: accentTextColor, compact: true, rounded: false, style: { borderRadius: 0 }, children: item.label }));
24243
+ item.disabled ? theme.text.disabled : highlightColor;
24244
+ return (jsx(MenuItemButton, { onPress: () => handleSelect(item), disabled: !!item.disabled, active: false, tone: "default", hoverTone: "default", activeTone: "default", textColor: baseTextColor, hoverTextColor: baseTextColor, activeTextColor: baseTextColor, startIcon: selected ? jsx(Icon, { name: "check", size: 16, color: highlightColor }) : jsx(View, { style: { width: 16 } }), compact: true, rounded: false, style: { borderRadius: 0 }, children: item.label }));
24671
24245
  }, ItemSeparatorComponent: renderOption ? undefined : ListGroupDivider, style: maxHeightStyle, bounces: false }) }) }));
24672
24246
  }, [resolvedDropdownWidth, listMaxHeight, menuStyles.dropdown, options, value, renderOption, theme.colors.primary, theme.colors.secondary, theme.colorScheme, theme.text.disabled, theme.text.primary, theme.text.onPrimary, handleSelect]);
24673
24247
  useEffect(() => {
@@ -24849,6 +24423,7 @@ const AutoComplete = factory((props, ref) => {
24849
24423
  offset,
24850
24424
  autoUpdate: autoReposition,
24851
24425
  fallbackPlacements,
24426
+ matchAnchorWidth: true,
24852
24427
  });
24853
24428
  // Guard: remember last popover size to avoid re-triggering updatePosition on position-only changes
24854
24429
  const lastPopoverSizeRef = useRef(null);
@@ -24872,13 +24447,12 @@ const AutoComplete = factory((props, ref) => {
24872
24447
  }, radiusStyles), [inputStyleFactory, size, focused, error, disabled, showClearButton, radiusStyles]);
24873
24448
  const clearLabel = clearButtonLabel || 'Clear input';
24874
24449
  const menuHighlightColor = useMemo(() => {
24875
- var _a;
24876
24450
  const primaryPalette = theme.colors.primary || [];
24877
24451
  if (theme.colorScheme === 'dark') {
24878
- return primaryPalette[2] || primaryPalette[3] || theme.text.onPrimary || theme.text.primary;
24452
+ return primaryPalette[5] || primaryPalette[4] || '#60A5FA';
24879
24453
  }
24880
- return primaryPalette[6] || primaryPalette[5] || ((_a = theme.colors.secondary) === null || _a === void 0 ? void 0 : _a[6]) || '#6941C6';
24881
- }, [theme.colors.primary, theme.colors.secondary, theme.colorScheme, theme.text.onPrimary, theme.text.primary]);
24454
+ return primaryPalette[6] || primaryPalette[5] || '#3B82F6';
24455
+ }, [theme.colors.primary, theme.colorScheme]);
24882
24456
  const selectedCount = (_a = selectedValues === null || selectedValues === void 0 ? void 0 : selectedValues.length) !== null && _a !== void 0 ? _a : 0;
24883
24457
  const hasSelectedValues = multiSelect && selectedCount > 0;
24884
24458
  const currentQueryRef = useRef(query);
@@ -25196,8 +24770,8 @@ const AutoComplete = factory((props, ref) => {
25196
24770
  const defaultRenderItem = useCallback((item, index, isSelected = false) => {
25197
24771
  const highlightQuery = highlightMatches ? currentQueryRef.current : undefined;
25198
24772
  const baseTextColor = item.disabled ? theme.text.disabled : theme.text.primary;
25199
- const accentTextColor = item.disabled ? theme.text.disabled : menuHighlightColor;
25200
- return (jsx(MenuItemButton, { onPress: () => handleSelectSuggestion(item), disabled: item.disabled, active: isSelected, tone: isSelected ? 'primary' : 'default', hoverTone: "primary", activeTone: "primary", textColor: baseTextColor, hoverTextColor: accentTextColor, activeTextColor: accentTextColor, compact: true, rounded: false, style: [styles.menuItemButton, suggestionItemStyle], ...(Platform.OS === 'web' ? {
24773
+ item.disabled ? theme.text.disabled : menuHighlightColor;
24774
+ return (jsx(MenuItemButton, { onPress: () => handleSelectSuggestion(item), disabled: item.disabled, active: false, tone: "default", hoverTone: "default", activeTone: "default", textColor: baseTextColor, hoverTextColor: baseTextColor, activeTextColor: baseTextColor, startIcon: isSelected ? jsx(Icon, { name: "check", size: 16, color: menuHighlightColor }) : jsx(View, { style: { width: 16 } }), compact: true, rounded: false, style: [styles.menuItemButton, suggestionItemStyle], ...(Platform.OS === 'web' ? {
25201
24775
  onMouseDown: (event) => {
25202
24776
  if (event === null || event === void 0 ? void 0 : event.preventDefault) {
25203
24777
  event.preventDefault();
@@ -27464,7 +27038,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
27464
27038
  }
27465
27039
  onChange === null || onChange === void 0 ? void 0 : onChange(date);
27466
27040
  }, [isControlled, maxDate, minDate, onChange]);
27467
- return (jsxs(View, { children: [jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsx(Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
27041
+ return (jsxs(View, { style: { alignSelf: 'flex-start' }, children: [jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsx(Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
27468
27042
  {
27469
27043
  padding: 8,
27470
27044
  borderRadius: 6,
@@ -27476,7 +27050,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
27476
27050
  borderRadius: 6,
27477
27051
  backgroundColor: pressed ? theme.colors.gray[2] : 'transparent',
27478
27052
  },
27479
- ], ...nextControlProps, children: jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
27053
+ ], ...nextControlProps, children: jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: { flexGrow: 0 }, style: { flexGrow: 0 }, children: jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
27480
27054
  const isSelected = selectedDate ? dateUtils$1.isSameDay(date, selectedDate) : false;
27481
27055
  const isToday = dateUtils$1.isToday(date);
27482
27056
  const isWeekend = dateUtils$1.isWeekend(date);
@@ -27706,7 +27280,7 @@ const DatePickerInput = forwardRef(function DatePickerInputInner({ value, defaul
27706
27280
  } }));
27707
27281
  }
27708
27282
  if (dropdownType === 'modal') {
27709
- return (jsxs(View, { ref: ref, children: [renderInput(), jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, width: numberOfMonths > 1 ? Math.min(700, 380 * numberOfMonths + 40) : 400, title: type === 'range'
27283
+ return (jsxs(View, { ref: ref, children: [renderInput(), jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, w: numberOfMonths > 1 ? Math.min(700, 380 * numberOfMonths + 40) : 400, title: type === 'range'
27710
27284
  ? 'Select Date Range'
27711
27285
  : type === 'multiple'
27712
27286
  ? 'Select Dates'
@@ -27735,7 +27309,7 @@ const DatePickerInput = forwardRef(function DatePickerInputInner({ value, defaul
27735
27309
  backgroundColor: pressed ? theme.colors.primary[6] : theme.colors.primary[5],
27736
27310
  }), children: jsx(Text, { size: "sm", weight: "semibold", style: { color: 'white' }, children: "Done" }) })] })] }) }))] }) })] }));
27737
27311
  }
27738
- return (jsxs(View, { ref: ref, children: [renderInput(), jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, width: numberOfMonths > 1 ? Math.min(600, 320 * numberOfMonths + 40) : 350, children: jsxs(View, { ref: focusTrapRef, style: { padding: DESIGN_TOKENS.spacing.lg }, accessible: true, accessibilityLabel: type === 'range'
27312
+ return (jsxs(View, { ref: ref, children: [renderInput(), jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, w: numberOfMonths > 1 ? Math.min(600, 320 * numberOfMonths + 40) : 350, children: jsxs(View, { ref: focusTrapRef, style: { padding: DESIGN_TOKENS.spacing.lg }, accessible: true, accessibilityLabel: type === 'range'
27739
27313
  ? 'Date range picker dialog'
27740
27314
  : type === 'multiple'
27741
27315
  ? 'Multiple date picker dialog'
@@ -27830,7 +27404,7 @@ const MonthPickerInput = forwardRef(function MonthPickerInput({ value, defaultVa
27830
27404
  pointerEvents: 'none',
27831
27405
  accessible: false,
27832
27406
  focusable: false,
27833
- } }) }), jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, width: 360, children: jsx(View, { style: {
27407
+ } }) }), jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, w: 360, children: jsx(View, { style: {
27834
27408
  padding: DESIGN_TOKENS.spacing.lg,
27835
27409
  }, children: jsx(MonthPicker, { ...restMonthPickerProps, value: currentValue, onChange: handleMonthChange, locale: resolvedLocale, size: resolvedSize }) }) })] }));
27836
27410
  });
@@ -27893,7 +27467,7 @@ const YearPickerInput = forwardRef(function YearPickerInput({ value, defaultValu
27893
27467
  pointerEvents: 'none',
27894
27468
  accessible: false,
27895
27469
  focusable: false,
27896
- } }) }), jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, width: 360, children: jsx(View, { style: {
27470
+ } }) }), jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, w: 360, children: jsx(View, { style: {
27897
27471
  padding: DESIGN_TOKENS.spacing.lg,
27898
27472
  }, children: jsx(YearPicker, { ...restYearPickerProps, value: currentValue, onChange: handleYearChange, size: resolvedSize }) }) })] }));
27899
27473
  });
@@ -28058,7 +27632,7 @@ const TimePickerInput = ({ value, defaultValue, onChange, format = 24, withSecon
28058
27632
  }
28059
27633
  }, label: label, placeholder: is12h ? 'hh:mm AM' : 'hh:mm', endSection: jsx(Icon, { name: "clock", size: 16, color: disabled ? theme.text.disabled : theme.text.muted }), disabled: disabled, error: error, helperText: helperText, size: size, fullWidth: fullWidth, clearable: clearable && hasValue, clearButtonLabel: clearButtonLabel, onClear: clearValue }) }), jsx(Dialog, { visible: open,
28060
27634
  // variant="fullscreen"
28061
- onClose: handleClose, width: typeof computedPanelWidth === 'number' ? computedPanelWidth : 360, title: title || 'Select Time', children: jsxs(Pressable, { style: {
27635
+ onClose: handleClose, w: typeof computedPanelWidth === 'number' ? computedPanelWidth : 360, title: title || 'Select Time', children: jsxs(Pressable, { style: {
28062
27636
  flex: 1,
28063
27637
  width: '100%',
28064
27638
  justifyContent: 'center',
@@ -29010,303 +28584,6 @@ const EmojiPicker = factory((props, ref) => {
29010
28584
  });
29011
28585
  EmojiPicker.displayName = 'EmojiPicker';
29012
28586
 
29013
- function useRichTextEditorStyles() {
29014
- const theme = useTheme();
29015
- return useMemo(() => StyleSheet.create({
29016
- characterCount: {
29017
- fontSize: 12,
29018
- marginTop: 4,
29019
- textAlign: 'right',
29020
- },
29021
- container: {
29022
- width: '100%',
29023
- },
29024
- disabled: {
29025
- opacity: 0.5,
29026
- },
29027
- editorContainer: {
29028
- backgroundColor: theme.backgrounds.surface,
29029
- borderColor: theme.backgrounds.border,
29030
- borderRadius: parseInt(theme.radii.md, 10),
29031
- borderWidth: 1,
29032
- overflow: 'hidden',
29033
- },
29034
- errorText: {
29035
- fontSize: 12,
29036
- marginTop: 4,
29037
- },
29038
- helperText: {
29039
- fontSize: 12,
29040
- marginTop: 4,
29041
- },
29042
- textInput: {
29043
- fontSize: 16,
29044
- lineHeight: 24,
29045
- padding: parseInt(theme.spacing.md, 10),
29046
- },
29047
- toolButton: {
29048
- alignItems: 'center',
29049
- backgroundColor: 'transparent',
29050
- borderColor: theme.backgrounds.border,
29051
- borderRadius: parseInt(theme.radii.sm, 10),
29052
- borderWidth: 1,
29053
- height: 32,
29054
- justifyContent: 'center',
29055
- width: 32,
29056
- },
29057
- toolSeparator: {
29058
- backgroundColor: theme.backgrounds.border,
29059
- height: 24,
29060
- marginHorizontal: 4,
29061
- width: 1,
29062
- },
29063
- toolbar: {
29064
- backgroundColor: theme.backgrounds.elevated,
29065
- borderBottomColor: theme.backgrounds.border,
29066
- borderBottomWidth: 1,
29067
- },
29068
- toolbarContent: {
29069
- alignItems: 'center',
29070
- flexDirection: 'row',
29071
- gap: 4,
29072
- paddingHorizontal: parseInt(theme.spacing.sm, 10),
29073
- paddingVertical: parseInt(theme.spacing.xs, 10),
29074
- },
29075
- }), [theme]);
29076
- }
29077
-
29078
- // Default toolbar configuration
29079
- const DEFAULT_TOOLBAR_TOOLS = [
29080
- 'bold',
29081
- 'italic',
29082
- 'underline',
29083
- 'separator',
29084
- 'heading',
29085
- 'separator',
29086
- 'align',
29087
- 'separator',
29088
- 'list',
29089
- 'separator',
29090
- 'link',
29091
- 'separator',
29092
- 'color',
29093
- ];
29094
- const RichTextEditor = React__default.memo(({ defaultValue, value, onChange, onSelectionChange, onFocus, onBlur, placeholder = 'Start typing...', readOnly = false, disabled = false, toolbar = {
29095
- enabled: true,
29096
- position: 'top',
29097
- tools: DEFAULT_TOOLBAR_TOOLS,
29098
- }, formats = {
29099
- fontFamilies: ['Arial', 'Georgia', 'Times New Roman', 'Courier New'],
29100
- fontSizes: [12, 14, 16, 18, 20, 24, 28, 32],
29101
- colors: ['#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FF0000', '#00FF00', '#0000FF'],
29102
- headings: [1, 2, 3, 4, 5, 6],
29103
- }, images = { enabled: true }, links = { enabled: true, openInNewTab: true }, plugins = [], autosave, spellCheck = true, maxLength, minHeight = 200, maxHeight = 600, className, theme: themeOverride = 'auto', error, helperText, style, ...props }) => {
29104
- const theme = useTheme();
29105
- const styles = useRichTextEditorStyles();
29106
- const [content, setContent] = useState(value || defaultValue || { html: '', text: '' });
29107
- const [selection, setSelection] = useState({
29108
- index: 0,
29109
- length: 0,
29110
- });
29111
- const [activeFormats, setActiveFormats] = useState({});
29112
- const [isFocused, setIsFocused] = useState(false);
29113
- const editorRef = useRef(null);
29114
- const autosaveTimerRef = useRef(null);
29115
- // Update content when value prop changes
29116
- useEffect(() => {
29117
- if (value && value !== content) {
29118
- setContent(value);
29119
- }
29120
- }, [value]);
29121
- // Autosave functionality
29122
- useEffect(() => {
29123
- if ((autosave === null || autosave === void 0 ? void 0 : autosave.enabled) && autosave.onSave) {
29124
- if (autosaveTimerRef.current) {
29125
- clearTimeout(autosaveTimerRef.current);
29126
- }
29127
- autosaveTimerRef.current = setTimeout(() => {
29128
- autosave.onSave(content);
29129
- }, autosave.interval || 5000);
29130
- return () => {
29131
- if (autosaveTimerRef.current) {
29132
- clearTimeout(autosaveTimerRef.current);
29133
- }
29134
- };
29135
- }
29136
- }, [content, autosave]);
29137
- const handleContentChange = useCallback((text) => {
29138
- const newContent = {
29139
- text,
29140
- html: text, // For now, treating as plain text
29141
- };
29142
- setContent(newContent);
29143
- onChange === null || onChange === void 0 ? void 0 : onChange(newContent);
29144
- }, [onChange]);
29145
- const handleSelectionChange = useCallback((selection) => {
29146
- const newSelection = {
29147
- index: selection.start,
29148
- length: selection.end - selection.start,
29149
- format: activeFormats,
29150
- };
29151
- setSelection(newSelection);
29152
- onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(newSelection);
29153
- }, [activeFormats, onSelectionChange]);
29154
- const handleFocus = useCallback(() => {
29155
- setIsFocused(true);
29156
- onFocus === null || onFocus === void 0 ? void 0 : onFocus();
29157
- }, [onFocus]);
29158
- const handleBlur = useCallback(() => {
29159
- setIsFocused(false);
29160
- onBlur === null || onBlur === void 0 ? void 0 : onBlur();
29161
- }, [onBlur]);
29162
- const applyFormat = useCallback((format) => {
29163
- if (readOnly || disabled)
29164
- return;
29165
- const newFormats = { ...activeFormats, ...format };
29166
- setActiveFormats(newFormats);
29167
- // In a real implementation, this would apply formatting to the selected text
29168
- // For this demo, we'll just track the format state
29169
- }, [activeFormats, readOnly, disabled]);
29170
- const toggleFormat = useCallback((formatKey) => {
29171
- if (readOnly || disabled)
29172
- return;
29173
- const currentValue = activeFormats[formatKey];
29174
- applyFormat({ [formatKey]: !currentValue });
29175
- }, [activeFormats, applyFormat, readOnly, disabled]);
29176
- const insertText = useCallback((text) => {
29177
- if (readOnly || disabled)
29178
- return;
29179
- const currentText = content.text;
29180
- const { index } = selection;
29181
- const newText = currentText.slice(0, index) + text + currentText.slice(index);
29182
- handleContentChange(newText);
29183
- }, [content.text, selection, handleContentChange, readOnly, disabled]);
29184
- const insertLink = useCallback(() => {
29185
- if (!(links === null || links === void 0 ? void 0 : links.enabled) || readOnly || disabled)
29186
- return;
29187
- // In a real implementation, this would show a link dialog
29188
- const url = prompt('Enter URL:');
29189
- if (url && (!links.validate || links.validate(url))) {
29190
- applyFormat({ link: url });
29191
- }
29192
- }, [links, applyFormat, readOnly, disabled]);
29193
- useCallback(async () => {
29194
- if (!(images === null || images === void 0 ? void 0 : images.enabled) || readOnly || disabled)
29195
- return;
29196
- // In a real implementation, this would show a file picker
29197
- // For now, we'll just insert a placeholder
29198
- insertText('[Image]');
29199
- }, [images, insertText, readOnly, disabled]);
29200
- useCallback((level) => {
29201
- applyFormat({ heading: level });
29202
- }, [applyFormat]);
29203
- const setAlignment = useCallback((align) => {
29204
- applyFormat({ align });
29205
- }, [applyFormat]);
29206
- const setList = useCallback((listType) => {
29207
- applyFormat({ list: listType });
29208
- }, [applyFormat]);
29209
- const getToolButtonStyle = useCallback((isActive) => [
29210
- styles.toolButton,
29211
- {
29212
- backgroundColor: isActive
29213
- ? (theme.colorScheme === 'dark' ? theme.colors.primary[7] : theme.colors.primary[1])
29214
- : 'transparent',
29215
- borderColor: isActive ? theme.colors.primary[4] : theme.backgrounds.border,
29216
- },
29217
- (disabled || readOnly) && styles.disabled,
29218
- ], [styles.toolButton, theme, disabled, readOnly]);
29219
- const renderToolButton = useCallback((tool, icon, onPress, isActive = false) => (jsx(TouchableOpacity, { onPress: onPress, disabled: disabled || readOnly, style: getToolButtonStyle(isActive), children: jsx(Icon, { name: icon, size: 16, color: isActive ? theme.colors.primary[5] : theme.text.secondary }) }, tool)), [theme, disabled, readOnly, getToolButtonStyle]);
29220
- const renderToolSeparator = useCallback((index) => (jsx(View, { style: styles.toolSeparator }, `separator-${index}`)), [styles.toolSeparator]);
29221
- const renderToolbar = useCallback(() => {
29222
- if (!(toolbar === null || toolbar === void 0 ? void 0 : toolbar.enabled))
29223
- return null;
29224
- const tools = toolbar.tools || DEFAULT_TOOLBAR_TOOLS;
29225
- return (jsx(View, { style: styles.toolbar, children: jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.toolbarContent, children: tools.map((tool, index) => {
29226
- if (tool === 'separator') {
29227
- return renderToolSeparator(index);
29228
- }
29229
- switch (tool) {
29230
- case 'bold':
29231
- return renderToolButton('bold', 'bold', () => toggleFormat('bold'), !!activeFormats.bold);
29232
- case 'italic':
29233
- return renderToolButton('italic', 'italic', () => toggleFormat('italic'), !!activeFormats.italic);
29234
- case 'underline':
29235
- return renderToolButton('underline', 'underline', () => toggleFormat('underline'), !!activeFormats.underline);
29236
- case 'strikethrough':
29237
- return renderToolButton('strikethrough', 'strikethrough', () => toggleFormat('strikethrough'), !!activeFormats.strikethrough);
29238
- case 'heading':
29239
- return renderToolButton('heading', 'heading', () => applyFormat({ heading: activeFormats.heading ? null : 2 }), !!activeFormats.heading);
29240
- case 'align':
29241
- return renderToolButton('align', 'alignLeft', // Default to left align icon, could be dynamic based on current align
29242
- () => setAlignment(activeFormats.align === 'left' ? 'center' : 'left'), !!activeFormats.align);
29243
- case 'list':
29244
- return renderToolButton('list', 'listUnordered', // Default to unordered list icon, could be dynamic
29245
- () => setList(activeFormats.list === 'unordered' ? 'ordered' : 'unordered'), !!activeFormats.list);
29246
- case 'link':
29247
- return renderToolButton('link', 'link', insertLink, !!activeFormats.link);
29248
- case 'image':
29249
- return renderToolButton('image', 'image', () => { }, // TODO: Implement image insertion
29250
- false);
29251
- case 'code':
29252
- return renderToolButton('code', 'code', () => toggleFormat('code'), !!activeFormats.code);
29253
- case 'quote':
29254
- return renderToolButton('quote', 'quote', () => toggleFormat('quote'), !!activeFormats.quote);
29255
- case 'color':
29256
- return renderToolButton('color', 'color', () => { }, // TODO: Implement color picker
29257
- !!activeFormats.color);
29258
- default:
29259
- return null;
29260
- }
29261
- }) }) }));
29262
- }, [toolbar, theme, activeFormats, renderToolButton, renderToolSeparator, toggleFormat, insertLink, styles.toolbar, styles.toolbarContent]);
29263
- const renderEditor = useCallback(() => (jsx(View, { style: [
29264
- styles.editorContainer,
29265
- {
29266
- borderColor: isFocused ? theme.colors.primary[5] : theme.backgrounds.border,
29267
- minHeight,
29268
- maxHeight,
29269
- },
29270
- error && { borderColor: theme.colors.error[5] },
29271
- (disabled || readOnly) && styles.disabled,
29272
- ], children: jsx(TextInput, { ref: editorRef, value: content.text, onChangeText: handleContentChange, onSelectionChange: (event) => handleSelectionChange(event.nativeEvent.selection), onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder, placeholderTextColor: theme.text.muted, multiline: true, textAlignVertical: "top", editable: !disabled && !readOnly, spellCheck: spellCheck, maxLength: maxLength, style: [
29273
- styles.textInput,
29274
- Platform.OS === 'web' ? { outlineWidth: 0 } : null,
29275
- {
29276
- color: theme.text.primary,
29277
- fontSize: activeFormats.fontSize || 16,
29278
- fontFamily: activeFormats.fontFamily || theme.fontFamily,
29279
- fontWeight: activeFormats.bold ? 'bold' : 'normal',
29280
- fontStyle: activeFormats.italic ? 'italic' : 'normal',
29281
- textDecorationLine: activeFormats.underline ? 'underline' : 'none',
29282
- textAlign: activeFormats.align || 'left',
29283
- },
29284
- ], ...props }) })), [
29285
- content.text,
29286
- handleContentChange,
29287
- handleSelectionChange,
29288
- handleFocus,
29289
- handleBlur,
29290
- placeholder,
29291
- disabled,
29292
- readOnly,
29293
- spellCheck,
29294
- maxLength,
29295
- isFocused,
29296
- theme,
29297
- minHeight,
29298
- maxHeight,
29299
- error,
29300
- activeFormats,
29301
- props,
29302
- styles.editorContainer,
29303
- styles.disabled,
29304
- styles.textInput,
29305
- ]);
29306
- return (jsxs(View, { style: [styles.container, style], children: [(toolbar === null || toolbar === void 0 ? void 0 : toolbar.position) === 'top' && renderToolbar(), renderEditor(), (toolbar === null || toolbar === void 0 ? void 0 : toolbar.position) === 'bottom' && renderToolbar(), maxLength && (jsxs(Text$1, { style: [styles.characterCount, { color: theme.text.secondary }], children: [content.text.length, "/", maxLength] })), error && (jsx(Text$1, { style: [styles.errorText, { color: theme.colors.error[5] }], children: error })), helperText && !error && (jsx(Text$1, { style: [styles.helperText, { color: theme.text.secondary }], children: helperText }))] }));
29307
- });
29308
- RichTextEditor.displayName = 'RichTextEditor';
29309
-
29310
28587
  function RatingBase(rawProps, ref) {
29311
28588
  const { disclaimerProps: disclaimerData, otherProps: propsAfterDisclaimer } = extractDisclaimerProps(rawProps);
29312
28589
  const { spacingProps, otherProps: props } = extractSpacingProps(propsAfterDisclaimer);
@@ -30058,7 +29335,7 @@ function useMenuContext() {
30058
29335
  return context;
30059
29336
  }
30060
29337
  function MenuBase(props, ref) {
30061
- const { opened: controlledOpened, trigger = 'click', position = 'auto', offset = 4, closeOnClickOutside = true, closeOnEscape = true, onOpen, onClose, width = 'auto', maxHeight = 300, shadow = 'md', radius = 'md', children, testID, disabled = false, strategy = Platform.OS === 'web' ? 'fixed' : 'portal', ...spacingProps } = props;
29338
+ const { opened: controlledOpened, trigger = 'click', position = 'auto', offset = 4, closeOnClickOutside = true, closeOnEscape = true, onOpen, onClose, w = 'auto', maxH = 300, shadow = 'md', radius = 'md', children, testID, disabled = false, strategy = Platform.OS === 'web' ? 'fixed' : 'portal', ...spacingProps } = props;
30062
29339
  const [internalOpened, setInternalOpened] = useState(false);
30063
29340
  // Derive menu dropdown items from children each render for reactivity
30064
29341
  const { menuItems, menuDropdownProps } = useMemo(() => {
@@ -30133,11 +29410,11 @@ function MenuBase(props, ref) {
30133
29410
  const listGroupStyle = {
30134
29411
  ...styles.dropdown,
30135
29412
  ...(dropdownSpacingStyles || {}),
30136
- maxHeight,
29413
+ maxHeight: maxH,
30137
29414
  width: resolvedWidth,
30138
29415
  };
30139
- return (jsx(MenuContext.Provider, { value: menuContextValueOpened, children: jsx(ListGroup, { variant: "default", size: "sm", style: listGroupStyle, children: scrollable ? (jsx(ScrollView, { showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", style: { maxHeight }, children: jsx(ListGroupBody, { children: menuItems }) })) : (jsx(View, { style: { maxHeight, overflow: 'hidden' }, children: jsx(ListGroupBody, { children: menuItems }) })) }) }));
30140
- }, [menuItems, menuDropdownProps, styles.dropdown, dropdownSpacingStyles, maxHeight, menuContextValueOpened]);
29416
+ return (jsx(MenuContext.Provider, { value: menuContextValueOpened, children: jsx(ListGroup, { variant: "default", size: "sm", style: listGroupStyle, children: scrollable ? (jsx(ScrollView, { showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", style: { maxHeight: maxH }, children: jsx(ListGroupBody, { children: menuItems }) })) : (jsx(View, { style: { maxHeight: maxH, overflow: 'hidden' }, children: jsx(ListGroupBody, { children: menuItems }) })) }) }));
29417
+ }, [menuItems, menuDropdownProps, styles.dropdown, dropdownSpacingStyles, maxH, menuContextValueOpened]);
30141
29418
  const handleOpen = useCallback(async (opts) => {
30142
29419
  var _a, _b, _c, _d, _e, _f;
30143
29420
  // Use ref to avoid stale isOpened value after async close from backdrop click
@@ -30169,7 +29446,7 @@ function MenuBase(props, ref) {
30169
29446
  }
30170
29447
  // Calculate base overlay size
30171
29448
  const estimatedMenuHeight = 120; // Estimate for typical menu with 3-4 items
30172
- const resolvedWidth = width === 'target' ? triggerRect.width : (typeof width === 'number' ? width : (width === 'auto' ? 200 : 200));
29449
+ const resolvedWidth = w === 'target' ? triggerRect.width : (typeof w === 'number' ? w : (w === 'auto' ? 200 : 200));
30173
29450
  const overlaySize = {
30174
29451
  width: resolvedWidth,
30175
29452
  height: estimatedMenuHeight,
@@ -30217,6 +29494,7 @@ function MenuBase(props, ref) {
30217
29494
  const overlayId = openOverlay({
30218
29495
  content: menuDropdown,
30219
29496
  anchor: { x: positionResult.x, y: positionResult.y, width: overlaySize.width, height: overlaySize.height },
29497
+ placement: positionResult.placement || position,
30220
29498
  closeOnClickOutside,
30221
29499
  closeOnEscape,
30222
29500
  strategy,
@@ -30236,7 +29514,7 @@ function MenuBase(props, ref) {
30236
29514
  catch (error) {
30237
29515
  console.warn('Failed to open menu:', error);
30238
29516
  }
30239
- }, [disabled, width, position, offset, strategy, closeOnClickOutside, closeOnEscape, onOpen, menuItems, trigger, buildMenuDropdown, onClose]);
29517
+ }, [disabled, w, position, offset, strategy, closeOnClickOutside, closeOnEscape, onOpen, menuItems, trigger, buildMenuDropdown, onClose]);
30240
29518
  // When menu content changes while open, update overlay content in place
30241
29519
  useEffect(() => {
30242
29520
  var _a;
@@ -30248,14 +29526,14 @@ function MenuBase(props, ref) {
30248
29526
  return; // no structural change
30249
29527
  lastSignatureRef.current = menuItemsSignature;
30250
29528
  const currentId = overlayIdRef.current;
30251
- const resolvedWidth = (_a = lastResolvedWidthRef.current) !== null && _a !== void 0 ? _a : (typeof width === 'number' ? width : undefined);
29529
+ const resolvedWidth = (_a = lastResolvedWidthRef.current) !== null && _a !== void 0 ? _a : (typeof w === 'number' ? w : undefined);
30252
29530
  const menuDropdown = buildMenuDropdown(resolvedWidth);
30253
29531
  if (!menuDropdown)
30254
29532
  return;
30255
29533
  updateOverlay(currentId, {
30256
29534
  content: menuDropdown,
30257
29535
  });
30258
- }, [menuItemsSignature, menuItems, updateOverlay, width, buildMenuDropdown]);
29536
+ }, [menuItemsSignature, menuItems, updateOverlay, w, buildMenuDropdown]);
30259
29537
  const handleToggle = useCallback(() => {
30260
29538
  if (isOpenedRef.current) {
30261
29539
  handleClose();
@@ -32186,8 +31464,8 @@ function usePopoverContext(component) {
32186
31464
  const DEFAULT_ARROW_SIZE = 7;
32187
31465
  const PopoverBase = (props, ref) => {
32188
31466
  var _a;
32189
- const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
32190
- trapFocus = false, keepMounted = false, returnFocus = false, withinPortal = true, withOverlay = false, overlayProps, width, minWidth, minHeight, maxWidth, maxHeight, radius, shadow, zIndex = 300, position = 'bottom', offset = 8, floatingStrategy = 'fixed', middlewares, preventPositionChangeWhenVisible = false, hideDetached = true, viewport, keyboardAvoidance = true, fallbackPlacements, boundary, withRoles = true, id, withArrow = false, arrowSize = DEFAULT_ARROW_SIZE, arrowRadius = 0, arrowOffset = 5, arrowPosition = 'center', onPositionChange, testID, ...rest } = props;
31467
+ const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, trigger = 'click', disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
31468
+ trapFocus = false, keepMounted = false, returnFocus = false, withinPortal = true, withOverlay = false, overlayProps, w, minW, minH, maxW, maxH, radius, shadow, zIndex = 300, position = 'bottom', offset = 8, floatingStrategy = 'fixed', middlewares, preventPositionChangeWhenVisible = false, hideDetached = true, viewport, keyboardAvoidance = true, fallbackPlacements, boundary, withRoles = true, id, withArrow = false, arrowSize = DEFAULT_ARROW_SIZE, arrowRadius = 0, arrowOffset = 5, arrowPosition = 'center', onPositionChange, testID, ...rest } = props;
32191
31469
  const theme = useTheme();
32192
31470
  const { spacingProps } = extractSpacingProps(rest);
32193
31471
  const spacingStyles = getSpacingStyles(spacingProps);
@@ -32198,9 +31476,18 @@ const PopoverBase = (props, ref) => {
32198
31476
  const openedRef = useRef(opened);
32199
31477
  const closingReasonRef = useRef(null);
32200
31478
  const anchorMeasurementsRef = useRef(null);
31479
+ const hoverTimeoutRef = useRef(null);
32201
31480
  useEffect(() => {
32202
31481
  openedRef.current = opened;
32203
31482
  }, [opened]);
31483
+ // Cleanup hover timeout on unmount
31484
+ useEffect(() => {
31485
+ return () => {
31486
+ if (hoverTimeoutRef.current) {
31487
+ clearTimeout(hoverTimeoutRef.current);
31488
+ }
31489
+ };
31490
+ }, []);
32204
31491
  const resolvedOffset = typeof offset === 'number' ? offset : (_a = offset === null || offset === void 0 ? void 0 : offset.mainAxis) !== null && _a !== void 0 ? _a : 8;
32205
31492
  const resolvedFlip = preventPositionChangeWhenVisible
32206
31493
  ? false
@@ -32213,7 +31500,7 @@ const PopoverBase = (props, ref) => {
32213
31500
  ? false
32214
31501
  : true;
32215
31502
  const resolvedStrategy = floatingStrategy !== null && floatingStrategy !== void 0 ? floatingStrategy : 'fixed';
32216
- const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition } = useDropdownPositioning({
31503
+ const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition, isPositioning } = useDropdownPositioning({
32217
31504
  isOpen: opened && !disabled && !!dropdownState,
32218
31505
  placement: position,
32219
31506
  offset: resolvedOffset,
@@ -32225,9 +31512,20 @@ const PopoverBase = (props, ref) => {
32225
31512
  fallbackPlacements,
32226
31513
  viewport,
32227
31514
  onClose: () => handleOverlayClose('dismiss'),
32228
- closeOnClickOutside,
31515
+ closeOnClickOutside: trigger === 'hover' ? false : closeOnClickOutside,
32229
31516
  closeOnEscape,
32230
31517
  });
31518
+ // Track if we've done measurement-based positioning to avoid flicker
31519
+ const hasPositionedRef = useRef(false);
31520
+ useEffect(() => {
31521
+ // Only mark as positioned when we have a measurement-based position
31522
+ if (opened && positioningResult && positioningResult._hasMeasuredPopover) {
31523
+ hasPositionedRef.current = true;
31524
+ }
31525
+ if (!opened) {
31526
+ hasPositionedRef.current = false;
31527
+ }
31528
+ }, [opened, positioningResult]);
32231
31529
  const popoverStyles = useMemo(() => createPopoverStyles(theme)({
32232
31530
  radius,
32233
31531
  shadow,
@@ -32331,6 +31629,28 @@ const PopoverBase = (props, ref) => {
32331
31629
  openPopover();
32332
31630
  }
32333
31631
  }, [closePopover, openPopover]);
31632
+ // Hover-specific handlers with delay to prevent glitching when moving between target and dropdown
31633
+ const handleHoverOpen = useCallback(() => {
31634
+ if (hoverTimeoutRef.current) {
31635
+ clearTimeout(hoverTimeoutRef.current);
31636
+ hoverTimeoutRef.current = null;
31637
+ }
31638
+ openPopover();
31639
+ }, [openPopover]);
31640
+ const handleHoverClose = useCallback(() => {
31641
+ if (hoverTimeoutRef.current) {
31642
+ clearTimeout(hoverTimeoutRef.current);
31643
+ }
31644
+ hoverTimeoutRef.current = setTimeout(() => {
31645
+ closePopover('programmatic');
31646
+ hoverTimeoutRef.current = null;
31647
+ }, 150); // Delay to allow mouse to move to dropdown
31648
+ }, [closePopover]);
31649
+ // Store hover handlers in refs to avoid causing re-renders in useEffect
31650
+ const hoverHandlersRef = useRef({ open: handleHoverOpen, close: handleHoverClose });
31651
+ useEffect(() => {
31652
+ hoverHandlersRef.current = { open: handleHoverOpen, close: handleHoverClose };
31653
+ }, [handleHoverOpen, handleHoverClose]);
32334
31654
  useEffect(() => {
32335
31655
  if (opened) {
32336
31656
  updateAnchorMeasurements();
@@ -32362,41 +31682,53 @@ const PopoverBase = (props, ref) => {
32362
31682
  : undefined;
32363
31683
  const widthOverride = (() => {
32364
31684
  var _a, _b;
32365
- if (typeof width === 'number')
32366
- return width;
32367
- if (width === 'target') {
31685
+ if (typeof w === 'number')
31686
+ return w;
31687
+ if (w === 'target') {
32368
31688
  return (_b = (_a = anchorMeasurementsRef.current) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : computedFinalWidth;
32369
31689
  }
32370
31690
  return computedFinalWidth;
32371
31691
  })();
32372
31692
  const sizeStyles = {};
32373
- if (typeof minWidth === 'number')
32374
- sizeStyles.minWidth = minWidth;
32375
- if (typeof minHeight === 'number')
32376
- sizeStyles.minHeight = minHeight;
32377
- if (typeof maxWidth === 'number')
32378
- sizeStyles.maxWidth = maxWidth;
31693
+ if (typeof minW === 'number')
31694
+ sizeStyles.minWidth = minW;
31695
+ if (typeof minH === 'number')
31696
+ sizeStyles.minHeight = minH;
31697
+ if (typeof maxW === 'number')
31698
+ sizeStyles.maxWidth = maxW;
32379
31699
  const computedMaxHeight = positioningResult.maxHeight;
32380
31700
  const resolvedMaxHeight = (() => {
32381
- if (typeof maxHeight === 'number') {
31701
+ if (typeof maxH === 'number') {
32382
31702
  if (typeof computedMaxHeight === 'number') {
32383
- return Math.min(maxHeight, computedMaxHeight);
31703
+ return Math.min(maxH, computedMaxHeight);
32384
31704
  }
32385
- return maxHeight;
31705
+ return maxH;
32386
31706
  }
32387
- return typeof computedMaxHeight === 'number' ? computedMaxHeight : maxHeight;
31707
+ return typeof computedMaxHeight === 'number' ? computedMaxHeight : maxH;
32388
31708
  })();
32389
31709
  if (typeof resolvedMaxHeight === 'number')
32390
31710
  sizeStyles.maxHeight = resolvedMaxHeight;
32391
31711
  const dropdownStyle = [popoverStyles.dropdown, dropdownState.style, sizeStyles];
32392
- const content = (jsxs(View, { ref: popoverRef, style: [popoverStyles.wrapper, widthOverride ? { width: widthOverride } : null], pointerEvents: dropdownState.trapFocus ? 'auto' : 'box-none', testID: dropdownState.testID, onLayout: handleDropdownLayout, ...dropdownState.containerProps, children: [jsx(View, { style: dropdownStyle, children: dropdownState.content }), withArrow && (jsx(View, { style: getArrowStyle(positioningResult.placement, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme) }))] }));
31712
+ // Hover handlers for the dropdown to keep it open when mouse moves from target to dropdown
31713
+ const dropdownHoverHandlers = trigger === 'hover' && Platform.OS === 'web'
31714
+ ? {
31715
+ onMouseEnter: () => hoverHandlersRef.current.open(),
31716
+ onMouseLeave: () => hoverHandlersRef.current.close(),
31717
+ }
31718
+ : {};
31719
+ // Hide content until we have measurement-based positioning to prevent visual "snap"
31720
+ const hasMeasuredPosition = (positioningResult === null || positioningResult === void 0 ? void 0 : positioningResult._hasMeasuredPopover) === true;
31721
+ const visibilityStyle = !hasMeasuredPosition && Platform.OS === 'web'
31722
+ ? { opacity: 0 }
31723
+ : {};
31724
+ const content = (jsxs(View, { ref: popoverRef, style: [popoverStyles.wrapper, widthOverride ? { width: widthOverride } : null, visibilityStyle], pointerEvents: trigger === 'hover' ? 'auto' : (dropdownState.trapFocus ? 'auto' : 'box-none'), testID: dropdownState.testID, onLayout: handleDropdownLayout, ...dropdownHoverHandlers, ...dropdownState.containerProps, children: [jsx(View, { style: dropdownStyle, children: dropdownState.content }), withArrow && (jsx(View, { style: getArrowStyle(positioningResult.placement, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme) }))] }));
32393
31725
  showOverlay(content, {
32394
31726
  width: widthOverride,
32395
31727
  maxHeight: resolvedMaxHeight,
32396
31728
  zIndex,
32397
31729
  });
32398
31730
  onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(positioningResult.placement);
32399
- }, [opened, dropdownState, positioningResult, popoverRef, showOverlay, hideOverlay, popoverStyles.dropdown, popoverStyles.wrapper, width, maxHeight, minWidth, minHeight, maxWidth, withArrow, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme, zIndex, onPositionChange, schedulePositionUpdate]);
31731
+ }, [opened, dropdownState, positioningResult, popoverRef, showOverlay, hideOverlay, popoverStyles.dropdown, popoverStyles.wrapper, w, maxH, minW, minH, maxW, withArrow, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme, zIndex, onPositionChange, schedulePositionUpdate, trigger, isPositioning]);
32400
31732
  useEffect(() => {
32401
31733
  return () => {
32402
31734
  hideOverlay();
@@ -32417,6 +31749,8 @@ const PopoverBase = (props, ref) => {
32417
31749
  open: openPopover,
32418
31750
  close: () => closePopover('programmatic'),
32419
31751
  toggle: togglePopover,
31752
+ hoverOpen: handleHoverOpen,
31753
+ hoverClose: handleHoverClose,
32420
31754
  registerDropdown,
32421
31755
  unregisterDropdown,
32422
31756
  anchorRef,
@@ -32425,7 +31759,8 @@ const PopoverBase = (props, ref) => {
32425
31759
  withRoles,
32426
31760
  disabled,
32427
31761
  returnFocus,
32428
- }), [opened, openPopover, closePopover, togglePopover, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus]);
31762
+ trigger,
31763
+ }), [opened, openPopover, closePopover, togglePopover, handleHoverOpen, handleHoverClose, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus, trigger]);
32429
31764
  const setContainerRef = useCallback((node) => {
32430
31765
  if (typeof ref === 'function') {
32431
31766
  ref(node);
@@ -32475,16 +31810,44 @@ const PopoverTargetBase = (props, ref) => {
32475
31810
  : { id: context.targetId };
32476
31811
  const composedRef = mergeRefs(children.ref, externalTargetRef);
32477
31812
  const triggerHandlers = {};
32478
- triggerHandlers.onPress = (...args) => {
32479
- const tgt = targetProps;
32480
- if (tgt && typeof tgt.onPress === 'function') {
32481
- tgt.onPress(...args);
32482
- }
32483
- if (typeof childProps.onPress === 'function') {
32484
- childProps.onPress(...args);
32485
- }
32486
- context.toggle();
32487
- };
31813
+ const wrapperHoverHandlers = {};
31814
+ // Click trigger: toggle on press
31815
+ if (context.trigger === 'click') {
31816
+ triggerHandlers.onPress = (...args) => {
31817
+ const tgt = targetProps;
31818
+ if (tgt && typeof tgt.onPress === 'function') {
31819
+ tgt.onPress(...args);
31820
+ }
31821
+ if (typeof childProps.onPress === 'function') {
31822
+ childProps.onPress(...args);
31823
+ }
31824
+ context.toggle();
31825
+ };
31826
+ }
31827
+ // Hover trigger: open/close on mouse enter/leave (web only)
31828
+ // Applied to the wrapper View for reliable hover detection
31829
+ if (context.trigger === 'hover' && Platform.OS === 'web') {
31830
+ wrapperHoverHandlers.onMouseEnter = (...args) => {
31831
+ const tgt = targetProps;
31832
+ if (tgt && typeof tgt.onMouseEnter === 'function') {
31833
+ tgt.onMouseEnter(...args);
31834
+ }
31835
+ if (typeof childProps.onMouseEnter === 'function') {
31836
+ childProps.onMouseEnter(...args);
31837
+ }
31838
+ context.hoverOpen();
31839
+ };
31840
+ wrapperHoverHandlers.onMouseLeave = (...args) => {
31841
+ const tgt = targetProps;
31842
+ if (tgt && typeof tgt.onMouseLeave === 'function') {
31843
+ tgt.onMouseLeave(...args);
31844
+ }
31845
+ if (typeof childProps.onMouseLeave === 'function') {
31846
+ childProps.onMouseLeave(...args);
31847
+ }
31848
+ context.hoverClose();
31849
+ };
31850
+ }
32488
31851
  if (Platform.OS === 'web') {
32489
31852
  triggerHandlers.onKeyDown = (event) => {
32490
31853
  const tgt = targetProps;
@@ -32506,7 +31869,14 @@ const PopoverTargetBase = (props, ref) => {
32506
31869
  };
32507
31870
  }
32508
31871
  const dynamicRefProp = { [refProp]: composedRef };
32509
- delete sanitizedTargetProps.onPress;
31872
+ // Remove handlers that we're overriding from sanitizedTargetProps
31873
+ if (context.trigger === 'click') {
31874
+ delete sanitizedTargetProps.onPress;
31875
+ }
31876
+ if (context.trigger === 'hover') {
31877
+ delete sanitizedTargetProps.onMouseEnter;
31878
+ delete sanitizedTargetProps.onMouseLeave;
31879
+ }
32510
31880
  delete sanitizedTargetProps.onKeyDown;
32511
31881
  const mergedProps = {
32512
31882
  ...sanitizedTargetProps,
@@ -32518,7 +31888,7 @@ const PopoverTargetBase = (props, ref) => {
32518
31888
  mergedProps.disabled = true;
32519
31889
  }
32520
31890
  const anchorWrapperRef = mergeRefs(context.anchorRef, ref);
32521
- return (jsx(View, { ref: anchorWrapperRef, collapsable: false, children: cloneElement(children, mergedProps) }));
31891
+ return (jsx(View, { ref: anchorWrapperRef, collapsable: false, ...wrapperHoverHandlers, children: cloneElement(children, mergedProps) }));
32522
31892
  };
32523
31893
  const PopoverDropdownBase = (props, _ref) => {
32524
31894
  const { children, trapFocus = false, keepMounted, style, testID, ...rest } = props;
@@ -32562,8 +31932,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32562
31932
  const [side, alignment] = placement.split('-');
32563
31933
  switch (side) {
32564
31934
  case 'top':
31935
+ // Arrow points down, hide the borders that overlap with content (top-left corner after rotation)
32565
31936
  return {
32566
31937
  ...base,
31938
+ borderTopWidth: 0,
31939
+ borderLeftWidth: 0,
32567
31940
  bottom: -arrowSize,
32568
31941
  left: alignment === 'end'
32569
31942
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32573,8 +31946,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32573
31946
  marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
32574
31947
  };
32575
31948
  case 'bottom':
31949
+ // Arrow points up, hide the borders that overlap with content (bottom-right corner after rotation)
32576
31950
  return {
32577
31951
  ...base,
31952
+ borderBottomWidth: 0,
31953
+ borderRightWidth: 0,
32578
31954
  top: -arrowSize,
32579
31955
  left: alignment === 'end'
32580
31956
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32584,8 +31960,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32584
31960
  marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
32585
31961
  };
32586
31962
  case 'left':
31963
+ // Arrow points right, hide the borders that overlap with content (bottom-left corner after rotation)
32587
31964
  return {
32588
31965
  ...base,
31966
+ borderBottomWidth: 0,
31967
+ borderLeftWidth: 0,
32589
31968
  right: -arrowSize,
32590
31969
  top: alignment === 'end'
32591
31970
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32595,8 +31974,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32595
31974
  marginTop: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
32596
31975
  };
32597
31976
  case 'right':
31977
+ // Arrow points left, hide the borders that overlap with content (top-right corner after rotation)
32598
31978
  return {
32599
31979
  ...base,
31980
+ borderTopWidth: 0,
31981
+ borderRightWidth: 0,
32600
31982
  left: -arrowSize,
32601
31983
  top: alignment === 'end'
32602
31984
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32634,7 +32016,7 @@ const getSpacingValue = (spacing, theme) => {
32634
32016
  // Table Cell Components
32635
32017
  const TableTh = (allProps) => {
32636
32018
  const { spacingProps, otherProps } = extractSpacingProps(allProps);
32637
- const { children, w, align = 'left', minWidth, maxWidth, flex, widthStrategy = 'auto', style } = otherProps;
32019
+ const { children, w, align = 'left', minW, maxW, flex, widthStrategy = 'auto', style } = otherProps;
32638
32020
  const theme = useTheme();
32639
32021
  const { isRTL } = useDirection();
32640
32022
  // Swap alignment in RTL
@@ -32665,10 +32047,10 @@ const TableTh = (allProps) => {
32665
32047
  else if (widthStrategy === 'auto') {
32666
32048
  widthStyle.flex = 1;
32667
32049
  }
32668
- if (minWidth)
32669
- widthStyle.minWidth = minWidth;
32670
- if (maxWidth)
32671
- widthStyle.maxWidth = maxWidth;
32050
+ if (minW)
32051
+ widthStyle.minWidth = minW;
32052
+ if (maxW)
32053
+ widthStyle.maxWidth = maxW;
32672
32054
  return widthStyle;
32673
32055
  };
32674
32056
  const cellStyle = [
@@ -32689,7 +32071,7 @@ const TableTh = (allProps) => {
32689
32071
  };
32690
32072
  const TableTd = (allProps) => {
32691
32073
  const { spacingProps, otherProps } = extractSpacingProps(allProps);
32692
- const { children, w, align = 'left', minWidth, maxWidth, flex, widthStrategy = 'auto', style } = otherProps;
32074
+ const { children, w, align = 'left', minW, maxW, flex, widthStrategy = 'auto', style } = otherProps;
32693
32075
  const theme = useTheme();
32694
32076
  const { isRTL } = useDirection();
32695
32077
  // Swap alignment in RTL
@@ -32720,10 +32102,10 @@ const TableTd = (allProps) => {
32720
32102
  else if (widthStrategy === 'auto') {
32721
32103
  widthStyle.flex = 1;
32722
32104
  }
32723
- if (minWidth)
32724
- widthStyle.minWidth = minWidth;
32725
- if (maxWidth)
32726
- widthStyle.maxWidth = maxWidth;
32105
+ if (minW)
32106
+ widthStyle.minWidth = minW;
32107
+ if (maxW)
32108
+ widthStyle.maxWidth = maxW;
32727
32109
  return widthStyle;
32728
32110
  };
32729
32111
  const cellStyle = [
@@ -32802,16 +32184,16 @@ const TableCaption = (allProps) => {
32802
32184
  // Scroll Container Component
32803
32185
  const TableScrollContainer = (allProps) => {
32804
32186
  const { spacingProps, otherProps } = extractSpacingProps(allProps);
32805
- const { children, minWidth = 500, maxHeight, type = 'native', style } = otherProps;
32187
+ const { children, minW = 500, maxH, type = 'native', style } = otherProps;
32806
32188
  const containerStyle = [
32807
32189
  {
32808
32190
  width: '100%',
32809
- maxHeight
32191
+ maxHeight: maxH
32810
32192
  },
32811
32193
  getSpacingStyles(spacingProps),
32812
32194
  style
32813
32195
  ];
32814
- const scrollViewStyle = minWidth ? { minWidth } : undefined;
32196
+ const scrollViewStyle = minW ? { minWidth: minW } : undefined;
32815
32197
  return (jsx(View, { style: containerStyle, children: jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: Platform.OS === 'web', contentContainerStyle: scrollViewStyle, children: jsx(ScrollView, { style: { flex: 1 }, showsVerticalScrollIndicator: Platform.OS === 'web', children: children }) }) }));
32816
32198
  };
32817
32199
  // Main Table Component
@@ -33749,7 +33131,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
33749
33131
  alignItems: 'center',
33750
33132
  marginBottom: DESIGN_TOKENS.spacing.md,
33751
33133
  paddingHorizontal: DESIGN_TOKENS.spacing.xs
33752
- }, children: [jsx(Flex, { gap: DESIGN_TOKENS.spacing.md, align: "center", children: selectedRows.length > 0 && bulkActions.length > 0 && (jsxs(Flex, { gap: 8, children: [jsxs(Text, { variant: "small", colorVariant: "muted", children: [selectedRows.length, " selected"] }), bulkActions.map(action => (jsx(Button, { variant: "outline", size: "sm", startIcon: action.icon, onPress: () => action.action(selectedRows, data), children: action.label }, action.key)))] })) }), jsxs(Flex, { gap: 8, children: [(searchable || columns.some(c => c.filterable)) && (jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, width: 320, trapFocus: true, children: [jsx(Popover.Target, { children: jsxs(Button, { variant: "outline", size: "sm", startIcon: jsx(Icon, { name: "search", size: 14 }), children: ["Search", (searchValue || activeFilters.length > 0) && (jsx(View, { style: {
33134
+ }, children: [jsx(Flex, { gap: DESIGN_TOKENS.spacing.md, align: "center", children: selectedRows.length > 0 && bulkActions.length > 0 && (jsxs(Flex, { gap: 8, children: [jsxs(Text, { variant: "small", colorVariant: "muted", children: [selectedRows.length, " selected"] }), bulkActions.map(action => (jsx(Button, { variant: "outline", size: "sm", startIcon: action.icon, onPress: () => action.action(selectedRows, data), children: action.label }, action.key)))] })) }), jsxs(Flex, { gap: 8, children: [(searchable || columns.some(c => c.filterable)) && (jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, w: 320, trapFocus: true, children: [jsx(Popover.Target, { children: jsxs(Button, { variant: "outline", size: "sm", startIcon: jsx(Icon, { name: "search", size: 14 }), children: ["Search", (searchValue || activeFilters.length > 0) && (jsx(View, { style: {
33753
33135
  width: 6,
33754
33136
  height: 6,
33755
33137
  borderRadius: 3,
@@ -33779,7 +33161,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
33779
33161
  }) })), jsx(Flex, { direction: "column", gap: DESIGN_TOKENS.spacing.sm, children: columns.filter(c => c.filterable).map(column => {
33780
33162
  const currentFilter = getColumnFilter(column.key);
33781
33163
  return (jsx(View, { children: renderFilterControl(column) }, `${column.key}-${(currentFilter === null || currentFilter === void 0 ? void 0 : currentFilter.value) || 'no-filter'}`));
33782
- }) })] }))] }) })] })), onEditModeChange && (jsx(Button, { variant: editMode ? 'filled' : 'outline', size: "sm", onPress: () => onEditModeChange(!editMode), children: editMode ? 'Exit Edit' : 'Edit' })), showColumnVisibilityManager && (jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, width: 280, trapFocus: true, children: [jsx(Popover.Target, { children: jsx(Button, { variant: "outline", size: "sm", startIcon: jsx(Icon, { name: "eye", size: 14 }), children: "Columns" }) }), jsx(Popover.Dropdown, { children: jsxs(View, { style: { padding: 8, maxHeight: 300, width: 260 }, children: [jsx(ComponentWithDisclaimer, { disclaimer: "Selected view determines the layout style", disclaimerProps: { colorVariant: 'muted', size: 'sm' }, children: jsxs(Row, { children: [jsx(Button, { size: "xs", title: "Deselect All", variant: hiddenColumns.length === columns.length ? 'filled' : 'outline', onPress: () => setHiddenColumns(columns.map(c => c.key)), style: { marginBottom: 8 } }), jsx(Button, { size: "xs", title: "Select All", variant: hiddenColumns.length === 0 ? 'filled' : 'outline', onPress: () => setHiddenColumns([]), style: { marginBottom: 8 } })] }) }), jsx(ScrollView, { style: { maxHeight: 200 }, children: columns.map(col => (jsx(Checkbox, { label: tempHeaderEdits[col.key] || col.header, onChange: () => {
33164
+ }) })] }))] }) })] })), onEditModeChange && (jsx(Button, { variant: editMode ? 'filled' : 'outline', size: "sm", onPress: () => onEditModeChange(!editMode), children: editMode ? 'Exit Edit' : 'Edit' })), showColumnVisibilityManager && (jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, w: 280, trapFocus: true, children: [jsx(Popover.Target, { children: jsx(Button, { variant: "outline", size: "sm", startIcon: jsx(Icon, { name: "eye", size: 14 }), children: "Columns" }) }), jsx(Popover.Dropdown, { children: jsxs(View, { style: { padding: 8, maxHeight: 300, width: 260 }, children: [jsx(ComponentWithDisclaimer, { disclaimer: "Selected view determines the layout style", disclaimerProps: { colorVariant: 'muted', size: 'sm' }, children: jsxs(Row, { children: [jsx(Button, { size: "xs", title: "Deselect All", variant: hiddenColumns.length === columns.length ? 'filled' : 'outline', onPress: () => setHiddenColumns(columns.map(c => c.key)), style: { marginBottom: 8 } }), jsx(Button, { size: "xs", title: "Select All", variant: hiddenColumns.length === 0 ? 'filled' : 'outline', onPress: () => setHiddenColumns([]), style: { marginBottom: 8 } })] }) }), jsx(ScrollView, { style: { maxHeight: 200 }, children: columns.map(col => (jsx(Checkbox, { label: tempHeaderEdits[col.key] || col.header, onChange: () => {
33783
33165
  if (hiddenColumns.includes(col.key)) {
33784
33166
  setHiddenColumns(prev => prev.filter(h => h !== col.key));
33785
33167
  }
@@ -34153,9 +33535,9 @@ const resolveTokenColor = (token, theme) => {
34153
33535
  return token; // assume raw color string
34154
33536
  };
34155
33537
  // Item
34156
- const TimelineItem = forwardRef(({ children, title, bullet, colorVariant, lineVariant = 'solid', color, active, itemIndex = 0, isLastItem = false, itemAlign, ...rest }, ref) => {
33538
+ const TimelineItem = forwardRef(({ children, title, timestamp, bullet, colorVariant, lineVariant = 'solid', color, titleColor, descriptionColor, timestampColor, active, itemIndex = 0, isLastItem = false, itemAlign, ...rest }, ref) => {
34157
33539
  const theme = useTheme();
34158
- const { active: timelineActive, color: timelineColor, lineWidth, bulletSize: contextBulletSize, align, reverseActive, size, centerMode, metrics, } = useTimelineContext();
33540
+ const { active: timelineActive, color: timelineColor, lineWidth, bulletSize: contextBulletSize, align, reverseActive, size, centerMode, metrics, titleColor: timelineTitleColor, descriptionColor: timelineDescriptionColor, timestampColor: timelineTimestampColor, } = useTimelineContext();
34159
33541
  const sizeConfig = metrics;
34160
33542
  const finalBulletSize = contextBulletSize || sizeConfig.bulletSize;
34161
33543
  const showAllColored = timelineActive === undefined;
@@ -34170,6 +33552,9 @@ const TimelineItem = forwardRef(({ children, title, bullet, colorVariant, lineVa
34170
33552
  const resolvedItemColor = color
34171
33553
  ? color
34172
33554
  : (colorVariant ? resolveTokenColor(colorVariant, theme) : timelineColor);
33555
+ const resolvedTitleColor = titleColor !== null && titleColor !== void 0 ? titleColor : timelineTitleColor;
33556
+ const resolvedDescriptionColor = descriptionColor !== null && descriptionColor !== void 0 ? descriptionColor : timelineDescriptionColor;
33557
+ const resolvedTimestampColor = timestampColor !== null && timestampColor !== void 0 ? timestampColor : timelineTimestampColor;
34173
33558
  // Active logic
34174
33559
  const isActive = showAllColored
34175
33560
  ? true
@@ -34255,10 +33640,16 @@ const TimelineItem = forwardRef(({ children, title, bullet, colorVariant, lineVa
34255
33640
  const getTitleStyle = () => ({
34256
33641
  fontSize: sizeConfig.fontSize,
34257
33642
  fontWeight: '600',
34258
- color: theme.text.primary,
33643
+ color: resolvedTitleColor !== null && resolvedTitleColor !== void 0 ? resolvedTitleColor : theme.text.primary,
34259
33644
  marginBottom: title && children ? 4 : 0,
34260
33645
  textAlign: effectiveAlign === 'right' ? 'right' : 'left',
34261
33646
  });
33647
+ const getTimestampStyle = () => ({
33648
+ fontSize: Math.max(10, Math.round(sizeConfig.fontSize * 0.8)),
33649
+ color: resolvedTimestampColor !== null && resolvedTimestampColor !== void 0 ? resolvedTimestampColor : theme.text.secondary,
33650
+ marginBottom: (title || children) ? 4 : 0,
33651
+ textAlign: effectiveAlign === 'right' ? 'right' : 'left',
33652
+ });
34262
33653
  const getItemWrapperStyle = () => {
34263
33654
  if (centerMode) {
34264
33655
  return {
@@ -34274,36 +33665,53 @@ const TimelineItem = forwardRef(({ children, title, bullet, colorVariant, lineVa
34274
33665
  alignItems: 'flex-start',
34275
33666
  };
34276
33667
  };
33668
+ const applyTextStyle = (nodes, styleOverride) => {
33669
+ if (!styleOverride)
33670
+ return nodes;
33671
+ return React__default.Children.map(nodes, (child) => {
33672
+ var _a;
33673
+ if (typeof child === 'string' || typeof child === 'number') {
33674
+ return jsx(Text$1, { style: styleOverride, children: child });
33675
+ }
33676
+ if (!React__default.isValidElement(child))
33677
+ return child;
33678
+ const props = child.props || {};
33679
+ const isTextLike = ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'Text' || child.type === Text$1 || typeof props.children === 'string';
33680
+ if (isTextLike) {
33681
+ const mergedStyle = Array.isArray(props.style)
33682
+ ? [...props.style, styleOverride]
33683
+ : [props.style, styleOverride];
33684
+ return React__default.cloneElement(child, { style: mergedStyle });
33685
+ }
33686
+ if (props.children) {
33687
+ return React__default.cloneElement(child, { children: applyTextStyle(props.children, styleOverride) });
33688
+ }
33689
+ return child;
33690
+ });
33691
+ };
34277
33692
  if (centerMode) {
34278
33693
  // Three column layout: left content | bullet/line | right content
34279
33694
  const leftContent = effectiveAlign === 'left' && (title || children);
34280
33695
  const rightContent = effectiveAlign === 'right' && (title || children);
34281
33696
  // Helper to clone Text children with alignment
34282
33697
  const alignChildText = (nodes, side) => {
34283
- return React__default.Children.map(nodes, (child) => {
34284
- var _a;
34285
- if (!React__default.isValidElement(child))
34286
- return child;
34287
- const props = child.props || {};
34288
- const isTextLike = ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'Text' || (typeof props.children === 'string');
34289
- if (isTextLike) {
34290
- const mergedStyle = Array.isArray(props.style)
34291
- ? [...props.style, { textAlign: side }]
34292
- : [props.style, { textAlign: side }];
34293
- return React__default.cloneElement(child, { style: mergedStyle });
34294
- }
34295
- if (props.children) {
34296
- return React__default.cloneElement(child, { children: alignChildText(props.children, side) });
34297
- }
34298
- return child;
34299
- });
33698
+ const styleOverride = {
33699
+ textAlign: side,
33700
+ ...(resolvedDescriptionColor ? { color: resolvedDescriptionColor } : {}),
33701
+ };
33702
+ return applyTextStyle(nodes, styleOverride);
34300
33703
  };
34301
- return (jsxs(View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [jsx(View, { style: { flex: 1, paddingRight: sizeConfig.spacing, alignItems: 'flex-end' }, children: leftContent && (jsxs(View, { style: { width: '100%', alignItems: 'flex-end' }, children: [title && jsx(Text$1, { style: [getTitleStyle(), { textAlign: 'right' }], children: title }), alignChildText(children, 'right')] })) }), jsxs(View, { style: { width: finalBulletSize, alignItems: 'center', position: 'relative' }, children: [getLine(), jsx(View, { style: getBulletStyle(), children: bullet })] }), jsx(View, { style: { flex: 1, paddingLeft: sizeConfig.spacing, alignItems: 'flex-start' }, children: rightContent && (jsxs(View, { style: { width: '100%', alignItems: 'flex-start' }, children: [title && jsx(Text$1, { style: [getTitleStyle(), { textAlign: 'left' }], children: title }), alignChildText(children, 'left')] })) })] }));
33704
+ return (jsxs(View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [jsx(View, { style: { flex: 1, paddingRight: sizeConfig.spacing, alignItems: 'flex-end' }, children: leftContent && (jsxs(View, { style: { width: '100%', alignItems: 'flex-end' }, children: [timestamp && (jsx(Text$1, { style: [getTimestampStyle(), { textAlign: 'right' }], children: timestamp })), title && jsx(Text$1, { style: [getTitleStyle(), { textAlign: 'right' }], children: title }), alignChildText(children, 'right')] })) }), jsxs(View, { style: { width: finalBulletSize, alignItems: 'center', position: 'relative' }, children: [getLine(), jsx(View, { style: getBulletStyle(), children: bullet })] }), jsx(View, { style: { flex: 1, paddingLeft: sizeConfig.spacing, alignItems: 'flex-start' }, children: rightContent && (jsxs(View, { style: { width: '100%', alignItems: 'flex-start' }, children: [timestamp && (jsx(Text$1, { style: [getTimestampStyle(), { textAlign: 'left' }], children: timestamp })), title && jsx(Text$1, { style: [getTitleStyle(), { textAlign: 'left' }], children: title }), alignChildText(children, 'left')] })) })] }));
34302
33705
  }
34303
- return (jsxs(View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [getLine(), jsx(View, { style: getBulletStyle(), children: bullet }), (title || children) && (jsxs(View, { style: getContentStyle(), children: [title && jsx(Text$1, { style: getTitleStyle(), children: title }), children] }))] }));
33706
+ return (jsxs(View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [getLine(), jsx(View, { style: getBulletStyle(), children: bullet }), (title || children) && (jsxs(View, { style: getContentStyle(), children: [timestamp && jsx(Text$1, { style: getTimestampStyle(), children: timestamp }), title && jsx(Text$1, { style: getTitleStyle(), children: title }), resolvedDescriptionColor
33707
+ ? applyTextStyle(children, {
33708
+ color: resolvedDescriptionColor,
33709
+ textAlign: effectiveAlign === 'right' ? 'right' : 'left',
33710
+ })
33711
+ : children] }))] }));
34304
33712
  });
34305
33713
  // Root Timeline
34306
- const Timeline = forwardRef(({ children, active, color, colorVariant, lineWidth, bulletSize, align = 'left', reverseActive = false, size = 'md', centerMode = false, ...rest }, ref) => {
33714
+ const Timeline = forwardRef(({ children, active, color, colorVariant, titleColor, descriptionColor, timestampColor, lineWidth, bulletSize, align = 'left', reverseActive = false, size = 'md', centerMode = false, ...rest }, ref) => {
34307
33715
  const theme = useTheme();
34308
33716
  const clampedSize = clampComponentSize(size, TIMELINE_ALLOWED_SIZES);
34309
33717
  const baseMetrics = resolveTimelineMetrics(clampedSize);
@@ -34325,6 +33733,9 @@ const Timeline = forwardRef(({ children, active, color, colorVariant, lineWidth,
34325
33733
  size: clampedSize,
34326
33734
  metrics,
34327
33735
  centerMode,
33736
+ titleColor,
33737
+ descriptionColor,
33738
+ timestampColor,
34328
33739
  };
34329
33740
  const items = [];
34330
33741
  React__default.Children.forEach(children, (child, index) => {
@@ -35042,7 +34453,7 @@ const Notice = factory(NoticeBase);
35042
34453
  Notice.displayName = 'Notice';
35043
34454
 
35044
34455
  function SkeletonBase(props, ref) {
35045
- const { shape = 'rectangle', width, height, size = 'md', radius, animate = true, animationDuration = 1500, colors, style, testID, ...rest } = props;
34456
+ const { shape = 'rectangle', w, h, size = 'md', radius, animate = true, animationDuration = 1500, colors, style, testID, ...rest } = props;
35046
34457
  const { spacingProps, otherProps } = extractSpacingProps(rest);
35047
34458
  const spacingStyles = getSpacingStyles(spacingProps);
35048
34459
  const theme = useTheme();
@@ -35063,36 +34474,36 @@ function SkeletonBase(props, ref) {
35063
34474
  switch (shape) {
35064
34475
  case 'text':
35065
34476
  return {
35066
- width: width || '100%',
35067
- height: height || getSpacing('md')
34477
+ width: w || '100%',
34478
+ height: h || getSpacing('md')
35068
34479
  };
35069
34480
  case 'chip':
35070
34481
  return {
35071
- width: width || (sizeValue * 3),
35072
- height: height || sizeValue
34482
+ width: w || (sizeValue * 3),
34483
+ height: h || sizeValue
35073
34484
  };
35074
34485
  case 'avatar':
35075
34486
  case 'circle':
35076
34487
  return {
35077
- width: width || sizeValue,
35078
- height: height || sizeValue
34488
+ width: w || sizeValue,
34489
+ height: h || sizeValue
35079
34490
  };
35080
34491
  case 'button':
35081
34492
  return {
35082
- width: width || (sizeValue * 4),
35083
- height: height || sizeValue
34493
+ width: w || (sizeValue * 4),
34494
+ height: h || sizeValue
35084
34495
  };
35085
34496
  case 'card':
35086
34497
  return {
35087
- width: width || '100%',
35088
- height: height || (sizeValue * 6)
34498
+ width: w || '100%',
34499
+ height: h || (sizeValue * 6)
35089
34500
  };
35090
34501
  case 'rectangle':
35091
34502
  case 'rounded':
35092
34503
  default:
35093
34504
  return {
35094
- width: width || '100%',
35095
- height: height || sizeValue
34505
+ width: w || '100%',
34506
+ height: h || sizeValue
35096
34507
  };
35097
34508
  }
35098
34509
  };
@@ -35731,104 +35142,6 @@ const Ring = factory((props, ref) => {
35731
35142
  return (jsxs(View, { ref: ref, style: [styles$8.container, spacingStyles, style], testID: testID, accessibilityLabel: accessibilityLabel !== null && accessibilityLabel !== void 0 ? accessibilityLabel : `Ring value ${Math.round(percent)} percent`, accessibilityRole: "progressbar", accessibilityValue: { min, max, now: Math.round(clampedValue) }, ...otherProps, children: [jsxs(View, { style: [styles$8.ringWrapper, { width: size, height: size }, ringStyle], children: [jsxs(Svg, { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [jsx(Circle, { cx: size / 2, cy: size / 2, r: radius, stroke: defaultTrackColor, strokeWidth: thickness, fill: "transparent" }), jsx(Circle, { cx: size / 2, cy: size / 2, r: radius, stroke: resolvedProgressColor, strokeWidth: thickness, strokeLinecap: roundedCaps ? 'round' : 'butt', strokeDasharray: `${circumference} ${circumference}`, strokeDashoffset: dashOffset, fill: "transparent", transform: `rotate(-90 ${size / 2} ${size / 2})` })] }), jsx(View, { pointerEvents: "none", style: [styles$8.centerContent, { width: size, height: size }, contentStyle], children: centerContent })] }), caption !== undefined && caption !== null ? (React__default.isValidElement(caption) ? (caption) : (jsx(Text, { variant: "span", size: "xs", color: captionTextColor, weight: "600", style: [{ marginTop: 6, letterSpacing: 1 }, captionStyle], children: caption }))) : null] }));
35732
35143
  }, { displayName: 'Ring' });
35733
35144
 
35734
- const NAVIGATIONPROGRESS_DEFAULTS = {
35735
- size: 3,
35736
- color: 'primary',
35737
- zIndex: 9999,
35738
- overlay: true,
35739
- stepInterval: 500,
35740
- radius: 0,
35741
- };
35742
-
35743
- let subscribers = new Set();
35744
- let internalState = { value: 0, active: false };
35745
- let interval = null;
35746
- function broadcast() { subscribers.forEach(cb => cb({ ...internalState })); }
35747
- function schedule(intervalMs) {
35748
- clearInterval(interval);
35749
- interval = setInterval(() => {
35750
- if (!internalState.active)
35751
- return;
35752
- const remain = 100 - internalState.value;
35753
- const inc = Math.max(0.1, remain * 0.03);
35754
- internalState.value = Math.min(99, internalState.value + inc);
35755
- broadcast();
35756
- }, intervalMs);
35757
- }
35758
- const navigationProgress = {
35759
- start() { if (internalState.active)
35760
- return; internalState.active = true; if (internalState.value >= 100)
35761
- internalState.value = 0; broadcast(); schedule(NAVIGATIONPROGRESS_DEFAULTS.stepInterval); },
35762
- stop() { internalState.active = false; broadcast(); },
35763
- complete() { internalState.active = true; internalState.value = 100; broadcast(); setTimeout(() => { internalState.active = false; internalState.value = 0; broadcast(); }, 400); },
35764
- reset() { internalState.value = 0; internalState.active = false; broadcast(); },
35765
- set(v) { internalState.value = Math.max(0, Math.min(100, v)); broadcast(); },
35766
- increment(delta = 5) { internalState.value = Math.min(100, internalState.value + delta); broadcast(); },
35767
- decrement(delta = 5) { internalState.value = Math.max(0, internalState.value - delta); broadcast(); },
35768
- isActive() { return internalState.active; }
35769
- };
35770
- const NavigationProgress = ({ value, size = NAVIGATIONPROGRESS_DEFAULTS.size, color = NAVIGATIONPROGRESS_DEFAULTS.color, zIndex = NAVIGATIONPROGRESS_DEFAULTS.zIndex, overlay = NAVIGATIONPROGRESS_DEFAULTS.overlay, stepInterval = NAVIGATIONPROGRESS_DEFAULTS.stepInterval, radius = NAVIGATIONPROGRESS_DEFAULTS.radius, active = true, style }) => {
35771
- const theme = useTheme();
35772
- const scheme = useColorScheme();
35773
- const isDark = scheme === 'dark';
35774
- const progress = useSharedValue(0);
35775
- const opacity = useSharedValue(0);
35776
- useEffect(() => {
35777
- const sub = (s) => {
35778
- if (value == null) {
35779
- progress.value = withTiming(s.value, { duration: stepInterval });
35780
- opacity.value = withTiming(s.active ? 1 : 0, { duration: 150 });
35781
- }
35782
- };
35783
- subscribers.add(sub);
35784
- broadcast();
35785
- return () => { subscribers.delete(sub); };
35786
- }, [value, stepInterval, progress, opacity]);
35787
- useEffect(() => {
35788
- if (value != null) {
35789
- progress.value = withTiming(value, { duration: stepInterval });
35790
- opacity.value = withTiming(active ? 1 : 0, { duration: 150 });
35791
- }
35792
- }, [value, active, stepInterval]);
35793
- let resolvedColor = color;
35794
- if (theme.colors[color]) {
35795
- const bucket = theme.colors[color];
35796
- resolvedColor = bucket[5] || bucket[4] || bucket[0];
35797
- }
35798
- const barStyle = useAnimatedStyle(() => ({ width: `${progress.value}%` }));
35799
- const containerStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
35800
- return (jsxs(Animated.View, { style: [
35801
- {
35802
- position: overlay ? 'absolute' : 'relative',
35803
- top: 0,
35804
- left: 0,
35805
- right: 0,
35806
- height: size,
35807
- backgroundColor: isDark ? theme.colors.gray[3] : theme.colors.gray[2],
35808
- overflow: 'hidden',
35809
- zIndex,
35810
- borderRadius: radius,
35811
- pointerEvents: 'none'
35812
- },
35813
- containerStyle,
35814
- style
35815
- ], children: [jsx(Animated.View, { style: [{
35816
- position: 'absolute',
35817
- top: 0,
35818
- bottom: 0,
35819
- left: 0,
35820
- backgroundColor: resolvedColor,
35821
- borderRadius: radius,
35822
- }, barStyle] }), jsx(Animated.View, { style: [{
35823
- position: 'absolute',
35824
- top: 0,
35825
- bottom: 0,
35826
- right: 0,
35827
- width: 80,
35828
- backgroundColor: 'rgba(255,255,255,0.2)'
35829
- }, barStyle] })] }));
35830
- };
35831
-
35832
35145
  const DEFAULT_OPACITY = 0.6;
35833
35146
  const HEX_COLOR_REGEX = /^#?[0-9a-f]{3,8}$/i;
35834
35147
  const clampOpacity = (value) => {
@@ -36021,270 +35334,6 @@ const LoadingOverlay = React__default.forwardRef((props, ref) => {
36021
35334
  });
36022
35335
  LoadingOverlay.displayName = 'LoadingOverlay';
36023
35336
 
36024
- // A lightweight hover-activated floating panel similar to Mantine HoverCard
36025
- function HoverCardBase(props, ref) {
36026
- const { children, target, position = 'top', offset = 8, openDelay = 100, closeDelay = 150, opened: controlledOpened, shadow = 'md', radius = 'md', withinPortal = true, width, withArrow = false, closeOnEscape = true, onOpen, onClose, disabled = false, style, testID, zIndex = 3000, keepMounted = false, trigger = 'hover', } = props;
36027
- const [opened, setOpened] = useState(false);
36028
- const openTimeout = useRef(null);
36029
- const closeTimeout = useRef(null);
36030
- const containerRef = useRef(null);
36031
- const targetRef = useRef(null);
36032
- const overlayIdRef = useRef(null);
36033
- const overlayContentRef = useRef(null);
36034
- const isHoveringTargetRef = useRef(false);
36035
- const isHoveringOverlayRef = useRef(false);
36036
- const theme = useTheme();
36037
- const { openOverlay, closeOverlay, updateOverlay } = useOverlay();
36038
- const isOpened = controlledOpened !== undefined ? controlledOpened : opened;
36039
- const clearTimers = () => {
36040
- if (openTimeout.current) {
36041
- clearTimeout(openTimeout.current);
36042
- openTimeout.current = null;
36043
- }
36044
- if (closeTimeout.current) {
36045
- clearTimeout(closeTimeout.current);
36046
- closeTimeout.current = null;
36047
- }
36048
- };
36049
- const doOpen = useCallback(() => {
36050
- if (disabled)
36051
- return;
36052
- setOpened(true);
36053
- onOpen === null || onOpen === void 0 ? void 0 : onOpen();
36054
- }, [disabled, onOpen]);
36055
- const doClose = useCallback(() => {
36056
- setOpened(false);
36057
- onClose === null || onClose === void 0 ? void 0 : onClose();
36058
- }, [onClose]);
36059
- const scheduleOpen = useCallback(() => {
36060
- clearTimers();
36061
- openTimeout.current = setTimeout(doOpen, openDelay);
36062
- }, [doOpen, openDelay]);
36063
- const scheduleClose = useCallback(() => {
36064
- clearTimers();
36065
- closeTimeout.current = setTimeout(() => {
36066
- // Only close if neither target nor overlay are hovered (web)
36067
- if (Platform.OS === 'web') {
36068
- if (isHoveringTargetRef.current || isHoveringOverlayRef.current)
36069
- return;
36070
- }
36071
- doClose();
36072
- }, closeDelay);
36073
- }, [doClose, closeDelay]);
36074
- useEffect(() => () => clearTimers(), []);
36075
- // Escape key (web only)
36076
- useEffect(() => {
36077
- if (!closeOnEscape || Platform.OS !== 'web')
36078
- return;
36079
- const handler = (e) => { if (e.key === 'Escape')
36080
- doClose(); };
36081
- document.addEventListener('keydown', handler);
36082
- return () => document.removeEventListener('keydown', handler);
36083
- }, [closeOnEscape, doClose]);
36084
- const getInlinePositionStyle = () => {
36085
- const base = { position: 'absolute' };
36086
- switch (position) {
36087
- case 'top': return { ...base, bottom: '100%', left: 0, marginBottom: offset };
36088
- case 'bottom': return { ...base, top: '100%', left: 0, marginTop: offset };
36089
- case 'left': return { ...base, right: '100%', top: 0, marginRight: offset };
36090
- case 'right': return { ...base, left: '100%', top: 0, marginLeft: offset };
36091
- default: return { ...base, top: '100%', left: 0, marginTop: offset };
36092
- }
36093
- };
36094
- const shadowStyle = (() => {
36095
- switch (shadow) {
36096
- case 'sm':
36097
- return { boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', elevation: 2 };
36098
- case 'md':
36099
- return { boxShadow: '0 2px 4px rgba(0, 0, 0, 0.15)', elevation: 4 };
36100
- case 'lg':
36101
- return { boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)', elevation: 8 };
36102
- default:
36103
- return {};
36104
- }
36105
- })();
36106
- const renderArrow = (placement) => {
36107
- if (!withArrow)
36108
- return null;
36109
- const base = { position: 'absolute', width: 0, height: 0 };
36110
- const color = theme.colors.gray[0];
36111
- const styles = {
36112
- top: { top: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderTopWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: color },
36113
- bottom: { bottom: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderBottomWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderBottomColor: color },
36114
- left: { left: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderLeftWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderLeftColor: color },
36115
- right: { right: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderRightWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderRightColor: color },
36116
- };
36117
- const key = placement.split('-')[0];
36118
- return jsx(View, { style: { ...base, ...(styles[key] || styles.top) } });
36119
- };
36120
- const openPortal = useCallback(async () => {
36121
- if (!withinPortal || !isOpened || overlayIdRef.current)
36122
- return;
36123
- const rect = await measureElement(targetRef);
36124
- const estWidth = width || 240;
36125
- const estHeight = 160; // rough initial height
36126
- const pos = calculateOverlayPositionEnhanced(rect, { width: estWidth, height: estHeight }, {
36127
- placement: position,
36128
- offset,
36129
- viewport: getViewport(),
36130
- strategy: 'fixed'
36131
- });
36132
- const overlayContent = (jsxs(View, { ref: overlayContentRef, style: [
36133
- {
36134
- backgroundColor: theme.colors.gray[0],
36135
- borderRadius: getRadius$2(radius),
36136
- paddingHorizontal: getSpacing('md'),
36137
- paddingVertical: getSpacing('sm'),
36138
- borderWidth: 1,
36139
- borderColor: theme.colors.gray[3],
36140
- minWidth: width || 160,
36141
- maxWidth: width || 320,
36142
- },
36143
- shadowStyle,
36144
- ], ...(Platform.OS === 'web' && trigger === 'hover' ? {
36145
- onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
36146
- onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
36147
- } : {}), children: [children, renderArrow(pos.placement)] }));
36148
- const id = openOverlay({
36149
- content: overlayContent,
36150
- anchor: { x: pos.x, y: pos.y, width: estWidth, height: estHeight },
36151
- trigger: trigger,
36152
- // For hover-triggered overlays, do NOT render a click-outside backdrop – it steals hover
36153
- // and immediately fires target onMouseLeave. We rely on pointer leave timers instead.
36154
- closeOnClickOutside: trigger !== 'hover',
36155
- closeOnEscape: closeOnEscape,
36156
- strategy: 'fixed',
36157
- onClose: () => { overlayIdRef.current = null; if (opened)
36158
- setOpened(false); onClose === null || onClose === void 0 ? void 0 : onClose(); },
36159
- zIndex
36160
- });
36161
- overlayIdRef.current = id;
36162
- }, [withinPortal, isOpened, overlayIdRef, position, offset, width, trigger, closeOnEscape, theme, radius, shadowStyle, children, opened, onClose, getSpacing, getRadius$2]);
36163
- const closePortal = useCallback(() => {
36164
- if (overlayIdRef.current) {
36165
- closeOverlay(overlayIdRef.current);
36166
- overlayIdRef.current = null;
36167
- }
36168
- }, [closeOverlay]);
36169
- useEffect(() => {
36170
- if (withinPortal) {
36171
- if (isOpened)
36172
- openPortal();
36173
- else
36174
- closePortal();
36175
- }
36176
- return () => { if (!isOpened)
36177
- closePortal(); };
36178
- }, [isOpened, withinPortal, openPortal, closePortal]);
36179
- useEffect(() => {
36180
- if (!withinPortal || Platform.OS !== 'web' || !isOpened || !overlayIdRef.current)
36181
- return;
36182
- const handler = () => {
36183
- Promise.all([measureElement(targetRef)]).then(([rect]) => {
36184
- var _a, _b;
36185
- const actualWidth = ((_a = overlayContentRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || width || 240;
36186
- const actualHeight = ((_b = overlayContentRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 160;
36187
- const pos = calculateOverlayPositionEnhanced(rect, { width: actualWidth, height: actualHeight }, {
36188
- placement: position,
36189
- offset,
36190
- viewport: getViewport(),
36191
- strategy: 'fixed'
36192
- });
36193
- updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: actualWidth, height: actualHeight } });
36194
- });
36195
- };
36196
- window.addEventListener('resize', handler);
36197
- window.addEventListener('scroll', handler, true);
36198
- return () => {
36199
- window.removeEventListener('resize', handler);
36200
- window.removeEventListener('scroll', handler, true);
36201
- };
36202
- }, [withinPortal, isOpened, position, offset, width, updateOverlay]);
36203
- // Smart sizing: after content mounts, measure actual size and reposition if changed
36204
- useEffect(() => {
36205
- if (!withinPortal || !isOpened || !overlayIdRef.current)
36206
- return;
36207
- let frame;
36208
- const attempt = () => {
36209
- Promise.all([
36210
- measureElement(targetRef),
36211
- measureElement({ current: overlayContentRef.current })
36212
- ]).then(([targetRect, contentRect]) => {
36213
- if (!targetRect.width || !contentRect.width)
36214
- return; // skip invalid
36215
- const desiredWidth = width || contentRect.width;
36216
- const desiredHeight = contentRect.height;
36217
- // Recalculate with actual content size
36218
- const pos = calculateOverlayPositionEnhanced(targetRect, { width: desiredWidth, height: desiredHeight }, {
36219
- placement: position,
36220
- offset,
36221
- viewport: getViewport(),
36222
- strategy: 'fixed'
36223
- });
36224
- updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: desiredWidth, height: desiredHeight } });
36225
- });
36226
- };
36227
- // Delay a bit to allow layout
36228
- frame = setTimeout(attempt, 30);
36229
- return () => { if (frame)
36230
- clearTimeout(frame); };
36231
- }, [withinPortal, isOpened, position, offset, width, updateOverlay]);
36232
- const targetProps = {};
36233
- if (trigger === 'hover') {
36234
- if (Platform.OS === 'web') {
36235
- targetProps.onMouseEnter = () => { isHoveringTargetRef.current = true; scheduleOpen(); };
36236
- targetProps.onMouseLeave = () => { isHoveringTargetRef.current = false; scheduleClose(); };
36237
- }
36238
- else {
36239
- // fallback: tap to toggle on native
36240
- targetProps.onPress = () => {
36241
- if (isOpened) {
36242
- doClose();
36243
- }
36244
- else {
36245
- doOpen();
36246
- }
36247
- };
36248
- }
36249
- }
36250
- else if (trigger === 'click') {
36251
- targetProps.onPress = () => {
36252
- if (isOpened) {
36253
- doClose();
36254
- }
36255
- else {
36256
- doOpen();
36257
- }
36258
- };
36259
- }
36260
- const inlineContent = (isOpened || keepMounted) && !withinPortal ? (jsxs(View, { style: [
36261
- getInlinePositionStyle(),
36262
- {
36263
- backgroundColor: theme.colors.gray[0],
36264
- borderRadius: getRadius$2(radius),
36265
- paddingHorizontal: getSpacing('md'),
36266
- paddingVertical: getSpacing('sm'),
36267
- borderWidth: 1,
36268
- borderColor: theme.colors.gray[3],
36269
- minWidth: width,
36270
- zIndex,
36271
- },
36272
- shadowStyle,
36273
- ], pointerEvents: "auto", ...(Platform.OS === 'web' && trigger === 'hover' ? {
36274
- onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
36275
- onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
36276
- } : {}), children: [children, renderArrow(position)] })) : null;
36277
- return (jsxs(View, { ref: ref, style: [{ position: 'relative', alignSelf: 'flex-start' }, style], testID: testID, children: [jsx(Pressable, { ref: (node) => { containerRef.current = node; targetRef.current = node; }, ...targetProps, style: ({ pressed }) => {
36278
- var _a;
36279
- return [
36280
- { opacity: pressed ? 0.85 : 1 },
36281
- (_a = target === null || target === void 0 ? void 0 : target.props) === null || _a === void 0 ? void 0 : _a.style,
36282
- ];
36283
- }, children: target }), inlineContent] }));
36284
- }
36285
- const HoverCard = factory(HoverCardBase);
36286
- HoverCard.displayName = 'HoverCard';
36287
-
36288
35337
  const ContextMenu = ({ children, items, closeOnSelect = true, longPressDelay = 350, maxHeight = 280, onOpen, onClose, open: controlledOpen, position: controlledPosition, portalId, style, }) => {
36289
35338
  var _a, _b;
36290
35339
  const [internalOpen, setInternalOpen] = useState(false);
@@ -36522,7 +35571,7 @@ const styles$6 = StyleSheet.create({
36522
35571
  },
36523
35572
  });
36524
35573
 
36525
- const WaveformSkeleton = ({ width = 300, height = 60, fullWidth = false, barsCount = 20, }) => {
35574
+ const WaveformSkeleton = ({ w = 300, h = 60, fullWidth = false, barsCount = 20, }) => {
36526
35575
  const theme = useTheme();
36527
35576
  const styles = StyleSheet.create({
36528
35577
  animatedBar: {
@@ -36538,18 +35587,18 @@ const WaveformSkeleton = ({ width = 300, height = 60, fullWidth = false, barsCou
36538
35587
  backgroundColor: theme.colors.gray[1],
36539
35588
  borderRadius: 4,
36540
35589
  flexDirection: 'row',
36541
- height,
35590
+ height: h,
36542
35591
  justifyContent: 'space-between',
36543
35592
  paddingHorizontal: 4,
36544
- width: fullWidth ? '100%' : width,
35593
+ width: fullWidth ? '100%' : w,
36545
35594
  },
36546
35595
  });
36547
35596
  // Generate random heights for skeleton bars
36548
35597
  const barHeights = Array.from({ length: barsCount }, () => Math.random() * 0.6 + 0.2 // Heights between 20% and 80% of container
36549
35598
  );
36550
- const barWidth = fullWidth ? 'auto' : Math.max(1, (width - 40) / barsCount - 2);
35599
+ const barWidth = fullWidth ? 'auto' : Math.max(1, (w - 40) / barsCount - 2);
36551
35600
  return (jsx(View, { style: styles.container, children: barHeights.map((heightRatio, index) => {
36552
- const barHeight = height * heightRatio;
35601
+ const barHeight = h * heightRatio;
36553
35602
  const isAnimated = index % 3 === 0; // Animate every 3rd bar for shimmer effect
36554
35603
  return (jsx(View, { style: [
36555
35604
  styles.bar,
@@ -36564,7 +35613,7 @@ const WaveformSkeleton = ({ width = 300, height = 60, fullWidth = false, barsCou
36564
35613
  }) }));
36565
35614
  };
36566
35615
 
36567
- const Waveform = React__default.memo(({ peaks, width = 300, height = 60, color = 'primary', barWidth = 2, barGap = 1, strokeWidth = 2, minBarHeight = 1, variant = 'bars', gradientColors, progress = 0, progressColor, interactive = false, normalize = false, fullWidth = false, onSeek, onDragStart, onDrag, onDragEnd, accessibilityLabel, accessibilityHint, style, maxVisibleBars, showProgressLine = false, progressLineStyle, showTimeStamps = false, duration, timeStampInterval,
35616
+ const Waveform = React__default.memo(({ peaks, w = 300, h = 60, color = 'primary', barWidth = 2, barGap = 1, strokeWidth = 2, minBarHeight = 1, variant = 'bars', gradientColors, progress = 0, progressColor, interactive = false, normalize = false, fullWidth = false, onSeek, onDragStart, onDrag, onDragEnd, accessibilityLabel, accessibilityHint, style, maxVisibleBars, showProgressLine = false, progressLineStyle, showTimeStamps = false, duration, timeStampInterval,
36568
35617
  // New features
36569
35618
  loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel = 1, zoomCenter = 0.5, onZoomChange, enableAnimations = true, showRMS = false, rmsData, markers = [], enablePerformanceMonitoring = false, onPerformanceMetrics, ...restProps }) => {
36570
35619
  const theme = useTheme();
@@ -36651,12 +35700,12 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36651
35700
  targetBars = maxVisibleBars || peaks.length;
36652
35701
  }
36653
35702
  else {
36654
- // For fixed width, calculate how many bars fit
36655
- const maxBars = Math.floor(width / totalBarSpace);
35703
+ // For fixed w, calculate how many bars fit
35704
+ const maxBars = Math.floor(w / totalBarSpace);
36656
35705
  targetBars = maxVisibleBars ? Math.min(maxBars, maxVisibleBars) : maxBars;
36657
35706
  }
36658
35707
  if (targetBars <= 0) {
36659
- console.warn('Waveform: Not enough width to render any bars');
35708
+ console.warn('Waveform: Not enough w to render any bars');
36660
35709
  return [];
36661
35710
  }
36662
35711
  // If we have fewer peaks than target bars, return all peaks
@@ -36679,7 +35728,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36679
35728
  downsampled.push(maxValue);
36680
35729
  }
36681
35730
  return downsampled;
36682
- }, [peaks, width, barWidth, barGap, fullWidth, maxVisibleBars]);
35731
+ }, [peaks, w, barWidth, barGap, fullWidth, maxVisibleBars]);
36683
35732
  // Normalize peaks if requested
36684
35733
  const normalizedPeaks = useMemo(() => {
36685
35734
  if (!normalize || processedPeaks.length === 0) {
@@ -36702,16 +35751,16 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36702
35751
  if (fullWidth) {
36703
35752
  return {
36704
35753
  width: '100%',
36705
- height: height,
36706
- viewBox: `0 0 ${actualWaveformWidth} ${height}`,
35754
+ height: h,
35755
+ viewBox: `0 0 ${actualWaveformWidth} ${h}`,
36707
35756
  preserveAspectRatio: 'none'
36708
35757
  };
36709
35758
  }
36710
35759
  return {
36711
- width: width,
36712
- height: height
35760
+ width: w,
35761
+ height: h
36713
35762
  };
36714
- }, [fullWidth, actualWaveformWidth, height, width]);
35763
+ }, [fullWidth, actualWaveformWidth, h, w]);
36715
35764
  const handleLayout = useCallback((event) => {
36716
35765
  const { width: containerWidth, height: containerHeight } = event.nativeEvent.layout;
36717
35766
  setContainerDimensions({ width: containerWidth, height: containerHeight });
@@ -36726,7 +35775,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36726
35775
  }
36727
35776
  else {
36728
35777
  // Fallback if container hasn't been measured yet
36729
- position = locationX / (width || 300);
35778
+ position = locationX / (w || 300);
36730
35779
  }
36731
35780
  }
36732
35781
  else {
@@ -36734,7 +35783,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36734
35783
  position = Math.min(locationX, actualWaveformWidth) / actualWaveformWidth;
36735
35784
  }
36736
35785
  return Math.max(0, Math.min(1, position));
36737
- }, [fullWidth, containerDimensions.width, width, actualWaveformWidth]);
35786
+ }, [fullWidth, containerDimensions.width, w, actualWaveformWidth]);
36738
35787
  const handleResponderGrant = useCallback((event) => {
36739
35788
  var _a, _b, _c;
36740
35789
  if (!interactive)
@@ -36821,8 +35870,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36821
35870
  const renderBars = () => {
36822
35871
  return normalizedPeaks.map((peak, index) => {
36823
35872
  const x = index * (barWidth + barGap);
36824
- const barHeight = Math.max(minBarHeight, Math.abs(peak) * height * 0.8);
36825
- const y = (height - barHeight) / 2;
35873
+ const barHeight = Math.max(minBarHeight, Math.abs(peak) * h * 0.8);
35874
+ const y = (h - barHeight) / 2;
36826
35875
  const isProgress = x < progressX;
36827
35876
  const fillColor = isProgress ? actualProgressColor : waveformColor;
36828
35877
  return (jsx(Rect, { x: x, y: y, width: barWidth, height: barHeight, fill: fillColor, rx: variant === 'rounded' ? barWidth / 2 : 0 }, index));
@@ -36836,7 +35885,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36836
35885
  const stepX = actualWaveformWidth / (normalizedPeaks.length - 1);
36837
35886
  normalizedPeaks.forEach((peak, index) => {
36838
35887
  const x = index * stepX;
36839
- const y = height / 2 + (peak * height * 0.4);
35888
+ const y = h / 2 + (peak * h * 0.4);
36840
35889
  const lineCommand = index === 0 ? `M ${x} ${y}` : ` L ${x} ${y}`;
36841
35890
  pathData += lineCommand;
36842
35891
  // Build progress path up to the progress position
@@ -36850,8 +35899,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36850
35899
  const renderGradient = () => {
36851
35900
  return (jsxs(Fragment, { children: [jsx(Defs, { children: jsx(LinearGradient, { id: gradientId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: resolvedGradientColors.map((color, index) => (jsx(Stop, { offset: `${(index / (resolvedGradientColors.length - 1 || 1)) * 100}%`, stopColor: color }, index))) }) }), normalizedPeaks.map((peak, index) => {
36852
35901
  const x = index * (barWidth + barGap);
36853
- const barHeight = Math.max(minBarHeight, Math.abs(peak) * height * 0.8);
36854
- const y = (height - barHeight) / 2;
35902
+ const barHeight = Math.max(minBarHeight, Math.abs(peak) * h * 0.8);
35903
+ const y = (h - barHeight) / 2;
36855
35904
  return (jsx(Rect, { x: x, y: y, width: barWidth, height: barHeight, fill: `url(#${gradientId})` }, index));
36856
35905
  })] }));
36857
35906
  };
@@ -36861,8 +35910,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36861
35910
  return null;
36862
35911
  const clampedProgress = Math.max(0, Math.min(1, progress));
36863
35912
  const progressX = clampedProgress * actualWaveformWidth;
36864
- return (jsx(Line, { x1: progressX, y1: 0, x2: progressX, y2: height, stroke: (progressLineStyle === null || progressLineStyle === void 0 ? void 0 : progressLineStyle.color) || theme.colors.gray[7], strokeWidth: (progressLineStyle === null || progressLineStyle === void 0 ? void 0 : progressLineStyle.width) || 2, strokeOpacity: (progressLineStyle === null || progressLineStyle === void 0 ? void 0 : progressLineStyle.opacity) || 0.8 }));
36865
- }, [showProgressLine, progress, actualWaveformWidth, height, progressLineStyle, theme.colors.gray]);
35913
+ return (jsx(Line, { x1: progressX, y1: 0, x2: progressX, y2: h, stroke: (progressLineStyle === null || progressLineStyle === void 0 ? void 0 : progressLineStyle.color) || theme.colors.gray[7], strokeWidth: (progressLineStyle === null || progressLineStyle === void 0 ? void 0 : progressLineStyle.width) || 2, strokeOpacity: (progressLineStyle === null || progressLineStyle === void 0 ? void 0 : progressLineStyle.opacity) || 0.8 }));
35914
+ }, [showProgressLine, progress, actualWaveformWidth, h, progressLineStyle, theme.colors.gray]);
36866
35915
  // Timestamp markers component
36867
35916
  const TimeStamps = useMemo(() => {
36868
35917
  if (!showTimeStamps || !duration || !timeStampInterval)
@@ -36883,10 +35932,10 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36883
35932
  }
36884
35933
  return `${mins}:${secs.toString().padStart(2, '0')}`;
36885
35934
  };
36886
- timestamps.push(jsxs(G, { children: [jsx(Line, { x1: x, y1: height - 10, x2: x, y2: height, stroke: theme.colors.gray[5], strokeWidth: 1, strokeOpacity: 0.6 }), jsx(Text$2, { x: x, y: height + 15, fill: theme.colors.gray[6], fontSize: 10, textAnchor: "middle", opacity: 0.8, children: formatTime(time) })] }, i));
35935
+ timestamps.push(jsxs(G, { children: [jsx(Line, { x1: x, y1: h - 10, x2: x, y2: h, stroke: theme.colors.gray[5], strokeWidth: 1, strokeOpacity: 0.6 }), jsx(Text$2, { x: x, y: h + 15, fill: theme.colors.gray[6], fontSize: 10, textAnchor: "middle", opacity: 0.8, children: formatTime(time) })] }, i));
36887
35936
  }
36888
35937
  return jsx(G, { children: timestamps });
36889
- }, [showTimeStamps, duration, timeStampInterval, actualWaveformWidth, height, theme.colors]);
35938
+ }, [showTimeStamps, duration, timeStampInterval, actualWaveformWidth, h, theme.colors]);
36890
35939
  // Selection overlay component
36891
35940
  const SelectionOverlay = useMemo(() => {
36892
35941
  if (!selection || selection[0] === selection[1])
@@ -36895,8 +35944,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36895
35944
  const startX = start * actualWaveformWidth;
36896
35945
  const endX = end * actualWaveformWidth;
36897
35946
  const selectionWidth = endX - startX;
36898
- return (jsx(Rect, { x: startX, y: 0, width: selectionWidth, height: height, fill: theme.colors.primary[3], opacity: 0.3, stroke: theme.colors.primary[5], strokeWidth: 1, strokeOpacity: 0.8 }));
36899
- }, [selection, actualWaveformWidth, height, theme.colors.primary]);
35947
+ return (jsx(Rect, { x: startX, y: 0, width: selectionWidth, height: h, fill: theme.colors.primary[3], opacity: 0.3, stroke: theme.colors.primary[5], strokeWidth: 1, strokeOpacity: 0.8 }));
35948
+ }, [selection, actualWaveformWidth, h, theme.colors.primary]);
36900
35949
  // Markers component
36901
35950
  const Markers = useMemo(() => {
36902
35951
  if (!markers || markers.length === 0)
@@ -36906,16 +35955,16 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36906
35955
  const markerColor = marker.color || theme.colors.warning[5];
36907
35956
  switch (marker.type || 'line') {
36908
35957
  case 'line':
36909
- return (jsxs(G, { children: [jsx(Line, { x1: x, y1: 0, x2: x, y2: height, stroke: markerColor, strokeWidth: 2, strokeOpacity: 0.8 }), marker.label && (jsx(Text$2, { x: x, y: -5, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
35958
+ return (jsxs(G, { children: [jsx(Line, { x1: x, y1: 0, x2: x, y2: h, stroke: markerColor, strokeWidth: 2, strokeOpacity: 0.8 }), marker.label && (jsx(Text$2, { x: x, y: -5, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
36910
35959
  case 'flag':
36911
- return (jsxs(G, { children: [jsx(Line, { x1: x, y1: 0, x2: x, y2: height, stroke: markerColor, strokeWidth: 1, strokeOpacity: 0.6 }), jsx(Rect, { x: x + 2, y: 2, width: marker.label ? marker.label.length * 6 + 4 : 20, height: 14, fill: markerColor, rx: 2 }), marker.label && (jsx(Text$2, { x: x + 4, y: 12, fill: "white", fontSize: 9, fontWeight: "bold", children: marker.label }))] }, index));
35960
+ return (jsxs(G, { children: [jsx(Line, { x1: x, y1: 0, x2: x, y2: h, stroke: markerColor, strokeWidth: 1, strokeOpacity: 0.6 }), jsx(Rect, { x: x + 2, y: 2, width: marker.label ? marker.label.length * 6 + 4 : 20, height: 14, fill: markerColor, rx: 2 }), marker.label && (jsx(Text$2, { x: x + 4, y: 12, fill: "white", fontSize: 9, fontWeight: "bold", children: marker.label }))] }, index));
36912
35961
  case 'dot':
36913
- return (jsxs(G, { children: [jsx("circle", { cx: x, cy: height / 2, r: 4, fill: markerColor, stroke: "white", strokeWidth: 1 }), marker.label && (jsx(Text$2, { x: x, y: height / 2 + 20, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
35962
+ return (jsxs(G, { children: [jsx("circle", { cx: x, cy: h / 2, r: 4, fill: markerColor, stroke: "white", strokeWidth: 1 }), marker.label && (jsx(Text$2, { x: x, y: h / 2 + 20, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
36914
35963
  default:
36915
35964
  return null;
36916
35965
  }
36917
35966
  }) }));
36918
- }, [markers, actualWaveformWidth, height, theme.colors.warning]);
35967
+ }, [markers, actualWaveformWidth, h, theme.colors.warning]);
36919
35968
  // RMS visualization component
36920
35969
  const RMSBars = useMemo(() => {
36921
35970
  if (!showRMS || !rmsData || rmsData.length === 0)
@@ -36923,11 +35972,11 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36923
35972
  const processedRMS = rmsData.slice(0, normalizedPeaks.length);
36924
35973
  return (jsx(G, { opacity: 0.5, children: processedRMS.map((rms, index) => {
36925
35974
  const x = index * (barWidth + barGap);
36926
- const rmsHeight = Math.max(minBarHeight, Math.abs(rms) * height * 0.4); // RMS bars are shorter
36927
- const y = (height - rmsHeight) / 2;
35975
+ const rmsHeight = Math.max(minBarHeight, Math.abs(rms) * h * 0.4); // RMS bars are shorter
35976
+ const y = (h - rmsHeight) / 2;
36928
35977
  return (jsx(Rect, { x: x, y: y, width: barWidth, height: rmsHeight, fill: theme.colors.gray[4], rx: variant === 'rounded' ? barWidth / 2 : 0 }, `rms-${index}`));
36929
35978
  }) }));
36930
- }, [showRMS, rmsData, normalizedPeaks, barWidth, barGap, minBarHeight, height, variant, theme.colors.gray]);
35979
+ }, [showRMS, rmsData, normalizedPeaks, barWidth, barGap, minBarHeight, h, variant, theme.colors.gray]);
36931
35980
  const renderWaveform = () => {
36932
35981
  switch (variant) {
36933
35982
  case 'line':
@@ -36964,17 +36013,17 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36964
36013
  };
36965
36014
  // Early return for empty state
36966
36015
  if (normalizedPeaks.length === 0) {
36967
- return (jsx(View, { style: [style, fullWidth ? { width: '100%' } : { width }, { height, justifyContent: 'center', alignItems: 'center' }], accessibilityRole: "image", accessibilityLabel: accessibilityLabel || 'Empty waveform', ...restProps, children: jsx(Svg, { ...svgProps, children: jsx(Rect, { x: 0, y: height / 2 - 1, width: fullWidth ? '100%' : width, height: 2, fill: waveformColor, opacity: 0.3 }) }) }));
36016
+ return (jsx(View, { style: [style, fullWidth ? { width: '100%' } : { width: w }, { height: h, justifyContent: 'center', alignItems: 'center' }], accessibilityRole: "image", accessibilityLabel: accessibilityLabel || 'Empty waveform', ...restProps, children: jsx(Svg, { ...svgProps, children: jsx(Rect, { x: 0, y: h / 2 - 1, width: fullWidth ? '100%' : w, height: 2, fill: waveformColor, opacity: 0.3 }) }) }));
36968
36017
  }
36969
36018
  if (loading) {
36970
- return (jsx(WaveformSkeleton, { width: width, height: height, fullWidth: fullWidth, barsCount: maxVisibleBars || 20 }));
36019
+ return (jsx(WaveformSkeleton, { w: w, h: h, fullWidth: fullWidth, barsCount: maxVisibleBars || 20 }));
36971
36020
  }
36972
36021
  if (error) {
36973
36022
  return (jsx(View, { style: [
36974
36023
  style,
36975
- fullWidth ? { width: '100%' } : { width },
36024
+ fullWidth ? { width: '100%' } : { width: w },
36976
36025
  {
36977
- height,
36026
+ height: h,
36978
36027
  justifyContent: 'center',
36979
36028
  alignItems: 'center',
36980
36029
  backgroundColor: theme.colors.error[1],
@@ -36984,7 +36033,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36984
36033
  }
36985
36034
  ], accessibilityRole: "alert", accessibilityLabel: `Waveform error: ${error}`, ...restProps, children: jsx(Text$1, { style: { color: theme.colors.error[7], fontSize: 12, textAlign: 'center' }, children: error }) }));
36986
36035
  }
36987
- return (jsx(WrapperComponent, { ref: containerRef, style: [style, fullWidth ? { width: '100%' } : { width }], accessible: true, focusable: interactive, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), ...wrapperProps, ...restProps, children: jsxs(Svg, { ...svgProps, children: [SelectionOverlay, RMSBars, renderWaveform(), ProgressLine, TimeStamps, Markers] }) }));
36036
+ return (jsx(WrapperComponent, { ref: containerRef, style: [style, fullWidth ? { width: '100%' } : { width: w }], accessible: true, focusable: interactive, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), ...wrapperProps, ...restProps, children: jsxs(Svg, { ...svgProps, children: [SelectionOverlay, RMSBars, renderWaveform(), ProgressLine, TimeStamps, Markers] }) }));
36988
36037
  });
36989
36038
  Waveform.displayName = 'Waveform';
36990
36039
 
@@ -37006,7 +36055,7 @@ const AudioPlayer = forwardRef(({ source, peaks: providedPeaks, autoPlay = false
37006
36055
  channel: 'mix',
37007
36056
  }, showTime = true, timeFormat = 'mm:ss', showMetadata = false, metadata, showSpectrum = false, spectrumOptions, enableKeyboardShortcuts = true, enableGestures = true, onLoad, onPlaybackStateChange, onProgress, onEnd, onError, onBuffer,
37008
36057
  // Waveform props
37009
- width = 300, height = 60, color = 'primary', interactive = true, onSeek, style, ...waveformProps }, ref) => {
36058
+ w = 300, h = 60, color = 'primary', interactive = true, onSeek, style, ...waveformProps }, ref) => {
37010
36059
  const theme = useTheme();
37011
36060
  const { playSound } = useSound();
37012
36061
  // Refs
@@ -37353,7 +36402,7 @@ width = 300, height = 60, color = 'primary', interactive = true, onSeek, style,
37353
36402
  alignSelf: 'flex-start',
37354
36403
  }, children: jsx(Text$1, { style: { color: 'white', fontSize: DESIGN_TOKENS.typography.fontSize.sm }, children: "Retry" }) }))] }));
37355
36404
  }
37356
- return (jsxs(View, { style: [{ width: '100%' }, style], children: [controlsPosition === 'top' && renderMetadata(), controlsPosition === 'top' && renderControls(), controls.waveform && peaks.length > 0 && (jsx(View, { style: { marginVertical: DESIGN_TOKENS.spacing.sm }, children: jsx(Waveform, { peaks: peaks, width: width, height: height, color: color, progress: progress, interactive: interactive, onSeek: handleWaveformSeek, showProgressLine: true, progressLineStyle: {
36405
+ return (jsxs(View, { style: [{ width: '100%' }, style], children: [controlsPosition === 'top' && renderMetadata(), controlsPosition === 'top' && renderControls(), controls.waveform && peaks.length > 0 && (jsx(View, { style: { marginVertical: DESIGN_TOKENS.spacing.sm }, children: jsx(Waveform, { peaks: peaks, w: w, h: h, color: color, progress: progress, interactive: interactive, onSeek: handleWaveformSeek, showProgressLine: true, progressLineStyle: {
37357
36406
  color: theme.colors.primary[5],
37358
36407
  width: 2,
37359
36408
  opacity: 0.8,
@@ -38082,14 +37131,14 @@ const IMAGE_SIZES = {
38082
37131
  '2xl': 80,
38083
37132
  '3xl': 96,
38084
37133
  };
38085
- function Image({ src, source, alt, accessibilityLabel, resizeMode = 'cover', size, width, height, aspectRatio, borderWidth, borderColor, rounded, circle, fallback, loading, onLoad, onError, onLoadStart, onLoadEnd, containerStyle, imageStyle, testID, style, ...rest }) {
37134
+ function Image({ src, source, alt, accessibilityLabel, resizeMode = 'cover', size, w, h, aspectRatio, borderWidth, borderColor, rounded, circle, fallback, loading, onLoad, onError, onLoadStart, onLoadEnd, containerStyle, imageStyle, testID, style, ...rest }) {
38086
37135
  const theme = useTheme();
38087
37136
  const [loadError, setLoadError] = useState(false);
38088
37137
  const [isLoading, setIsLoading] = useState(true);
38089
37138
  const { spacingProps } = extractSpacingProps(rest);
38090
37139
  // Determine dimensions
38091
- let finalWidth = width;
38092
- let finalHeight = height;
37140
+ let finalWidth = w;
37141
+ let finalHeight = h;
38093
37142
  if (size && typeof size === 'string' && IMAGE_SIZES[size]) {
38094
37143
  finalWidth = finalWidth || IMAGE_SIZES[size];
38095
37144
  finalHeight = finalHeight || IMAGE_SIZES[size];
@@ -39874,11 +38923,14 @@ QRCodeSVG.displayName = 'QRCodeSVG';
39874
38923
  */
39875
38924
  function QRCode(props) {
39876
38925
  var _a;
38926
+ const theme = useTheme();
39877
38927
  const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
39878
38928
  const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
39879
- const { value, size = 400, backgroundColor = 'transparent', color = '#000000', errorCorrectionLevel = 'M', quietZone = 4, logo, style, testID, accessibilityLabel, onError, onLoadStart, // deprecated noop
38929
+ const { value, size = 400, backgroundColor = 'transparent', color, errorCorrectionLevel = 'M', quietZone = 4, logo, style, testID, accessibilityLabel, onError, onLoadStart, // deprecated noop
39880
38930
  onLoadEnd, // deprecated noop
39881
38931
  ...rest } = otherProps;
38932
+ // Default color to theme's primary text color for dark mode support
38933
+ const resolvedColor = color !== null && color !== void 0 ? color : theme.text.primary;
39882
38934
  const { copy } = useClipboard();
39883
38935
  const toast = useToast();
39884
38936
  const shouldCopyOnPress = !!otherProps.copyOnPress;
@@ -39894,7 +38946,7 @@ function QRCode(props) {
39894
38946
  });
39895
38947
  }
39896
38948
  }, [copy, copyValue, toast, otherProps.copyToastMessage, otherProps.copyToastTitle]);
39897
- const content = (jsxs(View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsx(QRCodeSVG, { value: value, size: size, maxWidth: '100%', backgroundColor: backgroundColor, color: color, errorCorrectionLevel: errorCorrectionLevel, quietZone: quietZone, logo: logo, style: style, testID: testID, accessibilityLabel: accessibilityLabel, onError: onError, ...spacingProps, ...layoutProps, ...rest }), otherProps.showCopyButton && (jsx(CopyButton, { value: copyValue, iconOnly: true, size: "sm", style: { position: 'absolute', top: 8, right: 8 }, onCopy: () => { } }))] }));
38949
+ const content = (jsxs(View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsx(QRCodeSVG, { value: value, size: size, maxW: '100%', backgroundColor: backgroundColor, color: resolvedColor, errorCorrectionLevel: errorCorrectionLevel, quietZone: quietZone, logo: logo, style: style, testID: testID, accessibilityLabel: accessibilityLabel, onError: onError, ...spacingProps, ...layoutProps, ...rest }), otherProps.showCopyButton && (jsx(CopyButton, { value: copyValue, iconOnly: true, size: "sm", style: { position: 'absolute', top: 8, right: 8 }, onCopy: () => { } }))] }));
39898
38950
  if (shouldCopyOnPress) {
39899
38951
  return (jsx(Pressable, { onPress: handleCopy, accessibilityLabel: accessibilityLabel || 'QR code', children: content }));
39900
38952
  }
@@ -40544,111 +39596,6 @@ const styles$2 = StyleSheet.create({
40544
39596
  },
40545
39597
  });
40546
39598
 
40547
- // Optional imports for web compatibility
40548
- const LottieReact = Platform.OS === 'web'
40549
- ? resolveOptionalModule('lottie-react', {
40550
- accessor: mod => { var _a; return (_a = mod.default) !== null && _a !== void 0 ? _a : mod; },
40551
- })
40552
- : null;
40553
- const DotLottieReact = Platform.OS === 'web'
40554
- ? resolveOptionalModule('@lottiefiles/dotlottie-react', {
40555
- accessor: mod => mod.DotLottieReact,
40556
- })
40557
- : null;
40558
- let cachedNativeStatus = null;
40559
- let nativeLottieComponent;
40560
- let nativeModuleLoadWarningLogged = false;
40561
- let nativeModuleConfigWarningLogged = false;
40562
- const loadNativeLottieComponent = () => {
40563
- if (nativeLottieComponent !== undefined) {
40564
- return nativeLottieComponent;
40565
- }
40566
- const module = resolveOptionalModule('lottie-react-native', {
40567
- accessor: mod => { var _a; return (_a = mod === null || mod === void 0 ? void 0 : mod.default) !== null && _a !== void 0 ? _a : mod; },
40568
- });
40569
- if (!module && !nativeModuleLoadWarningLogged && __DEV__) {
40570
- console.warn('[Lottie] Failed to load lottie-react-native module. Rendering fallback instead.');
40571
- nativeModuleLoadWarningLogged = true;
40572
- }
40573
- nativeLottieComponent = module !== null && module !== void 0 ? module : null;
40574
- return nativeLottieComponent;
40575
- };
40576
- const getNativeLottieStatus = () => {
40577
- var _a, _b, _c;
40578
- if (cachedNativeStatus) {
40579
- return cachedNativeStatus;
40580
- }
40581
- if (Platform.OS === 'web') {
40582
- cachedNativeStatus = { component: null, available: false };
40583
- return cachedNativeStatus;
40584
- }
40585
- const component = loadNativeLottieComponent();
40586
- if (!component) {
40587
- cachedNativeStatus = { component: null, available: false };
40588
- return cachedNativeStatus;
40589
- }
40590
- let viewManagerAvailable = false;
40591
- try {
40592
- const viewManager = (_c = (_b = (_a = UIManager === null || UIManager === void 0 ? void 0 : UIManager.getViewManagerConfig) === null || _a === void 0 ? void 0 : _a.call(UIManager, 'LottieAnimationView')) !== null && _b !== void 0 ? _b : UIManager === null || UIManager === void 0 ? void 0 : UIManager.LottieAnimationView) !== null && _c !== void 0 ? _c : NativeModules === null || NativeModules === void 0 ? void 0 : NativeModules.LottieAnimationView;
40593
- viewManagerAvailable = !!viewManager;
40594
- }
40595
- catch (error) {
40596
- viewManagerAvailable = false;
40597
- }
40598
- if (!viewManagerAvailable && !nativeModuleConfigWarningLogged && __DEV__) {
40599
- console.warn('[Lottie] Native LottieAnimationView is unavailable. Run `npx expo install lottie-react-native` and rebuild to enable animations.');
40600
- nativeModuleConfigWarningLogged = true;
40601
- }
40602
- cachedNativeStatus = {
40603
- component,
40604
- available: viewManagerAvailable,
40605
- };
40606
- return cachedNativeStatus;
40607
- };
40608
- /**
40609
- * Lottie component with safe fallback when native module not present or on unsupported platforms.
40610
- */
40611
- const Lottie = forwardRef(function LottieCmp(props, ref) {
40612
- const { source, autoPlay = true, loop = true, progress, speed = 1, style, testID, paused, resizeMode = 'contain', onAnimationFinish } = props;
40613
- const internalRef = useRef(null);
40614
- const nativeStatus = getNativeLottieStatus();
40615
- const NativeLottieView = nativeStatus.component;
40616
- useImperativeHandle(ref, () => ({
40617
- play: (...args) => { var _a, _b; return (_b = (_a = internalRef.current) === null || _a === void 0 ? void 0 : _a.play) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
40618
- pause: () => { var _a, _b; return (_b = (_a = internalRef.current) === null || _a === void 0 ? void 0 : _a.pause) === null || _b === void 0 ? void 0 : _b.call(_a); },
40619
- reset: () => { var _a, _b; return (_b = (_a = internalRef.current) === null || _a === void 0 ? void 0 : _a.reset) === null || _b === void 0 ? void 0 : _b.call(_a); },
40620
- setProgress: (p) => { var _a, _b; return (_b = (_a = internalRef.current) === null || _a === void 0 ? void 0 : _a.setProgress) === null || _b === void 0 ? void 0 : _b.call(_a, p); },
40621
- }), []);
40622
- useEffect(() => {
40623
- var _a;
40624
- if (progress != null && ((_a = internalRef.current) === null || _a === void 0 ? void 0 : _a.setProgress)) {
40625
- internalRef.current.setProgress(progress);
40626
- }
40627
- }, [progress]);
40628
- // Web implementation
40629
- if (Platform.OS === 'web') {
40630
- // Check if source is a string (URL) and ends with .lottie
40631
- const isLottieFile = typeof source === 'string' && source.endsWith('.lottie');
40632
- if (isLottieFile && DotLottieReact) {
40633
- // Use DotLottieReact for .lottie files
40634
- return (jsx(DotLottieReact, { src: source, autoplay: autoPlay, loop: loop, speed: speed, style: style, "data-testid": testID }));
40635
- }
40636
- else if (LottieReact) {
40637
- // Use lottie-react for standard Lottie JSON
40638
- return (jsx(LottieReact, { animationData: source, autoplay: autoPlay, loop: loop, style: style, "data-testid": testID }));
40639
- }
40640
- else {
40641
- return jsx(Text, { children: "Lottie not available on web" });
40642
- }
40643
- }
40644
- // Native implementation using lottie-react-native
40645
- if (!nativeStatus.available || !NativeLottieView) {
40646
- return (jsx(View, { style: [{ justifyContent: 'center', alignItems: 'center' }, style], testID: testID, children: jsx(Text, { style: { textAlign: 'center', opacity: 0.7 }, children: "Lottie animations require the native `lottie-react-native` module. Install it and rebuild the app, or view this example on the web." }) }));
40647
- }
40648
- return (jsx(NativeLottieView, { ref: internalRef, source: source, autoPlay: autoPlay, loop: loop, speed: speed, progress: progress, style: style, testID: testID, resizeMode: resizeMode, onAnimationFinish: onAnimationFinish, ...(paused != null ? { paused } : {}) }));
40649
- });
40650
- Lottie.displayName = 'Lottie';
40651
-
40652
39599
  const PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
40653
39600
  function formatTime(seconds) {
40654
39601
  const hours = Math.floor(seconds / 3600);
@@ -41596,7 +40543,7 @@ const DEFAULT_CONTROLS = {
41596
40543
  autoHide: true,
41597
40544
  autoHideTimeout: 3000,
41598
40545
  };
41599
- const Video = forwardRef(({ source, width, height, aspectRatio = 16 / 9, poster, autoPlay = false, loop = false, muted = false, volume = 1, playbackRate = 1, quality = 'auto', controls = true, timeline = [], youtubeOptions, onPlay, onPause, onSeek, onTimeUpdate, onDurationChange, onVolumeChange, onPlaybackRateChange, onQualityChange, onFullscreenChange, onError, onLoad, onLoadStart, onBuffer, onTimelineEvent, style, videoStyle, controlsStyle, accessibilityLabel, testID, ...rest }, ref) => {
40546
+ const Video = forwardRef(({ source, w, h, aspectRatio = 16 / 9, poster, autoPlay = false, loop = false, muted = false, volume = 1, playbackRate = 1, quality = 'auto', controls = true, timeline = [], youtubeOptions, onPlay, onPause, onSeek, onTimeUpdate, onDurationChange, onVolumeChange, onPlaybackRateChange, onQualityChange, onFullscreenChange, onError, onLoad, onLoadStart, onBuffer, onTimelineEvent, style, videoStyle, controlsStyle, accessibilityLabel, testID, ...rest }, ref) => {
41600
40547
  const theme = useTheme();
41601
40548
  const { spacingProps } = extractSpacingProps(rest);
41602
40549
  // Internal state
@@ -41846,24 +40793,24 @@ const Video = forwardRef(({ source, width, height, aspectRatio = 16 / 9, poster,
41846
40793
  // overflow: 'hidden',
41847
40794
  // position: 'relative',
41848
40795
  };
41849
- if (width && height) {
41850
- baseStyle.width = width;
41851
- baseStyle.height = height;
40796
+ if (w && h) {
40797
+ baseStyle.width = w;
40798
+ baseStyle.height = h;
41852
40799
  }
41853
- else if (width) {
41854
- baseStyle.width = width;
41855
- baseStyle.height = typeof width === 'number' ? width / aspectRatio : '100%';
40800
+ else if (w) {
40801
+ baseStyle.width = w;
40802
+ baseStyle.height = typeof w === 'number' ? w / aspectRatio : '100%';
41856
40803
  }
41857
- else if (height) {
41858
- baseStyle.height = height;
41859
- baseStyle.width = typeof height === 'number' ? height * aspectRatio : '100%';
40804
+ else if (h) {
40805
+ baseStyle.height = h;
40806
+ baseStyle.width = typeof h === 'number' ? h * aspectRatio : '100%';
41860
40807
  }
41861
40808
  else {
41862
40809
  baseStyle.width = '100%';
41863
40810
  baseStyle.aspectRatio = aspectRatio;
41864
40811
  }
41865
40812
  return baseStyle;
41866
- }, [theme.colors.surface, width, height, aspectRatio]);
40813
+ }, [theme.colors.surface, w, h, aspectRatio]);
41867
40814
  // Handle touch events for control visibility
41868
40815
  const handleContainerPress = useCallback(() => {
41869
40816
  if (controlsConfig && controlsConfig.autoHide) {
@@ -41967,5 +40914,5 @@ function withPressAnimation(Component, animationProps) {
41967
40914
  */
41968
40915
  const AnimatedPressable = PressAnimation;
41969
40916
 
41970
- export { AbilityCore, AccessibilityProvider, Accordion, AmazonAppstoreBadge, AmazonAppstoreButton, AmazonMusicListenBadge, AmazonPrimeVideoBadge, AmazonStoreBadge, AnimatedPressable, AppLayoutProvider, AppLayoutRenderer, AppShell, AppShellAside, AppShellBottomNav, AppShellFooter, AppShellHeader, AppShellMain, AppShellNavbar, AppShellSection, AppStoreBadge, AppStoreButton, AppStoreDownloadBadge, AppleAppStoreButton, AppleMusicListenBadge, ApplePodcastsListenBadge, AutoComplete, Avatar, AvatarGroup, Badge, Block, Blockquote, Bold, BottomAppBar, BrandButton, BrandIcon, Breadcrumbs, Button, COMPONENT_SIZES$1 as COMPONENT_SIZES, COMPONENT_SIZE_ORDER, Calendar, Can, CanWithConditions, Cannot, Card, Carousel, Checkbox, Chip, ChromeWebStoreBadge, Cite, Code, CodeBlock, Collapse, ColorPicker, ColorSwatch, Column, ComponentWithDisclaimer, ContextMenu, CopyButton, DARK_THEME, DEFAULT_BREAKPOINTS, DEFAULT_COMPONENT_SIZE, DEFAULT_SOUND_IDS, DEFAULT_THEME, DataTable, DatePicker, DatePickerInput, Day, Dialog, DialogProvider, DialogRenderer, DirectionProvider, Disclaimer, DiscordJoinBadge, Divider, EmojiPicker, Emphasis, FDroidButton, FileInput, Flex, FloatingActions, Form, GalaxyStoreDownloadBadge, Gallery, Gauge, GitHubViewBadge, GooglePlayButton, GooglePlayDownloadBadge, Grid, GridItem, H1, H2, H3, H4, H5, H6, HapticsProvider, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlight, HoverCard, HuaweiAppGalleryBadge, I18nProvider, Icon, IconButton, Image, Indicator, Input, Italic, Kbd, KeyCap, KeyboardAwareLayout, KeyboardManagerProvider, Knob, Link, ListGroup, ListGroupBody, ListGroupDivider, ListGroupItem, Loader, LoadingOverlay, Lottie, MacAppStoreButton, Mark, Markdown, Masonry, Menu, MenuDivider, MenuDropdown, MenuItem, MenuItemButton, MenuLabel, MicrosoftStoreButton, MicrosoftStoreDownloadBadge, MiniCalendar, Month, MonthPicker, MonthPickerInput, NavigationProgress, Notice, NumberInput, Overlay, OverlayProvider, P, Pagination, PasswordInput, PermissionBuilder, PermissionGate, PermissionPatterns, PermissionProvider, PhoneInput, PinInput, PlatformBlocksProvider, Popover, PressAnimation, Progress, QRCode, Radio, RadioGroup, RangeSlider, Rating, RedditJoinBadge, RichTextEditor, Ring, RoleBuilder, Row, SIZE_SCALES, Search, SegmentedControl, Select, ShimmerText, Skeleton, Slider, Small, SoundCloudListenBadge, SoundProvider, Space, Spoiler, SpotifyListenBadge, Spotlight, SpotlightProvider, StatusBarManager, StepperWithSubComponents as Stepper, Strong, Sub, Sup, Switch, Table, TableOfContents, Tabs, Text, TextArea, TextInputBase, ThemeModeProvider, TikTokWatchBadge, TimePickerInput as TimePicker, TimePickerInput, TimelineWithItems as Timeline, Title, TitleRegistryProvider, Toast, ToastProvider, ToggleBar, ToggleButton, ToggleGroup, Tooltip, Tree, TwitchWatchBadge, Underline, Video, Waveform, YearPicker, YearPickerInput, YouTubeMusicListenBadge, YouTubeWatchBadge, calculateOverlayPositionEnhanced, clampComponentSize, clearOverlayPositionCache, createSound, createSpotlightStore, createTheme, debounce$1 as debounce, defineAbility, defineAppLayout, defineRoleAbility, directSpotlight, extractDisclaimerProps, factory, getAllSounds, getColor, getFontSize, getHeight, getIconSize$1 as getIconSize, getLineHeight, getRadius$1 as getRadius, getScrollPosition, getShadow$1 as getShadow, getSize, getSoundsByCategory, getSpacing, getViewport, globalHotkeys, measureAsyncPerformance, measureElement, measurePerformance, navigationProgress, onDialogsRequested, onSpotlightRequested, onToastsRequested, permissions, pointInRect, polymorphicFactory, px, rem, resolveComponentSize, resolveResponsiveProp, resolveResponsiveValue, resolveSize, spotlight, throttle, useAbility, useAccessibility, useAppLayoutContext, useAppShell, useAppShellApi, useAppShellLayout, useBreakpoint, useColorScheme, useDialog, useDialogApi, useDialogs, useDirectSpotlightState, useDirection, useDirectionSafe, useDisclaimer, useDropdownPositioning, useEscapeKey, useFormContext, useGlobalHotkeys, useHaptics, useHapticsSettings, useHotkeys, useI18n, useKeyboardManager, useKeyboardManagerOptional, useNavbarHover, useOptionalFormContext, useOverlay, useOverlayApi, useOverlays, usePermissions, usePopoverPositioning, useSimpleDialog, useSound, useSpotlightStore, useSpotlightStoreInstance, useSpotlightToggle, useTheme, useThemeMode, useTitleRegistry, useTitleRegistryOptional, useToast, useToastApi, useToggleColorScheme, useTooltipPositioning, withCan, withCannot, withDisclaimer, withPressAnimation };
40917
+ export { AccessibilityProvider, Accordion, AmazonAppstoreBadge, AmazonAppstoreButton, AmazonMusicListenBadge, AmazonPrimeVideoBadge, AmazonStoreBadge, AnimatedPressable, AppLayoutProvider, AppLayoutRenderer, AppShell, AppShellAside, AppShellBottomNav, AppShellFooter, AppShellHeader, AppShellMain, AppShellNavbar, AppShellSection, AppStoreBadge, AppStoreButton, AppStoreDownloadBadge, AppleAppStoreButton, AppleMusicListenBadge, ApplePodcastsListenBadge, AutoComplete, Avatar, AvatarGroup, Badge, Block, Blockquote, Bold, BottomAppBar, BrandButton, BrandIcon, Breadcrumbs, Button, COMPONENT_SIZES$1 as COMPONENT_SIZES, COMPONENT_SIZE_ORDER, Calendar, Card, Carousel, Checkbox, Chip, ChromeWebStoreBadge, Cite, Code, CodeBlock, Collapse, ColorPicker, ColorSwatch, Column, ComponentWithDisclaimer, ContextMenu, CopyButton, DARK_THEME, DEFAULT_BREAKPOINTS, DEFAULT_COMPONENT_SIZE, DEFAULT_SOUND_IDS, DEFAULT_THEME, DataTable, DatePicker, DatePickerInput, Day, Dialog, DialogProvider, DialogRenderer, DirectionProvider, Disclaimer, DiscordJoinBadge, Divider, EmojiPicker, Emphasis, FDroidButton, FileInput, Flex, FloatingActions, Form, GalaxyStoreDownloadBadge, Gallery, Gauge, GitHubViewBadge, GooglePlayButton, GooglePlayDownloadBadge, Grid, GridItem, H1, H2, H3, H4, H5, H6, HapticsProvider, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlight, HuaweiAppGalleryBadge, I18nProvider, Icon, IconButton, Image, Indicator, Input, Italic, Kbd, KeyCap, KeyboardAwareLayout, KeyboardManagerProvider, Knob, Link, ListGroup, ListGroupBody, ListGroupDivider, ListGroupItem, Loader, LoadingOverlay, MacAppStoreButton, Mark, Markdown, Masonry, Menu, MenuDivider, MenuDropdown, MenuItem, MenuItemButton, MenuLabel, MicrosoftStoreButton, MicrosoftStoreDownloadBadge, MiniCalendar, Month, MonthPicker, MonthPickerInput, Notice, NumberInput, Overlay, OverlayProvider, P, Pagination, PasswordInput, PhoneInput, PinInput, PlatformBlocksProvider, Popover, PressAnimation, Progress, QRCode, Radio, RadioGroup, RangeSlider, Rating, RedditJoinBadge, Ring, Row, SIZE_SCALES, Search, SegmentedControl, Select, ShimmerText, Skeleton, Slider, Small, SoundCloudListenBadge, SoundProvider, Space, Spoiler, SpotifyListenBadge, Spotlight, SpotlightProvider, StatusBarManager, StepperWithSubComponents as Stepper, Strong, Sub, Sup, Switch, Table, TableOfContents, Tabs, Text, TextArea, TextInputBase, ThemeModeProvider, TikTokWatchBadge, TimePickerInput as TimePicker, TimePickerInput, TimelineWithItems as Timeline, Title, TitleRegistryProvider, Toast, ToastProvider, ToggleBar, ToggleButton, ToggleGroup, Tooltip, Tree, TwitchWatchBadge, Underline, Video, Waveform, YearPicker, YearPickerInput, YouTubeMusicListenBadge, YouTubeWatchBadge, calculateOverlayPositionEnhanced, clampComponentSize, clearOverlayPositionCache, createSound, createSpotlightStore, createTheme, debounce$1 as debounce, defineAppLayout, directSpotlight, extractDisclaimerProps, factory, getAllSounds, getColor, getFontSize, getHeight, getIconSize$1 as getIconSize, getLineHeight, getRadius$1 as getRadius, getScrollPosition, getShadow$1 as getShadow, getSize, getSoundsByCategory, getSpacing, getViewport, globalHotkeys, measureAsyncPerformance, measureElement, measurePerformance, onDialogsRequested, onSpotlightRequested, onToastsRequested, pointInRect, polymorphicFactory, px, rem, resolveComponentSize, resolveResponsiveProp, resolveResponsiveValue, resolveSize, spotlight, throttle, useAccessibility, useAppLayoutContext, useAppShell, useAppShellApi, useAppShellLayout, useBreakpoint, useColorScheme, useDialog, useDialogApi, useDialogs, useDirectSpotlightState, useDirection, useDirectionSafe, useDisclaimer, useDropdownPositioning, useEscapeKey, useFormContext, useGlobalHotkeys, useHaptics, useHapticsSettings, useHotkeys, useI18n, useKeyboardManager, useKeyboardManagerOptional, useNavbarHover, useOptionalFormContext, useOverlay, useOverlayApi, useOverlays, usePopoverPositioning, useSimpleDialog, useSound, useSpotlightStore, useSpotlightStoreInstance, useSpotlightToggle, useTheme, useThemeMode, useTitleRegistry, useTitleRegistryOptional, useToast, useToastApi, useToggleColorScheme, useTooltipPositioning, withDisclaimer, withPressAnimation };
41971
40918
  //# sourceMappingURL=index.js.map