Skip to content

Commit ed64769

Browse files
committed
feat: expose built-in type
1 parent feecc4e commit ed64769

File tree

12 files changed

+357
-302
lines changed

12 files changed

+357
-302
lines changed

docs/pages/full/index.tsx

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { SvgIconProps } from '@mui/material'
12
import {
23
AppBar,
34
Box,
@@ -6,22 +7,25 @@ import {
67
InputLabel,
78
MenuItem,
89
Select,
9-
Switch,
10+
SvgIcon, Switch,
1011
TextField,
1112
Toolbar,
1213
Typography
1314
} from '@mui/material'
1415
import type {
16+
DataType,
1517
JsonViewerKeyRenderer,
1618
JsonViewerOnChange,
1719
JsonViewerTheme
1820
} from '@textea/json-viewer'
1921
import {
2022
applyValue,
2123
createDataType,
22-
JsonViewer
24+
JsonViewer,
25+
stringType
2326
} from '@textea/json-viewer'
2427
import Image from 'next/image'
28+
import Link from 'next/link'
2529
import type { FC } from 'react'
2630
import { useCallback, useEffect, useState } from 'react'
2731

@@ -99,6 +103,7 @@ const example = {
99103
},
100104
string_number: '1234',
101105
timer: 0,
106+
link: 'http://example.com',
102107
avatar,
103108
date: new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)'),
104109
bigint: 123456789087654321n
@@ -111,6 +116,61 @@ const KeyRenderer: JsonViewerKeyRenderer = ({ path }) => {
111116
}
112117
KeyRenderer.when = (props) => props.value === 114.514
113118

