Skip to content

Commit

Permalink
New: Add option to collapse picker
Browse files Browse the repository at this point in the history
  • Loading branch information
jonnitto committed Mar 21, 2024
1 parent 5660f8f commit 58b9a33
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 172 deletions.
2 changes: 2 additions & 0 deletions Configuration/Settings.Colors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Neos:
showLuminance: false
# The precision of the OKLCH color picker. Set to 0 to disable rounding and use the raw values.
precision: 5
# Collapse the color picker (enables only when showPicker is true)
collapsed: false
# The presets are based on https://tailwindcss.com/docs/customizing-colors with the key 600
# false and null values get filtered out
presets:
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

# Carbon.ColorPicker.OKLCH

Color picker for Neos CMS who saves the color in the [`OKLCH`] color space
Color picker for Neos CMS who saves the color in the [`OKLCH`] color space.

There are many options on how the picker should look like:

Here you can see some of the combinations:

![screenshot]

Expand Down Expand Up @@ -117,6 +121,8 @@ Neos:
showLightness: false
# Show slider to set the luminance
showLuminance: false
# Collapse the color picker (enables only when showPicker is true)
collapsed: false
# The precision of the OKLCH color picker. Set to 0 to disable rounding and use the raw values.
precision: 5
# The presets are based on https://tailwindcss.com/docs/customizing-colors with the key 600
Expand Down Expand Up @@ -163,12 +169,13 @@ Foo.Bar:Your.Prototype:
showLuminance: true
disable: true
allowEmpty: false
collapsed: true
presets:
red: "#dc2626"
orange: "#ea580c"
```

[screenshot]: https://github.com/CarbonPackages/Carbon.ColorPicker.OKLCH/assets/4510166/7cd440ac-ca24-459c-b71f-bfb896592cc8
[screenshot]: https://github.com/CarbonPackages/Carbon.ColorPicker.OKLCH/assets/4510166/320c14e8-f961-49ac-8959-38d2c43b3a81
[tailwind oklch plugin]: https://github.com/MartijnCuppens/tailwindcss-oklch
[`oklch`]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
[packagist]: https://packagist.org/packages/carbon/colorpicker-oklch
Expand Down
211 changes: 211 additions & 0 deletions Resources/Private/Editor/ColorPicker/Components/Panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// @ts-ignore
import React, { useEffect, useState } from "react";
import { HexColorPicker, HexColorInput } from "react-colorful";
import { onHexChange, setLuminance, setLightness, OptionPreview, RangeSlider } from "./index";
import { IconButton, SelectBox } from "@neos-project/react-ui-components";
import * as stylex from "@stylexjs/stylex";
import { colors, sizes, fonts, transitions } from "../Tokens.stylex";

const styles = stylex.create({
highlight: {
borderRadius: sizes.borderRadius,
boxShadow: `0 0 0 2px ${colors.warn}`,
},
fontMono: {
fontFamily: fonts.mono,
},
elementRow: {
display: "flex",
gap: sizes.spacingHalf,
},
colorPreview: (color) => ({
borderRadius: sizes.borderRadius,
height: sizes.goldenUnit,
minWidth: sizes.goldenUnit,
flexBasis: sizes.goldenUnit,
flex: 1,
backgroundColor: color || colors.contrastNeutral,
backgroundSize: color ? null : "16px 16px",
backgroundImage: color ? null : colors.checkerboard,
}),
colorInput: {
flexGrow: 1,
height: sizes.goldenUnit,
width: "100%",
borderRadius: sizes.borderRadius,
border: 0,
backgroundColor: colors.contrastNeutral,
paddingInline: sizes.spacingFull,
color: "white",
outline: "none",
":focus": {
color: "black",
backgroundColor: "white",
},
},
colorPicker: {
width: "100%",
height: "auto",
aspectRatio: 1,
marginTop: sizes.spacingHalf,
// :where(*) is a hack to select classes inside the component
":where(*) > :first-child": {
borderTopLeftRadius: sizes.borderRadius,
borderTopRightRadius: sizes.borderRadius,
},
":where(*) > :last-child": {
borderBottomLeftRadius: sizes.borderRadius,
borderBottomRightRadius: sizes.borderRadius,
},
":where(*) .react-colorful__pointer": {
height: 20,
width: 20,
backgroundColor: colors.primaryBlue,
borderColor: colors.primaryBlue,
transitionProperty: "transform, background-color, border-color",
transitionTimingFunction: transitions.timing,
transitionDuration: transitions.default,
transition: `transform ${transitions.default} ${transitions.timing}`,
},
":where(*) .react-colorful__pointer:hover": {
backgroundColor: colors.primaryBlueHover,
borderColor: colors.primaryBlueHover,
cursor: "grab",
},
":where(*) .react-colorful__pointer:active": {
transform: "translate(-50%,-50%) scale(1.5)",
cursor: "grabbing",
},
},
colorPickerCollapsed: {
marginTop: sizes.spacingFull,
},
});

// @ts-ignore
export default function Panel({
allowEmpty,
precision,
presets,
showHexInput,
showLightness,
showLuminance,
showPicker,
showPresets,
i18nRegistry,
highlight,
state,
setState,
id,
onFocus = () => {},
collapsed,
}: {
allowEmpty: boolean;
precision: number;
presets: object;
showHexInput: boolean;
showLightness: boolean;
showLuminance: boolean;
showPicker: boolean;
showPresets: boolean;
i18nRegistry: any;
highlight?: boolean;
state: any;
setState: Function;
id: string;
onFocus?: Function;
collapsed: boolean;
}) {
function handleHexChange(hex: string) {
setState(onHexChange(hex, precision));
}

function handleLightnessChange(lightness: number) {
handleHexChange(setLightness(state?.hex, lightness));
}

function handleLuminanceChange(luminance: number) {
handleHexChange(setLuminance(state?.oklch, luminance));
}

const presetOptions =
showPresets &&
presets &&
Object.entries(presets)
.map(([key, color]) => ({ value: color, label: key }))
.filter((preset) => !!preset.value);

return (
<>
{Boolean(showPicker) && (
<HexColorPicker
{...stylex.props(styles.colorPicker, collapsed && styles.colorPickerCollapsed)}
color={state?.hex}
onChange={handleHexChange}
/>
)}

{Boolean(showLightness) && (
<RangeSlider
disabled={state?.hex ? false : true}
value={state?.lightness || 0}
onChange={handleLightnessChange}
label={i18nRegistry.translate("Carbon.ColorPicker.OKLCH:Main:lightness")}
id={`${id}-lightness`}
/>
)}

{Boolean(showLuminance) && (
<RangeSlider
disabled={state?.coords?.l ? false : true}
value={state?.coords?.l * 100 || 0}
onChange={handleLuminanceChange}
label={i18nRegistry.translate("Carbon.ColorPicker.OKLCH:Main:luminance")}
id={`${id}-luminance`}
/>
)}

{(Boolean(collapsed) ? Boolean(showHexInput) : true) && (
<div {...stylex.props(styles.elementRow)}>
{Boolean(collapsed) || (
<div {...stylex.props(styles.colorPreview(state?.oklch), highlight && styles.highlight)} />
)}

{Boolean(showHexInput) && (
<HexColorInput
{...stylex.props(styles.colorInput, styles.fontMono)}
title={i18nRegistry.translate("Carbon.ColorPicker.OKLCH:Main:setHexColor")}
color={state?.hex}
onChange={handleHexChange}
prefixed={false}
id={id}
onFocus={() => onFocus()}
/>
)}

{!Boolean(collapsed) && Boolean(allowEmpty) && (
<IconButton
style="light"
icon="times"
title={i18nRegistry.translate("Carbon.ColorPicker.OKLCH:Main:resetColor")}
onClick={() => {
setState(null);
}}
/>
)}
</div>
)}

{Boolean(!!presetOptions) && (
<SelectBox
options={presetOptions}
value={state?.hex}
placeholder={i18nRegistry.translate("Carbon.ColorPicker.OKLCH:Main:preset")}
allowEmpty={false}
onValueChange={handleHexChange}
ListPreviewElement={OptionPreview}
/>
)}
</>
);
}
2 changes: 2 additions & 0 deletions Resources/Private/Editor/ColorPicker/Components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { onHexChange, setLightness, setLuminance, setStateFromValue } from "./ColorConverter";
import OptionPreview from "./OptionPreview";
import RangeSlider from "./RangeSlider";
import Panel from "./Panel";

export default Panel;
export { onHexChange, setLuminance, setStateFromValue, OptionPreview, setLightness, RangeSlider };
1 change: 1 addition & 0 deletions Resources/Private/Editor/ColorPicker/Tokens.stylex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const colors = stylex.defineVars({
contrastNeutral: "var(--colors-ContrastNeutral)",
warn: "var(--colors-Warn)",
error: "var(--colors-Error)",
checkerboard: `url('data:image/svg+xml, <svg xmlns="http://www.w3.org/2000/svg" width="2" height="2" fill-opacity=".25"><rect x="1" width="1" height="1" /><rect y="1" width="1" height="1" /></svg>')`,
});

export const sizes = stylex.defineVars({
Expand Down
Loading

0 comments on commit 58b9a33

Please sign in to comment.