@@ -11,7 +11,7 @@ | |||||
- [X] RadioButton | - [X] RadioButton | ||||
- [X] RadioTickBox | - [X] RadioTickBox | ||||
- Color | - Color | ||||
- [ ] ColorPicker | |||||
- [X] ColorPicker | |||||
- [X] Swatch (unify with color picker? Swatch is basically a readonly color picker with click-to-copy behavior) | - [X] Swatch (unify with color picker? Swatch is basically a readonly color picker with click-to-copy behavior) | ||||
- Code | - Code | ||||
- [ ] CodeInput (extract to own package) | - [ ] CodeInput (extract to own package) | ||||
@@ -20,6 +20,7 @@ | |||||
- Formatted | - Formatted | ||||
- [X] EmailInput | - [X] EmailInput | ||||
- [X] PhoneNumberInput | - [X] PhoneNumberInput | ||||
- [X] PatternTextInput | |||||
- [X] UrlInput | - [X] UrlInput | ||||
- Freeform | - Freeform | ||||
- [X] MaskedTextInput | - [X] MaskedTextInput | ||||
@@ -53,24 +54,24 @@ | |||||
- RichText (extract to own package) | - RichText (extract to own package) | ||||
- [ ] RichTextInput | - [ ] RichTextInput | ||||
- Temporal | - Temporal | ||||
- [ ] Calendar | |||||
- [ ] ~~Calendar~~ | |||||
- [X] DateDropdown | - [X] DateDropdown | ||||
- [ ] DateTimeRangeInput | |||||
- [ ] DurationInput | |||||
- [ ] MonthInput | |||||
- [ ] MonthDayInput | |||||
- [ ] ~~DateTimeRangeInput~~ | |||||
- [ ] ~~DurationInput~~ | |||||
- [ ] ~~MonthInput~~ | |||||
- [ ] ~~MonthDayInput~~ | |||||
- [X] TimeSpinner | - [X] TimeSpinner | ||||
- [-] YearMonthInput | - [-] YearMonthInput | ||||
- [-] WeekInput | - [-] WeekInput | ||||
- [ ] YearInput | |||||
- [ ] ~~YearInput~~ | |||||
# Others | # Others | ||||
- [X] Add `select-none` to input labels, etc. | - [X] Add `select-none` to input labels, etc. | ||||
- [X] Add indicators to components (select, datetime input 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! | - [ ] Test all components! | ||||
- [ ] Where to put the "click-to-copy" textboxes? Does `Swatch` | - [ ] Where to put the "click-to-copy" textboxes? Does `Swatch` | ||||
belong to this category? | belong to this category? | ||||
@@ -16,10 +16,10 @@ export const colorPickerPlugin = plugin(({ addComponents }) => { | |||||
'padding': '0', | 'padding': '0', | ||||
}, | }, | ||||
'&::-webkit-color-swatch': { | '&::-webkit-color-swatch': { | ||||
'border': '2px solid black', | |||||
'border': '0', | |||||
}, | }, | ||||
'&::-moz-color-swatch': { | '&::-moz-color-swatch': { | ||||
'border': '2px solid black', | |||||
'border': '0', | |||||
}, | }, | ||||
}, | }, | ||||
}); | }); | ||||
@@ -33,57 +33,81 @@ export const ColorPicker = React.forwardRef< | |||||
className, | className, | ||||
id: idProp, | id: idProp, | ||||
style, | style, | ||||
square = false, | |||||
square = false as const, | |||||
size = 'medium' as const, | size = 'medium' as const, | ||||
...etcProps | ...etcProps | ||||
}, | }, | ||||
forwardedRef, | 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( | 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( | 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'; | ColorPicker.displayName = 'ColorPicker'; | ||||
@@ -16,10 +16,9 @@ export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, | |||||
export const useSwatchControls = () => { | export const useSwatchControls = () => { | ||||
const id = React.useId(); | 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; | 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(() => ({ | return React.useMemo(() => ({ | ||||
id, | id, | ||||
@@ -68,6 +67,7 @@ export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({ | |||||
title={colorValue} | title={colorValue} | ||||
htmlFor={id} | htmlFor={id} | ||||
> | > | ||||
{/* todo border primary */} | |||||
<span | <span | ||||
className="inline-block w-5 h-5 align-middle border border-[#ffffff]" | 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 {DefaultLayout} from '@/components/DefaultLayout'; | ||||
import {Section, Subsection} from '@/components/Section'; | import {Section, Subsection} from '@/components/Section'; | ||||
import * as Color from '@tesseract-design/web-color-react'; | import * as Color from '@tesseract-design/web-color-react'; | ||||
import { TextInput } from '@tesseract-design/web-freeform-react'; | |||||
const ColorPage: NextPage = () => { | const ColorPage: NextPage = () => { | ||||
return ( | return ( | ||||
@@ -55,6 +56,32 @@ const ColorPage: NextPage = () => { | |||||
disabled | disabled | ||||
/> | /> | ||||
</Subsection> | </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> | </Section> | ||||
</DefaultLayout> | </DefaultLayout> | ||||
) | ) | ||||