Skip to content

Commit

Permalink
feat: new ColorField component (#510)
Browse files Browse the repository at this point in the history
* feat: new ColorWheel component

---------

Co-authored-by: jer3m01 <[email protected]>
  • Loading branch information
HBS999 and jer3m01 authored Nov 2, 2024
1 parent 3674cfe commit 4988fb3
Show file tree
Hide file tree
Showing 21 changed files with 2,330 additions and 4 deletions.
84 changes: 84 additions & 0 deletions apps/docs/src/examples/color-field.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.color-field {
display: flex;
flex-direction: column;
gap: 4px;
}

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

.color-field__input {
display: inline-flex;
width: 200px;
border-radius: 6px;
padding: 6px 12px;
font-size: 16px;
outline: none;
background-color: white;
border: 1px solid hsl(240 6% 90%);
color: hsl(240 4% 16%);
transition:
border-color 250ms,
color 250ms;
}

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

.color-field__input:focus-visible {
outline: 2px solid hsl(200 98% 39%);
outline-offset: 2px;
}

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

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

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

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

[data-kb-theme="dark"] .color-field__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"] .color-field__input:hover {
border-color: hsl(240 4% 46%);
}

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

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

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

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

import style from "./color-field.module.css";

export function BasicExample() {
return (
<ColorField class={style["color-field"]}>
<ColorField.Label class={style["color-field__label"]}>
Favorite color
</ColorField.Label>
<ColorField.Input class={style["color-field__input"]} />
</ColorField>
);
}

export function DefaultValueExample() {
return (
<ColorField class={style["color-field"]} defaultValue="#7f007f">
<ColorField.Label class={style["color-field__label"]}>
Favorite color
</ColorField.Label>
<ColorField.Input class={style["color-field__input"]} />
</ColorField>
);
}

export function ControlledExample() {
const [value, setValue] = createSignal("#7f007f");

return (
<>
<ColorField
class={style["color-field"]}
value={value()}
onChange={setValue}
>
<ColorField.Label class={style["color-field__label"]}>
Favorite color
</ColorField.Label>
<ColorField.Input class={style["color-field__input"]} />
</ColorField>
<p class="not-prose text-sm mt-4">Your favorite color is: {value()}</p>
</>
);
}

export function DescriptionExample() {
return (
<ColorField class={style["color-field"]}>
<ColorField.Label class={style["color-field__label"]}>
Favorite color
</ColorField.Label>
<ColorField.Input class={style["color-field__input"]} />
<ColorField.Description class={style["color-field__description"]}>
Choose the color you like the most.
</ColorField.Description>
</ColorField>
);
}

export function ErrorMessageExample() {
const [value, setValue] = createSignal("#7f007f");

return (
<ColorField
class={style["color-field"]}
value={value()}
onChange={setValue}
validationState={value() !== "#000000" ? "invalid" : "valid"}
>
<ColorField.Label class={style["color-field__label"]}>
Favorite color
</ColorField.Label>
<ColorField.Input class={style["color-field__input"]} />
<ColorField.ErrorMessage class={style["color-field__error-message"]}>
Hmm, I prefer black.
</ColorField.ErrorMessage>
</ColorField>
);
}

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"
>
<ColorField class={style["color-field"]} name="favorite-color">
<ColorField.Label class={style["color-field__label"]}>
Favorite color
</ColorField.Label>
<ColorField.Input class={style["color-field__input"]} />
</ColorField>
<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>
);
}
33 changes: 33 additions & 0 deletions apps/docs/src/examples/color-wheel.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.ColorWheelRoot {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
user-select: none;
touch-action: none;
}

.ColorWheelTrack {
position: relative;
height: 160px;
width: 160px;
}

.ColorWheelThumb {
display: block;
width: 16px;
height: 16px;
border-radius: 9999px;
border: 2px solid #fff;
box-shadow: 0 0 0 1px #0000006b;
}

.ColorWheelThumb:focus {
outline: none;
}

