@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/cjs/index.js CHANGED
@@ -726,16 +726,16 @@ const DARK_THEME = {
726
726
  '#F2F2F7'
727
727
  ],
728
728
  highlight: [
729
- '#2A2313',
730
- '#3D3320',
731
- '#4F422D',
732
- '#61523A',
733
- '#736247',
734
- '#FBBF24', // Keep same base as light mode for consistency
735
- '#FCD34D',
736
- '#FDE68A',
737
- '#FEF3C7',
738
- '#FFFBEB'
729
+ '#1E3A5F', // Deep blue
730
+ '#1E4976', //
731
+ '#1D5A8F', //
732
+ '#2563EB', // Bright blue
733
+ '#3B82F6', // Primary blue
734
+ '#60A5FA', // Light blue
735
+ '#93C5FD', //
736
+ '#BFDBFE', //
737
+ '#DBEAFE', //
738
+ '#EFF6FF' // Very light blue
739
739
  ],
740
740
  pink: [
741
741
  '#831843', '#9D174D', '#BE185D', '#DB2777', '#EC4899',
@@ -791,9 +791,9 @@ const DARK_THEME = {
791
791
  },
792
792
  states: {
793
793
  focusRing: 'rgba(10,132,255,0.55)',
794
- textSelection: 'rgba(251, 191, 36, 0.2)', // Slightly more subtle for dark mode
795
- highlightText: '#FDE68A', // highlight[7] for good contrast on dark
796
- highlightBackground: 'rgba(97, 82, 58, 0.8)' // Darker highlight[3] with more opacity
794
+ textSelection: 'rgba(10, 132, 255, 0.25)', // Primary blue for selection
795
+ highlightText: '#60A5FA', // primary[4] - bright blue for good contrast on dark
796
+ highlightBackground: 'rgba(59, 130, 246, 0.35)' // primary[5] with transparency
797
797
  },
798
798
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
799
799
  fontSizes: {
@@ -882,6 +882,8 @@ const DARK_THEME = {
882
882
  const optionalModuleCache = new Map();
883
883
  const isDev = typeof __DEV__ !== 'undefined' ? __DEV__ : process.env.NODE_ENV !== 'production';
884
884
  // Metro bundler requires static string literals for require; keep all optional modules here.
885
+ // NOTE: Do NOT add react-syntax-highlighter here - it causes Metro to fail on native
886
+ // when the package isn't installed. Instead, pass the loader dynamically from web-only code.
885
887
  const optionalModuleLoaders = {
886
888
  'react-native': () => require('react-native'),
887
889
  'expo-clipboard': () => require('expo-clipboard'),
@@ -890,21 +892,9 @@ const optionalModuleLoaders = {
890
892
  'expo-document-picker': () => require('expo-document-picker'),
891
893
  'react-native-webview': () => require('react-native-webview'),
892
894
  'lodash.debounce': () => require('lodash.debounce'),
893
- 'react-syntax-highlighter': () => require('react-syntax-highlighter'),
894
- 'react-syntax-highlighter/dist/esm/languages/prism/jsx': () => require('react-syntax-highlighter/dist/esm/languages/prism/jsx'),
895
- 'react-syntax-highlighter/dist/esm/languages/prism/tsx': () => require('react-syntax-highlighter/dist/esm/languages/prism/tsx'),
896
- 'react-syntax-highlighter/dist/esm/languages/prism/typescript': () => require('react-syntax-highlighter/dist/esm/languages/prism/typescript'),
897
- 'react-syntax-highlighter/dist/esm/languages/prism/javascript': () => require('react-syntax-highlighter/dist/esm/languages/prism/javascript'),
898
- 'react-syntax-highlighter/dist/esm/languages/prism/json': () => require('react-syntax-highlighter/dist/esm/languages/prism/json'),
899
- 'react-syntax-highlighter/dist/esm/languages/prism/bash': () => require('react-syntax-highlighter/dist/esm/languages/prism/bash'),
900
- 'react-syntax-highlighter/dist/esm/styles/prism/prism': () => require('react-syntax-highlighter/dist/esm/styles/prism/prism'),
901
- 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus': () => require('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus'),
902
895
  'expo-audio': () => require('expo-audio'),
903
896
  'react-native-gesture-handler': () => require('react-native-gesture-handler'),
904
897
  'expo-status-bar': () => require('expo-status-bar'),
905
- 'lottie-react': () => require('lottie-react'),
906
- '@lottiefiles/dotlottie-react': () => require('@lottiefiles/dotlottie-react'),
907
- 'lottie-react-native': () => require('lottie-react-native'),
908
898
  'expo-navigation-bar': () => require('expo-navigation-bar'),
909
899
  };
910
900
  /**
@@ -1184,25 +1174,50 @@ function OverlayRenderer({ style } = {}) {
1184
1174
  }) }));
1185
1175
  }
1186
1176
  function OverlayContent({ overlay, isTopmost, onBackdropPress }) {
1187
- var _a, _b, _c;
1177
+ var _a, _b, _c, _d, _e, _f;
1188
1178
  useTheme();
1189
1179
  const DEBUG = overlay.debug === true;
1190
1180
  if (DEBUG) {
1191
1181
  console.log('Rendering overlay content:');
1192
1182
  console.log('- anchor:', overlay.anchor);
1183
+ console.log('- placement:', overlay.placement);
1193
1184
  console.log('- strategy:', overlay.strategy);
1194
1185
  console.log('- zIndex:', overlay.zIndex);
1195
1186
  }
1187
+ // Check if this is a top-positioned overlay
1188
+ const isTopPlacement = (_a = overlay.placement) === null || _a === void 0 ? void 0 : _a.startsWith('top');
1189
+ // For top placements, we need to anchor from the bottom of the overlay
1190
+ // The anchor.y represents where the bottom of the overlay should be (top of the trigger minus offset)
1191
+ // So we use the estimated height to calculate where the top of the overlay would be
1196
1192
  const overlayStyle = {
1197
1193
  // Use fixed positioning on web for viewport-anchored overlays
1198
1194
  position: (reactNative.Platform.OS === 'web' && overlay.strategy === 'fixed') ? 'fixed' : 'absolute',
1199
- top: ((_a = overlay.anchor) === null || _a === void 0 ? void 0 : _a.y) || 0,
1200
1195
  left: ((_b = overlay.anchor) === null || _b === void 0 ? void 0 : _b.x) || 0,
1201
1196
  zIndex: overlay.zIndex,
1202
1197
  width: overlay.width || (((_c = overlay.anchor) === null || _c === void 0 ? void 0 : _c.width) ? overlay.anchor.width : undefined),
1203
1198
  maxWidth: overlay.maxWidth,
1204
1199
  maxHeight: overlay.maxHeight,
1205
1200
  };
1201
+ if (isTopPlacement && reactNative.Platform.OS === 'web') {
1202
+ // For top placements, position from the bottom of the overlay
1203
+ // anchor.y is where the top of the overlay should be, but we want to anchor from the bottom
1204
+ // so the overlay can grow upward naturally
1205
+ // The "bottom" of the anchor point is: viewport.height - (anchor.y + estimatedHeight)
1206
+ // But since we don't know actual height, use bottom anchoring relative to the trigger
1207
+ // Actually, anchor.y already accounts for the estimated height, so:
1208
+ // anchor.y = trigger.y - estimatedHeight - offset
1209
+ // We want the overlay's bottom edge to be at: trigger.y - offset
1210
+ // Which means: bottom = viewport.height - (trigger.y - offset) = viewport.height - anchor.y - estimatedHeight
1211
+ // Simpler: just set top and let it render, but the issue is the estimate is wrong
1212
+ // Better approach: use the anchor.y + anchor.height as the "bottom anchor point"
1213
+ // This is where the bottom of the overlay should be
1214
+ 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);
1215
+ overlayStyle.top = undefined;
1216
+ overlayStyle.bottom = `calc(100vh - ${bottomAnchorPoint}px)`;
1217
+ }
1218
+ else {
1219
+ overlayStyle.top = ((_f = overlay.anchor) === null || _f === void 0 ? void 0 : _f.y) || 0;
1220
+ }
1206
1221
  if (DEBUG) {
1207
1222
  console.log('- overlayStyle:', overlayStyle);
1208
1223
  }
@@ -1967,7 +1982,6 @@ function resolveComponentSize(value, scale, options = {}) {
1967
1982
  }
1968
1983
  const firstAvailable = allowed.find(key => scale[key] !== undefined);
1969
1984
  if (firstAvailable && scale[firstAvailable] !== undefined) {
1970
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1971
1985
  return scale[firstAvailable];
1972
1986
  }
1973
1987
  throw new Error('resolveComponentSize: no matching size found in provided scale.');
@@ -2329,18 +2343,17 @@ function extractSpacingProps(props) {
2329
2343
  *
2330
2344
  * @param props - The layout properties object
2331
2345
  * @param props.fullWidth - When true, sets width to 100%
2332
- * @param props.w - Shorthand width property (overrides fullWidth)
2333
- * @param props.width - Specific width value (overrides fullWidth and w)
2334
- * @param props.height - Height value
2335
- * @param props.maxWidth - Maximum width constraint
2336
- * @param props.minWidth - Minimum width constraint
2337
- * @param props.maxHeight - Maximum height constraint
2338
- * @param props.minHeight - Minimum height constraint
2346
+ * @param props.w - Width property (overrides fullWidth)
2347
+ * @param props.h - Height value
2348
+ * @param props.maxW - Maximum width constraint
2349
+ * @param props.minW - Minimum width constraint
2350
+ * @param props.maxH - Maximum height constraint
2351
+ * @param props.minH - Minimum height constraint
2339
2352
  *
2340
2353
  * @returns A partial ViewStyle object containing the computed layout styles
2341
2354
  *
2342
2355
  * @remarks
2343
- * Property precedence for width: width > w > fullWidth
2356
+ * Property precedence for width: w > fullWidth
2344
2357
  * The function processes width properties in order of specificity, with more specific
2345
2358
  * properties overriding more general ones.
2346
2359
  */
@@ -2350,43 +2363,38 @@ function getLayoutStyles(props) {
2350
2363
  if (props.fullWidth) {
2351
2364
  styles.width = '100%';
2352
2365
  }
2353
- // Handle shorthand width prop first
2366
+ // Handle width prop (overrides fullWidth)
2354
2367
  if (props.w !== undefined) {
2355
2368
  styles.width = props.w;
2356
2369
  }
2357
- // Handle specific dimensions (override fullWidth and w if specified)
2358
- if (props.width !== undefined) {
2359
- styles.width = props.width;
2360
- }
2361
- if (props.height !== undefined) {
2362
- styles.height = props.height;
2370
+ if (props.h !== undefined) {
2371
+ styles.height = props.h;
2363
2372
  }
2364
- if (props.maxWidth !== undefined) {
2365
- styles.maxWidth = props.maxWidth;
2373
+ if (props.maxW !== undefined) {
2374
+ styles.maxWidth = props.maxW;
2366
2375
  }
2367
- if (props.minWidth !== undefined) {
2368
- styles.minWidth = props.minWidth;
2376
+ if (props.minW !== undefined) {
2377
+ styles.minWidth = props.minW;
2369
2378
  }
2370
- if (props.maxHeight !== undefined) {
2371
- styles.maxHeight = props.maxHeight;
2379
+ if (props.maxH !== undefined) {
2380
+ styles.maxHeight = props.maxH;
2372
2381
  }
2373
- if (props.minHeight !== undefined) {
2374
- styles.minHeight = props.minHeight;
2382
+ if (props.minH !== undefined) {
2383
+ styles.minHeight = props.minH;
2375
2384
  }
2376
2385
  return styles;
2377
2386
  }
2378
2387
  // Helper to extract layout props from component props
2379
2388
  function extractLayoutProps(props) {
2380
- const { fullWidth, w, width, height, maxWidth, minWidth, maxHeight, minHeight, ...otherProps } = props;
2389
+ const { fullWidth, w, h, maxW, minW, maxH, minH, ...otherProps } = props;
2381
2390
  const layoutProps = {
2382
2391
  fullWidth,
2383
2392
  w,
2384
- width,
2385
- height,
2386
- maxWidth,
2387
- minWidth,
2388
- maxHeight,
2389
- minHeight
2393
+ h,
2394
+ maxW,
2395
+ minW,
2396
+ maxH,
2397
+ minH
2390
2398
  };
2391
2399
  return { layoutProps, otherProps };
2392
2400
  }
@@ -2655,7 +2663,7 @@ async function measureAsyncPerformance(name, fn) {
2655
2663
  const OVERLAY_CACHE_LIMIT = 200;
2656
2664
  const overlayPositionCache = new Map();
2657
2665
  const formatNumber = (value) => Number.isFinite(value) ? Math.round(value * 100) / 100 : 0;
2658
- const createOverlayCacheKey = (anchorX, anchorY, anchorWidth, anchorHeight, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary) => {
2666
+ const createOverlayCacheKey = (anchorX, anchorY, anchorWidth, anchorHeight, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary, matchAnchorWidth) => {
2659
2667
  return [
2660
2668
  formatNumber(anchorX),
2661
2669
  formatNumber(anchorY),
@@ -2672,6 +2680,7 @@ const createOverlayCacheKey = (anchorX, anchorY, anchorWidth, anchorHeight, over
2672
2680
  flip ? '1' : '0',
2673
2681
  shift ? '1' : '0',
2674
2682
  formatNumber(boundary),
2683
+ matchAnchorWidth ? '1' : '0',
2675
2684
  reactNative.Platform.OS,
2676
2685
  ].join('|');
2677
2686
  };
@@ -2717,11 +2726,12 @@ registerViewportListeners();
2717
2726
  * Enhanced overlay positioning that prevents off-screen rendering with intelligent caching
2718
2727
  */
2719
2728
  function calculateOverlayPositionEnhanced(anchor, overlay, options = {}) {
2720
- const { placement = 'auto', offset = 8, viewport = getViewport(), strategy = 'fixed', flip = true, shift = true, boundary = 8, fallbackPlacements = ['bottom', 'top', 'right', 'left'] } = options;
2729
+ const { placement = 'auto', offset = 8, viewport = getViewport(), strategy = 'fixed', flip = true, shift = true, boundary = 8, fallbackPlacements = ['bottom', 'top', 'right', 'left'], matchAnchorWidth = false, } = options;
2721
2730
  // If overlay height is unknown/small (pre-measure), use a heuristic height for decision-making
2722
2731
  // This helps avoid choosing "bottom" when near the bottom of the viewport.
2723
2732
  const heuristicHeight = Math.max(overlay.height || 0, 240);
2724
- const overlayWidth = overlay.width;
2733
+ // When matchAnchorWidth is true, use anchor width for overlay width calculations
2734
+ const overlayWidth = matchAnchorWidth ? anchor.width : overlay.width;
2725
2735
  const overlayHeight = overlay.height > 0 ? overlay.height : heuristicHeight;
2726
2736
  // Account for scroll if using absolute positioning
2727
2737
  const scrollX = (reactNative.Platform.OS === 'web' && strategy === 'absolute')
@@ -2732,7 +2742,7 @@ function calculateOverlayPositionEnhanced(anchor, overlay, options = {}) {
2732
2742
  const anchorX = anchor.x + scrollX;
2733
2743
  const anchorY = anchor.y + scrollY;
2734
2744
  // Check cache first
2735
- const cacheKey = createOverlayCacheKey(anchorX, anchorY, anchor.width, anchor.height, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary);
2745
+ const cacheKey = createOverlayCacheKey(anchorX, anchorY, anchor.width, anchor.height, overlayWidth, overlayHeight, placement, offset, viewport, strategy, flip, shift, boundary, matchAnchorWidth);
2736
2746
  const cached = getCachedOverlayPosition(cacheKey);
2737
2747
  if (cached) {
2738
2748
  return cached;
@@ -2800,10 +2810,14 @@ function calculateOverlayPositionEnhanced(anchor, overlay, options = {}) {
2800
2810
  // If enforcement moved the overlay to the opposite vertical side to avoid covering the anchor,
2801
2811
  // reflect that in the returned placement so arrows/styles are consistent.
2802
2812
  const resolvedPlacement = adjustPlacementIfMoved(finalPlacement, result, anchorRect);
2813
+ // When matchAnchorWidth is true, preserve anchor width without constraining to maxWidth
2814
+ const computedFinalWidth = matchAnchorWidth
2815
+ ? anchor.width
2816
+ : Math.min(result.finalWidth || overlay.width, result.maxWidth || overlay.width);
2803
2817
  const finalResult = {
2804
2818
  ...result,
2805
2819
  placement: resolvedPlacement,
2806
- finalWidth: Math.min(result.finalWidth || overlay.width, result.maxWidth || overlay.width),
2820
+ finalWidth: computedFinalWidth,
2807
2821
  finalHeight: Math.min(result.finalHeight || overlay.height, result.maxHeight || overlay.height),
2808
2822
  };
2809
2823
  // Cache the result
@@ -3560,9 +3574,14 @@ const Text = (allProps) => {
3560
3574
  }
3561
3575
  // Platform-specific rendering
3562
3576
  if (reactNative.Platform.OS === 'web' && isHTMLVariant(htmlTag)) {
3563
- const webStyles = convertToWebStyles([textStyles, spacingStyles, style,
3564
- // make sure text is side to side
3565
- { display: 'inline' }
3577
+ const styleArray = Array.isArray(style) ? style : [style];
3578
+ const hasDisplayOverride = styleArray.some((item) => item && ((item.display !== undefined) || (item.whiteSpace !== undefined)));
3579
+ const webStyles = convertToWebStyles([
3580
+ textStyles,
3581
+ spacingStyles,
3582
+ style,
3583
+ // default to inline unless caller explicitly requests display/whitespace behavior
3584
+ ...(hasDisplayOverride ? [] : [{ display: 'inline' }]),
3566
3585
  ]);
3567
3586
  // Handle text selection for web
3568
3587
  if (!selectable) {
@@ -6173,31 +6192,29 @@ const Button = (allProps) => {
6173
6192
  const { getDuration } = useReducedMotion$1();
6174
6193
  const { announce } = useAnnouncer();
6175
6194
  const { ref: focusRef} = useFocus(`button-${title || 'button'}`);
6195
+ // Track measured width for loading state preservation
6196
+ const [measuredWidth, setMeasuredWidth] = React.useState(null);
6197
+ const wasLoadingRef = React.useRef(loading);
6198
+ // When loading starts, we want to preserve the current measured width
6199
+ // When loading ends, clear the preserved width so it can resize naturally
6200
+ React.useEffect(() => {
6201
+ if (!loading && wasLoadingRef.current) {
6202
+ // Loading just ended, allow width to be recalculated
6203
+ setMeasuredWidth(null);
6204
+ }
6205
+ wasLoadingRef.current = loading;
6206
+ }, [loading]);
6207
+ const handleLayout = React.useCallback((event) => {
6208
+ // Only update measured width when not loading, so we capture the natural content width
6209
+ if (!loading) {
6210
+ const { width } = event.nativeEvent.layout;
6211
+ setMeasuredWidth(width);
6212
+ }
6213
+ // Call user's onLayout if provided
6214
+ onLayout === null || onLayout === void 0 ? void 0 : onLayout(event);
6215
+ }, [loading, onLayout]);
6176
6216
  // Determine button content - children takes precedence over title
6177
6217
  const buttonContent = children !== null && children !== void 0 ? children : title;
6178
- // Calculate minimum width for loading state based on content and size
6179
- const calculateMinWidth = () => {
6180
- if (!buttonContent || typeof buttonContent !== 'string')
6181
- return undefined;
6182
- // Base character width estimates based on size
6183
- const charWidthBySize = {
6184
- xs: 6,
6185
- sm: 7,
6186
- md: 8,
6187
- lg: 9,
6188
- xl: 10,
6189
- '2xl': 11,
6190
- '3xl': 12
6191
- };
6192
- const sizeKey = typeof size === 'string' ? size : 'md';
6193
- const charWidth = charWidthBySize[sizeKey] || 8;
6194
- const horizontalPadding = getSpacing(size) * 2; // Left + right padding
6195
- // Estimate content width: character count * average char width + padding
6196
- const contentWidth = buttonContent.length * charWidth + horizontalPadding;
6197
- // Add space for loader and gap when loading
6198
- const loaderWidth = getFontSize$1(size) + getSpacing(size) / 2; // Loader + margin
6199
- return Math.max(contentWidth, contentWidth + loaderWidth);
6200
- };
6201
6218
  // Determine what content to show based on loading state
6202
6219
  const displayContent = loading
6203
6220
  ? (loadingTitle !== undefined ? loadingTitle : '')
@@ -6236,12 +6253,12 @@ const Button = (allProps) => {
6236
6253
  const shadowStyles = getShadowStyles({ shadow: effectiveShadow }, theme, 'button');
6237
6254
  const spacingStyles = getSpacingStyles(spacingProps);
6238
6255
  const baseLayoutStyles = getLayoutStyles(layoutProps);
6239
- // Apply minimum width when loading to prevent size changes
6240
- const calculatedMinWidth = calculateMinWidth();
6256
+ // Apply measured width when loading to prevent size changes
6257
+ // Use the actual measured width instead of character-based estimates
6241
6258
  const layoutStyles = {
6242
6259
  ...baseLayoutStyles,
6243
- ...(loading && calculatedMinWidth && !layoutProps.width && !layoutProps.w && !layoutProps.fullWidth
6244
- ? { minWidth: calculatedMinWidth }
6260
+ ...(loading && measuredWidth && !layoutProps.w && !layoutProps.fullWidth
6261
+ ? { width: measuredWidth, minWidth: measuredWidth }
6245
6262
  : {})
6246
6263
  };
6247
6264
  const iconSpacing = getSpacing(size) / 2;
@@ -6434,7 +6451,7 @@ const Button = (allProps) => {
6434
6451
  ...(reactNative.Platform.OS !== 'web' ? { transform: [{ translateY: 1 }] } : {})
6435
6452
  } : null,
6436
6453
  style,
6437
- ], onPress: handleInternalPress, onLayout: onLayout, onPressIn: handlePressIn, onPressOut: handlePressOut, onHoverIn: onHoverIn, onHoverOut: onHoverOut, onLongPress: onLongPress, disabled: isInteractionDisabled, children: [variant === 'gradient' && hasLinearGradient$4 && (jsxRuntime.jsx(OptionalLinearGradient$6, { colors: resolvedCustomColor
6454
+ ], onPress: handleInternalPress, onLayout: handleLayout, onPressIn: handlePressIn, onPressOut: handlePressOut, onHoverIn: onHoverIn, onHoverOut: onHoverOut, onLongPress: onLongPress, disabled: isInteractionDisabled, children: [variant === 'gradient' && hasLinearGradient$4 && (jsxRuntime.jsx(OptionalLinearGradient$6, { colors: resolvedCustomColor
6438
6455
  ? [resolvedCustomColor, theme.colors.primary[7]]
6439
6456
  : [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 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Loader, { size: size, color: getLoaderColor(), style: !isIconButton ? { marginRight: iconSpacing } : undefined }), !isIconButton && renderButtonContent(displayContent)] })) : isIconButton ? (
6440
6457
  // Icon-only button
@@ -6674,18 +6691,22 @@ const useSafeSafeAreaInsets = () => {
6674
6691
  return { top: 0, bottom: 0, left: 0, right: 0 };
6675
6692
  }
6676
6693
  };
6677
- function Dialog({ visible, variant = 'modal', title, children, closable = true, backdrop = true, backdropClosable = true, shouldClose = false, onClose, width, height, style, bottomSheetSwipeZone = 'container', }) {
6694
+ function Dialog({ visible, variant = 'modal', title, children, closable = true, backdrop = true, backdropClosable = true, shouldClose = false, onClose, w, h, radius, style, showHeader = true, bottomSheetSwipeZone = 'container', }) {
6678
6695
  const theme = useTheme();
6679
6696
  const { isRTL } = useDirection();
6680
6697
  const insets = useSafeSafeAreaInsets();
6681
6698
  const { width: screenWidth, height: screenHeight } = reactNative.useWindowDimensions();
6682
6699
  const horizontalMargin = 32; // safety margin so dialog never touches edges
6683
6700
  const isNativePlatform = reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android';
6684
- const defaultModalMaxWidth = Math.min((width || 500), Math.max(200, screenWidth - horizontalMargin));
6701
+ const defaultModalMaxWidth = Math.min((w || 500), Math.max(200, screenWidth - horizontalMargin));
6685
6702
  const modalEffectiveWidth = variant !== 'modal'
6686
6703
  ? undefined
6687
6704
  : Math.min(defaultModalMaxWidth, screenWidth - horizontalMargin);
6688
- const bottomSheetMaxWidth = Math.min(width ? width : (isNativePlatform ? 720 : Math.min(600, screenWidth - horizontalMargin)), screenWidth);
6705
+ const bottomSheetMaxWidth = Math.min(w ? w : (isNativePlatform ? 720 : Math.min(600, screenWidth - horizontalMargin)), screenWidth);
6706
+ const resolvedRadius = radius !== null && radius !== void 0 ? radius : (variant === 'bottomsheet' ? 20 : 16);
6707
+ const resolvedMaxHeight = variant === 'bottomsheet'
6708
+ ? (h !== null && h !== void 0 ? h : Math.max(200, screenHeight - insets.top - 24))
6709
+ : (variant === 'fullscreen' ? '100%' : (h || '90%'));
6689
6710
  const invokeOnClose = React.useCallback(() => {
6690
6711
  onClose === null || onClose === void 0 ? void 0 : onClose();
6691
6712
  }, [onClose]);
@@ -6741,20 +6762,12 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6741
6762
  event.preventDefault();
6742
6763
  }
6743
6764
  }
6744
- // Allow dragging in both directions but apply rubber band for upward movement
6745
- const dragDistance = gestureState.dy;
6746
- if (dragDistance >= 0) {
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;
6751
- }
6752
- else {
6753
- // Upward movement - apply rubber band effect
6754
- const upwardResistance = 0.3;
6755
- const rubberBandDistance = dragDistance * upwardResistance;
6756
- slideAnim.value = rubberBandDistance;
6757
- }
6765
+ // Only allow downward movement (dismiss gesture)
6766
+ const dragDistance = Math.max(0, gestureState.dy);
6767
+ // Downward movement - apply subtle resistance for better feel
6768
+ const resistance = 0.8;
6769
+ const resistedDistance = dragDistance * resistance + (dragDistance > 100 ? (dragDistance - 100) * 0.2 : 0);
6770
+ slideAnim.value = resistedDistance;
6758
6771
  }
6759
6772
  },
6760
6773
  onPanResponderRelease: (_, gestureState) => {
@@ -6911,8 +6924,8 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6911
6924
  }, [shouldClose]);
6912
6925
  const isDark = theme.colorScheme === 'dark';
6913
6926
  const surfaceColor = isDark ? theme.backgrounds.surface : '#FFFFFF';
6914
- const borderColor = isDark ? theme.colors.gray[6] : '#E1E3E6';
6915
- const headerBg = isDark ? theme.backgrounds.subtle : surfaceColor;
6927
+ isDark ? theme.colors.gray[6] : '#E1E3E6';
6928
+ const headerBg = surfaceColor;
6916
6929
  const contentBg = surfaceColor;
6917
6930
  const dynamicStyles = reactNative.StyleSheet.create({
6918
6931
  backdrop: {
@@ -6923,24 +6936,28 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6923
6936
  }, // Allow backdropFilter on web
6924
6937
  modalContainer: {
6925
6938
  backgroundColor: contentBg,
6926
- borderRadius: variant === 'fullscreen' ? 0 : (variant === 'bottomsheet' ? 20 : 16),
6927
- borderBottomLeftRadius: variant === 'bottomsheet' ? 0 : undefined,
6928
- borderBottomRightRadius: variant === 'bottomsheet' ? 0 : undefined,
6939
+ borderRadius: variant === 'fullscreen' ? 0 : resolvedRadius,
6940
+ ...(variant === 'bottomsheet' ? {
6941
+ borderBottomLeftRadius: 0,
6942
+ borderBottomRightRadius: 0,
6943
+ } : {}),
6944
+ overflow: 'hidden', // Clip content to border radius
6929
6945
  // Clamp width to viewport (minus margins) while respecting provided width
6930
6946
  maxWidth: variant === 'fullscreen'
6931
6947
  ? '100%'
6932
6948
  : variant === 'bottomsheet'
6933
6949
  ? bottomSheetMaxWidth
6934
6950
  : defaultModalMaxWidth,
6935
- maxHeight: variant === 'fullscreen' ? '100%' : (height || '90%'),
6951
+ maxHeight: resolvedMaxHeight,
6936
6952
  width: variant === 'fullscreen'
6937
6953
  ? '100%'
6938
6954
  : variant === 'modal'
6939
6955
  ? modalEffectiveWidth || 'auto'
6940
6956
  : '100%',
6941
- height: variant === 'fullscreen' ? '100%' : (variant === 'modal' ? undefined : undefined),
6942
- // For modal variant, remove flex to allow fit-content behavior
6943
- ...(variant === 'modal' ? {} : { flex: 1 }),
6957
+ // Fullscreen uses 100% height, others auto-size to content
6958
+ height: variant === 'fullscreen' ? '100%' : undefined,
6959
+ // Only fullscreen should stretch to fill
6960
+ ...(variant === 'fullscreen' ? { flex: 1 } : {}),
6944
6961
  // Ensure minWidth never exceeds viewport clamp
6945
6962
  minWidth: variant === 'modal' ? Math.min(300, Math.max(200, screenWidth - horizontalMargin)) : undefined,
6946
6963
  alignSelf: variant === 'bottomsheet' ? 'center' : 'center',
@@ -6966,24 +6983,27 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
6966
6983
  }
6967
6984
  : reactNative.Platform.OS === 'android' && variant !== 'fullscreen'
6968
6985
  ? { elevation: 16, }
6969
- : {
6970
- boxShadow: 'none',
6971
- height: '100%',
6972
- position: 'absolute',
6973
- }),
6986
+ : variant === 'fullscreen'
6987
+ ? {
6988
+ boxShadow: 'none',
6989
+ height: '100%',
6990
+ position: 'absolute',
6991
+ }
6992
+ : { boxShadow: 'none' }),
6974
6993
  }, // Allow boxShadow on web
6975
6994
  header: {
6976
6995
  alignItems: 'center',
6977
- backgroundColor: headerBg,
6978
- borderBottomColor: borderColor,
6979
- borderBottomWidth: variant === 'fullscreen' ? 0 : 1,
6996
+ backgroundColor: showHeader ? headerBg : 'transparent',
6997
+ // borderBottomColor: showHeader ? borderColor : 'transparent',
6998
+ // borderBottomWidth: showHeader && variant !== 'fullscreen' ? 1 : 0,
6980
6999
  flexDirection: isRTL ? 'row-reverse' : 'row',
6981
7000
  justifyContent: 'space-between',
6982
7001
  padding: 20,
7002
+ paddingBottom: title ? 0 : 20,
6983
7003
  },
6984
7004
  content: {
6985
- // For modal variant, remove flex to allow fit-content behavior
6986
- ...(variant === 'modal' ? {} : { flex: 1 }),
7005
+ // Only fullscreen content should stretch
7006
+ ...(variant === 'fullscreen' ? { flex: 1 } : {}),
6987
7007
  alignSelf: 'stretch',
6988
7008
  backgroundColor: contentBg,
6989
7009
  padding: variant === 'fullscreen' ? 0 : 20,
@@ -7039,8 +7059,10 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
7039
7059
  });
7040
7060
  const bottomSheetAnimatedStyle = Animated.useAnimatedStyle(() => {
7041
7061
  if (variant === 'bottomsheet') {
7062
+ // Clamp to 0 minimum to prevent seeing "under" the sheet
7063
+ const clampedY = Math.max(0, slideAnim.value);
7042
7064
  return {
7043
- transform: [{ translateY: slideAnim.value }],
7065
+ transform: [{ translateY: clampedY }],
7044
7066
  };
7045
7067
  }
7046
7068
  return {};
@@ -7057,7 +7079,7 @@ function Dialog({ visible, variant = 'modal', title, children, closable = true,
7057
7079
  animatedStyle = bottomSheetAnimatedStyle;
7058
7080
  }
7059
7081
  return (jsxRuntime.jsxs(Animated.View, { style: [dynamicStyles.modalContainer, animatedStyle], ...(variant === 'bottomsheet' && bottomSheetSwipeZone === 'container' && panHandlers ? panHandlers : {}), children: [variant === 'bottomsheet' && (jsxRuntime.jsx(reactNative.View, { style: dynamicStyles.dragHandleContainer, ...(bottomSheetSwipeZone === 'handle' && panHandlers ? panHandlers : {}), children: jsxRuntime.jsx(reactNative.View, { style: dynamicStyles.dragHandle }) })), (title !== null &&
7060
- title && closable) && (jsxRuntime.jsxs(reactNative.View, { style: dynamicStyles.header, children: [jsxRuntime.jsx(Text, { variant: "h3", color: "text", children: title || '' }), closable && (jsxRuntime.jsx(Button, { variant: "ghost", onPress: handleClose, style: dynamicStyles.closeButton, children: jsxRuntime.jsx(Icon, { name: "x", size: "md" }) }))] })), jsxRuntime.jsx(reactNative.View, { style: [dynamicStyles.content, style], children: children })] }));
7082
+ title && closable) && (jsxRuntime.jsxs(reactNative.View, { style: dynamicStyles.header, children: [jsxRuntime.jsx(Text, { variant: "h3", color: "text", children: title || '' }), closable && variant !== 'bottomsheet' && (jsxRuntime.jsx(Button, { variant: "ghost", onPress: handleClose, style: dynamicStyles.closeButton, children: jsxRuntime.jsx(Icon, { name: "x", size: "md" }) }))] })), jsxRuntime.jsx(reactNative.View, { style: [dynamicStyles.content, style], children: children })] }));
7061
7083
  };
7062
7084
  return (jsxRuntime.jsx(reactNative.Modal, { visible: visible, transparent: true, animationType: "none", statusBarTranslucent: variant === 'fullscreen', children: jsxRuntime.jsxs(Animated.View, { style: [
7063
7085
  dynamicStyles.backdrop,
@@ -7266,7 +7288,7 @@ function DialogRenderer() {
7266
7288
  return null;
7267
7289
  // Render the topmost dialog
7268
7290
  const topDialog = dialogs[dialogs.length - 1];
7269
- return (jsxRuntime.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 }));
7291
+ return (jsxRuntime.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 }));
7270
7292
  }
7271
7293
 
7272
7294
  const Flex = factory((props, ref) => {
@@ -8351,7 +8373,14 @@ const getContrastPreference = () => {
8351
8373
  return 'less';
8352
8374
  return 'no-preference';
8353
8375
  };
8354
- const getColorScheme = () => { var _a, _b; return (_b = (_a = reactNative.Appearance === null || reactNative.Appearance === void 0 ? void 0 : reactNative.Appearance.getColorScheme) === null || _a === void 0 ? void 0 : _a.call(reactNative.Appearance)) !== null && _b !== void 0 ? _b : 'no-preference'; };
8376
+ const getColorScheme = () => {
8377
+ var _a;
8378
+ const scheme = (_a = reactNative.Appearance === null || reactNative.Appearance === void 0 ? void 0 : reactNative.Appearance.getColorScheme) === null || _a === void 0 ? void 0 : _a.call(reactNative.Appearance);
8379
+ // Handle 'unspecified' from newer React Native versions
8380
+ if (scheme === 'light' || scheme === 'dark')
8381
+ return scheme;
8382
+ return 'no-preference';
8383
+ };
8355
8384
  const getReducedMotion = async () => {
8356
8385
  if (reactNative.Platform.OS === 'web') {
8357
8386
  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function')
@@ -8576,7 +8605,13 @@ function useDeviceInfo(options = {}) {
8576
8605
  React.useEffect(() => {
8577
8606
  var _a;
8578
8607
  const colorSubscription = (_a = reactNative.Appearance === null || reactNative.Appearance === void 0 ? void 0 : reactNative.Appearance.addChangeListener) === null || _a === void 0 ? void 0 : _a.call(reactNative.Appearance, ({ colorScheme: scheme }) => {
8579
- setColorScheme(scheme !== null && scheme !== void 0 ? scheme : 'no-preference');
8608
+ // Handle 'unspecified' from newer React Native versions
8609
+ if (scheme === 'light' || scheme === 'dark') {
8610
+ setColorScheme(scheme);
8611
+ }
8612
+ else {
8613
+ setColorScheme('no-preference');
8614
+ }
8580
8615
  });
8581
8616
  const mediaListeners = [];
8582
8617
  let boldSubscription;
@@ -9121,7 +9156,7 @@ function SpotlightRoot({ query, onQueryChange, children, opened = false, onClose
9121
9156
  const targetWidth = Math.min(560, Math.max(280, screenWidth - horizontalMargin));
9122
9157
  // (Hotkey registration moved to main Spotlight component for access to store.toggle())
9123
9158
  const fullscreen = shouldUseModal;
9124
- return (jsxRuntime.jsx(Dialog, { visible: opened, onClose: onClose, variant: fullscreen ? 'fullscreen' : 'modal', backdrop: true, backdropClosable: true, width: fullscreen ? undefined : targetWidth, title: null, style: [
9159
+ return (jsxRuntime.jsx(Dialog, { visible: opened, onClose: onClose, variant: fullscreen ? 'fullscreen' : 'modal', backdrop: true, backdropClosable: true, w: fullscreen ? undefined : targetWidth, title: null, style: [
9125
9160
  styles$e.spotlightModal,
9126
9161
  fullscreen && { width: '100%', height: '100%', maxHeight: '100%', borderRadius: 0, position: 'fixed', top: 0, left: 0 },
9127
9162
  !fullscreen && {
@@ -9683,6 +9718,23 @@ function generateUniversalCSS() {
9683
9718
  xl: '88em'
9684
9719
  };
9685
9720
  const universalCSS = `
9721
+ /* Reset browser default input styles to prevent double borders */
9722
+ input, textarea, select {
9723
+ outline: none !important;
9724
+ -webkit-appearance: none !important;
9725
+ -moz-appearance: none !important;
9726
+ appearance: none !important;
9727
+ }
9728
+
9729
+ input:focus, textarea:focus, select:focus {
9730
+ outline: none !important;
9731
+ }
9732
+
9733
+ /* Ensure React Native Web focusable elements don't show browser outlines */
9734
+ [data-focusable="true"]:focus {
9735
+ outline: none !important;
9736
+ }
9737
+
9686
9738
  /* Color scheme based visibility */
9687
9739
  .platform-blocks-light-hidden {
9688
9740
  display: none !important;
@@ -9729,12 +9781,14 @@ function UniversalCSS() {
9729
9781
  return;
9730
9782
  }
9731
9783
  // Check if styles are already injected
9732
- const existingStyle = document.getElementById('platform-blocks-universal-css');
9733
- if (existingStyle) {
9784
+ let styleElement = document.getElementById('platform-blocks-universal-css');
9785
+ if (styleElement) {
9786
+ // Update content if it exists (in case CSS changed)
9787
+ styleElement.textContent = css;
9734
9788
  return;
9735
9789
  }
9736
9790
  // Create and inject styles
9737
- const styleElement = document.createElement('style');
9791
+ styleElement = document.createElement('style');
9738
9792
  styleElement.id = 'platform-blocks-universal-css';
9739
9793
  styleElement.textContent = css;
9740
9794
  document.head.appendChild(styleElement);
@@ -9752,593 +9806,6 @@ function UniversalCSS() {
9752
9806
  return null;
9753
9807
  }
9754
9808
 
9755
- /**
9756
- * Core Ability class for managing permissions
9757
- */
9758
- class AbilityCore {
9759
- constructor(rules = []) {
9760
- this.rules = [];
9761
- this.cache = new Map();
9762
- this.rules = [...rules];
9763
- }
9764
- /**
9765
- * Check if action is allowed on subject
9766
- */
9767
- can(action, subject, field) {
9768
- return this.check(action, subject, field).allowed;
9769
- }
9770
- /**
9771
- * Check if action is forbidden on subject
9772
- */
9773
- cannot(action, subject, field) {
9774
- return !this.can(action, subject, field);
9775
- }
9776
- /**
9777
- * Get detailed permission check result
9778
- */
9779
- check(action, subject, field) {
9780
- const cacheKey = this.getCacheKey(action, subject, field);
9781
- if (this.cache.has(cacheKey)) {
9782
- return this.cache.get(cacheKey);
9783
- }
9784
- const result = this.performCheck(action, subject, field);
9785
- this.cache.set(cacheKey, result);
9786
- return result;
9787
- }
9788
- /**
9789
- * Update ability rules and clear cache
9790
- */
9791
- update(rules) {
9792
- this.rules = [...rules];
9793
- this.cache.clear();
9794
- }
9795
- /**
9796
- * Get all current rules
9797
- */
9798
- getRules() {
9799
- return [...this.rules];
9800
- }
9801
- /**
9802
- * Clear all rules and cache
9803
- */
9804
- clear() {
9805
- this.rules = [];
9806
- this.cache.clear();
9807
- }
9808
- /**
9809
- * Perform the actual permission check
9810
- */
9811
- performCheck(action, subject, field) {
9812
- // Start with denied by default
9813
- let result = {
9814
- allowed: false,
9815
- reason: 'No matching permission rule found'
9816
- };
9817
- // Check rules in order (later rules can override earlier ones)
9818
- for (const rule of this.rules) {
9819
- if (this.ruleMatches(rule, action, subject, field)) {
9820
- result = {
9821
- allowed: !rule.inverted,
9822
- reason: rule.reason || (rule.inverted ? 'Access denied by rule' : 'Access granted by rule'),
9823
- rule
9824
- };
9825
- }
9826
- }
9827
- return result;
9828
- }
9829
- /**
9830
- * Check if a rule matches the current permission check
9831
- */
9832
- ruleMatches(rule, action, subject, field) {
9833
- // Check action match
9834
- const actions = Array.isArray(rule.action) ? rule.action : [rule.action];
9835
- if (!actions.includes(action) && !actions.includes('*')) {
9836
- return false;
9837
- }
9838
- // Check subject match
9839
- const subjects = Array.isArray(rule.subject) ? rule.subject : [rule.subject];
9840
- if (!this.subjectMatches(subjects, subject)) {
9841
- return false;
9842
- }
9843
- // Check field match (if specified)
9844
- if (field && rule.fields && !rule.fields.includes(field)) {
9845
- return false;
9846
- }
9847
- // Check conditions (if subject is an object)
9848
- if (rule.conditions && typeof subject === 'object' && subject !== null) {
9849
- return this.conditionsMatch(rule.conditions, subject);
9850
- }
9851
- return true;
9852
- }
9853
- /**
9854
- * Check if subject matches any of the rule subjects
9855
- */
9856
- subjectMatches(ruleSubjects, checkSubject) {
9857
- for (const ruleSubject of ruleSubjects) {
9858
- if (ruleSubject === '*')
9859
- return true;
9860
- if (ruleSubject === checkSubject)
9861
- return true;
9862
- // Handle class/constructor matching
9863
- if (typeof ruleSubject === 'function' && typeof checkSubject === 'object') {
9864
- if (checkSubject instanceof ruleSubject)
9865
- return true;
9866
- if (checkSubject.constructor === ruleSubject)
9867
- return true;
9868
- }
9869
- // Handle string matching for object types
9870
- if (typeof ruleSubject === 'string' && typeof checkSubject === 'object') {
9871
- if (checkSubject.__type === ruleSubject)
9872
- return true;
9873
- if (checkSubject.type === ruleSubject)
9874
- return true;
9875
- if (checkSubject.constructor.name === ruleSubject)
9876
- return true;
9877
- }
9878
- }
9879
- return false;
9880
- }
9881
- /**
9882
- * Check if conditions match the subject object
9883
- */
9884
- conditionsMatch(conditions, subject) {
9885
- for (const [key, expectedValue] of Object.entries(conditions)) {
9886
- const actualValue = subject[key];
9887
- if (!this.valuesMatch(actualValue, expectedValue)) {
9888
- return false;
9889
- }
9890
- }
9891
- return true;
9892
- }
9893
- /**
9894
- * Check if two values match (handles various comparison types)
9895
- */
9896
- valuesMatch(actual, expected) {
9897
- // Exact match
9898
- if (actual === expected)
9899
- return true;
9900
- // Array contains check
9901
- if (Array.isArray(expected) && expected.includes(actual))
9902
- return true;
9903
- if (Array.isArray(actual) && actual.includes(expected))
9904
- return true;
9905
- // Function/predicate check
9906
- if (typeof expected === 'function') {
9907
- return expected(actual);
9908
- }
9909
- // Regex match for strings
9910
- if (expected instanceof RegExp && typeof actual === 'string') {
9911
- return expected.test(actual);
9912
- }
9913
- // Object comparison (shallow)
9914
- if (typeof expected === 'object' && typeof actual === 'object' && expected !== null && actual !== null) {
9915
- return Object.keys(expected).every(key => this.valuesMatch(actual[key], expected[key]));
9916
- }
9917
- return false;
9918
- }
9919
- /**
9920
- * Generate cache key for permission check
9921
- */
9922
- getCacheKey(action, subject, field) {
9923
- const subjectKey = typeof subject === 'object'
9924
- ? JSON.stringify(subject)
9925
- : String(subject);
9926
- return `${action}:${subjectKey}:${field || ''}`;
9927
- }
9928
- }
9929
- /**
9930
- * Create a new Ability instance
9931
- */
9932
- function createAbility(rules = []) {
9933
- return new AbilityCore(rules);
9934
- }
9935
-
9936
- /**
9937
- * Permission Context
9938
- */
9939
- const PermissionContext = React.createContext(null);
9940
- /**
9941
- * Permission Provider Component
9942
- */
9943
- const PermissionProvider = ({ rules = [], user, children, dev = {} }) => {
9944
- const [ability] = React.useState(() => createAbility(rules));
9945
- const [currentUser, setCurrentUser] = React.useState(user);
9946
- const updateAbility = React.useCallback((newRules) => {
9947
- ability.update(newRules);
9948
- }, [ability]);
9949
- const can = React.useCallback((action, subject, field) => {
9950
- const result = ability.can(action, subject, field);
9951
- if (dev.logChecks) {
9952
- console.log(`[Permissions] Can ${action} ${subject}${field ? `.${field}` : ''}:`, result);
9953
- }
9954
- return result;
9955
- }, [ability, dev.logChecks]);
9956
- const cannot = React.useCallback((action, subject, field) => {
9957
- const result = ability.cannot(action, subject, field);
9958
- if (dev.logChecks) {
9959
- console.log(`[Permissions] Cannot ${action} ${subject}${field ? `.${field}` : ''}:`, result);
9960
- }
9961
- return result;
9962
- }, [ability, dev.logChecks]);
9963
- const setUser = React.useCallback((newUser) => {
9964
- setCurrentUser(newUser);
9965
- }, []);
9966
- const contextValue = React.useMemo(() => ({
9967
- ability,
9968
- updateAbility,
9969
- can,
9970
- cannot,
9971
- user: currentUser,
9972
- setUser
9973
- }), [ability, updateAbility, can, cannot, currentUser, setUser]);
9974
- return React.createElement(PermissionContext.Provider, { value: contextValue }, children);
9975
- };
9976
- /**
9977
- * Hook to access permission context
9978
- */
9979
- const usePermissions = (options = {}) => {
9980
- const context = React.useContext(PermissionContext);
9981
- if (!context) {
9982
- if (options.required) {
9983
- throw new Error('usePermissions must be used within a PermissionProvider');
9984
- }
9985
- if (options.debug) {
9986
- console.warn('[Permissions] usePermissions called outside of PermissionProvider');
9987
- }
9988
- // Return a fallback context that allows everything
9989
- return {
9990
- ability: createAbility([{ action: '*', subject: '*' }]),
9991
- updateAbility: () => { },
9992
- can: () => true,
9993
- cannot: () => false,
9994
- user: null,
9995
- setUser: () => { }
9996
- };
9997
- }
9998
- return context;
9999
- };
10000
- /**
10001
- * Hook to get the current ability instance
10002
- */
10003
- const useAbility = () => {
10004
- const { ability } = usePermissions();
10005
- return ability;
10006
- };
10007
-
10008
- /**
10009
- * Can Component - Renders children if permission is granted
10010
- */
10011
- const Can = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
10012
- const { ability: contextAbility } = usePermissions();
10013
- const ability = customAbility || contextAbility;
10014
- // Development passthrough
10015
- if (passthrough && __DEV__) {
10016
- return React.createElement(reactNative.View, { style, testID }, children);
10017
- }
10018
- const hasPermission = subject
10019
- ? ability.can(action, subject, field)
10020
- : ability.can(action, '*', field);
10021
- if (hasPermission) {
10022
- return React.createElement(reactNative.View, { style, testID }, children);
10023
- }
10024
- return React.createElement(reactNative.View, { style, testID }, fallback);
10025
- };
10026
- /**
10027
- * Can Component with conditions - For object-level permissions
10028
- */
10029
- const CanWithConditions = ({ I: action, this: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
10030
- const { ability: contextAbility } = usePermissions();
10031
- const ability = customAbility || contextAbility;
10032
- // Development passthrough
10033
- if (passthrough && __DEV__) {
10034
- return React.createElement(reactNative.View, { style, testID }, children);
10035
- }
10036
- const hasPermission = ability.can(action, subject, field);
10037
- if (hasPermission) {
10038
- return React.createElement(reactNative.View, { style, testID }, children);
10039
- }
10040
- return React.createElement(reactNative.View, { style, testID }, fallback);
10041
- };
10042
- /**
10043
- * Cannot Component - Renders children if permission is NOT granted
10044
- */
10045
- const Cannot = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
10046
- const { ability: contextAbility } = usePermissions();
10047
- const ability = customAbility || contextAbility;
10048
- // Development passthrough
10049
- if (passthrough && __DEV__) {
10050
- return React.createElement(reactNative.View, { style, testID }, fallback);
10051
- }
10052
- const hasPermission = subject
10053
- ? ability.can(action, subject, field)
10054
- : ability.can(action, '*', field);
10055
- if (!hasPermission) {
10056
- return React.createElement(reactNative.View, { style, testID }, children);
10057
- }
10058
- return React.createElement(reactNative.View, { style, testID }, fallback);
10059
- };
10060
- /**
10061
- * Permission Gate - Requires ALL permissions to pass
10062
- */
10063
- const PermissionGate = ({ permissions, children, fallback = null, ability: customAbility, onUnauthorized }) => {
10064
- const { ability: contextAbility } = usePermissions();
10065
- const ability = customAbility || contextAbility;
10066
- const allPermissionsGranted = permissions.every(({ action, subject, field }) => ability.can(action, subject, field));
10067
- React.useEffect(() => {
10068
- if (!allPermissionsGranted && onUnauthorized) {
10069
- onUnauthorized();
10070
- }
10071
- }, [allPermissionsGranted, onUnauthorized]);
10072
- if (allPermissionsGranted) {
10073
- return React.createElement(React.Fragment, null, children);
10074
- }
10075
- return React.createElement(React.Fragment, null, fallback);
10076
- };
10077
- /**
10078
- * Higher-Order Component for permission checking
10079
- */
10080
- function withCan(action, subject, field) {
10081
- return function CanHOC(Component) {
10082
- const WrappedComponent = (props) => {
10083
- const { fallback, ...componentProps } = props;
10084
- return React.createElement(Can, { I: action, a: subject, field, fallback }, React.createElement(Component, componentProps));
10085
- };
10086
- WrappedComponent.displayName = `withCan(${Component.displayName || Component.name})`;
10087
- return WrappedComponent;
10088
- };
10089
- }
10090
- /**
10091
- * Higher-Order Component for permission denial checking
10092
- */
10093
- function withCannot(action, subject, field) {
10094
- return function CannotHOC(Component) {
10095
- const WrappedComponent = (props) => {
10096
- const { fallback, ...componentProps } = props;
10097
- return React.createElement(Cannot, { I: action, a: subject, field, fallback }, React.createElement(Component, componentProps));
10098
- };
10099
- WrappedComponent.displayName = `withCannot(${Component.displayName || Component.name})`;
10100
- return WrappedComponent;
10101
- };
10102
- }
10103
-
10104
- /**
10105
- * Fluent API for building permissions
10106
- */
10107
- class PermissionBuilder {
10108
- constructor() {
10109
- this.rules = [];
10110
- }
10111
- /**
10112
- * Grant permission
10113
- */
10114
- allow(action, subject, field) {
10115
- this.rules.push({
10116
- action,
10117
- subject: subject || '*',
10118
- fields: field ? [field] : undefined,
10119
- inverted: false
10120
- });
10121
- return this;
10122
- }
10123
- /**
10124
- * Deny permission
10125
- */
10126
- forbid(action, subject, field) {
10127
- this.rules.push({
10128
- action,
10129
- subject: subject || '*',
10130
- fields: field ? [field] : undefined,
10131
- inverted: true
10132
- });
10133
- return this;
10134
- }
10135
- /**
10136
- * Conditional permission
10137
- */
10138
- allowIf(action, subject, conditions, field) {
10139
- this.rules.push({
10140
- action,
10141
- subject: subject || '*',
10142
- fields: field ? [field] : undefined,
10143
- inverted: false,
10144
- conditions
10145
- });
10146
- return this;
10147
- }
10148
- /**
10149
- * Conditional denial
10150
- */
10151
- forbidIf(action, subject, conditions, field) {
10152
- this.rules.push({
10153
- action,
10154
- subject: subject || '*',
10155
- fields: field ? [field] : undefined,
10156
- inverted: true,
10157
- conditions
10158
- });
10159
- return this;
10160
- }
10161
- /**
10162
- * Grant all actions on a subject
10163
- */
10164
- manage(subject) {
10165
- this.rules.push({
10166
- action: '*',
10167
- subject,
10168
- inverted: false
10169
- });
10170
- return this;
10171
- }
10172
- /**
10173
- * Forbid all actions on a subject
10174
- */
10175
- forbidAll(subject) {
10176
- this.rules.push({
10177
- action: '*',
10178
- subject,
10179
- inverted: true
10180
- });
10181
- return this;
10182
- }
10183
- /**
10184
- * Role-based permissions
10185
- */
10186
- role(roleName, callback) {
10187
- const roleBuilder = new RoleBuilder(roleName);
10188
- callback(roleBuilder);
10189
- this.rules.push(...roleBuilder.getRules());
10190
- return this;
10191
- }
10192
- /**
10193
- * Build the ability with all rules
10194
- */
10195
- build() {
10196
- return new AbilityCore(this.rules);
10197
- }
10198
- /**
10199
- * Get all rules
10200
- */
10201
- getRules() {
10202
- return [...this.rules];
10203
- }
10204
- /**
10205
- * Clear all rules
10206
- */
10207
- clear() {
10208
- this.rules = [];
10209
- return this;
10210
- }
10211
- /**
10212
- * Merge rules from another builder
10213
- */
10214
- merge(other) {
10215
- this.rules.push(...other.getRules());
10216
- return this;
10217
- }
10218
- }
10219
- /**
10220
- * Role-specific permission builder
10221
- */
10222
- class RoleBuilder {
10223
- constructor(roleName) {
10224
- this.roleName = roleName;
10225
- this.rules = [];
10226
- }
10227
- /**
10228
- * Grant permission for this role
10229
- */
10230
- can(action, subject, field) {
10231
- this.rules.push({
10232
- action,
10233
- subject: subject || '*',
10234
- fields: field ? [field] : undefined,
10235
- inverted: false,
10236
- conditions: { role: this.roleName }
10237
- });
10238
- return this;
10239
- }
10240
- /**
10241
- * Deny permission for this role
10242
- */
10243
- cannot(action, subject, field) {
10244
- this.rules.push({
10245
- action,
10246
- subject: subject || '*',
10247
- fields: field ? [field] : undefined,
10248
- inverted: true,
10249
- conditions: { role: this.roleName }
10250
- });
10251
- return this;
10252
- }
10253
- /**
10254
- * Manage all actions on subject for this role
10255
- */
10256
- manage(subject) {
10257
- this.rules.push({
10258
- action: '*',
10259
- subject,
10260
- inverted: false,
10261
- conditions: { role: this.roleName }
10262
- });
10263
- return this;
10264
- }
10265
- /**
10266
- * Get all rules for this role
10267
- */
10268
- getRules() {
10269
- return [...this.rules];
10270
- }
10271
- }
10272
- /**
10273
- * Common permission patterns
10274
- */
10275
- class PermissionPatterns {
10276
- /**
10277
- * Admin permissions - can do everything
10278
- */
10279
- static admin() {
10280
- return new PermissionBuilder()
10281
- .manage('*');
10282
- }
10283
- /**
10284
- * User permissions - basic CRUD on own resources
10285
- */
10286
- static user(userId) {
10287
- return new PermissionBuilder()
10288
- .allowIf('read', 'User', { id: userId })
10289
- .allowIf('update', 'User', { id: userId })
10290
- .allowIf('delete', 'User', { id: userId })
10291
- .allow('read', 'public');
10292
- }
10293
- /**
10294
- * Guest permissions - read-only public content
10295
- */
10296
- static guest() {
10297
- return new PermissionBuilder()
10298
- .allow('read', 'public');
10299
- }
10300
- /**
10301
- * Moderator permissions - manage content but not users
10302
- */
10303
- static moderator() {
10304
- return new PermissionBuilder()
10305
- .manage('Content')
10306
- .manage('Comment')
10307
- .allow('read', 'User')
10308
- .forbid('delete', 'User');
10309
- }
10310
- /**
10311
- * Owner permissions - full control over owned resources
10312
- */
10313
- static owner(ownerId) {
10314
- return new PermissionBuilder()
10315
- .allowIf('*', '*', { ownerId })
10316
- .allow('create', '*');
10317
- }
10318
- }
10319
- /**
10320
- * Helper function to create a new permission builder
10321
- */
10322
- function permissions() {
10323
- return new PermissionBuilder();
10324
- }
10325
- /**
10326
- * Helper function to create ability from rules array
10327
- */
10328
- function defineAbility(callback) {
10329
- const builder = new PermissionBuilder();
10330
- callback(builder);
10331
- return builder.build();
10332
- }
10333
- /**
10334
- * Helper function to create common role-based abilities
10335
- */
10336
- function defineRoleAbility(role, callback) {
10337
- const roleBuilder = new RoleBuilder(role);
10338
- callback(roleBuilder);
10339
- return new AbilityCore(roleBuilder.getRules());
10340
- }
10341
-
10342
9809
  const ThemeModeContext = React.createContext(null);
10343
9810
  // Default persistence using localStorage (web only)
10344
9811
  const defaultPersistence = {
@@ -10468,7 +9935,6 @@ const OverlayBoundary = React.memo(function OverlayBoundary({ enabled, children
10468
9935
  const I18nBoundary = React.memo(function I18nBoundary({ locale, fallbackLocale, resources, children }) {
10469
9936
  return (jsxRuntime.jsx(I18nProvider, { initial: { locale, fallbackLocale, resources }, children: children }));
10470
9937
  });
10471
- const DEFAULT_PERMISSION_RULES = [{ action: '*', subject: '*' }];
10472
9938
  /**
10473
9939
  * Internal component that uses the enhanced theme mode when config is provided
10474
9940
  */
@@ -10506,30 +9972,20 @@ function PlatformBlocksContent({ children, theme, inherit = true, withCSSVariabl
10506
9972
  document.documentElement.setAttribute('data-platform-blocks-color-scheme', target);
10507
9973
  }
10508
9974
  }, [effectiveColorScheme, osColorScheme]);
10509
- const mainContent = (jsxRuntime.jsxs(ThemeBoundary, { theme: resolvedTheme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, withGlobalCSS: withGlobalCSS, children: [children, withSpotlight && jsxRuntime.jsx(SpotlightController, { config: spotlightConfig })] }));
10510
- return (jsxRuntime.jsx(OverlayBoundary, { enabled: withOverlays, children: mainContent }));
9975
+ const mainContent = (jsxRuntime.jsx(ThemeBoundary, { theme: resolvedTheme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, withGlobalCSS: withGlobalCSS, children: jsxRuntime.jsxs(OverlayBoundary, { enabled: withOverlays, children: [children, withSpotlight && jsxRuntime.jsx(SpotlightController, { config: spotlightConfig })] }) }));
9976
+ return mainContent;
10511
9977
  }
10512
9978
  /**
10513
9979
  * Main provider component for Platform Blocks library
10514
9980
  * Provides theme context and injects CSS variables
10515
9981
  */
10516
- 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 }) {
9982
+ 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 }) {
10517
9983
  const i18nStore = React.useMemo(() => i18nResources || { en: { translation: {} } }, [i18nResources]);
10518
9984
  const content = (jsxRuntime.jsx(PlatformBlocksContent, { theme: theme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, colorSchemeMode: colorSchemeMode, withOverlays: withOverlays, withSpotlight: withSpotlight, withGlobalCSS: withGlobalCSS, spotlightConfig: spotlightConfig, themeModeConfig: themeModeConfig, children: children }));
10519
9985
  const themedTree = themeModeConfig ? (jsxRuntime.jsx(ThemeModeProvider, { config: themeModeConfig, children: content })) : (content);
10520
9986
  const directionConfig = direction === false ? null : (direction !== null && direction !== void 0 ? direction : {});
10521
9987
  const hapticsConfig = haptics === false ? null : (haptics !== null && haptics !== void 0 ? haptics : {});
10522
- const permissionConfig = permissions === false ? null : (() => {
10523
- const base = { ...(permissions !== null && permissions !== void 0 ? permissions : {}) };
10524
- if (base.rules === undefined) {
10525
- base.rules = DEFAULT_PERMISSION_RULES;
10526
- }
10527
- return base;
10528
- })();
10529
9988
  let enhancedTree = themedTree;
10530
- if (permissionConfig) {
10531
- enhancedTree = (jsxRuntime.jsx(PermissionProvider, { ...permissionConfig, children: enhancedTree }));
10532
- }
10533
9989
  if (hapticsConfig) {
10534
9990
  enhancedTree = (jsxRuntime.jsx(HapticsProvider, { ...hapticsConfig, children: enhancedTree }));
10535
9991
  }
@@ -11019,14 +10475,18 @@ function usePopoverPositioning(isOpen, options = {}) {
11019
10475
  // Get popover dimensions
11020
10476
  // Always use measureElement for robustness across platforms (RNW refs may not expose getBoundingClientRect)
11021
10477
  let popoverDimensions = { width: 200, height: 100 }; // sensible defaults for initial calculation
10478
+ let hasMeasuredPopover = false;
11022
10479
  if (popoverRef.current) {
11023
10480
  const popoverRect = await measureElement(popoverRef);
11024
10481
  if (popoverRect.width > 0 && popoverRect.height > 0) {
11025
10482
  popoverDimensions = { width: popoverRect.width, height: popoverRect.height };
10483
+ hasMeasuredPopover = true;
11026
10484
  }
11027
10485
  }
11028
10486
  // Calculate optimal position
11029
10487
  const result = calculateOverlayPositionEnhanced(anchorRect, popoverDimensions, positioningOptionsRef.current);
10488
+ // Mark whether this position is based on actual measurements
10489
+ result._hasMeasuredPopover = hasMeasuredPopover;
11030
10490
  setPosition(result);
11031
10491
  }
11032
10492
  catch (error) {
@@ -12452,9 +11912,10 @@ const Row = ({ direction = 'row', gap = 'sm', ...props }) => {
12452
11912
  };
12453
11913
  /**
12454
11914
  * Column component - alias for Flex with direction="column"
11915
+ * Defaults to fullWidth={true} since vertical layouts typically fill available width
12455
11916
  */
12456
- const Column = ({ direction = 'column', gap = 'sm', ...props }) => {
12457
- return jsxRuntime.jsx(Flex, { direction: direction, gap: gap, ...props });
11917
+ const Column = ({ direction = 'column', gap = 'sm', fullWidth = true, ...props }) => {
11918
+ return jsxRuntime.jsx(Flex, { direction: direction, gap: gap, fullWidth: fullWidth, ...props });
12458
11919
  };
12459
11920
  Row.displayName = 'Row';
12460
11921
 
@@ -14569,35 +14030,101 @@ function createNativeHighlighter(theme, isDark, variant = 'code', overrides) {
14569
14030
  };
14570
14031
  }
14571
14032
 
14572
- // Prism light build for JSX/TSX (react-syntax-highlighter)
14033
+ // Syntax highlighter - only loaded on web, native uses built-in tokenizer
14034
+ // These are initialized lazily on first use to avoid Metro bundling issues
14573
14035
  let PrismSyntaxHighlighter = null;
14574
14036
  let prismLightTheme = null;
14575
14037
  let prismDarkTheme = null;
14576
- if (reactNative.Platform.OS === 'web') {
14577
- PrismSyntaxHighlighter = resolveOptionalModule('react-syntax-highlighter', {
14578
- accessor: (module) => module.PrismLight,
14579
- devWarning: 'react-syntax-highlighter not found, CodeBlock will use basic formatting',
14580
- });
14581
- if (PrismSyntaxHighlighter) {
14582
- const registerLanguage = (moduleId, name) => {
14583
- const languageModule = resolveOptionalModule(moduleId, { accessor: (mod) => mod.default });
14584
- if (languageModule) {
14585
- PrismSyntaxHighlighter.registerLanguage(name, languageModule);
14038
+ let syntaxHighlighterInitialized = false;
14039
+ // Use indirect require via new Function to prevent Metro from statically analyzing imports
14040
+ // Metro bundles ALL require() calls it finds, even in try-catch blocks
14041
+ // new Function() creates a runtime-evaluated require that Metro can't see
14042
+ const safeRequire = (() => {
14043
+ try {
14044
+ // This creates: function(moduleName) { return require(moduleName); }
14045
+ // The string 'require' is not statically analyzable by Metro
14046
+ return new Function('moduleName', 'return require(moduleName)');
14047
+ }
14048
+ catch (_a) {
14049
+ return null;
14050
+ }
14051
+ })();
14052
+ function initSyntaxHighlighter() {
14053
+ if (syntaxHighlighterInitialized)
14054
+ return;
14055
+ syntaxHighlighterInitialized = true;
14056
+ // Only attempt to load on web
14057
+ if (reactNative.Platform.OS !== 'web')
14058
+ return;
14059
+ if (!safeRequire)
14060
+ return;
14061
+ try {
14062
+ const rsh = safeRequire('react-syntax-highlighter');
14063
+ PrismSyntaxHighlighter = rsh.PrismLight;
14064
+ if (PrismSyntaxHighlighter) {
14065
+ // Register languages
14066
+ try {
14067
+ const jsx = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/jsx').default;
14068
+ PrismSyntaxHighlighter.registerLanguage('jsx', jsx);
14586
14069
  }
14587
- };
14588
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/jsx', 'jsx');
14589
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/tsx', 'tsx');
14590
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/typescript', 'typescript');
14591
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/javascript', 'javascript');
14592
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/json', 'json');
14593
- registerLanguage('react-syntax-highlighter/dist/esm/languages/prism/bash', 'bash');
14594
- prismLightTheme = resolveOptionalModule('react-syntax-highlighter/dist/esm/styles/prism/prism', {
14595
- accessor: (mod) => mod.default,
14596
- });
14597
- prismDarkTheme = resolveOptionalModule('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus', {
14598
- accessor: (mod) => mod.default,
14599
- devWarning: 'Failed to load prism vsc-dark-plus theme, falling back to prism',
14600
- });
14070
+ catch (_a) {
14071
+ // Language not available
14072
+ }
14073
+ try {
14074
+ const tsx = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/tsx').default;
14075
+ PrismSyntaxHighlighter.registerLanguage('tsx', tsx);
14076
+ }
14077
+ catch (_b) {
14078
+ // Language not available
14079
+ }
14080
+ try {
14081
+ const ts = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/typescript').default;
14082
+ PrismSyntaxHighlighter.registerLanguage('typescript', ts);
14083
+ }
14084
+ catch (_c) {
14085
+ // Language not available
14086
+ }
14087
+ try {
14088
+ const js = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/javascript').default;
14089
+ PrismSyntaxHighlighter.registerLanguage('javascript', js);
14090
+ }
14091
+ catch (_d) {
14092
+ // Language not available
14093
+ }
14094
+ try {
14095
+ const json = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/json').default;
14096
+ PrismSyntaxHighlighter.registerLanguage('json', json);
14097
+ }
14098
+ catch (_e) {
14099
+ // Language not available
14100
+ }
14101
+ try {
14102
+ const bash = safeRequire('react-syntax-highlighter/dist/esm/languages/prism/bash').default;
14103
+ PrismSyntaxHighlighter.registerLanguage('bash', bash);
14104
+ }
14105
+ catch (_f) {
14106
+ // Language not available
14107
+ }
14108
+ // Load themes
14109
+ try {
14110
+ prismLightTheme = safeRequire('react-syntax-highlighter/dist/esm/styles/prism/prism').default;
14111
+ }
14112
+ catch (_g) {
14113
+ // Theme not available
14114
+ }
14115
+ try {
14116
+ prismDarkTheme = safeRequire('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus').default;
14117
+ }
14118
+ catch (_h) {
14119
+ // Theme not available
14120
+ }
14121
+ }
14122
+ }
14123
+ catch (_j) {
14124
+ // react-syntax-highlighter not installed, will use native fallback
14125
+ if (__DEV__) {
14126
+ console.warn('[platform-blocks] react-syntax-highlighter not found, CodeBlock will use basic formatting');
14127
+ }
14601
14128
  }
14602
14129
  }
14603
14130
  const NO_HIGHLIGHTS = new Set();
@@ -14821,6 +14348,8 @@ const FloatingCopyControls = ({ visible, code, onCopy, topOffset, isWeb }) => (j
14821
14348
  }, children: jsxRuntime.jsx(CopyButton, { value: code, onCopy: onCopy, iconOnly: true, size: "sm", tooltip: "Copy code", tooltipPosition: "left", style: { minHeight: 32, minWidth: 32 } }) }));
14822
14349
  const CodeBlock = (props) => {
14823
14350
  var _a, _b, _c;
14351
+ // Initialize syntax highlighter on first render (web only)
14352
+ React.useMemo(() => initSyntaxHighlighter(), []);
14824
14353
  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;
14825
14354
  const { spacingProps, otherProps } = extractSpacingProps(rest);
14826
14355
  const spacingStyles = getSpacingStyles(spacingProps);
@@ -14835,6 +14364,7 @@ const CodeBlock = (props) => {
14835
14364
  const [hovered, setHovered] = React.useState(false);
14836
14365
  const [codeHeight, setCodeHeight] = React.useState(null);
14837
14366
  const isWeb = reactNative.Platform.OS === 'web';
14367
+ const webWhitespaceStyle = React.useMemo(() => (isWeb ? { whiteSpace: wrap ? 'pre-wrap' : 'pre', display: 'block' } : null), [isWeb, wrap]);
14838
14368
  const showFloatingCopy = showCopyButton && !title && !fileName;
14839
14369
  const showCopyVisible = !isWeb ? showFloatingCopy : showFloatingCopy && hovered;
14840
14370
  const codeData = React.useMemo(() => {
@@ -14868,6 +14398,7 @@ const CodeBlock = (props) => {
14868
14398
  boxSizing: 'border-box',
14869
14399
  paddingLeft: showLineNumbers ? 0 : 12,
14870
14400
  paddingRight: showLineNumbers ? 0 : 12,
14401
+ whiteSpace: wrap ? 'pre-wrap' : 'pre',
14871
14402
  }), [showLineNumbers, wrap]);
14872
14403
  const highlightedLineStyle = React.useMemo(() => ({
14873
14404
  backgroundColor: highlightBackgroundColor,
@@ -14879,6 +14410,18 @@ const CodeBlock = (props) => {
14879
14410
  const tokenLines = React.useMemo(() => (highlight ? nativeHighlighter(codeData.transformed) : null), [highlight, nativeHighlighter, codeData.transformed]);
14880
14411
  const shouldVirtualizeNative = !isWeb && codeData.lineCount >= LONG_LIST_THRESHOLD;
14881
14412
  const lineHeight = (_c = styles.codeText.lineHeight) !== null && _c !== void 0 ? _c : 18;
14413
+ const normalizeTokenText = React.useCallback((text, tokenIndex) => {
14414
+ if (!isWeb || !text)
14415
+ return text;
14416
+ const replaceSpaces = (value) => value.replace(/\t/g, ' ').replace(/ /g, '\u00A0');
14417
+ if (tokenIndex === 0) {
14418
+ return text.replace(/^[\t ]+/, (match) => replaceSpaces(match));
14419
+ }
14420
+ if (text.trim().length === 0) {
14421
+ return replaceSpaces(text);
14422
+ }
14423
+ return text;
14424
+ }, [isWeb]);
14882
14425
  const buildNativeLine = React.useCallback((line, index, appendNewline, includeKey) => {
14883
14426
  var _a;
14884
14427
  const lineNumber = index + 1;
@@ -14887,13 +14430,14 @@ const CodeBlock = (props) => {
14887
14430
  const lineStyles = [
14888
14431
  styles.codeText,
14889
14432
  textStyle,
14433
+ webWhitespaceStyle,
14890
14434
  wrap ? { flexWrap: 'wrap' } : { flexWrap: 'nowrap', width: 'auto' },
14891
14435
  ];
14892
14436
  if (isLineHighlighted) {
14893
14437
  lineStyles.push(styles.highlightedLine(isDark, highlightColors));
14894
14438
  }
14895
- return (jsxRuntime.jsxs(Text, { selectable: true, style: lineStyles, children: [showLineNumbers ? (jsxRuntime.jsx(Text, { style: { color: lineNumberColor, opacity: 0.7 }, children: `${String(lineNumber).padStart(lineNumberWidth, ' ')} | ` })) : null, tokens.map((token, tokenIdx) => (jsxRuntime.jsx(Text, { style: { color: token.color }, children: token.text || ' ' }, `${lineNumber}-${tokenIdx}`))), appendNewline ? '\n' : null] }, includeKey ? `line-${lineNumber}` : undefined));
14896
- }, [fallbackColor, highlightColors, highlightSet, isDark, lineNumberColor, lineNumberWidth, showLineNumbers, styles.codeText, styles.highlightedLine, textStyle, tokenLines, wrap]);
14439
+ return (jsxRuntime.jsxs(Text, { selectable: true, style: lineStyles, children: [showLineNumbers ? (jsxRuntime.jsx(Text, { style: { color: lineNumberColor, opacity: 0.7 }, children: `${String(lineNumber).padStart(lineNumberWidth, ' ')} | ` })) : null, tokens.map((token, tokenIdx) => (jsxRuntime.jsx(Text, { style: { color: token.color }, children: normalizeTokenText(token.text || ' ', tokenIdx) }, `${lineNumber}-${tokenIdx}`))), appendNewline ? '\n' : null] }, includeKey ? `line-${lineNumber}` : undefined));
14440
+ }, [fallbackColor, highlightColors, highlightSet, isDark, lineNumberColor, lineNumberWidth, normalizeTokenText, showLineNumbers, styles.codeText, styles.highlightedLine, textStyle, tokenLines, webWhitespaceStyle, wrap]);
14897
14441
  const renderWebCode = React.useMemo(() => {
14898
14442
  if (!(isWeb && highlight && PrismSyntaxHighlighter)) {
14899
14443
  return null;
@@ -14907,7 +14451,13 @@ const CodeBlock = (props) => {
14907
14451
  lineHeight: '18px',
14908
14452
  display: 'block',
14909
14453
  width: '100%',
14910
- }, codeTagProps: { style: { fontFamily: styles.codeText.fontFamily } }, wrapLongLines: wrap, wrapLines: wrap, showLineNumbers: prismShowLineNumbers, lineNumberStyle: hideLineNumbersVisually
14454
+ whiteSpace: wrap ? 'pre-wrap' : 'pre',
14455
+ }, codeTagProps: {
14456
+ style: {
14457
+ fontFamily: styles.codeText.fontFamily,
14458
+ whiteSpace: wrap ? 'pre-wrap' : 'pre',
14459
+ },
14460
+ }, wrapLongLines: wrap, wrapLines: wrap, showLineNumbers: prismShowLineNumbers, lineNumberStyle: hideLineNumbersVisually
14911
14461
  ? { display: 'none' }
14912
14462
  : { opacity: 0.55, paddingRight: 12, userSelect: 'none' }, lineProps: (lineNumber) => {
14913
14463
  const style = { ...baseLineStyle };
@@ -14940,13 +14490,13 @@ const CodeBlock = (props) => {
14940
14490
  ]);
14941
14491
  const renderNativeCode = React.useMemo(() => {
14942
14492
  if (!codeData.lineCount) {
14943
- return (jsxRuntime.jsx(Text, { selectable: true, style: [styles.codeText, textStyle], children: ' ' }));
14493
+ return (jsxRuntime.jsx(Text, { selectable: true, style: [styles.codeText, textStyle, webWhitespaceStyle], children: ' ' }));
14944
14494
  }
14945
14495
  if (shouldVirtualizeNative) {
14946
14496
  return (jsxRuntime.jsx(reactNative.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 }) }));
14947
14497
  }
14948
- return (jsxRuntime.jsx(Text, { selectable: true, style: [styles.codeText, textStyle], children: codeData.lines.map((line, idx) => buildNativeLine(line, idx, idx < codeData.lineCount - 1, true)) }));
14949
- }, [buildNativeLine, codeData.lineCount, codeData.lines, lineHeight, shouldVirtualizeNative, styles.codeText, textStyle]);
14498
+ return (jsxRuntime.jsx(Text, { selectable: true, style: [styles.codeText, textStyle, webWhitespaceStyle], children: codeData.lines.map((line, idx) => buildNativeLine(line, idx, idx < codeData.lineCount - 1, true)) }));
14499
+ }, [buildNativeLine, codeData.lineCount, codeData.lines, lineHeight, shouldVirtualizeNative, styles.codeText, textStyle, webWhitespaceStyle]);
14950
14500
  const codeContent = renderWebCode !== null && renderWebCode !== void 0 ? renderWebCode : renderNativeCode;
14951
14501
  const scrollableCodeContent = wrap ? (codeContent) : (jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, bounces: false, showsHorizontalScrollIndicator: true, showsVerticalScrollIndicator: false, contentContainerStyle: { flexGrow: 1 }, style: { width: '100%' }, children: jsxRuntime.jsx(reactNative.View, { style: { flexGrow: 1 }, children: codeContent }) }));
14952
14502
  let wrappedCodeContent = scrollableCodeContent;
@@ -16551,11 +16101,13 @@ const BrandButton = (props) => {
16551
16101
  return {
16552
16102
  backgroundColor: 'transparent',
16553
16103
  borderColor: brandConfig.borderColor || brandConfig.backgroundColor,
16104
+ paddingHorizontal: 16,
16554
16105
  };
16555
16106
  case 'ghost':
16556
16107
  return {
16557
16108
  backgroundColor: 'transparent',
16558
16109
  borderColor: 'transparent',
16110
+ paddingHorizontal: 16,
16559
16111
  };
16560
16112
  case 'link':
16561
16113
  return { backgroundColor: 'transparent', borderColor: 'transparent' };
@@ -16563,7 +16115,7 @@ const BrandButton = (props) => {
16563
16115
  return {
16564
16116
  backgroundColor: 'white',
16565
16117
  borderColor: 'transparent',
16566
- paddingHorizontal: 0,
16118
+ paddingHorizontal: 16,
16567
16119
  minWidth: 0,
16568
16120
  height: 'auto',
16569
16121
  color: 'black'
@@ -16572,6 +16124,7 @@ const BrandButton = (props) => {
16572
16124
  return {
16573
16125
  backgroundColor: brandConfig.backgroundColor,
16574
16126
  borderColor: brandConfig.borderColor || brandConfig.backgroundColor,
16127
+ paddingHorizontal: 16,
16575
16128
  };
16576
16129
  }
16577
16130
  })();
@@ -17148,8 +16701,12 @@ const createInputStyles = (theme, isRTL = false) => {
17148
16701
  // Remove any web-specific styling that could interfere
17149
16702
  ...(typeof window !== 'undefined' && {
17150
16703
  outlineWidth: 0,
16704
+ outlineStyle: 'none',
17151
16705
  border: 'none',
16706
+ borderWidth: 0,
16707
+ boxShadow: 'none',
17152
16708
  backgroundColor: 'transparent',
16709
+ boxSizing: 'border-box',
17153
16710
  }),
17154
16711
  },
17155
16712
  inputContainer: {
@@ -17277,6 +16834,7 @@ const TextInputBase = factory((props, ref) => {
17277
16834
  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;
17278
16835
  const renderDisclaimer = useDisclaimer(disclaimerData.disclaimer, disclaimerData.disclaimerProps);
17279
16836
  const [focused, setFocused] = React.useState(false);
16837
+ const [cursorVisible, setCursorVisible] = React.useState(true);
17280
16838
  const theme = useTheme();
17281
16839
  const { isRTL } = useDirection();
17282
16840
  const internalInputRef = React.useRef(null);
@@ -17348,6 +16906,16 @@ const TextInputBase = factory((props, ref) => {
17348
16906
  return '';
17349
16907
  return '•'.repeat(length);
17350
16908
  }, [isSecureEntry, normalizedValue]);
16909
+ // Blinking cursor for secure entry (simple interval toggle)
16910
+ React.useEffect(() => {
16911
+ if (focused && isSecureEntry) {
16912
+ setCursorVisible(true);
16913
+ const interval = setInterval(() => {
16914
+ setCursorVisible(v => !v);
16915
+ }, 530);
16916
+ return () => clearInterval(interval);
16917
+ }
16918
+ }, [focused, isSecureEntry]);
17351
16919
  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);
17352
16920
  const resolvedInputStyle = React.useMemo(() => {
17353
16921
  const base = [styles.input];
@@ -17449,7 +17017,12 @@ const TextInputBase = factory((props, ref) => {
17449
17017
  }
17450
17018
  }, [keyboardManager, pendingFocusTarget, focusTargetId]);
17451
17019
  const disclaimerNode = renderDisclaimer();
17452
- return (jsxRuntime.jsxs(reactNative.View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsxRuntime.jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxRuntime.jsxs(reactNative.View, { style: styles.inputContainer, children: [startSection && (jsxRuntime.jsx(reactNative.View, { style: styles.startSection, children: startSection })), jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsxRuntime.jsx(reactNative.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 && (jsxRuntime.jsx(reactNative.Text, { pointerEvents: "none", accessible: false, style: overlayStyle, numberOfLines: 1, ellipsizeMode: "clip", children: maskedValue }))] }), (showClearButton || endSection) && (jsxRuntime.jsxs(reactNative.View, { style: styles.endSection, children: [showClearButton && (jsxRuntime.jsx(ClearButton, { onPress: handleClear, size: size, accessibilityLabel: clearButtonLabelText, hasRightSection: !!endSection })), endSection] }))] }), disclaimerNode, error && (jsxRuntime.jsx(reactNative.Text, { style: styles.error, role: "alert", accessibilityLiveRegion: "polite", children: error })), helperText && !error && (jsxRuntime.jsx(reactNative.Text, { style: styles.helperText, children: helperText }))] }));
17020
+ return (jsxRuntime.jsxs(reactNative.View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsxRuntime.jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxRuntime.jsxs(reactNative.View, { style: styles.inputContainer, children: [startSection && (jsxRuntime.jsx(reactNative.View, { style: styles.startSection, children: startSection })), jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsxRuntime.jsx(reactNative.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 && (jsxRuntime.jsxs(reactNative.View, { pointerEvents: "none", style: [overlayStyle, { flexDirection: 'row', alignItems: 'center' }], children: [jsxRuntime.jsx(reactNative.Text, { accessible: false, style: { color: textColor, fontSize: styles.input.fontSize, fontFamily: theme.fontFamily }, numberOfLines: 1, children: maskedValue }), focused && cursorVisible && (jsxRuntime.jsx(reactNative.View, { style: {
17021
+ width: 1,
17022
+ height: styles.input.fontSize || 16,
17023
+ backgroundColor: textColor,
17024
+ marginLeft: 1,
17025
+ } }))] }))] }), (showClearButton || endSection) && (jsxRuntime.jsxs(reactNative.View, { style: styles.endSection, children: [showClearButton && (jsxRuntime.jsx(ClearButton, { onPress: handleClear, size: size, accessibilityLabel: clearButtonLabelText, hasRightSection: !!endSection })), endSection] }))] }), disclaimerNode, error && (jsxRuntime.jsx(reactNative.Text, { style: styles.error, role: "alert", accessibilityLiveRegion: "polite", children: error })), helperText && !error && (jsxRuntime.jsx(reactNative.Text, { style: styles.helperText, children: helperText }))] }));
17453
17026
  });
17454
17027
 
17455
17028
  const getInputTypeConfig = (type) => {
@@ -18007,18 +17580,19 @@ const useTextAreaStyles = (props) => {
18007
17580
  ? theme.colors.error[5]
18008
17581
  : styleProps.focused
18009
17582
  ? theme.colors.primary[5]
18010
- : styleProps.disabled
18011
- ? theme.backgrounds.border
18012
- : 'transparent',
17583
+ : theme.backgrounds.border,
18013
17584
  borderRadius: DESIGN_TOKENS.radius.lg,
18014
- borderWidth: DESIGN_TOKENS.radius.xs,
17585
+ borderWidth: 2,
18015
17586
  paddingHorizontal: DESIGN_TOKENS.spacing.sm,
18016
17587
  paddingVertical: DESIGN_TOKENS.spacing.xs,
17588
+ // Match Input focus treatment on web
18017
17589
  ...(styleProps.focused && !styleProps.disabled && reactNative.Platform.OS === 'web' && {
18018
17590
  boxShadow: `0 0 0 2px ${((_a = theme.states) === null || _a === void 0 ? void 0 : _a.focusRing) || theme.colors.primary[2]}`,
18019
17591
  }),
17592
+ // Light elevation similar to Input
18020
17593
  ...(!styleProps.disabled && theme.colorScheme === 'light' && {
18021
17594
  elevation: 1,
17595
+ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
18022
17596
  }),
18023
17597
  opacity: styleProps.disabled ? DESIGN_TOKENS.opacity.disabled : 1,
18024
17598
  },
@@ -18060,7 +17634,7 @@ const TextArea = factory((props, ref) => {
18060
17634
  const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
18061
17635
  const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
18062
17636
  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;
18063
- const { height } = layoutProps;
17637
+ const { h } = layoutProps;
18064
17638
  const theme = useTheme();
18065
17639
  const { getTextAreaStyles } = useTextAreaStyles({ theme });
18066
17640
  const [focused, setFocused] = React.useState(false);
@@ -18124,11 +17698,11 @@ const TextArea = factory((props, ref) => {
18124
17698
  const inputContainerStyles = [
18125
17699
  styles.inputContainer,
18126
17700
  radiusStyles,
18127
- { height }
17701
+ { height: h }
18128
17702
  ];
18129
17703
  const textInputStyles = [
18130
17704
  styles.textInput,
18131
- { height: height || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
17705
+ { height: h || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
18132
17706
  textAlignVertical: resize === 'none' ? 'top' : undefined,
18133
17707
  // Disable resizing by user if resize is 'none'
18134
17708
  ...(resize === 'none' ? { resizeMode: 'none' } : {})
@@ -18156,7 +17730,7 @@ const TextArea = factory((props, ref) => {
18156
17730
  const clearLabel = clearButtonLabel || 'Clear input';
18157
17731
  return (jsxRuntime.jsxs(reactNative.View, { style: containerStyles, testID: testID, children: [(label || description) && (jsxRuntime.jsx(FieldHeader, { label: label, description: description, required: required, disabled: disabled, error: !!error })), jsxRuntime.jsxs(reactNative.View, { style: [inputContainerStyles, { position: 'relative' }], children: [jsxRuntime.jsx(reactNative.TextInput, { ref: assignRef,
18158
17732
  // style={]}
18159
- style: { height: height || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
17733
+ style: { height: h || (autoResize ? currentRows * 24 : rows * 24), // Approximate row height
18160
17734
  ...textInputStyles.reduce((acc, style) => ({ ...acc, ...style }), {}),
18161
17735
  textAlignVertical: resize === 'none' ? 'top' : undefined,
18162
17736
  // Disable resizing by user if resize is 'none'
@@ -19700,7 +19274,7 @@ const useSwitchStyles = (props) => {
19700
19274
  ...(reactNative.Platform.OS === 'web' && { userSelect: 'none' }),
19701
19275
  },
19702
19276
  labelContainer: {
19703
- flex: 1,
19277
+ flexShrink: 1,
19704
19278
  justifyContent: 'center',
19705
19279
  },
19706
19280
  labelDisabled: {
@@ -19869,8 +19443,8 @@ const Switch = factory((rawProps, ref) => {
19869
19443
  const LayoutComponent = isVertical ? Column : Row;
19870
19444
  // For vertical layouts (top/bottom), we want tighter spacing and center alignment
19871
19445
  const layoutProps = isVertical
19872
- ? { gap: 'xs', style: { alignItems: 'center' } }
19873
- : { gap: 'sm', style: { alignItems: 'center' } };
19446
+ ? { gap: 'xs', align: 'center' }
19447
+ : { gap: 'sm', align: 'center' };
19874
19448
  const disclaimerNode = renderDisclaimer();
19875
19449
  return (jsxRuntime.jsxs(reactNative.View, { style: spacingStyles, children: [jsxRuntime.jsxs(LayoutComponent, { ...layoutProps, children: [labelPosition === 'top' && labelElement, labelPosition === 'left' && labelElement, switchElement, labelPosition === 'right' && labelElement, labelPosition === 'bottom' && labelElement] }), disclaimerNode ? (jsxRuntime.jsx(reactNative.View, { style: { width: '100%' }, children: disclaimerNode })) : null] }));
19876
19450
  });
@@ -24482,7 +24056,7 @@ const Select = factory((allProps, ref) => {
24482
24056
  var _a;
24483
24057
  const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(allProps);
24484
24058
  const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
24485
- 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;
24059
+ 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;
24486
24060
  const theme = useTheme();
24487
24061
  const { shouldUseModal, shouldUseOverlay } = useOverlayMode();
24488
24062
  const menuStyles = useMenuStyles();
@@ -24504,6 +24078,7 @@ const Select = factory((allProps, ref) => {
24504
24078
  keyboardAvoidance,
24505
24079
  closeOnClickOutside: true,
24506
24080
  closeOnEscape: true,
24081
+ matchAnchorWidth: true,
24507
24082
  onClose: () => setOpen(false),
24508
24083
  });
24509
24084
  const hasMeasuredDropdownRef = React.useRef(false);
@@ -24637,11 +24212,11 @@ const Select = factory((allProps, ref) => {
24637
24212
  }, [position === null || position === void 0 ? void 0 : position.finalWidth, triggerWidth]);
24638
24213
  const resolvedDropdownMaxHeight = React.useMemo(() => {
24639
24214
  const keyboardMax = typeof (position === null || position === void 0 ? void 0 : position.maxHeight) === 'number' ? position.maxHeight : undefined;
24640
- if (typeof maxHeight === 'number') {
24641
- return keyboardMax ? Math.min(maxHeight, keyboardMax) : maxHeight;
24215
+ if (typeof maxH === 'number') {
24216
+ return keyboardMax ? Math.min(maxH, keyboardMax) : maxH;
24642
24217
  }
24643
- return keyboardMax !== null && keyboardMax !== void 0 ? keyboardMax : maxHeight;
24644
- }, [maxHeight, position === null || position === void 0 ? void 0 : position.maxHeight]);
24218
+ return keyboardMax !== null && keyboardMax !== void 0 ? keyboardMax : maxH;
24219
+ }, [maxH, position === null || position === void 0 ? void 0 : position.maxHeight]);
24645
24220
  const handleSelect = React.useCallback((opt) => {
24646
24221
  if (opt.disabled)
24647
24222
  return;
@@ -24663,7 +24238,7 @@ const Select = factory((allProps, ref) => {
24663
24238
  close();
24664
24239
  }
24665
24240
  }, [closeOnSelect, close, onChange, valueProp, refocusAfterSelect, keyboardManager, focusTrigger, blurTrigger]);
24666
- const listMaxHeight = resolvedDropdownMaxHeight !== null && resolvedDropdownMaxHeight !== void 0 ? resolvedDropdownMaxHeight : maxHeight;
24241
+ const listMaxHeight = resolvedDropdownMaxHeight !== null && resolvedDropdownMaxHeight !== void 0 ? resolvedDropdownMaxHeight : maxH;
24667
24242
  const menu = React.useMemo(() => {
24668
24243
  const widthStyle = resolvedDropdownWidth && resolvedDropdownWidth > 0
24669
24244
  ? { width: resolvedDropdownWidth, minWidth: resolvedDropdownWidth }
@@ -24676,18 +24251,17 @@ const Select = factory((allProps, ref) => {
24676
24251
  ...(maxHeightStyle !== null && maxHeightStyle !== void 0 ? maxHeightStyle : {}),
24677
24252
  ...(widthStyle !== null && widthStyle !== void 0 ? widthStyle : {}),
24678
24253
  }, children: jsxRuntime.jsx(reactNative.FlatList, { data: options, keyExtractor: o => String(o.value), renderItem: ({ item }) => {
24679
- var _a;
24680
24254
  const selected = item.value === value;
24681
24255
  if (renderOption) {
24682
24256
  return jsxRuntime.jsx(reactNative.View, { children: renderOption(item, false, selected) });
24683
24257
  }
24684
24258
  const primaryPalette = theme.colors.primary || [];
24685
24259
  const highlightColor = theme.colorScheme === 'dark'
24686
- ? primaryPalette[2] || primaryPalette[3] || theme.text.onPrimary || theme.text.primary
24687
- : primaryPalette[6] || primaryPalette[5] || ((_a = theme.colors.secondary) === null || _a === void 0 ? void 0 : _a[6]) || '#6941C6';
24260
+ ? primaryPalette[5] || primaryPalette[4] || '#60A5FA'
24261
+ : primaryPalette[6] || primaryPalette[5] || '#3B82F6';
24688
24262
  const baseTextColor = item.disabled ? theme.text.disabled : theme.text.primary;
24689
- const accentTextColor = item.disabled ? theme.text.disabled : highlightColor;
24690
- return (jsxRuntime.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 }));
24263
+ item.disabled ? theme.text.disabled : highlightColor;
24264
+ return (jsxRuntime.jsx(MenuItemButton, { onPress: () => handleSelect(item), disabled: !!item.disabled, active: false, tone: "default", hoverTone: "default", activeTone: "default", textColor: baseTextColor, hoverTextColor: baseTextColor, activeTextColor: baseTextColor, startIcon: selected ? jsxRuntime.jsx(Icon, { name: "check", size: 16, color: highlightColor }) : jsxRuntime.jsx(reactNative.View, { style: { width: 16 } }), compact: true, rounded: false, style: { borderRadius: 0 }, children: item.label }));
24691
24265
  }, ItemSeparatorComponent: renderOption ? undefined : ListGroupDivider, style: maxHeightStyle, bounces: false }) }) }));
24692
24266
  }, [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]);
24693
24267
  React.useEffect(() => {
@@ -24869,6 +24443,7 @@ const AutoComplete = factory((props, ref) => {
24869
24443
  offset,
24870
24444
  autoUpdate: autoReposition,
24871
24445
  fallbackPlacements,
24446
+ matchAnchorWidth: true,
24872
24447
  });
24873
24448
  // Guard: remember last popover size to avoid re-triggering updatePosition on position-only changes
24874
24449
  const lastPopoverSizeRef = React.useRef(null);
@@ -24892,13 +24467,12 @@ const AutoComplete = factory((props, ref) => {
24892
24467
  }, radiusStyles), [inputStyleFactory, size, focused, error, disabled, showClearButton, radiusStyles]);
24893
24468
  const clearLabel = clearButtonLabel || 'Clear input';
24894
24469
  const menuHighlightColor = React.useMemo(() => {
24895
- var _a;
24896
24470
  const primaryPalette = theme.colors.primary || [];
24897
24471
  if (theme.colorScheme === 'dark') {
24898
- return primaryPalette[2] || primaryPalette[3] || theme.text.onPrimary || theme.text.primary;
24472
+ return primaryPalette[5] || primaryPalette[4] || '#60A5FA';
24899
24473
  }
24900
- return primaryPalette[6] || primaryPalette[5] || ((_a = theme.colors.secondary) === null || _a === void 0 ? void 0 : _a[6]) || '#6941C6';
24901
- }, [theme.colors.primary, theme.colors.secondary, theme.colorScheme, theme.text.onPrimary, theme.text.primary]);
24474
+ return primaryPalette[6] || primaryPalette[5] || '#3B82F6';
24475
+ }, [theme.colors.primary, theme.colorScheme]);
24902
24476
  const selectedCount = (_a = selectedValues === null || selectedValues === void 0 ? void 0 : selectedValues.length) !== null && _a !== void 0 ? _a : 0;
24903
24477
  const hasSelectedValues = multiSelect && selectedCount > 0;
24904
24478
  const currentQueryRef = React.useRef(query);
@@ -25216,8 +24790,8 @@ const AutoComplete = factory((props, ref) => {
25216
24790
  const defaultRenderItem = React.useCallback((item, index, isSelected = false) => {
25217
24791
  const highlightQuery = highlightMatches ? currentQueryRef.current : undefined;
25218
24792
  const baseTextColor = item.disabled ? theme.text.disabled : theme.text.primary;
25219
- const accentTextColor = item.disabled ? theme.text.disabled : menuHighlightColor;
25220
- return (jsxRuntime.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], ...(reactNative.Platform.OS === 'web' ? {
24793
+ item.disabled ? theme.text.disabled : menuHighlightColor;
24794
+ return (jsxRuntime.jsx(MenuItemButton, { onPress: () => handleSelectSuggestion(item), disabled: item.disabled, active: false, tone: "default", hoverTone: "default", activeTone: "default", textColor: baseTextColor, hoverTextColor: baseTextColor, activeTextColor: baseTextColor, startIcon: isSelected ? jsxRuntime.jsx(Icon, { name: "check", size: 16, color: menuHighlightColor }) : jsxRuntime.jsx(reactNative.View, { style: { width: 16 } }), compact: true, rounded: false, style: [styles.menuItemButton, suggestionItemStyle], ...(reactNative.Platform.OS === 'web' ? {
25221
24795
  onMouseDown: (event) => {
25222
24796
  if (event === null || event === void 0 ? void 0 : event.preventDefault) {
25223
24797
  event.preventDefault();
@@ -27484,7 +27058,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
27484
27058
  }
27485
27059
  onChange === null || onChange === void 0 ? void 0 : onChange(date);
27486
27060
  }, [isControlled, maxDate, minDate, onChange]);
27487
- return (jsxRuntime.jsxs(reactNative.View, { children: [jsxRuntime.jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsxRuntime.jsx(reactNative.Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
27061
+ return (jsxRuntime.jsxs(reactNative.View, { style: { alignSelf: 'flex-start' }, children: [jsxRuntime.jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsxRuntime.jsx(reactNative.Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
27488
27062
  {
27489
27063
  padding: 8,
27490
27064
  borderRadius: 6,
@@ -27496,7 +27070,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
27496
27070
  borderRadius: 6,
27497
27071
  backgroundColor: pressed ? theme.colors.gray[2] : 'transparent',
27498
27072
  },
27499
- ], ...nextControlProps, children: jsxRuntime.jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: jsxRuntime.jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
27073
+ ], ...nextControlProps, children: jsxRuntime.jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: { flexGrow: 0 }, style: { flexGrow: 0 }, children: jsxRuntime.jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
27500
27074
  const isSelected = selectedDate ? dateUtils$1.isSameDay(date, selectedDate) : false;
27501
27075
  const isToday = dateUtils$1.isToday(date);
27502
27076
  const isWeekend = dateUtils$1.isWeekend(date);
@@ -27726,7 +27300,7 @@ const DatePickerInput = React.forwardRef(function DatePickerInputInner({ value,
27726
27300
  } }));
27727
27301
  }
27728
27302
  if (dropdownType === 'modal') {
27729
- return (jsxRuntime.jsxs(reactNative.View, { ref: ref, children: [renderInput(), jsxRuntime.jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, width: numberOfMonths > 1 ? Math.min(700, 380 * numberOfMonths + 40) : 400, title: type === 'range'
27303
+ return (jsxRuntime.jsxs(reactNative.View, { ref: ref, children: [renderInput(), jsxRuntime.jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, w: numberOfMonths > 1 ? Math.min(700, 380 * numberOfMonths + 40) : 400, title: type === 'range'
27730
27304
  ? 'Select Date Range'
27731
27305
  : type === 'multiple'
27732
27306
  ? 'Select Dates'
@@ -27755,7 +27329,7 @@ const DatePickerInput = React.forwardRef(function DatePickerInputInner({ value,
27755
27329
  backgroundColor: pressed ? theme.colors.primary[6] : theme.colors.primary[5],
27756
27330
  }), children: jsxRuntime.jsx(Text, { size: "sm", weight: "semibold", style: { color: 'white' }, children: "Done" }) })] })] }) }))] }) })] }));
27757
27331
  }
27758
- return (jsxRuntime.jsxs(reactNative.View, { ref: ref, children: [renderInput(), jsxRuntime.jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, width: numberOfMonths > 1 ? Math.min(600, 320 * numberOfMonths + 40) : 350, children: jsxRuntime.jsxs(reactNative.View, { ref: focusTrapRef, style: { padding: DESIGN_TOKENS.spacing.lg }, accessible: true, accessibilityLabel: type === 'range'
27332
+ return (jsxRuntime.jsxs(reactNative.View, { ref: ref, children: [renderInput(), jsxRuntime.jsx(Dialog, { visible: isOpen, variant: "modal", onClose: handleClose, w: numberOfMonths > 1 ? Math.min(600, 320 * numberOfMonths + 40) : 350, children: jsxRuntime.jsxs(reactNative.View, { ref: focusTrapRef, style: { padding: DESIGN_TOKENS.spacing.lg }, accessible: true, accessibilityLabel: type === 'range'
27759
27333
  ? 'Date range picker dialog'
27760
27334
  : type === 'multiple'
27761
27335
  ? 'Multiple date picker dialog'
@@ -27850,7 +27424,7 @@ const MonthPickerInput = React.forwardRef(function MonthPickerInput({ value, def
27850
27424
  pointerEvents: 'none',
27851
27425
  accessible: false,
27852
27426
  focusable: false,
27853
- } }) }), jsxRuntime.jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, width: 360, children: jsxRuntime.jsx(reactNative.View, { style: {
27427
+ } }) }), jsxRuntime.jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, w: 360, children: jsxRuntime.jsx(reactNative.View, { style: {
27854
27428
  padding: DESIGN_TOKENS.spacing.lg,
27855
27429
  }, children: jsxRuntime.jsx(MonthPicker, { ...restMonthPickerProps, value: currentValue, onChange: handleMonthChange, locale: resolvedLocale, size: resolvedSize }) }) })] }));
27856
27430
  });
@@ -27913,7 +27487,7 @@ const YearPickerInput = React.forwardRef(function YearPickerInput({ value, defau
27913
27487
  pointerEvents: 'none',
27914
27488
  accessible: false,
27915
27489
  focusable: false,
27916
- } }) }), jsxRuntime.jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, width: 360, children: jsxRuntime.jsx(reactNative.View, { style: {
27490
+ } }) }), jsxRuntime.jsx(Dialog, { visible: opened, variant: "modal", onClose: handleClose, title: modalTitle, w: 360, children: jsxRuntime.jsx(reactNative.View, { style: {
27917
27491
  padding: DESIGN_TOKENS.spacing.lg,
27918
27492
  }, children: jsxRuntime.jsx(YearPicker, { ...restYearPickerProps, value: currentValue, onChange: handleYearChange, size: resolvedSize }) }) })] }));
27919
27493
  });
@@ -28078,7 +27652,7 @@ const TimePickerInput = ({ value, defaultValue, onChange, format = 24, withSecon
28078
27652
  }
28079
27653
  }, label: label, placeholder: is12h ? 'hh:mm AM' : 'hh:mm', endSection: jsxRuntime.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 }) }), jsxRuntime.jsx(Dialog, { visible: open,
28080
27654
  // variant="fullscreen"
28081
- onClose: handleClose, width: typeof computedPanelWidth === 'number' ? computedPanelWidth : 360, title: title || 'Select Time', children: jsxRuntime.jsxs(reactNative.Pressable, { style: {
27655
+ onClose: handleClose, w: typeof computedPanelWidth === 'number' ? computedPanelWidth : 360, title: title || 'Select Time', children: jsxRuntime.jsxs(reactNative.Pressable, { style: {
28082
27656
  flex: 1,
28083
27657
  width: '100%',
28084
27658
  justifyContent: 'center',
@@ -29030,303 +28604,6 @@ const EmojiPicker = factory((props, ref) => {
29030
28604
  });
29031
28605
  EmojiPicker.displayName = 'EmojiPicker';
29032
28606
 
29033
- function useRichTextEditorStyles() {
29034
- const theme = useTheme();
29035
- return React.useMemo(() => reactNative.StyleSheet.create({
29036
- characterCount: {
29037
- fontSize: 12,
29038
- marginTop: 4,
29039
- textAlign: 'right',
29040
- },
29041
- container: {
29042
- width: '100%',
29043
- },
29044
- disabled: {
29045
- opacity: 0.5,
29046
- },
29047
- editorContainer: {
29048
- backgroundColor: theme.backgrounds.surface,
29049
- borderColor: theme.backgrounds.border,
29050
- borderRadius: parseInt(theme.radii.md, 10),
29051
- borderWidth: 1,
29052
- overflow: 'hidden',
29053
- },
29054
- errorText: {
29055
- fontSize: 12,
29056
- marginTop: 4,
29057
- },
29058
- helperText: {
29059
- fontSize: 12,
29060
- marginTop: 4,
29061
- },
29062
- textInput: {
29063
- fontSize: 16,
29064
- lineHeight: 24,
29065
- padding: parseInt(theme.spacing.md, 10),
29066
- },
29067
- toolButton: {
29068
- alignItems: 'center',
29069
- backgroundColor: 'transparent',
29070
- borderColor: theme.backgrounds.border,
29071
- borderRadius: parseInt(theme.radii.sm, 10),
29072
- borderWidth: 1,
29073
- height: 32,
29074
- justifyContent: 'center',
29075
- width: 32,
29076
- },
29077
- toolSeparator: {
29078
- backgroundColor: theme.backgrounds.border,
29079
- height: 24,
29080
- marginHorizontal: 4,
29081
- width: 1,
29082
- },
29083
- toolbar: {
29084
- backgroundColor: theme.backgrounds.elevated,
29085
- borderBottomColor: theme.backgrounds.border,
29086
- borderBottomWidth: 1,
29087
- },
29088
- toolbarContent: {
29089
- alignItems: 'center',
29090
- flexDirection: 'row',
29091
- gap: 4,
29092
- paddingHorizontal: parseInt(theme.spacing.sm, 10),
29093
- paddingVertical: parseInt(theme.spacing.xs, 10),
29094
- },
29095
- }), [theme]);
29096
- }
29097
-
29098
- // Default toolbar configuration
29099
- const DEFAULT_TOOLBAR_TOOLS = [
29100
- 'bold',
29101
- 'italic',
29102
- 'underline',
29103
- 'separator',
29104
- 'heading',
29105
- 'separator',
29106
- 'align',
29107
- 'separator',
29108
- 'list',
29109
- 'separator',
29110
- 'link',
29111
- 'separator',
29112
- 'color',
29113
- ];
29114
- const RichTextEditor = React.memo(({ defaultValue, value, onChange, onSelectionChange, onFocus, onBlur, placeholder = 'Start typing...', readOnly = false, disabled = false, toolbar = {
29115
- enabled: true,
29116
- position: 'top',
29117
- tools: DEFAULT_TOOLBAR_TOOLS,
29118
- }, formats = {
29119
- fontFamilies: ['Arial', 'Georgia', 'Times New Roman', 'Courier New'],
29120
- fontSizes: [12, 14, 16, 18, 20, 24, 28, 32],
29121
- colors: ['#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FF0000', '#00FF00', '#0000FF'],
29122
- headings: [1, 2, 3, 4, 5, 6],
29123
- }, 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 }) => {
29124
- const theme = useTheme();
29125
- const styles = useRichTextEditorStyles();
29126
- const [content, setContent] = React.useState(value || defaultValue || { html: '', text: '' });
29127
- const [selection, setSelection] = React.useState({
29128
- index: 0,
29129
- length: 0,
29130
- });
29131
- const [activeFormats, setActiveFormats] = React.useState({});
29132
- const [isFocused, setIsFocused] = React.useState(false);
29133
- const editorRef = React.useRef(null);
29134
- const autosaveTimerRef = React.useRef(null);
29135
- // Update content when value prop changes
29136
- React.useEffect(() => {
29137
- if (value && value !== content) {
29138
- setContent(value);
29139
- }
29140
- }, [value]);
29141
- // Autosave functionality
29142
- React.useEffect(() => {
29143
- if ((autosave === null || autosave === void 0 ? void 0 : autosave.enabled) && autosave.onSave) {
29144
- if (autosaveTimerRef.current) {
29145
- clearTimeout(autosaveTimerRef.current);
29146
- }
29147
- autosaveTimerRef.current = setTimeout(() => {
29148
- autosave.onSave(content);
29149
- }, autosave.interval || 5000);
29150
- return () => {
29151
- if (autosaveTimerRef.current) {
29152
- clearTimeout(autosaveTimerRef.current);
29153
- }
29154
- };
29155
- }
29156
- }, [content, autosave]);
29157
- const handleContentChange = React.useCallback((text) => {
29158
- const newContent = {
29159
- text,
29160
- html: text, // For now, treating as plain text
29161
- };
29162
- setContent(newContent);
29163
- onChange === null || onChange === void 0 ? void 0 : onChange(newContent);
29164
- }, [onChange]);
29165
- const handleSelectionChange = React.useCallback((selection) => {
29166
- const newSelection = {
29167
- index: selection.start,
29168
- length: selection.end - selection.start,
29169
- format: activeFormats,
29170
- };
29171
- setSelection(newSelection);
29172
- onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(newSelection);
29173
- }, [activeFormats, onSelectionChange]);
29174
- const handleFocus = React.useCallback(() => {
29175
- setIsFocused(true);
29176
- onFocus === null || onFocus === void 0 ? void 0 : onFocus();
29177
- }, [onFocus]);
29178
- const handleBlur = React.useCallback(() => {
29179
- setIsFocused(false);
29180
- onBlur === null || onBlur === void 0 ? void 0 : onBlur();
29181
- }, [onBlur]);
29182
- const applyFormat = React.useCallback((format) => {
29183
- if (readOnly || disabled)
29184
- return;
29185
- const newFormats = { ...activeFormats, ...format };
29186
- setActiveFormats(newFormats);
29187
- // In a real implementation, this would apply formatting to the selected text
29188
- // For this demo, we'll just track the format state
29189
- }, [activeFormats, readOnly, disabled]);
29190
- const toggleFormat = React.useCallback((formatKey) => {
29191
- if (readOnly || disabled)
29192
- return;
29193
- const currentValue = activeFormats[formatKey];
29194
- applyFormat({ [formatKey]: !currentValue });
29195
- }, [activeFormats, applyFormat, readOnly, disabled]);
29196
- const insertText = React.useCallback((text) => {
29197
- if (readOnly || disabled)
29198
- return;
29199
- const currentText = content.text;
29200
- const { index } = selection;
29201
- const newText = currentText.slice(0, index) + text + currentText.slice(index);
29202
- handleContentChange(newText);
29203
- }, [content.text, selection, handleContentChange, readOnly, disabled]);
29204
- const insertLink = React.useCallback(() => {
29205
- if (!(links === null || links === void 0 ? void 0 : links.enabled) || readOnly || disabled)
29206
- return;
29207
- // In a real implementation, this would show a link dialog
29208
- const url = prompt('Enter URL:');
29209
- if (url && (!links.validate || links.validate(url))) {
29210
- applyFormat({ link: url });
29211
- }
29212
- }, [links, applyFormat, readOnly, disabled]);
29213
- React.useCallback(async () => {
29214
- if (!(images === null || images === void 0 ? void 0 : images.enabled) || readOnly || disabled)
29215
- return;
29216
- // In a real implementation, this would show a file picker
29217
- // For now, we'll just insert a placeholder
29218
- insertText('[Image]');
29219
- }, [images, insertText, readOnly, disabled]);
29220
- React.useCallback((level) => {
29221
- applyFormat({ heading: level });
29222
- }, [applyFormat]);
29223
- const setAlignment = React.useCallback((align) => {
29224
- applyFormat({ align });
29225
- }, [applyFormat]);
29226
- const setList = React.useCallback((listType) => {
29227
- applyFormat({ list: listType });
29228
- }, [applyFormat]);
29229
- const getToolButtonStyle = React.useCallback((isActive) => [
29230
- styles.toolButton,
29231
- {
29232
- backgroundColor: isActive
29233
- ? (theme.colorScheme === 'dark' ? theme.colors.primary[7] : theme.colors.primary[1])
29234
- : 'transparent',
29235
- borderColor: isActive ? theme.colors.primary[4] : theme.backgrounds.border,
29236
- },
29237
- (disabled || readOnly) && styles.disabled,
29238
- ], [styles.toolButton, theme, disabled, readOnly]);
29239
- const renderToolButton = React.useCallback((tool, icon, onPress, isActive = false) => (jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onPress, disabled: disabled || readOnly, style: getToolButtonStyle(isActive), children: jsxRuntime.jsx(Icon, { name: icon, size: 16, color: isActive ? theme.colors.primary[5] : theme.text.secondary }) }, tool)), [theme, disabled, readOnly, getToolButtonStyle]);
29240
- const renderToolSeparator = React.useCallback((index) => (jsxRuntime.jsx(reactNative.View, { style: styles.toolSeparator }, `separator-${index}`)), [styles.toolSeparator]);
29241
- const renderToolbar = React.useCallback(() => {
29242
- if (!(toolbar === null || toolbar === void 0 ? void 0 : toolbar.enabled))
29243
- return null;
29244
- const tools = toolbar.tools || DEFAULT_TOOLBAR_TOOLS;
29245
- return (jsxRuntime.jsx(reactNative.View, { style: styles.toolbar, children: jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: styles.toolbarContent, children: tools.map((tool, index) => {
29246
- if (tool === 'separator') {
29247
- return renderToolSeparator(index);
29248
- }
29249
- switch (tool) {
29250
- case 'bold':
29251
- return renderToolButton('bold', 'bold', () => toggleFormat('bold'), !!activeFormats.bold);
29252
- case 'italic':
29253
- return renderToolButton('italic', 'italic', () => toggleFormat('italic'), !!activeFormats.italic);
29254
- case 'underline':
29255
- return renderToolButton('underline', 'underline', () => toggleFormat('underline'), !!activeFormats.underline);
29256
- case 'strikethrough':
29257
- return renderToolButton('strikethrough', 'strikethrough', () => toggleFormat('strikethrough'), !!activeFormats.strikethrough);
29258
- case 'heading':
29259
- return renderToolButton('heading', 'heading', () => applyFormat({ heading: activeFormats.heading ? null : 2 }), !!activeFormats.heading);
29260
- case 'align':
29261
- return renderToolButton('align', 'alignLeft', // Default to left align icon, could be dynamic based on current align
29262
- () => setAlignment(activeFormats.align === 'left' ? 'center' : 'left'), !!activeFormats.align);
29263
- case 'list':
29264
- return renderToolButton('list', 'listUnordered', // Default to unordered list icon, could be dynamic
29265
- () => setList(activeFormats.list === 'unordered' ? 'ordered' : 'unordered'), !!activeFormats.list);
29266
- case 'link':
29267
- return renderToolButton('link', 'link', insertLink, !!activeFormats.link);
29268
- case 'image':
29269
- return renderToolButton('image', 'image', () => { }, // TODO: Implement image insertion
29270
- false);
29271
- case 'code':
29272
- return renderToolButton('code', 'code', () => toggleFormat('code'), !!activeFormats.code);
29273
- case 'quote':
29274
- return renderToolButton('quote', 'quote', () => toggleFormat('quote'), !!activeFormats.quote);
29275
- case 'color':
29276
- return renderToolButton('color', 'color', () => { }, // TODO: Implement color picker
29277
- !!activeFormats.color);
29278
- default:
29279
- return null;
29280
- }
29281
- }) }) }));
29282
- }, [toolbar, theme, activeFormats, renderToolButton, renderToolSeparator, toggleFormat, insertLink, styles.toolbar, styles.toolbarContent]);
29283
- const renderEditor = React.useCallback(() => (jsxRuntime.jsx(reactNative.View, { style: [
29284
- styles.editorContainer,
29285
- {
29286
- borderColor: isFocused ? theme.colors.primary[5] : theme.backgrounds.border,
29287
- minHeight,
29288
- maxHeight,
29289
- },
29290
- error && { borderColor: theme.colors.error[5] },
29291
- (disabled || readOnly) && styles.disabled,
29292
- ], children: jsxRuntime.jsx(reactNative.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: [
29293
- styles.textInput,
29294
- reactNative.Platform.OS === 'web' ? { outlineWidth: 0 } : null,
29295
- {
29296
- color: theme.text.primary,
29297
- fontSize: activeFormats.fontSize || 16,
29298
- fontFamily: activeFormats.fontFamily || theme.fontFamily,
29299
- fontWeight: activeFormats.bold ? 'bold' : 'normal',
29300
- fontStyle: activeFormats.italic ? 'italic' : 'normal',
29301
- textDecorationLine: activeFormats.underline ? 'underline' : 'none',
29302
- textAlign: activeFormats.align || 'left',
29303
- },
29304
- ], ...props }) })), [
29305
- content.text,
29306
- handleContentChange,
29307
- handleSelectionChange,
29308
- handleFocus,
29309
- handleBlur,
29310
- placeholder,
29311
- disabled,
29312
- readOnly,
29313
- spellCheck,
29314
- maxLength,
29315
- isFocused,
29316
- theme,
29317
- minHeight,
29318
- maxHeight,
29319
- error,
29320
- activeFormats,
29321
- props,
29322
- styles.editorContainer,
29323
- styles.disabled,
29324
- styles.textInput,
29325
- ]);
29326
- return (jsxRuntime.jsxs(reactNative.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 && (jsxRuntime.jsxs(reactNative.Text, { style: [styles.characterCount, { color: theme.text.secondary }], children: [content.text.length, "/", maxLength] })), error && (jsxRuntime.jsx(reactNative.Text, { style: [styles.errorText, { color: theme.colors.error[5] }], children: error })), helperText && !error && (jsxRuntime.jsx(reactNative.Text, { style: [styles.helperText, { color: theme.text.secondary }], children: helperText }))] }));
29327
- });
29328
- RichTextEditor.displayName = 'RichTextEditor';
29329
-
29330
28607
  function RatingBase(rawProps, ref) {
29331
28608
  const { disclaimerProps: disclaimerData, otherProps: propsAfterDisclaimer } = extractDisclaimerProps(rawProps);
29332
28609
  const { spacingProps, otherProps: props } = extractSpacingProps(propsAfterDisclaimer);
@@ -30078,7 +29355,7 @@ function useMenuContext() {
30078
29355
  return context;
30079
29356
  }
30080
29357
  function MenuBase(props, ref) {
30081
- 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 = reactNative.Platform.OS === 'web' ? 'fixed' : 'portal', ...spacingProps } = props;
29358
+ 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 = reactNative.Platform.OS === 'web' ? 'fixed' : 'portal', ...spacingProps } = props;
30082
29359
  const [internalOpened, setInternalOpened] = React.useState(false);
30083
29360
  // Derive menu dropdown items from children each render for reactivity
30084
29361
  const { menuItems, menuDropdownProps } = React.useMemo(() => {
@@ -30153,11 +29430,11 @@ function MenuBase(props, ref) {
30153
29430
  const listGroupStyle = {
30154
29431
  ...styles.dropdown,
30155
29432
  ...(dropdownSpacingStyles || {}),
30156
- maxHeight,
29433
+ maxHeight: maxH,
30157
29434
  width: resolvedWidth,
30158
29435
  };
30159
- return (jsxRuntime.jsx(MenuContext.Provider, { value: menuContextValueOpened, children: jsxRuntime.jsx(ListGroup, { variant: "default", size: "sm", style: listGroupStyle, children: scrollable ? (jsxRuntime.jsx(reactNative.ScrollView, { showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", style: { maxHeight }, children: jsxRuntime.jsx(ListGroupBody, { children: menuItems }) })) : (jsxRuntime.jsx(reactNative.View, { style: { maxHeight, overflow: 'hidden' }, children: jsxRuntime.jsx(ListGroupBody, { children: menuItems }) })) }) }));
30160
- }, [menuItems, menuDropdownProps, styles.dropdown, dropdownSpacingStyles, maxHeight, menuContextValueOpened]);
29436
+ return (jsxRuntime.jsx(MenuContext.Provider, { value: menuContextValueOpened, children: jsxRuntime.jsx(ListGroup, { variant: "default", size: "sm", style: listGroupStyle, children: scrollable ? (jsxRuntime.jsx(reactNative.ScrollView, { showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", style: { maxHeight: maxH }, children: jsxRuntime.jsx(ListGroupBody, { children: menuItems }) })) : (jsxRuntime.jsx(reactNative.View, { style: { maxHeight: maxH, overflow: 'hidden' }, children: jsxRuntime.jsx(ListGroupBody, { children: menuItems }) })) }) }));
29437
+ }, [menuItems, menuDropdownProps, styles.dropdown, dropdownSpacingStyles, maxH, menuContextValueOpened]);
30161
29438
  const handleOpen = React.useCallback(async (opts) => {
30162
29439
  var _a, _b, _c, _d, _e, _f;
30163
29440
  // Use ref to avoid stale isOpened value after async close from backdrop click
@@ -30189,7 +29466,7 @@ function MenuBase(props, ref) {
30189
29466
  }
30190
29467
  // Calculate base overlay size
30191
29468
  const estimatedMenuHeight = 120; // Estimate for typical menu with 3-4 items
30192
- const resolvedWidth = width === 'target' ? triggerRect.width : (typeof width === 'number' ? width : (width === 'auto' ? 200 : 200));
29469
+ const resolvedWidth = w === 'target' ? triggerRect.width : (typeof w === 'number' ? w : (w === 'auto' ? 200 : 200));
30193
29470
  const overlaySize = {
30194
29471
  width: resolvedWidth,
30195
29472
  height: estimatedMenuHeight,
@@ -30237,6 +29514,7 @@ function MenuBase(props, ref) {
30237
29514
  const overlayId = openOverlay({
30238
29515
  content: menuDropdown,
30239
29516
  anchor: { x: positionResult.x, y: positionResult.y, width: overlaySize.width, height: overlaySize.height },
29517
+ placement: positionResult.placement || position,
30240
29518
  closeOnClickOutside,
30241
29519
  closeOnEscape,
30242
29520
  strategy,
@@ -30256,7 +29534,7 @@ function MenuBase(props, ref) {
30256
29534
  catch (error) {
30257
29535
  console.warn('Failed to open menu:', error);
30258
29536
  }
30259
- }, [disabled, width, position, offset, strategy, closeOnClickOutside, closeOnEscape, onOpen, menuItems, trigger, buildMenuDropdown, onClose]);
29537
+ }, [disabled, w, position, offset, strategy, closeOnClickOutside, closeOnEscape, onOpen, menuItems, trigger, buildMenuDropdown, onClose]);
30260
29538
  // When menu content changes while open, update overlay content in place
30261
29539
  React.useEffect(() => {
30262
29540
  var _a;
@@ -30268,14 +29546,14 @@ function MenuBase(props, ref) {
30268
29546
  return; // no structural change
30269
29547
  lastSignatureRef.current = menuItemsSignature;
30270
29548
  const currentId = overlayIdRef.current;
30271
- const resolvedWidth = (_a = lastResolvedWidthRef.current) !== null && _a !== void 0 ? _a : (typeof width === 'number' ? width : undefined);
29549
+ const resolvedWidth = (_a = lastResolvedWidthRef.current) !== null && _a !== void 0 ? _a : (typeof w === 'number' ? w : undefined);
30272
29550
  const menuDropdown = buildMenuDropdown(resolvedWidth);
30273
29551
  if (!menuDropdown)
30274
29552
  return;
30275
29553
  updateOverlay(currentId, {
30276
29554
  content: menuDropdown,
30277
29555
  });
30278
- }, [menuItemsSignature, menuItems, updateOverlay, width, buildMenuDropdown]);
29556
+ }, [menuItemsSignature, menuItems, updateOverlay, w, buildMenuDropdown]);
30279
29557
  const handleToggle = React.useCallback(() => {
30280
29558
  if (isOpenedRef.current) {
30281
29559
  handleClose();
@@ -32206,8 +31484,8 @@ function usePopoverContext(component) {
32206
31484
  const DEFAULT_ARROW_SIZE = 7;
32207
31485
  const PopoverBase = (props, ref) => {
32208
31486
  var _a;
32209
- const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
32210
- 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;
31487
+ const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, trigger = 'click', disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
31488
+ 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;
32211
31489
  const theme = useTheme();
32212
31490
  const { spacingProps } = extractSpacingProps(rest);
32213
31491
  const spacingStyles = getSpacingStyles(spacingProps);
@@ -32218,9 +31496,18 @@ const PopoverBase = (props, ref) => {
32218
31496
  const openedRef = React.useRef(opened);
32219
31497
  const closingReasonRef = React.useRef(null);
32220
31498
  const anchorMeasurementsRef = React.useRef(null);
31499
+ const hoverTimeoutRef = React.useRef(null);
32221
31500
  React.useEffect(() => {
32222
31501
  openedRef.current = opened;
32223
31502
  }, [opened]);
31503
+ // Cleanup hover timeout on unmount
31504
+ React.useEffect(() => {
31505
+ return () => {
31506
+ if (hoverTimeoutRef.current) {
31507
+ clearTimeout(hoverTimeoutRef.current);
31508
+ }
31509
+ };
31510
+ }, []);
32224
31511
  const resolvedOffset = typeof offset === 'number' ? offset : (_a = offset === null || offset === void 0 ? void 0 : offset.mainAxis) !== null && _a !== void 0 ? _a : 8;
32225
31512
  const resolvedFlip = preventPositionChangeWhenVisible
32226
31513
  ? false
@@ -32233,7 +31520,7 @@ const PopoverBase = (props, ref) => {
32233
31520
  ? false
32234
31521
  : true;
32235
31522
  const resolvedStrategy = floatingStrategy !== null && floatingStrategy !== void 0 ? floatingStrategy : 'fixed';
32236
- const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition } = useDropdownPositioning({
31523
+ const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition, isPositioning } = useDropdownPositioning({
32237
31524
  isOpen: opened && !disabled && !!dropdownState,
32238
31525
  placement: position,
32239
31526
  offset: resolvedOffset,
@@ -32245,9 +31532,20 @@ const PopoverBase = (props, ref) => {
32245
31532
  fallbackPlacements,
32246
31533
  viewport,
32247
31534
  onClose: () => handleOverlayClose('dismiss'),
32248
- closeOnClickOutside,
31535
+ closeOnClickOutside: trigger === 'hover' ? false : closeOnClickOutside,
32249
31536
  closeOnEscape,
32250
31537
  });
31538
+ // Track if we've done measurement-based positioning to avoid flicker
31539
+ const hasPositionedRef = React.useRef(false);
31540
+ React.useEffect(() => {
31541
+ // Only mark as positioned when we have a measurement-based position
31542
+ if (opened && positioningResult && positioningResult._hasMeasuredPopover) {
31543
+ hasPositionedRef.current = true;
31544
+ }
31545
+ if (!opened) {
31546
+ hasPositionedRef.current = false;
31547
+ }
31548
+ }, [opened, positioningResult]);
32251
31549
  const popoverStyles = React.useMemo(() => createPopoverStyles(theme)({
32252
31550
  radius,
32253
31551
  shadow,
@@ -32351,6 +31649,28 @@ const PopoverBase = (props, ref) => {
32351
31649
  openPopover();
32352
31650
  }
32353
31651
  }, [closePopover, openPopover]);
31652
+ // Hover-specific handlers with delay to prevent glitching when moving between target and dropdown
31653
+ const handleHoverOpen = React.useCallback(() => {
31654
+ if (hoverTimeoutRef.current) {
31655
+ clearTimeout(hoverTimeoutRef.current);
31656
+ hoverTimeoutRef.current = null;
31657
+ }
31658
+ openPopover();
31659
+ }, [openPopover]);
31660
+ const handleHoverClose = React.useCallback(() => {
31661
+ if (hoverTimeoutRef.current) {
31662
+ clearTimeout(hoverTimeoutRef.current);
31663
+ }
31664
+ hoverTimeoutRef.current = setTimeout(() => {
31665
+ closePopover('programmatic');
31666
+ hoverTimeoutRef.current = null;
31667
+ }, 150); // Delay to allow mouse to move to dropdown
31668
+ }, [closePopover]);
31669
+ // Store hover handlers in refs to avoid causing re-renders in useEffect
31670
+ const hoverHandlersRef = React.useRef({ open: handleHoverOpen, close: handleHoverClose });
31671
+ React.useEffect(() => {
31672
+ hoverHandlersRef.current = { open: handleHoverOpen, close: handleHoverClose };
31673
+ }, [handleHoverOpen, handleHoverClose]);
32354
31674
  React.useEffect(() => {
32355
31675
  if (opened) {
32356
31676
  updateAnchorMeasurements();
@@ -32382,41 +31702,53 @@ const PopoverBase = (props, ref) => {
32382
31702
  : undefined;
32383
31703
  const widthOverride = (() => {
32384
31704
  var _a, _b;
32385
- if (typeof width === 'number')
32386
- return width;
32387
- if (width === 'target') {
31705
+ if (typeof w === 'number')
31706
+ return w;
31707
+ if (w === 'target') {
32388
31708
  return (_b = (_a = anchorMeasurementsRef.current) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : computedFinalWidth;
32389
31709
  }
32390
31710
  return computedFinalWidth;
32391
31711
  })();
32392
31712
  const sizeStyles = {};
32393
- if (typeof minWidth === 'number')
32394
- sizeStyles.minWidth = minWidth;
32395
- if (typeof minHeight === 'number')
32396
- sizeStyles.minHeight = minHeight;
32397
- if (typeof maxWidth === 'number')
32398
- sizeStyles.maxWidth = maxWidth;
31713
+ if (typeof minW === 'number')
31714
+ sizeStyles.minWidth = minW;
31715
+ if (typeof minH === 'number')
31716
+ sizeStyles.minHeight = minH;
31717
+ if (typeof maxW === 'number')
31718
+ sizeStyles.maxWidth = maxW;
32399
31719
  const computedMaxHeight = positioningResult.maxHeight;
32400
31720
  const resolvedMaxHeight = (() => {
32401
- if (typeof maxHeight === 'number') {
31721
+ if (typeof maxH === 'number') {
32402
31722
  if (typeof computedMaxHeight === 'number') {
32403
- return Math.min(maxHeight, computedMaxHeight);
31723
+ return Math.min(maxH, computedMaxHeight);
32404
31724
  }
32405
- return maxHeight;
31725
+ return maxH;
32406
31726
  }
32407
- return typeof computedMaxHeight === 'number' ? computedMaxHeight : maxHeight;
31727
+ return typeof computedMaxHeight === 'number' ? computedMaxHeight : maxH;
32408
31728
  })();
32409
31729
  if (typeof resolvedMaxHeight === 'number')
32410
31730
  sizeStyles.maxHeight = resolvedMaxHeight;
32411
31731
  const dropdownStyle = [popoverStyles.dropdown, dropdownState.style, sizeStyles];
32412
- const content = (jsxRuntime.jsxs(reactNative.View, { ref: popoverRef, style: [popoverStyles.wrapper, widthOverride ? { width: widthOverride } : null], pointerEvents: dropdownState.trapFocus ? 'auto' : 'box-none', testID: dropdownState.testID, onLayout: handleDropdownLayout, ...dropdownState.containerProps, children: [jsxRuntime.jsx(reactNative.View, { style: dropdownStyle, children: dropdownState.content }), withArrow && (jsxRuntime.jsx(reactNative.View, { style: getArrowStyle(positioningResult.placement, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme) }))] }));
31732
+ // Hover handlers for the dropdown to keep it open when mouse moves from target to dropdown
31733
+ const dropdownHoverHandlers = trigger === 'hover' && reactNative.Platform.OS === 'web'
31734
+ ? {
31735
+ onMouseEnter: () => hoverHandlersRef.current.open(),
31736
+ onMouseLeave: () => hoverHandlersRef.current.close(),
31737
+ }
31738
+ : {};
31739
+ // Hide content until we have measurement-based positioning to prevent visual "snap"
31740
+ const hasMeasuredPosition = (positioningResult === null || positioningResult === void 0 ? void 0 : positioningResult._hasMeasuredPopover) === true;
31741
+ const visibilityStyle = !hasMeasuredPosition && reactNative.Platform.OS === 'web'
31742
+ ? { opacity: 0 }
31743
+ : {};
31744
+ const content = (jsxRuntime.jsxs(reactNative.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: [jsxRuntime.jsx(reactNative.View, { style: dropdownStyle, children: dropdownState.content }), withArrow && (jsxRuntime.jsx(reactNative.View, { style: getArrowStyle(positioningResult.placement, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme) }))] }));
32413
31745
  showOverlay(content, {
32414
31746
  width: widthOverride,
32415
31747
  maxHeight: resolvedMaxHeight,
32416
31748
  zIndex,
32417
31749
  });
32418
31750
  onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(positioningResult.placement);
32419
- }, [opened, dropdownState, positioningResult, popoverRef, showOverlay, hideOverlay, popoverStyles.dropdown, popoverStyles.wrapper, width, maxHeight, minWidth, minHeight, maxWidth, withArrow, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme, zIndex, onPositionChange, schedulePositionUpdate]);
31751
+ }, [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]);
32420
31752
  React.useEffect(() => {
32421
31753
  return () => {
32422
31754
  hideOverlay();
@@ -32437,6 +31769,8 @@ const PopoverBase = (props, ref) => {
32437
31769
  open: openPopover,
32438
31770
  close: () => closePopover('programmatic'),
32439
31771
  toggle: togglePopover,
31772
+ hoverOpen: handleHoverOpen,
31773
+ hoverClose: handleHoverClose,
32440
31774
  registerDropdown,
32441
31775
  unregisterDropdown,
32442
31776
  anchorRef,
@@ -32445,7 +31779,8 @@ const PopoverBase = (props, ref) => {
32445
31779
  withRoles,
32446
31780
  disabled,
32447
31781
  returnFocus,
32448
- }), [opened, openPopover, closePopover, togglePopover, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus]);
31782
+ trigger,
31783
+ }), [opened, openPopover, closePopover, togglePopover, handleHoverOpen, handleHoverClose, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus, trigger]);
32449
31784
  const setContainerRef = React.useCallback((node) => {
32450
31785
  if (typeof ref === 'function') {
32451
31786
  ref(node);
@@ -32495,16 +31830,44 @@ const PopoverTargetBase = (props, ref) => {
32495
31830
  : { id: context.targetId };
32496
31831
  const composedRef = mergeRefs(children.ref, externalTargetRef);
32497
31832
  const triggerHandlers = {};
32498
- triggerHandlers.onPress = (...args) => {
32499
- const tgt = targetProps;
32500
- if (tgt && typeof tgt.onPress === 'function') {
32501
- tgt.onPress(...args);
32502
- }
32503
- if (typeof childProps.onPress === 'function') {
32504
- childProps.onPress(...args);
32505
- }
32506
- context.toggle();
32507
- };
31833
+ const wrapperHoverHandlers = {};
31834
+ // Click trigger: toggle on press
31835
+ if (context.trigger === 'click') {
31836
+ triggerHandlers.onPress = (...args) => {
31837
+ const tgt = targetProps;
31838
+ if (tgt && typeof tgt.onPress === 'function') {
31839
+ tgt.onPress(...args);
31840
+ }
31841
+ if (typeof childProps.onPress === 'function') {
31842
+ childProps.onPress(...args);
31843
+ }
31844
+ context.toggle();
31845
+ };
31846
+ }
31847
+ // Hover trigger: open/close on mouse enter/leave (web only)
31848
+ // Applied to the wrapper View for reliable hover detection
31849
+ if (context.trigger === 'hover' && reactNative.Platform.OS === 'web') {
31850
+ wrapperHoverHandlers.onMouseEnter = (...args) => {
31851
+ const tgt = targetProps;
31852
+ if (tgt && typeof tgt.onMouseEnter === 'function') {
31853
+ tgt.onMouseEnter(...args);
31854
+ }
31855
+ if (typeof childProps.onMouseEnter === 'function') {
31856
+ childProps.onMouseEnter(...args);
31857
+ }
31858
+ context.hoverOpen();
31859
+ };
31860
+ wrapperHoverHandlers.onMouseLeave = (...args) => {
31861
+ const tgt = targetProps;
31862
+ if (tgt && typeof tgt.onMouseLeave === 'function') {
31863
+ tgt.onMouseLeave(...args);
31864
+ }
31865
+ if (typeof childProps.onMouseLeave === 'function') {
31866
+ childProps.onMouseLeave(...args);
31867
+ }
31868
+ context.hoverClose();
31869
+ };
31870
+ }
32508
31871
  if (reactNative.Platform.OS === 'web') {
32509
31872
  triggerHandlers.onKeyDown = (event) => {
32510
31873
  const tgt = targetProps;
@@ -32526,7 +31889,14 @@ const PopoverTargetBase = (props, ref) => {
32526
31889
  };
32527
31890
  }
32528
31891
  const dynamicRefProp = { [refProp]: composedRef };
32529
- delete sanitizedTargetProps.onPress;
31892
+ // Remove handlers that we're overriding from sanitizedTargetProps
31893
+ if (context.trigger === 'click') {
31894
+ delete sanitizedTargetProps.onPress;
31895
+ }
31896
+ if (context.trigger === 'hover') {
31897
+ delete sanitizedTargetProps.onMouseEnter;
31898
+ delete sanitizedTargetProps.onMouseLeave;
31899
+ }
32530
31900
  delete sanitizedTargetProps.onKeyDown;
32531
31901
  const mergedProps = {
32532
31902
  ...sanitizedTargetProps,
@@ -32538,7 +31908,7 @@ const PopoverTargetBase = (props, ref) => {
32538
31908
  mergedProps.disabled = true;
32539
31909
  }
32540
31910
  const anchorWrapperRef = mergeRefs(context.anchorRef, ref);
32541
- return (jsxRuntime.jsx(reactNative.View, { ref: anchorWrapperRef, collapsable: false, children: React.cloneElement(children, mergedProps) }));
31911
+ return (jsxRuntime.jsx(reactNative.View, { ref: anchorWrapperRef, collapsable: false, ...wrapperHoverHandlers, children: React.cloneElement(children, mergedProps) }));
32542
31912
  };
32543
31913
  const PopoverDropdownBase = (props, _ref) => {
32544
31914
  const { children, trapFocus = false, keepMounted, style, testID, ...rest } = props;
@@ -32582,8 +31952,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32582
31952
  const [side, alignment] = placement.split('-');
32583
31953
  switch (side) {
32584
31954
  case 'top':
31955
+ // Arrow points down, hide the borders that overlap with content (top-left corner after rotation)
32585
31956
  return {
32586
31957
  ...base,
31958
+ borderTopWidth: 0,
31959
+ borderLeftWidth: 0,
32587
31960
  bottom: -arrowSize,
32588
31961
  left: alignment === 'end'
32589
31962
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32593,8 +31966,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32593
31966
  marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
32594
31967
  };
32595
31968
  case 'bottom':
31969
+ // Arrow points up, hide the borders that overlap with content (bottom-right corner after rotation)
32596
31970
  return {
32597
31971
  ...base,
31972
+ borderBottomWidth: 0,
31973
+ borderRightWidth: 0,
32598
31974
  top: -arrowSize,
32599
31975
  left: alignment === 'end'
32600
31976
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32604,8 +31980,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32604
31980
  marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
32605
31981
  };
32606
31982
  case 'left':
31983
+ // Arrow points right, hide the borders that overlap with content (bottom-left corner after rotation)
32607
31984
  return {
32608
31985
  ...base,
31986
+ borderBottomWidth: 0,
31987
+ borderLeftWidth: 0,
32609
31988
  right: -arrowSize,
32610
31989
  top: alignment === 'end'
32611
31990
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32615,8 +31994,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
32615
31994
  marginTop: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
32616
31995
  };
32617
31996
  case 'right':
31997
+ // Arrow points left, hide the borders that overlap with content (top-right corner after rotation)
32618
31998
  return {
32619
31999
  ...base,
32000
+ borderTopWidth: 0,
32001
+ borderRightWidth: 0,
32620
32002
  left: -arrowSize,
32621
32003
  top: alignment === 'end'
32622
32004
  ? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
@@ -32654,7 +32036,7 @@ const getSpacingValue = (spacing, theme) => {
32654
32036
  // Table Cell Components
32655
32037
  const TableTh = (allProps) => {
32656
32038
  const { spacingProps, otherProps } = extractSpacingProps(allProps);
32657
- const { children, w, align = 'left', minWidth, maxWidth, flex, widthStrategy = 'auto', style } = otherProps;
32039
+ const { children, w, align = 'left', minW, maxW, flex, widthStrategy = 'auto', style } = otherProps;
32658
32040
  const theme = useTheme();
32659
32041
  const { isRTL } = useDirection();
32660
32042
  // Swap alignment in RTL
@@ -32685,10 +32067,10 @@ const TableTh = (allProps) => {
32685
32067
  else if (widthStrategy === 'auto') {
32686
32068
  widthStyle.flex = 1;
32687
32069
  }
32688
- if (minWidth)
32689
- widthStyle.minWidth = minWidth;
32690
- if (maxWidth)
32691
- widthStyle.maxWidth = maxWidth;
32070
+ if (minW)
32071
+ widthStyle.minWidth = minW;
32072
+ if (maxW)
32073
+ widthStyle.maxWidth = maxW;
32692
32074
  return widthStyle;
32693
32075
  };
32694
32076
  const cellStyle = [
@@ -32709,7 +32091,7 @@ const TableTh = (allProps) => {
32709
32091
  };
32710
32092
  const TableTd = (allProps) => {
32711
32093
  const { spacingProps, otherProps } = extractSpacingProps(allProps);
32712
- const { children, w, align = 'left', minWidth, maxWidth, flex, widthStrategy = 'auto', style } = otherProps;
32094
+ const { children, w, align = 'left', minW, maxW, flex, widthStrategy = 'auto', style } = otherProps;
32713
32095
  const theme = useTheme();
32714
32096
  const { isRTL } = useDirection();
32715
32097
  // Swap alignment in RTL
@@ -32740,10 +32122,10 @@ const TableTd = (allProps) => {
32740
32122
  else if (widthStrategy === 'auto') {
32741
32123
  widthStyle.flex = 1;
32742
32124
  }
32743
- if (minWidth)
32744
- widthStyle.minWidth = minWidth;
32745
- if (maxWidth)
32746
- widthStyle.maxWidth = maxWidth;
32125
+ if (minW)
32126
+ widthStyle.minWidth = minW;
32127
+ if (maxW)
32128
+ widthStyle.maxWidth = maxW;
32747
32129
  return widthStyle;
32748
32130
  };
32749
32131
  const cellStyle = [
@@ -32822,16 +32204,16 @@ const TableCaption = (allProps) => {
32822
32204
  // Scroll Container Component
32823
32205
  const TableScrollContainer = (allProps) => {
32824
32206
  const { spacingProps, otherProps } = extractSpacingProps(allProps);
32825
- const { children, minWidth = 500, maxHeight, type = 'native', style } = otherProps;
32207
+ const { children, minW = 500, maxH, type = 'native', style } = otherProps;
32826
32208
  const containerStyle = [
32827
32209
  {
32828
32210
  width: '100%',
32829
- maxHeight
32211
+ maxHeight: maxH
32830
32212
  },
32831
32213
  getSpacingStyles(spacingProps),
32832
32214
  style
32833
32215
  ];
32834
- const scrollViewStyle = minWidth ? { minWidth } : undefined;
32216
+ const scrollViewStyle = minW ? { minWidth: minW } : undefined;
32835
32217
  return (jsxRuntime.jsx(reactNative.View, { style: containerStyle, children: jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: reactNative.Platform.OS === 'web', contentContainerStyle: scrollViewStyle, children: jsxRuntime.jsx(reactNative.ScrollView, { style: { flex: 1 }, showsVerticalScrollIndicator: reactNative.Platform.OS === 'web', children: children }) }) }));
32836
32218
  };
32837
32219
  // Main Table Component
@@ -33769,7 +33151,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
33769
33151
  alignItems: 'center',
33770
33152
  marginBottom: DESIGN_TOKENS.spacing.md,
33771
33153
  paddingHorizontal: DESIGN_TOKENS.spacing.xs
33772
- }, children: [jsxRuntime.jsx(Flex, { gap: DESIGN_TOKENS.spacing.md, align: "center", children: selectedRows.length > 0 && bulkActions.length > 0 && (jsxRuntime.jsxs(Flex, { gap: 8, children: [jsxRuntime.jsxs(Text, { variant: "small", colorVariant: "muted", children: [selectedRows.length, " selected"] }), bulkActions.map(action => (jsxRuntime.jsx(Button, { variant: "outline", size: "sm", startIcon: action.icon, onPress: () => action.action(selectedRows, data), children: action.label }, action.key)))] })) }), jsxRuntime.jsxs(Flex, { gap: 8, children: [(searchable || columns.some(c => c.filterable)) && (jsxRuntime.jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, width: 320, trapFocus: true, children: [jsxRuntime.jsx(Popover.Target, { children: jsxRuntime.jsxs(Button, { variant: "outline", size: "sm", startIcon: jsxRuntime.jsx(Icon, { name: "search", size: 14 }), children: ["Search", (searchValue || activeFilters.length > 0) && (jsxRuntime.jsx(reactNative.View, { style: {
33154
+ }, children: [jsxRuntime.jsx(Flex, { gap: DESIGN_TOKENS.spacing.md, align: "center", children: selectedRows.length > 0 && bulkActions.length > 0 && (jsxRuntime.jsxs(Flex, { gap: 8, children: [jsxRuntime.jsxs(Text, { variant: "small", colorVariant: "muted", children: [selectedRows.length, " selected"] }), bulkActions.map(action => (jsxRuntime.jsx(Button, { variant: "outline", size: "sm", startIcon: action.icon, onPress: () => action.action(selectedRows, data), children: action.label }, action.key)))] })) }), jsxRuntime.jsxs(Flex, { gap: 8, children: [(searchable || columns.some(c => c.filterable)) && (jsxRuntime.jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, w: 320, trapFocus: true, children: [jsxRuntime.jsx(Popover.Target, { children: jsxRuntime.jsxs(Button, { variant: "outline", size: "sm", startIcon: jsxRuntime.jsx(Icon, { name: "search", size: 14 }), children: ["Search", (searchValue || activeFilters.length > 0) && (jsxRuntime.jsx(reactNative.View, { style: {
33773
33155
  width: 6,
33774
33156
  height: 6,
33775
33157
  borderRadius: 3,
@@ -33799,7 +33181,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
33799
33181
  }) })), jsxRuntime.jsx(Flex, { direction: "column", gap: DESIGN_TOKENS.spacing.sm, children: columns.filter(c => c.filterable).map(column => {
33800
33182
  const currentFilter = getColumnFilter(column.key);
33801
33183
  return (jsxRuntime.jsx(reactNative.View, { children: renderFilterControl(column) }, `${column.key}-${(currentFilter === null || currentFilter === void 0 ? void 0 : currentFilter.value) || 'no-filter'}`));
33802
- }) })] }))] }) })] })), onEditModeChange && (jsxRuntime.jsx(Button, { variant: editMode ? 'filled' : 'outline', size: "sm", onPress: () => onEditModeChange(!editMode), children: editMode ? 'Exit Edit' : 'Edit' })), showColumnVisibilityManager && (jsxRuntime.jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, width: 280, trapFocus: true, children: [jsxRuntime.jsx(Popover.Target, { children: jsxRuntime.jsx(Button, { variant: "outline", size: "sm", startIcon: jsxRuntime.jsx(Icon, { name: "eye", size: 14 }), children: "Columns" }) }), jsxRuntime.jsx(Popover.Dropdown, { children: jsxRuntime.jsxs(reactNative.View, { style: { padding: 8, maxHeight: 300, width: 260 }, children: [jsxRuntime.jsx(ComponentWithDisclaimer, { disclaimer: "Selected view determines the layout style", disclaimerProps: { colorVariant: 'muted', size: 'sm' }, children: jsxRuntime.jsxs(Row, { children: [jsxRuntime.jsx(Button, { size: "xs", title: "Deselect All", variant: hiddenColumns.length === columns.length ? 'filled' : 'outline', onPress: () => setHiddenColumns(columns.map(c => c.key)), style: { marginBottom: 8 } }), jsxRuntime.jsx(Button, { size: "xs", title: "Select All", variant: hiddenColumns.length === 0 ? 'filled' : 'outline', onPress: () => setHiddenColumns([]), style: { marginBottom: 8 } })] }) }), jsxRuntime.jsx(reactNative.ScrollView, { style: { maxHeight: 200 }, children: columns.map(col => (jsxRuntime.jsx(Checkbox, { label: tempHeaderEdits[col.key] || col.header, onChange: () => {
33184
+ }) })] }))] }) })] })), onEditModeChange && (jsxRuntime.jsx(Button, { variant: editMode ? 'filled' : 'outline', size: "sm", onPress: () => onEditModeChange(!editMode), children: editMode ? 'Exit Edit' : 'Edit' })), showColumnVisibilityManager && (jsxRuntime.jsxs(Popover, { position: "bottom-end", offset: { mainAxis: 12 }, w: 280, trapFocus: true, children: [jsxRuntime.jsx(Popover.Target, { children: jsxRuntime.jsx(Button, { variant: "outline", size: "sm", startIcon: jsxRuntime.jsx(Icon, { name: "eye", size: 14 }), children: "Columns" }) }), jsxRuntime.jsx(Popover.Dropdown, { children: jsxRuntime.jsxs(reactNative.View, { style: { padding: 8, maxHeight: 300, width: 260 }, children: [jsxRuntime.jsx(ComponentWithDisclaimer, { disclaimer: "Selected view determines the layout style", disclaimerProps: { colorVariant: 'muted', size: 'sm' }, children: jsxRuntime.jsxs(Row, { children: [jsxRuntime.jsx(Button, { size: "xs", title: "Deselect All", variant: hiddenColumns.length === columns.length ? 'filled' : 'outline', onPress: () => setHiddenColumns(columns.map(c => c.key)), style: { marginBottom: 8 } }), jsxRuntime.jsx(Button, { size: "xs", title: "Select All", variant: hiddenColumns.length === 0 ? 'filled' : 'outline', onPress: () => setHiddenColumns([]), style: { marginBottom: 8 } })] }) }), jsxRuntime.jsx(reactNative.ScrollView, { style: { maxHeight: 200 }, children: columns.map(col => (jsxRuntime.jsx(Checkbox, { label: tempHeaderEdits[col.key] || col.header, onChange: () => {
33803
33185
  if (hiddenColumns.includes(col.key)) {
33804
33186
  setHiddenColumns(prev => prev.filter(h => h !== col.key));
33805
33187
  }
@@ -34173,9 +33555,9 @@ const resolveTokenColor = (token, theme) => {
34173
33555
  return token; // assume raw color string
34174
33556
  };
34175
33557
  // Item
34176
- const TimelineItem = React.forwardRef(({ children, title, bullet, colorVariant, lineVariant = 'solid', color, active, itemIndex = 0, isLastItem = false, itemAlign, ...rest }, ref) => {
33558
+ const TimelineItem = React.forwardRef(({ children, title, timestamp, bullet, colorVariant, lineVariant = 'solid', color, titleColor, descriptionColor, timestampColor, active, itemIndex = 0, isLastItem = false, itemAlign, ...rest }, ref) => {
34177
33559
  const theme = useTheme();
34178
- const { active: timelineActive, color: timelineColor, lineWidth, bulletSize: contextBulletSize, align, reverseActive, size, centerMode, metrics, } = useTimelineContext();
33560
+ const { active: timelineActive, color: timelineColor, lineWidth, bulletSize: contextBulletSize, align, reverseActive, size, centerMode, metrics, titleColor: timelineTitleColor, descriptionColor: timelineDescriptionColor, timestampColor: timelineTimestampColor, } = useTimelineContext();
34179
33561
  const sizeConfig = metrics;
34180
33562
  const finalBulletSize = contextBulletSize || sizeConfig.bulletSize;
34181
33563
  const showAllColored = timelineActive === undefined;
@@ -34190,6 +33572,9 @@ const TimelineItem = React.forwardRef(({ children, title, bullet, colorVariant,
34190
33572
  const resolvedItemColor = color
34191
33573
  ? color
34192
33574
  : (colorVariant ? resolveTokenColor(colorVariant, theme) : timelineColor);
33575
+ const resolvedTitleColor = titleColor !== null && titleColor !== void 0 ? titleColor : timelineTitleColor;
33576
+ const resolvedDescriptionColor = descriptionColor !== null && descriptionColor !== void 0 ? descriptionColor : timelineDescriptionColor;
33577
+ const resolvedTimestampColor = timestampColor !== null && timestampColor !== void 0 ? timestampColor : timelineTimestampColor;
34193
33578
  // Active logic
34194
33579
  const isActive = showAllColored
34195
33580
  ? true
@@ -34275,10 +33660,16 @@ const TimelineItem = React.forwardRef(({ children, title, bullet, colorVariant,
34275
33660
  const getTitleStyle = () => ({
34276
33661
  fontSize: sizeConfig.fontSize,
34277
33662
  fontWeight: '600',
34278
- color: theme.text.primary,
33663
+ color: resolvedTitleColor !== null && resolvedTitleColor !== void 0 ? resolvedTitleColor : theme.text.primary,
34279
33664
  marginBottom: title && children ? 4 : 0,
34280
33665
  textAlign: effectiveAlign === 'right' ? 'right' : 'left',
34281
33666
  });
33667
+ const getTimestampStyle = () => ({
33668
+ fontSize: Math.max(10, Math.round(sizeConfig.fontSize * 0.8)),
33669
+ color: resolvedTimestampColor !== null && resolvedTimestampColor !== void 0 ? resolvedTimestampColor : theme.text.secondary,
33670
+ marginBottom: (title || children) ? 4 : 0,
33671
+ textAlign: effectiveAlign === 'right' ? 'right' : 'left',
33672
+ });
34282
33673
  const getItemWrapperStyle = () => {
34283
33674
  if (centerMode) {
34284
33675
  return {
@@ -34294,36 +33685,53 @@ const TimelineItem = React.forwardRef(({ children, title, bullet, colorVariant,
34294
33685
  alignItems: 'flex-start',
34295
33686
  };
34296
33687
  };
33688
+ const applyTextStyle = (nodes, styleOverride) => {
33689
+ if (!styleOverride)
33690
+ return nodes;
33691
+ return React.Children.map(nodes, (child) => {
33692
+ var _a;
33693
+ if (typeof child === 'string' || typeof child === 'number') {
33694
+ return jsxRuntime.jsx(reactNative.Text, { style: styleOverride, children: child });
33695
+ }
33696
+ if (!React.isValidElement(child))
33697
+ return child;
33698
+ const props = child.props || {};
33699
+ const isTextLike = ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'Text' || child.type === reactNative.Text || typeof props.children === 'string';
33700
+ if (isTextLike) {
33701
+ const mergedStyle = Array.isArray(props.style)
33702
+ ? [...props.style, styleOverride]
33703
+ : [props.style, styleOverride];
33704
+ return React.cloneElement(child, { style: mergedStyle });
33705
+ }
33706
+ if (props.children) {
33707
+ return React.cloneElement(child, { children: applyTextStyle(props.children, styleOverride) });
33708
+ }
33709
+ return child;
33710
+ });
33711
+ };
34297
33712
  if (centerMode) {
34298
33713
  // Three column layout: left content | bullet/line | right content
34299
33714
  const leftContent = effectiveAlign === 'left' && (title || children);
34300
33715
  const rightContent = effectiveAlign === 'right' && (title || children);
34301
33716
  // Helper to clone Text children with alignment
34302
33717
  const alignChildText = (nodes, side) => {
34303
- return React.Children.map(nodes, (child) => {
34304
- var _a;
34305
- if (!React.isValidElement(child))
34306
- return child;
34307
- const props = child.props || {};
34308
- const isTextLike = ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'Text' || (typeof props.children === 'string');
34309
- if (isTextLike) {
34310
- const mergedStyle = Array.isArray(props.style)
34311
- ? [...props.style, { textAlign: side }]
34312
- : [props.style, { textAlign: side }];
34313
- return React.cloneElement(child, { style: mergedStyle });
34314
- }
34315
- if (props.children) {
34316
- return React.cloneElement(child, { children: alignChildText(props.children, side) });
34317
- }
34318
- return child;
34319
- });
33718
+ const styleOverride = {
33719
+ textAlign: side,
33720
+ ...(resolvedDescriptionColor ? { color: resolvedDescriptionColor } : {}),
33721
+ };
33722
+ return applyTextStyle(nodes, styleOverride);
34320
33723
  };
34321
- return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [jsxRuntime.jsx(reactNative.View, { style: { flex: 1, paddingRight: sizeConfig.spacing, alignItems: 'flex-end' }, children: leftContent && (jsxRuntime.jsxs(reactNative.View, { style: { width: '100%', alignItems: 'flex-end' }, children: [title && jsxRuntime.jsx(reactNative.Text, { style: [getTitleStyle(), { textAlign: 'right' }], children: title }), alignChildText(children, 'right')] })) }), jsxRuntime.jsxs(reactNative.View, { style: { width: finalBulletSize, alignItems: 'center', position: 'relative' }, children: [getLine(), jsxRuntime.jsx(reactNative.View, { style: getBulletStyle(), children: bullet })] }), jsxRuntime.jsx(reactNative.View, { style: { flex: 1, paddingLeft: sizeConfig.spacing, alignItems: 'flex-start' }, children: rightContent && (jsxRuntime.jsxs(reactNative.View, { style: { width: '100%', alignItems: 'flex-start' }, children: [title && jsxRuntime.jsx(reactNative.Text, { style: [getTitleStyle(), { textAlign: 'left' }], children: title }), alignChildText(children, 'left')] })) })] }));
33724
+ return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [jsxRuntime.jsx(reactNative.View, { style: { flex: 1, paddingRight: sizeConfig.spacing, alignItems: 'flex-end' }, children: leftContent && (jsxRuntime.jsxs(reactNative.View, { style: { width: '100%', alignItems: 'flex-end' }, children: [timestamp && (jsxRuntime.jsx(reactNative.Text, { style: [getTimestampStyle(), { textAlign: 'right' }], children: timestamp })), title && jsxRuntime.jsx(reactNative.Text, { style: [getTitleStyle(), { textAlign: 'right' }], children: title }), alignChildText(children, 'right')] })) }), jsxRuntime.jsxs(reactNative.View, { style: { width: finalBulletSize, alignItems: 'center', position: 'relative' }, children: [getLine(), jsxRuntime.jsx(reactNative.View, { style: getBulletStyle(), children: bullet })] }), jsxRuntime.jsx(reactNative.View, { style: { flex: 1, paddingLeft: sizeConfig.spacing, alignItems: 'flex-start' }, children: rightContent && (jsxRuntime.jsxs(reactNative.View, { style: { width: '100%', alignItems: 'flex-start' }, children: [timestamp && (jsxRuntime.jsx(reactNative.Text, { style: [getTimestampStyle(), { textAlign: 'left' }], children: timestamp })), title && jsxRuntime.jsx(reactNative.Text, { style: [getTitleStyle(), { textAlign: 'left' }], children: title }), alignChildText(children, 'left')] })) })] }));
34322
33725
  }
34323
- return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [getLine(), jsxRuntime.jsx(reactNative.View, { style: getBulletStyle(), children: bullet }), (title || children) && (jsxRuntime.jsxs(reactNative.View, { style: getContentStyle(), children: [title && jsxRuntime.jsx(reactNative.Text, { style: getTitleStyle(), children: title }), children] }))] }));
33726
+ return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: getItemWrapperStyle(), ...rest, children: [getLine(), jsxRuntime.jsx(reactNative.View, { style: getBulletStyle(), children: bullet }), (title || children) && (jsxRuntime.jsxs(reactNative.View, { style: getContentStyle(), children: [timestamp && jsxRuntime.jsx(reactNative.Text, { style: getTimestampStyle(), children: timestamp }), title && jsxRuntime.jsx(reactNative.Text, { style: getTitleStyle(), children: title }), resolvedDescriptionColor
33727
+ ? applyTextStyle(children, {
33728
+ color: resolvedDescriptionColor,
33729
+ textAlign: effectiveAlign === 'right' ? 'right' : 'left',
33730
+ })
33731
+ : children] }))] }));
34324
33732
  });
34325
33733
  // Root Timeline
34326
- const Timeline = React.forwardRef(({ children, active, color, colorVariant, lineWidth, bulletSize, align = 'left', reverseActive = false, size = 'md', centerMode = false, ...rest }, ref) => {
33734
+ const Timeline = React.forwardRef(({ children, active, color, colorVariant, titleColor, descriptionColor, timestampColor, lineWidth, bulletSize, align = 'left', reverseActive = false, size = 'md', centerMode = false, ...rest }, ref) => {
34327
33735
  const theme = useTheme();
34328
33736
  const clampedSize = clampComponentSize(size, TIMELINE_ALLOWED_SIZES);
34329
33737
  const baseMetrics = resolveTimelineMetrics(clampedSize);
@@ -34345,6 +33753,9 @@ const Timeline = React.forwardRef(({ children, active, color, colorVariant, line
34345
33753
  size: clampedSize,
34346
33754
  metrics,
34347
33755
  centerMode,
33756
+ titleColor,
33757
+ descriptionColor,
33758
+ timestampColor,
34348
33759
  };
34349
33760
  const items = [];
34350
33761
  React.Children.forEach(children, (child, index) => {
@@ -35062,7 +34473,7 @@ const Notice = factory(NoticeBase);
35062
34473
  Notice.displayName = 'Notice';
35063
34474
 
35064
34475
  function SkeletonBase(props, ref) {
35065
- const { shape = 'rectangle', width, height, size = 'md', radius, animate = true, animationDuration = 1500, colors, style, testID, ...rest } = props;
34476
+ const { shape = 'rectangle', w, h, size = 'md', radius, animate = true, animationDuration = 1500, colors, style, testID, ...rest } = props;
35066
34477
  const { spacingProps, otherProps } = extractSpacingProps(rest);
35067
34478
  const spacingStyles = getSpacingStyles(spacingProps);
35068
34479
  const theme = useTheme();
@@ -35083,36 +34494,36 @@ function SkeletonBase(props, ref) {
35083
34494
  switch (shape) {
35084
34495
  case 'text':
35085
34496
  return {
35086
- width: width || '100%',
35087
- height: height || getSpacing('md')
34497
+ width: w || '100%',
34498
+ height: h || getSpacing('md')
35088
34499
  };
35089
34500
  case 'chip':
35090
34501
  return {
35091
- width: width || (sizeValue * 3),
35092
- height: height || sizeValue
34502
+ width: w || (sizeValue * 3),
34503
+ height: h || sizeValue
35093
34504
  };
35094
34505
  case 'avatar':
35095
34506
  case 'circle':
35096
34507
  return {
35097
- width: width || sizeValue,
35098
- height: height || sizeValue
34508
+ width: w || sizeValue,
34509
+ height: h || sizeValue
35099
34510
  };
35100
34511
  case 'button':
35101
34512
  return {
35102
- width: width || (sizeValue * 4),
35103
- height: height || sizeValue
34513
+ width: w || (sizeValue * 4),
34514
+ height: h || sizeValue
35104
34515
  };
35105
34516
  case 'card':
35106
34517
  return {
35107
- width: width || '100%',
35108
- height: height || (sizeValue * 6)
34518
+ width: w || '100%',
34519
+ height: h || (sizeValue * 6)
35109
34520
  };
35110
34521
  case 'rectangle':
35111
34522
  case 'rounded':
35112
34523
  default:
35113
34524
  return {
35114
- width: width || '100%',
35115
- height: height || sizeValue
34525
+ width: w || '100%',
34526
+ height: h || sizeValue
35116
34527
  };
35117
34528
  }
35118
34529
  };
@@ -35751,104 +35162,6 @@ const Ring = factory((props, ref) => {
35751
35162
  return (jsxRuntime.jsxs(reactNative.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: [jsxRuntime.jsxs(reactNative.View, { style: [styles$8.ringWrapper, { width: size, height: size }, ringStyle], children: [jsxRuntime.jsxs(Svg, { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [jsxRuntime.jsx(Svg.Circle, { cx: size / 2, cy: size / 2, r: radius, stroke: defaultTrackColor, strokeWidth: thickness, fill: "transparent" }), jsxRuntime.jsx(Svg.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})` })] }), jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: [styles$8.centerContent, { width: size, height: size }, contentStyle], children: centerContent })] }), caption !== undefined && caption !== null ? (React.isValidElement(caption) ? (caption) : (jsxRuntime.jsx(Text, { variant: "span", size: "xs", color: captionTextColor, weight: "600", style: [{ marginTop: 6, letterSpacing: 1 }, captionStyle], children: caption }))) : null] }));
35752
35163
  }, { displayName: 'Ring' });
35753
35164
 
35754
- const NAVIGATIONPROGRESS_DEFAULTS = {
35755
- size: 3,
35756
- color: 'primary',
35757
- zIndex: 9999,
35758
- overlay: true,
35759
- stepInterval: 500,
35760
- radius: 0,
35761
- };
35762
-
35763
- let subscribers = new Set();
35764
- let internalState = { value: 0, active: false };
35765
- let interval = null;
35766
- function broadcast() { subscribers.forEach(cb => cb({ ...internalState })); }
35767
- function schedule(intervalMs) {
35768
- clearInterval(interval);
35769
- interval = setInterval(() => {
35770
- if (!internalState.active)
35771
- return;
35772
- const remain = 100 - internalState.value;
35773
- const inc = Math.max(0.1, remain * 0.03);
35774
- internalState.value = Math.min(99, internalState.value + inc);
35775
- broadcast();
35776
- }, intervalMs);
35777
- }
35778
- const navigationProgress = {
35779
- start() { if (internalState.active)
35780
- return; internalState.active = true; if (internalState.value >= 100)
35781
- internalState.value = 0; broadcast(); schedule(NAVIGATIONPROGRESS_DEFAULTS.stepInterval); },
35782
- stop() { internalState.active = false; broadcast(); },
35783
- complete() { internalState.active = true; internalState.value = 100; broadcast(); setTimeout(() => { internalState.active = false; internalState.value = 0; broadcast(); }, 400); },
35784
- reset() { internalState.value = 0; internalState.active = false; broadcast(); },
35785
- set(v) { internalState.value = Math.max(0, Math.min(100, v)); broadcast(); },
35786
- increment(delta = 5) { internalState.value = Math.min(100, internalState.value + delta); broadcast(); },
35787
- decrement(delta = 5) { internalState.value = Math.max(0, internalState.value - delta); broadcast(); },
35788
- isActive() { return internalState.active; }
35789
- };
35790
- 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 }) => {
35791
- const theme = useTheme();
35792
- const scheme = useColorScheme();
35793
- const isDark = scheme === 'dark';
35794
- const progress = Animated.useSharedValue(0);
35795
- const opacity = Animated.useSharedValue(0);
35796
- React.useEffect(() => {
35797
- const sub = (s) => {
35798
- if (value == null) {
35799
- progress.value = Animated.withTiming(s.value, { duration: stepInterval });
35800
- opacity.value = Animated.withTiming(s.active ? 1 : 0, { duration: 150 });
35801
- }
35802
- };
35803
- subscribers.add(sub);
35804
- broadcast();
35805
- return () => { subscribers.delete(sub); };
35806
- }, [value, stepInterval, progress, opacity]);
35807
- React.useEffect(() => {
35808
- if (value != null) {
35809
- progress.value = Animated.withTiming(value, { duration: stepInterval });
35810
- opacity.value = Animated.withTiming(active ? 1 : 0, { duration: 150 });
35811
- }
35812
- }, [value, active, stepInterval]);
35813
- let resolvedColor = color;
35814
- if (theme.colors[color]) {
35815
- const bucket = theme.colors[color];
35816
- resolvedColor = bucket[5] || bucket[4] || bucket[0];
35817
- }
35818
- const barStyle = Animated.useAnimatedStyle(() => ({ width: `${progress.value}%` }));
35819
- const containerStyle = Animated.useAnimatedStyle(() => ({ opacity: opacity.value }));
35820
- return (jsxRuntime.jsxs(Animated.View, { style: [
35821
- {
35822
- position: overlay ? 'absolute' : 'relative',
35823
- top: 0,
35824
- left: 0,
35825
- right: 0,
35826
- height: size,
35827
- backgroundColor: isDark ? theme.colors.gray[3] : theme.colors.gray[2],
35828
- overflow: 'hidden',
35829
- zIndex,
35830
- borderRadius: radius,
35831
- pointerEvents: 'none'
35832
- },
35833
- containerStyle,
35834
- style
35835
- ], children: [jsxRuntime.jsx(Animated.View, { style: [{
35836
- position: 'absolute',
35837
- top: 0,
35838
- bottom: 0,
35839
- left: 0,
35840
- backgroundColor: resolvedColor,
35841
- borderRadius: radius,
35842
- }, barStyle] }), jsxRuntime.jsx(Animated.View, { style: [{
35843
- position: 'absolute',
35844
- top: 0,
35845
- bottom: 0,
35846
- right: 0,
35847
- width: 80,
35848
- backgroundColor: 'rgba(255,255,255,0.2)'
35849
- }, barStyle] })] }));
35850
- };
35851
-
35852
35165
  const DEFAULT_OPACITY = 0.6;
35853
35166
  const HEX_COLOR_REGEX = /^#?[0-9a-f]{3,8}$/i;
35854
35167
  const clampOpacity = (value) => {
@@ -36041,270 +35354,6 @@ const LoadingOverlay = React.forwardRef((props, ref) => {
36041
35354
  });
36042
35355
  LoadingOverlay.displayName = 'LoadingOverlay';
36043
35356
 
36044
- // A lightweight hover-activated floating panel similar to Mantine HoverCard
36045
- function HoverCardBase(props, ref) {
36046
- 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;
36047
- const [opened, setOpened] = React.useState(false);
36048
- const openTimeout = React.useRef(null);
36049
- const closeTimeout = React.useRef(null);
36050
- const containerRef = React.useRef(null);
36051
- const targetRef = React.useRef(null);
36052
- const overlayIdRef = React.useRef(null);
36053
- const overlayContentRef = React.useRef(null);
36054
- const isHoveringTargetRef = React.useRef(false);
36055
- const isHoveringOverlayRef = React.useRef(false);
36056
- const theme = useTheme();
36057
- const { openOverlay, closeOverlay, updateOverlay } = useOverlay();
36058
- const isOpened = controlledOpened !== undefined ? controlledOpened : opened;
36059
- const clearTimers = () => {
36060
- if (openTimeout.current) {
36061
- clearTimeout(openTimeout.current);
36062
- openTimeout.current = null;
36063
- }
36064
- if (closeTimeout.current) {
36065
- clearTimeout(closeTimeout.current);
36066
- closeTimeout.current = null;
36067
- }
36068
- };
36069
- const doOpen = React.useCallback(() => {
36070
- if (disabled)
36071
- return;
36072
- setOpened(true);
36073
- onOpen === null || onOpen === void 0 ? void 0 : onOpen();
36074
- }, [disabled, onOpen]);
36075
- const doClose = React.useCallback(() => {
36076
- setOpened(false);
36077
- onClose === null || onClose === void 0 ? void 0 : onClose();
36078
- }, [onClose]);
36079
- const scheduleOpen = React.useCallback(() => {
36080
- clearTimers();
36081
- openTimeout.current = setTimeout(doOpen, openDelay);
36082
- }, [doOpen, openDelay]);
36083
- const scheduleClose = React.useCallback(() => {
36084
- clearTimers();
36085
- closeTimeout.current = setTimeout(() => {
36086
- // Only close if neither target nor overlay are hovered (web)
36087
- if (reactNative.Platform.OS === 'web') {
36088
- if (isHoveringTargetRef.current || isHoveringOverlayRef.current)
36089
- return;
36090
- }
36091
- doClose();
36092
- }, closeDelay);
36093
- }, [doClose, closeDelay]);
36094
- React.useEffect(() => () => clearTimers(), []);
36095
- // Escape key (web only)
36096
- React.useEffect(() => {
36097
- if (!closeOnEscape || reactNative.Platform.OS !== 'web')
36098
- return;
36099
- const handler = (e) => { if (e.key === 'Escape')
36100
- doClose(); };
36101
- document.addEventListener('keydown', handler);
36102
- return () => document.removeEventListener('keydown', handler);
36103
- }, [closeOnEscape, doClose]);
36104
- const getInlinePositionStyle = () => {
36105
- const base = { position: 'absolute' };
36106
- switch (position) {
36107
- case 'top': return { ...base, bottom: '100%', left: 0, marginBottom: offset };
36108
- case 'bottom': return { ...base, top: '100%', left: 0, marginTop: offset };
36109
- case 'left': return { ...base, right: '100%', top: 0, marginRight: offset };
36110
- case 'right': return { ...base, left: '100%', top: 0, marginLeft: offset };
36111
- default: return { ...base, top: '100%', left: 0, marginTop: offset };
36112
- }
36113
- };
36114
- const shadowStyle = (() => {
36115
- switch (shadow) {
36116
- case 'sm':
36117
- return { boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', elevation: 2 };
36118
- case 'md':
36119
- return { boxShadow: '0 2px 4px rgba(0, 0, 0, 0.15)', elevation: 4 };
36120
- case 'lg':
36121
- return { boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)', elevation: 8 };
36122
- default:
36123
- return {};
36124
- }
36125
- })();
36126
- const renderArrow = (placement) => {
36127
- if (!withArrow)
36128
- return null;
36129
- const base = { position: 'absolute', width: 0, height: 0 };
36130
- const color = theme.colors.gray[0];
36131
- const styles = {
36132
- top: { top: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderTopWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: color },
36133
- bottom: { bottom: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderBottomWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderBottomColor: color },
36134
- left: { left: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderLeftWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderLeftColor: color },
36135
- right: { right: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderRightWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderRightColor: color },
36136
- };
36137
- const key = placement.split('-')[0];
36138
- return jsxRuntime.jsx(reactNative.View, { style: { ...base, ...(styles[key] || styles.top) } });
36139
- };
36140
- const openPortal = React.useCallback(async () => {
36141
- if (!withinPortal || !isOpened || overlayIdRef.current)
36142
- return;
36143
- const rect = await measureElement(targetRef);
36144
- const estWidth = width || 240;
36145
- const estHeight = 160; // rough initial height
36146
- const pos = calculateOverlayPositionEnhanced(rect, { width: estWidth, height: estHeight }, {
36147
- placement: position,
36148
- offset,
36149
- viewport: getViewport(),
36150
- strategy: 'fixed'
36151
- });
36152
- const overlayContent = (jsxRuntime.jsxs(reactNative.View, { ref: overlayContentRef, style: [
36153
- {
36154
- backgroundColor: theme.colors.gray[0],
36155
- borderRadius: getRadius$2(radius),
36156
- paddingHorizontal: getSpacing('md'),
36157
- paddingVertical: getSpacing('sm'),
36158
- borderWidth: 1,
36159
- borderColor: theme.colors.gray[3],
36160
- minWidth: width || 160,
36161
- maxWidth: width || 320,
36162
- },
36163
- shadowStyle,
36164
- ], ...(reactNative.Platform.OS === 'web' && trigger === 'hover' ? {
36165
- onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
36166
- onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
36167
- } : {}), children: [children, renderArrow(pos.placement)] }));
36168
- const id = openOverlay({
36169
- content: overlayContent,
36170
- anchor: { x: pos.x, y: pos.y, width: estWidth, height: estHeight },
36171
- trigger: trigger,
36172
- // For hover-triggered overlays, do NOT render a click-outside backdrop – it steals hover
36173
- // and immediately fires target onMouseLeave. We rely on pointer leave timers instead.
36174
- closeOnClickOutside: trigger !== 'hover',
36175
- closeOnEscape: closeOnEscape,
36176
- strategy: 'fixed',
36177
- onClose: () => { overlayIdRef.current = null; if (opened)
36178
- setOpened(false); onClose === null || onClose === void 0 ? void 0 : onClose(); },
36179
- zIndex
36180
- });
36181
- overlayIdRef.current = id;
36182
- }, [withinPortal, isOpened, overlayIdRef, position, offset, width, trigger, closeOnEscape, theme, radius, shadowStyle, children, opened, onClose, getSpacing, getRadius$2]);
36183
- const closePortal = React.useCallback(() => {
36184
- if (overlayIdRef.current) {
36185
- closeOverlay(overlayIdRef.current);
36186
- overlayIdRef.current = null;
36187
- }
36188
- }, [closeOverlay]);
36189
- React.useEffect(() => {
36190
- if (withinPortal) {
36191
- if (isOpened)
36192
- openPortal();
36193
- else
36194
- closePortal();
36195
- }
36196
- return () => { if (!isOpened)
36197
- closePortal(); };
36198
- }, [isOpened, withinPortal, openPortal, closePortal]);
36199
- React.useEffect(() => {
36200
- if (!withinPortal || reactNative.Platform.OS !== 'web' || !isOpened || !overlayIdRef.current)
36201
- return;
36202
- const handler = () => {
36203
- Promise.all([measureElement(targetRef)]).then(([rect]) => {
36204
- var _a, _b;
36205
- const actualWidth = ((_a = overlayContentRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || width || 240;
36206
- const actualHeight = ((_b = overlayContentRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 160;
36207
- const pos = calculateOverlayPositionEnhanced(rect, { width: actualWidth, height: actualHeight }, {
36208
- placement: position,
36209
- offset,
36210
- viewport: getViewport(),
36211
- strategy: 'fixed'
36212
- });
36213
- updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: actualWidth, height: actualHeight } });
36214
- });
36215
- };
36216
- window.addEventListener('resize', handler);
36217
- window.addEventListener('scroll', handler, true);
36218
- return () => {
36219
- window.removeEventListener('resize', handler);
36220
- window.removeEventListener('scroll', handler, true);
36221
- };
36222
- }, [withinPortal, isOpened, position, offset, width, updateOverlay]);
36223
- // Smart sizing: after content mounts, measure actual size and reposition if changed
36224
- React.useEffect(() => {
36225
- if (!withinPortal || !isOpened || !overlayIdRef.current)
36226
- return;
36227
- let frame;
36228
- const attempt = () => {
36229
- Promise.all([
36230
- measureElement(targetRef),
36231
- measureElement({ current: overlayContentRef.current })
36232
- ]).then(([targetRect, contentRect]) => {
36233
- if (!targetRect.width || !contentRect.width)
36234
- return; // skip invalid
36235
- const desiredWidth = width || contentRect.width;
36236
- const desiredHeight = contentRect.height;
36237
- // Recalculate with actual content size
36238
- const pos = calculateOverlayPositionEnhanced(targetRect, { width: desiredWidth, height: desiredHeight }, {
36239
- placement: position,
36240
- offset,
36241
- viewport: getViewport(),
36242
- strategy: 'fixed'
36243
- });
36244
- updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: desiredWidth, height: desiredHeight } });
36245
- });
36246
- };
36247
- // Delay a bit to allow layout
36248
- frame = setTimeout(attempt, 30);
36249
- return () => { if (frame)
36250
- clearTimeout(frame); };
36251
- }, [withinPortal, isOpened, position, offset, width, updateOverlay]);
36252
- const targetProps = {};
36253
- if (trigger === 'hover') {
36254
- if (reactNative.Platform.OS === 'web') {
36255
- targetProps.onMouseEnter = () => { isHoveringTargetRef.current = true; scheduleOpen(); };
36256
- targetProps.onMouseLeave = () => { isHoveringTargetRef.current = false; scheduleClose(); };
36257
- }
36258
- else {
36259
- // fallback: tap to toggle on native
36260
- targetProps.onPress = () => {
36261
- if (isOpened) {
36262
- doClose();
36263
- }
36264
- else {
36265
- doOpen();
36266
- }
36267
- };
36268
- }
36269
- }
36270
- else if (trigger === 'click') {
36271
- targetProps.onPress = () => {
36272
- if (isOpened) {
36273
- doClose();
36274
- }
36275
- else {
36276
- doOpen();
36277
- }
36278
- };
36279
- }
36280
- const inlineContent = (isOpened || keepMounted) && !withinPortal ? (jsxRuntime.jsxs(reactNative.View, { style: [
36281
- getInlinePositionStyle(),
36282
- {
36283
- backgroundColor: theme.colors.gray[0],
36284
- borderRadius: getRadius$2(radius),
36285
- paddingHorizontal: getSpacing('md'),
36286
- paddingVertical: getSpacing('sm'),
36287
- borderWidth: 1,
36288
- borderColor: theme.colors.gray[3],
36289
- minWidth: width,
36290
- zIndex,
36291
- },
36292
- shadowStyle,
36293
- ], pointerEvents: "auto", ...(reactNative.Platform.OS === 'web' && trigger === 'hover' ? {
36294
- onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
36295
- onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
36296
- } : {}), children: [children, renderArrow(position)] })) : null;
36297
- return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: [{ position: 'relative', alignSelf: 'flex-start' }, style], testID: testID, children: [jsxRuntime.jsx(reactNative.Pressable, { ref: (node) => { containerRef.current = node; targetRef.current = node; }, ...targetProps, style: ({ pressed }) => {
36298
- var _a;
36299
- return [
36300
- { opacity: pressed ? 0.85 : 1 },
36301
- (_a = target === null || target === void 0 ? void 0 : target.props) === null || _a === void 0 ? void 0 : _a.style,
36302
- ];
36303
- }, children: target }), inlineContent] }));
36304
- }
36305
- const HoverCard = factory(HoverCardBase);
36306
- HoverCard.displayName = 'HoverCard';
36307
-
36308
35357
  const ContextMenu = ({ children, items, closeOnSelect = true, longPressDelay = 350, maxHeight = 280, onOpen, onClose, open: controlledOpen, position: controlledPosition, portalId, style, }) => {
36309
35358
  var _a, _b;
36310
35359
  const [internalOpen, setInternalOpen] = React.useState(false);
@@ -36542,7 +35591,7 @@ const styles$6 = reactNative.StyleSheet.create({
36542
35591
  },
36543
35592
  });
36544
35593
 
36545
- const WaveformSkeleton = ({ width = 300, height = 60, fullWidth = false, barsCount = 20, }) => {
35594
+ const WaveformSkeleton = ({ w = 300, h = 60, fullWidth = false, barsCount = 20, }) => {
36546
35595
  const theme = useTheme();
36547
35596
  const styles = reactNative.StyleSheet.create({
36548
35597
  animatedBar: {
@@ -36558,18 +35607,18 @@ const WaveformSkeleton = ({ width = 300, height = 60, fullWidth = false, barsCou
36558
35607
  backgroundColor: theme.colors.gray[1],
36559
35608
  borderRadius: 4,
36560
35609
  flexDirection: 'row',
36561
- height,
35610
+ height: h,
36562
35611
  justifyContent: 'space-between',
36563
35612
  paddingHorizontal: 4,
36564
- width: fullWidth ? '100%' : width,
35613
+ width: fullWidth ? '100%' : w,
36565
35614
  },
36566
35615
  });
36567
35616
  // Generate random heights for skeleton bars
36568
35617
  const barHeights = Array.from({ length: barsCount }, () => Math.random() * 0.6 + 0.2 // Heights between 20% and 80% of container
36569
35618
  );
36570
- const barWidth = fullWidth ? 'auto' : Math.max(1, (width - 40) / barsCount - 2);
35619
+ const barWidth = fullWidth ? 'auto' : Math.max(1, (w - 40) / barsCount - 2);
36571
35620
  return (jsxRuntime.jsx(reactNative.View, { style: styles.container, children: barHeights.map((heightRatio, index) => {
36572
- const barHeight = height * heightRatio;
35621
+ const barHeight = h * heightRatio;
36573
35622
  const isAnimated = index % 3 === 0; // Animate every 3rd bar for shimmer effect
36574
35623
  return (jsxRuntime.jsx(reactNative.View, { style: [
36575
35624
  styles.bar,
@@ -36584,7 +35633,7 @@ const WaveformSkeleton = ({ width = 300, height = 60, fullWidth = false, barsCou
36584
35633
  }) }));
36585
35634
  };
36586
35635
 
36587
- const Waveform = React.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,
35636
+ const Waveform = React.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,
36588
35637
  // New features
36589
35638
  loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel = 1, zoomCenter = 0.5, onZoomChange, enableAnimations = true, showRMS = false, rmsData, markers = [], enablePerformanceMonitoring = false, onPerformanceMetrics, ...restProps }) => {
36590
35639
  const theme = useTheme();
@@ -36671,12 +35720,12 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36671
35720
  targetBars = maxVisibleBars || peaks.length;
36672
35721
  }
36673
35722
  else {
36674
- // For fixed width, calculate how many bars fit
36675
- const maxBars = Math.floor(width / totalBarSpace);
35723
+ // For fixed w, calculate how many bars fit
35724
+ const maxBars = Math.floor(w / totalBarSpace);
36676
35725
  targetBars = maxVisibleBars ? Math.min(maxBars, maxVisibleBars) : maxBars;
36677
35726
  }
36678
35727
  if (targetBars <= 0) {
36679
- console.warn('Waveform: Not enough width to render any bars');
35728
+ console.warn('Waveform: Not enough w to render any bars');
36680
35729
  return [];
36681
35730
  }
36682
35731
  // If we have fewer peaks than target bars, return all peaks
@@ -36699,7 +35748,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36699
35748
  downsampled.push(maxValue);
36700
35749
  }
36701
35750
  return downsampled;
36702
- }, [peaks, width, barWidth, barGap, fullWidth, maxVisibleBars]);
35751
+ }, [peaks, w, barWidth, barGap, fullWidth, maxVisibleBars]);
36703
35752
  // Normalize peaks if requested
36704
35753
  const normalizedPeaks = React.useMemo(() => {
36705
35754
  if (!normalize || processedPeaks.length === 0) {
@@ -36722,16 +35771,16 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36722
35771
  if (fullWidth) {
36723
35772
  return {
36724
35773
  width: '100%',
36725
- height: height,
36726
- viewBox: `0 0 ${actualWaveformWidth} ${height}`,
35774
+ height: h,
35775
+ viewBox: `0 0 ${actualWaveformWidth} ${h}`,
36727
35776
  preserveAspectRatio: 'none'
36728
35777
  };
36729
35778
  }
36730
35779
  return {
36731
- width: width,
36732
- height: height
35780
+ width: w,
35781
+ height: h
36733
35782
  };
36734
- }, [fullWidth, actualWaveformWidth, height, width]);
35783
+ }, [fullWidth, actualWaveformWidth, h, w]);
36735
35784
  const handleLayout = React.useCallback((event) => {
36736
35785
  const { width: containerWidth, height: containerHeight } = event.nativeEvent.layout;
36737
35786
  setContainerDimensions({ width: containerWidth, height: containerHeight });
@@ -36746,7 +35795,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36746
35795
  }
36747
35796
  else {
36748
35797
  // Fallback if container hasn't been measured yet
36749
- position = locationX / (width || 300);
35798
+ position = locationX / (w || 300);
36750
35799
  }
36751
35800
  }
36752
35801
  else {
@@ -36754,7 +35803,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36754
35803
  position = Math.min(locationX, actualWaveformWidth) / actualWaveformWidth;
36755
35804
  }
36756
35805
  return Math.max(0, Math.min(1, position));
36757
- }, [fullWidth, containerDimensions.width, width, actualWaveformWidth]);
35806
+ }, [fullWidth, containerDimensions.width, w, actualWaveformWidth]);
36758
35807
  const handleResponderGrant = React.useCallback((event) => {
36759
35808
  var _a, _b, _c;
36760
35809
  if (!interactive)
@@ -36841,8 +35890,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36841
35890
  const renderBars = () => {
36842
35891
  return normalizedPeaks.map((peak, index) => {
36843
35892
  const x = index * (barWidth + barGap);
36844
- const barHeight = Math.max(minBarHeight, Math.abs(peak) * height * 0.8);
36845
- const y = (height - barHeight) / 2;
35893
+ const barHeight = Math.max(minBarHeight, Math.abs(peak) * h * 0.8);
35894
+ const y = (h - barHeight) / 2;
36846
35895
  const isProgress = x < progressX;
36847
35896
  const fillColor = isProgress ? actualProgressColor : waveformColor;
36848
35897
  return (jsxRuntime.jsx(Svg.Rect, { x: x, y: y, width: barWidth, height: barHeight, fill: fillColor, rx: variant === 'rounded' ? barWidth / 2 : 0 }, index));
@@ -36856,7 +35905,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36856
35905
  const stepX = actualWaveformWidth / (normalizedPeaks.length - 1);
36857
35906
  normalizedPeaks.forEach((peak, index) => {
36858
35907
  const x = index * stepX;
36859
- const y = height / 2 + (peak * height * 0.4);
35908
+ const y = h / 2 + (peak * h * 0.4);
36860
35909
  const lineCommand = index === 0 ? `M ${x} ${y}` : ` L ${x} ${y}`;
36861
35910
  pathData += lineCommand;
36862
35911
  // Build progress path up to the progress position
@@ -36870,8 +35919,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36870
35919
  const renderGradient = () => {
36871
35920
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Svg.Defs, { children: jsxRuntime.jsx(Svg.LinearGradient, { id: gradientId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: resolvedGradientColors.map((color, index) => (jsxRuntime.jsx(Svg.Stop, { offset: `${(index / (resolvedGradientColors.length - 1 || 1)) * 100}%`, stopColor: color }, index))) }) }), normalizedPeaks.map((peak, index) => {
36872
35921
  const x = index * (barWidth + barGap);
36873
- const barHeight = Math.max(minBarHeight, Math.abs(peak) * height * 0.8);
36874
- const y = (height - barHeight) / 2;
35922
+ const barHeight = Math.max(minBarHeight, Math.abs(peak) * h * 0.8);
35923
+ const y = (h - barHeight) / 2;
36875
35924
  return (jsxRuntime.jsx(Svg.Rect, { x: x, y: y, width: barWidth, height: barHeight, fill: `url(#${gradientId})` }, index));
36876
35925
  })] }));
36877
35926
  };
@@ -36881,8 +35930,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36881
35930
  return null;
36882
35931
  const clampedProgress = Math.max(0, Math.min(1, progress));
36883
35932
  const progressX = clampedProgress * actualWaveformWidth;
36884
- return (jsxRuntime.jsx(Svg.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 }));
36885
- }, [showProgressLine, progress, actualWaveformWidth, height, progressLineStyle, theme.colors.gray]);
35933
+ return (jsxRuntime.jsx(Svg.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 }));
35934
+ }, [showProgressLine, progress, actualWaveformWidth, h, progressLineStyle, theme.colors.gray]);
36886
35935
  // Timestamp markers component
36887
35936
  const TimeStamps = React.useMemo(() => {
36888
35937
  if (!showTimeStamps || !duration || !timeStampInterval)
@@ -36903,10 +35952,10 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36903
35952
  }
36904
35953
  return `${mins}:${secs.toString().padStart(2, '0')}`;
36905
35954
  };
36906
- timestamps.push(jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx(Svg.Line, { x1: x, y1: height - 10, x2: x, y2: height, stroke: theme.colors.gray[5], strokeWidth: 1, strokeOpacity: 0.6 }), jsxRuntime.jsx(Svg.Text, { x: x, y: height + 15, fill: theme.colors.gray[6], fontSize: 10, textAnchor: "middle", opacity: 0.8, children: formatTime(time) })] }, i));
35955
+ timestamps.push(jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx(Svg.Line, { x1: x, y1: h - 10, x2: x, y2: h, stroke: theme.colors.gray[5], strokeWidth: 1, strokeOpacity: 0.6 }), jsxRuntime.jsx(Svg.Text, { x: x, y: h + 15, fill: theme.colors.gray[6], fontSize: 10, textAnchor: "middle", opacity: 0.8, children: formatTime(time) })] }, i));
36907
35956
  }
36908
35957
  return jsxRuntime.jsx(Svg.G, { children: timestamps });
36909
- }, [showTimeStamps, duration, timeStampInterval, actualWaveformWidth, height, theme.colors]);
35958
+ }, [showTimeStamps, duration, timeStampInterval, actualWaveformWidth, h, theme.colors]);
36910
35959
  // Selection overlay component
