Skip to content

feat: support displayComma for showing comma #509

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 4 commits into from
Aug 26, 2024
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
13 changes: 6 additions & 7 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ on:
branches:
- main
jobs:
release-please:
release:
name: 'Release Please'
runs-on: ubuntu-latest
outputs:
releases_created: ${{ steps.release.outputs.releases_created }}
steps:
- uses: google-github-actions/release-please-action@v4
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{secrets.GITHUB_TOKEN}}
publish-json-viewer:
publish:
name: 'Publish @textea/json-viewer'
needs: release-please
if: ${{ needs.release-please.outputs.releases_created }}
needs: release
if: needs.release.outputs.release_created
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions docs/pages/apis.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
| `quotesOnKeys` | `boolean` | `true` | Whether add quotes on keys. |
| `displayDataTypes` | `boolean` | `true` | Whether display data type labels. |
| `displaySize` | `boolean` \|<br />`(path, currentValue) => boolean` | `true` | Whether display the size of `Object`, `Array`, `Map` and `Set`. Provide a function to customize this behavior by returning a boolean based on the value and path. |
| `displayComma` | `boolean` | `true` | Whether display commas at the end of the line. |
| `highlightUpdates` | `boolean` | `true` | Whether to highlight updates. |

### Mapping from [`mac-s-g/react-json-view`](https://github.com/mac-s-g/react-json-view)
Expand Down
13 changes: 12 additions & 1 deletion docs/pages/full/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
const [src, setSrc] = useState(() => example)
const [displayDataTypes, setDisplayDataTypes] = useState(true)
const [displaySize, setDisplaySize] = useState(true)
const [displayComma, setDisplayComma] = useState(false)

Check warning on line 209 in docs/pages/full/index.tsx

View check run for this annotation

Codecov / codecov/patch

docs/pages/full/index.tsx#L209

Added line #L209 was not covered by tests
const [editable, setEditable] = useState(true)
const [highlightUpdates, setHighlightUpdates] = useState(true)
useEffect(() => {
Expand Down Expand Up @@ -281,6 +282,15 @@
)}
label='DisplayObjectSize'
/>
<FormControlLabel
control={(
<Switch
checked={displayComma}
onChange={event => setDisplayComma(event.target.checked)}
/>
)}
label='DisplayComma'
/>

Check warning on line 293 in docs/pages/full/index.tsx

View check run for this annotation

Codecov / codecov/patch

docs/pages/full/index.tsx#L285-L293

Added lines #L285 - L293 were not covered by tests
<TextField
label='indentWidth'
value={indent}
Expand Down Expand Up @@ -343,6 +353,7 @@
enableDelete={true}
displayDataTypes={displayDataTypes}
displaySize={displaySize}
displayComma={displayComma}

Check warning on line 356 in docs/pages/full/index.tsx

View check run for this annotation

Codecov / codecov/patch

docs/pages/full/index.tsx#L356

