sprintify-ui 0.6.82 → 0.6.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sprintify-ui.es.js +8375 -8383
- package/dist/style.css +1 -1
- package/dist/types/components/BaseDataIteratorSectionColumns.vue.d.ts +2 -32
- package/dist/types/components/BaseDataTableTemplate.vue.d.ts +7 -13
- package/dist/types/components/BaseJsonReader.vue.d.ts +40 -0
- package/package.json +1 -1
- package/src/assets/base-json-reader.css +32 -0
- package/src/assets/main.css +1 -0
- package/src/components/BaseDataTableTemplate.vue +36 -44
- package/src/components/BaseJsonReader.stories.js +128 -0
- package/src/components/BaseJsonReader.vue +199 -0
- package/src/components/BaseScrollColumn.vue +0 -2
- package/src/components/BaseTimePicker.vue +0 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.base-json-reader {
|
|
2
|
+
ul {
|
|
3
|
+
list-style-type: disc !important;
|
|
4
|
+
padding-left: 20px !important;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
li {
|
|
8
|
+
margin-bottom: 5px !important;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.chevron {
|
|
12
|
+
cursor: pointer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.heroicons--chevron-right-16-solid,
|
|
16
|
+
.heroicons--chevron-down-16-solid {
|
|
17
|
+
display: inline-block;
|
|
18
|
+
background-color: currentColor;
|
|
19
|
+
-webkit-mask-image: var(--svg);
|
|
20
|
+
mask-image: var(--svg);
|
|
21
|
+
-webkit-mask-repeat: no-repeat;
|
|
22
|
+
mask-repeat: no-repeat;
|
|
23
|
+
-webkit-mask-size: 100% 100%;
|
|
24
|
+
mask-size: 100% 100%;
|
|
25
|
+
}
|
|
26
|
+
.heroicons--chevron-right-16-solid {
|
|
27
|
+
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8L6.22 5.28a.75.75 0 0 1 0-1.06' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
28
|
+
}
|
|
29
|
+
.heroicons--chevron-down-16-solid {
|
|
30
|
+
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/assets/main.css
CHANGED
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
<tbody class="bg-white">
|
|
126
126
|
<template
|
|
127
127
|
v-for="(row, index) in data"
|
|
128
|
-
:key="
|
|
128
|
+
:key="getRowKey(row)"
|
|
129
129
|
>
|
|
130
130
|
<tr class="item-row">
|
|
131
131
|
<td
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
<transition :name="detailTransition">
|
|
221
221
|
<tr
|
|
222
222
|
v-if="isActiveDetailRow(row)"
|
|
223
|
-
:key="
|
|
223
|
+
:key="getRowKey(row) + 'detail'"
|
|
224
224
|
>
|
|
225
225
|
<td
|
|
226
226
|
:colspan="columnCount"
|
|
@@ -272,27 +272,26 @@
|
|
|
272
272
|
</div>
|
|
273
273
|
</template>
|
|
274
274
|
|
|
275
|
-
<script lang="ts">
|
|
276
|
-
export default {
|
|
277
|
-
name: 'BaseDataTableTemplate',
|
|
278
|
-
inheritAttrs: false,
|
|
279
|
-
};
|
|
280
|
-
</script>
|
|
281
|
-
|
|
282
275
|
<script lang="ts" setup>
|
|
283
|
-
import { PropType, ref } from 'vue';
|
|
276
|
+
import { PropType, StyleValue, ref } from 'vue';
|
|
284
277
|
import { BaseTableColumn, Row } from '@/types';
|
|
285
278
|
import SlotComponent from './SlotComponent';
|
|
286
279
|
import { useResizeObserver, useScroll } from '@vueuse/core';
|
|
287
280
|
import { debounce, isArray } from 'lodash';
|
|
288
281
|
import BaseSpinnerLarge from '../svg/BaseSpinnerLarge.vue';
|
|
289
282
|
import { Size } from '@/utils/sizes';
|
|
283
|
+
import objectHash from 'object-hash';
|
|
290
284
|
|
|
291
285
|
const checkboxStyle =
|
|
292
286
|
'disabled:bg-slate-100 group-hover:shadow-md disabled:border-slate-300 disabled:cursor-not-allowed duration-300 cursor-pointer focus:ring-blue-300 border border-slate-300 shadow h-[18px] w-[18px] rounded';
|
|
293
287
|
const DETAIL_ROW_WIDTH = 36;
|
|
294
288
|
const CHECK_ROW_WIDTH = 36;
|
|
295
289
|
|
|
290
|
+
defineOptions({
|
|
291
|
+
name: 'BaseDataTableTemplate',
|
|
292
|
+
inheritAttrs: false,
|
|
293
|
+
});
|
|
294
|
+
|
|
296
295
|
provide('table', getCurrentInstance());
|
|
297
296
|
|
|
298
297
|
const props = defineProps({
|
|
@@ -356,11 +355,6 @@ const props = defineProps({
|
|
|
356
355
|
type: Function,
|
|
357
356
|
default: () => true,
|
|
358
357
|
},
|
|
359
|
-
/** Use a unique key of your data Object when use detailed or opened detailed. (id recommended) */
|
|
360
|
-
rowKey: {
|
|
361
|
-
type: String,
|
|
362
|
-
default: 'id',
|
|
363
|
-
},
|
|
364
358
|
/* Transition name to use when toggling row details. */
|
|
365
359
|
detailTransition: {
|
|
366
360
|
type: String,
|
|
@@ -388,7 +382,7 @@ const emit = defineEmits([
|
|
|
388
382
|
'cell-click',
|
|
389
383
|
]);
|
|
390
384
|
|
|
391
|
-
const visibleDetailRows = ref<
|
|
385
|
+
const visibleDetailRows = ref<string[]>([]);
|
|
392
386
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
|
393
387
|
const newCheckedRows = ref<Row[]>([...props.checkedRows]);
|
|
394
388
|
const lastCheckedRowIndex = ref<number | null>(null);
|
|
@@ -521,10 +515,13 @@ function sort(column: BaseTableColumn, updatingData = false, event = null) {
|
|
|
521
515
|
* Check if the row is checked (is added to the array).
|
|
522
516
|
*/
|
|
523
517
|
function isRowChecked(row: Row): boolean {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
518
|
+
const found = newCheckedRows.value.find((r) => {
|
|
519
|
+
const key1 = getRowKey(r);
|
|
520
|
+
const key2 = getRowKey(row);
|
|
521
|
+
return key1 == key2
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
return found !== undefined;
|
|
528
525
|
}
|
|
529
526
|
|
|
530
527
|
/**
|
|
@@ -555,9 +552,13 @@ const isAllChecked = computed(() => {
|
|
|
555
552
|
});
|
|
556
553
|
|
|
557
554
|
function getCheckedRowIndex(row: Row) {
|
|
558
|
-
|
|
559
|
-
(r)
|
|
560
|
-
|
|
555
|
+
const foundIndex = newCheckedRows.value.findIndex((r) => {
|
|
556
|
+
const key1 = getRowKey(r);
|
|
557
|
+
const key2 = getRowKey(row);
|
|
558
|
+
return key1 == key2
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
return foundIndex;
|
|
561
562
|
}
|
|
562
563
|
|
|
563
564
|
/**
|
|
@@ -668,36 +669,27 @@ function toggleDetails(row: Row) {
|
|
|
668
669
|
}
|
|
669
670
|
|
|
670
671
|
function openDetailRow(row: Row) {
|
|
671
|
-
const
|
|
672
|
-
visibleDetailRows.value.push(
|
|
672
|
+
const key = getRowKey(row);
|
|
673
|
+
visibleDetailRows.value.push(key);
|
|
673
674
|
}
|
|
674
675
|
|
|
675
676
|
function closeDetailRow(row: Row) {
|
|
676
|
-
const
|
|
677
|
-
const i = visibleDetailRows.value.indexOf(
|
|
677
|
+
const key = getRowKey(row);
|
|
678
|
+
const i = visibleDetailRows.value.indexOf(key);
|
|
678
679
|
if (i >= 0) {
|
|
679
680
|
visibleDetailRows.value.splice(i, 1);
|
|
680
681
|
}
|
|
681
682
|
}
|
|
682
683
|
|
|
683
684
|
function isVisibleDetailRow(row: Row) {
|
|
684
|
-
const
|
|
685
|
-
return visibleDetailRows.value.indexOf(
|
|
685
|
+
const key = getRowKey(row);
|
|
686
|
+
return visibleDetailRows.value.indexOf(key) >= 0;
|
|
686
687
|
}
|
|
687
688
|
|
|
688
689
|
function isActiveDetailRow(row: Row) {
|
|
689
690
|
return props.detailed && isVisibleDetailRow(row);
|
|
690
691
|
}
|
|
691
692
|
|
|
692
|
-
/**
|
|
693
|
-
* When the rowKey is defined we use the object[rowKey] as index.
|
|
694
|
-
* If not, use the object reference by default.
|
|
695
|
-
*/
|
|
696
|
-
function getDetailedIndex(row: Row) {
|
|
697
|
-
const key = props.rowKey;
|
|
698
|
-
return !key.length || !row ? row : row[key];
|
|
699
|
-
}
|
|
700
|
-
|
|
701
693
|
/**
|
|
702
694
|
* Update sort state
|
|
703
695
|
*/
|
|
@@ -759,7 +751,7 @@ function removeColumn(column: BaseTableColumn) {
|
|
|
759
751
|
|
|
760
752
|
const borderClasses = 'border-b border-slate-200';
|
|
761
753
|
|
|
762
|
-
function borderBottomClasses(index: number, row:
|
|
754
|
+
function borderBottomClasses(index: number, row: Row): string {
|
|
763
755
|
if (index < props.data.length - 1) {
|
|
764
756
|
return borderClasses;
|
|
765
757
|
}
|
|
@@ -795,7 +787,7 @@ function nextSequence() {
|
|
|
795
787
|
return sequence.value++;
|
|
796
788
|
}
|
|
797
789
|
|
|
798
|
-
function
|
|
790
|
+
function getRowKey(row: Row): string {
|
|
799
791
|
if (row.id) {
|
|
800
792
|
return row.id;
|
|
801
793
|
}
|
|
@@ -805,7 +797,7 @@ function getRowIndex(row: Row, index: number): string {
|
|
|
805
797
|
if (row.uuid) {
|
|
806
798
|
return row.uuid;
|
|
807
799
|
}
|
|
808
|
-
return
|
|
800
|
+
return objectHash(row);
|
|
809
801
|
}
|
|
810
802
|
|
|
811
803
|
// Sticky styles
|
|
@@ -825,7 +817,7 @@ function zIndex(th: boolean) {
|
|
|
825
817
|
return 1;
|
|
826
818
|
}
|
|
827
819
|
|
|
828
|
-
function detailsStyles(th: boolean):
|
|
820
|
+
function detailsStyles(th: boolean): StyleValue {
|
|
829
821
|
if (props.detailed) {
|
|
830
822
|
return {
|
|
831
823
|
zIndex: zIndex(th) + 1,
|
|
@@ -839,7 +831,7 @@ function detailsStyles(th: boolean): any {
|
|
|
839
831
|
return {};
|
|
840
832
|
}
|
|
841
833
|
|
|
842
|
-
function checkStyles(th: boolean):
|
|
834
|
+
function checkStyles(th: boolean): StyleValue {
|
|
843
835
|
if (props.checkable) {
|
|
844
836
|
return {
|
|
845
837
|
zIndex: zIndex(th) + 1,
|
|
@@ -853,7 +845,7 @@ function checkStyles(th: boolean): any {
|
|
|
853
845
|
return {};
|
|
854
846
|
}
|
|
855
847
|
|
|
856
|
-
function firstColStyles(th: boolean):
|
|
848
|
+
function firstColStyles(th: boolean): StyleValue {
|
|
857
849
|
let left = 0;
|
|
858
850
|
if (props.checkable) {
|
|
859
851
|
left += CHECK_ROW_WIDTH;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import BaseJsonReader from './BaseJsonReader.vue';
|
|
2
|
+
import ShowValue from '@/../.storybook/components/ShowValue.vue';
|
|
3
|
+
|
|
4
|
+
const sizes = ['xs', 'sm', 'md'];
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Components/BaseJsonReader',
|
|
8
|
+
component: BaseJsonReader,
|
|
9
|
+
argTypes: {
|
|
10
|
+
size: {
|
|
11
|
+
control: { type: 'select' },
|
|
12
|
+
options: sizes,
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const Template = (args) => ({
|
|
18
|
+
components: { BaseJsonReader, ShowValue },
|
|
19
|
+
setup() {
|
|
20
|
+
const object = {
|
|
21
|
+
"user": {
|
|
22
|
+
"name": "John Doe",
|
|
23
|
+
"email": "john@witify.io",
|
|
24
|
+
"permissions": [
|
|
25
|
+
"read",
|
|
26
|
+
"create",
|
|
27
|
+
"delete"
|
|
28
|
+
],
|
|
29
|
+
comments: [
|
|
30
|
+
{
|
|
31
|
+
comment: "First comment",
|
|
32
|
+
replies: [
|
|
33
|
+
{
|
|
34
|
+
comment: "sub-comment 1 for comment 1",
|
|
35
|
+
replies: [
|
|
36
|
+
{
|
|
37
|
+
comment: "sub-sub-comment 1",
|
|
38
|
+
replies: [
|
|
39
|
+
{
|
|
40
|
+
comment: "sub-sub-sub-comment 1",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
comment: {
|
|
44
|
+
name: "sub-sub-sub-comment 2",
|
|
45
|
+
desc: "test desc"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
comment: {
|
|
50
|
+
name: "sub-sub-sub-comment 3",
|
|
51
|
+
desc: "test desc2"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{ comment: "sub-sub-comment 2" },
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{ comment: "sub-comment 2 for comment 1" },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
comment: "Second comment",
|
|
65
|
+
replies: [
|
|
66
|
+
{
|
|
67
|
+
comment: "sub-comment 1 for comment 2",
|
|
68
|
+
replies: [
|
|
69
|
+
{ comment: "sub-sub-comment 1" },
|
|
70
|
+
{ comment: "sub-sub-comment 2" },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{ comment: "sub-comment 2 for comment 2" },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
"category": {
|
|
78
|
+
"id": 1,
|
|
79
|
+
"name": "Other"
|
|
80
|
+
},
|
|
81
|
+
"tags": {
|
|
82
|
+
"id": [
|
|
83
|
+
"create",
|
|
84
|
+
"delete"
|
|
85
|
+
],
|
|
86
|
+
"name": {
|
|
87
|
+
"id": {
|
|
88
|
+
"read": {
|
|
89
|
+
"id": {
|
|
90
|
+
"create": {
|
|
91
|
+
"id": {
|
|
92
|
+
"delete": {
|
|
93
|
+
"id": {
|
|
94
|
+
"update": {
|
|
95
|
+
"id": {
|
|
96
|
+
"name": "Read"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"name": "Read"
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"foo": "bar",
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const value = ref(object);
|
|
114
|
+
return { value, args };
|
|
115
|
+
},
|
|
116
|
+
template: `
|
|
117
|
+
<BaseJsonReader v-model="value" v-bind="args">
|
|
118
|
+
</BaseJsonReader>
|
|
119
|
+
<ShowValue :value="value" />
|
|
120
|
+
`,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export const Demo = Template.bind({});
|
|
124
|
+
|
|
125
|
+
export const VariantCollapse = Template.bind({});
|
|
126
|
+
VariantCollapse.args = {
|
|
127
|
+
variant: 'collapse',
|
|
128
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="base-json-reader"
|
|
4
|
+
:class="classes"
|
|
5
|
+
@click="handleClick"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
v-html="renderObject(modelValue)"
|
|
9
|
+
/>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script lang="ts" setup>
|
|
14
|
+
import { Size, sizes } from '@/utils/sizes';
|
|
15
|
+
import { twMerge } from 'tailwind-merge';
|
|
16
|
+
import { defineProps } from 'vue';
|
|
17
|
+
|
|
18
|
+
interface JsonData {
|
|
19
|
+
[key: string]: string | number | null | undefined | JsonData[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const props = withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
modelValue: JsonData;
|
|
25
|
+
size?: Size;
|
|
26
|
+
variant?: 'list' | 'collapse';
|
|
27
|
+
}>(),
|
|
28
|
+
{
|
|
29
|
+
size: 'sm',
|
|
30
|
+
variant: 'list',
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const classes = computed(() => {
|
|
35
|
+
const base = 'bg-slate-100 p-2 rounded-md text-sm text-slate-800';
|
|
36
|
+
const sizeConfig = sizes[props.size];
|
|
37
|
+
|
|
38
|
+
return twMerge(
|
|
39
|
+
base,
|
|
40
|
+
sizeConfig.fontSize,
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const classSizeChevron = computed(() => {
|
|
45
|
+
const chevronSizes = {
|
|
46
|
+
xs: {
|
|
47
|
+
width: 'w-[1em]',
|
|
48
|
+
height: 'h-[1em]',
|
|
49
|
+
marginBottom: 'mb-[-2.5px]'
|
|
50
|
+
},
|
|
51
|
+
sm: {
|
|
52
|
+
width: 'w-[1.1em]',
|
|
53
|
+
height: 'h-[1.1em]',
|
|
54
|
+
marginBottom: 'mb-[-3.5px]'
|
|
55
|
+
},
|
|
56
|
+
md: {
|
|
57
|
+
width: 'w-[1.2em]',
|
|
58
|
+
height: 'h-[1.2em]',
|
|
59
|
+
marginBottom: 'mb-[-5px]'
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const sizeConfig = chevronSizes[props.size];
|
|
64
|
+
|
|
65
|
+
return twMerge(
|
|
66
|
+
sizeConfig.height,
|
|
67
|
+
sizeConfig.width,
|
|
68
|
+
sizeConfig.marginBottom
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const expandedKeys = ref<string[]>([]);
|
|
73
|
+
|
|
74
|
+
function toggleExpand(key: string) {
|
|
75
|
+
if (isExpanded(key)) {
|
|
76
|
+
expandedKeys.value = expandedKeys.value.filter(k => k !== key);
|
|
77
|
+
} else {
|
|
78
|
+
expandedKeys.value.push(key);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isExpanded(key: string): boolean {
|
|
83
|
+
return expandedKeys.value.includes(key);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Expand when created
|
|
87
|
+
function recursiveExpand(data: JsonData | JsonData[] , parentKey = '') {
|
|
88
|
+
if (props.variant !== 'collapse') {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (Array.isArray(data)) {
|
|
93
|
+
data.forEach((item, index) => {
|
|
94
|
+
const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
|
|
95
|
+
expandedKeys.value.push(uniqueKey);
|
|
96
|
+
recursiveExpand(item, uniqueKey);
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
Object.entries(data).forEach(([key, value], index) => {
|
|
100
|
+
const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
|
|
101
|
+
expandedKeys.value.push(uniqueKey);
|
|
102
|
+
|
|
103
|
+
if (typeof value === 'object' && value !== null) {
|
|
104
|
+
recursiveExpand(value, uniqueKey);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
recursiveExpand(props.modelValue);
|
|
111
|
+
|
|
112
|
+
function handleClick(event: MouseEvent) {
|
|
113
|
+
if (props.variant !== 'collapse') {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const target = event.target as HTMLElement;
|
|
118
|
+
if (target.classList.contains('chevron')) {
|
|
119
|
+
const key = target.dataset.key;
|
|
120
|
+
|
|
121
|
+
if (key) {
|
|
122
|
+
toggleExpand(key);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function renderContent(data: JsonData | JsonData[], uniqueKey = ''): string {
|
|
128
|
+
if (Array.isArray(data)) {
|
|
129
|
+
return renderArray(data, uniqueKey);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
else if (typeof data === 'object' && data !== null) {
|
|
133
|
+
return renderObject(data, uniqueKey);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return `<span>${data}</span>`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// If data is an array
|
|
140
|
+
function renderArray(data: JsonData[], parentKey = ''): string {
|
|
141
|
+
let result = '<ul>';
|
|
142
|
+
|
|
143
|
+
data.forEach((item, index) => {
|
|
144
|
+
const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
|
|
145
|
+
|
|
146
|
+
if (typeof item === 'object' && item !== null) {
|
|
147
|
+
result += `${renderContent(item, uniqueKey)}`;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
result += `<li>${renderContent(item, uniqueKey)}</li>`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
result += '</ul>';
|
|
156
|
+
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// If data is an object
|
|
161
|
+
function renderObject(data: JsonData, parentKey = ''): string {
|
|
162
|
+
let result = '<ul>';
|
|
163
|
+
|
|
164
|
+
Object.entries(data).forEach(([key, value], index) => {
|
|
165
|
+
const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
|
|
166
|
+
console.log('uniqueKey', uniqueKey, 'parentKey', parentKey, 'index', index);
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
if (props.variant === 'collapse') {
|
|
170
|
+
result += `<li> <b data-key="${uniqueKey}" class="${(typeof value === 'object' && value !== null) ? 'chevron' : ''}">${key}</b>`;
|
|
171
|
+
} else {
|
|
172
|
+
result += `<li> <b>${key}</b>`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (typeof value === 'object' && value !== null) {
|
|
176
|
+
if (props.variant === 'collapse') {
|
|
177
|
+
result += `<span data-key="${uniqueKey}" class="chevron ml-[-2px]"> ${renderChevron(uniqueKey)} </span>`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (isExpanded(uniqueKey) || props.variant !== 'collapse') {
|
|
181
|
+
result += renderContent(value, uniqueKey);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
result += ` <span>${value}</span>`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
result += '</li>';
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
result += '</ul>';
|
|
191
|
+
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function renderChevron(key: string): string {
|
|
196
|
+
return isExpanded(key) ? `<span class="chevron heroicons--chevron-right-16-solid w-1 h-1 ${classSizeChevron.value}" data-key="${key}"></span>`
|
|
197
|
+
: `<span class="chevron heroicons--chevron-down-16-solid ${classSizeChevron.value}" data-key="${key}"></span>`;
|
|
198
|
+
}
|
|
199
|
+
</script>
|