Skip to content

Commit

Permalink
feat: added signature pad component
Browse files Browse the repository at this point in the history
  • Loading branch information
Swappea committed Nov 7, 2024
1 parent 9abd5d0 commit c684b4b
Show file tree
Hide file tree
Showing 18 changed files with 1,215 additions and 1 deletion.
94 changes: 94 additions & 0 deletions apps/docs/src/examples/signature-pad.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
.signature-pad-root {
width: 400px;
height: 400px;
padding: 20px;
display: flex;
flex-direction: column;
row-gap: 20px;
align-items: center;
border: 1px solid #fff;
}

.signature-pad-label {
color: #fff;
font-size: 20px;
}

.signature-pad-control {
width: 100%;
height: 100%;
border: 1px dashed #fff;
position: relative;
touch-action: none;
user-select: none;
-webkit-user-select: none;
}

.signature-pad-segment {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
fill: #ccc;
}

.signature-pad-clear-trigger {
position: absolute;
top: 20px;
right: 20px;
cursor: pointer;
background-color: transparent;
color: #fff;
border-color: transparent;
border-radius: 3px;
font-size: 20px;
padding: 5px;
margin: 0;
width: max-content;
}

.signature-pad-clear-trigger:hover {
background-color: gray;
}

.signature-pad-guide {
border-bottom: 1px dashed #ccc;
position: absolute;
bottom: 20px;
left: 20px;
right: 20px;
}

.signature-pad-image-container {
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
align-items: center;
row-gap: 10px;
border: 1px solid #fff;
margin-top: 10px;
}

.signature-pad-image-preview {
height: 100%;
width: 100%;
background-color: transparent;
}

.form-container {
display: flex;
flex-direction: column;
row-gap: 20px;
width: 100%;
align-items: center;
}

.submit-btn {
background-color: hsl(201 96% 32%);
color: white;
padding: 5px 10px;
border-radius: 4px;
}
119 changes: 119 additions & 0 deletions apps/docs/src/examples/signature-pad.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { SignaturePad } from "@kobalte/core/signature-pad";
import { Show, createSignal } from "solid-js";

import styles from "./signature-pad.module.css";

export function BasicExample() {
return (
<SignaturePad
class={styles["signature-pad-root"]}
onDrawing={(details) => console.log("onDrawing", details)}
onDrawingEnd={async (details) => {
console.log("onDrawingEnd", details);
}}
>
<SignaturePad.Label class={styles["signature-pad-label"]}>
Sign here
</SignaturePad.Label>
<SignaturePad.Control class={styles["signature-pad-control"]}>
<SignaturePad.Segment class={styles["signature-pad-segment"]} />
<SignaturePad.ClearTrigger
class={styles["signature-pad-clear-trigger"]}
>
&#x21bb;
</SignaturePad.ClearTrigger>
<SignaturePad.Guide class={styles["signature-pad-guide"]} />
</SignaturePad.Control>
</SignaturePad>
);
}

export function ImagePreviewExample() {
const [imageUrl, setImageUrl] = createSignal<string>();

return (
<>
<SignaturePad
class={styles["signature-pad-root"]}
onDrawing={(details) => console.log("onDrawing", details)}
onDrawingEnd={async (details) => {
console.log("onDrawingEnd", details);
details.getDataUrl({ type: "image/png" }).then((dataUrl) => {
setImageUrl(dataUrl);
});
}}
>
<SignaturePad.Label class={styles["signature-pad-label"]}>
Sign here
</SignaturePad.Label>
<SignaturePad.Control class={styles["signature-pad-control"]}>
<SignaturePad.Segment class={styles["signature-pad-segment"]} />
<SignaturePad.ClearTrigger
class={styles["signature-pad-clear-trigger"]}
>
&#x21bb;
</SignaturePad.ClearTrigger>
<SignaturePad.Guide class={styles["signature-pad-guide"]} />
</SignaturePad.Control>
<SignaturePad.HiddenInput name="signature" value={imageUrl()} />
</SignaturePad>
<div class={styles["signature-pad-image-container"]}>
<div>Image Preview:</div>
<Show when={imageUrl()}>
<img
src={imageUrl()}
alt="Signature"
class={styles["signature-pad-image-preview"]}
/>
</Show>
</div>
</>
);
}

export function HTMLFormExample() {
let formRef: HTMLFormElement | undefined;

const [imageUrl, setImageUrl] = createSignal<string>();

return (
<form
class={styles["form-container"]}
onSubmit={(event) => {
event.preventDefault();
const formData = new FormData(formRef);
alert("you will get an image data url on submit");
console.log("formData", formData.get("signature"));
}}
ref={formRef}
>
<SignaturePad
class={styles["signature-pad-root"]}
onDrawing={(details) => console.log("onDrawing", details)}
onDrawingEnd={async (details) => {
console.log("onDrawingEnd", details);
details.getDataUrl({ type: "image/png" }).then((dataUrl) => {
setImageUrl(dataUrl);
});
}}
>
<SignaturePad.Label class={styles["signature-pad-label"]}>
Sign here
</SignaturePad.Label>
<SignaturePad.Control class={styles["signature-pad-control"]}>
<SignaturePad.Segment class={styles["signature-pad-segment"]} />
<SignaturePad.ClearTrigger
class={styles["signature-pad-clear-trigger"]}
>
&#x21bb;
</SignaturePad.ClearTrigger>
<SignaturePad.Guide class={styles["signature-pad-guide"]} />
</SignaturePad.Control>
<SignaturePad.HiddenInput name="signature" value={imageUrl()} />
</SignaturePad>
<button type="submit" class={styles["submit-btn"]}>
Submit
</button>
</form>
);
}
4 changes: 4 additions & 0 deletions apps/docs/src/routes/docs/core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ const CORE_NAV_SECTIONS: NavSection[] = [
title: "Separator",
href: "/docs/core/components/separator",
},
{
title: "Signature Pad",
href: "/docs/core/components/signature-pad",
},
{
title: "Skeleton",
href: "/docs/core/components/skeleton",
Expand Down
Loading

0 comments on commit c684b4b

Please sign in to comment.