Skip to content

Commit 2f96aef

Browse files
committed
change the way how we determine if default value should be returned
1 parent 6b5dca8 commit 2f96aef

File tree

6 files changed

+141
-69
lines changed

6 files changed

+141
-69
lines changed

packages/vue-vuetify/src/complex/MixedRenderer.vue

Lines changed: 115 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,86 @@
11
<template>
2-
<div
3-
:class="[
4-
'prefixed-input',
5-
{ 'vertical-layout': valueType === 'object' || valueType === 'array' },
6-
]"
7-
v-if="control.visible"
8-
>
9-
<v-select
10-
v-if="mixedRenderInfos && mixedRenderInfos.length > 1"
11-
:class="['prefix']"
12-
v-disabled-icon-focus
13-
:id="control.id + '-input-selector'"
14-
:disabled="!control.enabled"
15-
:label="computedLabel"
16-
:required="control.required"
17-
:error-messages="control.errors"
18-
:items="mixedRenderInfos"
19-
:clearable="control.enabled"
20-
@update:model-value="handleSelectChange"
21-
:item-title="(item: SchemaRenderInfo) => t(item.label, item.label)"
22-
item-value="index"
23-
v-model="selectedIndex"
24-
v-bind="vuetifyProps('v-select')"
25-
@focus="handleFocus"
26-
@blur="handleBlur"
27-
>
28-
</v-select>
29-
<dispatch-renderer
30-
:class="['input']"
31-
v-if="schema && !(nullable && control.data === null)"
32-
:schema="schema"
33-
:uischema="uischema"
34-
:path="path"
35-
:renderers="control.renderers"
36-
:cells="control.cells"
37-
:enabled="control.enabled"
38-
>
39-
</dispatch-renderer>
2+
<div :class="['prefixed-input']" v-if="control.visible">
3+
<template v-if="valueType === 'array' || valueType === 'object'">
4+
<v-expansion-panels accordion flat v-model="currentlyExpanded">
5+
<v-expansion-panel>
6+
<v-expansion-panel-title class="py-0 px-0">
7+
<v-container class="py-0">
8+
<v-row>
9+
<v-col align-self="center" class="pl-0"
10+
><v-select
11+
v-if="mixedRenderInfos && mixedRenderInfos.length > 1"
12+
v-disabled-icon-focus
13+
:id="control.id + '-input-selector'"
14+
:disabled="!control.enabled"
15+
:label="computedLabel"
16+
:required="control.required"
17+
:error-messages="control.errors"
18+
:items="mixedRenderInfos"
19+
:clearable="control.enabled"
20+
@update:model-value="handleSelectChange"
21+
:item-title="
22+
(item: SchemaRenderInfo) => t(item.label, item.label)
23+
"
24+
item-value="index"
25+
v-model="selectedIndex"
26+
v-bind="vuetifyProps('v-select')"
27+
@click.stop
28+
@focus="handleFocus"
29+
@blur="handleBlur"
30+
>
31+
</v-select
32+
></v-col>
33+
</v-row>
34+
</v-container>
35+
</v-expansion-panel-title>
36+
<v-expansion-panel-text>
37+
<dispatch-renderer
38+
:class="['input']"
39+
v-if="schema && !(nullable && control.data === null)"
40+
:schema="schema"
41+
:uischema="uischema"
42+
:path="path"
43+
:renderers="control.renderers"
44+
:cells="control.cells"
45+
:enabled="control.enabled"
46+
>
47+
</dispatch-renderer>
48+
</v-expansion-panel-text>
49+
</v-expansion-panel>
50+
</v-expansion-panels>
51+
</template>
52+
<template v-else>
53+
<v-select
54+
v-if="mixedRenderInfos && mixedRenderInfos.length > 1"
55+
v-disabled-icon-focus
56+
:id="control.id + '-input-selector'"
57+
:disabled="!control.enabled"
58+
:label="computedLabel"
59+
:required="control.required"
60+
:error-messages="control.errors"
61+
:items="mixedRenderInfos"
62+
:clearable="control.enabled"
63+
@update:model-value="handleSelectChange"
64+
:item-title="(item: SchemaRenderInfo) => t(item.label, item.label)"
65+
item-value="index"
66+
v-model="selectedIndex"
67+
v-bind="vuetifyProps('v-select')"
68+
@focus="handleFocus"
69+
@blur="handleBlur"
70+
>
71+
</v-select>
72+
<dispatch-renderer
73+
:class="['input']"
74+
v-if="schema && !(nullable && control.data === null)"
75+
:schema="schema"
76+
:uischema="uischema"
77+
:path="path"
78+
:renderers="control.renderers"
79+
:cells="control.cells"
80+
:enabled="control.enabled"
81+
>
82+
</dispatch-renderer>
83+
</template>
4084
</div>
4185
</template>
4286

