app-studio 0.6.59 → 0.6.60
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/dist/app-studio.cjs.development.js +427 -116
- package/dist/app-studio.cjs.development.js.map +1 -1
- package/dist/app-studio.cjs.production.min.js +1 -1
- package/dist/app-studio.esm.js +420 -117
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +427 -116
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/hooks/useClickOutside.d.ts +5 -1
- package/dist/hooks/useElementPosition.d.ts +2 -0
- package/dist/hooks/useIframeStyles.d.ts +41 -0
- package/dist/hooks/useInView.d.ts +2 -0
- package/dist/hooks/useOnScreen.d.ts +5 -1
- package/dist/hooks/useResponsive.d.ts +46 -0
- package/dist/hooks/useScroll.d.ts +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/providers/Responsive.d.ts +38 -4
- package/dist/providers/Theme.d.ts +2 -1
- package/dist/providers/WindowSize.d.ts +5 -2
- package/dist/stories/IframeCSSSupport.stories.d.ts +28 -0
- package/dist/stories/IframeSupport.stories.d.ts +16 -0
- package/dist/stories/ScrollTimeline.stories.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1072,7 +1072,8 @@ const ThemeProvider = _ref => {
|
|
|
1072
1072
|
dark: darkOverride = {},
|
|
1073
1073
|
light: lightOverride = {},
|
|
1074
1074
|
children,
|
|
1075
|
-
strict = false
|
|
1075
|
+
strict = false,
|
|
1076
|
+
targetWindow
|
|
1076
1077
|
} = _ref;
|
|
1077
1078
|
const [themeMode, setThemeMode] = React.useState(initialMode);
|
|
1078
1079
|
const colorCache = React.useRef(new Map()).current;
|
|
@@ -1394,9 +1395,34 @@ const ThemeProvider = _ref => {
|
|
|
1394
1395
|
themeMode,
|
|
1395
1396
|
setThemeMode
|
|
1396
1397
|
}), [getColor, getColorHex, getColorRGBA, getColorScheme, getContrastColor, mergedTheme, currentColors, themeMode]);
|
|
1398
|
+
// Generate CSS variables
|
|
1399
|
+
const cssVariables = React.useMemo(() => generateCSSVariables(mergedTheme, themeColors.light, themeColors.dark), [mergedTheme, themeColors]);
|
|
1400
|
+
// Inject CSS variables into target document (for iframe support)
|
|
1401
|
+
React.useEffect(() => {
|
|
1402
|
+
if (!targetWindow) return;
|
|
1403
|
+
const targetDoc = targetWindow.document;
|
|
1404
|
+
const styleId = 'app-studio-theme-vars';
|
|
1405
|
+
// Remove existing style tag if any
|
|
1406
|
+
const existing = targetDoc.getElementById(styleId);
|
|
1407
|
+
if (existing) {
|
|
1408
|
+
existing.remove();
|
|
1409
|
+
}
|
|
1410
|
+
// Create and inject new style tag
|
|
1411
|
+
const styleTag = targetDoc.createElement('style');
|
|
1412
|
+
styleTag.id = styleId;
|
|
1413
|
+
styleTag.textContent = cssVariables;
|
|
1414
|
+
targetDoc.head.appendChild(styleTag);
|
|
1415
|
+
// Cleanup on unmount
|
|
1416
|
+
return () => {
|
|
1417
|
+
const styleToRemove = targetDoc.getElementById(styleId);
|
|
1418
|
+
if (styleToRemove) {
|
|
1419
|
+
styleToRemove.remove();
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
}, [targetWindow, cssVariables]);
|
|
1397
1423
|
return /*#__PURE__*/React__default.createElement(ThemeContext.Provider, {
|
|
1398
1424
|
value: contextValue
|
|
1399
|
-
}, /*#__PURE__*/React__default.createElement("style", null,
|
|
1425
|
+
}, !targetWindow && /*#__PURE__*/React__default.createElement("style", null, cssVariables), /*#__PURE__*/React__default.createElement("div", {
|
|
1400
1426
|
"data-theme": themeMode,
|
|
1401
1427
|
style: {
|
|
1402
1428
|
backgroundColor: 'white',
|
|
@@ -1465,32 +1491,57 @@ const debounce = (func, wait) => {
|
|
|
1465
1491
|
};
|
|
1466
1492
|
// Helper to compute breakpoint from width
|
|
1467
1493
|
const getBreakpointFromWidth = (width, breakpoints) => {
|
|
1468
|
-
// console.log('[ResponsiveProvider] Computing breakpoint for width:', width);
|
|
1469
|
-
// console.log('[ResponsiveProvider] Breakpoints config:', breakpoints);
|
|
1470
1494
|
const sortedBreakpoints = Object.entries(breakpoints).sort((_ref, _ref2) => {
|
|
1471
1495
|
let [, a] = _ref;
|
|
1472
1496
|
let [, b] = _ref2;
|
|
1473
1497
|
return b - a;
|
|
1474
1498
|
}); // Sort descending by min value
|
|
1475
|
-
// console.log('[ResponsiveProvider] Sorted breakpoints:', sortedBreakpoints);
|
|
1476
1499
|
for (const [name, minWidth] of sortedBreakpoints) {
|
|
1477
1500
|
if (width >= minWidth) {
|
|
1478
|
-
// console.log(
|
|
1479
|
-
// '[ResponsiveProvider] ✓ Match found:',
|
|
1480
|
-
// name,
|
|
1481
|
-
// 'for width',
|
|
1482
|
-
// width,
|
|
1483
|
-
// '>= minWidth',
|
|
1484
|
-
// minWidth
|
|
1485
|
-
// );
|
|
1486
1501
|
return name;
|
|
1487
1502
|
}
|
|
1488
1503
|
}
|
|
1489
1504
|
const fallback = sortedBreakpoints[sortedBreakpoints.length - 1]?.[0] || 'xs';
|
|
1490
|
-
// console.log('[ResponsiveProvider] No match, using fallback:', fallback);
|
|
1491
1505
|
return fallback;
|
|
1492
1506
|
};
|
|
1493
|
-
//
|
|
1507
|
+
// ============================================================================
|
|
1508
|
+
// SPLIT CONTEXTS FOR OPTIMIZED RE-RENDERS
|
|
1509
|
+
// ============================================================================
|
|
1510
|
+
// BreakpointContext - changes rarely (only on breakpoint threshold crossing)
|
|
1511
|
+
const defaultBreakpointConfig = {
|
|
1512
|
+
breakpoints: defaultBreakpointsConfig,
|
|
1513
|
+
devices: defaultDeviceConfig,
|
|
1514
|
+
mediaQueries: /*#__PURE__*/getMediaQueries(defaultBreakpointsConfig),
|
|
1515
|
+
currentBreakpoint: 'xs',
|
|
1516
|
+
currentDevice: 'mobile',
|
|
1517
|
+
orientation: 'portrait'
|
|
1518
|
+
};
|
|
1519
|
+
const BreakpointContext = /*#__PURE__*/React.createContext(defaultBreakpointConfig);
|
|
1520
|
+
// WindowDimensionsContext - changes often (on every resize)
|
|
1521
|
+
const defaultWindowDimensions = {
|
|
1522
|
+
width: 0,
|
|
1523
|
+
height: 0
|
|
1524
|
+
};
|
|
1525
|
+
const WindowDimensionsContext = /*#__PURE__*/React.createContext(defaultWindowDimensions);
|
|
1526
|
+
// ============================================================================
|
|
1527
|
+
// HOOKS FOR SPLIT CONTEXTS
|
|
1528
|
+
// ============================================================================
|
|
1529
|
+
/**
|
|
1530
|
+
* Hook to access breakpoint information only.
|
|
1531
|
+
* Components using this hook will NOT re-render on every resize,
|
|
1532
|
+
* only when the breakpoint actually changes.
|
|
1533
|
+
*/
|
|
1534
|
+
const useBreakpointContext = () => React.useContext(BreakpointContext);
|
|
1535
|
+
/**
|
|
1536
|
+
* Hook to access window dimensions.
|
|
1537
|
+
* Components using this hook WILL re-render on every resize.
|
|
1538
|
+
* Use sparingly - prefer useBreakpointContext when possible.
|
|
1539
|
+
*/
|
|
1540
|
+
const useWindowDimensionsContext = () => React.useContext(WindowDimensionsContext);
|
|
1541
|
+
// ============================================================================
|
|
1542
|
+
// LEGACY CONTEXT FOR BACKWARD COMPATIBILITY
|
|
1543
|
+
// ============================================================================
|
|
1544
|
+
// Create the combined Context with default values (for backward compatibility)
|
|
1494
1545
|
const ResponsiveContext = /*#__PURE__*/React.createContext({
|
|
1495
1546
|
breakpoints: defaultBreakpointsConfig,
|
|
1496
1547
|
devices: defaultDeviceConfig,
|
|
@@ -1501,56 +1552,63 @@ const ResponsiveContext = /*#__PURE__*/React.createContext({
|
|
|
1501
1552
|
currentDevice: 'mobile',
|
|
1502
1553
|
orientation: 'portrait'
|
|
1503
1554
|
});
|
|
1504
|
-
|
|
1555
|
+
/**
|
|
1556
|
+
* Legacy hook for backward compatibility.
|
|
1557
|
+
* Prefer useBreakpointContext for better performance.
|
|
1558
|
+
* @deprecated Use useBreakpointContext instead for better performance
|
|
1559
|
+
*/
|
|
1505
1560
|
const useResponsiveContext = () => React.useContext(ResponsiveContext);
|
|
1506
1561
|
const ResponsiveProvider = _ref3 => {
|
|
1507
1562
|
let {
|
|
1508
1563
|
breakpoints = defaultBreakpointsConfig,
|
|
1509
1564
|
devices = defaultDeviceConfig,
|
|
1510
|
-
children
|
|
1565
|
+
children,
|
|
1566
|
+
targetWindow
|
|
1511
1567
|
} = _ref3;
|
|
1568
|
+
const win = targetWindow || (typeof window !== 'undefined' ? window : null);
|
|
1569
|
+
// Track current breakpoint - only updates when crossing thresholds
|
|
1512
1570
|
const [screen, setScreen] = React.useState(() => {
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
return getBreakpointFromWidth(window.innerWidth, breakpoints);
|
|
1571
|
+
if (win) {
|
|
1572
|
+
return getBreakpointFromWidth(win.innerWidth, breakpoints);
|
|
1516
1573
|
}
|
|
1517
1574
|
return 'xs';
|
|
1518
1575
|
});
|
|
1576
|
+
// Track orientation - rarely changes
|
|
1519
1577
|
const [orientation, setOrientation] = React.useState('portrait');
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1578
|
+
// Track window dimensions - changes often
|
|
1579
|
+
const [dimensions, setDimensions] = React.useState({
|
|
1580
|
+
width: win?.innerWidth || 0,
|
|
1581
|
+
height: win?.innerHeight || 0
|
|
1523
1582
|
});
|
|
1583
|
+
// Use ref to track previous breakpoint to avoid unnecessary state updates
|
|
1584
|
+
const prevBreakpointRef = React.useRef(screen);
|
|
1524
1585
|
const mediaQueries = React.useMemo(() => getMediaQueries(breakpoints), [breakpoints]);
|
|
1525
1586
|
React.useEffect(() => {
|
|
1526
|
-
|
|
1587
|
+
if (!win) return;
|
|
1527
1588
|
// Set initial screen size immediately based on window width
|
|
1528
|
-
const initialScreen = getBreakpointFromWidth(
|
|
1529
|
-
// console.log(
|
|
1530
|
-
// '[ResponsiveProvider] Setting initial screen to:',
|
|
1531
|
-
// initialScreen
|
|
1532
|
-
// );
|
|
1589
|
+
const initialScreen = getBreakpointFromWidth(win.innerWidth, breakpoints);
|
|
1533
1590
|
setScreen(initialScreen);
|
|
1591
|
+
prevBreakpointRef.current = initialScreen;
|
|
1534
1592
|
const handleResize = () => {
|
|
1535
|
-
const newWidth =
|
|
1536
|
-
const newHeight =
|
|
1537
|
-
//
|
|
1538
|
-
|
|
1539
|
-
// height: newHeight,
|
|
1540
|
-
// });
|
|
1541
|
-
setSize({
|
|
1593
|
+
const newWidth = win.innerWidth;
|
|
1594
|
+
const newHeight = win.innerHeight;
|
|
1595
|
+
// Always update dimensions (WindowDimensionsContext will re-render)
|
|
1596
|
+
setDimensions({
|
|
1542
1597
|
width: newWidth,
|
|
1543
1598
|
height: newHeight
|
|
1544
1599
|
});
|
|
1545
|
-
//
|
|
1600
|
+
// Only update breakpoint if it actually changed
|
|
1601
|
+
// This prevents BreakpointContext from causing unnecessary re-renders
|
|
1546
1602
|
const newScreen = getBreakpointFromWidth(newWidth, breakpoints);
|
|
1547
|
-
|
|
1548
|
-
|
|
1603
|
+
if (newScreen !== prevBreakpointRef.current) {
|
|
1604
|
+
prevBreakpointRef.current = newScreen;
|
|
1605
|
+
setScreen(newScreen);
|
|
1606
|
+
}
|
|
1549
1607
|
};
|
|
1550
1608
|
const debouncedResize = debounce(handleResize, 100);
|
|
1551
|
-
|
|
1609
|
+
win.addEventListener('resize', debouncedResize);
|
|
1552
1610
|
// Set up orientation listener
|
|
1553
|
-
const orientationMql =
|
|
1611
|
+
const orientationMql = win.matchMedia('(orientation: landscape)');
|
|
1554
1612
|
const onOrientationChange = () => setOrientation(orientationMql.matches ? 'landscape' : 'portrait');
|
|
1555
1613
|
if (orientationMql.addEventListener) {
|
|
1556
1614
|
orientationMql.addEventListener('change', onOrientationChange);
|
|
@@ -1559,30 +1617,46 @@ const ResponsiveProvider = _ref3 => {
|
|
|
1559
1617
|
}
|
|
1560
1618
|
onOrientationChange();
|
|
1561
1619
|
return () => {
|
|
1562
|
-
|
|
1620
|
+
win.removeEventListener('resize', debouncedResize);
|
|
1563
1621
|
if (orientationMql.removeEventListener) {
|
|
1564
1622
|
orientationMql.removeEventListener('change', onOrientationChange);
|
|
1565
1623
|
} else {
|
|
1566
1624
|
orientationMql.removeListener(onOrientationChange);
|
|
1567
1625
|
}
|
|
1568
1626
|
};
|
|
1569
|
-
}, [breakpoints]);
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1627
|
+
}, [breakpoints, win]);
|
|
1628
|
+
// Breakpoint context value - only updates when breakpoint/orientation changes
|
|
1629
|
+
const breakpointValue = React.useMemo(() => ({
|
|
1630
|
+
breakpoints,
|
|
1631
|
+
devices,
|
|
1632
|
+
mediaQueries,
|
|
1633
|
+
currentBreakpoint: screen,
|
|
1634
|
+
currentDevice: determineCurrentDevice(screen, devices),
|
|
1635
|
+
orientation
|
|
1636
|
+
}), [breakpoints, devices, mediaQueries, screen, orientation]);
|
|
1637
|
+
// Window dimensions context value - updates on every resize
|
|
1638
|
+
const dimensionsValue = React.useMemo(() => ({
|
|
1639
|
+
width: dimensions.width,
|
|
1640
|
+
height: dimensions.height
|
|
1641
|
+
}), [dimensions.width, dimensions.height]);
|
|
1642
|
+
// Combined legacy context value for backward compatibility
|
|
1643
|
+
const legacyValue = React.useMemo(() => ({
|
|
1644
|
+
breakpoints,
|
|
1645
|
+
devices,
|
|
1646
|
+
mediaQueries,
|
|
1647
|
+
currentWidth: dimensions.width,
|
|
1648
|
+
currentHeight: dimensions.height,
|
|
1649
|
+
currentBreakpoint: screen,
|
|
1650
|
+
currentDevice: determineCurrentDevice(screen, devices),
|
|
1651
|
+
orientation
|
|
1652
|
+
}), [breakpoints, devices, mediaQueries, dimensions, screen, orientation]);
|
|
1653
|
+
return /*#__PURE__*/React__default.createElement(BreakpointContext.Provider, {
|
|
1654
|
+
value: breakpointValue
|
|
1655
|
+
}, /*#__PURE__*/React__default.createElement(WindowDimensionsContext.Provider, {
|
|
1656
|
+
value: dimensionsValue
|
|
1657
|
+
}, /*#__PURE__*/React__default.createElement(ResponsiveContext.Provider, {
|
|
1658
|
+
value: legacyValue
|
|
1659
|
+
}, children)));
|
|
1586
1660
|
};
|
|
1587
1661
|
|
|
1588
1662
|
const Shadows = {
|
|
@@ -2876,6 +2950,50 @@ const AnalyticsProvider = _ref => {
|
|
|
2876
2950
|
}, children);
|
|
2877
2951
|
};
|
|
2878
2952
|
|
|
2953
|
+
/**
|
|
2954
|
+
* Computes a stable hash of style-relevant props.
|
|
2955
|
+
* This is used to determine if style extraction needs to be re-run.
|
|
2956
|
+
*/
|
|
2957
|
+
function hashStyleProps(props) {
|
|
2958
|
+
// Build a deterministic string representation of style-relevant props
|
|
2959
|
+
const parts = [];
|
|
2960
|
+
const sortedKeys = Object.keys(props).sort();
|
|
2961
|
+
for (const key of sortedKeys) {
|
|
2962
|
+
// Skip non-style props that don't affect CSS generation
|
|
2963
|
+
if (key === 'children' || key === 'ref' || key === 'key') continue;
|
|
2964
|
+
// Include style-relevant props
|
|
2965
|
+
if (isStyleProp(key) || key.startsWith('_') || key === 'on' || key === 'media' || key === 'animate' || key === 'css' || key === 'shadow' || key === 'blend' || key === 'widthHeight' || key === 'paddingHorizontal' || key === 'paddingVertical' || key === 'marginHorizontal' || key === 'marginVertical') {
|
|
2966
|
+
const value = props[key];
|
|
2967
|
+
if (value !== undefined) {
|
|
2968
|
+
// Use JSON.stringify for consistent serialization
|
|
2969
|
+
parts.push(`${key}:${JSON.stringify(value)}`);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
return hash(parts.join('|'));
|
|
2974
|
+
}
|
|
2975
|
+
/**
|
|
2976
|
+
* Custom hook that memoizes style extraction based on a stable hash of props.
|
|
2977
|
+
* Only recalculates when the hash of style-relevant props changes.
|
|
2978
|
+
*/
|
|
2979
|
+
function useStableStyleMemo(propsToProcess, getColor, mediaQueries, devices, manager, theme) {
|
|
2980
|
+
const cacheRef = React.useRef(null);
|
|
2981
|
+
// Compute hash of current props
|
|
2982
|
+
const currentHash = React.useMemo(() => {
|
|
2983
|
+
// Include theme in hash to bust cache on theme changes
|
|
2984
|
+
const themeHash = theme ? JSON.stringify(theme) : '';
|
|
2985
|
+
return hashStyleProps(propsToProcess) + '|' + hash(themeHash);
|
|
2986
|
+
}, [propsToProcess, theme]);
|
|
2987
|
+
// Only recompute classes if hash changed
|
|
2988
|
+
if (!cacheRef.current || cacheRef.current.hash !== currentHash) {
|
|
2989
|
+
const classes = extractUtilityClasses(propsToProcess, getColor, mediaQueries, devices, manager);
|
|
2990
|
+
cacheRef.current = {
|
|
2991
|
+
hash: currentHash,
|
|
2992
|
+
classes
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
return cacheRef.current.classes;
|
|
2996
|
+
}
|
|
2879
2997
|
const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
2880
2998
|
let {
|
|
2881
2999
|
as = 'div',
|
|
@@ -2921,15 +3039,11 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
|
|
|
2921
3039
|
const {
|
|
2922
3040
|
mediaQueries,
|
|
2923
3041
|
devices
|
|
2924
|
-
} =
|
|
3042
|
+
} = useBreakpointContext();
|
|
2925
3043
|
const {
|
|
2926
3044
|
manager
|
|
2927
3045
|
} = useStyleRegistry();
|
|
2928
3046
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
2929
|
-
console.log({
|
|
2930
|
-
mediaQueries,
|
|
2931
|
-
devices
|
|
2932
|
-
});
|
|
2933
3047
|
React.useEffect(() => {
|
|
2934
3048
|
if (!animateIn) {
|
|
2935
3049
|
setIsVisible(true);
|
|
@@ -2970,15 +3084,16 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
|
|
|
2970
3084
|
}
|
|
2971
3085
|
};
|
|
2972
3086
|
}, [animateOut, manager]);
|
|
2973
|
-
|
|
2974
|
-
|
|
3087
|
+
// Prepare props for processing (apply view/scroll timeline if needed)
|
|
3088
|
+
const propsToProcess = React.useMemo(() => {
|
|
3089
|
+
const processed = {
|
|
2975
3090
|
...rest,
|
|
2976
3091
|
blend
|
|
2977
3092
|
};
|
|
2978
3093
|
// Apply view() timeline ONLY if animateOn='View' (not Both or Mount)
|
|
2979
|
-
if (animateOn === 'View' &&
|
|
2980
|
-
const animations = Array.isArray(
|
|
2981
|
-
|
|
3094
|
+
if (animateOn === 'View' && processed.animate) {
|
|
3095
|
+
const animations = Array.isArray(processed.animate) ? processed.animate : [processed.animate];
|
|
3096
|
+
processed.animate = animations.map(anim => {
|
|
2982
3097
|
// Only add timeline if not already specified
|
|
2983
3098
|
if (!anim.timeline) {
|
|
2984
3099
|
return {
|
|
@@ -2992,9 +3107,9 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
|
|
|
2992
3107
|
});
|
|
2993
3108
|
}
|
|
2994
3109
|
// Apply scroll() timeline if animateOn='Scroll'
|
|
2995
|
-
if (animateOn === 'Scroll' &&
|
|
2996
|
-
const animations = Array.isArray(
|
|
2997
|
-
|
|
3110
|
+
if (animateOn === 'Scroll' && processed.animate) {
|
|
3111
|
+
const animations = Array.isArray(processed.animate) ? processed.animate : [processed.animate];
|
|
3112
|
+
processed.animate = animations.map(anim => {
|
|
2998
3113
|
// Only add timeline if not already specified
|
|
2999
3114
|
if (!anim.timeline) {
|
|
3000
3115
|
return {
|
|
@@ -3006,10 +3121,10 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
|
|
|
3006
3121
|
return anim;
|
|
3007
3122
|
});
|
|
3008
3123
|
}
|
|
3009
|
-
return
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3124
|
+
return processed;
|
|
3125
|
+
}, [rest, blend, animateOn]);
|
|
3126
|
+
// Use hash-based memoization for style extraction
|
|
3127
|
+
const utilityClasses = useStableStyleMemo(propsToProcess, getColor, mediaQueries, devices, manager, theme);
|
|
3013
3128
|
const newProps = {
|
|
3014
3129
|
ref: setRef
|
|
3015
3130
|
};
|
|
@@ -4921,20 +5036,23 @@ const WindowSizeContext = /*#__PURE__*/React.createContext({
|
|
|
4921
5036
|
});
|
|
4922
5037
|
const WindowSizeProvider = _ref => {
|
|
4923
5038
|
let {
|
|
4924
|
-
children
|
|
5039
|
+
children,
|
|
5040
|
+
targetWindow
|
|
4925
5041
|
} = _ref;
|
|
5042
|
+
const win = targetWindow || (typeof window !== 'undefined' ? window : null);
|
|
4926
5043
|
const [size, setSize] = React.useState({
|
|
4927
|
-
width:
|
|
4928
|
-
height:
|
|
5044
|
+
width: win?.innerWidth || 0,
|
|
5045
|
+
height: win?.innerHeight || 0
|
|
4929
5046
|
});
|
|
4930
5047
|
React.useEffect(() => {
|
|
5048
|
+
if (!win) return;
|
|
4931
5049
|
const handleResize = () => setSize({
|
|
4932
|
-
width:
|
|
4933
|
-
height:
|
|
5050
|
+
width: win.innerWidth,
|
|
5051
|
+
height: win.innerHeight
|
|
4934
5052
|
});
|
|
4935
|
-
|
|
4936
|
-
return () =>
|
|
4937
|
-
}, []);
|
|
5053
|
+
win.addEventListener('resize', handleResize);
|
|
5054
|
+
return () => win.removeEventListener('resize', handleResize);
|
|
5055
|
+
}, [win]);
|
|
4938
5056
|
return /*#__PURE__*/React__default.createElement(WindowSizeContext.Provider, {
|
|
4939
5057
|
value: size
|
|
4940
5058
|
}, children);
|
|
@@ -4966,10 +5084,16 @@ function useActive() {
|
|
|
4966
5084
|
return [ref, active];
|
|
4967
5085
|
}
|
|
4968
5086
|
|
|
4969
|
-
function useClickOutside() {
|
|
5087
|
+
function useClickOutside(options) {
|
|
4970
5088
|
const [clickedOutside, setClickedOutside] = React.useState(false);
|
|
4971
5089
|
const ref = React.useRef(null);
|
|
5090
|
+
const {
|
|
5091
|
+
targetWindow
|
|
5092
|
+
} = options || {};
|
|
4972
5093
|
React.useEffect(() => {
|
|
5094
|
+
const win = targetWindow || (typeof window !== 'undefined' ? window : null);
|
|
5095
|
+
if (!win) return;
|
|
5096
|
+
const doc = win.document;
|
|
4973
5097
|
const handleClick = e => {
|
|
4974
5098
|
if (ref.current && !ref.current.contains(e.target)) {
|
|
4975
5099
|
setClickedOutside(true);
|
|
@@ -4977,11 +5101,11 @@ function useClickOutside() {
|
|
|
4977
5101
|
setClickedOutside(false);
|
|
4978
5102
|
}
|
|
4979
5103
|
};
|
|
4980
|
-
|
|
5104
|
+
doc.addEventListener('mousedown', handleClick);
|
|
4981
5105
|
return () => {
|
|
4982
|
-
|
|
5106
|
+
doc.removeEventListener('mousedown', handleClick);
|
|
4983
5107
|
};
|
|
4984
|
-
}, []);
|
|
5108
|
+
}, [targetWindow]);
|
|
4985
5109
|
return [ref, clickedOutside];
|
|
4986
5110
|
}
|
|
4987
5111
|
|
|
@@ -4998,7 +5122,8 @@ function useElementPosition(options) {
|
|
|
4998
5122
|
throttleMs = 500,
|
|
4999
5123
|
trackOnHover = true,
|
|
5000
5124
|
trackOnScroll = false,
|
|
5001
|
-
trackOnResize = false
|
|
5125
|
+
trackOnResize = false,
|
|
5126
|
+
targetWindow
|
|
5002
5127
|
} = options;
|
|
5003
5128
|
const elementRef = React.useRef(null);
|
|
5004
5129
|
const [relation, setRelation] = React.useState(null);
|
|
@@ -5009,9 +5134,10 @@ function useElementPosition(options) {
|
|
|
5009
5134
|
setRelation(currentRelation => currentRelation === null ? null : null);
|
|
5010
5135
|
return;
|
|
5011
5136
|
}
|
|
5137
|
+
const win = targetWindow || element.ownerDocument?.defaultView || window;
|
|
5012
5138
|
const rect = element.getBoundingClientRect();
|
|
5013
|
-
const viewportHeight =
|
|
5014
|
-
const viewportWidth =
|
|
5139
|
+
const viewportHeight = win.innerHeight;
|
|
5140
|
+
const viewportWidth = win.innerWidth;
|
|
5015
5141
|
// 1. Determine element's general position in viewport
|
|
5016
5142
|
const elementCenterY = rect.top + rect.height / 2;
|
|
5017
5143
|
const elementCenterX = rect.left + rect.width / 2;
|
|
@@ -5040,7 +5166,7 @@ function useElementPosition(options) {
|
|
|
5040
5166
|
}
|
|
5041
5167
|
return newRelation;
|
|
5042
5168
|
});
|
|
5043
|
-
}, []); // This callback is stable
|
|
5169
|
+
}, [targetWindow]); // This callback is stable
|
|
5044
5170
|
const throttledUpdate = React.useCallback(() => {
|
|
5045
5171
|
if (throttleTimerRef.current) {
|
|
5046
5172
|
clearTimeout(throttleTimerRef.current);
|
|
@@ -5058,6 +5184,7 @@ function useElementPosition(options) {
|
|
|
5058
5184
|
}
|
|
5059
5185
|
const element = elementRef.current;
|
|
5060
5186
|
if (!element) return;
|
|
5187
|
+
const win = targetWindow || element.ownerDocument?.defaultView || window;
|
|
5061
5188
|
const handler = throttledUpdate;
|
|
5062
5189
|
const immediateHandler = calculateRelation;
|
|
5063
5190
|
// Add event listeners based on configuration
|
|
@@ -5073,18 +5200,18 @@ function useElementPosition(options) {
|
|
|
5073
5200
|
}
|
|
5074
5201
|
// Scroll events - throttled
|
|
5075
5202
|
if (trackOnScroll) {
|
|
5076
|
-
|
|
5203
|
+
win.addEventListener('scroll', handler, {
|
|
5077
5204
|
passive: true
|
|
5078
5205
|
});
|
|
5079
5206
|
cleanupFunctions.push(() => {
|
|
5080
|
-
|
|
5207
|
+
win.removeEventListener('scroll', handler);
|
|
5081
5208
|
});
|
|
5082
5209
|
}
|
|
5083
5210
|
// Resize events - throttled
|
|
5084
5211
|
if (trackOnResize) {
|
|
5085
|
-
|
|
5212
|
+
win.addEventListener('resize', handler);
|
|
5086
5213
|
cleanupFunctions.push(() => {
|
|
5087
|
-
|
|
5214
|
+
win.removeEventListener('resize', handler);
|
|
5088
5215
|
});
|
|
5089
5216
|
}
|
|
5090
5217
|
return () => {
|
|
@@ -5093,7 +5220,7 @@ function useElementPosition(options) {
|
|
|
5093
5220
|
}
|
|
5094
5221
|
cleanupFunctions.forEach(cleanup => cleanup());
|
|
5095
5222
|
};
|
|
5096
|
-
}, [trackChanges, trackOnHover, trackOnScroll, trackOnResize, throttledUpdate, calculateRelation]);
|
|
5223
|
+
}, [trackChanges, trackOnHover, trackOnScroll, trackOnResize, throttledUpdate, calculateRelation, targetWindow]);
|
|
5097
5224
|
const manualUpdateRelation = React.useCallback(() => {
|
|
5098
5225
|
calculateRelation();
|
|
5099
5226
|
}, [calculateRelation]);
|
|
@@ -5168,21 +5295,84 @@ const useMount = callback => {
|
|
|
5168
5295
|
function useOnScreen(options) {
|
|
5169
5296
|
const ref = React.useRef(null);
|
|
5170
5297
|
const [isOnScreen, setOnScreen] = React.useState(false);
|
|
5298
|
+
const {
|
|
5299
|
+
targetWindow,
|
|
5300
|
+
...observerOptions
|
|
5301
|
+
} = options || {};
|
|
5171
5302
|
React.useEffect(() => {
|
|
5172
5303
|
const node = ref.current;
|
|
5173
5304
|
if (!node) return;
|
|
5305
|
+
// If targetWindow is provided and root is not explicitly set,
|
|
5306
|
+
// use the target window's document as the root
|
|
5307
|
+
const win = targetWindow || node.ownerDocument?.defaultView || window;
|
|
5308
|
+
const effectiveRoot = observerOptions.root !== undefined ? observerOptions.root : targetWindow ? win.document.documentElement : undefined;
|
|
5174
5309
|
const observer = new IntersectionObserver(_ref => {
|
|
5175
5310
|
let [entry] = _ref;
|
|
5176
5311
|
setOnScreen(entry.isIntersecting);
|
|
5177
|
-
},
|
|
5312
|
+
}, {
|
|
5313
|
+
...observerOptions,
|
|
5314
|
+
root: effectiveRoot
|
|
5315
|
+
});
|
|
5178
5316
|
observer.observe(node);
|
|
5179
5317
|
return () => {
|
|
5180
5318
|
observer.disconnect();
|
|
5181
5319
|
};
|
|
5182
|
-
}, [options]);
|
|
5320
|
+
}, [targetWindow, options]);
|
|
5183
5321
|
return [ref, isOnScreen];
|
|
5184
5322
|
}
|
|
5185
5323
|
|
|
5324
|
+
/**
|
|
5325
|
+
* Optimized hook for components that only need breakpoint information.
|
|
5326
|
+
* This hook will NOT cause re-renders on every window resize,
|
|
5327
|
+
* only when the breakpoint actually changes.
|
|
5328
|
+
*
|
|
5329
|
+
* Use this hook instead of useResponsive for better performance
|
|
5330
|
+
* when you only need to check breakpoints or device type.
|
|
5331
|
+
*
|
|
5332
|
+
* @example
|
|
5333
|
+
* const { screen, on, is, orientation } = useBreakpoint();
|
|
5334
|
+
* if (on('mobile')) { ... }
|
|
5335
|
+
* if (is('xs')) { ... }
|
|
5336
|
+
*/
|
|
5337
|
+
const useBreakpoint = () => {
|
|
5338
|
+
const context = useBreakpointContext();
|
|
5339
|
+
const {
|
|
5340
|
+
currentBreakpoint: screen,
|
|
5341
|
+
orientation,
|
|
5342
|
+
devices
|
|
5343
|
+
} = context;
|
|
5344
|
+
// Helper to check if current screen matches a breakpoint or device
|
|
5345
|
+
const on = s => devices[s] ? devices[s].includes(screen) : s === screen;
|
|
5346
|
+
return {
|
|
5347
|
+
...context,
|
|
5348
|
+
screen,
|
|
5349
|
+
orientation,
|
|
5350
|
+
on,
|
|
5351
|
+
is: on
|
|
5352
|
+
};
|
|
5353
|
+
};
|
|
5354
|
+
/**
|
|
5355
|
+
* Hook for components that need exact window dimensions.
|
|
5356
|
+
* This hook WILL cause re-renders on every window resize.
|
|
5357
|
+
* Use sparingly - prefer useBreakpoint when possible.
|
|
5358
|
+
*
|
|
5359
|
+
* @example
|
|
5360
|
+
* const { width, height } = useWindowDimensions();
|
|
5361
|
+
*/
|
|
5362
|
+
const useWindowDimensions = () => {
|
|
5363
|
+
return useWindowDimensionsContext();
|
|
5364
|
+
};
|
|
5365
|
+
/**
|
|
5366
|
+
* Combined hook that provides both breakpoint info and window dimensions.
|
|
5367
|
+
* This hook WILL cause re-renders on every window resize.
|
|
5368
|
+
*
|
|
5369
|
+
* For better performance, use:
|
|
5370
|
+
* - useBreakpoint() when you only need breakpoint/device info
|
|
5371
|
+
* - useWindowDimensions() when you only need exact dimensions
|
|
5372
|
+
*
|
|
5373
|
+
* @example
|
|
5374
|
+
* const { screen, on, currentWidth, currentHeight } = useResponsive();
|
|
5375
|
+
*/
|
|
5186
5376
|
const useResponsive = () => {
|
|
5187
5377
|
const context = useResponsiveContext();
|
|
5188
5378
|
const {
|
|
@@ -5198,7 +5388,6 @@ const useResponsive = () => {
|
|
|
5198
5388
|
on,
|
|
5199
5389
|
is: on
|
|
5200
5390
|
};
|
|
5201
|
-
// console.log('[useResponsive] Hook called, returning:', { screen, orientation, 'on(mobile)': on('mobile') });
|
|
5202
5391
|
return result;
|
|
5203
5392
|
};
|
|
5204
5393
|
|
|
@@ -5368,27 +5557,28 @@ const useScrollAnimation = function (ref, options) {
|
|
|
5368
5557
|
};
|
|
5369
5558
|
};
|
|
5370
5559
|
// Enhanced useSmoothScroll with error handling
|
|
5371
|
-
const useSmoothScroll =
|
|
5560
|
+
const useSmoothScroll = targetWindow => {
|
|
5372
5561
|
return React.useCallback(function (element, offset) {
|
|
5373
5562
|
if (offset === void 0) {
|
|
5374
5563
|
offset = 0;
|
|
5375
5564
|
}
|
|
5376
5565
|
if (!element) return;
|
|
5377
5566
|
try {
|
|
5378
|
-
const
|
|
5379
|
-
|
|
5380
|
-
|
|
5567
|
+
const win = targetWindow || element.ownerDocument?.defaultView || window;
|
|
5568
|
+
const top = element.getBoundingClientRect().top + (win.scrollY || win.pageYOffset) - offset;
|
|
5569
|
+
if ('scrollBehavior' in win.document.documentElement.style) {
|
|
5570
|
+
win.scrollTo({
|
|
5381
5571
|
top,
|
|
5382
5572
|
behavior: 'smooth'
|
|
5383
5573
|
});
|
|
5384
5574
|
} else {
|
|
5385
5575
|
// Fallback for browsers that don't support smooth scrolling
|
|
5386
|
-
|
|
5576
|
+
win.scrollTo(0, top);
|
|
5387
5577
|
}
|
|
5388
5578
|
} catch (error) {
|
|
5389
5579
|
console.error('Error during smooth scroll:', error);
|
|
5390
5580
|
}
|
|
5391
|
-
}, []);
|
|
5581
|
+
}, [targetWindow]);
|
|
5392
5582
|
};
|
|
5393
5583
|
// Enhanced useInfiniteScroll with debouncing
|
|
5394
5584
|
const useInfiniteScroll = function (callback, options) {
|
|
@@ -5432,7 +5622,7 @@ const useInfiniteScroll = function (callback, options) {
|
|
|
5432
5622
|
sentinelRef: setSentinel
|
|
5433
5623
|
};
|
|
5434
5624
|
};
|
|
5435
|
-
const useScrollDirection = function (threshold) {
|
|
5625
|
+
const useScrollDirection = function (threshold, targetWindow) {
|
|
5436
5626
|
if (threshold === void 0) {
|
|
5437
5627
|
threshold = 5;
|
|
5438
5628
|
}
|
|
@@ -5441,12 +5631,15 @@ const useScrollDirection = function (threshold) {
|
|
|
5441
5631
|
const lastDirection = React.useRef('up');
|
|
5442
5632
|
const animationFrame = React.useRef();
|
|
5443
5633
|
const ticking = React.useRef(false);
|
|
5444
|
-
const updateDirection = () => {
|
|
5445
|
-
const
|
|
5634
|
+
const updateDirection = React.useCallback(() => {
|
|
5635
|
+
const win = targetWindow || (typeof window !== 'undefined' ? window : null);
|
|
5636
|
+
if (!win) return;
|
|
5637
|
+
const doc = win.document.documentElement;
|
|
5638
|
+
const scrollY = win.scrollY || doc.scrollTop;
|
|
5446
5639
|
const direction = scrollY > lastScrollY.current ? 'down' : 'up';
|
|
5447
5640
|
const scrollDelta = Math.abs(scrollY - lastScrollY.current);
|
|
5448
5641
|
// Vérifier si on est au bas de la page
|
|
5449
|
-
const isAtBottom =
|
|
5642
|
+
const isAtBottom = win.innerHeight + scrollY >= doc.scrollHeight - 1;
|
|
5450
5643
|
// Logique principale
|
|
5451
5644
|
if (scrollDelta > threshold || direction === 'down' && isAtBottom) {
|
|
5452
5645
|
if (direction !== lastDirection.current) {
|
|
@@ -5457,8 +5650,10 @@ const useScrollDirection = function (threshold) {
|
|
|
5457
5650
|
// Mise à jour de la position avec un minimum de 0
|
|
5458
5651
|
lastScrollY.current = Math.max(scrollY, 0);
|
|
5459
5652
|
ticking.current = false;
|
|
5460
|
-
};
|
|
5653
|
+
}, [threshold, targetWindow]);
|
|
5461
5654
|
React.useEffect(() => {
|
|
5655
|
+
const win = targetWindow || (typeof window !== 'undefined' ? window : null);
|
|
5656
|
+
if (!win) return;
|
|
5462
5657
|
const handleScroll = () => {
|
|
5463
5658
|
if (!ticking.current) {
|
|
5464
5659
|
animationFrame.current = requestAnimationFrame(() => {
|
|
@@ -5468,16 +5663,16 @@ const useScrollDirection = function (threshold) {
|
|
|
5468
5663
|
ticking.current = true;
|
|
5469
5664
|
}
|
|
5470
5665
|
};
|
|
5471
|
-
|
|
5666
|
+
win.addEventListener('scroll', handleScroll, {
|
|
5472
5667
|
passive: true
|
|
5473
5668
|
});
|
|
5474
5669
|
return () => {
|
|
5475
|
-
|
|
5670
|
+
win.removeEventListener('scroll', handleScroll);
|
|
5476
5671
|
if (animationFrame.current) {
|
|
5477
5672
|
cancelAnimationFrame(animationFrame.current);
|
|
5478
5673
|
}
|
|
5479
5674
|
};
|
|
5480
|
-
}, [
|
|
5675
|
+
}, [updateDirection, targetWindow]);
|
|
5481
5676
|
return scrollDirection;
|
|
5482
5677
|
};
|
|
5483
5678
|
|
|
@@ -5486,6 +5681,7 @@ const useWindowSize = () => React.useContext(WindowSizeContext);
|
|
|
5486
5681
|
function useInView(options) {
|
|
5487
5682
|
const {
|
|
5488
5683
|
triggerOnce = false,
|
|
5684
|
+
targetWindow,
|
|
5489
5685
|
...observerOptions
|
|
5490
5686
|
} = options || {};
|
|
5491
5687
|
const ref = React.useRef(null);
|
|
@@ -5493,6 +5689,10 @@ function useInView(options) {
|
|
|
5493
5689
|
React.useEffect(() => {
|
|
5494
5690
|
const element = ref.current;
|
|
5495
5691
|
if (!element) return;
|
|
5692
|
+
// If targetWindow is provided and root is not explicitly set,
|
|
5693
|
+
// use the target window's document as the root
|
|
5694
|
+
const win = targetWindow || element.ownerDocument?.defaultView || window;
|
|
5695
|
+
const effectiveRoot = observerOptions.root !== undefined ? observerOptions.root : targetWindow ? win.document.documentElement : undefined;
|
|
5496
5696
|
const observer = new IntersectionObserver(_ref => {
|
|
5497
5697
|
let [entry] = _ref;
|
|
5498
5698
|
if (entry.isIntersecting) {
|
|
@@ -5505,18 +5705,121 @@ function useInView(options) {
|
|
|
5505
5705
|
// Only update to false if not using triggerOnce
|
|
5506
5706
|
setInView(false);
|
|
5507
5707
|
}
|
|
5508
|
-
},
|
|
5708
|
+
}, {
|
|
5709
|
+
...observerOptions,
|
|
5710
|
+
root: effectiveRoot
|
|
5711
|
+
});
|
|
5509
5712
|
observer.observe(element);
|
|
5510
5713
|
return () => {
|
|
5511
5714
|
observer.disconnect();
|
|
5512
5715
|
};
|
|
5513
|
-
}, [triggerOnce, ...Object.values(observerOptions || {})]);
|
|
5716
|
+
}, [triggerOnce, targetWindow, ...Object.values(observerOptions || {})]);
|
|
5514
5717
|
return {
|
|
5515
5718
|
ref,
|
|
5516
5719
|
inView
|
|
5517
5720
|
};
|
|
5518
5721
|
}
|
|
5519
5722
|
|
|
5723
|
+
/**
|
|
5724
|
+
* Hook to register an iframe's document with the style manager.
|
|
5725
|
+
* This ensures that all CSS utility classes are automatically injected into the iframe.
|
|
5726
|
+
*
|
|
5727
|
+
* @param iframeRef - Reference to the iframe element
|
|
5728
|
+
*
|
|
5729
|
+
* @example
|
|
5730
|
+
* ```tsx
|
|
5731
|
+
* const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
5732
|
+
* useIframeStyles(iframeRef);
|
|
5733
|
+
*
|
|
5734
|
+
* return <iframe ref={iframeRef} src="/content" />;
|
|
5735
|
+
* ```
|
|
5736
|
+
*/
|
|
5737
|
+
function useIframeStyles(iframeRef) {
|
|
5738
|
+
const {
|
|
5739
|
+
manager
|
|
5740
|
+
} = useStyleRegistry();
|
|
5741
|
+
const registeredDocRef = React.useRef(null);
|
|
5742
|
+
React.useEffect(() => {
|
|
5743
|
+
const iframe = iframeRef.current;
|
|
5744
|
+
if (!iframe) return;
|
|
5745
|
+
const registerDocument = () => {
|
|
5746
|
+
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
5747
|
+
if (!iframeDoc) return;
|
|
5748
|
+
// Only register if not already registered
|
|
5749
|
+
if (registeredDocRef.current !== iframeDoc) {
|
|
5750
|
+
manager.addDocument(iframeDoc);
|
|
5751
|
+
registeredDocRef.current = iframeDoc;
|
|
5752
|
+
}
|
|
5753
|
+
};
|
|
5754
|
+
// Try to register immediately if document is ready
|
|
5755
|
+
if (iframe.contentDocument) {
|
|
5756
|
+
registerDocument();
|
|
5757
|
+
}
|
|
5758
|
+
// Also register on load event (for external sources)
|
|
5759
|
+
iframe.addEventListener('load', registerDocument);
|
|
5760
|
+
return () => {
|
|
5761
|
+
iframe.removeEventListener('load', registerDocument);
|
|
5762
|
+
// Clean up when unmounting
|
|
5763
|
+
if (registeredDocRef.current) {
|
|
5764
|
+
manager.removeDocument(registeredDocRef.current);
|
|
5765
|
+
registeredDocRef.current = null;
|
|
5766
|
+
}
|
|
5767
|
+
};
|
|
5768
|
+
}, [manager, iframeRef]);
|
|
5769
|
+
}
|
|
5770
|
+
/**
|
|
5771
|
+
* Hook to get an iframe's window and document, and automatically register styles.
|
|
5772
|
+
* This is a convenience hook that combines iframe access with style registration.
|
|
5773
|
+
*
|
|
5774
|
+
* @param iframeRef - Reference to the iframe element
|
|
5775
|
+
* @returns Object containing iframeWindow, iframeDocument, and isLoaded flag
|
|
5776
|
+
*
|
|
5777
|
+
* @example
|
|
5778
|
+
* ```tsx
|
|
5779
|
+
* const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
5780
|
+
* const { iframeWindow, iframeDocument, isLoaded } = useIframe(iframeRef);
|
|
5781
|
+
*
|
|
5782
|
+
* return (
|
|
5783
|
+
* <>
|
|
5784
|
+
* <iframe ref={iframeRef} src="/content" />
|
|
5785
|
+
* {isLoaded && <div>Iframe loaded!</div>}
|
|
5786
|
+
* </>
|
|
5787
|
+
* );
|
|
5788
|
+
* ```
|
|
5789
|
+
*/
|
|
5790
|
+
function useIframe(iframeRef) {
|
|
5791
|
+
const [iframeWindow, setIframeWindow] = React.useState(null);
|
|
5792
|
+
const [iframeDocument, setIframeDocument] = React.useState(null);
|
|
5793
|
+
const [isLoaded, setIsLoaded] = React.useState(false);
|
|
5794
|
+
// Register styles
|
|
5795
|
+
useIframeStyles(iframeRef);
|
|
5796
|
+
React.useEffect(() => {
|
|
5797
|
+
const iframe = iframeRef.current;
|
|
5798
|
+
if (!iframe) return;
|
|
5799
|
+
const updateState = () => {
|
|
5800
|
+
const win = iframe.contentWindow;
|
|
5801
|
+
const doc = iframe.contentDocument || win?.document;
|
|
5802
|
+
if (win && doc) {
|
|
5803
|
+
setIframeWindow(win);
|
|
5804
|
+
setIframeDocument(doc);
|
|
5805
|
+
setIsLoaded(true);
|
|
5806
|
+
}
|
|
5807
|
+
};
|
|
5808
|
+
// Try immediately
|
|
5809
|
+
updateState();
|
|
5810
|
+
// Listen for load event
|
|
5811
|
+
iframe.addEventListener('load', updateState);
|
|
5812
|
+
return () => {
|
|
5813
|
+
iframe.removeEventListener('load', updateState);
|
|
5814
|
+
};
|
|
5815
|
+
}, [iframeRef]);
|
|
5816
|
+
return {
|
|
5817
|
+
iframeWindow,
|
|
5818
|
+
iframeDocument,
|
|
5819
|
+
isLoaded
|
|
5820
|
+
};
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5520
5823
|
/**
|
|
5521
5824
|
* View Animation Utilities
|
|
5522
5825
|
*
|
|
@@ -6091,6 +6394,7 @@ exports.AnalyticsContext = AnalyticsContext;
|
|
|
6091
6394
|
exports.AnalyticsProvider = AnalyticsProvider;
|
|
6092
6395
|
exports.Animation = Animation;
|
|
6093
6396
|
exports.AnimationUtils = AnimationUtils;
|
|
6397
|
+
exports.BreakpointContext = BreakpointContext;
|
|
6094
6398
|
exports.Button = Button;
|
|
6095
6399
|
exports.Center = Center;
|
|
6096
6400
|
exports.Div = Div;
|
|
@@ -6117,6 +6421,7 @@ exports.UtilityClassManager = UtilityClassManager;
|
|
|
6117
6421
|
exports.Vertical = Vertical;
|
|
6118
6422
|
exports.VerticalResponsive = VerticalResponsive;
|
|
6119
6423
|
exports.View = View;
|
|
6424
|
+
exports.WindowDimensionsContext = WindowDimensionsContext;
|
|
6120
6425
|
exports.WindowSizeContext = WindowSizeContext;
|
|
6121
6426
|
exports.WindowSizeProvider = WindowSizeProvider;
|
|
6122
6427
|
exports.animateOnView = animateOnView;
|
|
@@ -6156,10 +6461,14 @@ exports.slideRightOnView = slideRightOnView;
|
|
|
6156
6461
|
exports.slideUpOnView = slideUpOnView;
|
|
6157
6462
|
exports.useActive = useActive;
|
|
6158
6463
|
exports.useAnalytics = useAnalytics;
|
|
6464
|
+
exports.useBreakpoint = useBreakpoint;
|
|
6465
|
+
exports.useBreakpointContext = useBreakpointContext;
|
|
6159
6466
|
exports.useClickOutside = useClickOutside;
|
|
6160
6467
|
exports.useElementPosition = useElementPosition;
|
|
6161
6468
|
exports.useFocus = useFocus;
|
|
6162
6469
|
exports.useHover = useHover;
|
|
6470
|
+
exports.useIframe = useIframe;
|
|
6471
|
+
exports.useIframeStyles = useIframeStyles;
|
|
6163
6472
|
exports.useInView = useInView;
|
|
6164
6473
|
exports.useInfiniteScroll = useInfiniteScroll;
|
|
6165
6474
|
exports.useKeyPress = useKeyPress;
|
|
@@ -6174,6 +6483,8 @@ exports.useServerInsertedHTML = useServerInsertedHTML;
|
|
|
6174
6483
|
exports.useSmoothScroll = useSmoothScroll;
|
|
6175
6484
|
exports.useStyleRegistry = useStyleRegistry;
|
|
6176
6485
|
exports.useTheme = useTheme;
|
|
6486
|
+
exports.useWindowDimensions = useWindowDimensions;
|
|
6487
|
+
exports.useWindowDimensionsContext = useWindowDimensionsContext;
|
|
6177
6488
|
exports.useWindowSize = useWindowSize;
|
|
6178
6489
|
exports.utilityClassManager = utilityClassManager;
|
|
6179
6490
|
exports.viewAnimationPresets = viewAnimationPresets;
|