119+
const imageDataType = createDataType<string>(
120+
(value) => {
121+
if (typeof value === 'string') {
122+
try {
123+
const url = new URL(value)
124+
return allowedDomains.includes(url.host) && url.pathname.endsWith('.jpg')
125+
} catch (_) {
126+
return false
127+
}
128+
}
129+
return false
130+
},
131+
(props) => {
132+
return (
133+
<Image
134+
height={50}
135+
width={50}
136+
src={props.value}
137+
alt={props.value}
138+
/>
139+
)
140+
}
141+
)
142+
143+
const LinkIcon = (props: SvgIconProps) => (
144+
// <svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' strokeWidth='2' stroke='currentColor' fill='none' strokeLinecap='round' strokeLinejoin='round'>
145+
<SvgIcon {...props}>
146+
<path stroke='none' d='M0 0h24v24H0z' fill='none'></path>
147+
<path stroke='currentcolor' d='M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5' fill='none'></path>
148+
<path stroke='currentcolor' d='M10 14l10 -10'></path>
149+
<path stroke='currentcolor' d='M15 4l5 0l0 5' fill='none'></path>
150+
</SvgIcon>
151+
)
152+
153+
const linkType: DataType<string> = {
154+
...stringType,
155+
is (value) {
156+
return typeof value === 'string' && value.startsWith('http')
157+
},
158+
PostComponent: (props) => (
159+
<Box sx={{
160+
display: 'inline-block',
161+
marginLeft: 1,
162+
color: 'primary.main',
163+
textDecoration: 'underline'
164+
}}
165+
>
166+
<Link href={props.value}>
167+
Open
168+
<LinkIcon sx={{ strokeWidth: 2 }} />
169+
</Link>
170+
</Box>
171+
)
172+
}
173+
114174
const IndexPage: FC = () => {
115175
const [indent, setIndent] = useState(3)
116176
const [groupArraysAfterLength, setGroupArraysAfterLength] = useState(100)
@@ -257,29 +317,8 @@ const IndexPage: FC = () => {
257317
groupArraysAfterLength={groupArraysAfterLength}
258318
keyRenderer={KeyRenderer}
259319
valueTypes={[
260-
createDataType(
261-
(value) => {
262-
if (typeof value === 'string') {
263-
try {
264-
const url = new URL(value)
265-
return allowedDomains.includes(url.host) && url.pathname.endsWith('.jpg')
266-
} catch (_) {
267-
return false
268-
}
269-
}
270-
return false
271-
},
272-
(props) => {
273-
return (
274-
<Image
275-
height={50}
276-
width={50}
277-
src={props.value}
278-
alt={props.value}
279-
/>
280-
)
281-
}
282-
)
320+
linkType,
321+
imageDataType
283322
]}
284323
onChange={
285324
useCallback<JsonViewerOnChange>(

src/components/DataTypes/Boolean.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
import type { DataType } from '../../type'
3+
import { createEasyType } from './createEasyType'
4+
5+
export const booleanType: DataType<boolean> = {
6+
is: (value) => typeof value === 'boolean',
7+
...createEasyType(
8+
'bool',
9+
({ value }) => <>{value ? 'true' : 'false'}</>,
10+
{
11+
colorKey: 'base0E',
12+
fromString: value => Boolean(value)
13+
}
14+
)
15+
}

src/components/DataTypes/Date.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
import type { DataType } from '../../type'
3+
import { createEasyType } from './createEasyType'
4+
5+
const displayOptions: Intl.DateTimeFormatOptions = {
6+
weekday: 'short',
7+
year: 'numeric',
8+
month: 'short',
9+
day: 'numeric',
10+
hour: '2-digit',
11+
minute: '2-digit'
12+
}
13+
14+
export const dateType: DataType<Date> = {
15+
is: (value) => value instanceof Date,
16+
...createEasyType(
17+
'date',
18+
({ value }) => <>{value.toLocaleTimeString('en-us', displayOptions)}</>,
19+
{
20+
colorKey: 'base0D'
21+
}
22+
)
23+
}

src/components/DataTypes/Function.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Box, NoSsr } from '@mui/material'
66
import type { FC } from 'react'
77

88
import { useJsonViewerStore } from '../../stores/JsonViewerStore'
9-
import type { DataItemProps } from '../../type'
9+
import type { DataItemProps, DataType } from '../../type'
1010
import { DataTypeLabel } from '../DataTypeLabel'
1111

1212
const functionBody = (func: Function) => {
@@ -41,7 +41,7 @@ const functionName = (func: Function) => {
4141
const lb = '{'
4242
const rb = '}'
4343

44-
export const PreFunctionType: FC<DataItemProps<Function>> = (props) => {
44+
const PreFunctionType: FC<DataItemProps<Function>> = (props) => {
4545
return (
4646
<NoSsr>
4747
<DataTypeLabel dataType='function' />
@@ -59,7 +59,7 @@ export const PreFunctionType: FC<DataItemProps<Function>> = (props) => {
5959
)
6060
}
6161

62-
export const PostFunctionType: FC<DataItemProps<Function>> = () => {
62+
const PostFunctionType: FC<DataItemProps<Function>> = () => {
6363
return (
6464
<NoSsr>
6565
<Box component='span' className='data-function-end'>
@@ -69,7 +69,7 @@ export const PostFunctionType: FC<DataItemProps<Function>> = () => {
6969
)
7070
}
7171

72-
export const FunctionType: FC<DataItemProps<Function>> = (props) => {
72+
const FunctionType: FC<DataItemProps<Function>> = (props) => {
7373
const functionColor = useJsonViewerStore(store => store.colorspace.base05)
7474
return (
7575
<NoSsr>
@@ -100,3 +100,10 @@ export const FunctionType: FC<DataItemProps<Function>> = (props) => {
100100
</NoSsr>
101101
)
102102
}
103+
104+
export const functionType: DataType<Function> = {
105+
is: (value) => typeof value === 'function',
106+
Component: FunctionType,
107+
PreComponent: PreFunctionType,
108+
PostComponent: PostFunctionType
109+
}

src/components/DataTypes/Null.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Box } from '@mui/material'
2+
3+
import { useJsonViewerStore } from '../../stores/JsonViewerStore'
4+
import type { DataType } from '../../type'
5+
import { createEasyType } from './createEasyType'
6+
7+
export const nullType: DataType<null> = {
8+
is: (value) => value === null,
9+
...createEasyType(
10+
'null',
11+
() => {
12+
const backgroundColor = useJsonViewerStore(store => store.colorspace.base02)
13+
return (
14+
<Box
15+
sx={{
16+
fontSize: '0.8rem',
17+
backgroundColor,
18+
fontWeight: 'bold',
19+
borderRadius: '3px',
20+
padding: '0.5px 2px'
21+
}}
22+
>
23+
NULL
24+
</Box>
25+
)
26+
},
27+
{
28+
colorKey: 'base08',
29+
displayTypeLabel: false
30+
}
31+
)
32+
}

src/components/DataTypes/Number.tsx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Box } from '@mui/material'
2+
3+
import { useJsonViewerStore } from '../../stores/JsonViewerStore'
4+
import type { DataType } from '../../type'
5+
import { createEasyType } from './createEasyType'
6+
7+
const isInt = (n: number) => n % 1 === 0
8+
9+
export const nanType: DataType<number> = {
10+
is: (value) => typeof value === 'number' && isNaN(value),
11+
...createEasyType(
12+
'NaN',
13+
() => {
14+
const backgroundColor = useJsonViewerStore(store => store.colorspace.base02)
15+
return (
16+
<Box
17+
sx={{
18+
backgroundColor,
19+
fontSize: '0.8rem',
20+
fontWeight: 'bold',
21+
borderRadius: '3px'
22+
}}
23+
>
24+
NaN
25+
</Box>
26+
)
27+
},
28+
{
29+
colorKey: 'base08',
30+
displayTypeLabel: false
31+
}
32+
)
33+
}
34+
35+
export const floatType: DataType<number> = {
36+
is: (value) => typeof value === 'number' && !isInt(value),
37+
...createEasyType(
38+
'float',
39+
({ value }) => <>{value}</>,
40+
{
41+
colorKey: 'base0B',
42+
fromString: value => parseFloat(value)
43+
}
44+
)
45+
}
46+
47+
export const intType: DataType<number> = {
48+
is: (value) => typeof value === 'number' && isInt(value),
49+
...createEasyType(
50+
'int',
51+
({ value }) => <>{value}</>,
52+
{
53+
colorKey: 'base0F',
54+
fromString: value => parseInt(value)
55+
}
56+
)
57+
}
58+
59+
export const bigIntType: DataType<bigint> = {
60+
is: (value) => typeof value === 'bigint',
61+
...createEasyType(
62+
'bigint',
63+
({ value }) => <>{`${value}n`}</>,
64+
{
65+
colorKey: 'base0F',
66+
fromString: value => BigInt(value.replace(/\D/g, ''))
67+
}
68+
)
69+
}

src/components/DataTypes/Object.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useMemo, useState } from 'react'
55
import { useTextColor } from '../../hooks/useColor'
66
import { useIsCycleReference } from '../../hooks/useIsCycleReference'
77
import { useJsonViewerStore } from '../../stores/JsonViewerStore'
8-
import type { DataItemProps } from '../../type'
8+
import type { DataItemProps, DataType } from '../../type'
99
import { getValueSize, segmentArray } from '../../utils'
1010
import { DataKeyPair } from '../DataKeyPair'
1111
import { CircularArrowsIcon } from '../Icons'
@@ -29,7 +29,7 @@ function inspectMetadata (value: object) {
2929
return `${length} Items${name ? ` (${name})` : ''}`
3030
}
3131

32-
export const PreObjectType: FC<DataItemProps<object>> = (props) => {
32+
const PreObjectType: FC<DataItemProps<object>> = (props) => {
3333
const metadataColor = useJsonViewerStore(store => store.colorspace.base04)
3434
const textColor = useTextColor()
3535
const isArray = useMemo(() => Array.isArray(props.value), [props.value])
@@ -77,7 +77,7 @@ export const PreObjectType: FC<DataItemProps<object>> = (props) => {
7777
)
7878
}
7979

80-
export const PostObjectType: FC<DataItemProps<object>> = (props) => {
80+
const PostObjectType: FC<DataItemProps<object>> = (props) => {
8181
const metadataColor = useJsonViewerStore(store => store.colorspace.base04)
8282
const isArray = useMemo(() => Array.isArray(props.value), [props.value])
8383
const displayObjectSize = useJsonViewerStore(store => store.displayObjectSize)
@@ -110,7 +110,7 @@ function getIterator (value: any): value is Iterable<unknown> {
110110
return typeof value?.[Symbol.iterator] === 'function'
111111
}
112112

113-
export const ObjectType: FC<DataItemProps<object>> = (props) => {
113+
const ObjectType: FC<DataItemProps<object>> = (props) => {
114114
const keyColor = useTextColor()
115115
const borderColor = useJsonViewerStore(store => store.colorspace.base02)
116116
const groupArraysAfterLength = useJsonViewerStore(store => store.groupArraysAfterLength)
@@ -296,3 +296,10 @@ export const ObjectType: FC<DataItemProps<object>> = (props) => {
296296
</Box>
297297
)
298298
}
299+
300+
export const objectType: DataType<object> = {
301+
is: (value) => typeof value === 'object',
302+
Component: ObjectType,
303+
PreComponent: PreObjectType,
304+
PostComponent: PostObjectType
305+
}

0 commit comments

Comments
 (0)