mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat: add compound html timerange component (#14)
* fix: add context logic to component factory * feat: add compound time range html component
This commit is contained in:
@@ -11,6 +11,9 @@ module.exports = [
|
||||
format: 'esm',
|
||||
sourcemap: true,
|
||||
},
|
||||
watch: {
|
||||
clearScreen: false
|
||||
},
|
||||
external: (id) => {
|
||||
// Don't externalize relative imports (starts with . or /)
|
||||
if (id.startsWith('.') || id.startsWith('/')) return false;
|
||||
@@ -39,6 +42,9 @@ module.exports = [
|
||||
format: 'cjs',
|
||||
sourcemap: true,
|
||||
},
|
||||
watch: {
|
||||
clearScreen: false
|
||||
},
|
||||
external: (id) => {
|
||||
// Don't externalize relative imports (starts with . or /)
|
||||
if (id.startsWith('.') || id.startsWith('/')) return false;
|
||||
@@ -59,4 +65,4 @@ module.exports = [
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
@@ -12,6 +12,9 @@ module.exports = [
|
||||
format: 'esm',
|
||||
sourcemap: true,
|
||||
},
|
||||
watch: {
|
||||
clearScreen: false
|
||||
},
|
||||
external: [
|
||||
'react',
|
||||
'@vjs-10/react-icons',
|
||||
@@ -46,6 +49,9 @@ module.exports = [
|
||||
format: 'cjs',
|
||||
sourcemap: true,
|
||||
},
|
||||
watch: {
|
||||
clearScreen: false
|
||||
},
|
||||
external: [
|
||||
'react',
|
||||
'@vjs-10/react-icons',
|
||||
@@ -72,4 +78,4 @@ module.exports = [
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
@@ -33,29 +33,6 @@ const calculateSeekTimeFromPointerEvent = (
|
||||
// ROOT COMPONENT
|
||||
// ============================================================================
|
||||
|
||||
interface TimeRangeRootContextValue {
|
||||
currentTime: number;
|
||||
duration: number;
|
||||
requestSeek: (time: number) => void;
|
||||
pointerPosition: number | null;
|
||||
setPointerPosition: (position: number | null) => void;
|
||||
hovering: boolean;
|
||||
setHovering: (hovering: boolean) => void;
|
||||
dragging: boolean;
|
||||
setDragging: (dragging: boolean) => void;
|
||||
setTrackRef: (ref: HTMLDivElement | null) => void;
|
||||
}
|
||||
|
||||
const TimeRangeRootContext = React.createContext<TimeRangeRootContextValue | null>(null);
|
||||
|
||||
export const useTimeRangeRootContext = (): TimeRangeRootContextValue => {
|
||||
const context = React.useContext(TimeRangeRootContext);
|
||||
if (!context) {
|
||||
throw new Error('useTimeRangeRootContext must be used within a TimeRange.Root component');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const useTimeRangeRootState = (_props: any) => {
|
||||
const mediaStore = useMediaStore();
|
||||
const mediaState = useMediaSelector(timeRangeStateDefinition.stateTransform, shallowEqual);
|
||||
@@ -186,43 +163,11 @@ export const useTimeRangeRootProps = (
|
||||
|
||||
type useTimeRangeRootState = typeof useTimeRangeRootState;
|
||||
type useTimeRangeRootProps = typeof useTimeRangeRootProps;
|
||||
type TimeRangeRootState = ReturnType<useTimeRangeRootState>;
|
||||
type TimeRangeRootProps = ReturnType<useTimeRangeRootProps>;
|
||||
|
||||
export const renderTimeRangeRoot = (props: TimeRangeRootProps, state: TimeRangeRootState) => {
|
||||
const contextValue: TimeRangeRootContextValue = React.useMemo(
|
||||
() => ({
|
||||
currentTime: state.currentTime,
|
||||
duration: state.duration,
|
||||
requestSeek: state.requestSeek,
|
||||
pointerPosition: state.pointerPosition,
|
||||
setPointerPosition: state.setPointerPosition,
|
||||
hovering: state.hovering,
|
||||
setHovering: state.setHovering,
|
||||
dragging: state.dragging,
|
||||
setDragging: state.setDragging,
|
||||
setTrackRef: state.setTrackRef,
|
||||
}),
|
||||
[
|
||||
state.currentTime,
|
||||
state.duration,
|
||||
state.requestSeek,
|
||||
state.pointerPosition,
|
||||
state.setPointerPosition,
|
||||
state.hovering,
|
||||
state.setHovering,
|
||||
state.dragging,
|
||||
state.setDragging,
|
||||
state.setTrackRef,
|
||||
]
|
||||
);
|
||||
|
||||
export const renderTimeRangeRoot = (props: TimeRangeRootProps) => {
|
||||
return (
|
||||
<TimeRangeRootContext.Provider value={contextValue}>
|
||||
<div style={props.style} {...props}>
|
||||
{props.children}
|
||||
</div>
|
||||
</TimeRangeRootContext.Provider>
|
||||
<div {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -237,8 +182,8 @@ const TimeRangeRoot = toConnectedComponent(
|
||||
// TRACK COMPONENT
|
||||
// ============================================================================
|
||||
|
||||
export const useTimeRangeTrackProps = (props: React.PropsWithChildren<{ [k: string]: any }>) => {
|
||||
const { setTrackRef } = useTimeRangeRootContext();
|
||||
export const useTimeRangeTrackProps = (props: React.PropsWithChildren<{ [k: string]: any }>, context: any) => {
|
||||
const { setTrackRef } = context;
|
||||
|
||||
return {
|
||||
ref: setTrackRef,
|
||||
|
||||
@@ -7,18 +7,20 @@ export type StateHookFn<TProps = any, TState = any> = (props: TProps) => TState;
|
||||
|
||||
export type PropsHookFn<TProps = any, TState = any, TResultProps = any> = (
|
||||
props: TProps,
|
||||
state: TState,
|
||||
state: TState
|
||||
) => TResultProps;
|
||||
|
||||
export type RenderFn<TProps = any, TState = any> = (
|
||||
props: TProps,
|
||||
state: TState,
|
||||
state: TState
|
||||
) => React.ReactElement;
|
||||
|
||||
const Context = React.createContext<any | null>(null);
|
||||
|
||||
/**
|
||||
* Generic factory function to create connected components following the hooks pattern
|
||||
* inspired by Adobe React Spectrum and Base UI architectures.
|
||||
*
|
||||
*
|
||||
* @param useStateHook - Hook that provides component state
|
||||
* @param usePropsHook - Hook that enhances props with state-derived values
|
||||
* @param defaultRender - Default render function for the component
|
||||
@@ -29,12 +31,12 @@ export const toConnectedComponent = <
|
||||
TProps extends Record<string, any>,
|
||||
TState,
|
||||
TResultProps extends Record<string, any>,
|
||||
TRenderFn extends RenderFn<TResultProps, TState>
|
||||
TRenderFn extends RenderFn<TResultProps, TState>,
|
||||
>(
|
||||
useStateHook: StateHookFn<TProps, TState>,
|
||||
usePropsHook: PropsHookFn<TProps, TState, TResultProps>,
|
||||
defaultRender: TRenderFn,
|
||||
displayName: string,
|
||||
displayName: string
|
||||
) => {
|
||||
const ConnectedComponent = ({
|
||||
render = defaultRender,
|
||||
@@ -42,7 +44,11 @@ export const toConnectedComponent = <
|
||||
}: TProps & { render?: TRenderFn }) => {
|
||||
const connectedState = useStateHook(props as TProps);
|
||||
const connectedProps = usePropsHook(props as TProps, connectedState);
|
||||
return render(connectedProps, connectedState);
|
||||
return (
|
||||
<Context.Provider value={connectedState}>
|
||||
{render(connectedProps, connectedState)}
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
ConnectedComponent.displayName = displayName;
|
||||
@@ -54,13 +60,13 @@ export const toConnectedComponent = <
|
||||
*/
|
||||
export type ConnectedComponent<
|
||||
TProps extends Record<string, any>,
|
||||
TRenderFn extends RenderFn<any, any>
|
||||
TRenderFn extends RenderFn<any, any>,
|
||||
> = React.FC<TProps & { render?: TRenderFn }>;
|
||||
|
||||
/**
|
||||
* Factory function to create context-based components that don't use toConnectedComponent
|
||||
* These components rely on context provided by a parent component.
|
||||
*
|
||||
*
|
||||
* @param usePropsHook - Hook that enhances props with context-derived values
|
||||
* @param defaultRender - Default render function for the component
|
||||
* @param displayName - Display name for React DevTools
|
||||
@@ -69,18 +75,19 @@ export type ConnectedComponent<
|
||||
export const toContextComponent = <
|
||||
TProps extends Record<string, any>,
|
||||
TResultProps extends Record<string, any>,
|
||||
TRenderFn extends (props: TResultProps) => React.ReactElement
|
||||
TRenderFn extends (props: TResultProps, context: any) => React.ReactElement,
|
||||
>(
|
||||
usePropsHook: (props: TProps) => TResultProps,
|
||||
usePropsHook: (props: TProps, context: any) => TResultProps,
|
||||
defaultRender: TRenderFn,
|
||||
displayName: string,
|
||||
displayName: string
|
||||
) => {
|
||||
const ContextComponent = ({
|
||||
render = defaultRender,
|
||||
...props
|
||||
}: TProps & { render?: TRenderFn }) => {
|
||||
const contextProps = usePropsHook(props as TProps);
|
||||
return render(contextProps);
|
||||
const context = React.useContext(Context);
|
||||
const contextProps = usePropsHook(props as TProps, context);
|
||||
return render(contextProps, context);
|
||||
};
|
||||
|
||||
ContextComponent.displayName = displayName;
|
||||
@@ -92,5 +99,5 @@ export const toContextComponent = <
|
||||
*/
|
||||
export type ContextComponent<
|
||||
TProps extends Record<string, any>,
|
||||
TRenderFn extends (props: any) => React.ReactElement
|
||||
TRenderFn extends (props: any, context: any) => React.ReactElement,
|
||||
> = React.FC<TProps & { render?: TRenderFn }>;
|
||||
|
||||
Reference in New Issue
Block a user