@@ -291,7 +282,7 @@ export function getTemplateHTML() {
-
+
Play
@@ -318,7 +309,7 @@ export function getTemplateHTML() {
-
+
@@ -338,7 +329,7 @@ export function getTemplateHTML() {
-
+
Enter Fullscreen
diff --git a/packages/html/html/src/utils/component-factory.ts b/packages/html/html/src/utils/component-factory.ts
index 90be74e6..53cd2313 100644
--- a/packages/html/html/src/utils/component-factory.ts
+++ b/packages/html/html/src/utils/component-factory.ts
@@ -35,7 +35,7 @@ export function toConnectedHTMLComponent(
const ConnectedComponent = class extends ConsumerMixin(BaseClass) {
static get observedAttributes(): string[] {
return [
- // @ts-ignore
+ // @ts-expect-error ts(2339)
...(super.observedAttributes ?? []),
];
}
@@ -53,9 +53,8 @@ export function toConnectedHTMLComponent(
const state = stateHook.transform(rawState, mediaStore);
// Phase 2: Update element attributes/properties (props concern)
- // @ts-ignore - Element property access
- const props = propsHook(state ?? {}, this);
- // @ts-ignore
+ const props = propsHook(state ?? {} as State, this);
+ // @ts-expect-error any
this._update(props, state, mediaStore);
});
},
@@ -70,7 +69,7 @@ export function toConnectedHTMLComponent(
}
handleEvent(event: CustomEvent): void {
- // @ts-ignore
+ // @ts-expect-error any
super.handleEvent?.(event);
}
};
diff --git a/packages/react/react/src/components/MediaContainer.tsx b/packages/react/react/src/components/MediaContainer.tsx
index 3e55dad2..702ca310 100644
--- a/packages/react/react/src/components/MediaContainer.tsx
+++ b/packages/react/react/src/components/MediaContainer.tsx
@@ -52,13 +52,15 @@ export function useMediaContainerRef(): RefCallback {
*
* );
*/
-export const MediaContainer: FC>> = forwardRef(
- ({ children, ...props }, ref) => {
+export const MediaContainer: FC & { portalId?: string }>> = forwardRef(
+ ({ children, portalId = '@default_portal_id', ...props }, ref) => {
const containerRef = useMediaContainerRef();
const composedRef = useComposedRefs(ref, containerRef);
return (
{children}
+ {/* @TODO We need to make sure this is non-brittle longer term (CJP) */}
+
);
},
diff --git a/packages/react/react/src/components/Tooltip.tsx b/packages/react/react/src/components/Tooltip.tsx
index 2314f63f..061f0b9b 100644
--- a/packages/react/react/src/components/Tooltip.tsx
+++ b/packages/react/react/src/components/Tooltip.tsx
@@ -236,7 +236,7 @@ function TooltipArrow({ className = '', children }: TooltipArrowProps): JSX.Elem
);
}
-function TooltipPortal({ children, root, rootId }: TooltipPortalProps): JSX.Element {
+function TooltipPortal({ children, root, rootId = '@default_portal_id' }: TooltipPortalProps): JSX.Element {
return (
{children}
diff --git a/packages/react/react/src/index.ts b/packages/react/react/src/index.ts
index 14493cb2..4f43cfe5 100644
--- a/packages/react/react/src/index.ts
+++ b/packages/react/react/src/index.ts
@@ -2,10 +2,11 @@ export { CurrentTimeDisplay } from './components/CurrentTimeDisplay';
export { DurationDisplay } from './components/DurationDisplay';
export { FullscreenButton } from './components/FullscreenButton';
export { MediaContainer, useMediaContainerRef } from './components/MediaContainer';
-
export { MuteButton } from './components/MuteButton';
export { PlayButton } from './components/PlayButton';
export { Popover } from './components/Popover';
+export { TimeSlider } from './components/TimeSlider';
+export { Tooltip } from './components/Tooltip';
export { MediaElementVideo, Video } from './components/Video';
export { VolumeSlider } from './components/VolumeSlider';
export * from './skins';
diff --git a/packages/react/react/src/skins/default/MediaSkinDefault.tsx b/packages/react/react/src/skins/default/MediaSkinDefault.tsx
index ce0e9b16..a1972fb8 100644
--- a/packages/react/react/src/skins/default/MediaSkinDefault.tsx
+++ b/packages/react/react/src/skins/default/MediaSkinDefault.tsx
@@ -10,8 +10,6 @@ import {
VolumeOffIcon,
} from '@vjs-10/react-icons';
-import { useId } from 'react';
-
import { CurrentTimeDisplay } from '../../components/CurrentTimeDisplay';
import { DurationDisplay } from '../../components/DurationDisplay';
@@ -30,7 +28,6 @@ type SkinProps = PropsWithChildren<{
}>;
export default function MediaSkinDefault({ children, className = '' }: SkinProps): JSX.Element {
- const portalId = useId();
return (
{children}
@@ -42,11 +39,11 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
-
-
+
+
-
+
Play
@@ -77,12 +74,12 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
-
-
-
+
+
+
-
+
@@ -98,23 +95,21 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
-
-
-
+
+
+
-
+
-
- Enter Fullscreen
- Exit Fullscreen
+
+ Enter Fullscreen
+ Exit Fullscreen
-
-
);
}
diff --git a/packages/react/react/src/skins/default/styles.module.css b/packages/react/react/src/skins/default/styles.module.css
deleted file mode 100644
index 46b2424d..00000000
--- a/packages/react/react/src/skins/default/styles.module.css
+++ /dev/null
@@ -1,180 +0,0 @@
-/** @TODO: Improve/Polish CSS Here */
-/* Media Container UI/Styles */
-.Container {
- display: inline-block;
- position: relative;
- /* NOTE: Setting color here for generic inheritance, including SVG fill: currentColor defaults (CJP) */
- color: rgb(238 238 238);
-
- video {
- width: 100%;
- height: 100%;
- }
-
- .Overlay {
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- display: flex;
- flex-flow: column nowrap;
- align-items: start;
- /* pointer-events: none; */
- background: none;
- }
-}
-
-/* Generic Media Button Styling */
-.Button {
- border: none;
- background: rgb(20 20 30 / 0.7);
- padding: 4px;
- cursor: pointer;
- color: rgb(238 238 238);
-
- /* @TODO Currently, the web component version of icons "bakes in" these styles. Determine which approach we prefer (CJP) */
- .Icon {
- width: 24px;
- height: 24px;
- display: none;
- }
-}
-/*
-.MediaPlayButton:not([data-paused]) .PauseIcon,
-.MediaPlayButton[data-paused] .PlayIcon {
- display: inline-block;
-} */
-
-/* One way to define the "default visible" icon (CJP) */
-.MediaMuteButton:not([data-volume-level]) .VolumeLowIcon,
-.MediaMuteButton[data-volume-level='high'] .VolumeHighIcon,
-.MediaMuteButton[data-volume-level='low'] .VolumeLowIcon,
-.MediaMuteButton[data-volume-level='medium'] .VolumeLowIcon,
-.MediaMuteButton[data-volume-level='off'] .VolumeOffIcon {
- display: inline-block;
-}
-
-/* Fullscreen button icon states */
-.MediaFullscreenButton:not([data-fullscreen]) .FullscreenEnterIcon,
-.MediaFullscreenButton[data-fullscreen] .FullscreenExitIcon {
- display: inline-block;
-}
-
-/* Media Control Bar UI/Styles */
-.ControlBar {
- display: flex;
- align-items: center;
- justify-content: flex-start;
- width: 100%;
-}
-
-.Spacer {
- flex-grow: 1;
-}
-
-/* Time Display Styling */
-.TimeDisplay {
- background: rgb(20 20 30 / 0.7);
- padding: 4px 8px;
- color: rgb(238 238 238);
- font-family: monospace;
- font-size: 14px;
- border-radius: 2px;
- min-width: 3em;
- text-align: center;
-}
-
-/* Base Button Styling */
-.MediaPlayButton {
- border: none;
- background: rgb(20 20 30 / 0.7);
- padding: 4px;
- cursor: pointer;
- color: rgb(238 238 238);
-
- /* Basic Icon Styling for Buttons */
- .PlayIcon,
- .PauseIcon {
- width: 24px;
- height: 24px;
- display: none; /* Hide icons by default */
- }
-
- /* Show PlayIcon if paused and PauseIcon if unpaused */
- &:not([data-paused]) .PauseIcon,
- &[data-paused] .PlayIcon {
- display: inline-block;
- }
-}
-
-/* TimeSlider Component Styles */
-.TimeSliderRoot {
- display: flex;
- align-items: center;
- position: relative;
- min-width: 100px;
- width: 100%;
- padding-block: 0.75rem;
- margin: 0 0.5rem;
-}
-
-.TimeSliderTrack {
- position: relative;
- width: 100%;
- height: 0.375rem;
- background-color: #e0e0e0;
- border-radius: 0.25rem;
- overflow: hidden;
-}
-
-.TimeSliderThumb {
- width: 0.75rem;
- height: 0.75rem;
- background-color: #fff;
- border-radius: 50%;
- pointer-events: none;
-}
-
-.TimeSliderPointer {
- background-color: rgba(255, 255, 255, 0.5);
- pointer-events: none;
-}
-
-.TimeSliderProgress {
- background-color: #007bff;
- border-radius: inherit;
-}
-
-/* VolumeSlider Component Styles */
-.VolumeSliderRoot {
- display: flex;
- align-items: center;
- position: relative;
- min-width: 80px;
- width: 80px;
- padding-block: 0.75rem;
- margin: 0 0.5rem;
-}
-
-.VolumeSliderTrack {
- position: relative;
- width: 100%;
- height: 0.375rem;
- background-color: #e0e0e0;
- border-radius: 0.25rem;
- overflow: hidden;
-}
-
-.VolumeSliderThumb {
- width: 0.75rem;
- height: 0.75rem;
- background-color: #fff;
- border-radius: 50%;
- pointer-events: none;
-}
-
-.VolumeSliderProgress {
- background-color: #007bff;
- border-radius: inherit;
-}
diff --git a/packages/react/react/src/skins/default/styles.ts b/packages/react/react/src/skins/default/styles.ts
index 44bc23d9..91b17397 100644
--- a/packages/react/react/src/skins/default/styles.ts
+++ b/packages/react/react/src/skins/default/styles.ts
@@ -1,6 +1,13 @@
import type { MediaDefaultSkinStyles } from './types';
-import { cn } from '../../utils/cn';
+// NOTE: Removing import to sidestep for compiler complexity (CJP)
+// import { cn } from '../../utils/cn';
+// A (very crude) utility to merge class names
+// Usually I'd use something like `clsx` or `classnames` but this is ok for our simple use case.
+// It just makes the billions of Tailwind classes a little easier to read.
+function cn(...classes: (string | undefined)[]): string {
+ return classes.filter(Boolean).join(' ');
+}
const styles: MediaDefaultSkinStyles = {
MediaContainer: cn(
@@ -42,6 +49,7 @@ const styles: MediaDefaultSkinStyles = {
// High contrast mode
'contrast-more:bg-black/90 contrast-more:ring-black contrast-more:after:ring-white/20',
),
+ Icon: cn('icon'),
Button: cn(
'group/button cursor-pointer relative shrink-0 transition select-none p-2 rounded-full',
// Background/foreground
@@ -60,8 +68,8 @@ const styles: MediaDefaultSkinStyles = {
'active:scale-95',
),
IconButton: cn(
- 'grid [&_svg]:[grid-area:1/1]',
- '[&_svg]:shrink-0 [&_svg]:transition-opacity [&_svg]:duration-300 [&_svg]:ease-out [&_svg]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] [&_svg]:shadow-black/20',
+ 'grid [&_.icon]:[grid-area:1/1]',
+ '[&_.icon]:shrink-0 [&_.icon]:transition-opacity [&_.icon]:duration-300 [&_.icon]:ease-out [&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] [&_.icon]:shadow-black/20',
),
PlayButton: cn(
'[&_.pause-icon]:opacity-100 [&[data-paused]_.pause-icon]:opacity-0',
@@ -89,7 +97,7 @@ const styles: MediaDefaultSkinStyles = {
PlayTooltip: cn('play-tooltip'),
PauseTooltip: cn('pause-tooltip'),
MuteButton: cn(
- '[&_svg]:opacity-0',
+ '[&_.icon]:opacity-0',
'[&[data-volume-level="high"]_.volume-high-icon]:opacity-100',
'[&[data-volume-level="medium"]_.volume-low-icon]:opacity-100',
'[&[data-volume-level="low"]_.volume-low-icon]:opacity-100',
@@ -98,29 +106,29 @@ const styles: MediaDefaultSkinStyles = {
VolumeHighIcon: cn('volume-high-icon'),
VolumeLowIcon: cn('volume-low-icon'),
VolumeOffIcon: cn('volume-off-icon'),
- FullScreenButton: cn(
+ FullscreenButton: cn(
'[&_.fullscreen-enter-icon]:opacity-100 [&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0',
'[&_.fullscreen-exit-icon]:opacity-0 [&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100',
'[&_path]:transition-transform ease-out',
),
- FullScreenEnterIcon: cn(
+ FullscreenEnterIcon: cn(
'fullscreen-enter-icon',
'group-hover/button:[&_.arrow-1]:-translate-x-px group-hover/button:[&_.arrow-1]:-translate-y-px',
'group-hover/button:[&_.arrow-2]:translate-x-px group-hover/button:[&_.arrow-2]:translate-y-px',
),
- FullScreenExitIcon: cn(
+ FullscreenExitIcon: cn(
'fullscreen-exit-icon',
'[&_.arrow-1]:-translate-x-px [&_.arrow-1]:-translate-y-px',
'[&_.arrow-2]:translate-x-px [&_.arrow-2]:translate-y-px',
'group-hover/button:[&_.arrow-1]:translate-0',
'group-hover/button:[&_.arrow-2]:translate-0',
),
- FullScreenTooltipPopup: cn(
+ FullscreenTooltipPopup: cn(
'[&_.fullscreen-enter-tooltip]:inline [&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden',
'[&_.fullscreen-exit-tooltip]:hidden [&[data-fullscreen]_.fullscreen-exit-tooltip]:inline',
),
- FullScreenEnterTooltip: cn('fullscreen-enter-tooltip'),
- FullScreenExitTooltip: cn('fullscreen-exit-tooltip'),
+ FullscreenEnterTooltip: cn('fullscreen-enter-tooltip'),
+ FullscreenExitTooltip: cn('fullscreen-exit-tooltip'),
TimeControls: cn('flex-1 flex items-center gap-3 px-1.5'),
TimeDisplay: cn('tabular-nums text-shadow-2xs shadow-black/50'),
SliderRoot: cn(
diff --git a/packages/react/react/src/skins/default/types.ts b/packages/react/react/src/skins/default/types.ts
index bfed7182..3b9d1eaf 100644
--- a/packages/react/react/src/skins/default/types.ts
+++ b/packages/react/react/src/skins/default/types.ts
@@ -2,6 +2,7 @@ export interface MediaDefaultSkinStyles {
readonly MediaContainer: string;
readonly Overlay: string;
readonly Controls: string;
+ readonly Icon: string;
readonly Button: string;
readonly IconButton: string;
readonly PlayButton: string;
@@ -15,12 +16,12 @@ export interface MediaDefaultSkinStyles {
readonly VolumeHighIcon: string;
readonly VolumeLowIcon: string;
readonly VolumeOffIcon: string;
- readonly FullScreenButton: string;
- readonly FullScreenEnterIcon: string;
- readonly FullScreenExitIcon: string;
- readonly FullScreenTooltipPopup: string;
- readonly FullScreenEnterTooltip: string;
- readonly FullScreenExitTooltip: string;
+ readonly FullscreenButton: string;
+ readonly FullscreenEnterIcon: string;
+ readonly FullscreenExitIcon: string;
+ readonly FullscreenTooltipPopup: string;
+ readonly FullscreenEnterTooltip: string;
+ readonly FullscreenExitTooltip: string;
readonly SliderRoot: string;
readonly SliderTrack: string;
readonly SliderProgress: string;
diff --git a/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx b/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx
index 036a8e2d..131dce2c 100644
--- a/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx
+++ b/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx
@@ -33,8 +33,8 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
-
-
+
+
@@ -57,14 +57,14 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/packages/react/react/src/skins/toasted/styles.ts b/packages/react/react/src/skins/toasted/styles.ts
index c6e5bebd..fbc2f444 100644
--- a/packages/react/react/src/skins/toasted/styles.ts
+++ b/packages/react/react/src/skins/toasted/styles.ts
@@ -1,6 +1,13 @@
import type { MediaToastedSkinStyles } from './types';
-import { cn } from '../../utils/cn';
+// NOTE: Removing import to sidestep for compiler complexity (CJP)
+// import { cn } from '../../utils/cn';
+// A (very crude) utility to merge class names
+// Usually I'd use something like `clsx` or `classnames` but this is ok for our simple use case.
+// It just makes the billions of Tailwind classes a little easier to read.
+function cn(...classes: (string | undefined)[]): string {
+ return classes.filter(Boolean).join(' ');
+}
const styles: MediaToastedSkinStyles = {
MediaContainer: cn(
@@ -33,6 +40,7 @@ const styles: MediaToastedSkinStyles = {
'has-[[data-paused]]:translate-y-0 has-[[data-paused]]:opacity-100 has-[[data-paused]]:delay-0 has-[[data-paused]]:duration-75',
'group-hover/root:translate-y-0 group-hover/root:opacity-100 group-hover/root:delay-0 group-hover/root:duration-75',
),
+ Icon: cn('icon'),
Button: cn(
'group/button cursor-pointer relative shrink-0 transition select-none p-2 rounded-md',
// Background/foreground
@@ -52,8 +60,8 @@ const styles: MediaToastedSkinStyles = {
),
ButtonGroup: cn('flex items-center gap-1.5'),
IconButton: cn(
- 'grid [&_svg]:[grid-area:1/1]',
- '[&_svg]:shrink-0 [&_svg]:transition [&_svg]:duration-300 [&_svg]:ease-out [&_svg]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] [&_svg]:shadow-black/20',
+ 'grid [&_.icon]:[grid-area:1/1]',
+ '[&_.icon]:shrink-0 [&_.icon]:transition [&_.icon]:duration-300 [&_.icon]:ease-out [&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] [&_.icon]:shadow-black/20',
),
PlayButton: cn(
'[&_.pause-icon]:opacity-100 [&[data-paused]_.pause-icon]:opacity-0',
@@ -62,7 +70,7 @@ const styles: MediaToastedSkinStyles = {
PlayIcon: cn('play-icon'),
PauseIcon: cn('pause-icon'),
MuteButton: cn(
- '[&_svg]:hidden',
+ '[&_.icon]:hidden',
'[&[data-volume-level="high"]_.volume-high-icon]:inline',
'[&[data-volume-level="medium"]_.volume-low-icon]:inline',
'[&[data-volume-level="low"]_.volume-low-icon]:inline',
@@ -71,17 +79,17 @@ const styles: MediaToastedSkinStyles = {
VolumeHighIcon: cn('volume-high-icon'),
VolumeLowIcon: cn('volume-low-icon'),
VolumeOffIcon: cn('volume-off-icon'),
- FullScreenButton: cn(
+ FullscreenButton: cn(
'[&_.fullscreen-enter-icon]:opacity-100 [&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0',
'[&_.fullscreen-exit-icon]:opacity-0 [&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100',
'[&_path]:transition-transform ease-out',
),
- FullScreenEnterIcon: cn(
+ FullscreenEnterIcon: cn(
'fullscreen-enter-icon',
'group-hover/button:[&_.arrow-1]:-translate-x-px group-hover/button:[&_.arrow-1]:-translate-y-px',
'group-hover/button:[&_.arrow-2]:translate-x-px group-hover/button:[&_.arrow-2]:translate-y-px',
),
- FullScreenExitIcon: cn(
+ FullscreenExitIcon: cn(
'fullscreen-exit-icon',
'[&_.arrow-1]:-translate-x-px [&_.arrow-1]:-translate-y-px',
'[&_.arrow-2]:translate-x-px [&_.arrow-2]:translate-y-px',
diff --git a/packages/react/react/src/skins/toasted/types.ts b/packages/react/react/src/skins/toasted/types.ts
index babf3a90..3cf00216 100644
--- a/packages/react/react/src/skins/toasted/types.ts
+++ b/packages/react/react/src/skins/toasted/types.ts
@@ -2,6 +2,7 @@ export interface MediaToastedSkinStyles {
readonly MediaContainer: string;
readonly Overlay: string;
readonly Controls: string;
+ readonly Icon: string;
readonly Button: string;
readonly ButtonGroup: string;
readonly IconButton: string;
@@ -12,9 +13,9 @@ export interface MediaToastedSkinStyles {
readonly VolumeHighIcon: string;
readonly VolumeLowIcon: string;
readonly VolumeOffIcon: string;
- readonly FullScreenButton: string;
- readonly FullScreenEnterIcon: string;
- readonly FullScreenExitIcon: string;
+ readonly FullscreenButton: string;
+ readonly FullscreenEnterIcon: string;
+ readonly FullscreenExitIcon: string;
readonly TimeSliderRoot: string;
readonly TimeSliderThumb: string;
readonly TimeDisplay: string;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7e9aebe8..6f1848bc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -81,6 +81,9 @@ importers:
'@vjs-10/react':
specifier: workspace:*
version: link:../../packages/react/react
+ '@vjs-10/react-icons':
+ specifier: workspace:*
+ version: link:../../packages/react/react-icons
react:
specifier: ^18.0.0
version: 18.3.1