Skip to content

Commit

Permalink
feat(circuit-ui): Add experimental ColorInput component (#2655)
Browse files Browse the repository at this point in the history
Co-authored-by: Connor Bär <connor-baer@users.noreply.github.com>
Co-authored-by: Connor Bär <github@connorbaer.com>
  • Loading branch information
3 people authored Sep 9, 2024
1 parent 04a7016 commit 5c62949
Show file tree
Hide file tree
Showing 10 changed files with 404 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-seahorses-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sumup/circuit-ui": minor
---

Added an experimental ColorInput component that enables users to type or select a color.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"lint:fix": "biome check --write && foundry run eslint . --ext .js,.jsx,.ts,.tsx --fix",
"lint:ci": "biome ci && foundry run eslint . --ext .js,.jsx,.ts,.tsx --quiet ",
"lint:css": "foundry run stylelint '**/*.css'",
"lint:css:fix": "foundry run stylelint '**/*.css' --fix",
"dev": "npm run docs:start",
"docs": "npm run docs:start",
"docs:start": "storybook dev -p 6006",
Expand Down Expand Up @@ -95,4 +96,4 @@
"vitest": "^2.0.3",
"vitest-github-actions-reporter": "^0.11.1"
}
}
}
13 changes: 13 additions & 0 deletions packages/circuit-ui/components/ColorInput/ColorInput.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Meta, Status, Props, Story } from '../../../../.storybook/components';
import * as Stories from './ColorInput.stories';

<Meta of={Stories} />

# ColorInput

<Status variant="experimental" />

The ColorInput component enables users to type or select a color.

<Story of={Stories.Base} />
<Props />
83 changes: 83 additions & 0 deletions packages/circuit-ui/components/ColorInput/ColorInput.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.wrapper {
position: relative;
display: flex;
}

.picker {
position: relative;
width: var(--cui-spacings-exa);
height: var(--cui-spacings-exa);
margin-right: 1px;
cursor: pointer;
border-top-left-radius: var(--cui-border-radius-byte);
border-bottom-left-radius: var(--cui-border-radius-byte);
box-shadow: 0 0 0 1px var(--cui-border-normal);
}

.picker:hover {
z-index: var(--cui-z-index-absolute);
background: var(--cui-bg-normal-hovered);
box-shadow: 0 0 0 1px var(--cui-border-normal-hovered);
}

.picker:focus-within {
z-index: var(--cui-z-index-absolute);
background: var(--cui-bg-normal-pressed);
box-shadow: 0 0 0 2px var(--cui-border-focus);
}

.color-input {
width: var(--cui-spacings-giga);
height: var(--cui-spacings-giga);
padding: 0;
margin: var(--cui-spacings-kilo);
appearance: none;
cursor: pointer;
border: none;
border-radius: 6px;
outline: none;
box-shadow: 0 0 0 1px var(--cui-border-normal);
}

.color-input::-moz-color-swatch {
border: none;
}

.color-input::-webkit-color-swatch-wrapper {
padding: 0;
border-radius: 0;
}

.color-input::-webkit-color-swatch {
border: none;
}

.symbol {
position: absolute;
top: 0;
left: var(--cui-spacings-exa);
z-index: calc(var(--cui-z-index-absolute) + 1);
display: grid;
place-items: center center;
width: var(--cui-spacings-giga);
height: var(--cui-spacings-exa);
font-family: var(--cui-font-stack-mono);
color: var(--cui-fg-subtle);
}

.input {
position: relative;
padding-left: var(--cui-spacings-giga);
font-family: var(--cui-font-stack-mono);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

.input:hover,
.input:focus {
z-index: var(--cui-z-index-absolute);
}

.input::placeholder {
font-family: var(--cui-font-stack-mono);
}
64 changes: 64 additions & 0 deletions packages/circuit-ui/components/ColorInput/ColorInput.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright 2024, SumUp Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, expect, it } from 'vitest';
import { createRef } from 'react';

import { render, axe, screen } from '../../util/test-utils.js';
import type { InputElement } from '../Input/index.js';

import { ColorInput } from './ColorInput.js';

describe('ColorInput', () => {
const baseProps = { label: 'Car color', pickerLabel: 'Pick car color' };

it('should merge a custom class name with the default ones', () => {
const className = 'foo';
const { container } = render(
<ColorInput {...baseProps} inputClassName={className} />,
);
const input = container.querySelector('input[type="text"]');
expect(input?.className).toContain(className);
});

it('should forward a ref', () => {
const ref = createRef<InputElement>();
const { container } = render(<ColorInput {...baseProps} ref={ref} />);
const input = container.querySelector("input[type='color']");
expect(ref.current).toBe(input);
});

it('should have no accessibility violations', async () => {
const { container } = render(<ColorInput {...baseProps} />);
const actual = await axe(container);
expect(actual).toHaveNoViolations();
});

describe('Labeling', () => {
it('should accept a custom description via aria-describedby', () => {
const customDescription = 'Custom description';
const customDescriptionId = 'customDescriptionId';
render(
<>
<span id={customDescriptionId}>{customDescription}</span>
<ColorInput {...baseProps} aria-describedby={customDescriptionId} />
</>,
);
expect(screen.getByRole('textbox')).toHaveAccessibleDescription(
customDescription,
);
});
});
});
33 changes: 33 additions & 0 deletions packages/circuit-ui/components/ColorInput/ColorInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright 2024, SumUp Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ColorInput, type ColorInputProps } from './ColorInput.js';

export default {
title: 'Forms/Input/ColorInput',
component: ColorInput,
};

const baseArgs = {
label: 'Color',
pickerLabel: 'Pick color',
placeholder: '99ffbb',
};

export const Base = (args: ColorInputProps) => (
<ColorInput {...args} style={{ maxWidth: '250px' }} />
);

Base.args = baseArgs;
Loading

0 comments on commit 5c62949

Please sign in to comment.