36911
35960
  const SelectionOverlay = React.useMemo(() => {
36912
35961
  if (!selection || selection[0] === selection[1])
@@ -36915,8 +35964,8 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36915
35964
  const startX = start * actualWaveformWidth;
36916
35965
  const endX = end * actualWaveformWidth;
36917
35966
  const selectionWidth = endX - startX;
36918
- return (jsxRuntime.jsx(Svg.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 }));
36919
- }, [selection, actualWaveformWidth, height, theme.colors.primary]);
35967
+ return (jsxRuntime.jsx(Svg.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 }));
35968
+ }, [selection, actualWaveformWidth, h, theme.colors.primary]);
36920
35969
  // Markers component
36921
35970
  const Markers = React.useMemo(() => {
36922
35971
  if (!markers || markers.length === 0)
@@ -36926,16 +35975,16 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36926
35975
  const markerColor = marker.color || theme.colors.warning[5];
36927
35976
  switch (marker.type || 'line') {
36928
35977
  case 'line':
36929
- return (jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx(Svg.Line, { x1: x, y1: 0, x2: x, y2: height, stroke: markerColor, strokeWidth: 2, strokeOpacity: 0.8 }), marker.label && (jsxRuntime.jsx(Svg.Text, { x: x, y: -5, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
35978
+ return (jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx(Svg.Line, { x1: x, y1: 0, x2: x, y2: h, stroke: markerColor, strokeWidth: 2, strokeOpacity: 0.8 }), marker.label && (jsxRuntime.jsx(Svg.Text, { x: x, y: -5, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
36930
35979
  case 'flag':
36931
- return (jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx(Svg.Line, { x1: x, y1: 0, x2: x, y2: height, stroke: markerColor, strokeWidth: 1, strokeOpacity: 0.6 }), jsxRuntime.jsx(Svg.Rect, { x: x + 2, y: 2, width: marker.label ? marker.label.length * 6 + 4 : 20, height: 14, fill: markerColor, rx: 2 }), marker.label && (jsxRuntime.jsx(Svg.Text, { x: x + 4, y: 12, fill: "white", fontSize: 9, fontWeight: "bold", children: marker.label }))] }, index));
35980
+ return (jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx(Svg.Line, { x1: x, y1: 0, x2: x, y2: h, stroke: markerColor, strokeWidth: 1, strokeOpacity: 0.6 }), jsxRuntime.jsx(Svg.Rect, { x: x + 2, y: 2, width: marker.label ? marker.label.length * 6 + 4 : 20, height: 14, fill: markerColor, rx: 2 }), marker.label && (jsxRuntime.jsx(Svg.Text, { x: x + 4, y: 12, fill: "white", fontSize: 9, fontWeight: "bold", children: marker.label }))] }, index));
36932
35981
  case 'dot':
36933
- return (jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx("circle", { cx: x, cy: height / 2, r: 4, fill: markerColor, stroke: "white", strokeWidth: 1 }), marker.label && (jsxRuntime.jsx(Svg.Text, { x: x, y: height / 2 + 20, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
35982
+ return (jsxRuntime.jsxs(Svg.G, { children: [jsxRuntime.jsx("circle", { cx: x, cy: h / 2, r: 4, fill: markerColor, stroke: "white", strokeWidth: 1 }), marker.label && (jsxRuntime.jsx(Svg.Text, { x: x, y: h / 2 + 20, fill: markerColor, fontSize: 10, textAnchor: "middle", fontWeight: "bold", children: marker.label }))] }, index));
36934
35983
  default:
36935
35984
  return null;
36936
35985
  }
36937
35986
  }) }));
36938
- }, [markers, actualWaveformWidth, height, theme.colors.warning]);
35987
+ }, [markers, actualWaveformWidth, h, theme.colors.warning]);
36939
35988
  // RMS visualization component
