Skip to content

Commit 69a359f

Browse files
committed
fix: fix editing on any datatype
BREAKING CHANGE: dropping `createDataType` and change the signature of EditorComponent to only accept string
1 parent ed64769 commit 69a359f

File tree

14 files changed

+274
-233
lines changed

14 files changed

+274
-233
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ see [src/type.ts](src/type.ts)
4646

4747
### Basic Example
4848

49-
```tsx
49+
```jsx
5050
import { JsonViewer } from '@textea/json-viewer'
5151

5252
const object = {
@@ -57,8 +57,8 @@ const Component = () => <JsonViewer value={object} />
5757

5858
### Customizable data type
5959

60-
```tsx
61-
import { JsonViewer, createDataType } from '@textea/json-viewer'
60+
```jsx
61+
import { JsonViewer, defineDataType } from '@textea/json-viewer'
6262

6363
const object = {
6464
// what if I want to inspect a image?
@@ -75,10 +75,10 @@ const Component = () => (
7575
Component: (props) => <Image height={50} width={50} src={props.value} alt={props.value} />
7676
},
7777
// or
78-
createDataType(
79-
(value) => typeof value === 'string' && value.startsWith('https://i.imgur.com'),
80-
(props) => <Image height={50} width={50} src={props.value} alt={props.value} />
81-
)
78+
defineDataType({
79+
is: (value) => typeof value === 'string' && value.startsWith('https://i.imgur.com'),
80+
Component: (props) => <Image height={50} width={50} src={props.value} alt={props.value} />
81+
})
8282
]}
8383
/>
8484
)

docs/pages/full/index.tsx

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type {
2020
} from '@textea/json-viewer'
2121
import {
2222
applyValue,
23-
createDataType,
23+
defineDataType,
2424
JsonViewer,
2525
stringType
2626
} from '@textea/json-viewer'
@@ -44,8 +44,8 @@ const aPlusBConst = function (a: number, b: number) {
4444
}
4545

4646
const loopObject = {
47-
foo: 1,
48-
goo: 'string'
47+
foo: 42,
48+
goo: 'Lorem Ipsum'
4949
} as Record<string, any>
5050

5151
loopObject.self = loopObject
@@ -67,30 +67,35 @@ const set = new Set([1, 2, 3])
6767
const superLongString = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'
6868

6969
const example = {
70+
avatar,
71+
string: 'Lorem ipsum dolor sit amet',
72+
integer: 42,
73+
float: 114.514,
74+
bigint: 123456789087654321n,
75+
undefined,
76+
timer: 0,
77+
date: new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)'),
78+
link: 'http://example.com',
79+
emptyArray: [],
80+
array: [19, 19, 810, 'test', NaN],
81+
emptyObject: {},
82+
object: {
83+
foo: true,
84+
bar: false,
85+
last: null
86+
},
87+
emptyMap: new Map(),
88+
map,
89+
emptySet: new Set(),
90+
set,
7091
loopObject,
7192
loopArray,
7293
longArray,
73-
string: 'this is a string',
74-
integer: 42,
75-
array: [19, 19, 810, 'test', NaN],
76-
emptyArray: [],
7794
nestedArray: [
7895
[1, 2],
7996
[3, 4]
8097
],
81-
map,
82-
emptyMap: new Map(),
83-
set,
84-
emptySet: new Set(),
85-
float: 114.514,
86-
undefined,
8798
superLongString,
88-
object: {
89-
'first-child': true,
90-
'second-child': false,
91-
'last-child': null
92-
},
93-
emptyObject: {},
9499
function: aPlusB,
95100
constFunction: aPlusBConst,
96101
anonymousFunction: function (a: number, b: number) {
@@ -101,12 +106,7 @@ const example = {
101106
console.log(arg1, arg2)
102107
return '123'
103108
},
104-
string_number: '1234',
105-
timer: 0,
106-
link: 'http://example.com',
107-
avatar,
108-
date: new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)'),
109-
bigint: 123456789087654321n
109+
string_number: '1234'
110110
}
111111