@@ -56,11 +100,20 @@ import {
56100
useJsonFormsControl,
57101
type RendererProps,
58102
} from '@jsonforms/vue';
59-
import { computed, defineComponent, ref, watch } from 'vue';
60-
import { VSelect, VBtn } from 'vuetify/components';
103+
import { computed, defineComponent, provide, ref, watch } from 'vue';
104+
import {
105+
VCol,
106+
VContainer,
107+
VExpansionPanel,
108+
VExpansionPanelText,
109+
VExpansionPanelTitle,
110+
VRow,
111+
VSelect,
112+
} from 'vuetify/components';
61113
import { DisabledIconFocus } from '../controls';
62114
import {
63115
useCombinatorTranslations,
116+
UseDefaultValueKey,
64117
useIcons,
65118
useJsonForms,
66119
useTranslator,
@@ -179,7 +232,7 @@ const createMixedRenderInfos = (
179232
: false;
180233
} else if (schema.type === 'array') {
181234
schema.items = schema.items ?? {};
182-
if (!(schema.items as any)) {
235+
if (!(schema.items as any).type) {
183236
(schema.items as any).type = [
184237
'array',
185238
'boolean',
@@ -204,7 +257,10 @@ const createMixedRenderInfos = (
204257
...control,
205258
options: { ...control.options, detail: detailsForSchema },
206259
}
207-
: control;
260+
: {
261+
...control,
262+
scope: control.scope,
263+
};
208264
209265
return {
210266
schema,
@@ -244,8 +300,13 @@ const controlRenderer = defineComponent({
244300
name: 'mixed-renderer',
245301
components: {
246302
DispatchRenderer,
247-
VBtn,
248303
VSelect,
304+
VExpansionPanel,
305+
VExpansionPanelTitle,
306+
VExpansionPanelText,
307+
VContainer,
308+
VRow,
309+
VCol,
249310
},
250311
directives: {
251312
DisabledIconFocus,
@@ -334,6 +395,10 @@ const controlRenderer = defineComponent({
334395
: undefined,
335396
);
336397
398+
const currentlyExpanded = ref<number | null>(null);
399+
// use the default value since all properties are dynamic so preserve the property key
400+
provide(UseDefaultValueKey, true);
401+
337402
return {
338403
...useCombinatorTranslations(useVuetifyControl(input)),
339404
nullable,
@@ -345,6 +410,7 @@ const controlRenderer = defineComponent({
345410
uischema,
346411
path,
347412
icons,
413+
currentlyExpanded,
348414
};
349415
},
350416
methods: {
@@ -367,6 +433,8 @@ const controlRenderer = defineComponent({
367433
? this.mixedRenderInfos[newIndex]?.schema?.type
368434
: null;
369435
this.valueType = type as string | null; // we know that this should be either a string or null
436+
437+
this.currentlyExpanded = 0;
370438
},
371439
},
372440
});
@@ -379,16 +447,12 @@ export default controlRenderer;
379447
align-items: center;
380448
}
381449
382-
.vertical-layout {
383-
flex-direction: column;
384-
align-items: flex-start;
385-
}
386-
387-
.prefix {
388-
}
389-
390450
.input {
391451
flex-grow: 1;
392452
width: 100%;
393453
}
454+
455+
:deep(.v-expansion-panel-text__wrapper) {
456+
padding: 0px;
457+
}
394458
</style>

packages/vue-vuetify/src/complex/ObjectRenderer.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ import {
3333
import cloneDeep from 'lodash/cloneDeep';
3434
import isEmpty from 'lodash/isEmpty';
3535
import isObject from 'lodash/isObject';
36-
import { defineComponent } from 'vue';
36+
import { defineComponent, provide } from 'vue';
3737
import { useNested, useVuetifyControl } from '../util';
3838
import { AdditionalProperties } from './components';
39+
import { UseDefaultValueKey } from '@/util/inject';
3940
4041
const controlRenderer = defineComponent({
4142
name: 'object-renderer',
@@ -50,6 +51,11 @@ const controlRenderer = defineComponent({
5051
const control = useVuetifyControl(useJsonFormsControlWithDetail(props));
5152
5253
const nested = useNested('object');
54+
55+
// do not use the default value but the undefind so that
56+
// the property is cleared when property clear action is executed
57+
provide(UseDefaultValueKey, false);
58+
5359
return {
5460
...control,
5561
input: control,

packages/vue-vuetify/src/complex/components/AdditionalProperties.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ import {
124124
computed,
125125
defineComponent,
126126
markRaw,
127+
provide,
127128
ref,
128129
unref,
129130
type PropType,
@@ -146,6 +147,7 @@ import {
146147
useJsonForms,
147148
useTranslator,
148149
} from '../../util';
150+
import { UseDefaultValueKey } from '@/util/inject';
149151
150152
type Input = ReturnType<typeof useJsonFormsControlWithDetail>;
151153
interface AdditionalPropertyType {
@@ -407,6 +409,9 @@ export default defineComponent({
407409
newPropertyName.value ? parentValidationMode : 'ValidateAndHide',
408410
);
409411
412+
// use the default value since all properties are dynamic so preserve the property key
413+
provide(UseDefaultValueKey, true);
414+
410415
return {
411416
validationMode: validationMode,
412417
i18n: i18n ? markRaw(i18n) : i18n,

packages/vue-vuetify/src/util/composition.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
} from 'vue';
4040
import type { IconOptions } from 'vuetify';
4141
import { useStyles } from '../styles';
42+
import { UseDefaultValueKey } from './inject';
4243

4344
export const IconSymbol: InjectionKey<Required<IconOptions>> =
4445
Symbol.for('vuetify:icons');
@@ -489,23 +490,13 @@ export const determineClearValue = (
489490
props: RendererProps<ControlElement & Scopable>,
490491
defaultValue: any,
491492
) => {
492-
const { uischema } = props;
493-
494-
if (!isScoped(uischema) || props.schema?.type !== 'object') {
495-
return defaultValue;
496-
}
497-
498-
// check if we are wrapped in an object and
499-
// the path to the property is defined in the object properties
500-
// then return undefined to clear the property from the object
493+
const jsonforms = useJsonForms();
501494

502-
// remove any leading #, /, or #/
503-
const schemaPath = uischema.scope.replace(/^(#\/|#|\/)/, '');
504-
// replace / with .
505-
const property = schemaPath.replace(/\//g, '.');
495+
const useDefaultValue = inject<boolean>(
496+
UseDefaultValueKey,
497+
jsonforms.core?.schema.type !== 'object',
498+
);
506499

507-
const definedPropertySchema = get(props.schema, property);
508-
return typeof definedPropertySchema === 'object'
509-
? undefined // clear the property from the object
510-
: defaultValue;
500+
// undefined will clear the property from the object
501+
return useDefaultValue ? defaultValue : undefined;
511502
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './composition';
22
export * from './datejs';
3+
export * from './inject';
34
export * from './options';
45
export * from './validator';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { InjectionKey } from 'vue';
2+
3+
export const UseDefaultValueKey: InjectionKey<boolean> = Symbol.for(
4+
'jsonforms-vue-vuetify:useDefaultValue',
5+
);

0 commit comments

Comments
 (0)