fix break on build
This commit is contained in:
parent
0544b8358a
commit
3e95ae356a
@ -71,17 +71,15 @@ function Option({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InputArray(
|
export function InputArray<T extends object, K extends keyof T>(
|
||||||
props: {
|
props: {
|
||||||
fields: UIFormField[];
|
fields: UIFormField[];
|
||||||
labelField: string;
|
labelField: string;
|
||||||
} & UIFormProps<Array<{}>>,
|
} & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const { fields, labelField, name, label, required, tooltip } = props;
|
const { fields, labelField, name, label, required, tooltip } = props;
|
||||||
const { value, onChange, state } = useField<{ [s: string]: Array<any> }>(
|
const { value, onChange, state } = useField<T, K>(name);
|
||||||
name,
|
const list = (value ?? []) as Array<Record<string, string | undefined>>;
|
||||||
);
|
|
||||||
const list = value ?? [];
|
|
||||||
const [selectedIndex, setSelected] = useState<number | undefined>(undefined);
|
const [selectedIndex, setSelected] = useState<number | undefined>(undefined);
|
||||||
const selected =
|
const selected =
|
||||||
selectedIndex === undefined ? undefined : list[selectedIndex];
|
selectedIndex === undefined ? undefined : list[selectedIndex];
|
||||||
@ -98,7 +96,7 @@ export function InputArray(
|
|||||||
{list.map((v, idx) => {
|
{list.map((v, idx) => {
|
||||||
return (
|
return (
|
||||||
<Option
|
<Option
|
||||||
label={v[labelField]}
|
label={v[labelField] as TranslatedString}
|
||||||
isSelected={selectedIndex === idx}
|
isSelected={selectedIndex === idx}
|
||||||
isLast={idx === list.length - 1}
|
isLast={idx === list.length - 1}
|
||||||
disabled={selectedIndex !== undefined && selectedIndex !== idx}
|
disabled={selectedIndex !== undefined && selectedIndex !== idx}
|
||||||
@ -141,10 +139,16 @@ export function InputArray(
|
|||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return state.elements[selectedIndex];
|
return state.elements[selectedIndex];
|
||||||
}}
|
}}
|
||||||
|
onSubmit={(v) => {
|
||||||
|
const newValue = [...list];
|
||||||
|
newValue.splice(selectedIndex, 1, v);
|
||||||
|
onChange(newValue as T[K]);
|
||||||
|
setSelected(undefined);
|
||||||
|
}}
|
||||||
onUpdate={(v) => {
|
onUpdate={(v) => {
|
||||||
const newValue = [...list];
|
const newValue = [...list];
|
||||||
newValue.splice(selectedIndex, 1, v);
|
newValue.splice(selectedIndex, 1, v);
|
||||||
onChange(newValue);
|
onChange(newValue as T[K]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="px-4 py-6">
|
<div class="px-4 py-6">
|
||||||
@ -163,7 +167,7 @@ export function InputArray(
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newValue = [...list];
|
const newValue = [...list];
|
||||||
newValue.splice(selectedIndex, 1);
|
newValue.splice(selectedIndex, 1);
|
||||||
onChange(newValue);
|
onChange(newValue as T[K]);
|
||||||
setSelected(undefined);
|
setSelected(undefined);
|
||||||
}}
|
}}
|
||||||
class="block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 "
|
class="block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 "
|
||||||
|
@ -9,10 +9,10 @@ export interface Choice {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InputChoiceStacked(
|
export function InputChoiceStacked<T extends object, K extends keyof T>(
|
||||||
props: {
|
props: {
|
||||||
choices: Choice[];
|
choices: Choice[];
|
||||||
} & UIFormProps<string>,
|
} & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const {
|
const {
|
||||||
choices,
|
choices,
|
||||||
@ -26,9 +26,7 @@ export function InputChoiceStacked(
|
|||||||
after,
|
after,
|
||||||
converter,
|
converter,
|
||||||
} = props;
|
} = props;
|
||||||
const { value, onChange, state, isDirty } = useField<{
|
const { value, onChange, state, isDirty } = useField<T, K>(name);
|
||||||
[s: string]: undefined | string;
|
|
||||||
}>(name);
|
|
||||||
if (state.hidden) {
|
if (state.hidden) {
|
||||||
return <Fragment />;
|
return <Fragment />;
|
||||||
}
|
}
|
||||||
@ -58,7 +56,11 @@ export function InputChoiceStacked(
|
|||||||
name="server-size"
|
name="server-size"
|
||||||
defaultValue={choice.value}
|
defaultValue={choice.value}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
onChange(value === choice.value ? undefined : choice.value);
|
onChange(
|
||||||
|
(value === choice.value
|
||||||
|
? undefined
|
||||||
|
: choice.value) as T[K],
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
class="sr-only"
|
class="sr-only"
|
||||||
aria-labelledby="server-size-0-label"
|
aria-labelledby="server-size-0-label"
|
||||||
|
@ -4,24 +4,26 @@ import { CalendarIcon } from "@heroicons/react/24/outline";
|
|||||||
import { VNode, h } from "preact";
|
import { VNode, h } from "preact";
|
||||||
import { format, parse } from "date-fns";
|
import { format, parse } from "date-fns";
|
||||||
|
|
||||||
export function InputDate(
|
export function InputDate<T extends object, K extends keyof T>(
|
||||||
props: { pattern?: string } & UIFormProps<AbsoluteTime>,
|
props: { pattern?: string } & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const pattern = props.pattern ?? "dd/MM/yyyy";
|
const pattern = props.pattern ?? "dd/MM/yyyy";
|
||||||
return (
|
return (
|
||||||
<InputLine<AbsoluteTime>
|
<InputLine<T, K>
|
||||||
type="text"
|
type="text"
|
||||||
after={{
|
after={{
|
||||||
type: "icon",
|
type: "icon",
|
||||||
icon: <CalendarIcon class="h-6 w-6" />,
|
icon: <CalendarIcon class="h-6 w-6" />,
|
||||||
}}
|
}}
|
||||||
converter={{
|
converter={{
|
||||||
fromStringUI: (v) => {
|
//@ts-ignore
|
||||||
|
fromStringUI: (v): AbsoluteTime => {
|
||||||
if (!v) return { t_ms: "never" };
|
if (!v) return { t_ms: "never" };
|
||||||
const t_ms = parse(v, pattern, Date.now()).getTime();
|
const t_ms = parse(v, pattern, Date.now()).getTime();
|
||||||
return { t_ms };
|
return { t_ms };
|
||||||
},
|
},
|
||||||
toStringUI: (v) => {
|
//@ts-ignore
|
||||||
|
toStringUI: (v: AbsoluteTime) => {
|
||||||
return !v || !v.t_ms
|
return !v || !v.t_ms
|
||||||
? ""
|
? ""
|
||||||
: v.t_ms === "never"
|
: v.t_ms === "never"
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { Fragment, VNode, h } from "preact";
|
import { Fragment, VNode, h } from "preact";
|
||||||
import {
|
import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js";
|
||||||
InputLine,
|
|
||||||
LabelWithTooltipMaybeRequired,
|
|
||||||
UIFormProps,
|
|
||||||
} from "./InputLine.js";
|
|
||||||
import { useField } from "./useField.js";
|
import { useField } from "./useField.js";
|
||||||
|
|
||||||
export function InputFile(
|
export function InputFile<T extends object, K extends keyof T>(
|
||||||
props: { maxBites: number; accept?: string } & UIFormProps<string>,
|
props: { maxBites: number; accept?: string } & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
@ -19,7 +15,7 @@ export function InputFile(
|
|||||||
maxBites,
|
maxBites,
|
||||||
accept,
|
accept,
|
||||||
} = props;
|
} = props;
|
||||||
const { value, onChange, state } = useField<{ [s: string]: string }>(name);
|
const { value, onChange, state } = useField<T, K>(name);
|
||||||
|
|
||||||
if (state.hidden) {
|
if (state.hidden) {
|
||||||
return <div />;
|
return <div />;
|
||||||
@ -31,7 +27,7 @@ export function InputFile(
|
|||||||
tooltip={tooltip}
|
tooltip={tooltip}
|
||||||
required={required}
|
required={required}
|
||||||
/>
|
/>
|
||||||
{!value || !value.startsWith("data:image/") ? (
|
{!value || !(value as string).startsWith("data:image/") ? (
|
||||||
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 py-1">
|
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 py-1">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<svg
|
<svg
|
||||||
@ -84,7 +80,10 @@ export function InputFile(
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 relative">
|
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 relative">
|
||||||
<img src={value} class=" h-24 w-full object-cover relative" />
|
<img
|
||||||
|
src={value as string}
|
||||||
|
class=" h-24 w-full object-cover relative"
|
||||||
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="opacity-0 hover:opacity-70 duration-300 absolute rounded-lg border inset-0 z-10 flex justify-center text-xl items-center bg-black text-white cursor-pointer "
|
class="opacity-0 hover:opacity-70 duration-300 absolute rounded-lg border inset-0 z-10 flex justify-center text-xl items-center bg-black text-white cursor-pointer "
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import { VNode, h } from "preact";
|
import { VNode, h } from "preact";
|
||||||
import { InputLine, UIFormProps } from "./InputLine.js";
|
import { InputLine, UIFormProps } from "./InputLine.js";
|
||||||
|
|
||||||
export function InputInteger(props: UIFormProps<number>): VNode {
|
export function InputInteger<T extends object, K extends keyof T>(
|
||||||
|
props: UIFormProps<T, K>,
|
||||||
|
): VNode {
|
||||||
return (
|
return (
|
||||||
<InputLine
|
<InputLine
|
||||||
type="number"
|
type="number"
|
||||||
converter={{
|
converter={{
|
||||||
fromStringUI: (v) => {
|
//@ts-ignore
|
||||||
|
fromStringUI: (v): number => {
|
||||||
return !v ? 0 : Number.parseInt(v, 10);
|
return !v ? 0 : Number.parseInt(v, 10);
|
||||||
},
|
},
|
||||||
toStringUI: (v?: number) => {
|
//@ts-ignore
|
||||||
|
toStringUI: (v?: number): string => {
|
||||||
return v === undefined ? "" : String(v);
|
return v === undefined ? "" : String(v);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
@ -22,8 +22,8 @@ interface StringConverter<T> {
|
|||||||
fromStringUI: (v?: string) => T;
|
fromStringUI: (v?: string) => T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UIFormProps<T> {
|
export interface UIFormProps<T extends object, K extends keyof T> {
|
||||||
name: keyof T;
|
name: K;
|
||||||
label: TranslatedString;
|
label: TranslatedString;
|
||||||
placeholder?: TranslatedString;
|
placeholder?: TranslatedString;
|
||||||
tooltip?: TranslatedString;
|
tooltip?: TranslatedString;
|
||||||
@ -31,7 +31,7 @@ export interface UIFormProps<T> {
|
|||||||
before?: Addon;
|
before?: Addon;
|
||||||
after?: Addon;
|
after?: Addon;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
converter?: StringConverter<T>;
|
converter?: StringConverter<T[K]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormErrors<T> = {
|
export type FormErrors<T> = {
|
||||||
@ -102,7 +102,7 @@ export function LabelWithTooltipMaybeRequired({
|
|||||||
return WithTooltip;
|
return WithTooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
function InputWrapper<T>({
|
function InputWrapper<T extends object, K extends keyof T>({
|
||||||
children,
|
children,
|
||||||
label,
|
label,
|
||||||
tooltip,
|
tooltip,
|
||||||
@ -111,7 +111,7 @@ function InputWrapper<T>({
|
|||||||
help,
|
help,
|
||||||
error,
|
error,
|
||||||
required,
|
required,
|
||||||
}: { error?: string; children: ComponentChildren } & UIFormProps<T>): VNode {
|
}: { error?: string; children: ComponentChildren } & UIFormProps<T, K>): VNode {
|
||||||
return (
|
return (
|
||||||
<div class="sm:col-span-6">
|
<div class="sm:col-span-6">
|
||||||
<LabelWithTooltipMaybeRequired
|
<LabelWithTooltipMaybeRequired
|
||||||
@ -181,13 +181,13 @@ function defaultFromString(v: string) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
type InputType = "text" | "text-area" | "password" | "email";
|
type InputType = "text" | "text-area" | "password" | "email" | "number";
|
||||||
|
|
||||||
export function InputLine<T>(
|
export function InputLine<T extends object, K extends keyof T>(
|
||||||
props: { type: InputType } & UIFormProps<T>,
|
props: { type: InputType } & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const { name, placeholder, before, after, converter, type } = props;
|
const { name, placeholder, before, after, converter, type } = props;
|
||||||
const { value, onChange, state, isDirty } = useField(name);
|
const { value, onChange, state, isDirty } = useField<T, K>(name);
|
||||||
|
|
||||||
if (state.hidden) return <div />;
|
if (state.hidden) return <div />;
|
||||||
|
|
||||||
@ -239,7 +239,10 @@ export function InputLine<T>(
|
|||||||
|
|
||||||
if (type === "text-area") {
|
if (type === "text-area") {
|
||||||
return (
|
return (
|
||||||
<InputWrapper<T> {...props} error={showError ? state.error : undefined}>
|
<InputWrapper<T, K>
|
||||||
|
{...props}
|
||||||
|
error={showError ? state.error : undefined}
|
||||||
|
>
|
||||||
<textarea
|
<textarea
|
||||||
rows={4}
|
rows={4}
|
||||||
name={String(name)}
|
name={String(name)}
|
||||||
@ -258,7 +261,7 @@ export function InputLine<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputWrapper<T> {...props} error={showError ? state.error : undefined}>
|
<InputWrapper<T, K> {...props} error={showError ? state.error : undefined}>
|
||||||
<input
|
<input
|
||||||
name={String(name)}
|
name={String(name)}
|
||||||
type={type}
|
type={type}
|
||||||
|
@ -4,16 +4,16 @@ import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js";
|
|||||||
import { useField } from "./useField.js";
|
import { useField } from "./useField.js";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
export function InputSelectMultiple(
|
export function InputSelectMultiple<T extends object, K extends keyof T>(
|
||||||
props: {
|
props: {
|
||||||
choices: Choice[];
|
choices: Choice[];
|
||||||
unique?: boolean;
|
unique?: boolean;
|
||||||
max?: number;
|
max?: number;
|
||||||
} & UIFormProps<Array<string>>,
|
} & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const { name, label, choices, placeholder, tooltip, required, unique, max } =
|
const { name, label, choices, placeholder, tooltip, required, unique, max } =
|
||||||
props;
|
props;
|
||||||
const { value, onChange } = useField<{ [s: string]: Array<string> }>(name);
|
const { value, onChange } = useField<T, K>(name);
|
||||||
|
|
||||||
const [filter, setFilter] = useState<string | undefined>(undefined);
|
const [filter, setFilter] = useState<string | undefined>(undefined);
|
||||||
const regex = new RegExp(`.*${filter}.*`, "i");
|
const regex = new RegExp(`.*${filter}.*`, "i");
|
||||||
@ -21,7 +21,7 @@ export function InputSelectMultiple(
|
|||||||
return { ...prev, [curr.value]: curr.label };
|
return { ...prev, [curr.value]: curr.label };
|
||||||
}, {} as Record<string, string>);
|
}, {} as Record<string, string>);
|
||||||
|
|
||||||
const list = value ?? [];
|
const list = (value ?? []) as string[];
|
||||||
const filteredChoices =
|
const filteredChoices =
|
||||||
filter === undefined
|
filter === undefined
|
||||||
? undefined
|
? undefined
|
||||||
@ -44,7 +44,7 @@ export function InputSelectMultiple(
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newValue = [...list];
|
const newValue = [...list];
|
||||||
newValue.splice(idx, 1);
|
newValue.splice(idx, 1);
|
||||||
onChange(newValue);
|
onChange(newValue as T[K]);
|
||||||
setFilter(undefined);
|
setFilter(undefined);
|
||||||
}}
|
}}
|
||||||
class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
|
class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
|
||||||
@ -119,7 +119,7 @@ export function InputSelectMultiple(
|
|||||||
}
|
}
|
||||||
const newValue = [...list];
|
const newValue = [...list];
|
||||||
newValue.splice(0, 0, v.value);
|
newValue.splice(0, 0, v.value);
|
||||||
onChange(newValue);
|
onChange(newValue as T[K]);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// tabindex="-1"
|
// tabindex="-1"
|
||||||
|
@ -4,15 +4,13 @@ import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js";
|
|||||||
import { useField } from "./useField.js";
|
import { useField } from "./useField.js";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
export function InputSelectOne(
|
export function InputSelectOne<T extends object, K extends keyof T>(
|
||||||
props: {
|
props: {
|
||||||
choices: Choice[];
|
choices: Choice[];
|
||||||
} & UIFormProps<Array<string>>,
|
} & UIFormProps<T, K>,
|
||||||
): VNode {
|
): VNode {
|
||||||
const { name, label, choices, placeholder, tooltip, required } = props;
|
const { name, label, choices, placeholder, tooltip, required } = props;
|
||||||
const { value, onChange } = useField<{ [s: string]: string | undefined }>(
|
const { value, onChange } = useField<T, K>(name);
|
||||||
name,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [filter, setFilter] = useState<string | undefined>(undefined);
|
const [filter, setFilter] = useState<string | undefined>(undefined);
|
||||||
const regex = new RegExp(`.*${filter}.*`, "i");
|
const regex = new RegExp(`.*${filter}.*`, "i");
|
||||||
@ -35,11 +33,11 @@ export function InputSelectOne(
|
|||||||
/>
|
/>
|
||||||
{value ? (
|
{value ? (
|
||||||
<span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mr-2 font-medium text-gray-600">
|
<span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mr-2 font-medium text-gray-600">
|
||||||
{choiceMap[value]}
|
{choiceMap[value as string]}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onChange(undefined);
|
onChange(undefined!);
|
||||||
}}
|
}}
|
||||||
class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
|
class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
|
||||||
>
|
>
|
||||||
@ -103,7 +101,7 @@ export function InputSelectOne(
|
|||||||
role="option"
|
role="option"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setFilter(undefined);
|
setFilter(undefined);
|
||||||
onChange(v.value);
|
onChange(v.value as T[K]);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// tabindex="-1"
|
// tabindex="-1"
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { VNode, h } from "preact";
|
import { VNode, h } from "preact";
|
||||||
import { InputLine, UIFormProps } from "./InputLine.js";
|
import { InputLine, UIFormProps } from "./InputLine.js";
|
||||||
|
|
||||||
export function InputText<T>(props: UIFormProps<T>): VNode {
|
export function InputText<T extends object, K extends keyof T>(
|
||||||
|
props: UIFormProps<T, K>,
|
||||||
|
): VNode {
|
||||||
return <InputLine type="text" {...props} />;
|
return <InputLine type="text" {...props} />;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { VNode, h } from "preact";
|
import { VNode, h } from "preact";
|
||||||
import { InputLine, UIFormProps } from "./InputLine.js";
|
import { InputLine, UIFormProps } from "./InputLine.js";
|
||||||
|
|
||||||
export function InputTextArea(props: UIFormProps<string>): VNode {
|
export function InputTextArea<T extends object, K extends keyof T>(
|
||||||
|
props: UIFormProps<T, K>,
|
||||||
|
): VNode {
|
||||||
return <InputLine type="text-area" {...props} />;
|
return <InputLine type="text-area" {...props} />;
|
||||||
}
|
}
|
||||||
|
@ -25,18 +25,18 @@ type DoubleColumnFormSection = {
|
|||||||
/**
|
/**
|
||||||
* Constrain the type with the ui props
|
* Constrain the type with the ui props
|
||||||
*/
|
*/
|
||||||
type FieldType = {
|
type FieldType<T extends object = any, K extends keyof T = any> = {
|
||||||
group: Parameters<typeof Group>[0];
|
group: Parameters<typeof Group>[0];
|
||||||
caption: Parameters<typeof Caption>[0];
|
caption: Parameters<typeof Caption>[0];
|
||||||
array: Parameters<typeof InputArray>[0];
|
array: Parameters<typeof InputArray<T, K>>[0];
|
||||||
file: Parameters<typeof InputFile>[0];
|
file: Parameters<typeof InputFile<T, K>>[0];
|
||||||
selectOne: Parameters<typeof InputSelectOne>[0];
|
selectOne: Parameters<typeof InputSelectOne<T, K>>[0];
|
||||||
selectMultiple: Parameters<typeof InputSelectMultiple>[0];
|
selectMultiple: Parameters<typeof InputSelectMultiple<T, K>>[0];
|
||||||
text: Parameters<typeof InputText>[0];
|
text: Parameters<typeof InputText<T, K>>[0];
|
||||||
textArea: Parameters<typeof InputTextArea>[0];
|
textArea: Parameters<typeof InputTextArea<T, K>>[0];
|
||||||
choiceStacked: Parameters<typeof InputChoiceStacked>[0];
|
choiceStacked: Parameters<typeof InputChoiceStacked<T, K>>[0];
|
||||||
date: Parameters<typeof InputDate>[0];
|
date: Parameters<typeof InputDate<T, K>>[0];
|
||||||
integer: Parameters<typeof InputInteger>[0];
|
integer: Parameters<typeof InputInteger<T, K>>[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,14 +69,20 @@ type UIFormFieldMap = {
|
|||||||
const UIFormConfiguration: UIFormFieldMap = {
|
const UIFormConfiguration: UIFormFieldMap = {
|
||||||
group: Group,
|
group: Group,
|
||||||
caption: Caption,
|
caption: Caption,
|
||||||
|
//@ts-ignore
|
||||||
array: InputArray,
|
array: InputArray,
|
||||||
text: InputText,
|
text: InputText,
|
||||||
|
//@ts-ignore
|
||||||
file: InputFile,
|
file: InputFile,
|
||||||
textArea: InputTextArea,
|
textArea: InputTextArea,
|
||||||
|
//@ts-ignore
|
||||||
date: InputDate,
|
date: InputDate,
|
||||||
|
//@ts-ignore
|
||||||
choiceStacked: InputChoiceStacked,
|
choiceStacked: InputChoiceStacked,
|
||||||
integer: InputInteger,
|
integer: InputInteger,
|
||||||
|
//@ts-ignore
|
||||||
selectOne: InputSelectOne,
|
selectOne: InputSelectOne,
|
||||||
|
//@ts-ignore
|
||||||
selectMultiple: InputSelectMultiple,
|
selectMultiple: InputSelectMultiple,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,11 +103,11 @@ export function RenderAllFieldsByUiConfig({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormSet<T> = {
|
type FormSet<T extends object, K extends keyof T = any> = {
|
||||||
Provider: typeof FormProvider<T>;
|
Provider: typeof FormProvider<T>;
|
||||||
InputLine: typeof InputLine<T>;
|
InputLine: typeof InputLine<T, K>;
|
||||||
};
|
};
|
||||||
export function createNewForm<T>(): FormSet<T> {
|
export function createNewForm<T extends object>(): FormSet<T> {
|
||||||
return {
|
return {
|
||||||
Provider: FormProvider,
|
Provider: FormProvider,
|
||||||
InputLine: InputLine,
|
InputLine: InputLine,
|
||||||
|
@ -12,7 +12,9 @@ export interface InputFieldHandler<Type> {
|
|||||||
isDirty: boolean;
|
isDirty: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useField<T>(name: keyof T): InputFieldHandler<T[keyof T]> {
|
export function useField<T extends object, K extends keyof T>(
|
||||||
|
name: K,
|
||||||
|
): InputFieldHandler<T[K]> {
|
||||||
const {
|
const {
|
||||||
initialValue,
|
initialValue,
|
||||||
value: formValue,
|
value: formValue,
|
||||||
@ -78,3 +80,28 @@ function setValueDeeper(object: any, names: string[], value: any): any {
|
|||||||
}
|
}
|
||||||
return { ...object, [head]: setValueDeeper(object[head] ?? {}, rest, value) };
|
return { ...object, [head]: setValueDeeper(object[head] ?? {}, rest, value) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TTT<T extends object, K extends keyof T, R> = K extends keyof T
|
||||||
|
? R extends T[K]
|
||||||
|
? number
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
|
||||||
|
function impl<T extends object, K extends keyof T, R extends T[K]>(
|
||||||
|
obj: T,
|
||||||
|
name: K,
|
||||||
|
): T[K] {
|
||||||
|
return obj[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Pepe {
|
||||||
|
name: string;
|
||||||
|
when: Date;
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
const p: Pepe = {
|
||||||
|
name: "n",
|
||||||
|
when: new Date(),
|
||||||
|
size: 1,
|
||||||
|
};
|
||||||
|
const a = impl(p, "size");
|
||||||
|
@ -122,15 +122,11 @@ const exampleData = {
|
|||||||
type: TransactionType.Refund,
|
type: TransactionType.Refund,
|
||||||
refundedTransactionId:
|
refundedTransactionId:
|
||||||
"payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
|
"payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
|
||||||
info: {
|
paymentInfo: {
|
||||||
contractTermsHash: "ASDZXCASD",
|
|
||||||
merchant: {
|
merchant: {
|
||||||
name: "the merchant",
|
name: "the merchant",
|
||||||
},
|
},
|
||||||
orderId: "2021.167-03NPY6MCYMVGT",
|
|
||||||
products: [],
|
|
||||||
summary: "the summary",
|
summary: "the summary",
|
||||||
fulfillmentMessage: "",
|
|
||||||
},
|
},
|
||||||
refundPending: undefined,
|
refundPending: undefined,
|
||||||
} as TransactionRefund,
|
} as TransactionRefund,
|
||||||
|
@ -148,15 +148,12 @@ const exampleData = {
|
|||||||
type: TransactionType.Refund,
|
type: TransactionType.Refund,
|
||||||
refundedTransactionId:
|
refundedTransactionId:
|
||||||
"payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
|
"payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
|
||||||
info: {
|
paymentInfo: {
|
||||||
contractTermsHash: "ASDZXCASD",
|
|
||||||
merchant: {
|
merchant: {
|
||||||
name: "the merchant",
|
name: "The merchant",
|
||||||
},
|
},
|
||||||
orderId: "2021.167-03NPY6MCYMVGT",
|
|
||||||
products: [],
|
|
||||||
summary: "Essay: Why the Devil's Advocate Doesn't Help Reach the Truth",
|
summary: "Essay: Why the Devil's Advocate Doesn't Help Reach the Truth",
|
||||||
fulfillmentMessage: "",
|
summary_i18n: {},
|
||||||
},
|
},
|
||||||
refundPending: undefined,
|
refundPending: undefined,
|
||||||
} as TransactionRefund,
|
} as TransactionRefund,
|
||||||
|
@ -823,30 +823,35 @@ export function TransactionView({
|
|||||||
total={effective}
|
total={effective}
|
||||||
kind="positive"
|
kind="positive"
|
||||||
>
|
>
|
||||||
{"transaction.info.summary"}
|
{transaction.paymentInfo ? (
|
||||||
</Header>
|
|
||||||
|
|
||||||
<Part
|
|
||||||
title={i18n.str`Merchant`}
|
|
||||||
text={"transaction.info.merchant.name" as TranslatedString}
|
|
||||||
kind="neutral"
|
|
||||||
/>
|
|
||||||
<Part
|
|
||||||
title={i18n.str`Original order ID`}
|
|
||||||
text={
|
|
||||||
<a
|
<a
|
||||||
href={Pages.balanceTransaction({
|
href={Pages.balanceTransaction({
|
||||||
tid: transaction.refundedTransactionId,
|
tid: transaction.refundedTransactionId,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{"transaction.info.orderId"}
|
{transaction.paymentInfo.summary}
|
||||||
</a>
|
</a>
|
||||||
|
) : (
|
||||||
|
<span style={{ color: "gray" }}>-- deleted --</span>
|
||||||
|
)}
|
||||||
|
</Header>
|
||||||
|
|
||||||
|
<Part
|
||||||
|
title={i18n.str`Merchant`}
|
||||||
|
text={
|
||||||
|
(transaction.paymentInfo
|
||||||
|
? transaction.paymentInfo.merchant.name
|
||||||
|
: "-- deleted --") as TranslatedString
|
||||||
}
|
}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={i18n.str`Purchase summary`}
|
title={i18n.str`Purchase summary`}
|
||||||
text={"transaction.info.summary" as TranslatedString}
|
text={
|
||||||
|
(transaction.paymentInfo
|
||||||
|
? transaction.paymentInfo.summary
|
||||||
|
: "-- deleted --") as TranslatedString
|
||||||
|
}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
|
@ -173,8 +173,6 @@ importers:
|
|||||||
postcss: ^8.4.23
|
postcss: ^8.4.23
|
||||||
postcss-cli: ^10.1.0
|
postcss-cli: ^10.1.0
|
||||||
preact: 10.11.3
|
preact: 10.11.3
|
||||||
preact-router: 3.2.1
|
|
||||||
qrcode-generator: ^1.4.4
|
|
||||||
swr: 2.0.3
|
swr: 2.0.3
|
||||||
tailwindcss: ^3.3.2
|
tailwindcss: ^3.3.2
|
||||||
typescript: 4.9.4
|
typescript: 4.9.4
|
||||||
@ -187,8 +185,6 @@ importers:
|
|||||||
history: 4.10.1
|
history: 4.10.1
|
||||||
jed: 1.1.1
|
jed: 1.1.1
|
||||||
preact: 10.11.3
|
preact: 10.11.3
|
||||||
preact-router: 3.2.1_preact@10.11.3
|
|
||||||
qrcode-generator: 1.4.4
|
|
||||||
swr: 2.0.3
|
swr: 2.0.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@gnu-taler/pogen': link:../pogen
|
'@gnu-taler/pogen': link:../pogen
|
||||||
|
Loading…
Reference in New Issue
Block a user