feat: Add support for rotating camera streams (#2149)

* Closes #1307
This commit is contained in:
Dermot Duffy
2025-08-23 17:30:53 -07:00
committed by GitHub
parent 69ae80d6f1
commit 4d4b64232a
25 changed files with 1393 additions and 764 deletions
+22 -1
View File
@@ -209,6 +209,27 @@ export const setOrRemoveAttribute = <T extends string>(
}
};
/**
* Set or remove a style property on a HTMLElement.
* @param element The element.
* @param set If `true` sets the property, otherwise removes it.
* @param name The property name.
* @param value An optional value to set the property to. Never used if set is
* `false`.
*/
export const setOrRemoveStyleProperty = <T extends string>(
element: HTMLElement,
set: boolean,
name: string,
value?: T,
): void => {
if (set) {
element.style.setProperty(name, value ?? '');
} else {
element.style.removeProperty(name);
}
};
/**
* Allow typescript to narrow types based on truthy filter.
*/
@@ -243,7 +264,7 @@ export const recursivelyMergeObjectsConcatenatingArraysUniquely = <T>(
};
export const aspectRatioToString = (options?: {
ratio?: number[];
ratio?: number[] | null;
defaultStatic?: boolean;
}): string => {
if (options?.ratio && options.ratio.length === 2) {
+21 -28
View File
@@ -1,4 +1,5 @@
import { MediaLayoutConfig } from '../config/schema/camera/media-layout';
import { setOrRemoveStyleProperty } from './basic';
/**
* Update element style from a media configuration.
@@ -9,36 +10,28 @@ export const updateElementStyleFromMediaLayoutConfig = (
element: HTMLElement,
mediaLayoutConfig?: MediaLayoutConfig,
): void => {
if (mediaLayoutConfig?.fit !== undefined) {
element.style.setProperty(
'--advanced-camera-card-media-layout-fit',
mediaLayoutConfig.fit,
);
} else {
element.style.removeProperty('--advanced-camera-card-media-layout-fit');
}
setOrRemoveStyleProperty(
element,
!!mediaLayoutConfig?.fit,
'--advanced-camera-card-media-layout-fit',
mediaLayoutConfig?.fit,
);
for (const dimension of ['x', 'y']) {
if (mediaLayoutConfig?.position?.[dimension] !== undefined) {
element.style.setProperty(
`--advanced-camera-card-media-layout-position-${dimension}`,
`${mediaLayoutConfig.position[dimension]}%`,
);
} else {
element.style.removeProperty(
`--advanced-camera-card-media-layout-position-${dimension}`,
);
}
setOrRemoveStyleProperty(
element,
!!mediaLayoutConfig?.position?.[dimension],
`--advanced-camera-card-media-layout-position-${dimension}`,
`${mediaLayoutConfig?.position?.[dimension]}%`,
);
}
for (const dimension of ['top', 'bottom', 'left', 'right']) {
if (mediaLayoutConfig?.view_box?.[dimension] !== undefined) {
element.style.setProperty(
`--advanced-camera-card-media-layout-view-box-${dimension}`,
`${mediaLayoutConfig.view_box[dimension]}%`,
);
} else {
element.style.removeProperty(
`--advanced-camera-card-media-layout-view-box-${dimension}`,
);
}
setOrRemoveStyleProperty(
element,
!!mediaLayoutConfig?.view_box?.[dimension],
`--advanced-camera-card-media-layout-view-box-${dimension}`,
`${mediaLayoutConfig?.view_box?.[dimension]}%`,
);
}
};