Rewrite SharePage to typescript
This commit is contained in:
parent
9c939fd06c
commit
34a411be9d
|
@ -1,4 +1,3 @@
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Layout from '../../Layout'
|
import Layout from '../../Layout'
|
||||||
import AlbumGallery from '../../components/albumGallery/AlbumGallery'
|
import AlbumGallery from '../../components/albumGallery/AlbumGallery'
|
||||||
|
@ -73,7 +72,13 @@ const AlbumSharePageWrapper = styled.div`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
`
|
`
|
||||||
|
|
||||||
const AlbumSharePage = ({ albumID, token, password }) => {
|
type AlbumSharePageProps = {
|
||||||
|
albumID: string
|
||||||
|
token: string
|
||||||
|
password: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const AlbumSharePage = ({ albumID, token, password }: AlbumSharePageProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { data, loading, error } = useQuery(SHARE_ALBUM_QUERY, {
|
const { data, loading, error } = useQuery(SHARE_ALBUM_QUERY, {
|
||||||
variables: {
|
variables: {
|
||||||
|
@ -86,11 +91,11 @@ const AlbumSharePage = ({ albumID, token, password }) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return error.message
|
return <div>{error.message}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return t('general.loading.default', 'Loading...')
|
return <div>{t('general.loading.default', 'Loading...')}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const album = data.album
|
const album = data.album
|
||||||
|
@ -111,10 +116,4 @@ const AlbumSharePage = ({ albumID, token, password }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumSharePage.propTypes = {
|
|
||||||
albumID: PropTypes.string.isRequired,
|
|
||||||
token: PropTypes.string.isRequired,
|
|
||||||
password: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AlbumSharePage
|
export default AlbumSharePage
|
|
@ -1,58 +0,0 @@
|
||||||
import React, { useContext, useEffect } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import styled from 'styled-components'
|
|
||||||
import Layout from '../../Layout'
|
|
||||||
import {
|
|
||||||
ProtectedImage,
|
|
||||||
ProtectedVideo,
|
|
||||||
} from '../../components/photoGallery/ProtectedMedia'
|
|
||||||
import { SidebarContext } from '../../components/sidebar/Sidebar'
|
|
||||||
import MediaSidebar from '../../components/sidebar/MediaSidebar'
|
|
||||||
|
|
||||||
const DisplayPhoto = styled(ProtectedImage)`
|
|
||||||
width: 100%;
|
|
||||||
max-height: calc(80vh);
|
|
||||||
object-fit: contain;
|
|
||||||
`
|
|
||||||
|
|
||||||
const DisplayVideo = styled(ProtectedVideo)`
|
|
||||||
width: 100%;
|
|
||||||
max-height: calc(80vh);
|
|
||||||
`
|
|
||||||
|
|
||||||
const MediaView = ({ media }) => {
|
|
||||||
const { updateSidebar } = useContext(SidebarContext)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
updateSidebar(<MediaSidebar media={media} hidePreview />)
|
|
||||||
}, [media])
|
|
||||||
|
|
||||||
if (media.type == 'photo') {
|
|
||||||
return <DisplayPhoto src={media.highRes.url} />
|
|
||||||
}
|
|
||||||
|
|
||||||
if (media.type == 'video') {
|
|
||||||
return <DisplayVideo media={media} />
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Unsupported media type: ${media.type}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaView.propTypes = {
|
|
||||||
media: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
const MediaSharePage = ({ media }) => (
|
|
||||||
<Layout>
|
|
||||||
<div data-testid="MediaSharePage">
|
|
||||||
<h1>{media.title}</h1>
|
|
||||||
<MediaView media={media} />
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
|
|
||||||
MediaSharePage.propTypes = {
|
|
||||||
media: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MediaSharePage
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import React, { useContext, useEffect } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import Layout from '../../Layout'
|
||||||
|
import {
|
||||||
|
ProtectedImage,
|
||||||
|
ProtectedVideo,
|
||||||
|
} from '../../components/photoGallery/ProtectedMedia'
|
||||||
|
import { SidebarContext } from '../../components/sidebar/Sidebar'
|
||||||
|
import MediaSidebar from '../../components/sidebar/MediaSidebar'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { SharePageToken_shareToken_media } from './__generated__/SharePageToken'
|
||||||
|
import { MediaType } from '../../../__generated__/globalTypes'
|
||||||
|
|
||||||
|
const DisplayPhoto = styled(ProtectedImage)`
|
||||||
|
width: 100%;
|
||||||
|
max-height: calc(80vh);
|
||||||
|
object-fit: contain;
|
||||||
|
`
|
||||||
|
|
||||||
|
const DisplayVideo = styled(ProtectedVideo)`
|
||||||
|
width: 100%;
|
||||||
|
max-height: calc(80vh);
|
||||||
|
`
|
||||||
|
|
||||||
|
type MediaViewProps = {
|
||||||
|
media: SharePageToken_shareToken_media
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaView = ({ media }: MediaViewProps) => {
|
||||||
|
const { updateSidebar } = useContext(SidebarContext)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateSidebar(<MediaSidebar media={media} hidePreview />)
|
||||||
|
}, [media])
|
||||||
|
|
||||||
|
switch (media.type) {
|
||||||
|
case MediaType.Photo:
|
||||||
|
return <DisplayPhoto src={media.highRes?.url} />
|
||||||
|
case MediaType.Video:
|
||||||
|
return <DisplayVideo media={media} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaSharePageType = {
|
||||||
|
media: SharePageToken_shareToken_media
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaSharePage = ({ media }: MediaSharePageType) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout title={t('share_page.media.title', 'Shared media')}>
|
||||||
|
<div data-testid="MediaSharePage">
|
||||||
|
<h1>{media.title}</h1>
|
||||||
|
<MediaView media={media} />
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MediaSharePage
|
|
@ -82,7 +82,7 @@ describe('load correct share page, based on graphql query', () => {
|
||||||
media: {
|
media: {
|
||||||
id: '1',
|
id: '1',
|
||||||
title: 'shared_image.jpg',
|
title: 'shared_image.jpg',
|
||||||
type: 'photo',
|
type: 'Photo',
|
||||||
highRes: {
|
highRes: {
|
||||||
url: 'https://example.com/shared_image.jpg',
|
url: 'https://example.com/shared_image.jpg',
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useQuery, gql } from '@apollo/client'
|
import { useQuery, gql } from '@apollo/client'
|
||||||
import { Route, Switch } from 'react-router-dom'
|
import { match as MatchType, Route, Switch } from 'react-router-dom'
|
||||||
import RouterProps from 'react-router-prop-types'
|
|
||||||
import { Form, Header, Icon, Input, Message } from 'semantic-ui-react'
|
import { Form, Header, Icon, Input, Message } from 'semantic-ui-react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import {
|
import {
|
||||||
|
@ -71,7 +70,7 @@ export const VALIDATE_TOKEN_PASSWORD_QUERY = gql`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const AuthorizedTokenRoute = ({ match }) => {
|
const AuthorizedTokenRoute = ({ match }: MatchProps<TokenRouteMatch>) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const token = match.params.token
|
const token = match.params.token
|
||||||
|
@ -84,11 +83,11 @@ const AuthorizedTokenRoute = ({ match }) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (error) return error.message
|
if (error) return <div>{error.message}</div>
|
||||||
if (loading) return 'Loading...'
|
if (loading) return <div>{t('general.loading.default', 'Loading...')}</div>
|
||||||
|
|
||||||
if (data.shareToken.album) {
|
if (data.shareToken.album) {
|
||||||
const SharedSubAlbumPage = ({ match }) => {
|
const SharedSubAlbumPage = ({ match }: MatchProps<SubalbumRouteMatch>) => {
|
||||||
return (
|
return (
|
||||||
<AlbumSharePage
|
<AlbumSharePage
|
||||||
albumID={match.params.subAlbum}
|
albumID={match.params.subAlbum}
|
||||||
|
@ -136,10 +135,15 @@ const MessageContainer = styled.div`
|
||||||
margin: 100px auto 0;
|
margin: 100px auto 0;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
type ProtectedTokenEnterPasswordProps = {
|
||||||
|
refetchWithPassword(password: string): void
|
||||||
|
loading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
const ProtectedTokenEnterPassword = ({
|
const ProtectedTokenEnterPassword = ({
|
||||||
refetchWithPassword,
|
refetchWithPassword,
|
||||||
loading = false,
|
loading = false,
|
||||||
}) => {
|
}: ProtectedTokenEnterPasswordProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const [passwordValue, setPasswordValue] = useState('')
|
const [passwordValue, setPasswordValue] = useState('')
|
||||||
|
@ -178,7 +182,9 @@ const ProtectedTokenEnterPassword = ({
|
||||||
<Input
|
<Input
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onKeyUp={event => event.key == 'Enter' && onSubmit()}
|
onKeyUp={(event: KeyboardEvent) =>
|
||||||
|
event.key == 'Enter' && onSubmit()
|
||||||
|
}
|
||||||
onChange={e => setPasswordValue(e.target.value)}
|
onChange={e => setPasswordValue(e.target.value)}
|
||||||
placeholder={t('login_page.field.password', 'Password')}
|
placeholder={t('login_page.field.password', 'Password')}
|
||||||
type="password"
|
type="password"
|
||||||
|
@ -191,12 +197,19 @@ const ProtectedTokenEnterPassword = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectedTokenEnterPassword.propTypes = {
|
interface TokenRouteMatch {
|
||||||
refetchWithPassword: PropTypes.func.isRequired,
|
token: string
|
||||||
loading: PropTypes.bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TokenRoute = ({ match }) => {
|
interface SubalbumRouteMatch extends TokenRouteMatch {
|
||||||
|
subAlbum: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MatchProps<Route> {
|
||||||
|
match: MatchType<Route>
|
||||||
|
}
|
||||||
|
|
||||||
|
const TokenRoute = ({ match }: MatchProps<TokenRouteMatch>) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const token = match.params.token
|
const token = match.params.token
|
||||||
|
@ -227,13 +240,12 @@ const TokenRoute = ({ match }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return error.message
|
return <div>{error.message}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data && data.shareTokenValidatePassword == false) {
|
if (data && data.shareTokenValidatePassword == false) {
|
||||||
return (
|
return (
|
||||||
<ProtectedTokenEnterPassword
|
<ProtectedTokenEnterPassword
|
||||||
match={match}
|
|
||||||
refetchWithPassword={password => {
|
refetchWithPassword={password => {
|
||||||
saveSharePassword(token, password)
|
saveSharePassword(token, password)
|
||||||
refetch({ token, password })
|
refetch({ token, password })
|
||||||
|
@ -243,22 +255,18 @@ const TokenRoute = ({ match }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading) return t('general.loading.default', 'Loading...')
|
if (loading) return <div>{t('general.loading.default', 'Loading...')}</div>
|
||||||
|
|
||||||
return <AuthorizedTokenRoute match={match} />
|
return <AuthorizedTokenRoute match={match} />
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenRoute.propTypes = {
|
const SharePage = ({ match }: { match: MatchType }) => {
|
||||||
match: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
const SharePage = ({ match }) => {
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={`${match.url}/:token`}>
|
<Route path={`${match.url}/:token`}>
|
||||||
{({ match }) => {
|
{({ match }: { match: MatchType<TokenRouteMatch> }) => {
|
||||||
return <TokenRoute match={match} />
|
return <TokenRoute match={match} />
|
||||||
}}
|
}}
|
||||||
</Route>
|
</Route>
|
||||||
|
@ -267,8 +275,4 @@ const SharePage = ({ match }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SharePage.propTypes = {
|
|
||||||
...RouterProps,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SharePage
|
export default SharePage
|
|
@ -1,9 +1,21 @@
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import AlbumTitle from '../AlbumTitle'
|
import AlbumTitle from '../AlbumTitle'
|
||||||
import PhotoGallery from '../photoGallery/PhotoGallery'
|
import PhotoGallery from '../photoGallery/PhotoGallery'
|
||||||
import AlbumBoxes from './AlbumBoxes'
|
import AlbumBoxes from './AlbumBoxes'
|
||||||
import AlbumFilter from '../AlbumFilter'
|
import AlbumFilter from '../AlbumFilter'
|
||||||
|
import { albumQuery_album } from '../../Pages/AlbumPage/__generated__/albumQuery'
|
||||||
|
|
||||||
|
type AlbumGalleryProps = {
|
||||||
|
album: albumQuery_album
|
||||||
|
loading?: boolean
|
||||||
|
customAlbumLink?(albumID: string): string
|
||||||
|
showFilter?: boolean
|
||||||
|
setOnlyFavorites?(favorites: boolean): void
|
||||||
|
setOrdering?(ordering: { orderBy: string }): void
|
||||||
|
ordering?: { orderBy: string }
|
||||||
|
onlyFavorites?: boolean
|
||||||
|
onFavorite?(): void
|
||||||
|
}
|
||||||
|
|
||||||
const AlbumGallery = React.forwardRef(
|
const AlbumGallery = React.forwardRef(
|
||||||
(
|
(
|
||||||
|
@ -17,18 +29,23 @@ const AlbumGallery = React.forwardRef(
|
||||||
ordering,
|
ordering,
|
||||||
onlyFavorites = false,
|
onlyFavorites = false,
|
||||||
onFavorite,
|
onFavorite,
|
||||||
},
|
}: AlbumGalleryProps,
|
||||||
ref
|
ref: React.ForwardedRef<HTMLDivElement>
|
||||||
) => {
|
) => {
|
||||||
const [imageState, setImageState] = useState({
|
type ImageStateType = {
|
||||||
|
activeImage: number
|
||||||
|
presenting: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const [imageState, setImageState] = useState<ImageStateType>({
|
||||||
activeImage: -1,
|
activeImage: -1,
|
||||||
presenting: false,
|
presenting: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const setPresenting = presenting =>
|
const setPresenting = (presenting: boolean) =>
|
||||||
setImageState(state => ({ ...state, presenting }))
|
setImageState(state => ({ ...state, presenting }))
|
||||||
|
|
||||||
const setPresentingWithHistory = presenting => {
|
const setPresentingWithHistory = (presenting: boolean) => {
|
||||||
setPresenting(presenting)
|
setPresenting(presenting)
|
||||||
if (presenting) {
|
if (presenting) {
|
||||||
history.pushState({ imageState }, '')
|
history.pushState({ imageState }, '')
|
||||||
|
@ -37,12 +54,12 @@ const AlbumGallery = React.forwardRef(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateHistory = imageState => {
|
const updateHistory = (imageState: ImageStateType) => {
|
||||||
history.replaceState({ imageState }, '')
|
history.replaceState({ imageState }, '')
|
||||||
return imageState
|
return imageState
|
||||||
}
|
}
|
||||||
|
|
||||||
const setActiveImage = activeImage => {
|
const setActiveImage = (activeImage: number) => {
|
||||||
setImageState(state => updateHistory({ ...state, activeImage }))
|
setImageState(state => updateHistory({ ...state, activeImage }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +76,10 @@ const AlbumGallery = React.forwardRef(
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateImageState = event => {
|
const updateImageState = (event: PopStateEvent) => {
|
||||||
setImageState(event.state.imageState)
|
setImageState(event.state.imageState)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('popstate', updateImageState)
|
window.addEventListener('popstate', updateImageState)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -129,16 +147,4 @@ const AlbumGallery = React.forwardRef(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
AlbumGallery.propTypes = {
|
|
||||||
album: PropTypes.object,
|
|
||||||
loading: PropTypes.bool,
|
|
||||||
customAlbumLink: PropTypes.func,
|
|
||||||
showFilter: PropTypes.bool,
|
|
||||||
setOnlyFavorites: PropTypes.func,
|
|
||||||
onlyFavorites: PropTypes.bool,
|
|
||||||
onFavorite: PropTypes.func,
|
|
||||||
setOrdering: PropTypes.func,
|
|
||||||
ordering: PropTypes.object,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AlbumGallery
|
export default AlbumGallery
|
|
@ -119,7 +119,7 @@ type MediaThumbnailProps = {
|
||||||
index: number
|
index: number
|
||||||
active: boolean
|
active: boolean
|
||||||
setPresenting(presenting: boolean): void
|
setPresenting(presenting: boolean): void
|
||||||
onFavorite(): void
|
onFavorite?(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MediaThumbnail = ({
|
export const MediaThumbnail = ({
|
||||||
|
|
|
@ -48,7 +48,7 @@ type PhotoGalleryProps = {
|
||||||
setPresenting(presenting: boolean): void
|
setPresenting(presenting: boolean): void
|
||||||
nextImage(): void
|
nextImage(): void
|
||||||
previousImage(): void
|
previousImage(): void
|
||||||
onFavorite(): void
|
onFavorite?(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
const PhotoGallery = ({
|
const PhotoGallery = ({
|
||||||
|
|
|
@ -71,7 +71,7 @@ export interface ProtectedVideoProps_Media {
|
||||||
thumbnail: null | {
|
thumbnail: null | {
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
videoWeb: {
|
videoWeb: null | {
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,14 +80,21 @@ export interface ProtectedVideoProps {
|
||||||
media: ProtectedVideoProps_Media
|
media: ProtectedVideoProps_Media
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProtectedVideo = ({ media, ...props }: ProtectedVideoProps) => (
|
export const ProtectedVideo = ({ media, ...props }: ProtectedVideoProps) => {
|
||||||
<video
|
if (media.videoWeb === null) {
|
||||||
{...props}
|
console.error('ProetctedVideo called with media.videoWeb = null')
|
||||||
controls
|
return null
|
||||||
key={media.id}
|
}
|
||||||
crossOrigin="use-credentials"
|
|
||||||
poster={getProtectedUrl(media.thumbnail?.url)}
|
return (
|
||||||
>
|
<video
|
||||||
<source src={getProtectedUrl(media.videoWeb.url)} type="video/mp4" />
|
{...props}
|
||||||
</video>
|
controls
|
||||||
)
|
key={media.id}
|
||||||
|
crossOrigin="use-credentials"
|
||||||
|
poster={getProtectedUrl(media.thumbnail?.url)}
|
||||||
|
>
|
||||||
|
<source src={getProtectedUrl(media.videoWeb.url)} type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ const StyledVideo = styled(ProtectedVideo)`
|
||||||
|
|
||||||
export interface PresentMediaProps_Media extends ProtectedVideoProps_Media {
|
export interface PresentMediaProps_Media extends ProtectedVideoProps_Media {
|
||||||
type: MediaType
|
type: MediaType
|
||||||
highRes?: {
|
highRes: null | {
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,6 @@ export function debounce<T extends (...args: any[]) => any>(
|
||||||
return debounced
|
return debounced
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNil(value: any) {
|
export function isNil(value: any): value is undefined | null {
|
||||||
return value === undefined || value === null
|
return value === undefined || value === null
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
// "composite": true, /* Enable project compilation */
|
// "composite": true, /* Enable project compilation */
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
// "noEmit": true /* Do not emit outputs. */,
|
"noEmit": true /* Do not emit outputs. */,
|
||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
Loading…
Reference in New Issue