json-tree-view-vue3
Version:
JSON tree rendering Vue3 component
1 lines • 17.3 kB
Source Map (JSON)
{"version":3,"file":"json-tree-view-vue3.umd.cjs","sources":["../src/components/utils.ts","../src/components/JsonTreeViewItem.vue","../src/components/JsonTreeView.vue"],"sourcesContent":["import type { PrimitiveTypes } from './JsonTreeViewItem.vue'\n\nexport const isArray = (value: unknown): value is unknown[] => Array.isArray(value)\n\nexport const isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nexport const isPrimitive = (value: unknown): value is PrimitiveTypes =>\n value === null ||\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n\nexport const getValueColorVariable = (value: PrimitiveTypes) => {\n if (value === null) {\n return 'var(--jtv-null-color)'\n }\n\n const typeColorMap: Record<string, string> = {\n string: 'var(--jtv-string-color)',\n number: 'var(--jtv-number-color)',\n boolean: 'var(--jtv-boolean-color)'\n }\n\n return typeColorMap[typeof value] ?? 'var(--jtv-valueKey-color)'\n}\n\nexport const formatKey = (key: string) => {\n const numericKey = Number(key)\n return Number.isNaN(numericKey) ? `\"${key}\":` : `${key}\":`\n}\n\nexport const getLengthString = (length: number, isArray: boolean) => {\n const unit = isArray ? 'element' : 'property'\n const pluralUnit = isArray ? 'elements' : 'properties'\n return length === 1 ? `${length} ${unit}` : `${length} ${pluralUnit}`\n}\n\nexport const buildPath = (\n basePath: string,\n key: string,\n includeKey: boolean,\n isArrayElement = false\n) => {\n if (!includeKey) return basePath\n\n if (isArrayElement) {\n return `${basePath}${key}[${key}].`\n }\n\n return `${basePath}${key}.`\n}\n\nexport const buildValuePath = (basePath: string, key: string, includeKey: boolean) => {\n if (!includeKey) {\n return basePath.slice(0, -1)\n }\n return `${basePath}${key}`\n}\n","<script lang=\"ts\">\nexport enum ItemType {\n OBJECT,\n ARRAY,\n VALUE\n}\n\nexport type PrimitiveTypes = string | number | boolean | null\n\nexport interface SelectedData {\n key: string\n value: PrimitiveTypes\n path: string\n}\n\nexport type ItemData = {\n key: string\n type: ItemType\n path: string\n depth: number\n length?: number\n children?: ItemData[]\n value?: PrimitiveTypes\n}\n\nexport type Props = {\n data: ItemData\n maxDepth?: number\n canSelect?: boolean\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { getValueColorVariable, formatKey, getLengthString } from './utils'\n\ndefineOptions({\n name: 'JsonTreeViewItem'\n})\n\nconst { data, maxDepth = 1, canSelect = false } = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'selected', value: SelectedData): void\n}>()\n\nconst isOpen = ref(data.depth < maxDepth)\n\nconst toggleOpen = () => {\n isOpen.value = !isOpen.value\n}\n\nconst onClick = (itemData: ItemData) => {\n const selectedData: SelectedData = {\n key: itemData.key,\n value: itemData.value!,\n path: itemData.path\n }\n emit('selected', selectedData)\n}\n\nconst onSelected = (selectedData: SelectedData) => emit('selected', selectedData)\n\nconst chevronClasses = computed(() => ({\n 'chevron-arrow': true,\n opened: isOpen.value\n}))\n\nconst valueClasses = computed(() => ({\n 'value-key': true,\n 'can-select': canSelect\n}))\n\nconst lengthString = computed(() => {\n const { length, type } = data\n if (length === undefined) return ''\n\n return getLengthString(length, type === ItemType.ARRAY)\n})\n\nconst dataValue = computed(() => JSON.stringify(data.value))\n\nconst getItemKey = (item: ItemData) => formatKey(item.key)\n\nconst getValueColor = (value: PrimitiveTypes) => getValueColorVariable(value)\n</script>\n\n<template>\n <div class=\"json-view-item\">\n <!-- Container/Collection types (Object/Array) -->\n <template v-if=\"data.type === ItemType.OBJECT || data.type === ItemType.ARRAY\">\n <button class=\"data-key\" type=\"button\" :aria-expanded=\"isOpen\" @click.stop=\"toggleOpen\">\n <div :class=\"chevronClasses\" aria-hidden=\"true\" />\n <span>{{ data.key }}:</span>\n <span class=\"properties\">{{ lengthString }}</span>\n </button>\n\n <Transition name=\"expand\">\n <div v-show=\"isOpen\">\n <JsonTreeViewItem\n v-for=\"child in data.children\"\n :key=\"getItemKey(child)\"\n :data=\"child\"\n :max-depth=\"maxDepth\"\n :can-select=\"canSelect\"\n @selected=\"onSelected\"\n />\n </div>\n </Transition>\n </template>\n\n <!-- Primitive value type -->\n <component\n :is=\"canSelect ? 'button' : 'div'\"\n v-if=\"data.type === ItemType.VALUE\"\n :class=\"valueClasses\"\n :type=\"canSelect ? 'button' : null\"\n :tabindex=\"canSelect ? 0 : null\"\n @click=\"canSelect ? onClick(data) : null\"\n @keyup.enter=\"canSelect ? onClick(data) : null\"\n @keyup.space.prevent=\"canSelect ? onClick(data) : null\"\n >\n <span class=\"value-key\">{{ data.key }}:</span>\n <span :style=\"{ color: getValueColor(data.value as PrimitiveTypes) }\">\n {{ dataValue }}\n </span>\n </component>\n </div>\n</template>\n\n<style lang=\"scss\">\n/* Base item spacing */\n.json-view-item:where(:not(.root-item)) {\n margin-inline-start: 15px;\n}\n\n/* Value key styling */\n.value-key {\n /* Typography */\n color: var(--jtv-valueKey-color);\n font-weight: 600;\n white-space: nowrap;\n\n /* Layout */\n display: inline-block;\n padding-block: 5px;\n padding-inline: 10px 5px;\n margin-inline-start: 10px;\n border-radius: 2px;\n\n /* Interactive state */\n &.can-select {\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:is(:hover, :focus-visible) {\n background-color: oklch(0 0 0 / 0.08);\n }\n\n &:focus-visible {\n outline: 2px solid var(--jtv-hover-color);\n outline-offset: 2px;\n }\n }\n}\n\n/* Data key button styling */\n.data-key {\n /* Reset button styles */\n all: unset;\n box-sizing: border-box;\n\n /* Typography */\n color: var(--jtv-key-color);\n font-weight: 600;\n white-space: nowrap;\n\n /* Layout */\n display: flex;\n align-items: center;\n inline-size: 100%;\n padding-block: 5px;\n padding-inline: 5px;\n border-radius: 2px;\n\n /* Interactive */\n cursor: pointer;\n transition: background-color 0.2s ease;\n\n &:is(:hover, :focus-visible) {\n background-color: var(--jtv-hover-color);\n }\n\n &:focus-visible {\n outline: 2px solid var(--jtv-hover-color);\n outline-offset: 2px;\n }\n\n /* Child element - properties count */\n .properties {\n font-weight: 300;\n opacity: 0.9;\n margin-inline-start: calc(var(--jtv-spacing-unit, 4px) * 1);\n user-select: none;\n }\n}\n\n/* Chevron arrow indicator */\n.chevron-arrow {\n /* Layout */\n flex-shrink: 0;\n inline-size: var(--jtv-arrow-size);\n block-size: var(--jtv-arrow-size);\n margin-inline: 5px 20px;\n\n /* Visual */\n border-inline-end: 2px solid var(--jtv-arrow-color);\n border-block-end: 2px solid var(--jtv-arrow-color);\n transform: rotate(-45deg);\n transition: transform 0.2s ease;\n\n &.opened {\n margin-block-start: -3px;\n transform: rotate(45deg);\n }\n}\n\n/* Expand/Collapse transition */\n.expand-enter-active,\n.expand-leave-active {\n transition:\n opacity 0.2s ease,\n max-block-size 0.2s ease;\n overflow: hidden;\n}\n\n.expand-enter-from,\n.expand-leave-to {\n opacity: 0;\n max-block-size: 0;\n}\n\n.expand-enter-to,\n.expand-leave-from {\n opacity: 1;\n max-block-size: 1000px; /* Arbitrary large value */\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .value-key.can-select,\n .data-key,\n .chevron-arrow,\n .expand-enter-active,\n .expand-leave-active {\n transition: none;\n }\n}\n</style>\n","<script lang=\"ts\">\nexport type ColorScheme = 'light' | 'dark'\n\nexport type Props = {\n json: string\n rootKey?: string\n maxDepth?: number\n colorScheme?: ColorScheme\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport JsonTreeViewItem, {\n type ItemData,\n ItemType,\n type PrimitiveTypes,\n type SelectedData\n} from './JsonTreeViewItem.vue'\nimport { isArray, isObject, buildPath, buildValuePath } from './utils'\n\ndefineOptions({\n name: 'JsonTreeView'\n})\n\nconst { json, rootKey = '/', maxDepth = 1, colorScheme = 'light' } = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'selected', value: SelectedData): void\n}>()\n\nconst onSelected = (selectedData: SelectedData) => emit('selected', selectedData)\n\nconst buildArrayItem = (\n key: string,\n array: unknown[],\n depth: number,\n path: string,\n includeKey: boolean\n) => {\n const children = array.map((element, index) =>\n buildItemData(\n index.toString(),\n element,\n depth + 1,\n buildPath(path, key, includeKey, true),\n false\n )\n )\n\n return {\n key,\n type: ItemType.ARRAY,\n depth,\n path,\n length: children.length,\n children\n }\n}\n\nconst buildObjectItem = (\n key: string,\n obj: Record<string, unknown>,\n depth: number,\n path: string,\n includeKey: boolean\n) => {\n const children = Object.entries(obj).map(([childKey, childValue]) =>\n buildItemData(childKey, childValue, depth + 1, buildPath(path, key, includeKey), true)\n )\n\n return {\n key,\n type: ItemType.OBJECT,\n depth,\n path,\n length: children.length,\n children\n }\n}\n\nconst buildValueItem = (\n key: string,\n value: PrimitiveTypes,\n depth: number,\n path: string,\n includeKey: boolean\n) => ({\n key,\n type: ItemType.VALUE,\n path: buildValuePath(path, key, includeKey),\n depth,\n value\n})\n\nconst buildItemData = (\n key: string,\n value: unknown,\n depth: number,\n path: string,\n includeKey: boolean\n): ItemData => {\n if (isArray(value)) {\n return buildArrayItem(key, value, depth, path, includeKey)\n }\n\n if (isObject(value)) {\n return buildObjectItem(key, value, depth, path, includeKey)\n }\n\n return buildValueItem(key, value as PrimitiveTypes, depth, path, includeKey)\n}\n\nconst parseJsonToItemData = (jsonStr: string, key: string): ItemData => {\n try {\n const data = JSON.parse(jsonStr)\n\n if (isObject(data) || isArray(data)) {\n return buildItemData(key, data, 0, '', true)\n }\n\n return buildValueItem(key, data as PrimitiveTypes, 0, '', true)\n } catch {\n return buildValueItem(key, jsonStr, 0, '', true)\n }\n}\n\nconst parsed = computed(() => parseJsonToItemData(json, rootKey))\n</script>\n\n<template>\n <JsonTreeViewItem\n class=\"root-item\"\n :class=\"{ dark: colorScheme === 'dark' }\"\n :data=\"parsed\"\n :max-depth=\"maxDepth\"\n @selected=\"onSelected\"\n />\n</template>\n\n<style lang=\"scss\" scoped>\n.root-item {\n /* Color palette - Light theme */\n --jtv-key-color: oklch(0.55 0.15 240); /* #0977e6 */\n --jtv-valueKey-color: oklch(0.25 0.05 210); /* #073642 */\n --jtv-string-color: oklch(0.6 0.12 230); /* #268bd2 */\n --jtv-number-color: oklch(0.65 0.1 180); /* #2aa198 */\n --jtv-boolean-color: oklch(0.55 0.15 40); /* #cb4b16 */\n --jtv-null-color: oklch(0.55 0.12 280); /* #6c71c4 */\n\n /* UI colors */\n --jtv-arrow-color: oklch(0.3 0 0); /* #444 */\n --jtv-hover-color: oklch(0 0 0 / 0.1); /* rgba(0, 0, 0, 0.1) */\n\n /* Dimensions */\n --jtv-arrow-size: 6px;\n --jtv-spacing-unit: 4px;\n\n /* Layout */\n display: block;\n inline-size: 100%;\n block-size: auto;\n margin-inline-start: 0;\n\n &.dark {\n /* Color palette - Dark theme */\n --jtv-key-color: oklch(0.75 0.1 220); /* #80d8ff */\n --jtv-valueKey-color: oklch(0.95 0.02 90); /* #fdf6e3 */\n --jtv-hover-color: oklch(1 0 0 / 0.1); /* rgba(255, 255, 255, 0.1) */\n --jtv-arrow-color: oklch(0.95 0.02 90); /* #fdf6e3 */\n }\n}\n</style>\n"],"names":["isArray","value","isObject","getValueColorVariable","formatKey","key","numericKey","getLengthString","length","buildPath","basePath","includeKey","isArrayElement","buildValuePath","ItemType","emit","__emit","isOpen","ref","__props","toggleOpen","onClick","itemData","selectedData","onSelected","chevronClasses","computed","valueClasses","lengthString","type","dataValue","getItemKey","item","getValueColor","_openBlock","_createElementBlock","_hoisted_1","_Fragment","_createElementVNode","_toDisplayString","_hoisted_3","_createVNode","_Transition","_renderList","child","_createBlock","_component_JsonTreeViewItem","_resolveDynamicComponent","_cache","$event","_hoisted_4","_normalizeStyle","buildArrayItem","array","depth","path","children","element","index","buildItemData","buildObjectItem","obj","childKey","childValue","buildValueItem","parseJsonToItemData","jsonStr","data","parsed","JsonTreeViewItem","_normalizeClass"],"mappings":"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"}