36940
35989
  const RMSBars = React.useMemo(() => {
36941
35990
  if (!showRMS || !rmsData || rmsData.length === 0)
@@ -36943,11 +35992,11 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36943
35992
  const processedRMS = rmsData.slice(0, normalizedPeaks.length);
36944
35993
  return (jsxRuntime.jsx(Svg.G, { opacity: 0.5, children: processedRMS.map((rms, index) => {
36945
35994
  const x = index * (barWidth + barGap);
36946
- const rmsHeight = Math.max(minBarHeight, Math.abs(rms) * height * 0.4); // RMS bars are shorter
36947
- const y = (height - rmsHeight) / 2;
35995
+ const rmsHeight = Math.max(minBarHeight, Math.abs(rms) * h * 0.4); // RMS bars are shorter
35996
+ const y = (h - rmsHeight) / 2;
36948
35997
  return (jsxRuntime.jsx(Svg.Rect, { x: x, y: y, width: barWidth, height: rmsHeight, fill: theme.colors.gray[4], rx: variant === 'rounded' ? barWidth / 2 : 0 }, `rms-${index}`));
36949
35998
  }) }));
36950
- }, [showRMS, rmsData, normalizedPeaks, barWidth, barGap, minBarHeight, height, variant, theme.colors.gray]);
35999
+ }, [showRMS, rmsData, normalizedPeaks, barWidth, barGap, minBarHeight, h, variant, theme.colors.gray]);
36951
36000
  const renderWaveform = () => {
36952
36001
  switch (variant) {
36953
36002
  case 'line':
@@ -36984,17 +36033,17 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
36984
36033
  };
36985
36034
  // Early return for empty state
36986
36035
  if (normalizedPeaks.length === 0) {
36987
- return (jsxRuntime.jsx(reactNative.View, { style: [style, fullWidth ? { width: '100%' } : { width }, { height, justifyContent: 'center', alignItems: 'center' }], accessibilityRole: "image", accessibilityLabel: accessibilityLabel || 'Empty waveform', ...restProps, children: jsxRuntime.jsx(Svg, { ...svgProps, children: jsxRuntime.jsx(Svg.Rect, { x: 0, y: height / 2 - 1, width: fullWidth ? '100%' : width, height: 2, fill: waveformColor, opacity: 0.3 }) }) }));
36036
+ return (jsxRuntime.jsx(reactNative.View, { style: [style, fullWidth ? { width: '100%' } : { width: w }, { height: h, justifyContent: 'center', alignItems: 'center' }], accessibilityRole: "image", accessibilityLabel: accessibilityLabel || 'Empty waveform', ...restProps, children: jsxRuntime.jsx(Svg, { ...svgProps, children: jsxRuntime.jsx(Svg.Rect, { x: 0, y: h / 2 - 1, width: fullWidth ? '100%' : w, height: 2, fill: waveformColor, opacity: 0.3 }) }) }));
36988
36037
  }
36989
36038
  if (loading) {
36990
- return (jsxRuntime.jsx(WaveformSkeleton, { width: width, height: height, fullWidth: fullWidth, barsCount: maxVisibleBars || 20 }));
36039
+ return (jsxRuntime.jsx(WaveformSkeleton, { w: w, h: h, fullWidth: fullWidth, barsCount: maxVisibleBars || 20 }));
36991
36040
  }
36992
36041
  if (error) {
36993
36042
  return (jsxRuntime.jsx(reactNative.View, { style: [
36994
36043
  style,
36995
- fullWidth ? { width: '100%' } : { width },
36044
+ fullWidth ? { width: '100%' } : { width: w },
36996
36045
  {
36997
- height,
36046
+ height: h,
36998
36047
  justifyContent: 'center',
36999
36048
  alignItems: 'center',
37000
36049
  backgroundColor: theme.colors.error[1],
@@ -37004,7 +36053,7 @@ loading = false, error, loadingProgress, selection, onSelectionChange, zoomLevel
37004
36053
  }
37005
36054
  ], accessibilityRole: "alert", accessibilityLabel: `Waveform error: ${error}`, ...restProps, children: jsxRuntime.jsx(reactNative.Text, { style: { color: theme.colors.error[7], fontSize: 12, textAlign: 'center' }, children: error }) }));
37006
36055
  }
37007
- return (jsxRuntime.jsx(WrapperComponent, { ref: containerRef, style: [style, fullWidth ? { width: '100%' } : { width }], accessible: true, focusable: interactive, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), ...wrapperProps, ...restProps, children: jsxRuntime.jsxs(Svg, { ...svgProps, children: [SelectionOverlay, RMSBars, renderWaveform(), ProgressLine, TimeStamps, Markers] }) }));
36056
+ return (jsxRuntime.jsx(WrapperComponent, { ref: containerRef, style: [style, fullWidth ? { width: '100%' } : { width: w }], accessible: true, focusable: interactive, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), ...wrapperProps, ...restProps, children: jsxRuntime.jsxs(Svg, { ...svgProps, children: [SelectionOverlay, RMSBars, renderWaveform(), ProgressLine, TimeStamps, Markers] }) }));
37008
36057
  });
