1
+ <template >
2
+ <Collapsible :clickable-text =" sectionName" :href =" href" @expand =" emit('expand')" :initially-expanded =" initiallyExpanded" >
3
+ <template v-if =" Object .keys (properties ?? {}).length > 0 " #content >
4
+ <div class =" border rounded" >
5
+ <Collapsible
6
+ class =" property p-3"
7
+ v-for =" (property, propertyKey) in sortSchemaByRequired(properties)"
8
+ :key =" propertyKey"
9
+ :arrow =" false"
10
+ :clickable-text =" propertyKey"
11
+ :href =" href + '_' + propertyKey"
12
+ @expand =" initiallyExpanded = true"
13
+ >
14
+ <template #additionalButtonText >
15
+ <span v-if =" property['$required']" class =" text-danger" > *</span >
16
+ </template >
17
+ <template #buttonRight =" {collapsed } " >
18
+ <span class =" d-flex flex-grow-1 align-items-center justify-content-between" >
19
+ <span class =" d-flex gap-1" >
20
+ <Tooltip v-if =" showDynamic && !isDynamic(property)" class =" d-flex" title =" Non-dynamic" >
21
+ <Cancel class =" text-danger" />
22
+ </Tooltip >
23
+ <Tooltip v-if =" property['$beta']" class =" d-flex" title =" Beta" >
24
+ <AlphaBBox class =" text-warning" />
25
+ </Tooltip >
26
+ <Tooltip v-if =" property['$deprecated']" class =" d-flex" title =" Deprecated" >
27
+ <Alert class =" text-warning" />
28
+ </Tooltip >
29
+ </span >
30
+ <span class =" d-flex gap-2" >
31
+ <template v-for =" type in extractTypeInfo (property ).types " :key =" type " >
32
+ <a v-if =" type.startsWith('#')" class =" d-flex fw-bold type-box rounded fs-7 px-2 py-1" :href =" type" @click.stop >
33
+ <span class =" ref-type" >{{ className(type) }}</span ><eye-outline />
34
+ </a >
35
+ <span v-else class =" type-box rounded fs-7 px-2 py-1" >
36
+ {{ type }}
37
+ </span >
38
+ </template >
39
+ <component :is =" collapsed ? ChevronDown : ChevronUp" class =" arrow" />
40
+ </span >
41
+ </span >
42
+ </template >
43
+ <template #content >
44
+ <PropertyDetail :show-dynamic =" showDynamic" :is-dynamic =" showDynamic && isDynamic(property)" :property =" property" >
45
+ <template #markdown =" {content } " >
46
+ <slot :content =" content" name =" markdown" />
47
+ </template >
48
+ </PropertyDetail >
49
+ </template >
50
+ </Collapsible >
51
+ </div >
52
+ </template >
53
+ </Collapsible >
54
+ </template >
55
+
56
+ <script setup lang="ts">
57
+ import {extractTypeInfo , className , type JSONProperty } from " ../../utils/schemaUtils" ;
58
+ import ChevronDown from " vue-material-design-icons/ChevronDown.vue" ;
59
+ import Collapsible from " ../misc/Collapsible.vue" ;
60
+ import Tooltip from " ../misc/Tooltip.vue" ;
61
+ import PropertyDetail from " ./PropertyDetail.vue" ;
62
+ import ChevronUp from " vue-material-design-icons/ChevronUp.vue" ;
63
+ import Alert from " vue-material-design-icons/Alert.vue" ;
64
+ import Cancel from " vue-material-design-icons/Cancel.vue" ;
65
+ import AlphaBBox from " vue-material-design-icons/AlphaBBox.vue" ;
66
+ import type {JSONSchema } from " ./SchemaToHtml.vue" ;
67
+ import EyeOutline from " vue-material-design-icons/EyeOutline.vue" ;
68
+ import {ref , watch } from " vue" ;
69
+
70
+ withDefaults (defineProps <{ href? : string , sectionName: string , properties? : Record <string , JSONProperty >, showDynamic? : boolean }>(), {
71
+ properties: undefined ,
72
+ href: Math .random ().toString (36 ).substring (2 , 5 ),
73
+ showDynamic: true
74
+ });
75
+
76
+ const emit = defineEmits ([" expand" ]);
77
+
78
+ const initiallyExpanded = ref (false );
79
+
80
+ watch (
81
+ initiallyExpanded ,
82
+ newInitiallyExpanded => {
83
+ if (newInitiallyExpanded ) {
84
+ emit (" expand" );
85
+ }
86
+ }
87
+ );
88
+
89
+ const isDynamic = (property : JSONProperty ): boolean => {
90
+ if (property [" $dynamic" ] === true ) {
91
+ return true ;
92
+ }
93
+
94
+ if (property [" $dynamic" ] === false ) {
95
+ return false ;
96
+ }
97
+
98
+ return property .oneOf ?.some (prop => prop [" $dynamic" ] === true ) ?? false ;
99
+ };
100
+
101
+ function sortSchemaByRequired<T extends NonNullable <NonNullable <JSONSchema [" properties" ]>[" properties" ]>>(schema : T ): T {
102
+ const requiredKeys = [];
103
+ const nonRequiredKeys = [];
104
+
105
+ for (const key in schema ) {
106
+ if (typeof schema [key ] === " object" ) {
107
+ if (schema [key ].$required ) {
108
+ requiredKeys .push (key );
109
+ } else {
110
+ nonRequiredKeys .push (key );
111
+ }
112
+ }
113
+ }
114
+
115
+ const sortedKeys = [... requiredKeys .sort (), ... nonRequiredKeys .sort ()];
116
+
117
+ const sortedSchema: T = {} as T ;
118
+ sortedKeys .forEach (key => {
119
+ sortedSchema [key ] = schema [key ];
120
+ });
121
+
122
+ return sortedSchema ;
123
+ }
124
+ </script >
125
+
126
+ <style lang="scss" scoped>
127
+ @use " ../../scss/variables" as variables ;
128
+
129
+ .type-box , :deep(.type-box ) {
130
+ border : 1px solid variables .$blue !important ;
131
+ background : none ;
132
+
133
+ .ref-type {
134
+ padding-right : 0.625rem ;
135
+
136
+ + * {
137
+ margin-left : 0.625rem ;
138
+ }
139
+ }
140
+ }
141
+
142
+ .property :not (:first-child ) {
143
+ border-top : var (--bs-border-width ) var (--bs-border-style ) var (--bs-border-color );
144
+ }
145
+ </style >
0 commit comments