Added line #L356 was not covered by tests
groupArraysAfterLength={groupArraysAfterLength}
keyRenderer={KeyRenderer}
valueTypes={[
Expand Down Expand Up @@ -376,7 +387,7 @@
)
}
sx={{
paddingLeft: 2
paddingX: 2

Check warning on line 390 in docs/pages/full/index.tsx

View check run for this annotation

Codecov / codecov/patch

docs/pages/full/index.tsx#L390

Added line #L390 was not covered by tests
}}
/>
</div>
Expand Down
5 changes: 5 additions & 0 deletions docs/pages/how-to/styling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ Different part of the dom structure will have class names like `data-object-star

This is the list of class names. 🧐

- `data-key`
- `data-key-pair`
- `data-key-key`
- `data-key-colon`
- `data-key-toggle-expanded`
- `data-key-toggle-collapsed`
- `data-type-label`
- `data-object`
- `data-object-start`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
"@typescript-eslint/parser": "^8.2.0",
"@vitejs/plugin-react": "^4.3.1",
"@vitest/coverage-v8": "^1.4.0",
"eslint": "^9.9.0",
"eslint": "^8.57.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "npm:eslint-plugin-i@^2.29.1",
"eslint-plugin-n": "^16.6.2",
Expand Down
29 changes: 25 additions & 4 deletions src/components/DataKeyPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type DataKeyPairProps = {
nestedIndex?: number
editable?: boolean
path: (string | number)[]
last: boolean
}

type IconBoxProps = ComponentProps<typeof Box>
Expand All @@ -44,7 +45,7 @@ const IconBox: FC<IconBoxProps> = (props) => (
)

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

const propsEditable = props.editable ?? undefined
Expand Down Expand Up @@ -79,6 +80,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
const keyColor = useTextColor()
const numberKeyColor = useJsonViewerStore(store => store.colorspace.base0C)
const highlightColor = useJsonViewerStore(store => store.colorspace.base0A)
const displayComma = useJsonViewerStore(store => store.displayComma)
const quotesOnKeys = useJsonViewerStore(store => store.quotesOnKeys)
const rootName = useJsonViewerStore(store => store.rootName)
const isRoot = root === value
Expand Down Expand Up @@ -342,6 +344,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
? (inspect
? (
<ExpandMoreIcon
className='data-key-toggle-expanded'
sx={{
fontSize: '.8rem',
'&:hover': { cursor: 'pointer' }
Expand All @@ -350,6 +353,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
)
: (
<ChevronRightIcon
className='data-key-toggle-collapsed'
sx={{
fontSize: '.8rem',
'&:hover': { cursor: 'pointer' }
Expand All @@ -373,7 +377,17 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
? <KeyRenderer {...downstreamProps} />
: nestedIndex === undefined && (
isNumberKey
? <Box component='span' style={{ color: numberKeyColor }}>{key}</Box>
? (
<Box
component='span'
style={{
color: numberKeyColor,
userSelect: isNumberKey ? 'none' : 'auto'
}}
>
{key}
</Box>
)
: quotesOnKeys ? <>&quot;{key}&quot;</> : <>{key}</>
)
)
Expand All @@ -382,13 +396,19 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
{
(
isRoot
? (rootName !== false && <DataBox sx={{ mr: 0.5 }}>:</DataBox>)
? (rootName !== false && (
<DataBox
className='data-key-colon'
sx={{ mr: 0.5 }}
>:</DataBox>
))
: nestedIndex === undefined && (
<DataBox
className='data-key-colon'
sx={{
mr: 0.5,
'.data-key-key:empty + &': { display: 'none' }
'.data-key-key:empty + &': { display: 'none' },
userSelect: isNumberKey ? 'none' : 'auto'
}}
>:</DataBox>
)
Expand Down Expand Up @@ -417,6 +437,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
)
}
{PostComponent && <PostComponent {...downstreamProps} />}
{!last && displayComma && <DataBox>,</DataBox>}
{(isHover && expandable && !inspect) && actionIcons}
{(isHover && !expandable) && actionIcons}
{(!isHover && editing) && actionIcons}
Expand Down
47 changes: 38 additions & 9 deletions src/components/DataTypes/Object.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function inspectMetadata (value: object) {
const PreObjectType: FC<DataItemProps<object>> = (props) => {
const metadataColor = useJsonViewerStore(store => store.colorspace.base04)
const textColor = useTextColor()
const isArray = useMemo(() => Array.isArray(props.value), [props.value])
const isArrayLike = useMemo(() => Array.isArray(props.value) || (props.value instanceof Set), [props.value])
const isEmptyValue = useMemo(() => getValueSize(props.value) === 0, [props.value])
const sizeOfValue = useMemo(() => inspectMetadata(props.value), [props.value])
const displaySize = useJsonViewerStore(store => store.displaySize)
Expand All @@ -46,7 +46,7 @@ const PreObjectType: FC<DataItemProps<object>> = (props) => {
letterSpacing: 0.5
}}
>
{isArray ? arrayLb : objectLb}
{isArrayLike ? arrayLb : objectLb}
{shouldDisplaySize && props.inspect && !isEmptyValue && (
<Box
component='span'
Expand All @@ -70,7 +70,14 @@ const PreObjectType: FC<DataItemProps<object>> = (props) => {
mx: 0.5
}}
/>
{isTrap}
<DataBox
sx={{
cursor: 'pointer',
userSelect: 'none'
}}
>
{isTrap}
</DataBox>
</>
)}
</Box>
Expand All @@ -80,7 +87,7 @@ const PreObjectType: FC<DataItemProps<object>> = (props) => {
const PostObjectType: FC<DataItemProps<object>> = (props) => {
const metadataColor = useJsonViewerStore(store => store.colorspace.base04)
const textColor = useTextColor()
const isArray = useMemo(() => Array.isArray(props.value), [props.value])
const isArrayLike = useMemo(() => Array.isArray(props.value) || (props.value instanceof Set), [props.value])
const isEmptyValue = useMemo(() => getValueSize(props.value) === 0, [props.value])
const sizeOfValue = useMemo(() => inspectMetadata(props.value), [props.value])
const displaySize = useJsonViewerStore(store => store.displaySize)
Expand All @@ -97,7 +104,7 @@ const PostObjectType: FC<DataItemProps<object>> = (props) => {
opacity: 0.8
}}
>
{isArray ? arrayRb : objectRb}
{isArrayLike ? arrayRb : objectRb}
{shouldDisplaySize && (isEmptyValue || !props.inspect)
? (
<Box
Expand Down Expand Up @@ -138,6 +145,8 @@ const ObjectType: FC<DataItemProps<object>> = (props) => {
if (iterator && !Array.isArray(value)) {
const elements = []
if (value instanceof Map) {
const lastIndex = value.size - 1
let index = 0
value.forEach((value, k) => {
// fixme: key might be a object, array, or any value for the `Map<any, any>`
const key = k.toString()
Expand All @@ -149,31 +158,41 @@ const ObjectType: FC<DataItemProps<object>> = (props) => {
value={value}
prevValue={props.prevValue instanceof Map ? props.prevValue.get(k) : undefined}
editable={false}
last={index === lastIndex}
/>
)
index++
})
} else {
// iterate with iterator func
const iterator = value[Symbol.iterator]()
let result = iterator.next()
let count = 0
while (!result.done) {
while (true) {
const nextResult = iterator.next()
elements.push(
<DataKeyPair
key={count}
path={[...props.path, `iterator:${count}`]}
value={result.value}
nestedIndex={count}
editable={false}
last={nextResult.done ?? false}
/>
)

if (nextResult.done) {
break
}

count++
result = iterator.next()
result = nextResult
}
}
return elements
}
if (Array.isArray(value)) {
const lastIndex = value.length - 1
// unknown[]
if (value.length <= groupArraysAfterLength) {
const elements = value.slice(0, displayLength).map((value, _index) => {
Expand All @@ -185,6 +204,7 @@ const ObjectType: FC<DataItemProps<object>> = (props) => {
path={path}
value={value}
prevValue={Array.isArray(props.prevValue) ? props.prevValue[index] : undefined}
last={_index === lastIndex}
/>
)
})
Expand Down Expand Up @@ -213,6 +233,7 @@ const ObjectType: FC<DataItemProps<object>> = (props) => {
const elements: unknown[][] = segmentArray(value, groupArraysAfterLength)
const prevElements = Array.isArray(props.prevValue) ? segmentArray(props.prevValue, groupArraysAfterLength) : undefined

const elementsLastIndex = elements.length - 1
return elements.map((list, index) => {
return (
<DataKeyPair
Expand All @@ -221,6 +242,7 @@ const ObjectType: FC<DataItemProps<object>> = (props) => {
value={list}
nestedIndex={index}
prevValue={prevElements?.[index]}
last={index === elementsLastIndex}
/>
)
})
Expand All @@ -232,10 +254,17 @@ const ObjectType: FC<DataItemProps<object>> = (props) => {
? entries.sort(([a], [b]) => a.localeCompare(b))
: entries.sort(([a], [b]) => objectSortKeys(a, b))
}
const elements = entries.slice(0, displayLength).map(([key, value]) => {
const lastIndex = entries.length - 1
const elements = entries.slice(0, displayLength).map(([key, value], index) => {
const path = [...props.path, key]
return (
<DataKeyPair key={key} path={path} value={value} prevValue={(props.prevValue as any)?.[key]} />
<DataKeyPair
key={key}
path={path}
value={value}
prevValue={(props.prevValue as any)?.[key]}
last={index === lastIndex}
/>
)
})
if (entries.length > displayLength) {
Expand Down
3 changes: 3 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ const JsonViewerInner: FC<JsonViewerProps> = (props) => {
useSetIfNotUndefinedEffect('onDelete', props.onDelete)
useSetIfNotUndefinedEffect('maxDisplayLength', props.maxDisplayLength)
useSetIfNotUndefinedEffect('groupArraysAfterLength', props.groupArraysAfterLength)
useSetIfNotUndefinedEffect('quotesOnKeys', props.quotesOnKeys)
useSetIfNotUndefinedEffect('displayDataTypes', props.displayDataTypes)
useSetIfNotUndefinedEffect('displaySize', props.displaySize)
useSetIfNotUndefinedEffect('displayComma', props.displayComma)
useSetIfNotUndefinedEffect('highlightUpdates', props.highlightUpdates)
useEffect(() => {
if (props.theme === 'light') {
Expand Down Expand Up @@ -124,6 +126,7 @@ const JsonViewerInner: FC<JsonViewerProps> = (props) => {
value={value}
prevValue={prevValue}
path={emptyPath}
last={true}
/>
</Paper>
)
Expand Down
2 changes: 2 additions & 0 deletions src/stores/JsonViewerStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export type JsonViewerState<T = unknown> = {
quotesOnKeys: boolean
displayDataTypes: boolean
displaySize: boolean | ((path: Path, value: unknown) => boolean)
displayComma: boolean
highlightUpdates: boolean

inspectCache: Record<string, boolean>
Expand Down Expand Up @@ -79,6 +80,7 @@ export const createJsonViewerStore = <T = unknown> (props: JsonViewerProps<T>) =
quotesOnKeys: props.quotesOnKeys ?? true,
displayDataTypes: props.displayDataTypes ?? true,
displaySize: props.displaySize ?? true,
displayComma: props.displayComma ?? false,
highlightUpdates: props.highlightUpdates ?? false,

// internal state
Expand Down
7 changes: 7 additions & 0 deletions src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,13 @@ export type JsonViewerProps<T = unknown> = {
*/
displaySize?: boolean | ((path: Path, value: unknown) => boolean)

/**
* Whether display comma at the end of items. Just like valid JSON.
*
* @default false
*/
displayComma?: boolean

/**
* Whether to highlight updates.
*
Expand Down
Loading