Skip to content

Commit d798c7c

Browse files
committed
chore: replace contextTypes with modern alternatives
1 parent 799ab71 commit d798c7c

File tree

5 files changed

+56
-80
lines changed

5 files changed

+56
-80
lines changed

packages/webui/src/client/ui/RundownView/RundownTiming/RundownTimingProvider.tsx

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { PropsWithChildren } from 'react'
22
import { Meteor } from 'meteor/meteor'
3-
import * as PropTypes from 'prop-types'
43
import { withTracker } from '../../../lib/ReactMeteorData/react-meteor-data'
54
import { protectString } from '../../../lib/tempLib'
65
import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
@@ -21,6 +20,7 @@ import { sortPartInstancesInSortedSegments } from '@sofie-automation/corelib/dis
2120
import { RundownUtils } from '../../../lib/rundown'
2221
import { RundownPlaylistClientUtil } from '../../../lib/rundownPlaylistUtil'
2322
import { getCurrentTime } from '../../../lib/systemTime'
23+
import { IRundownTimingProviderValues, RundownTimingProviderContext } from './withTiming'
2424

2525
const TIMING_DEFAULT_REFRESH_INTERVAL = 1000 / 60 // the interval for high-resolution events (timeupdateHR)
2626
const LOW_RESOLUTION_TIMING_DECIMATOR = 15
@@ -44,10 +44,7 @@ interface IRundownTimingProviderProps {
4444
/** Fallback duration for Parts that have no as-played duration of their own. */
4545
defaultDuration?: number
4646
}
47-
interface IRundownTimingProviderChildContext {
48-
durations: RundownTimingContext
49-
syncedDurations: RundownTimingContext
50-
}
47+
5148
interface IRundownTimingProviderState {}
5249
interface IRundownTimingProviderTrackedProps {
5350
rundowns: Array<Rundown>
@@ -156,27 +153,28 @@ export const RundownTimingProvider = withTracker<
156153
partsInQuickLoop,
157154
}
158155
})(
159-
class RundownTimingProvider
160-
extends React.Component<
161-
PropsWithChildren<IRundownTimingProviderProps> & IRundownTimingProviderTrackedProps,
162-
IRundownTimingProviderState
163-
>
164-
implements React.ChildContextProvider<IRundownTimingProviderChildContext>
165-
{
166-
static childContextTypes = {
167-
durations: PropTypes.object.isRequired,
168-
syncedDurations: PropTypes.object.isRequired,
169-
}
170-
171-
durations: RundownTimingContext = {
156+
class RundownTimingProvider extends React.Component<
157+
PropsWithChildren<IRundownTimingProviderProps> & IRundownTimingProviderTrackedProps,
158+
IRundownTimingProviderState
159+
> {
160+
private durations: RundownTimingContext = {
172161
isLowResolution: false,
173162
}
174-
syncedDurations: RundownTimingContext = {
163+
private syncedDurations: RundownTimingContext = {
175164
isLowResolution: true,
176165
}
177-
refreshTimer: number | undefined
178-
refreshTimerInterval: number
179-
refreshDecimator: number
166+
/**
167+
* This context works in an unusual way.
168+
* It contains a constant value which gets mutated in place, with the consumer expected to setup a timer to poll for changes.
169+
*/
170+
private childContextValue: IRundownTimingProviderValues = {
171+
durations: this.durations,
172+
syncedDurations: this.syncedDurations,
173+
}
174+
175+
private refreshTimer: number | undefined
176+
private refreshTimerInterval: number
177+
private refreshDecimator: number
180178

181179
private timingCalculator: RundownTimingCalculator = new RundownTimingCalculator()
182180
/** last time (ms rounded down to full seconds) for which the timeupdateSynced event was dispatched */
@@ -190,18 +188,11 @@ export const RundownTimingProvider = withTracker<
190188
this.refreshDecimator = 0
191189
}
192190

193-
getChildContext(): IRundownTimingProviderChildContext {
194-
return {
195-
durations: this.durations,
196-
syncedDurations: this.syncedDurations,
197-
}
198-
}
199-
200-
calmDownTiming = (time: number) => {
191+
private calmDownTiming = (time: number) => {
201192
return Math.round(time / CURRENT_TIME_GRANULARITY) * CURRENT_TIME_GRANULARITY
202193
}
203194

204-
onRefreshTimer = () => {
195+
private onRefreshTimer = () => {
205196
const now = getCurrentTime()
206197
const calmedDownNow = this.calmDownTiming(now)
207198
this.updateDurations(calmedDownNow, false)
@@ -252,7 +243,7 @@ export const RundownTimingProvider = withTracker<
252243
if (this.refreshTimer !== undefined) Meteor.clearInterval(this.refreshTimer)
253244
}
254245

255-
dispatchHREvent(now: number) {
246+
private dispatchHREvent(now: number) {
256247
const event = new CustomEvent<TimeEventArgs>(RundownTiming.Events.timeupdateHighResolution, {
257248
detail: {
258249
currentTime: now,
@@ -262,7 +253,7 @@ export const RundownTimingProvider = withTracker<
262253
window.dispatchEvent(event)
263254
}
264255

265-
dispatchLREvent(now: number) {
256+
private dispatchLREvent(now: number) {
266257
const event = new CustomEvent<TimeEventArgs>(RundownTiming.Events.timeupdateLowResolution, {
267258
detail: {
268259
currentTime: now,
@@ -272,7 +263,7 @@ export const RundownTimingProvider = withTracker<
272263
window.dispatchEvent(event)
273264
}
274265

275-
dispatchSyncedEvent(now: number) {
266+
private dispatchSyncedEvent(now: number) {
276267
const event = new CustomEvent<TimeEventArgs>(RundownTiming.Events.timeupdateSynced, {
277268
detail: {
278269
currentTime: now,
@@ -282,7 +273,7 @@ export const RundownTimingProvider = withTracker<
282273
window.dispatchEvent(event)
283274
}
284275

285-
updateDurations(now: number, isSynced: boolean) {
276+
private updateDurations(now: number, isSynced: boolean) {
286277
const { playlist, rundowns, currentRundown, partInstances, partInstancesMap, segmentsMap } = this.props
287278

288279
const updatedDurations = this.timingCalculator.updateDurations(
@@ -305,7 +296,11 @@ export const RundownTimingProvider = withTracker<
305296
}
306297

307298
render(): React.ReactNode {
308-
return this.props.children
299+
return (
300+
<RundownTimingProviderContext.Provider value={this.childContextValue}>
301+
{this.props.children}
302+
</RundownTimingProviderContext.Provider>
303+
)
309304
}
310305
}
311306
)

packages/webui/src/client/ui/RundownView/RundownTiming/withTiming.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as React from 'react'
2-
import * as PropTypes from 'prop-types'
32
import * as _ from 'underscore'
43
import { RundownTiming } from './RundownTiming'
54
import { RundownTimingContext } from '../../../lib/rundownTiming'
@@ -32,6 +31,19 @@ type IWrappedComponent<IProps, IState> =
3231
| (new (props: WithTiming<IProps>, state: IState) => React.Component<WithTiming<IProps>, IState>)
3332
| ((props: WithTiming<IProps>) => JSX.Element | null)
3433

34+
export interface IRundownTimingProviderValues {
35+
durations: RundownTimingContext
36+
syncedDurations: RundownTimingContext
37+
}
38+
export const RundownTimingProviderContext = React.createContext<IRundownTimingProviderValues>({
39+
durations: {
40+
isLowResolution: false,
41+
},
42+
syncedDurations: {
43+
isLowResolution: true,
44+
},
45+
})
46+
3547
/**
3648
* Wrap a component in a HOC that will inject a the timing context as a prop. Takes an optional options object that
3749
* allows a high timing resolution or filtering of the changes in the context, so that the child component only
@@ -58,16 +70,8 @@ export function withTiming<IProps, IState>(
5870

5971
return (WrappedComponent) => {
6072
return class WithTimingHOCComponent extends React.Component<IProps, IState> {
61-
static contextTypes = {
62-
durations: PropTypes.object.isRequired,
63-
syncedDurations: PropTypes.object.isRequired,
64-
}
65-
66-
// Setup by React.Component constructor
67-
declare context: {
68-
durations: RundownTimingContext
69-
syncedDurations: RundownTimingContext
70-
}
73+
static contextType = RundownTimingProviderContext
74+
declare context: React.ContextType<typeof RundownTimingProviderContext>
7175

7276
filterGetter: ((o: any) => any) | undefined
7377
previousValue: any = undefined

packages/webui/src/client/ui/SegmentTimeline/SegmentTimeline.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as React from 'react'
2-
import * as PropTypes from 'prop-types'
32
import { WithTranslation, withTranslation } from 'react-i18next'
43

54
import ClassNames from 'classnames'
@@ -51,6 +50,7 @@ import {
5150
TimingTickResolution,
5251
TimingDataResolution,
5352
WithTiming,
53+
RundownTimingProviderContext,
5454
} from '../RundownView/RundownTiming/withTiming'
5555
import { SegmentTimeAnchorTime } from '../RundownView/RundownTiming/SegmentTimeAnchorTime'
5656
import { logger } from '../../lib/logging'
@@ -128,15 +128,8 @@ const SegmentTimelineZoom = class SegmentTimelineZoom extends React.Component<
128128
IProps & IZoomPropsHeader,
129129
IZoomStateHeader
130130
> {
131-
static contextTypes = {
132-
durations: PropTypes.object.isRequired,
133-
}
134-
135-
declare context:
136-
| {
137-
durations: RundownTimingContext
138-
}
139-
| undefined
131+
static contextType = RundownTimingProviderContext
132+
declare context: React.ContextType<typeof RundownTimingProviderContext>
140133

141134
constructor(props: IProps & IZoomPropsHeader, context: any) {
142135
super(props, context)

packages/webui/src/client/ui/SegmentTimeline/SegmentTimelineContainer.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { useMemo } from 'react'
2-
import * as PropTypes from 'prop-types'
32
import * as _ from 'underscore'
43
import { SegmentTimeline, SegmentTimelineClass } from './SegmentTimeline'
54
import { computeSegmentDisplayDuration, RundownTiming, TimingEvent } from '../RundownView/RundownTiming/RundownTiming'
@@ -24,7 +23,7 @@ import {
2423
ITrackedResolvedSegmentProps,
2524
IOutputLayerUi,
2625
} from '../SegmentContainer/withResolvedSegment'
27-
import { computeSegmentDuration, getPartInstanceTimingId, RundownTimingContext } from '../../lib/rundownTiming'
26+
import { computeSegmentDuration, getPartInstanceTimingId } from '../../lib/rundownTiming'
2827
import { RundownViewShelf } from '../RundownView/RundownViewShelf'
2928
import { PartInstanceId, SegmentId } from '@sofie-automation/corelib/dist/dataModel/Ids'
3029
import { catchError, useDebounce } from '../../lib/lib'
@@ -39,6 +38,7 @@ import {
3938
TIMELINE_RIGHT_PADDING,
4039
} from './Constants'
4140
import { UIPartInstances, UIParts } from '../Collections'
41+
import { RundownTimingProviderContext } from '../RundownView/RundownTiming/withTiming'
4242

4343
// Kept for backwards compatibility
4444
export type {
@@ -141,10 +141,8 @@ export function SegmentTimelineContainer(props: Readonly<IProps>): JSX.Element {
141141

142142
const SegmentTimelineContainerContent = withResolvedSegment(
143143
class SegmentTimelineContainerContent extends React.Component<IProps & ITrackedResolvedSegmentProps, IState> {
144-
static contextTypes = {
145-
durations: PropTypes.object.isRequired,
146-
syncedDurations: PropTypes.object.isRequired,
147-
}
144+
static contextType = RundownTimingProviderContext
145+
declare context: React.ContextType<typeof RundownTimingProviderContext>
148146

149147
isVisible: boolean
150148
rundownCurrentPartInstanceId: PartInstanceId | null = null
@@ -153,12 +151,6 @@ const SegmentTimelineContainerContent = withResolvedSegment(
153151
mountedTime = 0
154152
nextPartOffset = 0
155153

156-
// Setup by React.Component constructor
157-
declare context: {
158-
durations: RundownTimingContext
159-
syncedDurations: RundownTimingContext
160-
}
161-
162154
constructor(props: IProps & ITrackedResolvedSegmentProps) {
163155
super(props)
164156

packages/webui/src/client/ui/SegmentTimeline/TimelineGrid.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from 'react'
22
import _ from 'underscore'
3-
import PropTypes from 'prop-types'
43

54
import { RundownUtils } from '../../lib/rundown'
65

@@ -10,8 +9,8 @@ import { PartUi } from './SegmentTimelineContainer'
109
import { getCurrentTime } from '../../lib/systemTime'
1110
import { RundownTiming } from '../RundownView/RundownTiming/RundownTiming'
1211
import { SegmentTimelinePartClass } from './Parts/SegmentTimelinePart'
13-
import { RundownTimingContext } from '../../lib/rundownTiming'
1412
import { PartInstanceId } from '@sofie-automation/corelib/dist/dataModel/Ids'
13+
import { RundownTimingProviderContext } from '../RundownView/RundownTiming/withTiming'
1514

1615
// We're cheating a little: Fontface
1716
declare class FontFace {
@@ -51,15 +50,8 @@ let gridFont: any | undefined = undefined
5150
let gridFontAvailable = false
5251

5352
export class TimelineGrid extends React.Component<ITimelineGridProps> {
54-
static contextTypes = {
55-
durations: PropTypes.object.isRequired,
56-
}
57-
58-
declare context:
59-
| {
60-
durations: RundownTimingContext
61-
}
62-
| undefined
53+
static contextType = RundownTimingProviderContext
54+
declare context: React.ContextType<typeof RundownTimingProviderContext>
6355

6456
canvasElement: HTMLCanvasElement | null = null
6557
parentElement: HTMLDivElement | null = null

0 commit comments

Comments
 (0)