Style native input type color component.master
@@ -3,7 +3,7 @@ | |||
- Action | |||
- [X] ActionButton | |||
- Blob (choose to extract each preview component to their own library?) | |||
- [ ] FileSelectBox | |||
- [-] FileSelectBox | |||
- Choice | |||
- [X] ComboBox | |||
- [X] DropdownSelect | |||
@@ -61,7 +61,7 @@ | |||
- [ ] MonthDayInput | |||
- [X] TimeSpinner | |||
- [-] YearMonthInput | |||
- [-] YearWeekInput | |||
- [-] WeekInput | |||
- [ ] YearInput | |||
# Others | |||
@@ -15,6 +15,8 @@ | |||
"devDependencies": { | |||
"@testing-library/jest-dom": "^5.16.5", | |||
"@testing-library/react": "^13.4.0", | |||
"@types/color": "^3.0.3", | |||
"@types/color-convert": "^2.0.0", | |||
"@types/node": "^18.14.1", | |||
"@types/react": "^18.0.27", | |||
"eslint": "^8.35.0", | |||
@@ -25,6 +27,7 @@ | |||
"react-dom": "^18.2.0", | |||
"react-test-renderer": "^18.2.0", | |||
"tslib": "^2.5.0", | |||
"tsx": "^3.12.7", | |||
"typescript": "^4.9.5", | |||
"vitest": "^0.28.1" | |||
}, | |||
@@ -34,7 +37,7 @@ | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"build": "pridepack build && tsx scripts/build.ts", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
@@ -58,7 +61,9 @@ | |||
"access": "public" | |||
}, | |||
"dependencies": { | |||
"clsx": "^1.2.1" | |||
"clsx": "^1.2.1", | |||
"color": "^4.2.3", | |||
"color-convert": "^2.0.1" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"main": "./dist/cjs/production/index.js", | |||
@@ -72,9 +77,10 @@ | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"./dist/ColorPicker.css": "./dist/ColorPicker.css" | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
} | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
import { copyFileSync, readFileSync, writeFileSync } from 'fs'; | |||
import { resolve } from 'path'; | |||
const doCopy = (src: string, dest: string) => { | |||
const trueSrc = resolve(src); | |||
const trueDest = resolve(dest); | |||
console.log('Copying...'); | |||
console.log(`${trueSrc} -> ${trueDest}`); | |||
copyFileSync(trueSrc, trueDest); | |||
const packageJsonContents = readFileSync('./package.json', 'utf-8'); | |||
const packageJson = JSON.parse(packageJsonContents); | |||
packageJson.exports[dest] = dest; | |||
const newPackageJsonContents = JSON.stringify(packageJson, null, 2); | |||
console.log('Updating package.json...'); | |||
writeFileSync('./package.json', newPackageJsonContents); | |||
console.log('Done'); | |||
} | |||
doCopy('./src/components/ColorPicker/ColorPicker.css', './dist/ColorPicker.css'); |
@@ -0,0 +1,7 @@ | |||
.color-picker::-webkit-color-swatch-wrapper { | |||
padding: 0; | |||
} | |||
.color-picker::-webkit-color-swatch { | |||
border: 2px solid black; | |||
} |
@@ -0,0 +1,75 @@ | |||
import * as React from 'react'; | |||
import clsx from 'clsx'; | |||
export type ColorPickerDerivedElement = HTMLInputElement; | |||
export interface ColorPickerProps extends Omit<React.HTMLProps<ColorPickerDerivedElement>, 'size' | 'type' | 'label'> { | |||
square?: boolean; | |||
size?: 'small' | 'medium' | 'large'; | |||
} | |||
export const ColorPicker = React.forwardRef< | |||
ColorPickerDerivedElement, | |||
ColorPickerProps | |||
>(( | |||
{ | |||
className, | |||
id: idProp, | |||
style, | |||
square = false, | |||
size = 'medium' as const, | |||
...etcProps | |||
}, | |||
forwardedRef, | |||
) => { | |||
return ( | |||
<div | |||
className={clsx( | |||
'inline-block align-center relative', | |||
{ | |||
'w-4': square && size === 'small', | |||
'w-6': square && size === 'medium', | |||
'w-8': square && size === 'large', | |||
}, | |||
{ | |||
'w-8': !square && size === 'small', | |||
'w-12': !square && size === 'medium', | |||
'w-16': !square && size === 'large', | |||
}, | |||
className, | |||
)} | |||
style={style} | |||
> | |||
<span | |||
className={clsx( | |||
'block w-full', | |||
{ | |||
'p-[50%]': square, | |||
'p-[25%]': !square, | |||
}, | |||
)} | |||
> | |||
<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> | |||
); | |||
}); | |||
ColorPicker.displayName = 'ColorPicker'; | |||
ColorPicker.defaultProps = { | |||
square: false as const, | |||
size: 'medium' as const, | |||
}; |
@@ -1,13 +1,17 @@ | |||
import * as React from 'react'; | |||
import clsx from 'clsx'; | |||
type RgbTuple = [number, number, number]; | |||
import Color from 'color'; | |||
import * as convert from 'color-convert'; | |||
export type SwatchDerivedElement = HTMLInputElement; | |||
type ColorValue = ConstructorParameters<typeof Color>; | |||
type ColorMode = keyof typeof convert; | |||
export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> { | |||
color: RgbTuple; | |||
mode?: 'rgb' | 'hsl'; | |||
color: ColorValue; | |||
mode?: ColorMode; | |||
} | |||
export const useSwatchControls = () => { | |||
@@ -32,7 +36,9 @@ export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({ | |||
...etcProps | |||
}, forwardedRef) => { | |||
const { id, copyColor } = useSwatchControls(); | |||
const colorValue = `${mode}(${color.join(', ')})`; | |||
const colorInternal = React.useMemo(() => new Color(color, mode), [color, mode]); | |||
const colorValue = colorInternal.toString(); | |||
return ( | |||
<span | |||
@@ -68,7 +74,7 @@ export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({ | |||
<span | |||
className="block w-full h-full border border-[#000000]" | |||
style={{ | |||
backgroundColor: `${mode}(${color.join(' ')})`, | |||
backgroundColor: colorInternal.hex(), | |||
}} | |||
/> | |||
</span> | |||
@@ -1 +1,2 @@ | |||
export * from './components/ColorPicker'; | |||
export * from './components/Swatch'; |
@@ -212,6 +212,12 @@ importers: | |||
clsx: | |||
specifier: ^1.2.1 | |||
version: 1.2.1 | |||
color: | |||
specifier: ^4.2.3 | |||
version: 4.2.3 | |||
color-convert: | |||
specifier: ^2.0.1 | |||
version: 2.0.1 | |||
devDependencies: | |||
'@testing-library/jest-dom': | |||
specifier: ^5.16.5 | |||
@@ -219,6 +225,12 @@ importers: | |||
'@testing-library/react': | |||
specifier: ^13.4.0 | |||
version: 13.4.0(react-dom@18.2.0)(react@18.2.0) | |||
'@types/color': | |||
specifier: ^3.0.3 | |||
version: 3.0.3 | |||
'@types/color-convert': | |||
specifier: ^2.0.0 | |||
version: 2.0.0 | |||
'@types/node': | |||
specifier: ^18.14.1 | |||
version: 18.14.1 | |||
@@ -249,6 +261,9 @@ importers: | |||
tslib: | |||
specifier: ^2.5.0 | |||
version: 2.6.0 | |||
tsx: | |||
specifier: ^3.12.7 | |||
version: 3.12.7 | |||
typescript: | |||
specifier: ^4.9.5 | |||
version: 4.9.5 | |||
@@ -2039,6 +2054,22 @@ packages: | |||
resolution: {integrity: sha512-JklMxityrwjBTjGY2anH8JaTx3yjRU3/sEHSblLH1ba5lqcSh1LnImXJZO5peJfXyqKYWjHTGy4s5Wz++hARrw==} | |||
dev: true | |||
/@types/color-convert@2.0.0: | |||
resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==} | |||
dependencies: | |||
'@types/color-name': 1.1.1 | |||
dev: true | |||
/@types/color-name@1.1.1: | |||
resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==} | |||
dev: true | |||
/@types/color@3.0.3: | |||
resolution: {integrity: sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA==} | |||
dependencies: | |||
'@types/color-convert': 2.0.0 | |||
dev: true | |||
/@types/get-image-colors@4.0.2: | |||
resolution: {integrity: sha512-8E/xA3Dyl70sboWbjjt+UEHTC2Nvv6EIDxPx5nCSTN+QfBWbx60gGyBH0pQ9ABrRNqQ2gKtGboK3MoZodxMWtw==} | |||
dependencies: | |||
@@ -2938,6 +2969,21 @@ packages: | |||
/color-name@1.1.4: | |||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} | |||
/color-string@1.9.1: | |||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} | |||
dependencies: | |||
color-name: 1.1.4 | |||
simple-swizzle: 0.2.2 | |||
dev: false | |||
/color@4.2.3: | |||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} | |||
engines: {node: '>=12.5.0'} | |||
dependencies: | |||
color-convert: 2.0.1 | |||
color-string: 1.9.1 | |||
dev: false | |||
/colorthief@2.4.0: | |||
resolution: {integrity: sha512-0U48RGNRo5fVO+yusBwgp+d3augWSorXabnqXUu9SabEhCpCgZJEUjUTTI41OOBBYuMMxawa3177POT6qLfLeQ==} | |||
dependencies: | |||
@@ -4529,6 +4575,10 @@ packages: | |||
get-intrinsic: 1.2.1 | |||
is-typed-array: 1.1.10 | |||
/is-arrayish@0.3.2: | |||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} | |||
dev: false | |||
/is-bigint@1.0.4: | |||
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} | |||
dependencies: | |||
@@ -6113,6 +6163,12 @@ packages: | |||
/signal-exit@3.0.7: | |||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} | |||
/simple-swizzle@0.2.2: | |||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} | |||
dependencies: | |||
is-arrayish: 0.3.2 | |||
dev: false | |||
/sisteransi@1.0.5: | |||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} | |||
dev: true | |||
@@ -2,9 +2,9 @@ import * as React from 'react'; | |||
import { TextControl } from '@tesseract-design/web-base'; | |||
import clsx from 'clsx'; | |||
export type YearWeekInputDerivedElement = HTMLInputElement; | |||
export type WeekInputDerivedElement = HTMLInputElement; | |||
export interface YearWeekInputProps extends Omit<React.HTMLProps<YearWeekInputDerivedElement>, 'size' | 'type' | 'label' | 'pattern'> { | |||
export interface WeekInputProps extends Omit<React.HTMLProps<WeekInputDerivedElement>, 'size' | 'type' | 'label' | 'pattern'> { | |||
/** | |||
* Short textual description indicating the nature of the component's value. | |||
*/ | |||
@@ -42,9 +42,9 @@ export interface YearWeekInputProps extends Omit<React.HTMLProps<YearWeekInputDe | |||
/** | |||
* Component for inputting textual values. | |||
*/ | |||
export const YearWeekInput = React.forwardRef< | |||
YearWeekInputDerivedElement, | |||
YearWeekInputProps | |||
export const WeekInput = React.forwardRef< | |||
WeekInputDerivedElement, | |||
WeekInputProps | |||
>(( | |||
{ | |||
label, | |||
@@ -59,7 +59,7 @@ export const YearWeekInput = React.forwardRef< | |||
id: idProp, | |||
style, | |||
...etcProps | |||
}: YearWeekInputProps, | |||
}: WeekInputProps, | |||
forwardedRef, | |||
) => { | |||
const labelId = React.useId(); | |||
@@ -201,9 +201,9 @@ export const YearWeekInput = React.forwardRef< | |||
); | |||
}); | |||
YearWeekInput.displayName = 'YearWeekInput'; | |||
WeekInput.displayName = 'WeekInput'; | |||
YearWeekInput.defaultProps = { | |||
WeekInput.defaultProps = { | |||
label: undefined, | |||
hint: undefined, | |||
size: 'medium', |
@@ -1,3 +1,3 @@ | |||
export * from './TimeSpinner'; | |||
export * from './YearMonthInput'; | |||
export * from './YearWeekInput'; | |||
export * from './WeekInput'; |
@@ -6,6 +6,8 @@ import '@tesseract-design/web-choice-react/dist/MenuSelect.css' | |||
import '@tesseract-design/web-choice-react/dist/RadioButton.css' | |||
import '@tesseract-design/web-choice-react/dist/RadioTickBox.css' | |||
import '@tesseract-design/web-color-react/dist/ColorPicker.css' | |||
import '@tesseract-design/web-multichoice-react/dist/MenuMultiSelect.css' | |||
import '@tesseract-design/web-multichoice-react/dist/TagInput.css' | |||
import '@tesseract-design/web-multichoice-react/dist/ToggleButton.css' | |||
@@ -0,0 +1,46 @@ | |||
import {NextPage} from 'next'; | |||
import {DefaultLayout} from '@/components/DefaultLayout'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
import * as Color from '@tesseract-design/web-color-react'; | |||
const ColorPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout title="Color"> | |||
<Section title="DateDropdown"> | |||
<Subsection title="Default"> | |||
<Color.ColorPicker | |||
size="small" | |||
defaultValue="#ff0000" | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
defaultValue="#00ff00" | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
defaultValue="#0000ff" | |||
/> | |||
</Subsection> | |||
<Subsection title="Square"> | |||
<Color.ColorPicker | |||
size="small" | |||
square | |||
defaultValue="#ff0000" | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
square | |||
defaultValue="#00ff00" | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
square | |||
defaultValue="#0000ff" | |||
/> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default ColorPage; |
@@ -50,9 +50,9 @@ const TemporalPage: NextPage = () => { | |||
/> | |||
</Subsection> | |||
</Section> | |||
<Section title="YearWeekInput"> | |||
<Section title="WeekInput"> | |||
<Subsection title="Default"> | |||
<TemporalWip.YearWeekInput | |||
<TemporalWip.WeekInput | |||
label="Vacation" | |||
variant="default" | |||
border | |||