added checkbox

This commit is contained in:
2023-04-23 15:42:05 +10:00
parent 30c0caa04d
commit 50caf2753d
2 changed files with 156 additions and 262 deletions

View File

@@ -1,188 +0,0 @@
<template>
<SMControl class="control-type-checkbox">
<div :class="['control-item', { disabled: disabled }]">
<label class="control-label" v-bind="{ for: id }"
><input
type="checkbox"
class="checkbox-control"
:checked="props.modelValue"
@blur="handleBlur"
@input="handleInput" />
<span class="checkbox-control-box">
<span class="checkbox-control-tick"></span>
</span>
{{ label }}</label
>
</div>
{{ id }}
<template v-if="slots.help" #help><slot name="help"></slot></template>
</SMControl>
</template>
<script setup lang="ts">
import { inject, watch, ref, useSlots } from "vue";
import { isEmpty } from "../helpers/utils";
import { toTitleCase } from "../helpers/string";
import SMControl from "./SMControl.vue";
const emits = defineEmits(["update:modelValue", "blur"]);
const props = defineProps({
form: {
type: Object,
default: undefined,
required: false,
},
control: {
type: [String, Object],
default: "",
},
label: {
type: String,
default: undefined,
required: false,
},
modelValue: {
type: Boolean,
default: false,
required: true,
},
id: {
type: String,
default: undefined,
required: false,
},
disabled: {
type: Boolean,
default: false,
required: false,
},
});
const slots = useSlots();
const form = inject("form", props.form);
const control =
typeof props.control === "object"
? props.control
: !isEmpty(form) &&
typeof props.control === "string" &&
props.control !== "" &&
Object.prototype.hasOwnProperty.call(form.controls, props.control)
? form.controls[props.control]
: null;
const label = ref(
props.label != undefined
? props.label
: typeof props.control == "string"
? toTitleCase(props.control)
: ""
);
const value = ref(
props.modelValue != undefined
? props.modelValue
: control != null
? control.value
: ""
);
const id = ref(
props.id != undefined
? props.id
: typeof props.control == "string" && props.control.length > 0
? props.control
: null
);
const disabled = ref(props.disabled);
if (typeof control === "object" && control !== null) {
watch(
() => control.value,
(newValue) => {
value.value = newValue;
},
{ deep: true }
);
}
if (form) {
watch(
() => form.loading(),
(newValue) => {
disabled.value = newValue;
}
);
}
const handleBlur = async () => {
emits("blur");
};
const handleInput = (event: Event) => {
const target = event.target as HTMLInputElement;
value.value = target.checked;
emits("update:modelValue", target.checked);
if (control) {
control.value = target.checked;
}
};
</script>
<style lang="scss">
.control-group.control-type-checkbox {
.control-row {
.control-item {
.control-label {
display: flex;
align-items: center;
height: 24px;
padding-left: 32px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.checkbox-control {
opacity: 0;
width: 0;
height: 0;
&:checked + .checkbox-control-box {
.checkbox-control-tick {
display: block;
}
}
}
.checkbox-control-box {
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
border: 1px solid var(--base-color-darker);
border-radius: 2px;
background-color: var(--base-color-light);
.checkbox-control-tick {
position: absolute;
display: none;
border-right: 3px solid var(--base-color-text);
border-bottom: 3px solid var(--base-color-text);
top: 1px;
left: 7px;
width: 8px;
height: 16px;
transform: rotate(45deg);
}
}
}
&.disabled label {
cursor: not-allowed;
}
}
}
}
</style>

View File

