firefish/packages/client/src/components/form/radios.vue

125 lines
1.9 KiB
Vue

<script lang="ts">
import { type VNode, defineComponent, h } from "vue";
import MkRadio from "./radio.vue";
export default defineComponent({
components: {
MkRadio,
},
props: {
modelValue: {
required: false,
},
},
data() {
return {
value: this.modelValue,
};
},
watch: {
value() {
this.$emit("update:modelValue", this.value);
},
},
render() {
let options = this.$slots.default!();
const label = this.$slots.label && this.$slots.label!();
const caption = this.$slots.caption && this.$slots.caption!();
// なぜかFragmentになることがあるため
if (
options.length === 1 &&
options[0].props == null &&
Array.isArray(options[0].children)
)
options = options[0].children as VNode[];
return h(
"fieldset",
{
class: "novjtcto",
},
[
...(label
? [
h(
"legend",
{
class: "label",
},
[label],
),
]
: []),
h(
"div",
{
class: "body",
},
options.map((option) =>
h(
MkRadio,
{
// FIXME: It seems that there is a type error
key: option.key,
value: option.props?.value,
disabled: option.props?.disabled,
modelValue: this.value,
"onUpdate:modelValue": (value) => {
this.value = value;
return value;
},
},
option.children,
),
),
),
...(caption
? [
h(
"div",
{
class: "caption",
},
[caption],
),
]
: []),
],
);
},
});
</script>
<style lang="scss" scoped>
.novjtcto {
border: 0;
padding: 0;
> .label {
font-size: 0.85em;
padding: 0 0 8px 0;
user-select: none;
&:empty {
display: none;
}
}
> .body {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
> .caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--fgTransparentWeak);
&:empty {
display: none;
}
}
}
</style>