-
Notifications
You must be signed in to change notification settings - Fork 377
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add OneOfControlRenderer to vue-vanilla
- Loading branch information
Showing
6 changed files
with
317 additions
and
1 deletion.
There are no files selected for viewing
203 changes: 203 additions & 0 deletions
203
packages/vue/vue-vanilla/src/complex/OneOfControlRenderer.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
<template> | ||
<div v-if="control.visible"> | ||
<combinator-properties | ||
:schema="control.schema" | ||
combinator-keyword="oneOf" | ||
:path="path" | ||
/> | ||
|
||
<control-wrapper | ||
v-bind="controlWrapper" | ||
:styles="styles" | ||
:is-focused="isFocused" | ||
:applied-options="appliedOptions" | ||
> | ||
<select | ||
:id="control.id + '-input'" | ||
:class="styles.control.select" | ||
:value="selectIndex" | ||
:disabled="!control.enabled" | ||
:autofocus="appliedOptions.focus" | ||
@change="handleSelectChange" | ||
@focus="isFocused = true" | ||
@blur="isFocused = false" | ||
> | ||
<option | ||
v-for="optionElement in indexedOneOfRenderInfos" | ||
:key="optionElement.index" | ||
:value="optionElement.index" | ||
:label="optionElement.label" | ||
:class="styles.control.option" | ||
></option> | ||
</select> | ||
</control-wrapper> | ||
|
||
<dispatch-renderer | ||
v-if="selectedIndex !== undefined && selectedIndex !== null" | ||
:schema="indexedOneOfRenderInfos[selectedIndex].schema" | ||
:uischema="indexedOneOfRenderInfos[selectedIndex].uischema" | ||
:path="control.path" | ||
:renderers="control.renderers" | ||
:cells="control.cells" | ||
:enabled="control.enabled" | ||
/> | ||
|
||
<dialog ref="dialog" :class="styles.dialog.root"> | ||
<h1 :class="styles.dialog.title"> | ||
{{ t('form.clear.title', 'Clear form?') }} | ||
</h1> | ||
|
||
<p :class="styles.dialog.body"> | ||
{{ | ||
t( | ||
'form.clear.text', | ||
'Your data will be cleared. Do you want to proceed?' | ||
) | ||
}} | ||
</p> | ||
|
||
<div :class="styles.dialog.actions"> | ||
<button :onclick="onCancel" :class="styles.dialog.buttonSecondary"> | ||
{{ t('form.clear.cancel', 'No') }} | ||
</button> | ||
<button | ||
ref="confirm" | ||
:onclick="onConfirm" | ||
:class="styles.dialog.buttonPrimary" | ||
> | ||
{{ t('form.clear.confirm', 'Yes') }} | ||
</button> | ||
</div> | ||
</dialog> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { | ||
CombinatorSubSchemaRenderInfo, | ||
ControlElement, | ||
createCombinatorRenderInfos, | ||
createDefaultValue, | ||
isOneOfControl, | ||
JsonFormsRendererRegistryEntry, | ||
rankWith, | ||
} from '@jsonforms/core'; | ||
import { | ||
DispatchRenderer, | ||
rendererProps, | ||
RendererProps, | ||
useJsonFormsOneOfControl, | ||
} from '@jsonforms/vue'; | ||
import isEmpty from 'lodash/isEmpty'; | ||
import { defineComponent, nextTick, ref } from 'vue'; | ||
import { useTranslator, useVanillaControl } from '../util'; | ||
import { ControlWrapper } from '../controls'; | ||
//import { CombinatorProperties } from './components'; | ||
const controlRenderer = defineComponent({ | ||
name: 'OneOfSelectRenderer', | ||
components: { | ||
ControlWrapper, | ||
DispatchRenderer, | ||
//CombinatorProperties, | ||
}, | ||
props: { | ||
...rendererProps<ControlElement>(), | ||
}, | ||
setup(props: RendererProps<ControlElement>) { | ||
const input = useJsonFormsOneOfControl(props); | ||
const control = input.control.value; | ||
const selectedIndex = ref(control.indexOfFittingSchema); | ||
const selectIndex = ref(selectedIndex.value); | ||
const newSelectedIndex = ref(0); | ||
const t = useTranslator(); | ||
const dialog = ref<HTMLDialogElement>(null); | ||
const confirm = ref<HTMLElement>(null); | ||
return { | ||
...useVanillaControl(input), | ||
selectedIndex, | ||
selectIndex, | ||
newSelectedIndex, | ||
dialog, | ||
confirm, | ||
t, | ||
}; | ||
}, | ||
computed: { | ||
indexedOneOfRenderInfos(): (CombinatorSubSchemaRenderInfo & { | ||
index: number; | ||
})[] { | ||
const result = createCombinatorRenderInfos( | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
this.control.schema.oneOf!, | ||
this.control.rootSchema, | ||
'oneOf', | ||
this.control.uischema, | ||
this.control.path, | ||
this.control.uischemas | ||
); | ||
return result | ||
.filter((info) => info.uischema) | ||
.map((info, index) => ({ ...info, index: index })); | ||
}, | ||
}, | ||
methods: { | ||
handleSelectChange(event: Event): void { | ||
const target = event.target as any; | ||
this.selectIndex = target.value; | ||
if (this.control.enabled && !isEmpty(this.control.data)) { | ||
this.showDialog(); | ||
nextTick(() => { | ||
this.newSelectedIndex = this.selectIndex; | ||
// revert the selection while the dialog is open | ||
this.selectIndex = this.selectedIndex; | ||
this.confirm.focus(); | ||
}); | ||
} else { | ||
nextTick(() => { | ||
this.selectedIndex = this.selectIndex; | ||
}); | ||
} | ||
}, | ||
showDialog(): void { | ||
this.dialog.showModal(); | ||
}, | ||
closeDialog(): void { | ||
this.dialog.close(); | ||
}, | ||
onConfirm(): void { | ||
this.newSelection(); | ||
this.closeDialog(); | ||
}, | ||
onCancel(): void { | ||
this.newSelectedIndex = this.selectedIndex; | ||
this.closeDialog(); | ||
}, | ||
newSelection(): void { | ||
this.handleChange( | ||
this.path, | ||
this.newSelectedIndex !== undefined && this.newSelectedIndex !== null | ||
? createDefaultValue( | ||
this.indexedOneOfRenderInfos[this.newSelectedIndex].schema | ||
) | ||
: {} | ||
); | ||
this.selectIndex = this.newSelectedIndex; | ||
this.selectedIndex = this.newSelectedIndex; | ||
}, | ||
}, | ||
}); | ||
export default controlRenderer; | ||
export const entry: JsonFormsRendererRegistryEntry = { | ||
renderer: controlRenderer, | ||
tester: rankWith(3, isOneOfControl), | ||
}; | ||
</script> | ||
|
67 changes: 67 additions & 0 deletions
67
packages/vue/vue-vanilla/src/complex/components/CombinatorProperties.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<template> | ||
<div v-if="isLayoutWithElements"> | ||
<dispatch-renderer | ||
:schema="otherProps" | ||
:path="path" | ||
:uischema="foundUISchema" | ||
/> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { Generate, JsonSchema, Layout, UISchemaElement } from '@jsonforms/core'; | ||
import omit from 'lodash/omit'; | ||
import { PropType, defineComponent } from 'vue'; | ||
import { DispatchRenderer } from '@jsonforms/vue'; | ||
interface CombinatorProps { | ||
schema: JsonSchema; | ||
combinatorKeyword: 'oneOf' | 'anyOf' | 'allOf'; | ||
path: string; | ||
} | ||
export default defineComponent({ | ||
name: 'CombinatorProperties', | ||
components: { | ||
DispatchRenderer, | ||
}, | ||
props: { | ||
schema: { | ||
type: Object as PropType<JsonSchema>, | ||
required: true, | ||
}, | ||
combinatorKeyword: { | ||
type: String as PropType<'oneOf' | 'anyOf' | 'allOf'>, | ||
required: true, | ||
}, | ||
path: { | ||
type: String, | ||
required: true, | ||
}, | ||
}, | ||
setup(props: CombinatorProps) { | ||
const otherProps: JsonSchema = omit( | ||
props.schema, | ||
props.combinatorKeyword | ||
) as JsonSchema; | ||
const foundUISchema: UISchemaElement = Generate.uiSchema( | ||
otherProps, | ||
'VerticalLayout' | ||
); | ||
const isLayout = (uischema: UISchemaElement): uischema is Layout => | ||
Object.prototype.hasOwnProperty.call(uischema, 'elements'); | ||
let isLayoutWithElements = false; | ||
if (foundUISchema !== null && isLayout(foundUISchema)) { | ||
isLayoutWithElements = foundUISchema.elements.length > 0; | ||
} | ||
return { | ||
otherProps, | ||
foundUISchema, | ||
isLayoutWithElements, | ||
}; | ||
}, | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
export { default as ObjectControlRenderer } from './ObjectControlRenderer.vue'; | ||
export { default as OneOfControlRenderer } from './OneOfControlRenderer.vue'; | ||
|
||
import { entry as objectControlRendererEntry } from './ObjectControlRenderer.vue'; | ||
import { entry as oneOfControlRendererEntry } from './OneOfControlRenderer.vue'; | ||
|
||
export const complexRenderers = [objectControlRendererEntry]; | ||
export const complexRenderers = [ | ||
objectControlRendererEntry, | ||
oneOfControlRendererEntry, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters