Skip to content

Feature: Input color #1156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions packages/uui-input-color/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# uui-input-color

![npm](https://img.shields.io/npm/v/@umbraco-ui/uui-input-color?logoColor=%231B264F)

Umbraco style input-color component.

## Installation

### ES imports

```zsh
npm i @umbraco-ui/uui-input-color
```

Import the registration of `<uui-input-color>` via:

```javascript
import '@umbraco-ui/uui-input-color';
```

When looking to leverage the `UUIInputColorElement` base class as a type and/or for extension purposes, do so via:

```javascript
import { UUIInputColorElement } from '@umbraco-ui/uui-input-color';
```

## Usage

```html
<uui-input-color></uui-input-color>
```
1 change: 1 addition & 0 deletions packages/uui-input-color/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './uui-input-color.element';
120 changes: 120 additions & 0 deletions packages/uui-input-color/lib/uui-input-color.element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { demandCustomElement } from '@umbraco-ui/uui-base/lib/utils';
import { css, html } from 'lit';
import { InputType, UUIInputElement } from '@umbraco-ui/uui-input/lib';
import { property, query, state } from 'lit/decorators.js';
import type { UUIColorPickerElement } from '@umbraco-ui/uui-color-picker/lib';

/**
* @element uui-input-color
* @extends uui-input
*/
@defineElement('uui-input-color')
export class UUIInputColorElement extends UUIInputElement {
@state()
private inputType: InputType = 'text';

@state()
private _valueHex = '';

@query('#color')
protected _colorPicker!: UUIColorPickerElement;

@property({ type: String })
public override set value(value: string) {
if (value.startsWith('#')) {
this._valueHex = value;
super.value = value.substring(1);
} else {
super.value = value;
this._valueHex = `#${value}`;
}
}
public override get value() {
return super.value as string;
}

// this overrides the inherited type property, and moves the input's type handling to the inputType state.
@property()
get type() {
return this.inputType;
}
set type(newValue) {
this.inputType = newValue;
}

#onColorClick() {
if (this.disabled || this.readonly) {
return;
}
this._colorPicker.click();
}

#onColorChange(event: Event) {
event.stopPropagation();
this.value = this._colorPicker.value;
}

connectedCallback(): void {
super.connectedCallback();

demandCustomElement(this, 'uui-color-swatch');
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component demands 'uui-color-swatch' but the template uses 'uui-color-swatch'. However, the import statement references 'UUIColorPickerElement' which suggests a mismatch in dependencies.

Copilot uses AI. Check for mistakes.

}

renderPrepend() {
return html`<div class="color-wrapper">
<uui-color-swatch
?disabled=${this.disabled}
?readonly=${this.readonly}
value=${this._valueHex}
@click=${this.#onColorClick}></uui-color-swatch>
<input
type="color"
id="color"
aria-hidden="true"
value=${this.value}
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The color input value should use _valueHex instead of this.value to ensure proper hex format. The native color input expects a hex value with the # prefix.

Suggested change
value=${this.value}
value=${this._valueHex}

Copilot uses AI. Check for mistakes.

@change=${this.#onColorChange} />
</div>`;
}

static styles = [
...UUIInputElement.styles,
css`
.color-wrapper {
display: inline-flex;
position: relative;
border-right: var(--uui-input-border-width, 1px) solid
var(--uui-input-border-color, var(--uui-color-border));
}

input[type='color'] {
appearance: none;
visibility: hidden;
width: 0px;
padding: 0;
margin: 0;
position: absolute;
}

uui-color-swatch {
padding: var(--uui-size-1);
}

uui-color-swatch:not([disabled], [readonly]) {
cursor: pointer;
}

uui-color-swatch:focus-within {
outline: 2px solid var(--uui-color-selected);
outline-offset: 0;
border-radius: var(--uui-border-radius);
}
`,
];
}

declare global {
interface HTMLElementTagNameMap {
'uui-input-color': UUIInputColorElement;
}
}
49 changes: 49 additions & 0 deletions packages/uui-input-color/lib/uui-input-color.story.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { Meta, StoryObj } from '@storybook/web-components';

import './uui-input-color.element';
import type { UUIInputColorElement } from './uui-input-color.element';
import readme from '../README.md?raw';
import { html } from 'lit';
import { spread } from '../../../storyhelpers';

/**
* uui-input-color extends uui-input. See [uui-input](/docs/uui-input--docs) for more details.
*/
const meta: Meta<UUIInputColorElement> = {
id: 'uui-input-color',
title: 'Inputs/Input Color',
component: 'uui-input-color',
args: {
label: 'Color',
value: '#d0021b',
},
render: args => html`<uui-input-color ${spread(args)}></uui-input-color>`,
parameters: {
readme: {
markdown: readme,
},
},
};

export default meta;
type Story = StoryObj<UUIInputColorElement>;

export const Overview: Story = {};

export const Empty: Story = {
args: {
value: '',
},
};

export const Disabled: Story = {
args: {
disabled: true,
},
};