37009
36058
  Waveform.displayName = 'Waveform';
37010
36059
 
@@ -37026,7 +36075,7 @@ const AudioPlayer = React.forwardRef(({ source, peaks: providedPeaks, autoPlay =
37026
36075
  channel: 'mix',
37027
36076
  }, showTime = true, timeFormat = 'mm:ss', showMetadata = false, metadata, showSpectrum = false, spectrumOptions, enableKeyboardShortcuts = true, enableGestures = true, onLoad, onPlaybackStateChange, onProgress, onEnd, onError, onBuffer,
37028
36077
  // Waveform props
37029
- width = 300, height = 60, color = 'primary', interactive = true, onSeek, style, ...waveformProps }, ref) => {
36078
+ w = 300, h = 60, color = 'primary', interactive = true, onSeek, style, ...waveformProps }, ref) => {
37030
36079
  const theme = useTheme();
37031
36080
  const { playSound } = useSound();
37032
36081
  // Refs
@@ -37373,7 +36422,7 @@ width = 300, height = 60, color = 'primary', interactive = true, onSeek, style,
37373
36422
  alignSelf: 'flex-start',
37374
36423
  }, children: jsxRuntime.jsx(reactNative.Text, { style: { color: 'white', fontSize: DESIGN_TOKENS.typography.fontSize.sm }, children: "Retry" }) }))] }));
