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