@@ -6,83 +6,102 @@
<slot name="prepend"></slot> <slot name="prepend"></slot>
</div> </div>
<div class="control-item"> <div class="control-item">
<label class="control-label" v-bind="{ for: id }">{{ <template v-if="props.type == 'checkbox'">
label
}}</label>
<template v-if="props.type == 'static'">
<div class="static-input-control" v-bind="{ id: id }">
<span class="text">
{{ value }}
</span>
</div>
</template>
<template v-else-if="props.type == 'file'">
<input
:id="id"
type="file"
class="file-input-control"
:accept="props.accept"
@change="handleChange" />
<div class="file-input-control-value">
{{ value?.name ? value.name : value }}
</div>
<label <label
class="button primary file-input-control-button" class="control-label control-label-checkbox"
:for="id" v-bind="{ for: id }"
>Select file</label ><input
:id="id"
type="checkbox"
class="checkbox-control"
:value="value"
@input="handleCheckbox" />
<span class="checkbox-control-box">
<span class="checkbox-control-tick"></span> </span
>{{ label }}</label
> >
</template> </template>
<template v-else-if="props.type == 'textarea'">
<ion-icon
class="invalid-icon"
name="alert-circle-outline"></ion-icon>
<textarea
:type="props.type"
class="input-control"
:disabled="disabled"
v-bind="{ id: id, autofocus: props.autofocus }"
v-model="value"
rows="5"
@focus="handleFocus"
@blur="handleBlur"
@input="handleInput"
@keyup="handleKeyup"></textarea>
</template>
<template v-else-if="props.type == 'select'">
<ion-icon
class="select-dropdown-icon"
name="caret-down-outline" />
<select class="select-input-control">
<option
v-for="option in Object.entries(props.options)"
:key="option[0]"
:value="option[0]">
{{ option[1] }}
</option>
</select>
</template>
<template v-else> <template v-else>
<ion-icon <label class="control-label" v-bind="{ for: id }">{{
class="invalid-icon" label
name="alert-circle-outline"></ion-icon> }}</label>
<ion-icon <template v-if="props.type == 'static'">
v-if=" <div class="static-input-control" v-bind="{ id: id }">
props.showClear && value?.length > 0 && !feedbackInvalid <span class="text">
" {{ value }}
class="clear-icon" </span>
name="close-outline" </div>
@click.stop="handleClear"></ion-icon> </template>
<template v-else-if="props.type == 'file'">
<input
:id="id"
type="file"
class="file-input-control"
:accept="props.accept"
@change="handleChange" />
<div class="file-input-control-value">
{{ value?.name ? value.name : value }}
</div>
<label
class="button primary file-input-control-button"
:for="id"
>Select file</label
>
</template>
<template v-else-if="props.type == 'textarea'">
<ion-icon
class="invalid-icon"
name="alert-circle-outline"></ion-icon>
<textarea
:type="props.type"
class="input-control"
:disabled="disabled"
v-bind="{ id: id, autofocus: props.autofocus }"
v-model="value"
rows="5"
@focus="handleFocus"
@blur="handleBlur"
@input="handleInput"
@keyup="handleKeyup"></textarea>
</template>
<template v-else-if="props.type == 'select'">
<ion-icon
class="select-dropdown-icon"
name="caret-down-outline" />
<select class="select-input-control">
<option
v-for="option in Object.entries(props.options)"
:key="option[0]"
:value="option[0]">
{{ option[1] }}
</option>
</select>
</template>
<template v-else>
<ion-icon
class="invalid-icon"
name="alert-circle-outline"></ion-icon>
<ion-icon
v-if="
props.showClear &&
value?.length > 0 &&
!feedbackInvalid
"
class="clear-icon"
name="close-outline"
@click.stop="handleClear"></ion-icon>
<input <input
:type="props.type" :type="props.type"
class="input-control" class="input-control"
:disabled="disabled" :disabled="disabled"
v-bind="{ id: id, autofocus: props.autofocus }" v-bind="{ id: id, autofocus: props.autofocus }"
v-model="value" v-model="value"
@focus="handleFocus" @focus="handleFocus"
@blur="handleBlur" @blur="handleBlur"
@input="handleInput" @input="handleInput"
@keyup="handleKeyup" /> @keyup="handleKeyup" />
</template>
</template> </template>
</div> </div>
<div v-if="slots.append" class="input-control-append"> <div v-if="slots.append" class="input-control-append">
@@ -93,10 +112,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { inject, watch, ref, useSlots } from "vue"; import { inject, watch, ref, useSlots, computed } from "vue";
import { isEmpty, generateRandomElementId } from "../helpers/utils"; import { isEmpty, generateRandomElementId } from "../helpers/utils";
import { toTitleCase } from "../helpers/string"; import { toTitleCase } from "../helpers/string";
import SMControl from "./SMControl.vue"; import SMControl from "./SMControl.vue";
import { Booleanish } from "../helpers/api.types";
const emits = defineEmits(["update:modelValue", "blur", "keyup"]); const emits = defineEmits(["update:modelValue", "blur", "keyup"]);
const props = defineProps({ const props = defineProps({
@@ -196,7 +216,7 @@ const value = ref(
const id = ref( const id = ref(
props.id != undefined props.id != undefined
? props.id ? props.id
: typeof props.control == "string" : typeof props.control == "string" && props.control.length > 0
? props.control ? props.control
: generateRandomElementId() : generateRandomElementId()
); );
@@ -276,6 +296,18 @@ const handleBlur = async () => {
} }
}; };
const handleCheckbox = (event: Event) => {
console.log("here");
const target = event.target as HTMLInputElement;
value.value = target.checked;
emits("update:modelValue", target.checked);
if (control) {
control.value = target.checked;
feedbackInvalid.value = "";
}
};
const handleInput = (event: Event) => { const handleInput = (event: Event) => {
const target = event.target as HTMLInputElement; const target = event.target as HTMLInputElement;
value.value = target.value; value.value = target.value;
@@ -374,6 +406,11 @@ const handleChange = (event) => {
transition: all 0.1s ease-in-out; transition: all 0.1s ease-in-out;
color: var(--base-color-darker); color: var(--base-color-darker);
pointer-events: none; pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} }
.invalid-icon { .invalid-icon {
@@ -481,6 +518,51 @@ const handleChange = (event) => {
background-color: var(--base-color-light); background-color: var(--base-color-light);
height: 52px; height: 52px;
} }
.control-label-checkbox {
position: relative;
display: flex;
align-items: center;
padding: 16px 0 16px 32px;
pointer-events: all;
transform: none;
color: var(--base-color-text);
}
.checkbox-control {
opacity: 0;
width: 0;
height: 0;
&:checked + .checkbox-control-box {
.checkbox-control-tick {
display: block;
}
}
}
.checkbox-control-box {
position: absolute;
top: 14px;
left: 0;
width: 24px;
height: 24px;
border: 1px solid var(--base-color-darker);
border-radius: 2px;
background-color: var(--base-color-light);
.checkbox-control-tick {
position: absolute;
display: none;
border-right: 3px solid var(--base-color-text);
border-bottom: 3px solid var(--base-color-text);
top: 1px;
left: 7px;
width: 8px;
height: 16px;
transform: rotate(45deg);
}
}
} }
} }