Skip to content

Commit

Permalink
fix: fix editing on any datatype
Browse files Browse the repository at this point in the history
BREAKING CHANGE: dropping `createDataType` and change the signature of EditorComponent to only accept string
  • Loading branch information
pionxzh committed Apr 25, 2023
1 parent ed64769 commit 69a359f
Show file tree
Hide file tree
Showing 14 changed files with 274 additions and 233 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ see [src/type.ts](src/type.ts)

### Basic Example

```tsx
```jsx
import { JsonViewer } from '@textea/json-viewer'

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

### Customizable data type

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

const object = {
// what if I want to inspect a image?
Expand All @@ -75,10 +75,10 @@ const Component = () => (
Component: (props) => <Image height={50} width={50} src={props.value} alt={props.value} />
},
// or
createDataType(
(value) => typeof value === 'string' && value.startsWith('https://i.imgur.com'),
(props) => <Image height={50} width={50} src={props.value} alt={props.value} />
)
defineDataType({
is: (value) => typeof value === 'string' && value.startsWith('https://i.imgur.com'),
Component: (props) => <Image height={50} width={50} src={props.value} alt={props.value} />
})
]}
/>
)
Expand Down
65 changes: 33 additions & 32 deletions docs/pages/full/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {
} from '@textea/json-viewer'
import {
applyValue,
createDataType,
defineDataType,
JsonViewer,
stringType
} from '@textea/json-viewer'
Expand All @@ -44,8 +44,8 @@ const aPlusBConst = function (a: number, b: number) {
}

const loopObject = {
foo: 1,
goo: 'string'
foo: 42,
goo: 'Lorem Ipsum'
} as Record<string, any>

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

const example = {
avatar,
string: 'Lorem ipsum dolor sit amet',
integer: 42,
float: 114.514,
bigint: 123456789087654321n,
undefined,
timer: 0,
date: new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)'),
link: 'http://example.com',
emptyArray: [],
array: [19, 19, 810, 'test', NaN],
emptyObject: {},
object: {
foo: true,
bar: false,
last: null
},
emptyMap: new Map(),
map,
emptySet: new Set(),
set,
loopObject,
loopArray,
longArray,
string: 'this is a string',
integer: 42,
array: [19, 19, 810, 'test', NaN],
emptyArray: [],
nestedArray: [
[1, 2],
[3, 4]
],
map,
emptyMap: new Map(),
set,
emptySet: new Set(),
float: 114.514,
undefined,
superLongString,
object: {
'first-child': true,
'second-child': false,
'last-child': null
},
emptyObject: {},
function: aPlusB,
constFunction: aPlusBConst,
anonymousFunction: function (a: number, b: number) {
Expand All @@ -101,12 +106,7 @@ const example = {
console.log(arg1, arg2)
return '123'
},
string_number: '1234',
timer: 0,
link: 'http://example.com',
avatar,
date: new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)'),
bigint: 123456789087654321n
string_number: '1234'
}

