mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat: add showRemaining functionality to current time display
Adds support for displaying remaining time (countdown) instead of elapsed time:
**HTML Component:**
- Add `show-remaining` attribute support with observedAttributes
- Implement attributeChangedCallback for reactive updates
- Display remaining time as `-{duration - currentTime}` when attribute present
- Maintain backward compatibility with default current time display
**React Component:**
- Add `showRemaining` prop with proper TypeScript typing
- Calculate and display remaining time in render function
- Destructure prop to avoid passing to DOM element
- Consistent `-{remaining}` format matching HTML component
**Usage:**
- HTML: `<media-current-time-display show-remaining></media-current-time-display>`
- React: `<CurrentTimeDisplay showRemaining />`
Both implementations include documentation comments and maintain
consistent behavior across platforms.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
committed by
Christian Pillsbury
co-authored by
Claude
parent
3bca85f180
commit
ab07a8a9a2
@@ -3,7 +3,10 @@ import {
|
||||
StateHook,
|
||||
PropsHook,
|
||||
} from '../utils/component-factory';
|
||||
import { currentTimeDisplayStateDefinition, formatDisplayTime } from '@vjs-10/media-store';
|
||||
import {
|
||||
currentTimeDisplayStateDefinition,
|
||||
formatDisplayTime,
|
||||
} from '@vjs-10/media-store';
|
||||
import { namedNodeMapToObject } from '../utils/element-utils.js';
|
||||
|
||||
export function getTemplateHTML(
|
||||
@@ -21,6 +24,7 @@ export class CurrentTimeDisplayBase extends HTMLElement {
|
||||
mode: 'open' as ShadowRootMode,
|
||||
};
|
||||
static getTemplateHTML = getTemplateHTML;
|
||||
static observedAttributes = ['show-remaining'];
|
||||
|
||||
_state:
|
||||
| {
|
||||
@@ -56,13 +60,39 @@ export class CurrentTimeDisplayBase extends HTMLElement {
|
||||
return this._state?.duration;
|
||||
}
|
||||
|
||||
get showRemaining() {
|
||||
return this.hasAttribute('show-remaining');
|
||||
}
|
||||
|
||||
attributeChangedCallback(
|
||||
name: string,
|
||||
_oldValue: string | null,
|
||||
_newValue: string | null,
|
||||
) {
|
||||
if (name === 'show-remaining' && this._state) {
|
||||
// Re-render with current state when show-remaining attribute changes
|
||||
this._update({}, this._state);
|
||||
}
|
||||
}
|
||||
|
||||
_update(_props: any, state: any) {
|
||||
this._state = state;
|
||||
|
||||
// Update the span content with formatted current time
|
||||
|
||||
// Update the span content with formatted time
|
||||
const spanElement = this.shadowRoot?.querySelector('span') as HTMLElement;
|
||||
if (spanElement) {
|
||||
spanElement.textContent = formatDisplayTime(state.currentTime);
|
||||
if (
|
||||
this.showRemaining &&
|
||||
state.duration != null &&
|
||||
state.currentTime != null
|
||||
) {
|
||||
// Show remaining time: duration - currentTime
|
||||
const remainingTime = state.duration - state.currentTime;
|
||||
spanElement.textContent = `-${formatDisplayTime(remainingTime)}`;
|
||||
} else {
|
||||
// Show current time (default behavior)
|
||||
spanElement.textContent = formatDisplayTime(state.currentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +138,10 @@ export const CurrentTimeDisplay = toConnectedHTMLComponent(
|
||||
// Register the custom element
|
||||
if (!globalThis.customElements.get('media-current-time-display')) {
|
||||
// @ts-ignore - Custom element constructor compatibility
|
||||
globalThis.customElements.define('media-current-time-display', CurrentTimeDisplay);
|
||||
globalThis.customElements.define(
|
||||
'media-current-time-display',
|
||||
CurrentTimeDisplay,
|
||||
);
|
||||
}
|
||||
|
||||
export default CurrentTimeDisplay;
|
||||
export default CurrentTimeDisplay;
|
||||
|
||||
@@ -114,6 +114,7 @@ export function getTemplateHTML() {
|
||||
<media-play-icon class="icon play-icon"></media-play-icon>
|
||||
<media-pause-icon class="icon pause-icon"></media-pause-icon>
|
||||
</media-play-button>
|
||||
<!-- Use the show-remaining attribute to show count down/remaining time -->
|
||||
<media-current-time-display></media-current-time-display>
|
||||
<media-time-range></media-time-range>
|
||||
<media-duration-display></media-duration-display>
|
||||
|
||||
@@ -5,7 +5,10 @@ import {
|
||||
} from '@vjs-10/react-media-store';
|
||||
import * as React from 'react';
|
||||
import { toConnectedComponent } from '../utils/component-factory';
|
||||
import { currentTimeDisplayStateDefinition, formatDisplayTime } from '@vjs-10/media-store';
|
||||
import {
|
||||
currentTimeDisplayStateDefinition,
|
||||
formatDisplayTime,
|
||||
} from '@vjs-10/media-store';
|
||||
|
||||
export const useCurrentTimeDisplayState = (_props: any) => {
|
||||
const mediaStore = useMediaStore();
|
||||
@@ -26,7 +29,7 @@ export type useCurrentTimeDisplayState = typeof useCurrentTimeDisplayState;
|
||||
export type CurrentTimeDisplayState = ReturnType<useCurrentTimeDisplayState>;
|
||||
|
||||
export const useCurrentTimeDisplayProps = (
|
||||
props: React.PropsWithChildren<{ [k: string]: any }>,
|
||||
props: React.PropsWithChildren<{ showRemaining?: boolean; [k: string]: any }>,
|
||||
state: ReturnType<typeof useCurrentTimeDisplayState>,
|
||||
) => {
|
||||
const baseProps: Record<string, any> = {
|
||||
@@ -44,11 +47,19 @@ export const renderCurrentTimeDisplay = (
|
||||
props: CurrentTimeDisplayProps,
|
||||
state: CurrentTimeDisplayState,
|
||||
) => {
|
||||
return (
|
||||
<span {...props}>
|
||||
{formatDisplayTime(state.currentTime)}
|
||||
</span>
|
||||
);
|
||||
const { showRemaining, ...restProps } = props;
|
||||
|
||||
let timeToDisplay: number | undefined;
|
||||
|
||||
if (showRemaining && state.duration != null && state.currentTime != null) {
|
||||
// Show remaining time: duration - currentTime
|
||||
timeToDisplay = state.duration - state.currentTime;
|
||||
} else {
|
||||
// Show current time (default behavior)
|
||||
timeToDisplay = state.currentTime;
|
||||
}
|
||||
|
||||
return <span {...restProps}>-{formatDisplayTime(timeToDisplay)}</span>;
|
||||
};
|
||||
|
||||
export type renderCurrentTimeDisplay = typeof renderCurrentTimeDisplay;
|
||||
@@ -59,4 +70,4 @@ export const CurrentTimeDisplay = toConnectedComponent(
|
||||
renderCurrentTimeDisplay,
|
||||
'CurrentTimeDisplay',
|
||||
);
|
||||
export default CurrentTimeDisplay;
|
||||
export default CurrentTimeDisplay;
|
||||
|
||||
@@ -31,7 +31,11 @@ export const MediaSkinDefault: React.FC<{ children: React.ReactNode }> = ({
|
||||
<PlayIcon className={styles.PlayIcon}></PlayIcon>
|
||||
<PauseIcon className={styles.PauseIcon}></PauseIcon>
|
||||
</PlayButton>
|
||||
<CurrentTimeDisplay className={styles.TimeDisplay} />
|
||||
<CurrentTimeDisplay
|
||||
// Use showRemaining to show count down/remaining time
|
||||
// showRemaining
|
||||
className={styles.TimeDisplay}
|
||||
/>
|
||||
<TimeRange className={styles.TimeRange} />
|
||||
<DurationDisplay className={styles.TimeDisplay} />
|
||||
{/* @ts-ignore */}
|
||||
@@ -48,7 +52,9 @@ export const MediaSkinDefault: React.FC<{ children: React.ReactNode }> = ({
|
||||
</MuteButton>
|
||||
<VolumeRange className={styles.VolumeRange} />
|
||||
{/* @ts-ignore */}
|
||||
<FullscreenButton className={`${styles.Button} ${styles.MediaFullscreenButton}`}>
|
||||
<FullscreenButton
|
||||
className={`${styles.Button} ${styles.MediaFullscreenButton}`}
|
||||
>
|
||||
<FullscreenEnterIcon
|
||||
className={`${styles.Icon} ${styles.FullscreenEnterIcon}`}
|
||||
></FullscreenEnterIcon>
|
||||
|
||||
Reference in New Issue
Block a user