Dc3e4 new matrix field (#484)

* fix password reset bug

* wip: matrix input

* wip: matrix input

* wip: matrix input

* Fixed matric input component logic

* matrix input cleanup

* fix lint errors

* table border and radius

* cleanup, linting

* fix component methos

* wip matrix input

* matrix condition for contains and not contain

* patch matrix input condition logic

* linting

* refactor and cleanup

* fix syntax error

* Polished the matrix input

* Fix linting

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Favour Olayinka
2024-08-23 14:28:21 +01:00
committed by GitHub
parent fedc382594
commit 1adac8e00f
25 changed files with 919 additions and 85 deletions

View File

@@ -16,60 +16,45 @@
theme.default.input,
theme.default.borderRadius,
{
'mb-2': index !== options.length,
'!ring-red-500 !ring-2 !border-transparent': hasError,
'!cursor-not-allowed !bg-gray-200': disabled,
},
]"
>
<template
v-if="options && options.length"
>
<div
v-for="(option) in options"
:key="option[optionKey]"
:role="multiple?'checkbox':'radio'"
:aria-checked="isSelected(option[optionKey])"
:class="[
theme.FlatSelectInput.spacing.vertical,
theme.FlatSelectInput.fontSize,
theme.FlatSelectInput.option,
]"
@click="onSelect(option[optionKey])"
<template
v-if="options && options.length"
>
<template v-if="multiple">
<Icon
v-if="isSelected(option[optionKey])"
name="material-symbols:check-box"
class="text-inherit"
:color="color"
:class="[theme.FlatSelectInput.icon]"
/>
<Icon
v-else
name="material-symbols:check-box-outline-blank"
:class="[theme.FlatSelectInput.icon,theme.FlatSelectInput.unselectedIcon]"
/>
</template>
<template v-else>
<Icon
v-if="isSelected(option[optionKey])"
name="material-symbols:radio-button-checked-outline"
class="text-inherit"
:color="color"
:class="[theme.FlatSelectInput.icon]"
/>
<Icon
v-else
name="material-symbols:radio-button-unchecked"
:class="[theme.FlatSelectInput.icon,theme.FlatSelectInput.unselectedIcon]"
/>
</template>
<p class="flex-grow">
{{ option[displayKey] }}
</p>
</div>
</template>
<div
v-for="(option) in options"
:key="option[optionKey]"
:role="multiple?'checkbox':'radio'"
:aria-checked="isSelected(option[optionKey])"
:class="[
theme.FlatSelectInput.spacing.vertical,
theme.FlatSelectInput.fontSize,
theme.FlatSelectInput.option,
]"
@click="onSelect(option[optionKey])"
>
<template v-if="multiple">
<CheckboxIcon
:is-checked="isSelected(option[optionKey])"
:color="color"
:theme="theme"
/>
</template>
<template v-else>
<RadioButtonIcon
:is-checked="isSelected(option[optionKey])"
:color="color"
:theme="theme"
/>
</template>
<p class="flex-grow">
{{ option[displayKey] }}
</p>
</div>
</template>
<div
v-else
:class="[
@@ -96,13 +81,15 @@
<script>
import {inputProps, useFormInput} from "./useFormInput.js"
import InputWrapper from "./components/InputWrapper.vue"
import RadioButtonIcon from "./components/RadioButtonIcon.vue"
import CheckboxIcon from "./components/CheckboxIcon.vue"
/**
* Options: {name,value} objects
*/
export default {
name: "FlatSelectInput",
components: {InputWrapper},
components: {InputWrapper, RadioButtonIcon, CheckboxIcon},
props: {
...inputProps,
@@ -156,4 +143,4 @@ export default {
},
},
}
</script>
</script>

View File

@@ -0,0 +1,121 @@
<template>
<input-wrapper v-bind="inputWrapperProps">
<template #label>
<slot name="label" />
</template>
<div
class="border border-gray-300"
:class="[
theme.default.borderRadius,
{
'!ring-red-500 !ring-2 !border-transparent': hasError,
'!cursor-not-allowed !bg-gray-300': disabled,
},
]"
>
<table
class="w-full table-fixed overflow-hidden"
>
<thead class="">
<tr>
<th />
<td
v-for="column in columns"
:key="column"
class="border-l border-gray-300"
>
<div class="p-2 w-full flex items-center justify-center capitalize text-sm truncate">
{{ column }}
</div>
</td>
</tr>
</thead>
<tbody>
<tr
v-for="row, rowIndex in rows"
:key="rowIndex"
class="border-t border-gray-300"
>
<td>
<div class="w-full flex-grow p-2 text-sm truncate">
{{ row }}
</div>
</td>
<td
v-for="column in columns"
:key="row + column"
class="border-l border-gray-300 hover:!bg-gray-100 dark:hover:!bg-gray-800"
>
<div
v-if="compVal"
class="w-full flex items-center justify-center"
role="radio"
:aria-checked="compVal[row] === column"
:class="[
theme.FlatSelectInput.spacing.vertical,
theme.FlatSelectInput.fontSize,
theme.FlatSelectInput.option,
]"
@click="onSelect(row, column)"
>
<RadioButtonIcon
:key="row+column"
:is-checked="compVal[row] === column"
:color="color"
:theme="theme"
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<template #help>
<slot name="help" />
</template>
<template #error>
<slot name="error" />
</template>
</input-wrapper>
</template>
<script>
import {inputProps, useFormInput} from "./useFormInput.js"
import InputWrapper from "./components/InputWrapper.vue"
import RadioButtonIcon from "./components/RadioButtonIcon.vue"
export default {
name: "MatrixInput",
components: {InputWrapper, RadioButtonIcon},
props: {
...inputProps,
rows: {type: Array, required: true},
columns: {type: Array, required: true},
},
setup(props, context) {
return {
...useFormInput(props, context),
}
},
data() {
return {
}
},
computed: {},
beforeMount() {
if (!this.compVal || typeof this.compVal !== 'object') {
this.compVal = {}
}
},
methods: {
onSelect(row, column) {
if (this.compVal[row] === column && !this.required) {
this.compVal[row] = null
} else {
this.compVal[row] = column
}
},
},
}
</script>

View File

@@ -0,0 +1,27 @@
<template>
<Icon
:name="isChecked ? 'material-symbols:check-box' : 'material-symbols:check-box-outline-blank'"
:class="[
theme.FlatSelectInput.icon,
isChecked ? '' : theme.FlatSelectInput.unselectedIcon,
]"
:color="isChecked ? color : undefined"
/>
</template>
<script setup>
const props = defineProps({
isChecked: {
type: Boolean,
required: true
},
color: {
type: String,
default: ''
},
theme: {
type: Object,
required: true
}
})
</script>

View File

@@ -0,0 +1,29 @@
<template>
<Icon
:name="isChecked ? 'ic:round-radio-button-checked' : 'ic:round-radio-button-unchecked'"
:class="[
theme.FlatSelectInput.icon,
isChecked ? '' : theme.FlatSelectInput.unselectedIcon,
]"
:color="isChecked ? color : undefined"
/>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
isChecked: {
type: Boolean,
required: true
},
color: {
type: String,
default: ''
},
theme: {
type: Object,
required: true
}
})
</script>