Skip to content

feat: support groupArraysAfterLength #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion examples/basic/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const example = {
string: 'this is a string',
integer: 42,
array: [19, 19, 810, 'test', NaN],
nestedArray: [
[1, 2],
[3, 4]
],
float: 114.514,
undefined,
object: {
Expand All @@ -30,6 +34,7 @@ const example = {

const IndexPage: React.FC = () => {
const [indent, setIndent] = useState(2)
const [groupArraysAfterLength, setGroupArraysAfterLength] = useState(100)
const [src, setSrc] = useState(() => example)
useEffect(() => {
const loop = () => {
Expand Down Expand Up @@ -57,13 +62,30 @@ const IndexPage: React.FC = () => {
}
}
/>
<TextField
value={groupArraysAfterLength}
type='number'
onChange={
event => {
const groupArraysAfterLength = parseInt(event.target.value)
if (groupArraysAfterLength > -1 && groupArraysAfterLength < 500) {
setGroupArraysAfterLength(groupArraysAfterLength)
}
}
}
/>
<JsonViewer
value={src}
indentWidth={indent}
groupArraysAfterLength={groupArraysAfterLength}
onChange={
useCallback<JsonViewerOnChange>(
(path, oldValue, newValue) => {
setSrc(src => applyValue(src, path, newValue))
setSrc(src => {
const newSrc = applyValue(src, path, newValue)
console.log(newSrc, newSrc === src)
return src
})
}, []
)
}
Expand Down
27 changes: 18 additions & 9 deletions src/components/DataKeyPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import { DataBox } from './mui/DataBox'

export type DataKeyPairProps = {
value: unknown
path: string[]
nested?: boolean
path: (string | number)[]
}

const IconBox = styled(props => <Box {...props} component='span'/>)`
Expand All @@ -42,17 +43,18 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
const keyColor = useTextColor()
const numberKeyColor = useJsonViewerStore(
store => store.colorNamespace.base0C)
const { Component, PreComponent, PostComponent, Editor } = useTypeComponents(value)
const { Component, PreComponent, PostComponent, Editor } = useTypeComponents(
value)
const rootName = useJsonViewerStore(store => store.rootName)
const isRoot = useJsonViewerStore(store => store.value) === value
const isNumberKey = Number.isInteger(Number(key))
const displayKey = isRoot ? rootName : key
const downstreamProps: DataItemProps = {
const downstreamProps: DataItemProps = useMemo(() => ({
path,
inspect,
setInspect,
value
}
}), [inspect, path, value])
const actionIcons = useMemo(() => {
if (editing) {
return (
Expand Down Expand Up @@ -151,12 +153,19 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
}, [])
}
>
{isNumberKey
? <Box component='span'
style={{ color: numberKeyColor }}>{displayKey}</Box>
: <>&quot;{displayKey}&quot;</>
{
!props.nested && (
isNumberKey
? <Box component='span'
style={{ color: numberKeyColor }}>{displayKey}</Box>
: <>&quot;{displayKey}&quot;</>
)
}
{
!props.nested && (
<DataBox sx={{ mx: 0.5 }}>:</DataBox>
)
}
<DataBox sx={{ mx: 0.5 }}>:</DataBox>
{PreComponent && <PreComponent {...downstreamProps}/>}
{(isHover && expandable && inspect) && actionIcons}
</DataBox>
Expand Down
113 changes: 113 additions & 0 deletions src/components/DataTypes/Array.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Box } from '@mui/material'
import React, { useMemo } from 'react'

import { useTextColor } from '../../hooks/useColor'
import { useJsonViewerStore } from '../../stores/JsonViewerStore'
import type { DataItemProps } from '../../type'
import { DataKeyPair } from '../DataKeyPair'

const arrayLb = '['
const arrayRb = ']'

export const PreArrayType: React.FC<DataItemProps<unknown[]>> = (props) => {
const metadataColor = useJsonViewerStore(store => store.colorNamespace.base04)
const sizeOfValue = useMemo(
() => props.inspect ? `${Object.keys(props.value).length} Items` : '',
[props.inspect, props.value]
)
return (
<Box
component='span' className='data-array-start'
sx={{
letterSpacing: 0.5
}}
>
{arrayLb}
<Box
component='span'
sx={{
pl: 0.5,
fontStyle: 'italic',
color: metadataColor
}}
>
{sizeOfValue}
</Box>
</Box>
)
}

export const PostArrayType: React.FC<DataItemProps<unknown[]>> = (props) => {
const metadataColor = useJsonViewerStore(store => store.colorNamespace.base04)
const sizeOfValue = useMemo(
() => !props.inspect ? `${Object.keys(props.value).length} Items` : '',
[props.inspect, props.value]
)
return (
<Box component='span' className='data-array-end'>
{arrayRb}
<Box
component='span'
sx={{
pl: 0.5,
fontStyle: 'italic',
color: metadataColor
}}
>
{sizeOfValue}
</Box>
</Box>
)
}

export const ArrayType: React.FC<DataItemProps<unknown[]>> = (props) => {
const keyColor = useTextColor()
const groupArraysAfterLength = useJsonViewerStore(store => store.groupArraysAfterLength)
const elements = useMemo(() => {
if (props.value.length <= groupArraysAfterLength) {
return props.value.map((value, index) => {
const path = [...props.path, index]
return (
<DataKeyPair key={index} path={path} value={value}/>
)
})
}
const value = props.value.reduce<unknown[][]>((array, value, index) => {
const target = Math.floor(index / groupArraysAfterLength)
if (array[target]) {
array[target].push(value)
} else {
array[target] = [value]
}
return array
}, [])
console.log('value', value)

return value.map((list, index) => {
const path = [...props.path]
return (
<DataKeyPair key={index} path={path} value={list} nested/>
)
})
}, [props.path, props.value, groupArraysAfterLength])
return (
<Box
className='data-array'
sx={{
display: props.inspect ? 'block' : 'inline-block',
pl: props.inspect ? 2 : 0,
color: keyColor
}}
>
{
props.inspect
? elements
: (
<Box component='span' className='data-array-body'>
...
</Box>
)
}
</Box>
)
}
29 changes: 17 additions & 12 deletions src/components/DataTypes/Object.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { useJsonViewerStore } from '../../stores/JsonViewerStore'
import type { DataItemProps } from '../../type'
import { DataKeyPair } from '../DataKeyPair'

const lb = '{'
const rb = '}'
const objectLb = '{'
const arrayLb = '['
const objectRb = '}'
const arrayRb = ']'

export const PreObjectType: React.FC<DataItemProps<object>> = (props) => {
const metadataColor = useJsonViewerStore(store => store.colorNamespace.base04)
const isArray = useMemo(() => Array.isArray(props.value), [props.value])
const sizeOfValue = useMemo(
() => props.inspect ? `${Object.keys(props.value).length} Items` : '',
[props.inspect, props.value]
Expand All @@ -22,7 +25,7 @@ export const PreObjectType: React.FC<DataItemProps<object>> = (props) => {
letterSpacing: 0.5
}}
>
{lb}
{isArray ? arrayLb : objectLb}
<Box
component='span'
sx={{
Expand All @@ -39,13 +42,14 @@ export const PreObjectType: React.FC<DataItemProps<object>> = (props) => {

export const PostObjectType: React.FC<DataItemProps<object>> = (props) => {
const metadataColor = useJsonViewerStore(store => store.colorNamespace.base04)
const isArray = useMemo(() => Array.isArray(props.value), [props.value])
const sizeOfValue = useMemo(
() => !props.inspect ? `${Object.keys(props.value).length} Items` : '',
[props.inspect, props.value]
)
return (
<Box component='span' className='data-object-end'>
{rb}
{isArray ? arrayRb : objectRb}
<Box
component='span'
sx={{
Expand All @@ -62,6 +66,14 @@ export const PostObjectType: React.FC<DataItemProps<object>> = (props) => {

export const ObjectType: React.FC<DataItemProps<object>> = (props) => {
const keyColor = useTextColor()
const elements = useMemo(() => (
Object.entries(props.value).map(([key, value]) => {
const path = [...props.path, key]
return (
<DataKeyPair key={key} path={path} value={value}/>
)
})
), [props.path, props.value])
return (
<Box
className='data-object'
Expand All @@ -73,14 +85,7 @@ export const ObjectType: React.FC<DataItemProps<object>> = (props) => {
>
{
props.inspect
? (
Object.entries(props.value).map(([key, value]) => {
const path = [...props.path, key]
return (
<DataKeyPair key={key} path={path} value={value}/>
)
})
)
? elements
: (
<Box component='span' className='data-object-body'>
...
Expand Down
7 changes: 4 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { applyValue } from './utils'

export { applyValue }

export type JsonViewerOnChange = <U = unknown>(path: string[], oldValue: U, newValue: U) => void
export type JsonViewerOnChange = <U = unknown>(path: (string | number)[], oldValue: U, newValue: U) => void

const JsonViewerInner: React.FC<JsonViewerProps> = (props) => {
const api = useJsonViewerStoreApi()
Expand All @@ -26,9 +26,10 @@ const JsonViewerInner: React.FC<JsonViewerProps> = (props) => {
value: props.value,
indentWidth: props.indentWidth,
defaultCollapsed: props.defaultCollapsed,
onChange: props.onChange
onChange: props.onChange,
groupArraysAfterLength: props.groupArraysAfterLength
}))
}, [api, props.defaultCollapsed, props.indentWidth, props.onChange, props.value])
}, [api, props.defaultCollapsed, props.groupArraysAfterLength, props.indentWidth, props.onChange, props.value])

const value = useJsonViewerStore(store => store.value)
const setHover = useJsonViewerStore(store => store.setHover)
Expand Down
6 changes: 4 additions & 2 deletions src/stores/JsonViewerStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ export const darkNamespace: ColorNamespace = {
}

export type JsonViewerState = {
hoverPath: string[] | null
hoverPath: (string | number)[] | null
groupArraysAfterLength: number
defaultCollapsed: number | boolean
colorNamespace: ColorNamespace
expanded: string[]
Expand All @@ -72,7 +73,7 @@ export type JsonViewerState = {
}

export type JsonViewerActions = {
setHover: (path: string[] | null) => void
setHover: (path: (string | number)[] | null) => void
}

// todo
Expand All @@ -81,6 +82,7 @@ export const createJsonViewerStore = () =>
combine<JsonViewerState, JsonViewerActions>(
{
hoverPath: null,
groupArraysAfterLength: 100,
rootName: 'root',
defaultCollapsed: false,
colorNamespace: defaultColorNamespace,
Expand Down
14 changes: 14 additions & 0 deletions src/stores/typeRegistry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { Box } from '@mui/material'
import { DevelopmentError } from '@textea/dev-kit/utils'
import React, { useMemo } from 'react'

import {
ArrayType,
PostArrayType,
PreArrayType
} from '../components/DataTypes/Array'
import { createEasyType } from '../components/DataTypes/createEasyType'
import {
FunctionType, PostFunctionType,
Expand Down Expand Up @@ -200,6 +205,15 @@ registerType<number>(
}
)

registerType<unknown[]>(
{
is: (value): value is unknown[] => Array.isArray(value),
Component: ArrayType,
PreComponent: PreArrayType,
PostComponent: PostArrayType
}
)

// fallback for all data like 'object'
registerType<object>(
{
Expand Down
Loading