@@ -11,7 +11,7 @@ | |||
- [X] RadioButton | |||
- [X] RadioTickBox | |||
- Color | |||
- [ ] ColorPicker | |||
- [X] ColorPicker | |||
- [X] Swatch (unify with color picker? Swatch is basically a readonly color picker with click-to-copy behavior) | |||
- Code | |||
- [ ] CodeInput (extract to own package) | |||
@@ -20,6 +20,7 @@ | |||
- Formatted | |||
- [X] EmailInput | |||
- [X] PhoneNumberInput | |||
- [X] PatternTextInput | |||
- [X] UrlInput | |||
- Freeform | |||
- [X] MaskedTextInput | |||
@@ -53,24 +54,24 @@ | |||
- RichText (extract to own package) | |||
- [ ] RichTextInput | |||
- Temporal | |||
- [ ] Calendar | |||
- [ ] ~~Calendar~~ | |||
- [X] DateDropdown | |||
- [ ] DateTimeRangeInput | |||
- [ ] DurationInput | |||
- [ ] MonthInput | |||
- [ ] MonthDayInput | |||
- [ ] ~~DateTimeRangeInput~~ | |||
- [ ] ~~DurationInput~~ | |||
- [ ] ~~MonthInput~~ | |||
- [ ] ~~MonthDayInput~~ | |||
- [X] TimeSpinner | |||
- [-] YearMonthInput | |||
- [-] WeekInput | |||
- [ ] YearInput | |||
- [ ] ~~YearInput~~ | |||
# Others | |||
- [X] Add `select-none` to input labels, etc. | |||
- [X] Add indicators to components (select, datetime input etc) | |||
- [ ] Add proxies for setting component values | |||
- [ ] formatted/phonenumberinput | |||
- [ ] multichoice/taginput | |||
- [ ] blob/fileselectbox (?) | |||
- [X] Add proxies for setting component values | |||
- [X] formatted/phonenumberinput | |||
- [X] multichoice/taginput | |||
- [X] blob/fileselectbox (?) | |||
- [ ] Test all components! | |||
- [ ] Where to put the "click-to-copy" textboxes? Does `Swatch` | |||
belong to this category? | |||
@@ -16,10 +16,10 @@ export const colorPickerPlugin = plugin(({ addComponents }) => { | |||
'padding': '0', | |||
}, | |||
'&::-webkit-color-swatch': { | |||
'border': '2px solid black', | |||
'border': '0', | |||
}, | |||
'&::-moz-color-swatch': { | |||
'border': '2px solid black', | |||
'border': '0', | |||
}, | |||
}, | |||
}); | |||
@@ -33,57 +33,81 @@ export const ColorPicker = React.forwardRef< | |||
className, | |||
id: idProp, | |||
style, | |||
square = false, | |||
square = false as const, | |||
size = 'medium' as const, | |||
...etcProps | |||
}, | |||
forwardedRef, | |||
) => { | |||
return ( | |||
<div | |||
) => ( | |||
<div | |||
className={clsx( | |||
'inline-block align-center relative ring-secondary/50 rounded overflow-hidden box-border group has-[:disabled]:opacity-50', | |||
'rounded focus-within:ring-4 active:ring-tertiary/50', | |||
{ | |||
'w-8': square && size === 'small', | |||
'w-12': square && size === 'medium', | |||
'w-16': square && size === 'large', | |||
}, | |||
{ | |||
'w-16': !square && size === 'small', | |||
'w-24': !square && size === 'medium', | |||
'w-32': !square && size === 'large', | |||
}, | |||
className, | |||
)} | |||
style={style} | |||
> | |||
<span | |||
className={clsx( | |||
'inline-block align-center relative', | |||
{ | |||
'w-4': square && size === 'small', | |||
'w-6': square && size === 'medium', | |||
'w-8': square && size === 'large', | |||
}, | |||
'block w-full', | |||
{ | |||
'w-8': !square && size === 'small', | |||
'w-12': !square && size === 'medium', | |||
'w-16': !square && size === 'large', | |||
'p-[25%]': square, | |||
'p-[12.5%]': !square, | |||
}, | |||
className, | |||
)} | |||
style={style} | |||
> | |||
<span | |||
<input | |||
{...etcProps} | |||
className={clsx( | |||
'block w-full', | |||
{ | |||
'p-[50%]': square, | |||
'p-[25%]': !square, | |||
}, | |||
'color-picker absolute top-0 left-0 w-full h-full overflow-hidden cursor-pointer disabled:cursor-not-allowed', | |||
'focus:outline-0', | |||
)} | |||
ref={forwardedRef} | |||
id={idProp} | |||
type="color" | |||
/> | |||
</span> | |||
<span | |||
className={clsx( | |||
'border-y-4 border-l-4 border-r-2 absolute top-0 left-0 h-full pointer-events-none border-[#000000]', | |||
{ | |||
'w-1/2': square, | |||
'w-3/4': !square, | |||
}, | |||
)} | |||
/> | |||
<span | |||
className={clsx( | |||
'absolute flex items-center justify-center top-0 right-0 h-full pointer-events-none bg-negative text-primary group-has-[:disabled]:text-primary group-active:text-tertiary group-focus-within:text-secondary', | |||
{ | |||
'w-1/2': square, | |||
'w-1/4': !square, | |||
}, | |||
)} | |||
> | |||
<svg | |||
className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round" | |||
viewBox="0 0 24 24" | |||
role="presentation" | |||
> | |||
{/* todo add chevron down to picker */} | |||
<input | |||
{...etcProps} | |||
className={clsx( | |||
'color-picker absolute top-0 left-0 w-full h-full overflow-hidden ring-secondary/50 rounded cursor-pointer', | |||
'border-2 border-primary focus:border-secondary active:border-tertiary disabled:border-primary', | |||
'focus:outline-0 focus:ring-4', | |||
'active:ring-tertiary/50', | |||
'disabled:opacity-50 disabled:cursor-not-allowed', | |||
)} | |||
ref={forwardedRef} | |||
id={idProp} | |||
type="color" | |||
/> | |||
</span> | |||
</div> | |||
); | |||
}); | |||
<polyline points="6 9 12 15 18 9" /> | |||
</svg> | |||
</span> | |||
<span | |||
className="border-2 absolute top-0 left-0 w-full h-full pointer-events-none border-primary group-active:border-tertiary group-has-[:disabled]:border-primary group-focus-within:border-secondary" | |||
/> | |||
</div> | |||
)); | |||
ColorPicker.displayName = 'ColorPicker'; | |||
@@ -16,10 +16,9 @@ export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, | |||
export const useSwatchControls = () => { | |||
const id = React.useId(); | |||
const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback((e) => { | |||
const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback(async (e) => { | |||
const { value } = e.currentTarget; | |||
// eslint-disable-next-line no-void | |||
void window.navigator.clipboard.writeText(value); | |||
await window.navigator.clipboard.writeText(value); | |||
}, []); | |||
return React.useMemo(() => ({ | |||
id, | |||
@@ -68,6 +67,7 @@ export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({ | |||
title={colorValue} | |||
htmlFor={id} | |||
> | |||
{/* todo border primary */} | |||
<span | |||
className="inline-block w-5 h-5 align-middle border border-[#ffffff]" | |||
> | |||
@@ -2,6 +2,7 @@ import {NextPage} from 'next'; | |||
import {DefaultLayout} from '@/components/DefaultLayout'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
import * as Color from '@tesseract-design/web-color-react'; | |||
import { TextInput } from '@tesseract-design/web-freeform-react'; | |||
const ColorPage: NextPage = () => { | |||
return ( | |||
@@ -55,6 +56,32 @@ const ColorPage: NextPage = () => { | |||
disabled | |||
/> | |||
</Subsection> | |||
<Subsection title="Copy on select"> | |||
<Color.ColorPicker | |||
size="small" | |||
defaultValue="#ff0000" | |||
copyOnSelect | |||
readOnly | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
defaultValue="#00ff00" | |||
copyOnSelect | |||
readOnly | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
defaultValue="#0000ff" | |||
copyOnSelect | |||
readOnly | |||
/> | |||
<div> | |||
<TextInput | |||
label="Color" | |||
border | |||
/> | |||
</div> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
) | |||