npm i -g pnpm
Initialen Stand aus checken:
git clone https://github.com/public-ui/js-days-2023
pnpm create vite workshop --template react-ts
cd workshop
pnpm i
pnpm dev
Um leicht die Anwendung zu gestalten, integrieren wir UnoCSS.
pnpm add -D unocss
// uno.config.ts
import { defineConfig } from "unocss";
export default defineConfig({
// ...UnoCSS options
});
// vite.config.ts
import React from "@vitejs/plugin-react";
import UnoCSS from "unocss/vite";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [UnoCSS(), React()],
});
Geänderte Code-Stellen hervorheben
// vite.config.ts
import React from "@vitejs/plugin-react";
+ import UnoCSS from "unocss/vite";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ UnoCSS(),
React()],
});
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import "uno.css";
import App from "./App.tsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Geänderte Code-Stellen hervorheben
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
+ import "uno.css";
import App from "./App.tsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
pnpm add @public-ui/components@next @public-ui/react@next @public-ui/theme-default@next
VSCode TS-Server neu starten empfohlen.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script
type="module"
src="/node_modules/@public-ui/components/dist/kolibri/kolibri.esm.js"
></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Geänderte Code-Stellen hervorheben
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
+ <script
+ type="module"
+ src="/node_modules/@public-ui/components/dist/kolibri/kolibri.esm.js"
+ ></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Visual Studio Code
Damit IntelliSense für KoliBri im reinem HTML funktioniert, muss der
.vscode/settings.json
im Projekt folgende Einstellung hinzugefügt werden:// .vscode/settings.json { "html.customData": [ "./node_modules/@public-ui/components/dist/kolibri/kolibri.html-data.json" ] }
pnpm add @public-ui/theme-default@next
// src/main.tsx
import { register } from "@public-ui/components";
import { DEFAULT } from "@public-ui/theme-default";
import React from "react";
import ReactDOM from "react-dom/client";
import "uno.css";
import App from "./App.tsx";
import "./index.css";
register(DEFAULT, [])
.then(() => {
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
})
.catch(console.warn);
Geänderte Code-Stellen hervorheben
// src/main.tsx
+ import { register } from "@public-ui/components";
+ import { DEFAULT } from "@public-ui/theme-default";
import React from "react";
import ReactDOM from "react-dom/client";
import "uno.css";
import App from "./App.tsx";
import "./index.css";
+ register(DEFAULT, [])
+ .then(() => {
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
+ })
+ .catch(console.warn);
👉 https://github.com/public-ui/js-days-2023/pull/2/files
<!-- index.html -->
<!DOCTYPE html>
<html lang="de" dir="ltr">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script
type="module"
src="/node_modules/@public-ui/components/dist/kolibri/kolibri.esm.js"
></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Geänderte Code-Stellen hervorheben
<!-- index.html -->
<!DOCTYPE html>
+ <html lang="de" dir="ltr">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script
type="module"
src="/node_modules/@public-ui/components/dist/kolibri/kolibri.esm.js"
></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
// src/App.tsx
import { useState } from "react";
import "./App.css";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import { KolKolibri } from "@public-ui/react";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div className="flex place-end">
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
<a href="https://public-ui.github.io" target="_blank">
<KolKolibri className="block logo w-35" />
</a>
</div>
<h1>Vite + React + KoliBri</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
Geänderte Code-Stellen hervorheben
// src/App.tsx
import { useState } from "react";
import "./App.css";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
+ import { KolKolibri } from "@public-ui/react";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div className="flex place-end">
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
+ <a href="https://public-ui.github.io" target="_blank">
+ <KolKolibri className="block logo w-35" />
+ </a>
</div>
<h1>Vite + React + KoliBri</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
// src/App.tsx
import { useState } from "react";
import "./App.css";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import { KolButton, KolKolibri } from "@public-ui/react";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div className="flex place-end">
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
<a href="https://public-ui.github.io" target="_blank">
<KolKolibri className="block logo w-35" />
</a>
</div>
<h1>Vite + React + KoliBri</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<KolButton
_label={`count is ${count}`}
_on={{
onClick: () => setCount((count) => count + 1),
}}
/>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
Geänderte Code-Stellen hervorheben
// src/App.tsx
import { useState } from "react";
import "./App.css";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
+ import { KolButton, KolKolibri } from "@public-ui/react";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div className="flex place-end">
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
<a href="https://public-ui.github.io" target="_blank">
<KolKolibri className="block logo w-35" />
</a>
</div>
<h1>Vite + React + KoliBri</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
+ <KolButton
+ _label={`count is ${count}`}
+ _on={{
+ onClick: () => setCount((count) => count + 1),
+ }}
+ />
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
KoliBri arbeitet mit Fonts statt SVG (svg2font)
// src/App.tsx
<KolButton
_label={`count is ${count}`}
_icons="codicon codicon-thumbsup"
_on={{
onClick: () => setCount((count) => count + 1),
}}
/>
Geänderte Code-Stellen hervorheben
// src/App.tsx
<KolButton
_label={`count is ${count}`}
+ _icons="codicon codicon-thumbsup"
_on={{
onClick: () => setCount((count) => count + 1),
}}
/>
<!-- index.html -->
<!DOCTYPE html>
<html lang="de" dir="ltr">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script
type="module"
src="/node_modules/@public-ui/components/dist/kolibri/kolibri.esm.js"
></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@vscode/[email protected]/dist/codicon.min.css"
/>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Geänderte Code-Stellen hervorheben
<!-- index.html -->
<!DOCTYPE html>
<html lang="de" dir="ltr">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script
type="module"
src="/node_modules/@public-ui/components/dist/kolibri/kolibri.esm.js"
></script>
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@vscode/[email protected]/dist/codicon.min.css">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
👉 https://github.com/public-ui/js-days-2023/pull/3/files
Wir ersetzen den gesamten Quellcode in src/App.tsx
mit folgendem:
// src/App.tsx
import {
KolButton,
KolHeading,
KolInputDate,
KolInputNumber,
KolInputText,
} from "@public-ui/react";
import "./App.css";
import { ErrorList } from "./ErrorList";
function App() {
return (
<div className="flex flex-col gap-4">
<KolHeading _label="Tischreservierung" />
{/* https://public-ui.github.io/docs/concepts/formular */}
<form className="flex flex-col gap-4">
<div className="mt-2" tabIndex={0}>
<ErrorList errors={{}} />
</div>
<div className="grid md:grid-cols-2 gap-4">
<KolInputDate _label="Datum" _required />
<KolInputDate _label="Uhrzeit" _type="time" _required />
<KolInputNumber _label="Anzahl Personen" _min={1} _required />
<span />
{/* Über Label als Property zu sprechen . Robustheit, "echte" Barrierefreiheit */}
<KolInputText _label="Name" _required />
<KolInputText _label="Telefon" _required _type="tel" />
<hr className="col-span-2 w-full" />
<KolButton
_label="Anfrage absenden"
_type="submit"
_variant="primary"
/>
<KolButton _label="Zurücksetzen" _type="reset" _variant="secondary" />
</div>
</form>
</div>
);
}
export default App;
👉 https://github.com/public-ui/js-days-2023/pull/4/files
pnpm add formik
// src/App.tsx
import {
KolButton,
KolHeading,
KolInputDate,
KolInputNumber,
KolInputText,
} from "@public-ui/react";
import "./App.css";
import { ErrorList } from "./ErrorList";
import { InputTypeOnDefault, Iso8601 } from "@public-ui/components";
import { Formik, useFormikContext } from "formik";
type FormValues = {
date: Iso8601 | null;
time: Iso8601 | null;
numberOfPersons: number;
name: string;
phone: string;
};
const initialValues: FormValues = {
date: "2021-10-10",
time: "10:10",
numberOfPersons: 2,
name: "",
phone: "",
};
function Form() {
const form = useFormikContext<FormValues>();
const createOnChange = (name: keyof FormValues): InputTypeOnDefault => {
return {
onChange: (event: Event, value: unknown) => {
if (event.target) {
void form.setFieldValue(name, value, true);
}
},
};
};
return (
<form
className="flex flex-col gap-4"
onSubmit={() => {
form.handleSubmit();
}}
onReset={() => {
form.handleReset();
}}
>
<div className="mt-2" tabIndex={0}>
<ErrorList errors={{}} />
</div>
<div className="grid md:grid-cols-2 gap-4">
<KolInputDate
_label="Datum"
_required
_on={createOnChange("date")}
_value={form.values.date}
/>
<KolInputDate
_label="Uhrzeit"
_required
_type="time"
_on={createOnChange("time")}
_value={form.values.time}
/>
<KolInputNumber
_label="Anzahl Personen"
_min={1}
_required
_on={createOnChange("numberOfPersons")}
_value={form.values.numberOfPersons}
/>
<span />
<KolInputText
_label="Name"
_required
_on={createOnChange("name")}
_value={form.values.name}
/>
<KolInputText
_label="Telefon"
_required
_type="tel"
_on={createOnChange("phone")}
_value={form.values.phone}
/>
<hr className="col-span-2 w-full" />
<KolButton
_label="Anfrage absenden"
_type="submit"
_variant="primary"
/>
<KolButton _label="Zurücksetzen" _type="reset" _variant="secondary" />
</div>
<pre>{JSON.stringify(form.values, null, 2)}</pre>
</form>
);
}
function App() {
return (
<div className="flex flex-col gap-4">
<KolHeading _label="Tischreservierung" />
<Formik<FormValues>
initialValues={initialValues}
onSubmit={(values) => {
console.log(values);
}}
>
<Form />
</Formik>
</div>
);
}
export default App;
Geänderte Code-Stellen hervorheben
// src/App.tsx
import {
KolButton,
KolHeading,
KolInputDate,
KolInputNumber,
KolInputText,
} from "@public-ui/react";
import "./App.css";
import { ErrorList } from "./ErrorList";
+ import { InputTypeOnDefault, Iso8601 } from "@public-ui/components";
+ import { Formik, useFormikContext } from "formik";
+ type FormValues = {
+ date: Iso8601 | null;
+ time: Iso8601 | null;
+ numberOfPersons: number;
+ name: string;
+ phone: string;
+ };
+ const initialValues: FormValues = {
+ date: "2021-10-10",
+ time: "10:10",
+ numberOfPersons: 2,
+ name: "",
+ phone: "",
+ };
function Form() {
+ const form = useFormikContext<FormValues>();
+ const createOnChange = (name: keyof FormValues): InputTypeOnDefault => {
+ return {
+ onChange: (event: Event, value: unknown) => {
+ if (event.target) {
+ void form.setFieldValue(name, value, true);
+ }
+ },
+ };
+ };
+ return (
<form
className="flex flex-col gap-4"
+ onSubmit={() => {
+ form.handleSubmit();
+ }}
+ onReset={() => {
+ form.handleReset();
+ }}
>
<div className="mt-2" tabIndex={0}>
<ErrorList errors={{}} />
</div>
<div className="grid md:grid-cols-2 gap-4">
<KolInputDate
_label="Datum"
_required
+ _on={createOnChange("date")}
+ _value={form.values.date}
/>
<KolInputDate
_label="Uhrzeit"
_required
_type="time"
+ _on={createOnChange("time")}
+ _value={form.values.time}
/>
<KolInputNumber
_label="Anzahl Personen"
_min={1}
_required
+ _on={createOnChange("numberOfPersons")}
+ _value={form.values.numberOfPersons}
/>
<span />
<KolInputText
_label="Name"
_required
+ _on={createOnChange("name")}
+ _value={form.values.name}
/>
<KolInputText
_label="Telefon"
_required
_type="tel"
+ _on={createOnChange("phone")}
+ _value={form.values.phone}
/>
<hr className="col-span-2 w-full" />
<KolButton
_label="Anfrage absenden"
_type="submit"
_variant="primary"
/>
<KolButton _label="Zurücksetzen" _type="reset" _variant="secondary" />
</div>
+ <pre>{JSON.stringify(form.values, null, 2)}</pre>
</form>
);
}
function App() {
return (
<div className="flex flex-col gap-4">
<KolHeading _label="Tischreservierung" />
+ <Formik<FormValues>
+ initialValues={initialValues}
+ onSubmit={(values) => {
+ console.log(values);
+ }}
+ >
<Form />
+ </Formik>
</div>
);
}
export default App;
👉 https://github.com/public-ui/js-days-2023/pull/5/files
pnpm add yup
// src/App.tsx
import { InputTypeOnDefault, Iso8601 } from "@public-ui/components";
import {
KolButton,
KolHeading,
KolInputDate,
KolInputNumber,
KolInputText,
} from "@public-ui/react";
import { Formik, useFormikContext } from "formik";
import { useEffect, useMemo, useState } from "react";
import * as Yup from "yup";
import "./App.css";
import { ErrorList } from "./ErrorList";
type FormValues = {
date: Iso8601 | null;
time: Iso8601 | null;
numberOfPersons: number;
name: string;
phone: string;
};
const initialValues: FormValues = {
date: "2021-10-10",
time: "10:10",
numberOfPersons: 2,
name: "",
phone: "",
};
const terminSchema = {
date: Yup.string().required("Bitte Datum wählen."),
time: Yup.string().required("Bitte Zeit wählen."),
numberOfPersons: Yup.number()
.required("Bitte Personenanzahl wählen.")
.max(8, "Maximal 8 Personen."),
};
const contactSchema = {
name: Yup.string().required("Bitte Nachname eingeben."),
phone: Yup.string().required("Bitte Telefon eingeben."),
};
function Form() {
const form = useFormikContext<FormValues>();
const [errorList, setErrorList] = useState({
...form.errors,
});
const showErrorList = useMemo(
() => Object.keys(errorList).length > 0,
[errorList]
);
useEffect(() => {
if (errorList) {
const errorList = document.getElementById("error-list");
if (errorList) {
errorList.focus();
}
}
}, [errorList]);
const createOnChange = (name: keyof FormValues): InputTypeOnDefault => {
return {
onChange: (event: Event, value: unknown) => {
if (event.target) {
void form.setFieldValue(name, value, true);
}
},
};
};
// Hack to trigger validation on mount
useEffect(() => {
form.handleSubmit();
}, []);
const onSubmit = () => {
console.log(form.errors);
form.handleSubmit();
setErrorList({
...form.errors,
});
};
return (
<form
className="flex flex-col gap-4"
onSubmit={onSubmit}
onReset={() => {
setErrorList({});
form.handleReset();
form.handleSubmit(); // Hack to trigger validation on reset
}}
>
{showErrorList && (
<div className="mt-2" tabIndex={0} id="error-list">
<ErrorList errors={errorList} />
</div>
)}
<div className="grid md:grid-cols-2 gap-4">
<KolInputDate
id="field-date"
_label="Datum"
_required
_error={form.errors.date ?? ""}
_on={createOnChange("date")}
_touched={showErrorList}
_value={form.values.date}
/>
<KolInputDate
id="field-time"
_label="Uhrzeit"
_required
_type="time"
_error={form.errors.time ?? ""}
_on={createOnChange("time")}
_touched={showErrorList}
_value={form.values.time}
/>
<KolInputNumber
id="field-numberOfPersons"
_label="Anzahl Personen"
_min={1}
_required
_error={form.errors.numberOfPersons ?? ""}
_on={createOnChange("numberOfPersons")}
_touched={showErrorList}
_value={form.values.numberOfPersons}
/>
<span />
<KolInputText
id="field-name"
_label="Name"
_required
_error={form.errors.name ?? ""}
_on={createOnChange("name")}
_touched={showErrorList}
_value={form.values.name}
/>
<KolInputText
id="field-phone"
_label="Telefon"
_required
_type="tel"
_error={form.errors.phone ?? ""}
_on={createOnChange("phone")}
_touched={showErrorList}
_value={form.values.phone}
/>
<hr className="col-span-2 w-full" />
<KolButton
_label="Anfrage absenden"
_type="submit"
_variant="primary"
/>
<KolButton _label="Zurücksetzen" _type="reset" _variant="secondary" />
</div>
</form>
);
}
const validationSchema = Yup.object().shape({
...terminSchema,
...contactSchema,
});
function App() {
const onSubmit = (values: FormValues) => {
console.log("Valid form to sumbit", values);
};
return (
<div className="flex flex-col gap-4">
<KolHeading _label="Tischreservierung" />
<Formik<FormValues>
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
<Form />
</Formik>
</div>
);
}
export default App;
Geänderte Code-Stellen hervorheben
// src/App.tsx
+ import { InputTypeOnDefault, Iso8601 } from "@public-ui/components";
import {
KolButton,
KolHeading,
KolInputDate,
KolInputNumber,
KolInputText,
} from "@public-ui/react";
import { Formik, useFormikContext } from "formik";
+ import { useEffect, useMemo, useState } from "react";
+ import * as Yup from "yup";
import "./App.css";
import { ErrorList } from "./ErrorList";
type FormValues = {
date: Iso8601 | null;
time: Iso8601 | null;
numberOfPersons: number;
name: string;
phone: string;
};
const initialValues: FormValues = {
date: "2021-10-10",
time: "10:10",
numberOfPersons: 2,
name: "",
phone: "",
};
+ const terminSchema = {
+ date: Yup.string().required("Bitte Datum wählen."),
+ time: Yup.string().required("Bitte Zeit wählen."),
+ numberOfPersons: Yup.number()
+ .required("Bitte Personenanzahl wählen.")
+ .max(8, "Maximal 8 Personen."),
+ };
+ const contactSchema = {
+ name: Yup.string().required("Bitte Nachname eingeben."),
+ phone: Yup.string().required("Bitte Telefon eingeben."),
+ };
function Form() {
const form = useFormikContext<FormValues>();
+ const [errorList, setErrorList] = useState({
+ ...form.errors,
+ });
+ const showErrorList = useMemo(
+ () => Object.keys(errorList).length > 0,
+ [errorList]
+ );
+ useEffect(() => {
+ if (errorList) {
+ const errorList = document.getElementById("error-list");
+ if (errorList) {
+ errorList.focus();
+ }
+ }
+ }, [errorList]);
const createOnChange = (name: keyof FormValues): InputTypeOnDefault => {
return {
onChange: (event: Event, value: unknown) => {
if (event.target) {
void form.setFieldValue(name, value, true);
}
},
};
};
+ // Hack to trigger validation on mount
+ useEffect(() => {
+ form.handleSubmit();
+ }, []);
+ const onSubmit = () => {
+ console.log(form.errors);
+ form.handleSubmit();
+ setErrorList({
+ ...form.errors,
+ });
+ };
return (
<form
className="flex flex-col gap-4"
+ onSubmit={onSubmit}
onReset={() => {
+ setErrorList({});
form.handleReset();
+ form.handleSubmit(); // Hack to trigger validation on reset
}}
>
{showErrorList && (
<div className="mt-2" tabIndex={0} id="error-list">
+ <ErrorList errors={errorList} />
</div>
)}
<div className="grid md:grid-cols-2 gap-4">
<KolInputDate
+ id="field-date"
_label="Datum"
_required
+ _error={form.errors.date ?? ""}
_on={createOnChange("date")}
+ _touched={showErrorList}
_value={form.values.date}
/>
<KolInputDate
+ id="field-time"
_label="Uhrzeit"
_required
_type="time"
+ _error={form.errors.time ?? ""}
_on={createOnChange("time")}
+ _touched={showErrorList}
_value={form.values.time}
/>
<KolInputNumber
+ id="field-numberOfPersons"
_label="Anzahl Personen"
_min={1}
_required
+ _error={form.errors.numberOfPersons ?? ""}
_on={createOnChange("numberOfPersons")}
+ _touched={showErrorList}
_value={form.values.numberOfPersons}
/>
<span />
<KolInputText
+ id="field-name"
_label="Name"
_required
+ _error={form.errors.name ?? ""}
_on={createOnChange("name")}
+ _touched={showErrorList}
_value={form.values.name}
/>
<KolInputText
+ id="field-phone"
_label="Telefon"
_required
_type="tel"
+ _error={form.errors.phone ?? ""}
_on={createOnChange("phone")}
+ _touched={showErrorList}
_value={form.values.phone}
/>
<hr className="col-span-2 w-full" />
<KolButton
_label="Anfrage absenden"
_type="submit"
_variant="primary"
/>
<KolButton _label="Zurücksetzen" _type="reset" _variant="secondary" />
</div>
</form>
);
}
+ const validationSchema = Yup.object().shape({
+ ...terminSchema,
+ ...contactSchema,
+ });
function App() {
+ const onSubmit = (values: FormValues) => {
+ console.log("Valid form to sumbit", values);
+ };
return (
<div className="flex flex-col gap-4">
<KolHeading _label="Tischreservierung" />
<Formik<FormValues>
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
<Form />
</Formik>
</div>
);
}
export default App;