const KeyRenderer: JsonViewerKeyRenderer = ({ path }) => {
Expand All @@ -116,8 +116,8 @@ const KeyRenderer: JsonViewerKeyRenderer = ({ path }) => {
}
KeyRenderer.when = (props) => props.value === 114.514

const imageDataType = createDataType<string>(
(value) => {
const imageDataType = defineDataType<string>({
is: (value) => {
if (typeof value === 'string') {
try {
const url = new URL(value)
Expand All @@ -128,17 +128,18 @@ const imageDataType = createDataType<string>(
}
return false
},
(props) => {
Component: (props) => {
return (
<Image
height={50}
width={50}
height={48}
width={48}
src={props.value}
alt={props.value}
style={{ display: 'inline-block' }}
/>
)
}
)
})

const LinkIcon = (props: SvgIconProps) => (
// <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'>
Expand All @@ -163,7 +164,7 @@ const linkType: DataType<string> = {
textDecoration: 'underline'
}}
>
<Link href={props.value}>
<Link href={props.value} target='_blank' rel='noopener noreferrer'>
Open
<LinkIcon sx={{ strokeWidth: 2 }} />
</Link>
Expand Down
23 changes: 15 additions & 8 deletions src/components/DataKeyPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ const IconBox: FC<IconBoxProps> = (props) => (

export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
const { value, prevValue, path, nestedIndex } = props
const { Component, PreComponent, PostComponent, Editor, serialize, deserialize } = useTypeComponents(value, path)

const propsEditable = props.editable ?? undefined
const storeEditable = useJsonViewerStore(store => store.editable)
const editable = useMemo(() => {
Expand All @@ -58,7 +60,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
}
return storeEditable
}, [path, propsEditable, storeEditable, value])
const [tempValue, setTempValue] = useState(typeof value === 'function' ? () => value : value)
const [tempValue, setTempValue] = useState<string>('')
const depth = path.length
const key = path[depth - 1]
const hoverPath = useJsonViewerStore(store => store.hoverPath)
Expand All @@ -75,7 +77,6 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
const keyColor = useTextColor()
const numberKeyColor = useJsonViewerStore(store => store.colorspace.base0C)
const highlightColor = useJsonViewerStore(store => store.colorspace.base0A)
const { Component, PreComponent, PostComponent, Editor } = useTypeComponents(value, path)
const quotesOnKeys = useJsonViewerStore(store => store.quotesOnKeys)
const rootName = useJsonViewerStore(store => store.rootName)
const isRoot = root === value
Expand Down Expand Up @@ -134,7 +135,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
}, [highlightColor, isHighlight, prevValue, value])

const actionIcons = useMemo(() => {
if (editing) {
if (editing && deserialize) {
return (
<>
<IconBox>
Expand All @@ -143,7 +144,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
onClick={() => {
// abort editing
setEditing(false)
setTempValue(value)
setTempValue('')
}}
/>
</IconBox>
Expand All @@ -153,7 +154,12 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
onClick={() => {
// finish editing, save data
setEditing(false)
onChange(path, value, tempValue)
try {
const newValue = deserialize(tempValue)
onChange(path, value, newValue)
} catch (e) {
// do nothing when deserialize failed
}
}}
/>
</IconBox>
Expand Down Expand Up @@ -182,14 +188,13 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
}
</IconBox>
)}
{/* todo: support edit object */}
{(Editor && editable) &&
{(Editor && editable && serialize && deserialize) &&
(
<IconBox
onClick={event => {
event.preventDefault()
setTempValue(serialize(value))
setEditing(true)
setTempValue(value)
}}
>
<EditIcon sx={{ fontSize: '.8rem' }} />
Expand All @@ -200,6 +205,8 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
},
[
Editor,
serialize,
deserialize,
copied,
copy,
editable,
Expand Down
22 changes: 11 additions & 11 deletions src/components/DataTypes/Boolean.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

import type { DataType } from '../../type'
import { createEasyType } from './createEasyType'

export const booleanType: DataType<boolean> = {
export const booleanType = createEasyType<boolean>({
is: (value) => typeof value === 'boolean',
...createEasyType(
'bool',
({ value }) => <>{value ? 'true' : 'false'}</>,
{
colorKey: 'base0E',
fromString: value => Boolean(value)
}
)
}
type: 'bool',
colorKey: 'base0E',
serialize: value => value.toString(),
deserialize: value => {
if (value === 'true') return true
if (value === 'false') return false
throw new Error('Invalid boolean value')
},
Renderer: ({ value }) => <>{value ? 'true' : 'false'}</>
})
15 changes: 5 additions & 10 deletions src/components/DataTypes/Date.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

import type { DataType } from '../../type'
import { createEasyType } from './createEasyType'

const displayOptions: Intl.DateTimeFormatOptions = {
Expand All @@ -11,13 +10,9 @@ const displayOptions: Intl.DateTimeFormatOptions = {
minute: '2-digit'
}

export const dateType: DataType<Date> = {
export const dateType = createEasyType<Date>({
is: (value) => value instanceof Date,
...createEasyType(
'date',
({ value }) => <>{value.toLocaleTimeString('en-us', displayOptions)}</>,
{
colorKey: 'base0D'
}
)
}
type: 'date',
colorKey: 'base0D',
Renderer: ({ value }) => <>{value.toLocaleTimeString('en-us', displayOptions)}</>
})
47 changes: 21 additions & 26 deletions src/components/DataTypes/Null.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
import { Box } from '@mui/material'

import { useJsonViewerStore } from '../../stores/JsonViewerStore'
import type { DataType } from '../../type'
import { createEasyType } from './createEasyType'

export const nullType: DataType<null> = {
export const nullType = createEasyType<null>({
is: (value) => value === null,
...createEasyType(
'null',
() => {
const backgroundColor = useJsonViewerStore(store => store.colorspace.base02)
return (
<Box
sx={{
fontSize: '0.8rem',
backgroundColor,
fontWeight: 'bold',
borderRadius: '3px',
padding: '0.5px 2px'
}}
>
NULL
</Box>
)
},
{
colorKey: 'base08',
displayTypeLabel: false
}
)
}
type: 'null',
colorKey: 'base08',
displayTypeLabel: false,
Renderer: () => {
const backgroundColor = useJsonViewerStore(store => store.colorspace.base02)
return (
<Box
sx={{
fontSize: '0.8rem',
backgroundColor,
fontWeight: 'bold',
borderRadius: '3px',
padding: '0.5px 2px'
}}
>
NULL
</Box>
)
}
})
Loading

0 comments on commit 69a359f

Please sign in to comment.