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