mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Rewrite expandable content
This commit is contained in:
15
App.tsx
15
App.tsx
@ -10,14 +10,13 @@ import { persistor, store } from '@root/store'
|
|||||||
import { resetLocal } from '@root/utils/slices/instancesSlice'
|
import { resetLocal } from '@root/utils/slices/instancesSlice'
|
||||||
import ThemeManager from '@utils/styles/ThemeManager'
|
import ThemeManager from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
// if (__DEV__) {
|
if (__DEV__) {
|
||||||
// const whyDidYouRender = require('@welldone-software/why-did-you-render')
|
const whyDidYouRender = require('@welldone-software/why-did-you-render')
|
||||||
// whyDidYouRender(React, {
|
whyDidYouRender(React, {
|
||||||
// trackAllPureComponents: true,
|
trackHooks: true,
|
||||||
// trackHooks: true,
|
hotReloadBufferMs: 1000
|
||||||
// hotReloadBufferMs: 1000
|
})
|
||||||
// })
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
const queryClient = new QueryClient()
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useCallback, useState } from 'react'
|
import { LinearGradient } from 'expo-linear-gradient'
|
||||||
|
import React, { useCallback, useMemo, useState } from 'react'
|
||||||
import { Pressable, Text, View } from 'react-native'
|
import { Pressable, Text, View } from 'react-native'
|
||||||
import HTMLView from 'react-native-htmlview'
|
import HTMLView from 'react-native-htmlview'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
@ -6,8 +7,8 @@ import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
|||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { LinearGradient } from 'expo-linear-gradient'
|
|
||||||
import openLink from '@root/utils/openLink'
|
import openLink from '@root/utils/openLink'
|
||||||
|
import layoutAnimation from '@root/utils/styles/layoutAnimation'
|
||||||
|
|
||||||
// Prevent going to the same hashtag multiple times
|
// Prevent going to the same hashtag multiple times
|
||||||
const renderNode = ({
|
const renderNode = ({
|
||||||
@ -96,7 +97,7 @@ const renderNode = ({
|
|||||||
} else {
|
} else {
|
||||||
if (node.name === 'p') {
|
if (node.name === 'p') {
|
||||||
if (!node.children.length) {
|
if (!node.children.length) {
|
||||||
return <View key={index}></View> // bug when the tag is empty
|
return <View key={index} /> // bug when the tag is empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,6 +110,7 @@ export interface Props {
|
|||||||
mentions?: Mastodon.Mention[]
|
mentions?: Mastodon.Mention[]
|
||||||
showFullLink?: boolean
|
showFullLink?: boolean
|
||||||
numberOfLines?: number
|
numberOfLines?: number
|
||||||
|
expandHint?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParseContent: React.FC<Props> = ({
|
const ParseContent: React.FC<Props> = ({
|
||||||
@ -117,7 +119,8 @@ const ParseContent: React.FC<Props> = ({
|
|||||||
emojis,
|
emojis,
|
||||||
mentions,
|
mentions,
|
||||||
showFullLink = false,
|
showFullLink = false,
|
||||||
numberOfLines = 10
|
numberOfLines = 10,
|
||||||
|
expandHint = '全文'
|
||||||
}) => {
|
}) => {
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
@ -136,7 +139,8 @@ const ParseContent: React.FC<Props> = ({
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
const textComponent = useCallback(({ children }) => {
|
const textComponent = useCallback(({ children }) => {
|
||||||
return emojis && children ? (
|
if (children) {
|
||||||
|
return emojis ? (
|
||||||
<Emojis
|
<Emojis
|
||||||
content={children.toString()}
|
content={children.toString()}
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
@ -145,46 +149,66 @@ const ParseContent: React.FC<Props> = ({
|
|||||||
) : (
|
) : (
|
||||||
<Text>{children}</Text>
|
<Text>{children}</Text>
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
const rootComponent = useCallback(({ children }) => {
|
const rootComponent = useCallback(({ children }) => {
|
||||||
const { theme } = useTheme()
|
// layoutAnimation()
|
||||||
const [textLoaded, setTextLoaded] = useState(false)
|
const lineHeight = StyleConstants.Font.LineHeight[size]
|
||||||
const [totalLines, setTotalLines] = useState<number | undefined>()
|
|
||||||
const [lineHeight, setLineHeight] = useState<number | undefined>()
|
const [heightOriginal, setHeightOriginal] = useState<number>()
|
||||||
const [shownLines, setShownLines] = useState(numberOfLines)
|
const [heightTruncated, setHeightTruncated] = useState<number>()
|
||||||
|
const [allowExpand, setAllowExpand] = useState(false)
|
||||||
|
const [showAllText, setShowAllText] = useState(false)
|
||||||
|
|
||||||
|
const calNumberOfLines = useMemo(() => {
|
||||||
|
if (heightOriginal) {
|
||||||
|
if (!heightTruncated) {
|
||||||
|
return numberOfLines
|
||||||
|
} else {
|
||||||
|
if (allowExpand && !showAllText) {
|
||||||
|
return numberOfLines
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}, [heightOriginal, heightTruncated, allowExpand, showAllText])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={
|
style={{ lineHeight }}
|
||||||
totalLines && totalLines > numberOfLines ? shownLines : totalLines
|
children={children}
|
||||||
|
numberOfLines={calNumberOfLines}
|
||||||
|
onLayout={({ nativeEvent }) => {
|
||||||
|
if (!heightOriginal) {
|
||||||
|
setHeightOriginal(nativeEvent.layout.height)
|
||||||
|
} else {
|
||||||
|
if (!heightTruncated) {
|
||||||
|
setHeightTruncated(nativeEvent.layout.height)
|
||||||
|
} else {
|
||||||
|
if (heightOriginal > heightTruncated) {
|
||||||
|
setAllowExpand(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
style={{ lineHeight: StyleConstants.Font.LineHeight[size] }}
|
|
||||||
onTextLayout={({ nativeEvent }) => {
|
|
||||||
if (!textLoaded) {
|
|
||||||
setTextLoaded(true)
|
|
||||||
setTotalLines(nativeEvent.lines.length)
|
|
||||||
setLineHeight(nativeEvent.lines[0].height)
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
{children}
|
{allowExpand && (
|
||||||
</Text>
|
|
||||||
{totalLines && lineHeight && totalLines > shownLines && (
|
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() => {
|
onPress={() => setShowAllText(!showAllText)}
|
||||||
setShownLines(totalLines)
|
style={{ marginTop: showAllText ? 0 : -lineHeight * 1.25 }}
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
marginTop: -lineHeight
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={[
|
colors={[
|
||||||
theme.backgroundGradientStart,
|
theme.backgroundGradientStart,
|
||||||
theme.backgroundGradientEnd
|
theme.backgroundGradientEnd
|
||||||
]}
|
]}
|
||||||
locations={[0, lineHeight / (StyleConstants.Font.Size.S * 5)]}
|
locations={[0, lineHeight / (StyleConstants.Font.Size.S * 4)]}
|
||||||
style={{
|
style={{
|
||||||
paddingTop: StyleConstants.Font.Size.S * 2,
|
paddingTop: StyleConstants.Font.Size.S * 2,
|
||||||
paddingBottom: StyleConstants.Font.Size.S
|
paddingBottom: StyleConstants.Font.Size.S
|
||||||
@ -197,12 +221,12 @@ const ParseContent: React.FC<Props> = ({
|
|||||||
color: theme.primary
|
color: theme.primary
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
展开全文
|
{`${showAllText ? '折叠' : '展开'}${expandHint}`}
|
||||||
</Text>
|
</Text>
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
</>
|
</View>
|
||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
@ -55,7 +55,8 @@ const Timeline: React.FC<Props> = ({
|
|||||||
fetchPreviousPage,
|
fetchPreviousPage,
|
||||||
isFetchingPreviousPage,
|
isFetchingPreviousPage,
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
fetchNextPage
|
fetchNextPage,
|
||||||
|
isFetchingNextPage
|
||||||
} = useInfiniteQuery(queryKey, timelineFetch, {
|
} = useInfiniteQuery(queryKey, timelineFetch, {
|
||||||
getPreviousPageParam: firstPage => {
|
getPreviousPageParam: firstPage => {
|
||||||
return firstPage.toots.length
|
return firstPage.toots.length
|
||||||
@ -133,7 +134,10 @@ const Timeline: React.FC<Props> = ({
|
|||||||
() => <TimelineEmpty status={status} refetch={refetch} />,
|
() => <TimelineEmpty status={status} refetch={refetch} />,
|
||||||
[status]
|
[status]
|
||||||
)
|
)
|
||||||
const onEndReached = useCallback(() => !disableRefresh && fetchNextPage(), [])
|
const onEndReached = useCallback(
|
||||||
|
() => !disableRefresh && !isFetchingNextPage && fetchNextPage(),
|
||||||
|
[isFetchingNextPage]
|
||||||
|
)
|
||||||
const ListFooterComponent = useCallback(
|
const ListFooterComponent = useCallback(
|
||||||
() => <TimelineEnd hasNextPage={!disableRefresh ? hasNextPage : false} />,
|
() => <TimelineEnd hasNextPage={!disableRefresh ? hasNextPage : false} />,
|
||||||
[hasNextPage]
|
[hasNextPage]
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import React, { useState } from 'react'
|
import React from 'react'
|
||||||
import { LayoutAnimation, Pressable, Text, View } from 'react-native'
|
import { View } from 'react-native'
|
||||||
import ParseContent from '@components/ParseContent'
|
import ParseContent from '@components/ParseContent'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { LinearGradient } from 'expo-linear-gradient'
|
|
||||||
import layoutAnimation from '@root/utils/styles/layoutAnimation'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
@ -17,11 +14,6 @@ const TimelineContent: React.FC<Props> = ({
|
|||||||
numberOfLines,
|
numberOfLines,
|
||||||
highlighted = false
|
highlighted = false
|
||||||
}) => {
|
}) => {
|
||||||
layoutAnimation()
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const [spoilerCollapsed, setSpoilerCollapsed] = useState(false)
|
|
||||||
const lineHeight = 28
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{status.spoiler_text ? (
|
{status.spoiler_text ? (
|
||||||
@ -32,58 +24,16 @@ const TimelineContent: React.FC<Props> = ({
|
|||||||
emojis={status.emojis}
|
emojis={status.emojis}
|
||||||
numberOfLines={999}
|
numberOfLines={999}
|
||||||
/>
|
/>
|
||||||
<View
|
<View style={{ marginTop: StyleConstants.Font.Size.M }}>
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
height: spoilerCollapsed ? StyleConstants.Font.Size.M : undefined,
|
|
||||||
marginTop: StyleConstants.Font.Size.M
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={status.content}
|
content={status.content}
|
||||||
size={highlighted ? 'L' : 'M'}
|
size={highlighted ? 'L' : 'M'}
|
||||||
emojis={status.emojis}
|
emojis={status.emojis}
|
||||||
mentions={status.mentions}
|
mentions={status.mentions}
|
||||||
numberOfLines={999}
|
numberOfLines={1}
|
||||||
|
expandHint='隐藏内容'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Pressable
|
|
||||||
onPress={() => setSpoilerCollapsed(!spoilerCollapsed)}
|
|
||||||
style={{
|
|
||||||
marginTop: spoilerCollapsed ? -lineHeight : 0
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LinearGradient
|
|
||||||
{...(spoilerCollapsed
|
|
||||||
? {
|
|
||||||
colors: [
|
|
||||||
theme.backgroundGradientStart,
|
|
||||||
theme.backgroundGradientEnd
|
|
||||||
],
|
|
||||||
locations: [
|
|
||||||
0,
|
|
||||||
lineHeight / (StyleConstants.Font.Size.S * 4)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
colors: ['rgba(0, 0, 0, 0)']
|
|
||||||
})}
|
|
||||||
style={{
|
|
||||||
paddingTop: StyleConstants.Font.Size.S * 2,
|
|
||||||
paddingBottom: StyleConstants.Font.Size.S
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
textAlign: 'center',
|
|
||||||
fontSize: StyleConstants.Font.Size.S,
|
|
||||||
color: theme.primary
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{spoilerCollapsed ? '展开' : '收起'}隐藏内容
|
|
||||||
</Text>
|
|
||||||
</LinearGradient>
|
|
||||||
</Pressable>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ParseContent
|
<ParseContent
|
||||||
@ -91,7 +41,7 @@ const TimelineContent: React.FC<Props> = ({
|
|||||||
size={highlighted ? 'L' : 'M'}
|
size={highlighted ? 'L' : 'M'}
|
||||||
emojis={status.emojis}
|
emojis={status.emojis}
|
||||||
mentions={status.mentions}
|
mentions={status.mentions}
|
||||||
{...(numberOfLines && { numberOfLines: numberOfLines })}
|
numberOfLines={numberOfLines}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
34
yarn.lock
34
yarn.lock
@ -3400,25 +3400,25 @@ gl-react-blurhash@^1.0.0:
|
|||||||
blurhash "^1.1.3"
|
blurhash "^1.1.3"
|
||||||
|
|
||||||
gl-react-expo@^4.0.1:
|
gl-react-expo@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/gl-react-expo/-/gl-react-expo-4.0.1.tgz#7512b65fd7e27d84f3405e737f8b334aed6b69fc"
|
resolved "https://registry.yarnpkg.com/gl-react-expo/-/gl-react-expo-4.1.0.tgz#0f3b13fae7fe490bc72fcf59c894605293da642d"
|
||||||
integrity sha512-L4bwpqEolXmdc1YH8okN4qkfOW13/iLvevhJYgf2mHaLCRwhW1WDUJ18EEip8lUxaUmH9NmT9SC5DwMRiP0YSg==
|
integrity sha512-3Q4LOBGYsNNqpLkwUsUlRrFCNLUqjVsVPKE3c6pLABfkNxyBacbDK3mg3T8XOD7jp+Vsp/Ic9McjICMsYHANJw==
|
||||||
dependencies:
|
dependencies:
|
||||||
invariant "^2.2.4"
|
invariant "^2.2.4"
|
||||||
webgltexture-loader-expo "1.0.0"
|
webgltexture-loader-expo "1.0.0"
|
||||||
|
|
||||||
gl-react@^4.0.1:
|
gl-react@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/gl-react/-/gl-react-4.0.1.tgz#6b747084237dc2209eb3ed05162bb5941c5a6e94"
|
resolved "https://registry.yarnpkg.com/gl-react/-/gl-react-4.1.0.tgz#b7623555a4c3ba92a1ccbbb122c28c46231cd863"
|
||||||
integrity sha512-/+wbFHVeh21wOS6g3v7r/zAdXoYMqn7xCB0CwLwMxBUwUsnV0jcvGS+8HDoup9Yd20xGt77p2c3gmrt2XtEEgg==
|
integrity sha512-hTvxQHN2wxLfbA4c6mRcMdXWjA0/8UY2Sxn5eNre0DOrcauBj/+vMeAMbL2+zwE1BfVYnraE4cvKJTIzFIeBLw==
|
||||||
dependencies:
|
dependencies:
|
||||||
gl-shader "^4.2.1"
|
gl-shader "^4.2.1"
|
||||||
invariant "^2.2.4"
|
invariant "^2.2.4"
|
||||||
ndarray "^1.0.18"
|
ndarray "^1.0.19"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
typedarray-pool "^1.1.0"
|
typedarray-pool "^1.2.0"
|
||||||
webgltexture-loader "1.0.0"
|
webgltexture-loader "1.0.0"
|
||||||
webgltexture-loader-ndarray "1.0.0"
|
webgltexture-loader-ndarray "1.1.0"
|
||||||
|
|
||||||
gl-shader@^4.2.1:
|
gl-shader@^4.2.1:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
@ -4811,7 +4811,7 @@ ndarray-ops@^1.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
cwise-compiler "^1.0.0"
|
cwise-compiler "^1.0.0"
|
||||||
|
|
||||||
ndarray@^1.0.18:
|
ndarray@^1.0.19:
|
||||||
version "1.0.19"
|
version "1.0.19"
|
||||||
resolved "https://registry.yarnpkg.com/ndarray/-/ndarray-1.0.19.tgz#6785b5f5dfa58b83e31ae5b2a058cfd1ab3f694e"
|
resolved "https://registry.yarnpkg.com/ndarray/-/ndarray-1.0.19.tgz#6785b5f5dfa58b83e31ae5b2a058cfd1ab3f694e"
|
||||||
integrity sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==
|
integrity sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==
|
||||||
@ -6365,7 +6365,7 @@ type-fest@^0.7.1:
|
|||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
|
||||||
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
|
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
|
||||||
|
|
||||||
typedarray-pool@^1.1.0:
|
typedarray-pool@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray-pool/-/typedarray-pool-1.2.0.tgz#e7e90720144ba02b9ed660438af6f3aacfe33ac3"
|
resolved "https://registry.yarnpkg.com/typedarray-pool/-/typedarray-pool-1.2.0.tgz#e7e90720144ba02b9ed660438af6f3aacfe33ac3"
|
||||||
integrity sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==
|
integrity sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==
|
||||||
@ -6613,14 +6613,14 @@ webgltexture-loader-expo@1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
webgltexture-loader "^1.0.0"
|
webgltexture-loader "^1.0.0"
|
||||||
|
|
||||||
webgltexture-loader-ndarray@1.0.0:
|
webgltexture-loader-ndarray@1.1.0:
|
||||||
version "1.0.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/webgltexture-loader-ndarray/-/webgltexture-loader-ndarray-1.0.0.tgz#844181c4cbe0cbc066750d66412c11d9205ad79a"
|
resolved "https://registry.yarnpkg.com/webgltexture-loader-ndarray/-/webgltexture-loader-ndarray-1.1.0.tgz#20869150e79dfb6190cbd6bedafacda262e29a5e"
|
||||||
integrity sha512-ocEStCCkihBu+PyMr14ke2vv08c5wVObP5mH9AuPICcBvaS8zfxvMpoGc9dIxOxBC1reI/lzmpYxpYdoY/Ke8g==
|
integrity sha512-t9Q4x5do5feHjMOJLCg8UdQVx1eInnWXvgAqaL9NJJSL5pzI59Ynx3ZZSw3QqGxj15iRbYij7vK8BCIDyp5EZA==
|
||||||
dependencies:
|
dependencies:
|
||||||
ndarray "^1.0.18"
|
ndarray "^1.0.19"
|
||||||
ndarray-ops "^1.2.2"
|
ndarray-ops "^1.2.2"
|
||||||
typedarray-pool "^1.1.0"
|
typedarray-pool "^1.2.0"
|
||||||
webgltexture-loader "^1.0.0"
|
webgltexture-loader "^1.0.0"
|
||||||
|
|
||||||
webgltexture-loader@1.0.0, webgltexture-loader@^1.0.0:
|
webgltexture-loader@1.0.0, webgltexture-loader@^1.0.0:
|
||||||
|
Reference in New Issue
Block a user