37375
36424
  }
37376
- return (jsxRuntime.jsxs(reactNative.View, { style: [{ width: '100%' }, style], children: [controlsPosition === 'top' && renderMetadata(), controlsPosition === 'top' && renderControls(), controls.waveform && peaks.length > 0 && (jsxRuntime.jsx(reactNative.View, { style: { marginVertical: DESIGN_TOKENS.spacing.sm }, children: jsxRuntime.jsx(Waveform, { peaks: peaks, width: width, height: height, color: color, progress: progress, interactive: interactive, onSeek: handleWaveformSeek, showProgressLine: true, progressLineStyle: {
36425
+ return (jsxRuntime.jsxs(reactNative.View, { style: [{ width: '100%' }, style], children: [controlsPosition === 'top' && renderMetadata(), controlsPosition === 'top' && renderControls(), controls.waveform && peaks.length > 0 && (jsxRuntime.jsx(reactNative.View, { style: { marginVertical: DESIGN_TOKENS.spacing.sm }, children: jsxRuntime.jsx(Waveform, { peaks: peaks, w: w, h: h, color: color, progress: progress, interactive: interactive, onSeek: handleWaveformSeek, showProgressLine: true, progressLineStyle: {
37377
36426
  color: theme.colors.primary[5],
37378
36427
  width: 2,
37379
36428
  opacity: 0.8,
@@ -38102,14 +37151,14 @@ const IMAGE_SIZES = {
38102
37151
  '2xl': 80,
38103
37152
  '3xl': 96,
38104
37153
  };
38105
- 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 }) {
37154
+ 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 }) {
38106
37155
  const theme = useTheme();
38107
37156
  const [loadError, setLoadError] = React.useState(false);
38108
37157
  const [isLoading, setIsLoading] = React.useState(true);
38109
37158
  const { spacingProps } = extractSpacingProps(rest);
38110
37159
  // Determine dimensions
38111
- let finalWidth = width;
38112
- let finalHeight = height;
37160
+ let finalWidth = w;
37161
+ let finalHeight = h;
38113
37162
  if (size && typeof size === 'string' && IMAGE_SIZES[size]) {
38114
37163
  finalWidth = finalWidth || IMAGE_SIZES[size];
38115
37164
  finalHeight = finalHeight || IMAGE_SIZES[size];
@@ -39894,11 +38943,14 @@ QRCodeSVG.displayName = 'QRCodeSVG';
39894
38943
  */
39895
38944
  function QRCode(props) {
39896
38945
  var _a;
38946
+ const theme = useTheme();
39897
38947
  const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
39898
38948
  const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
39899
- const { value, size = 400, backgroundColor = 'transparent', color = '#000000', errorCorrectionLevel = 'M', quietZone = 4, logo, style, testID, accessibilityLabel, onError, onLoadStart, // deprecated noop
38949
+ const { value, size = 400, backgroundColor = 'transparent', color, errorCorrectionLevel = 'M', quietZone = 4, logo, style, testID, accessibilityLabel, onError, onLoadStart, // deprecated noop
39900
38950
  onLoadEnd, // deprecated noop
39901
38951
  ...rest } = otherProps;
38952
+ // Default color to theme's primary text color for dark mode support
38953
+ const resolvedColor = color !== null && color !== void 0 ? color : theme.text.primary;
39902
38954
  const { copy } = useClipboard();
39903
38955
  const toast = useToast();
39904
38956
  const shouldCopyOnPress = !!otherProps.copyOnPress;
@@ -39914,7 +38966,7 @@ function QRCode(props) {
39914
38966
  });
39915
38967
  }
39916
38968
  }, [copy, copyValue, toast, otherProps.copyToastMessage, otherProps.copyToastTitle]);
39917
- const content = (jsxRuntime.jsxs(reactNative.View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsxRuntime.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 && (jsxRuntime.jsx(CopyButton, { value: copyValue, iconOnly: true, size: "sm", style: { position: 'absolute', top: 8, right: 8 }, onCopy: () => { } }))] }));
38969
+ const content = (jsxRuntime.jsxs(reactNative.View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsxRuntime.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 && (jsxRuntime.jsx(CopyButton, { value: copyValue, iconOnly: true, size: "sm", style: { position: 'absolute', top: 8, right: 8 }, onCopy: () => { } }))] }));
39918
38970
  if (shouldCopyOnPress) {
39919
38971
  return (jsxRuntime.jsx(reactNative.Pressable, { onPress: handleCopy, accessibilityLabel: accessibilityLabel || 'QR code', children: content }));
39920
38972
  }
@@ -40564,111 +39616,6 @@ const styles$2 = reactNative.StyleSheet.create({
40564
39616
  },
40565
39617
  });
40566
39618
 
40567
- // Optional imports for web compatibility
40568
- const LottieReact = reactNative.Platform.OS === 'web'
40569
- ? resolveOptionalModule('lottie-react', {
40570
- accessor: mod => { var _a; return (_a = mod.default) !== null && _a !== void 0 ? _a : mod; },
40571
- })
40572
- : null;
40573
- const DotLottieReact = reactNative.Platform.OS === 'web'
40574
- ? resolveOptionalModule('@lottiefiles/dotlottie-react', {
40575
- accessor: mod => mod.DotLottieReact,
40576
- })
40577
- : null;
40578
- let cachedNativeStatus = null;
40579
- let nativeLottieComponent;
40580
- let nativeModuleLoadWarningLogged = false;
40581
- let nativeModuleConfigWarningLogged = false;
40582
- const loadNativeLottieComponent = () => {
40583
- if (nativeLottieComponent !== undefined) {
40584
- return nativeLottieComponent;
40585
- }
40586
- const module = resolveOptionalModule('lottie-react-native', {
40587
- accessor: mod => { var _a; return (_a = mod === null || mod === void 0 ? void 0 : mod.default) !== null && _a !== void 0 ? _a : mod; },
40588
- });
40589
- if (!module && !nativeModuleLoadWarningLogged && __DEV__) {
40590
- console.warn('[Lottie] Failed to load lottie-react-native module. Rendering fallback instead.');
40591
- nativeModuleLoadWarningLogged = true;
40592
- }
40593
- nativeLottieComponent = module !== null && module !== void 0 ? module : null;
40594
- return nativeLottieComponent;
40595
- };
40596
- const getNativeLottieStatus = () => {
40597
- var _a, _b, _c;
40598
- if (cachedNativeStatus) {
40599
- return cachedNativeStatus;
40600
- }
40601
- if (reactNative.Platform.OS === 'web') {
40602
- cachedNativeStatus = { component: null, available: false };
40603
- return cachedNativeStatus;
40604
- }
40605
- const component = loadNativeLottieComponent();
40606
- if (!component) {
40607
- cachedNativeStatus = { component: null, available: false };
40608
- return cachedNativeStatus;
40609
- }
40610
- let viewManagerAvailable = false;
40611
- try {
40612
- const viewManager = (_c = (_b = (_a = reactNative.UIManager === null || reactNative.UIManager === void 0 ? void 0 : reactNative.UIManager.getViewManagerConfig) === null || _a === void 0 ? void 0 : _a.call(reactNative.UIManager, 'LottieAnimationView')) !== null && _b !== void 0 ? _b : reactNative.UIManager === null || reactNative.UIManager === void 0 ? void 0 : reactNative.UIManager.LottieAnimationView) !== null && _c !== void 0 ? _c : reactNative.NativeModules === null || reactNative.NativeModules === void 0 ? void 0 : reactNative.NativeModules.LottieAnimationView;
40613
- viewManagerAvailable = !!viewManager;
40614
- }
40615
- catch (error) {
40616
- viewManagerAvailable = false;
40617
- }
40618
- if (!viewManagerAvailable && !nativeModuleConfigWarningLogged && __DEV__) {
40619
- console.warn('[Lottie] Native LottieAnimationView is unavailable. Run `npx expo install lottie-react-native` and rebuild to enable animations.');
40620
- nativeModuleConfigWarningLogged = true;
40621
- }
40622
- cachedNativeStatus = {
40623
- component,
40624
- available: viewManagerAvailable,
40625
- };
40626
- return cachedNativeStatus;
40627
- };
40628
- /**
40629
- * Lottie component with safe fallback when native module not present or on unsupported platforms.
40630
- */
40631
- const Lottie = React.forwardRef(function LottieCmp(props, ref) {
40632
- const { source, autoPlay = true, loop = true, progress, speed = 1, style, testID, paused, resizeMode = 'contain', onAnimationFinish } = props;
40633
- const internalRef = React.useRef(null);
40634
- const nativeStatus = getNativeLottieStatus();
40635
- const NativeLottieView = nativeStatus.component;
40636
- React.useImperativeHandle(ref, () => ({
40637
- 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); },
40638
- 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); },
40639
- 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); },
40640
- 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); },
40641
- }), []);
40642
- React.useEffect(() => {
40643
- var _a;
40644
- if (progress != null && ((_a = internalRef.current) === null || _a === void 0 ? void 0 : _a.setProgress)) {
40645
- internalRef.current.setProgress(progress);
40646
- }
40647
- }, [progress]);
40648
- // Web implementation
40649
- if (reactNative.Platform.OS === 'web') {
40650
- // Check if source is a string (URL) and ends with .lottie
40651
- const isLottieFile = typeof source === 'string' && source.endsWith('.lottie');
40652
- if (isLottieFile && DotLottieReact) {
40653
- // Use DotLottieReact for .lottie files
40654
- return (jsxRuntime.jsx(DotLottieReact, { src: source, autoplay: autoPlay, loop: loop, speed: speed, style: style, "data-testid": testID }));
40655
- }
40656
- else if (LottieReact) {
40657
- // Use lottie-react for standard Lottie JSON
40658
- return (jsxRuntime.jsx(LottieReact, { animationData: source, autoplay: autoPlay, loop: loop, style: style, "data-testid": testID }));
40659
- }
40660
- else {
40661
- return jsxRuntime.jsx(Text, { children: "Lottie not available on web" });
40662
- }
40663
- }
40664
- // Native implementation using lottie-react-native
40665
- if (!nativeStatus.available || !NativeLottieView) {
40666
- return (jsxRuntime.jsx(reactNative.View, { style: [{ justifyContent: 'center', alignItems: 'center' }, style], testID: testID, children: jsxRuntime.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." }) }));
40667
- }
40668
- return (jsxRuntime.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 } : {}) }));
40669
- });
40670
- Lottie.displayName = 'Lottie';
40671
-
40672
39619
  const PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
40673
39620
  function formatTime(seconds) {
40674
39621
  const hours = Math.floor(seconds / 3600);
@@ -41616,7 +40563,7 @@ const DEFAULT_CONTROLS = {
41616
40563
  autoHide: true,
41617
40564
  autoHideTimeout: 3000,
41618
40565
  };
41619
- const Video = React.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) => {
40566
+ const Video = React.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) => {
41620
40567
  const theme = useTheme();
41621
40568
  const { spacingProps } = extractSpacingProps(rest);
41622
40569
  // Internal state
@@ -41866,24 +40813,24 @@ const Video = React.forwardRef(({ source, width, height, aspectRatio = 16 / 9, p
41866
40813
  // overflow: 'hidden',
41867
40814
  // position: 'relative',
41868
40815
  };
41869
- if (width && height) {
41870
- baseStyle.width = width;
41871
- baseStyle.height = height;
40816
+ if (w && h) {
40817
+ baseStyle.width = w;
40818
+ baseStyle.height = h;
41872
40819
  }
41873
- else if (width) {
41874
- baseStyle.width = width;
41875
- baseStyle.height = typeof width === 'number' ? width / aspectRatio : '100%';
40820
+ else if (w) {
40821
+ baseStyle.width = w;
40822
+ baseStyle.height = typeof w === 'number' ? w / aspectRatio : '100%';
41876
40823
  }
41877
- else if (height) {
41878
- baseStyle.height = height;
41879
- baseStyle.width = typeof height === 'number' ? height * aspectRatio : '100%';
40824
+ else if (h) {
40825
+ baseStyle.height = h;
40826
+ baseStyle.width = typeof h === 'number' ? h * aspectRatio : '100%';
41880
40827
  }
41881
40828
  else {
41882
40829
  baseStyle.width = '100%';
41883
40830
  baseStyle.aspectRatio = aspectRatio;
41884
40831
  }
41885
40832
  return baseStyle;
41886
- }, [theme.colors.surface, width, height, aspectRatio]);
40833
+ }, [theme.colors.surface, w, h, aspectRatio]);
41887
40834
  // Handle touch events for control visibility
41888
40835
  const handleContainerPress = React.useCallback(() => {
41889
40836
  if (controlsConfig && controlsConfig.autoHide) {
@@ -41987,7 +40934,6 @@ function withPressAnimation(Component, animationProps) {
41987
40934
  */
41988
40935
  const AnimatedPressable = PressAnimation;
41989
40936
 
41990
- exports.AbilityCore = AbilityCore;
41991
40937
  exports.AccessibilityProvider = AccessibilityProvider;
41992
40938
  exports.Accordion = Accordion;
41993
40939
  exports.AmazonAppstoreBadge = AmazonAppstoreBadge;
@@ -42027,9 +40973,6 @@ exports.Button = Button;
42027
40973
  exports.COMPONENT_SIZES = COMPONENT_SIZES$1;
42028
40974
  exports.COMPONENT_SIZE_ORDER = COMPONENT_SIZE_ORDER;
42029
40975
  exports.Calendar = Calendar;
42030
- exports.Can = Can;
42031
- exports.CanWithConditions = CanWithConditions;
42032
- exports.Cannot = Cannot;
42033
40976
  exports.Card = Card;
42034
40977
  exports.Carousel = Carousel;
42035
40978
  exports.Checkbox = Checkbox;
@@ -42090,7 +41033,6 @@ exports.Heading4 = Heading4;
42090
41033
  exports.Heading5 = Heading5;
42091
41034
  exports.Heading6 = Heading6;
42092
41035
  exports.Highlight = Highlight;
42093
- exports.HoverCard = HoverCard;
42094
41036
  exports.HuaweiAppGalleryBadge = HuaweiAppGalleryBadge;
42095
41037
  exports.I18nProvider = I18nProvider;
42096
41038
  exports.Icon = Icon;
@@ -42111,7 +41053,6 @@ exports.ListGroupDivider = ListGroupDivider;
42111
41053
  exports.ListGroupItem = ListGroupItem;
42112
41054
  exports.Loader = Loader;
42113
41055
  exports.LoadingOverlay = LoadingOverlay;
42114
- exports.Lottie = Lottie;
42115
41056
  exports.MacAppStoreButton = MacAppStoreButton;
42116
41057
  exports.Mark = Mark;
42117
41058
  exports.Markdown = Markdown;
@@ -42128,7 +41069,6 @@ exports.MiniCalendar = MiniCalendar;
42128
41069
  exports.Month = Month;
42129
41070
  exports.MonthPicker = MonthPicker;
42130
41071
  exports.MonthPickerInput = MonthPickerInput;
42131
- exports.NavigationProgress = NavigationProgress;
42132
41072
  exports.Notice = Notice;
42133
41073
  exports.NumberInput = NumberInput;
42134
41074
  exports.Overlay = Overlay;
@@ -42136,10 +41076,6 @@ exports.OverlayProvider = OverlayProvider;
42136
41076
  exports.P = P;
42137
41077
  exports.Pagination = Pagination;
42138
41078
  exports.PasswordInput = PasswordInput;
42139
- exports.PermissionBuilder = PermissionBuilder;
42140
- exports.PermissionGate = PermissionGate;
42141
- exports.PermissionPatterns = PermissionPatterns;
42142
- exports.PermissionProvider = PermissionProvider;
42143
41079
  exports.PhoneInput = PhoneInput;
42144
41080
  exports.PinInput = PinInput;
42145
41081
  exports.PlatformBlocksProvider = PlatformBlocksProvider;
@@ -42152,9 +41088,7 @@ exports.RadioGroup = RadioGroup;
42152
41088
  exports.RangeSlider = RangeSlider;
42153
41089
  exports.Rating = Rating;
42154
41090
  exports.RedditJoinBadge = RedditJoinBadge;
42155
- exports.RichTextEditor = RichTextEditor;
42156
41091
  exports.Ring = Ring;
42157
- exports.RoleBuilder = RoleBuilder;
42158
41092
  exports.Row = Row;
42159
41093
  exports.SIZE_SCALES = SIZE_SCALES;
42160
41094
  exports.Search = Search;
@@ -42212,9 +41146,7 @@ exports.createSound = createSound;
42212
41146
  exports.createSpotlightStore = createSpotlightStore;
42213
41147
  exports.createTheme = createTheme;
42214
41148
  exports.debounce = debounce$1;
42215
- exports.defineAbility = defineAbility;
42216
41149
  exports.defineAppLayout = defineAppLayout;
42217
- exports.defineRoleAbility = defineRoleAbility;
42218
41150
  exports.directSpotlight = directSpotlight;
42219
41151
  exports.extractDisclaimerProps = extractDisclaimerProps;
42220
41152
  exports.factory = factory;
@@ -42235,11 +41167,9 @@ exports.globalHotkeys = globalHotkeys;
42235
41167
  exports.measureAsyncPerformance = measureAsyncPerformance;
42236
41168
  exports.measureElement = measureElement;
42237
41169
  exports.measurePerformance = measurePerformance;
42238
- exports.navigationProgress = navigationProgress;
42239
41170
  exports.onDialogsRequested = onDialogsRequested;
42240
41171
  exports.onSpotlightRequested = onSpotlightRequested;
42241
41172
  exports.onToastsRequested = onToastsRequested;
42242
- exports.permissions = permissions;
42243
41173
  exports.pointInRect = pointInRect;
42244
41174
  exports.polymorphicFactory = polymorphicFactory;
42245
41175
  exports.px = px;
@@ -42250,7 +41180,6 @@ exports.resolveResponsiveValue = resolveResponsiveValue;
42250
41180
  exports.resolveSize = resolveSize;
42251
41181
  exports.spotlight = spotlight;
42252
41182
  exports.throttle = throttle;
42253
- exports.useAbility = useAbility;
42254
41183
  exports.useAccessibility = useAccessibility;
42255
41184
  exports.useAppLayoutContext = useAppLayoutContext;
42256
41185
  exports.useAppShell = useAppShell;
@@ -42280,7 +41209,6 @@ exports.useOptionalFormContext = useOptionalFormContext;
42280
41209
  exports.useOverlay = useOverlay;
42281
41210
  exports.useOverlayApi = useOverlayApi;
42282
41211
  exports.useOverlays = useOverlays;
42283
- exports.usePermissions = usePermissions;
42284
41212
  exports.usePopoverPositioning = usePopoverPositioning;
42285
41213
  exports.useSimpleDialog = useSimpleDialog;
42286
41214
  exports.useSound = useSound;
@@ -42295,8 +41223,6 @@ exports.useToast = useToast;
42295
41223
  exports.useToastApi = useToastApi;
42296
41224
  exports.useToggleColorScheme = useToggleColorScheme;
42297
41225
  exports.useTooltipPositioning = useTooltipPositioning;
42298
- exports.withCan = withCan;
42299
- exports.withCannot = withCannot;
42300
41226
  exports.withDisclaimer = withDisclaimer;
42301
41227
  exports.withPressAnimation = withPressAnimation;
42302
41228
  //# sourceMappingURL=index.js.map