112112
const KeyRenderer: JsonViewerKeyRenderer = ({ path }) => {
@@ -116,8 +116,8 @@ const KeyRenderer: JsonViewerKeyRenderer = ({ path }) => {
116116
}
117117
KeyRenderer.when = (props) => props.value === 114.514
118118

119-
const imageDataType = createDataType<string>(
120-
(value) => {
119+
const imageDataType = defineDataType<string>({
120+
is: (value) => {
121121
if (typeof value === 'string') {
122122
try {
123123
const url = new URL(value)
@@ -128,17 +128,18 @@ const imageDataType = createDataType<string>(
128128
}
129129
return false
130130
},
131-
(props) => {
131+
Component: (props) => {
132132
return (
133133
<Image
134-
height={50}
135-
width={50}
134+
height={48}
135+
width={48}
136136
src={props.value}
137137
alt={props.value}
138+
style={{ display: 'inline-block' }}
138139
/>
139140
)
140141
}
141-
)
142+
})
142143

143144
const LinkIcon = (props: SvgIconProps) => (
144145
// <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'>
@@ -163,7 +164,7 @@ const linkType: DataType<string> = {
163164
textDecoration: 'underline'
164165
}}
165166
>
166-
<Link href={props.value}>
167+
<Link href={props.value} target='_blank' rel='noopener noreferrer'>
167168
Open
168169
<LinkIcon sx={{ strokeWidth: 2 }} />
169170
</Link>

src/components/DataKeyPair.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const IconBox: FC<IconBoxProps> = (props) => (
4343

4444
export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
4545
const { value, prevValue, path, nestedIndex } = props
46+
const { Component, PreComponent, PostComponent, Editor, serialize, deserialize } = useTypeComponents(value, path)
47+
4648
const propsEditable = props.editable ?? undefined
4749
const storeEditable = useJsonViewerStore(store => store.editable)
4850
const editable = useMemo(() => {
@@ -58,7 +60,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
5860
}
5961
return storeEditable
6062
}, [path, propsEditable, storeEditable, value])
61-
const [tempValue, setTempValue] = useState(typeof value === 'function' ? () => value : value)
63+
const [tempValue, setTempValue] = useState<string>('')
6264
const depth = path.length
6365
const key = path[depth - 1]
6466
const hoverPath = useJsonViewerStore(store => store.hoverPath)
@@ -75,7 +77,6 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
7577
const keyColor = useTextColor()
7678
const numberKeyColor = useJsonViewerStore(store => store.colorspace.base0C)
7779
const highlightColor = useJsonViewerStore(store => store.colorspace.base0A)
78-
const { Component, PreComponent, PostComponent, Editor } = useTypeComponents(value, path)
7980
const quotesOnKeys = useJsonViewerStore(store => store.quotesOnKeys)
8081
const rootName = useJsonViewerStore(store => store.rootName)
8182
const isRoot = root === value
@@ -134,7 +135,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
134135
}, [highlightColor, isHighlight, prevValue, value])
135136

136137
const actionIcons = useMemo(() => {
137-
if (editing) {
138+
if (editing && deserialize) {
138139
return (
139140
<>
140141
<IconBox>
@@ -143,7 +144,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
143144
onClick={() => {
144145
// abort editing
145146
setEditing(false)
146-
setTempValue(value)
147+
setTempValue('')
147148
}}
148149
/>
149150
</IconBox>
@@ -153,7 +154,12 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
153154
onClick={() => {
154155
// finish editing, save data
155156
setEditing(false)
156-
onChange(path, value, tempValue)
157+
try {
158+
const newValue = deserialize(tempValue)
159+
onChange(path, value, newValue)
160+
} catch (e) {
161+
// do nothing when deserialize failed
162+
}
157163
}}
158164
/>
159165
</IconBox>
@@ -182,14 +188,13 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
182188
}
183189
</IconBox>
184190
)}
185-
{/* todo: support edit object */}
186-
{(Editor && editable) &&
191+
{(Editor && editable && serialize && deserialize) &&
187192
(
188193
<IconBox
189194
onClick={event => {
190195
event.preventDefault()
196+
setTempValue(serialize(value))
191197
setEditing(true)
192-
setTempValue(value)
193198
}}
194199
>
195200
<EditIcon sx={{ fontSize: '.8rem' }} />
@@ -200,6 +205,8 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
200205
},
201206
[
202207
Editor,
208+
serialize,
209+
deserialize,
203210
copied,
204211
copy,
205212
editable,

src/components/DataTypes/Boolean.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11

2-
import type { DataType } from '../../type'
32
import { createEasyType } from './createEasyType'
43

5-
export const booleanType: DataType<boolean> = {
4+
export const booleanType = createEasyType<boolean>({
65
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-
}
6+
type: 'bool',
7+
colorKey: 'base0E',
8+
serialize: value => value.toString(),
9+
deserialize: value => {
10+
if (value === 'true') return true
11+
if (value === 'false') return false
12+
throw new Error('Invalid boolean value')
13+
},
14+
Renderer: ({ value }) => <>{value ? 'true' : 'false'}</>
15+
})

src/components/DataTypes/Date.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11

2-
import type { DataType } from '../../type'
32
import { createEasyType } from './createEasyType'
43

54
const displayOptions: Intl.DateTimeFormatOptions = {
@@ -11,13 +10,9 @@ const displayOptions: Intl.DateTimeFormatOptions = {
1110
minute: '2-digit'
1211
}
1312

14-
export const dateType: DataType<Date> = {
13+
export const dateType = createEasyType<Date>({
1514
is: (value) => value instanceof Date,
16-
...createEasyType(
17-
'date',
18-
({ value }) => <>{value.toLocaleTimeString('en-us', displayOptions)}</>,
19-
{
20-
colorKey: 'base0D'
21-
}
22-
)
23-
}
15+
type: 'date',
16+
colorKey: 'base0D',
17+
Renderer: ({ value }) => <>{value.toLocaleTimeString('en-us', displayOptions)}</>
18+
})

src/components/DataTypes/Null.tsx

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
11
import { Box } from '@mui/material'
22

33
import { useJsonViewerStore } from '../../stores/JsonViewerStore'
4-
import type { DataType } from '../../type'
54
import { createEasyType } from './createEasyType'
65

7-
export const nullType: DataType<null> = {
6+
export const nullType = createEasyType<null>({
87
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-
}
8+
type: 'null',
9+
colorKey: 'base08',
10+
displayTypeLabel: false,
11+
Renderer: () => {
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+
})

0 commit comments

Comments
 (0)