.ColorWheelLabel {
display: flex;
justify-content: space-between;
width: 100%;
}
131 changes: 131 additions & 0 deletions apps/docs/src/examples/color-wheel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { createSignal } from "solid-js";
import { ColorWheel } from "../../../../packages/core/src/colors/color-wheel";
import { parseColor } from "../../../../packages/core/src/colors/utils";
import style from "./color-wheel.module.css";

export function BasicExample() {
return (
<ColorWheel class={style.ColorWheelRoot} thickness={24}>
<ColorWheel.Track class={style.ColorWheelTrack}>
<ColorWheel.Thumb class={style.ColorWheelThumb}>
<ColorWheel.Input />
</ColorWheel.Thumb>
</ColorWheel.Track>
</ColorWheel>
);
}

export function DefaultValueExample() {
return (
<ColorWheel
class={style.ColorWheelRoot}
defaultValue={parseColor("hsl(80, 100%, 50%)")}
thickness={24}
>
<ColorWheel.Track class={style.ColorWheelTrack}>
<ColorWheel.Thumb class={style.ColorWheelThumb}>
<ColorWheel.Input />
</ColorWheel.Thumb>
</ColorWheel.Track>
</ColorWheel>
);
}

export function ThicknessExample() {
return (
<ColorWheel class={style.ColorWheelRoot} thickness={56}>
<ColorWheel.Track class={style.ColorWheelTrack}>
<ColorWheel.Thumb class={style.ColorWheelThumb}>
<ColorWheel.Input />
</ColorWheel.Thumb>
</ColorWheel.Track>
</ColorWheel>
);
}

export function ControlledValueExample() {
const [value, setValue] = createSignal(parseColor("hsl(0, 100%, 50%)"));

return (
<>
<ColorWheel
class={style.ColorWheelRoot}
value={value()}
onChange={setValue}
thickness={24}
>
<ColorWheel.Track class={style.ColorWheelTrack}>
<ColorWheel.Thumb class={style.ColorWheelThumb}>
<ColorWheel.Input />
</ColorWheel.Thumb>
</ColorWheel.Track>
</ColorWheel>
<p class="not-prose text-sm mt-4">
Current color value: {value().toString("hsl")}
</p>
</>
);
}

export function CustomValueLabelExample() {
return (
<ColorWheel
class={style.ColorWheelRoot}
thickness={24}
getValueLabel={(color) =>
color
.toFormat("hsl")
.withChannelValue("saturation", 100)
.withChannelValue("lightness", 50)
.withChannelValue("alpha", 1)
.toString()
}
>
<div class={style.ColorWheelLabel}>
<ColorWheel.ValueLabel />
</div>
<ColorWheel.Track class={style.ColorWheelTrack}>
<ColorWheel.Thumb class={style.ColorWheelThumb}>
<ColorWheel.Input />
</ColorWheel.Thumb>
</ColorWheel.Track>
</ColorWheel>
);
}

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"
>
<ColorWheel class={style.ColorWheelRoot} name="hue" thickness={24}>
<ColorWheel.Track class={style.ColorWheelTrack}>
<ColorWheel.Thumb class={style.ColorWheelThumb}>
<ColorWheel.Input />
</ColorWheel.Thumb>
</ColorWheel.Track>
</ColorWheel>
<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>
);
}
10 changes: 10 additions & 0 deletions apps/docs/src/routes/docs/core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ const CORE_NAV_SECTIONS: NavSection[] = [
href: "/docs/core/components/color-channel-field",
status: "new",
},
{
title: "Color Field",
href: "/docs/core/components/color-field",
status: "new",
},
{
title: "Color Slider",
href: "/docs/core/components/color-slider",
Expand All @@ -90,6 +95,11 @@ const CORE_NAV_SECTIONS: NavSection[] = [
href: "/docs/core/components/color-swatch",
status: "new",
},
{
title: "Color Wheel",
href: "/docs/core/components/color-wheel",
status: "new",
},
{
title: "Combobox",
href: "/docs/core/components/combobox",
Expand Down
Loading

0 comments on commit 4988fb3

Please sign in to comment.