Skip to content

Commit

Permalink
feat: PinInput component
Browse files Browse the repository at this point in the history
  • Loading branch information
HBS999 committed Nov 6, 2024
1 parent 9abd5d0 commit 94134e2
Show file tree
Hide file tree
Showing 13 changed files with 1,562 additions and 0 deletions.
89 changes: 89 additions & 0 deletions apps/docs/src/examples/pin-input.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
.pin-input {
display: flex;
flex-direction: column;
gap: 8px;
}

.pin-input__label {
color: hsl(240 6% 10%);
font-size: 14px;
font-weight: 500;
user-select: none;
}

.pin-input__description {
color: hsl(240 5% 26%);
font-size: 12px;
user-select: none;
}

.pin-input__error-message {
color: hsl(0 72% 51%);
font-size: 12px;
user-select: none;
}

.pin-input__control {
display: flex;
gap: 8px;
}

.pin-input__input {
width: 40px;
height: 40px;
border-radius: 6px;
font-size: 16px;
outline: none;
background-color: white;
text-align: center;
border: 1px solid hsl(240 6% 90%);
color: hsl(240 4% 16%);
transition:
border-color 250ms,
color 250ms;
}

.pin-input__input:hover {
border-color: hsl(240 5% 65%);
}

.pin-input__input:focus {
outline: 2px solid hsl(200 98% 39%);
outline-offset: 2px;
}

.pin-input__input::placeholder {
color: hsl(240 4% 46%);
}

.pin-input__input[data-invalid] {
border-color: hsl(0 72% 51%);
color: hsl(0 72% 51%);
}

[data-kb-theme="dark"] .pin-input__label {
color: hsl(240 5% 84%);
}

[data-kb-theme="dark"] .pin-input__input {
background-color: hsl(240 4% 16%);
border: 1px solid hsl(240 5% 34%);
color: hsl(0 100% 100% / 0.9);
}

[data-kb-theme="dark"] .pin-input__input:hover {
border-color: hsl(240 4% 46%);
}

[data-kb-theme="dark"] .pin-input__input::placeholder {
color: hsl(0 100% 100% / 0.5);
}

[data-kb-theme="dark"] .pin-input__input[data-invalid] {
border-color: hsl(0 72% 51%);
color: hsl(0 72% 51%);
}

[data-kb-theme="dark"] .pin-input__description {
color: hsl(240 5% 65%);
}
185 changes: 185 additions & 0 deletions apps/docs/src/examples/pin-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { Index, createSignal } from "solid-js";
import { PinInput } from "../../../../packages/core/src/pin-input";

import style from "./pin-input.module.css";

export function BasicExample() {
return (
<PinInput class={style["pin-input"]}>
<PinInput.Label class={style["pin-input__label"]}>PIN</PinInput.Label>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function DefaultValueExample() {
return (
<PinInput class={style["pin-input"]} defaultValue={["9", "9", "9"]}>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function ControlledExample() {
const [value, setValue] = createSignal([]);

return (
<>
<PinInput class={style["pin-input"]} value={value()} onChange={setValue}>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
<p class="not-prose text-sm mt-4">PIN code is: {value().join("")}</p>
</>
);
}

export function PlaceholderExample() {
return (
<PinInput class={style["pin-input"]} placeholder="*">
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function BlurOnCompleteExample() {
return (
<PinInput class={style["pin-input"]} blurOnComplete>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function OTPExample() {
return (
<PinInput class={style["pin-input"]} otp>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function MaskExample() {
return (
<PinInput class={style["pin-input"]} mask>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function TypeExample() {
return (
<PinInput class={style["pin-input"]} type="alphanumeric">
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
</PinInput>
);
}

export function DescriptionExample() {
return (
<PinInput class={style["pin-input"]}>
<PinInput.Label class={style["pin-input__label"]}>PIN</PinInput.Label>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
<PinInput.Description class={style["pin-input__description"]}>
Enter your 3 digit PIN code.
</PinInput.Description>
</PinInput>
);
}

export function ErrorMessageExample() {
const [value, setValue] = createSignal([]);

return (
<PinInput
class={style["pin-input"]}
value={value()}
onChange={setValue}
validationState={
value().every((element) => element === "9") ? "valid" : "invalid"
}
>
<PinInput.Label class={style["pin-input__label"]}>PIN</PinInput.Label>
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
<PinInput.ErrorMessage class={style["pin-input__error-message"]}>
Incorrect PIN. Please try again.
</PinInput.ErrorMessage>
</PinInput>
);
}

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

const onSubmit = (e: SubmitEvent) => {
e.preventDefault();
e.stopPropagation();

const formData = new FormData(formRef);

alert(JSON.stringify(Object.fromEntries(formData), null, 2));
};

return (
<form
ref={formRef}
onSubmit={onSubmit}
class="flex flex-col items-center space-y-6"
>
<PinInput class={style["pin-input"]} name="PIN">
<PinInput.Control class={style["pin-input__control"]}>
<Index each={Array(3)}>
{(_) => <PinInput.Input class={style["pin-input__input"]} />}
</Index>
</PinInput.Control>
<PinInput.HiddenInput />
</PinInput>
<div class="flex space-x-2">
<button type="reset" class="kb-button">
Reset
</button>
<button type="submit" class="kb-button-primary">
Submit
</button>
</div>
</form>
);
}
5 changes: 5 additions & 0 deletions apps/docs/src/routes/docs/core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ const CORE_NAV_SECTIONS: NavSection[] = [
title: "Pagination",
href: "/docs/core/components/pagination",
},
{
title: "Pin Input",
href: "/docs/core/components/pin-input",
status: "new",
},
{
title: "Popover",
href: "/docs/core/components/popover",
Expand Down
Loading

0 comments on commit 94134e2

Please sign in to comment.