Skip to content

Commit 30c9a93

Browse files
author
ricwilson
committed
refactor: replace useBrowserScaling with useResponsiveAppScaling and update related hooks
1 parent 53846e9 commit 30c9a93

File tree

8 files changed

+62
-78
lines changed

8 files changed

+62
-78
lines changed

ImageCrop/ImageCrop/components/imageCropControl.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react";
2-
import ReactCrop, { Crop, PixelCrop } from "react-image-crop";
2+
import { Crop, PixelCrop } from "react-image-crop";
33
import "react-image-crop/dist/ReactCrop.css";
44
import { usePcfContext } from "../services/pcfContext";
55
import { IImageCropControlProps } from "../types/imageCropTypes";
@@ -14,7 +14,7 @@ import {
1414
useRuleOfThirds,
1515
useCircularCrop,
1616
useDisabled,
17-
useBrowserScaling,
17+
useResponsiveAppScaling,
1818
useCropToBase64,
1919
useKeepSelection,
2020
useRotation,
@@ -27,7 +27,7 @@ const ImageCropControl: React.FC<IImageCropControlProps> = (props) => {
2727
const [crop, setCrop] = React.useState<Crop>();
2828
const [completedCrop, setCompletedCrop] = React.useState<PixelCrop>()
2929
const imgRef = React.useRef<HTMLImageElement>(null) as React.RefObject<HTMLImageElement>;
30-
const browserScaling = useBrowserScaling(imgRef);
30+
const appScaling = useResponsiveAppScaling(pcfContext.context, imgRef);
3131

3232
// Get the locked property from PCF context
3333
const locked = useLocked(pcfContext.context);
@@ -42,10 +42,10 @@ const ImageCropControl: React.FC<IImageCropControlProps> = (props) => {
4242
const circularCrop = useCircularCrop(pcfContext.context);
4343

4444
// Get min/max width/height from PCF context, scaled for browser
45-
const minWidth = useMinWidth(pcfContext.context, browserScaling);
46-
const maxWidth = useMaxWidth(pcfContext.context, browserScaling);
47-
const minHeight = useMinHeight(pcfContext.context, browserScaling);
48-
const maxHeight = useMaxHeight(pcfContext.context, browserScaling);
45+
const minWidth = useMinWidth(pcfContext.context);
46+
const maxWidth = useMaxWidth(pcfContext.context);
47+
const minHeight = useMinHeight(pcfContext.context);
48+
const maxHeight = useMaxHeight(pcfContext.context);
4949

5050
// Get the aspect ratio from PCF context and helper to center crop
5151
const [aspect, centerCropIfNeeded] = useAspect(pcfContext.context, imgRef, setCrop);
@@ -67,7 +67,7 @@ const ImageCropControl: React.FC<IImageCropControlProps> = (props) => {
6767
// Optionally, recenter crop when aspect changes (already handled in hook)
6868

6969
return (
70-
<CropWrapper
70+
<CropWrapper
7171
crop={crop}
7272
onChange={(c: Crop) => setCrop(c)}
7373
onDragStart={(e: PointerEvent) => props.onDragStart(e)}

ImageCrop/ImageCrop/hooks/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export * from "./useLocked";
88
export * from "./useRuleOfThirds";
99
export * from "./useCircularCrop";
1010
export * from "./useDisabled";
11-
export * from "./useBrowserScaling";
11+
export * from "./useResponsiveAppScaling";
1212
export * from "./useCropToBase64";
1313
export * from "./useKeepSelection";
1414
export * from "./useRotation";

ImageCrop/ImageCrop/hooks/useBrowserScaling.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.

ImageCrop/ImageCrop/hooks/useMaxHeight.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,23 @@ import { IInputs } from "../generated/ManifestTypes";
44
/**
55
* Custom hook to track the maxHeight property from PCF context and update when it or scaling changes.
66
* @param context The PCF context object
7-
* @param scaling The browser scaling factor to apply
87
* @returns The current scaled maxHeight value (number | undefined)
98
*/
109

11-
export function useMaxHeight(context: ComponentFramework.Context<IInputs>, scaling = 1): number | undefined {
10+
export function useMaxHeight(context: ComponentFramework.Context<IInputs>): number | undefined {
1211
const getMaxHeight = () => {
1312
const raw = context.parameters.maxHeight?.raw;
1413
if (raw === undefined || raw === null || (typeof raw === "string" && raw === "")) return undefined;
1514
const num = Number(raw);
1615
if (isNaN(num) || num === -1) return undefined;
17-
return num * scaling;
16+
return num;
1817
};
1918

2019
const [maxHeight, setMaxHeight] = useState<number | undefined>(getMaxHeight());
2120

2221
useEffect(() => {
2322
setMaxHeight(getMaxHeight());
24-
}, [context.parameters.maxHeight?.raw, scaling]);
23+
}, [context.parameters.maxHeight?.raw])
2524

2625
return maxHeight;
2726
}

ImageCrop/ImageCrop/hooks/useMaxWidth.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,22 @@ import { IInputs } from "../generated/ManifestTypes";
44
/**
55
* Custom hook to track the maxWidth property from PCF context and update when it or scaling changes.
66
* @param context The PCF context object
7-
* @param scaling The browser scaling factor to apply
87
* @returns The current scaled maxWidth value (number | undefined)
98
*/
10-
export function useMaxWidth(context: ComponentFramework.Context<IInputs>, scaling = 1): number | undefined {
9+
export function useMaxWidth(context: ComponentFramework.Context<IInputs>): number | undefined {
1110
const getMaxWidth = () => {
1211
const raw = context.parameters.maxWidth?.raw;
1312
if (raw === undefined || raw === null || (typeof raw === "string" && raw === "")) return undefined;
1413
const num = Number(raw);
1514
if (isNaN(num) || num === -1) return undefined;
16-
return num * scaling;
15+
return num;
1716
};
1817

1918
const [maxWidth, setMaxWidth] = useState<number | undefined>(getMaxWidth());
2019

2120
useEffect(() => {
2221
setMaxWidth(getMaxWidth());
23-
}, [context.parameters.maxWidth?.raw, scaling]);
22+
}, [context.parameters.maxWidth?.raw]);
2423

2524
return maxWidth;
2625
}

ImageCrop/ImageCrop/hooks/useMinHeight.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,23 @@ import { IInputs } from "../generated/ManifestTypes";
44
/**
55
* Custom hook to track the minHeight property from PCF context and update when it or scaling changes.
66
* @param context The PCF context object
7-
* @param scaling The browser scaling factor to apply
87
* @returns The current scaled minHeight value (number | undefined)
98
*/
109

11-
export function useMinHeight(context: ComponentFramework.Context<IInputs>, scaling = 1): number | undefined {
10+
export function useMinHeight(context: ComponentFramework.Context<IInputs>): number | undefined {
1211
const getMinHeight = () => {
1312
const raw = context.parameters.minHeight?.raw;
1413
if (raw === undefined || raw === null || (typeof raw === "string" && raw === "")) return undefined;
1514
const num = Number(raw);
1615
if (isNaN(num) || num === -1) return undefined;
17-
return num * scaling;
16+
return num;
1817
};
1918

2019
const [minHeight, setMinHeight] = useState<number | undefined>(getMinHeight());
2120

2221
useEffect(() => {
2322
setMinHeight(getMinHeight());
24-
}, [context.parameters.minHeight?.raw, scaling]);
23+
}, [context.parameters.minHeight?.raw])
2524

2625
return minHeight;
2726
}

ImageCrop/ImageCrop/hooks/useMinWidth.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,21 @@ import { IInputs } from "../generated/ManifestTypes";
44
/**
55
* Custom hook to track the minWidth property from PCF context and update when it or scaling changes.
66
* @param context The PCF context object
7-
* @param scaling The browser scaling factor to apply
87
* @returns The current scaled minWidth value (number | undefined)
98
*/
10-
export function useMinWidth(context: ComponentFramework.Context<IInputs>, scaling = 1): number | undefined {
9+
export function useMinWidth(context: ComponentFramework.Context<IInputs>): number | undefined {
1110
const getMinWidth = () => {
1211
const raw = context.parameters.minWidth?.raw;
1312
if (raw === undefined || raw === null || (typeof raw === "string" && raw === "")) return undefined;
1413
const num = Number(raw);
1514
if (isNaN(num) || num === -1) return undefined;
16-
return num * scaling;
15+
return num;
1716
};
1817

1918
const [minWidth, setMinWidth] = useState<number | undefined>(getMinWidth());
2019

2120
useEffect(() => {
2221
setMinWidth(getMinWidth());
23-
}, [context.parameters.minWidth?.raw, scaling]);
24-
22+
}, [context.parameters.minWidth?.raw])
2523
return minWidth;
2624
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useState, useEffect } from "react";
2+
3+
/**
4+
* Calculates the scaling factor applied by Power Apps' responsive layout.
5+
* Compares allocated size (from context) to rendered size (via getBoundingClientRect).
6+
*/
7+
export function useResponsiveAppScaling(
8+
context: ComponentFramework.Context<any>,
9+
elementRef: React.RefObject<HTMLElement | null>
10+
): number {
11+
const [appScaling, setAppScaling] = useState(1);
12+
13+
useEffect(() => {
14+
if (!elementRef.current) return;
15+
16+
const allocatedWidth = context.mode.allocatedWidth;
17+
const allocatedHeight = context.mode.allocatedHeight;
18+
19+
const updateAppScaling = () => {
20+
const rect = elementRef.current?.getBoundingClientRect();
21+
if (!rect || allocatedWidth === 0 || allocatedHeight === 0) return;
22+
23+
const scaleX = rect.width / allocatedWidth;
24+
const scaleY = rect.height / allocatedHeight;
25+
26+
// Use the smaller value for conservative scaling
27+
setAppScaling(Math.min(scaleX, scaleY));
28+
};
29+
30+
updateAppScaling();
31+
32+
const observer = new ResizeObserver(updateAppScaling);
33+
observer.observe(elementRef.current);
34+
35+
return () => {
36+
observer.disconnect();
37+
};
38+
}, [context, elementRef]);
39+
40+
return appScaling;
41+
}

0 commit comments

Comments
 (0)