fix: Render media correctly in rtl languages (#1757)
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
|||||||
CarouselController,
|
CarouselController,
|
||||||
CarouselDirection,
|
CarouselDirection,
|
||||||
} from '../utils/embla/carousel-controller';
|
} from '../utils/embla/carousel-controller';
|
||||||
|
import { getTextDirection } from '../utils/text-direction';
|
||||||
|
|
||||||
export type EmblaCarouselPlugins = CreatePluginType<
|
export type EmblaCarouselPlugins = CreatePluginType<
|
||||||
LoosePluginType,
|
LoosePluginType,
|
||||||
@@ -85,13 +86,13 @@ export class FrigateCardCarousel extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html` <div class="embla">
|
return html` <div class="embla">
|
||||||
<slot name="previous"></slot>
|
<slot name="left"></slot>
|
||||||
<div ${ref(this._refRoot)} class="embla__viewport">
|
<div ${ref(this._refRoot)} class="embla__viewport">
|
||||||
<div class="embla__container">
|
<div class="embla__container">
|
||||||
<slot ${ref(this._refParent)}></slot>
|
<slot ${ref(this._refParent)}></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot name="next"></slot>
|
<slot name="right"></slot>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@ export class FrigateCardCarousel extends LitElement {
|
|||||||
transitionEffect: this.transitionEffect,
|
transitionEffect: this.transitionEffect,
|
||||||
loop: this.loop,
|
loop: this.loop,
|
||||||
plugins: this.plugins,
|
plugins: this.plugins,
|
||||||
|
textDirection: getTextDirection(this),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else if (changedProps.has('selected')) {
|
} else if (changedProps.has('selected')) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { customElement, property, state } from 'lit/decorators.js';
|
|||||||
import { guard } from 'lit/directives/guard.js';
|
import { guard } from 'lit/directives/guard.js';
|
||||||
import { createRef, Ref, ref } from 'lit/directives/ref.js';
|
import { createRef, Ref, ref } from 'lit/directives/ref.js';
|
||||||
import { CameraManager } from '../../camera-manager/manager.js';
|
import { CameraManager } from '../../camera-manager/manager.js';
|
||||||
|
import { CameraManagerCameraMetadata } from '../../camera-manager/types.js';
|
||||||
import {
|
import {
|
||||||
ConditionsManagerEpoch,
|
ConditionsManagerEpoch,
|
||||||
getOverriddenConfig,
|
getOverriddenConfig,
|
||||||
@@ -37,6 +38,7 @@ import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy
|
|||||||
import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js';
|
import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js';
|
||||||
import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js';
|
import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js';
|
||||||
import { getStreamCameraID } from '../../utils/substream.js';
|
import { getStreamCameraID } from '../../utils/substream.js';
|
||||||
|
import { getTextDirection } from '../../utils/text-direction.js';
|
||||||
import { View } from '../../view/view.js';
|
import { View } from '../../view/view.js';
|
||||||
import '../carousel';
|
import '../carousel';
|
||||||
import { EmblaCarouselPlugins } from '../carousel.js';
|
import { EmblaCarouselPlugins } from '../carousel.js';
|
||||||
@@ -49,6 +51,16 @@ import { FrigateCardLiveProvider } from './provider.js';
|
|||||||
|
|
||||||
const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider';
|
const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider';
|
||||||
|
|
||||||
|
interface CameraNeighbor {
|
||||||
|
id: string;
|
||||||
|
metadata?: CameraManagerCameraMetadata | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CameraNeighbors {
|
||||||
|
previous?: CameraNeighbor;
|
||||||
|
next?: CameraNeighbor;
|
||||||
|
}
|
||||||
|
|
||||||
@customElement('frigate-card-live-carousel')
|
@customElement('frigate-card-live-carousel')
|
||||||
export class FrigateCardLiveCarousel extends LitElement {
|
export class FrigateCardLiveCarousel extends LitElement {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
@@ -315,31 +327,74 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _getCameraIDsOfNeighbors(): [string | null, string | null] {
|
protected _getSubstreamCameraID(cameraID: string, view?: View | null): string {
|
||||||
|
return view?.context?.live?.overrides?.get(cameraID) ?? cameraID;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _getCameraNeighbors(): CameraNeighbors | null {
|
||||||
const cameraIDs = this.cameraManager
|
const cameraIDs = this.cameraManager
|
||||||
? [...this.cameraManager?.getStore().getCameraIDsWithCapability('live')]
|
? [...this.cameraManager?.getStore().getCameraIDsWithCapability('live')]
|
||||||
: [];
|
: [];
|
||||||
const view = this.viewManagerEpoch?.manager.getView();
|
const view = this.viewManagerEpoch?.manager.getView();
|
||||||
|
|
||||||
if (this.viewFilterCameraID || cameraIDs.length <= 1 || !view || !this.hass) {
|
if (this.viewFilterCameraID || cameraIDs.length <= 1 || !view || !this.hass) {
|
||||||
return [null, null];
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const cameraID = this.viewFilterCameraID ?? view.camera;
|
const cameraID = this.viewFilterCameraID ?? view.camera;
|
||||||
const currentIndex = cameraIDs.indexOf(cameraID);
|
const currentIndex = cameraIDs.indexOf(cameraID);
|
||||||
|
|
||||||
if (currentIndex < 0) {
|
if (currentIndex < 0) {
|
||||||
return [null, null];
|
return {};
|
||||||
}
|
}
|
||||||
|
const prevID = cameraIDs[currentIndex > 0 ? currentIndex - 1 : cameraIDs.length - 1];
|
||||||
|
const nextID = cameraIDs[currentIndex + 1 < cameraIDs.length ? currentIndex + 1 : 0];
|
||||||
|
|
||||||
return [
|
return {
|
||||||
cameraIDs[currentIndex > 0 ? currentIndex - 1 : cameraIDs.length - 1],
|
previous: {
|
||||||
cameraIDs[currentIndex + 1 < cameraIDs.length ? currentIndex + 1 : 0],
|
id: prevID,
|
||||||
];
|
metadata: prevID
|
||||||
|
? this.cameraManager?.getCameraMetadata(
|
||||||
|
this._getSubstreamCameraID(prevID, view),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
next: {
|
||||||
|
id: nextID,
|
||||||
|
metadata: nextID
|
||||||
|
? this.cameraManager?.getCameraMetadata(
|
||||||
|
this._getSubstreamCameraID(nextID, view),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _getSubstreamCameraID(cameraID: string, view?: View | null): string {
|
protected _renderNextPrevious(
|
||||||
return view?.context?.live?.overrides?.get(cameraID) ?? cameraID;
|
side: 'left' | 'right',
|
||||||
|
neighbors: CameraNeighbors | null,
|
||||||
|
): TemplateResult {
|
||||||
|
const textDirection = getTextDirection(this);
|
||||||
|
const neighbor =
|
||||||
|
(textDirection === 'ltr' && side === 'left') ||
|
||||||
|
(textDirection === 'rtl' && side === 'right')
|
||||||
|
? neighbors?.previous
|
||||||
|
: neighbors?.next;
|
||||||
|
|
||||||
|
return html`<frigate-card-next-previous-control
|
||||||
|
slot=${side}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.side=${side}
|
||||||
|
.controlConfig=${this.overriddenLiveConfig?.controls.next_previous}
|
||||||
|
.label=${neighbor?.metadata?.title ?? ''}
|
||||||
|
.icon=${neighbor?.metadata?.icon}
|
||||||
|
?disabled=${!neighbor}
|
||||||
|
@click=${(ev) => {
|
||||||
|
this._setViewCameraID(neighbor?.id);
|
||||||
|
stopEventFromActivatingCardWideActions(ev);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</frigate-card-next-previous-control>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
@@ -355,14 +410,8 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hasMultipleCameras = slides.length > 1;
|
const hasMultipleCameras = slides.length > 1;
|
||||||
const [prevID, nextID] = this._getCameraIDsOfNeighbors();
|
const neighbors = this._getCameraNeighbors();
|
||||||
|
|
||||||
const cameraMetadataPrevious = prevID
|
|
||||||
? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(prevID, view))
|
|
||||||
: null;
|
|
||||||
const cameraMetadataNext = nextID
|
|
||||||
? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(nextID, view))
|
|
||||||
: null;
|
|
||||||
const forcePTZVisibility =
|
const forcePTZVisibility =
|
||||||
!this._mediaHasLoaded ||
|
!this._mediaHasLoaded ||
|
||||||
(!!this.viewFilterCameraID && this.viewFilterCameraID !== view.camera) ||
|
(!!this.viewFilterCameraID && this.viewFilterCameraID !== view.camera) ||
|
||||||
@@ -393,35 +442,11 @@ export class FrigateCardLiveCarousel extends LitElement {
|
|||||||
this._mediaHasLoaded = false;
|
this._mediaHasLoaded = false;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<frigate-card-next-previous-control
|
${this._renderNextPrevious('left', neighbors)}
|
||||||
slot="previous"
|
<!-- -->
|
||||||
.hass=${this.hass}
|
|
||||||
.direction=${'previous'}
|
|
||||||
.controlConfig=${this.overriddenLiveConfig.controls.next_previous}
|
|
||||||
.label=${cameraMetadataPrevious?.title ?? ''}
|
|
||||||
.icon=${cameraMetadataPrevious?.icon}
|
|
||||||
?disabled=${prevID === null}
|
|
||||||
@click=${(ev) => {
|
|
||||||
this._setViewCameraID(prevID);
|
|
||||||
stopEventFromActivatingCardWideActions(ev);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
</frigate-card-next-previous-control>
|
|
||||||
${slides}
|
${slides}
|
||||||
<frigate-card-next-previous-control
|
<!-- -->
|
||||||
slot="next"
|
${this._renderNextPrevious('right', neighbors)}
|
||||||
.hass=${this.hass}
|
|
||||||
.direction=${'next'}
|
|
||||||
.controlConfig=${this.overriddenLiveConfig.controls.next_previous}
|
|
||||||
.label=${cameraMetadataNext?.title ?? ''}
|
|
||||||
.icon=${cameraMetadataNext?.icon}
|
|
||||||
?disabled=${nextID === null}
|
|
||||||
@click=${(ev) => {
|
|
||||||
this._setViewCameraID(nextID);
|
|
||||||
stopEventFromActivatingCardWideActions(ev);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
</frigate-card-next-previous-control>
|
|
||||||
</frigate-card-carousel>
|
</frigate-card-carousel>
|
||||||
<frigate-card-ptz
|
<frigate-card-ptz
|
||||||
.config=${this.overriddenLiveConfig.controls.ptz}
|
.config=${this.overriddenLiveConfig.controls.ptz}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
|||||||
@customElement('frigate-card-next-previous-control')
|
@customElement('frigate-card-next-previous-control')
|
||||||
export class FrigateCardNextPreviousControl extends LitElement {
|
export class FrigateCardNextPreviousControl extends LitElement {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public direction?: 'next' | 'previous';
|
public side?: 'left' | 'right';
|
||||||
|
|
||||||
set controlConfig(controlConfig: NextPreviousControlConfig | undefined) {
|
set controlConfig(controlConfig: NextPreviousControlConfig | undefined) {
|
||||||
if (controlConfig?.size) {
|
if (controlConfig?.size) {
|
||||||
@@ -53,8 +53,8 @@ export class FrigateCardNextPreviousControl extends LitElement {
|
|||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
controls: true,
|
controls: true,
|
||||||
left: this.direction === 'previous',
|
left: this.side === 'left',
|
||||||
right: this.direction === 'next',
|
right: this.side === 'right',
|
||||||
thumbnails: !renderIcon,
|
thumbnails: !renderIcon,
|
||||||
icons: renderIcon,
|
icons: renderIcon,
|
||||||
button: renderIcon,
|
button: renderIcon,
|
||||||
@@ -63,7 +63,7 @@ export class FrigateCardNextPreviousControl extends LitElement {
|
|||||||
if (renderIcon) {
|
if (renderIcon) {
|
||||||
const icon =
|
const icon =
|
||||||
!this.thumbnail || !this.icon || this._controlConfig.style === 'chevrons'
|
!this.thumbnail || !this.icon || this._controlConfig.style === 'chevrons'
|
||||||
? this.direction === 'previous'
|
? this.side === 'left'
|
||||||
? 'mdi:chevron-left'
|
? 'mdi:chevron-left'
|
||||||
: 'mdi:chevron-right'
|
: 'mdi:chevron-right'
|
||||||
: this.icon;
|
: this.icon;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy
|
|||||||
import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js';
|
import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js';
|
||||||
import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js';
|
import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js';
|
||||||
import { ResolvedMediaCache } from '../../utils/ha/resolved-media.js';
|
import { ResolvedMediaCache } from '../../utils/ha/resolved-media.js';
|
||||||
|
import { getTextDirection } from '../../utils/text-direction.js';
|
||||||
import { ViewMedia } from '../../view/media.js';
|
import { ViewMedia } from '../../view/media.js';
|
||||||
import '../carousel';
|
import '../carousel';
|
||||||
import type { EmblaCarouselPlugins } from '../carousel.js';
|
import type { EmblaCarouselPlugins } from '../carousel.js';
|
||||||
@@ -306,6 +307,44 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected _renderNextPrevious(
|
||||||
|
side: 'left' | 'right',
|
||||||
|
neighbors?: MediaNeighbors | null,
|
||||||
|
): TemplateResult {
|
||||||
|
const scroll = (direction: 'previous' | 'next'): void => {
|
||||||
|
if (!neighbors || !this._media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newIndex =
|
||||||
|
(direction === 'previous' ? neighbors.previous?.index : neighbors.next?.index) ??
|
||||||
|
null;
|
||||||
|
if (newIndex !== null) {
|
||||||
|
this._setViewSelectedIndex(newIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const textDirection = getTextDirection(this);
|
||||||
|
const scrollDirection =
|
||||||
|
(textDirection === 'ltr' && side === 'left') ||
|
||||||
|
(textDirection === 'rtl' && side === 'right')
|
||||||
|
? 'previous'
|
||||||
|
: 'next';
|
||||||
|
|
||||||
|
return html` <frigate-card-next-previous-control
|
||||||
|
slot=${side}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.side=${side}
|
||||||
|
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
||||||
|
.thumbnail=${neighbors?.[scrollDirection]?.media.getThumbnail() ?? undefined}
|
||||||
|
.label=${neighbors?.[scrollDirection]?.media.getTitle() ?? ''}
|
||||||
|
?disabled=${!neighbors?.[scrollDirection]}
|
||||||
|
@click=${(ev: Event) => {
|
||||||
|
scroll(scrollDirection);
|
||||||
|
stopEventFromActivatingCardWideActions(ev);
|
||||||
|
}}
|
||||||
|
></frigate-card-next-previous-control>`;
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
const mediaCount = this._media?.length ?? 0;
|
const mediaCount = this._media?.length ?? 0;
|
||||||
if (!this._media || !mediaCount) {
|
if (!this._media || !mediaCount) {
|
||||||
@@ -324,18 +363,6 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const neighbors = this._getMediaNeighbors();
|
const neighbors = this._getMediaNeighbors();
|
||||||
const scroll = (direction: 'previous' | 'next'): void => {
|
|
||||||
if (!neighbors || !this._media) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const newIndex =
|
|
||||||
(direction === 'previous' ? neighbors.previous?.index : neighbors.next?.index) ??
|
|
||||||
null;
|
|
||||||
if (newIndex !== null) {
|
|
||||||
this._setViewSelectedIndex(newIndex);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const view = this.viewManagerEpoch?.manager.getView();
|
const view = this.viewManagerEpoch?.manager.getView();
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@@ -356,37 +383,9 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
this._player = null;
|
this._player = null;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
${this.showControls
|
${this.showControls ? this._renderNextPrevious('left', neighbors) : ''}
|
||||||
? html` <frigate-card-next-previous-control
|
|
||||||
slot="previous"
|
|
||||||
.hass=${this.hass}
|
|
||||||
.direction=${'previous'}
|
|
||||||
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
|
||||||
.thumbnail=${neighbors?.previous?.media.getThumbnail() ?? undefined}
|
|
||||||
.label=${neighbors?.previous?.media.getTitle() ?? ''}
|
|
||||||
?disabled=${!neighbors?.previous}
|
|
||||||
@click=${(ev: Event) => {
|
|
||||||
scroll('previous');
|
|
||||||
stopEventFromActivatingCardWideActions(ev);
|
|
||||||
}}
|
|
||||||
></frigate-card-next-previous-control>`
|
|
||||||
: ''}
|
|
||||||
${guard([this._media, view], () => this._getSlides())}
|
${guard([this._media, view], () => this._getSlides())}
|
||||||
${this.showControls
|
${this.showControls ? this._renderNextPrevious('right', neighbors) : ''}
|
||||||
? html` <frigate-card-next-previous-control
|
|
||||||
slot="next"
|
|
||||||
.hass=${this.hass}
|
|
||||||
.direction=${'next'}
|
|
||||||
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
|
||||||
.thumbnail=${neighbors?.next?.media.getThumbnail() ?? undefined}
|
|
||||||
.label=${neighbors?.next?.media.getTitle() ?? ''}
|
|
||||||
?disabled=${!neighbors?.next}
|
|
||||||
@click=${(ev: Event) => {
|
|
||||||
scroll('next');
|
|
||||||
stopEventFromActivatingCardWideActions(ev);
|
|
||||||
}}
|
|
||||||
></frigate-card-next-previous-control>`
|
|
||||||
: ''}
|
|
||||||
</frigate-card-carousel>
|
</frigate-card-carousel>
|
||||||
${view
|
${view
|
||||||
? html` <frigate-card-ptz
|
? html` <frigate-card-ptz
|
||||||
|
|||||||
@@ -40,14 +40,14 @@
|
|||||||
top: calc(50% - (var(--frigate-card-next-prev-size-hover) / 2));
|
top: calc(50% - (var(--frigate-card-next-prev-size-hover) / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls.previous.thumbnails:hover {
|
.controls.left.thumbnails:hover {
|
||||||
left: calc(
|
left: calc(
|
||||||
var(--frigate-card-left-position) -
|
var(--frigate-card-left-position) -
|
||||||
(var(--frigate-card-next-prev-size-hover) - var(--frigate-card-next-prev-size)) / 2
|
(var(--frigate-card-next-prev-size-hover) - var(--frigate-card-next-prev-size)) / 2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls.next.thumbnails:hover {
|
.controls.right.thumbnails:hover {
|
||||||
right: calc(
|
right: calc(
|
||||||
var(--frigate-card-right-position) -
|
var(--frigate-card-right-position) -
|
||||||
(var(--frigate-card-next-prev-size-hover) - var(--frigate-card-next-prev-size)) / 2
|
(var(--frigate-card-next-prev-size-hover) - var(--frigate-card-next-prev-size)) / 2
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plu
|
|||||||
import isEqual from 'lodash-es/isEqual';
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import { TransitionEffect } from '../../config/types';
|
import { TransitionEffect } from '../../config/types';
|
||||||
import { dispatchFrigateCardEvent, getChildrenFromElement } from '../basic.js';
|
import { dispatchFrigateCardEvent, getChildrenFromElement } from '../basic.js';
|
||||||
|
import { TextDirection } from '../text-direction';
|
||||||
|
|
||||||
export interface CarouselSelected {
|
export interface CarouselSelected {
|
||||||
index: number;
|
index: number;
|
||||||
@@ -23,6 +24,7 @@ export class CarouselController {
|
|||||||
protected _loop: boolean;
|
protected _loop: boolean;
|
||||||
protected _dragFree: boolean;
|
protected _dragFree: boolean;
|
||||||
protected _draggable: boolean;
|
protected _draggable: boolean;
|
||||||
|
protected _textDirection: TextDirection;
|
||||||
|
|
||||||
protected _plugins: EmblaCarouselPlugins;
|
protected _plugins: EmblaCarouselPlugins;
|
||||||
protected _carousel: EmblaCarouselType;
|
protected _carousel: EmblaCarouselType;
|
||||||
@@ -44,6 +46,7 @@ export class CarouselController {
|
|||||||
dragEnabled?: boolean;
|
dragEnabled?: boolean;
|
||||||
dragFree?: boolean;
|
dragFree?: boolean;
|
||||||
plugins?: EmblaCarouselPlugins;
|
plugins?: EmblaCarouselPlugins;
|
||||||
|
textDirection?: TextDirection;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
this._root = root;
|
this._root = root;
|
||||||
@@ -55,6 +58,7 @@ export class CarouselController {
|
|||||||
this._loop = options?.loop ?? false;
|
this._loop = options?.loop ?? false;
|
||||||
this._draggable = options?.dragEnabled ?? true;
|
this._draggable = options?.dragEnabled ?? true;
|
||||||
this._plugins = options?.plugins ?? [];
|
this._plugins = options?.plugins ?? [];
|
||||||
|
this._textDirection = options?.textDirection ?? 'ltr';
|
||||||
|
|
||||||
this._carousel = this._createCarousel(getChildrenFromElement(this._parent));
|
this._carousel = this._createCarousel(getChildrenFromElement(this._parent));
|
||||||
|
|
||||||
@@ -130,6 +134,8 @@ export class CarouselController {
|
|||||||
watchSlides: false,
|
watchSlides: false,
|
||||||
watchResize: true,
|
watchResize: true,
|
||||||
watchDrag: this._draggable,
|
watchDrag: this._draggable,
|
||||||
|
|
||||||
|
direction: this._textDirection,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
...this._plugins,
|
...this._plugins,
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export type TextDirection = 'ltr' | 'rtl';
|
||||||
|
|
||||||
|
export const getTextDirection = (element: HTMLElement): TextDirection => {
|
||||||
|
return getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';
|
||||||
|
};
|
||||||
@@ -194,6 +194,7 @@ describe('CarouselController', () => {
|
|||||||
loop: true,
|
loop: true,
|
||||||
dragEnabled: false,
|
dragEnabled: false,
|
||||||
plugins: plugins,
|
plugins: plugins,
|
||||||
|
textDirection: 'rtl',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(EmblaCarousel).toBeCalledWith(
|
expect(EmblaCarousel).toBeCalledWith(
|
||||||
@@ -209,6 +210,7 @@ describe('CarouselController', () => {
|
|||||||
watchSlides: false,
|
watchSlides: false,
|
||||||
watchResize: true,
|
watchResize: true,
|
||||||
watchDrag: false,
|
watchDrag: false,
|
||||||
|
direction: 'rtl',
|
||||||
},
|
},
|
||||||
plugins,
|
plugins,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { getTextDirection } from '../../src/utils/text-direction.js';
|
||||||
|
|
||||||
|
// @vitest-environment jsdom
|
||||||
|
describe('getTextDirection', () => {
|
||||||
|
it('should return rtl', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.style.direction = 'rtl';
|
||||||
|
|
||||||
|
expect(getTextDirection(element)).toBe('rtl');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return ltr', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.style.direction = 'ltr';
|
||||||
|
|
||||||
|
expect(getTextDirection(element)).toBe('ltr');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return ltr by default', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.style.direction = '_ANYTHING_ELSE_';
|
||||||
|
|
||||||
|
expect(getTextDirection(element)).toBe('ltr');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -38,6 +38,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [
|
|||||||
'utils/ptz.ts',
|
'utils/ptz.ts',
|
||||||
'utils/screenshot.ts',
|
'utils/screenshot.ts',
|
||||||
'utils/substream.ts',
|
'utils/substream.ts',
|
||||||
|
'utils/text-direction.ts',
|
||||||
'utils/timer.ts',
|
'utils/timer.ts',
|
||||||
'utils/zod.ts',
|
'utils/zod.ts',
|
||||||
'view/*.ts',
|
'view/*.ts',
|
||||||
|
|||||||
Reference in New Issue
Block a user