export const Readonly: Story = {
args: {
readonly: true,
},
};
18 changes: 18 additions & 0 deletions packages/uui-input-color/lib/uui-input-color.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, fixture, expect } from '@open-wc/testing';
import { UUIInputColorElement } from './uui-input-color.element';

describe('UUIInputColorElement', () => {
let element: UUIInputColorElement;

beforeEach(async () => {
element = await fixture(html` <uui-input-color></uui-input-color> `);
});

it('is defined with its own instance', () => {
expect(element).to.be.instanceOf(UUIInputColorElement);
});

it('passes the a11y audit', async () => {
await expect(element).shadowDom.to.be.accessible();
});
});
46 changes: 46 additions & 0 deletions packages/uui-input-color/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@umbraco-ui/uui-input-color",
"version": "0.0.0",
"license": "MIT",
"keywords": [
"Umbraco",
"Custom elements",
"Web components",
"UI",
"Lit",
"Input Color"
],
"description": "Umbraco UI input-color component",
"repository": {
"type": "git",
"url": "https://github.com/umbraco/Umbraco.UI.git",
"directory": "packages/uui-input-color"
},
"bugs": {
"url": "https://github.com/umbraco/Umbraco.UI/issues"
},
"main": "./lib/index.js",
"module": "./lib/index.js",
"types": "./lib/index.d.ts",
"type": "module",
"customElements": "custom-elements.json",
"files": [
"lib/**/*.d.ts",
"lib/**/*.js",
"custom-elements.json"
],
"dependencies": {
"@umbraco-ui/uui-base": "1.14.1",
"@umbraco-ui/uui-color-swatch": "1.14.1",
"@umbraco-ui/uui-input": "1.14.1"
},
"scripts": {
"build": "npm run analyze && tsc --build --force && rollup -c rollup.config.js",
"clean": "tsc --build --clean && rimraf -g dist lib/*.js lib/**/*.js *.tgz lib/**/*.d.ts custom-elements.json",
"analyze": "web-component-analyzer **/*.element.ts --outFile custom-elements.json"
},
"publishConfig": {
"access": "public"
},
"homepage": "https://uui.umbraco.com/?path=/story/uui-input-color"
}
5 changes: 5 additions & 0 deletions packages/uui-input-color/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { UUIProdConfig } from '../rollup-package.config.mjs';

export default UUIProdConfig({
entryPoints: ['index'],
});
23 changes: 23 additions & 0 deletions packages/uui-input-color/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Don't edit this file directly. It is generated by /scripts/generate-ts-config.js

{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./lib",
"rootDir": "./lib",
"composite": true
},
"include": ["./**/*.ts"],
"exclude": ["./**/*.test.ts", "./**/*.story.ts"],
"references": [
{
"path": "../uui-base"
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dependency reference to uui-input package. The component extends UUIInputElement but the tsconfig.json doesn't include a reference to the uui-input package.

Suggested change
"path": "../uui-base"
"path": "../uui-base"
},
{
"path": "../uui-input"

Copilot uses AI. Check for mistakes.

},
{
"path": "../uui-color-swatch"
},
{
"path": "../uui-input"
}
]
}
18 changes: 9 additions & 9 deletions packages/uui-input-password/lib/uui-input-password.element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ import { property, state } from 'lit/decorators.js';
@defineElement('uui-input-password')
export class UUIInputPasswordElement extends UUIInputElement {
@state()
private passwordType: InputType = 'password';
private inputType: InputType = 'password';

// this overrides the inherited type property, and moves the input's type handling to the passwordType state.
// this overrides the inherited type property, and moves the input's type handling to the inputType state.
@property()
get type() {
return this.passwordType;
return this.inputType;
}
set type(newValue) {
this.passwordType = newValue;
this.inputType = newValue;
}

_onPasswordToggle() {
if (this.passwordType === 'password') {
this.passwordType = 'text';
if (this.inputType === 'password') {
this.inputType = 'text';
} else {
this.passwordType = 'password';
this.inputType = 'password';
}
}

Expand All @@ -46,7 +46,7 @@ export class UUIInputPasswordElement extends UUIInputElement {
}

renderIcon() {
return this.passwordType === 'password'
return this.inputType === 'password'
? html`<uui-icon name="see" .fallback=${iconSee.strings[0]}></uui-icon>`
: html`<uui-icon
name="unsee"
Expand All @@ -58,7 +58,7 @@ export class UUIInputPasswordElement extends UUIInputElement {
.disabled=${this.disabled}
@click=${this._onPasswordToggle}
compact
label="${this.passwordType === 'password'
label="${this.inputType === 'password'
? 'Show password'
: 'Hide password'}"
id="eye">
Expand Down
1 change: 1 addition & 0 deletions packages/uui/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export * from '@umbraco-ui/uui-form/lib';
export * from '@umbraco-ui/uui-icon-registry-essential/lib';
export * from '@umbraco-ui/uui-icon-registry/lib';
export * from '@umbraco-ui/uui-icon/lib';
export * from '@umbraco-ui/uui-input-color/lib';
export * from '@umbraco-ui/uui-input-file/lib';
export * from '@umbraco-ui/uui-input-lock/lib';
export * from '@umbraco-ui/uui-input-password/lib';
Expand Down
Loading