94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
import { TranslatedString } from "@gnu-taler/taler-util";
|
|
import { Fragment, VNode, h } from "preact";
|
|
import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js";
|
|
import { useField } from "./useField.js";
|
|
|
|
export interface Choice {
|
|
label: TranslatedString;
|
|
description?: TranslatedString;
|
|
value: string;
|
|
}
|
|
|
|
export function InputChoiceStacked(
|
|
props: {
|
|
choices: Choice[];
|
|
} & UIFormProps<string>,
|
|
): VNode {
|
|
const {
|
|
choices,
|
|
name,
|
|
label,
|
|
tooltip,
|
|
placeholder,
|
|
required,
|
|
before,
|
|
after,
|
|
converter,
|
|
} = props;
|
|
const { value, onChange, state, isDirty } = useField<{
|
|
[s: string]: undefined | string;
|
|
}>(name);
|
|
if (state.hidden) {
|
|
return <Fragment />;
|
|
}
|
|
|
|
return (
|
|
<div class="sm:col-span-6">
|
|
<LabelWithTooltipMaybeRequired
|
|
label={label}
|
|
required={required}
|
|
tooltip={tooltip}
|
|
/>
|
|
<fieldset class="mt-2">
|
|
<div class="space-y-4">
|
|
{choices.map((choice) => {
|
|
let clazz =
|
|
"border relative block cursor-pointer rounded-lg bg-white px-6 py-4 shadow-sm focus:outline-none sm:flex sm:justify-between";
|
|
if (choice.value === value) {
|
|
clazz +=
|
|
" border-transparent border-indigo-600 ring-2 ring-indigo-600";
|
|
} else {
|
|
clazz += " border-gray-300";
|
|
}
|
|
return (
|
|
<label class={clazz}>
|
|
<input
|
|
type="radio"
|
|
name="server-size"
|
|
defaultValue={choice.value}
|
|
onClick={(e) => {
|
|
onChange(value === choice.value ? undefined : choice.value);
|
|
}}
|
|
class="sr-only"
|
|
aria-labelledby="server-size-0-label"
|
|
aria-describedby="server-size-0-description-0 server-size-0-description-1"
|
|
/>
|
|
<span class="flex items-center">
|
|
<span class="flex flex-col text-sm">
|
|
<span
|
|
id="server-size-0-label"
|
|
class="font-medium text-gray-900"
|
|
>
|
|
{choice.label}
|
|
</span>
|
|
{choice.description !== undefined && (
|
|
<span
|
|
id="server-size-0-description-0"
|
|
class="text-gray-500"
|
|
>
|
|
<span class="block sm:inline">
|
|
{choice.description}
|
|
</span>
|
|
</span>
|
|
)}
|
|
</span>
|
|
</span>
|
|
</label>
|
|
);
|
|
})}
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
);
|
|
}
|