Skip to content

Cell renderer set for vue vanilla (work in progress) #2279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/vue-vanilla/dev/components/App.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { JsonForms, JsonFormsChangeEvent } from '../../config/jsonforms';
import { vanillaRenderers, mergeStyles, defaultStyles } from '../../src';
import {
vanillaRenderers,
vanillaCells,
mergeStyles,
defaultStyles,
} from '../../src';
import '../../vanilla.css';
import { ErrorObject } from 'ajv';
import { getExamples } from '../../../examples';
@@ -29,6 +34,7 @@ export default defineComponent({
return {
data: {},
renderers: Object.freeze(vanillaRenderers),
cells: Object.freeze(vanillaCells),
currentExampleName: examples[0].name,
examples,
i18n: examples[0].i18n,
@@ -137,6 +143,7 @@ export default defineComponent({
:schema="example.schema"
:uischema="example.uischema"
:renderers="renderers"
:cells="cells"
:i18n="example.i18n"
:additional-errors="additionalErrors"
@change="onChange"
40 changes: 40 additions & 0 deletions packages/vue-vanilla/src/cells/BooleanCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<input
:id="cell.id + '-input'"
type="checkbox"
:class="styles.control.input"
:checked="!!cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import type { ControlElement, RankedTester } from '@jsonforms/core';
import { isBooleanControl, rankWith } from '@jsonforms/core';
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(
useJsonFormsCell(props),
(target) => target.checked
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

/**
* JUST AN PROPOSAL!!!
* @see https://github.com/eclipsesource/jsonforms/pull/2279#discussion_r1528101480
*/
defineOptions(
((): { tester: RankedTester } => {
const tester: RankedTester = rankWith(1, isBooleanControl);
return { tester };
})()
);
</script>
33 changes: 33 additions & 0 deletions packages/vue-vanilla/src/cells/DateCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>
<input
:id="cell.id + '-input'"
type="date"
:class="styles.control.input"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import type { ControlElement, RankedTester } from '@jsonforms/core';
import { isDateControl, rankWith } from '@jsonforms/core';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(
useJsonFormsCell(props),
(target) => target.value || undefined
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

defineOptions({
tester: rankWith(2, isDateControl) as RankedTester,
});
</script>
44 changes: 44 additions & 0 deletions packages/vue-vanilla/src/cells/DateTimeCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<template>
<input
:id="cell.id + '-input'"
v-model="dataTime"
type="datetime-local"
:class="styles.control.input"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import type { RankedTester, ControlElement } from '@jsonforms/core';
import { isDateTimeControl, rankWith } from '@jsonforms/core';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(useJsonFormsCell(props), (target) =>
'' !== target.value ? toISO(target.value) : undefined
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

const fromISO = (str: string | undefined) => str?.slice(0, 16);
const toISO = (str: string) => str + ':00.000Z';

const dataTime = ref();
const setDateTime = (str: string | undefined) => {
dataTime.value = fromISO(str);
};

setDateTime(input.cell.value.data);
watch(() => input.cell.value.data, setDateTime);

defineOptions({
tester: rankWith(2, isDateTimeControl) as RankedTester,
});
</script>
39 changes: 39 additions & 0 deletions packages/vue-vanilla/src/cells/EnumCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<select
:id="cell.id + '-select'"
:class="styles.control.select"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
>
<option key="empty" value="" :class="styles.control.option" />
<option
v-for="optionElement in cell?.options"
:key="optionElement.value"
:value="optionElement.value"
:label="optionElement.label"
:class="styles.control.option"
></option>
</select>
</template>

<script setup lang="ts">
import { rendererProps, useJsonFormsEnumCell } from '@jsonforms/vue';
import type { ControlElement } from '@jsonforms/core';
import { isEnumControl, rankWith } from '@jsonforms/core';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(useJsonFormsEnumCell(props), (target) =>
target.selectedIndex === 0 ? undefined : target.value
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

defineOptions({
tester: rankWith(2, isEnumControl),
});
</script>
39 changes: 39 additions & 0 deletions packages/vue-vanilla/src/cells/EnumOneOfCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<select
:id="cell.id + '-input'"
:class="styles.control.select"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
>
<option key="empty" value="" :class="styles.control.option" />
<option
v-for="optionElement in cell.options"
:key="optionElement.value"
:value="optionElement.value"
:label="optionElement.label"
:class="styles.control.option"
></option>
</select>
</template>

<script setup lang="ts">
import { rendererProps, useJsonFormsOneOfEnumCell } from '@jsonforms/vue';
import type { RankedTester, ControlElement } from '@jsonforms/core';
import { isOneOfEnumControl, rankWith } from '@jsonforms/core';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(useJsonFormsOneOfEnumCell(props), (target) =>
target.selectedIndex === 0 ? undefined : target.value
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

defineOptions({
tester: rankWith(5, isOneOfEnumControl) as RankedTester,
});
</script>
33 changes: 33 additions & 0 deletions packages/vue-vanilla/src/cells/IntegerCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>
<input
:id="cell.id + '-input'"
type="number"
:step="1"
:class="styles.control.input"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import type { RankedTester, ControlElement } from '@jsonforms/core';
import { isIntegerControl, rankWith } from '@jsonforms/core';
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(useJsonFormsCell(props), (target) =>
target.value === '' ? undefined : parseInt(target.value, 10)
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

defineOptions({
tester: rankWith(1, isIntegerControl) as RankedTester,
});
</script>
39 changes: 39 additions & 0 deletions packages/vue-vanilla/src/cells/NumberCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<input
:id="cell.id + '-input'"
type="number"
:step="step"
:class="styles.control.input"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import type { ControlElement, RankedTester } from '@jsonforms/core';
import { isNumberControl, rankWith } from '@jsonforms/core';
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(useJsonFormsCell(props), (target) =>
target.value === '' ? undefined : Number(target.value)
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

const step = computed(() => {
const options: any = appliedOptions;
return options.step ?? 0.1;
});

defineOptions({
tester: rankWith(1, isNumberControl) as RankedTester,
});
</script>
32 changes: 32 additions & 0 deletions packages/vue-vanilla/src/cells/TextCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<input
:id="cell.id + '-input'"
:class="styles.control.input"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import type { ControlElement, RankedTester } from '@jsonforms/core';
import { isStringControl, rankWith } from '@jsonforms/core';
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(
useJsonFormsCell(props),
(target) => target.value || undefined
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

defineOptions({
tester: rankWith(1, isStringControl) as RankedTester,
});
</script>
37 changes: 37 additions & 0 deletions packages/vue-vanilla/src/cells/TextareaCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<textarea
:id="cell.id + '-input'"
:class="styles.control.textarea"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import type { ControlElement, RankedTester } from '@jsonforms/core';
import {
and,
isMultiLineControl,
isStringControl,
rankWith,
} from '@jsonforms/core';
import { useVanillaCell } from '../util';

const props = defineProps(rendererProps<ControlElement>());

const input = useVanillaCell(
useJsonFormsCell(props),
(target) => target.value || undefined
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;

defineOptions({
tester: rankWith(2, and(isStringControl, isMultiLineControl)) as RankedTester,
});
</script>
35 changes: 35 additions & 0 deletions packages/vue-vanilla/src/cells/TimeCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<template>
<input
:id="cell.id + '-input'"
type="time"
:class="styles.control.input"
:value="cell.data"
:disabled="!cell.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</template>

<script setup lang="ts">
import { rendererProps, useJsonFormsCell } from '@jsonforms/vue';
import type { ControlElement, RankedTester } from '@jsonforms/core';
import { isTimeControl, rankWith } from '@jsonforms/core';
import { useVanillaCell } from '../util';
const props = defineProps(rendererProps<ControlElement>());
const input = useVanillaCell(useJsonFormsCell(props), (target) =>
appendSeconds(target.value || undefined)
);
const { styles, cell, appliedOptions, onChange, isFocused } = input;
const appendSeconds = (value: string | undefined) =>
value?.split(':').length === 2 ? value + ':00' : value;
defineOptions({
tester: rankWith(2, isTimeControl) as RankedTester,
});
</script>
24 changes: 24 additions & 0 deletions packages/vue-vanilla/src/cells/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type JsonFormsCellRendererRegistryEntry } from '@jsonforms/core';
import TextCell from './TextCell.vue';
import NumberCell from './NumberCell.vue';
import IntegerCell from './IntegerCell.vue';
import DateCell from './DateCell.vue';
import TimeCell from './TimeCell.vue';
import DateTimeCell from './DateTimeCell.vue';
import TextareaCell from './TextareaCell.vue';
import EnumCell from './EnumCell.vue';
import EnumOneOfCell from './EnumOneOfCell.vue';
import BooleanCell from './BooleanCell.vue';

export const vanillaCells: JsonFormsCellRendererRegistryEntry[] = [
{ cell: TextCell, tester: TextCell.tester },
{ cell: NumberCell, tester: NumberCell.tester },
{ cell: IntegerCell, tester: IntegerCell.tester },
{ cell: DateCell, tester: DateCell.tester },
{ cell: TimeCell, tester: TimeCell.tester },
{ cell: DateTimeCell, tester: DateTimeCell.tester },
{ cell: TextareaCell, tester: TextareaCell.tester },
{ cell: EnumCell, tester: EnumCell.tester },
{ cell: EnumOneOfCell, tester: EnumOneOfCell.tester },
{ cell: BooleanCell, tester: BooleanCell.tester },
];
5 changes: 4 additions & 1 deletion packages/vue-vanilla/src/complex/OneOfRenderer.vue
Original file line number Diff line number Diff line change
@@ -70,12 +70,15 @@

<script lang="ts">
import {
and,
CombinatorSubSchemaRenderInfo,
ControlElement,
createCombinatorRenderInfos,
createDefaultValue,
isOneOfControl,
isOneOfEnumControl,
JsonFormsRendererRegistryEntry,
not,
rankWith,
} from '@jsonforms/core';
import {
@@ -192,6 +195,6 @@ export default controlRenderer;
export const entry: JsonFormsRendererRegistryEntry = {
renderer: controlRenderer,
tester: rankWith(3, isOneOfControl),
tester: rankWith(3, and(isOneOfControl, not(isOneOfEnumControl))),
};
</script>
61 changes: 0 additions & 61 deletions packages/vue-vanilla/src/controls/BooleanControlRenderer.vue

This file was deleted.

61 changes: 0 additions & 61 deletions packages/vue-vanilla/src/controls/DateControlRenderer.vue

This file was deleted.

69 changes: 0 additions & 69 deletions packages/vue-vanilla/src/controls/DateTimeControlRenderer.vue

This file was deleted.

67 changes: 0 additions & 67 deletions packages/vue-vanilla/src/controls/EnumControlRenderer.vue

This file was deleted.

67 changes: 0 additions & 67 deletions packages/vue-vanilla/src/controls/EnumOneOfControlRenderer.vue

This file was deleted.

Original file line number Diff line number Diff line change
@@ -5,40 +5,37 @@
:is-focused="isFocused"
:applied-options="appliedOptions"
>
<input
<DispatchCell
:id="control.id + '-input'"
:class="styles.control.input"
:value="control.data"
:disabled="!control.enabled"
:autofocus="appliedOptions.focus"
:placeholder="appliedOptions.placeholder"
@change="onChange"
@focus="isFocused = true"
@blur="isFocused = false"
:schema="control.schema"
:uischema="control.uischema"
:enabled="control.enabled"
:path="control.path"
/>
</control-wrapper>
</template>

<script lang="ts">
import {
import type {
ControlElement,
JsonFormsRendererRegistryEntry,
rankWith,
isStringControl,
} from '@jsonforms/core';
import { isControl, rankWith } from '@jsonforms/core';
import { defineComponent } from 'vue';
import {
DispatchCell,
rendererProps,
type RendererProps,
useJsonFormsControl,
RendererProps,
} from '../../config/jsonforms';
import { default as ControlWrapper } from './ControlWrapper.vue';
import { useVanillaControl } from '../util';
const controlRenderer = defineComponent({
name: 'StringControlRenderer',
name: 'InputControlRenderer',
components: {
ControlWrapper,
DispatchCell,
},
props: {
...rendererProps<ControlElement>(),
@@ -55,6 +52,6 @@ export default controlRenderer;
export const entry: JsonFormsRendererRegistryEntry = {
renderer: controlRenderer,
tester: rankWith(1, isStringControl),
tester: rankWith(1, isControl),
};
</script>
61 changes: 0 additions & 61 deletions packages/vue-vanilla/src/controls/IntegerControlRenderer.vue

This file was deleted.

62 changes: 0 additions & 62 deletions packages/vue-vanilla/src/controls/MultiStringControlRenderer.vue

This file was deleted.

67 changes: 0 additions & 67 deletions packages/vue-vanilla/src/controls/NumberControlRenderer.vue

This file was deleted.

61 changes: 0 additions & 61 deletions packages/vue-vanilla/src/controls/TimeControlRenderer.vue

This file was deleted.

35 changes: 3 additions & 32 deletions packages/vue-vanilla/src/controls/index.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,6 @@
export { default as ControlWrapper } from './ControlWrapper.vue';
export { default as StringControlRenderer } from './StringControlRenderer.vue';
export { default as MultiStringControlRenderer } from './MultiStringControlRenderer.vue';
export { default as NumberControlRenderer } from './NumberControlRenderer.vue';
export { default as IntegerControlRenderer } from './IntegerControlRenderer.vue';
export { default as EnumControlRenderer } from './EnumControlRenderer.vue';
export { default as oneOfEnumControlRenderer } from './EnumOneOfControlRenderer.vue';
export { default as DateControlRenderer } from './DateControlRenderer.vue';
export { default as DateTimeControlRenderer } from './DateTimeControlRenderer.vue';
export { default as TimeControlRenderer } from './TimeControlRenderer.vue';
export { default as BooleanControlRenderer } from './BooleanControlRenderer.vue';
export { default as InputControlRenderer } from './InputControlRenderer.vue';

import { entry as stringControlRendererEntry } from './StringControlRenderer.vue';
import { entry as multiStringControlRendererEntry } from './MultiStringControlRenderer.vue';
import { entry as numberControlRendererEntry } from './NumberControlRenderer.vue';
import { entry as integerControlRendererEntry } from './IntegerControlRenderer.vue';
import { entry as enumControlRendererEntry } from './EnumControlRenderer.vue';
import { entry as oneOfEnumControlRendererEntry } from './EnumOneOfControlRenderer.vue';
import { entry as dateControlRendererEntry } from './DateControlRenderer.vue';
import { entry as dateTimeControlRendererEntry } from './DateTimeControlRenderer.vue';
import { entry as timeControlRendererEntry } from './TimeControlRenderer.vue';
import { entry as booleanControlRendererEntry } from './BooleanControlRenderer.vue';
import { entry as InputControlRendererEntry } from './InputControlRenderer.vue';

export const controlRenderers = [
stringControlRendererEntry,
multiStringControlRendererEntry,
numberControlRendererEntry,
integerControlRendererEntry,
enumControlRendererEntry,
oneOfEnumControlRendererEntry,
dateControlRendererEntry,
dateTimeControlRendererEntry,
timeControlRendererEntry,
booleanControlRendererEntry,
];
export const controlRenderers = [InputControlRendererEntry];
1 change: 1 addition & 0 deletions packages/vue-vanilla/src/index.ts
Original file line number Diff line number Diff line change
@@ -5,3 +5,4 @@ export * from './renderers';
export * from './styles';
export * from './util';
export * from './label';
export * from './cells';
29 changes: 29 additions & 0 deletions packages/vue-vanilla/src/util/composition.ts
Original file line number Diff line number Diff line change
@@ -9,6 +9,35 @@ import {
Resolve,
} from '@jsonforms/core';

/**
* Adds styles, isFocused, appliedOptions and onChange
*/
export const useVanillaCell = <I extends { cell: any; handleChange: any }>(
input: I,
adaptTarget: (target: any) => any = (v) => v.value
) => {
const appliedOptions = computed(() =>
merge(
{},
cloneDeep(input.cell.value.config),
cloneDeep(input.cell.value.uischema.options)
)
);

const isFocused = ref(false);
const onChange = (event: Event) => {
input.handleChange(input.cell.value.path, adaptTarget(event.target));
};

return {
...input,
styles: useStyles(input.cell.value.uischema),
isFocused,
appliedOptions,
onChange,
};
};

/**
* Adds styles, isFocused, appliedOptions and onChange
*/
4 changes: 3 additions & 1 deletion packages/vue-vanilla/tests/unit/util/TestComponent.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { JsonForms } from '../../../config/jsonforms';
import { vanillaRenderers } from '../../../src';
import { vanillaRenderers, vanillaCells } from '../../../src';
import { JsonFormsChangeEvent } from '@jsonforms/vue';
export default defineComponent({
@@ -14,6 +14,7 @@ export default defineComponent({
data() {
return {
renderers: Object.freeze(vanillaRenderers),
cells: Object.freeze(vanillaCells),
data: this.initialData,
};
},
@@ -31,6 +32,7 @@ export default defineComponent({
:schema="schema"
:uischema="uischema"
:renderers="renderers"
:cells="cells"
:config="config"
@change="onChange"
/>