Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/nextjs-with-typescript/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
10 changes: 4 additions & 6 deletions src/js/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,14 @@ export type StateChangeEventToAttributeMap = {
export const StateChangeEventToAttributeMap = Object.entries(
MediaStateChangeEvents
).reduce(
(mapObj, [key, eventType]) => {
const attrName = MediaUIAttributes[key];
(mapObj: Record<string, string>, [key, eventType]) => {
const attrName = MediaUIAttributes[key as keyof typeof MediaUIAttributes];
if (attrName) {
mapObj[eventType] = attrName;
}
return mapObj;
},
{ userinactivechange: 'userinactive' } as Partial<
Writeable<StateChangeEventToAttributeMap>
>
{ userinactivechange: 'userinactive' } as Record<string, string>
) as StateChangeEventToAttributeMap;

/** @TODO Make types more precise derivations, at least after updates to event type names mentioned above (CJP) */
Expand All @@ -168,7 +166,7 @@ export const AttributeToStateChangeEventMap = Object.entries(
MediaUIAttributes
).reduce(
(mapObj, [key, attrName]) => {
const evtType = MediaStateChangeEvents[key];
const evtType = MediaStateChangeEvents[key as keyof typeof MediaStateChangeEvents];
if (evtType) {
mapObj[attrName] = evtType;
}
Expand Down
92 changes: 45 additions & 47 deletions src/js/extras/media-clip-selector/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,23 @@ class MediaClipSelector extends globalThis.HTMLElement {
];
}

draggingEl: HTMLElement | null;
wrapper: HTMLElement;
selection: HTMLElement;
playhead: HTMLElement;
leftTrim: HTMLElement;
spacerFirst: HTMLElement;
startHandle: HTMLElement;
spacerMiddle: HTMLElement;
endHandle: HTMLElement;
spacerLast: HTMLElement;
initialX: number;
thumbnailPreview: HTMLElement;

_clickHandler: () => void;
_dragStart: () => void;
_dragEnd: () => void;
_drag: () => void;
draggingEl: HTMLElement | null = null;
wrapper!: HTMLElement;
selection!: HTMLElement;
playhead!: HTMLElement;
leftTrim!: HTMLElement;
spacerFirst!: HTMLElement;
startHandle!: HTMLElement;
spacerMiddle!: HTMLElement;
endHandle!: HTMLElement;
spacerLast!: HTMLElement;
initialX: number = 0;
thumbnailPreview!: HTMLElement;

_clickHandler!: (evt: MouseEvent) => void;
_dragStart!: (evt: MouseEvent) => void;
_dragEnd!: () => void;
_drag!: (evt: MouseEvent) => void;

constructor() {
super();
Expand All @@ -175,15 +175,15 @@ class MediaClipSelector extends globalThis.HTMLElement {

this.draggingEl = null;

this.wrapper = this.shadowRoot.querySelector('#selectorContainer');
this.selection = this.shadowRoot.querySelector('#selection');
this.playhead = this.shadowRoot.querySelector('#playhead');
this.leftTrim = this.shadowRoot.querySelector('#leftTrim');
this.spacerFirst = this.shadowRoot.querySelector('#spacerFirst');
this.startHandle = this.shadowRoot.querySelector('#startHandle');
this.spacerMiddle = this.shadowRoot.querySelector('#spacerMiddle');
this.endHandle = this.shadowRoot.querySelector('#endHandle');
this.spacerLast = this.shadowRoot.querySelector('#spacerLast');
this.wrapper = this.shadowRoot!.querySelector('#selectorContainer') as HTMLElement;
this.selection = this.shadowRoot!.querySelector('#selection') as HTMLElement;
this.playhead = this.shadowRoot!.querySelector('#playhead') as HTMLElement;
this.leftTrim = this.shadowRoot!.querySelector('#leftTrim') as HTMLElement;
this.spacerFirst = this.shadowRoot!.querySelector('#spacerFirst') as HTMLElement;
this.startHandle = this.shadowRoot!.querySelector('#startHandle') as HTMLElement;
this.spacerMiddle = this.shadowRoot!.querySelector('#spacerMiddle') as HTMLElement;
this.endHandle = this.shadowRoot!.querySelector('#endHandle') as HTMLElement;
this.spacerLast = this.shadowRoot!.querySelector('#spacerLast') as HTMLElement;

this._clickHandler = this.handleClick.bind(this);
this._dragStart = this.dragStart.bind(this);
Expand All @@ -204,11 +204,11 @@ class MediaClipSelector extends globalThis.HTMLElement {
}

get mediaDuration(): number {
return +this.getAttribute(MediaUIAttributes.MEDIA_DURATION);
return +(this.getAttribute(MediaUIAttributes.MEDIA_DURATION) ?? 0);
}

get mediaCurrentTime(): number {
return +this.getAttribute(MediaUIAttributes.MEDIA_CURRENT_TIME);
return +(this.getAttribute(MediaUIAttributes.MEDIA_CURRENT_TIME) ?? 0);
}

/*
Expand All @@ -218,7 +218,7 @@ class MediaClipSelector extends globalThis.HTMLElement {
*/
getPlayheadBasedOnMouseEvent(evt: MouseEvent): number {
const duration = this.mediaDuration;
if (!duration) return;
if (!duration) return 0;
const mousePercent = lockBetweenZeroAndOne(this.getMousePercent(evt));
return mousePercent * duration;
}
Expand Down Expand Up @@ -252,7 +252,7 @@ class MediaClipSelector extends globalThis.HTMLElement {
}

dragEnd(): void {
this.initialX = null;
this.initialX = 0;
this.draggingEl = null;
}

Expand Down Expand Up @@ -424,18 +424,17 @@ class MediaClipSelector extends globalThis.HTMLElement {
*/
enableThumbnails(): void {
/** @type {HTMLElement} */
this.thumbnailPreview = this.shadowRoot.querySelector(
this.thumbnailPreview = this.shadowRoot!.querySelector(
'media-preview-thumbnail'
);
/** @type {HTMLElement} */
const thumbnailContainer = this.shadowRoot.querySelector(
) as HTMLElement;
const thumbnailContainer = this.shadowRoot!.querySelector(
'#thumbnailContainer'
);
) as HTMLElement;
thumbnailContainer.classList.add('enabled');

let mouseMoveHandler;
let mouseMoveHandler: (evt: MouseEvent) => void;
const trackMouse = () => {
mouseMoveHandler = (evt) => {
mouseMoveHandler = (evt: MouseEvent) => {
const duration = this.mediaDuration;

// If no duration we can't calculate which time to show
Expand All @@ -460,21 +459,20 @@ class MediaClipSelector extends globalThis.HTMLElement {
};
globalThis.window?.addEventListener('mousemove', mouseMoveHandler, false);
};

const stopTrackingMouse = () => {
globalThis.window?.removeEventListener('mousemove', mouseMoveHandler);
if (mouseMoveHandler) {
globalThis.window?.removeEventListener('mousemove', mouseMoveHandler);
}
};

// Trigger when the mouse moves over the range
let rangeEntered = false;
const rangeMouseMoveHander = () => {
const rangeMouseMoveHandler = () => {
if (!rangeEntered && this.mediaDuration) {
rangeEntered = true;
this.thumbnailPreview.style.display = 'block';
trackMouse();

const offRangeHandler = (evt) => {
if (evt.target != this && !this.contains(evt.target)) {
const offRangeHandler = (evt: MouseEvent) => {
if (evt.target != this && !this.contains(evt.target as Node)) {
this.thumbnailPreview.style.display = 'none';
globalThis.window?.removeEventListener(
'mousemove',
Expand All @@ -496,13 +494,13 @@ class MediaClipSelector extends globalThis.HTMLElement {
}
};

this.addEventListener('mousemove', rangeMouseMoveHander, false);
this.addEventListener('mousemove', rangeMouseMoveHandler, false);
}

disableThumbnails(): void {
const thumbnailContainer = this.shadowRoot.querySelector(
const thumbnailContainer = this.shadowRoot!.querySelector(
'#thumbnailContainer'
);
) as HTMLElement;
thumbnailContainer.classList.remove('enabled');
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/js/media-preview-chapter-display.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MediaTextDisplay } from './media-text-display.js';
import { globalThis } from './utils/server-safe-globals.js';
import { MediaUIAttributes } from './constants.js';
import { MediaTextDisplay } from './media-text-display.js';
import { getStringAttr, setStringAttr } from './utils/element-utils.js';
import { globalThis } from './utils/server-safe-globals.js';
import { t } from './utils/i18n.js';

/**
Expand All @@ -10,7 +10,7 @@ import { t } from './utils/i18n.js';
* @cssproperty [--media-preview-chapter-display-display = inline-flex] - `display` property of display.
*/
class MediaPreviewChapterDisplay extends MediaTextDisplay {
#slot: HTMLSlotElement;
#slot!: HTMLSlotElement;

static get observedAttributes(): string[] {
return [
Expand Down Expand Up @@ -59,8 +59,8 @@ class MediaPreviewChapterDisplay extends MediaTextDisplay {
return getStringAttr(this, MediaUIAttributes.MEDIA_PREVIEW_CHAPTER);
}

set mediaPreviewChapter(value: string | undefined) {
setStringAttr(this, MediaUIAttributes.MEDIA_PREVIEW_CHAPTER, value);
set mediaPreviewChapter(value: string | null) {
setStringAttr(this, MediaUIAttributes.MEDIA_PREVIEW_CHAPTER, value ?? '');
}
}

Expand Down
38 changes: 14 additions & 24 deletions src/js/media-preview-thumbnail.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import { MediaUIAttributes , MediaStateReceiverAttributes } from './constants.js';
import { getStringAttr, setStringAttr, getOrInsertCSSRule, namedNodeMapToObject } from './utils/element-utils.js';
import { globalThis } from './utils/server-safe-globals.js';
import {
MediaUIAttributes,
MediaStateReceiverAttributes,
} from './constants.js';
import {
getOrInsertCSSRule,
getStringAttr,
namedNodeMapToObject,
setStringAttr,
} from './utils/element-utils.js';
import MediaController from './media-controller.js';

function getTemplateHTML(_attrs: Record<string, string>) {
Expand Down Expand Up @@ -42,7 +34,9 @@ class MediaPreviewThumbnail extends globalThis.HTMLElement {
static shadowRootOptions = { mode: 'open' as ShadowRootMode };
static getTemplateHTML = getTemplateHTML;

#mediaController: MediaController;
#mediaController: MediaController | null = null;
imgWidth: number = 0;
imgHeight: number = 0;

static get observedAttributes() {
return [
Expand All @@ -51,10 +45,6 @@ class MediaPreviewThumbnail extends globalThis.HTMLElement {
MediaUIAttributes.MEDIA_PREVIEW_COORDS,
];
}

imgWidth: number;
imgHeight: number;

constructor() {
super();

Expand All @@ -63,7 +53,7 @@ class MediaPreviewThumbnail extends globalThis.HTMLElement {
this.attachShadow((this.constructor as typeof MediaPreviewThumbnail).shadowRootOptions);

const attrs = namedNodeMapToObject(this.attributes);
this.shadowRoot.innerHTML = (this.constructor as typeof MediaPreviewThumbnail).getTemplateHTML(attrs);
this.shadowRoot!.innerHTML = (this.constructor as typeof MediaPreviewThumbnail).getTemplateHTML(attrs);
}
}

Expand Down Expand Up @@ -160,9 +150,9 @@ class MediaPreviewThumbnail extends globalThis.HTMLElement {
const isScalingDown = maxRatio < 1;
const scale = isScalingDown ? maxRatio : minRatio > 1 ? minRatio : 1;

const { style } = getOrInsertCSSRule(this.shadowRoot, ':host');
const imgStyle = getOrInsertCSSRule(this.shadowRoot, 'img').style;
const img = this.shadowRoot.querySelector('img');
const { style } = getOrInsertCSSRule(this.shadowRoot!, ':host');
const imgStyle = getOrInsertCSSRule(this.shadowRoot!, 'img').style;
const img = this.shadowRoot!.querySelector('img');

// Revert one set of extremum to its initial value on a known scale direction.
const extremum = isScalingDown ? 'min' : 'max';
Expand All @@ -177,13 +167,13 @@ class MediaPreviewThumbnail extends globalThis.HTMLElement {
imgStyle.display = 'block';
};

if (img.src !== src) {
img.onload = () => {
this.imgWidth = img.naturalWidth;
this.imgHeight = img.naturalHeight;
if (img!.src !== src) {
img!.onload = () => {
this.imgWidth = img!.naturalWidth;
this.imgHeight = img!.naturalHeight;
resize();
};
img.src = src;
img!.src = src;
resize();
}

Expand Down
10 changes: 5 additions & 5 deletions src/js/media-preview-time-display.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { MediaUIAttributes } from './constants.js';
import { MediaTextDisplay } from './media-text-display.js';
import { globalThis } from './utils/server-safe-globals.js';
import { formatTime } from './utils/time.js';
import { MediaUIAttributes } from './constants.js';
import { getNumericAttr, setNumericAttr } from './utils/element-utils.js';
import { globalThis } from './utils/server-safe-globals.js';
// Todo: Use data locals: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString

/**
Expand All @@ -11,7 +11,7 @@ import { getNumericAttr, setNumericAttr } from './utils/element-utils.js';
* @cssproperty [--media-preview-time-display-display = inline-flex] - `display` property of display.
*/
class MediaPreviewTimeDisplay extends MediaTextDisplay {
#slot: HTMLSlotElement;
#slot!: HTMLSlotElement;

static get observedAttributes() {
return [...super.observedAttributes, MediaUIAttributes.MEDIA_PREVIEW_TIME];
Expand Down Expand Up @@ -42,8 +42,8 @@ class MediaPreviewTimeDisplay extends MediaTextDisplay {
return getNumericAttr(this, MediaUIAttributes.MEDIA_PREVIEW_TIME);
}

set mediaPreviewTime(value: number | undefined) {
setNumericAttr(this, MediaUIAttributes.MEDIA_PREVIEW_TIME, value);
set mediaPreviewTime(value: number) {
setNumericAttr(this, MediaUIAttributes.MEDIA_PREVIEW_TIME, value ?? 0);
}
}

Expand Down
Loading
Loading