From 2199308df4f4f257399a9dc077dacbef1e4e6e43 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Wed, 23 Jul 2025 14:43:23 +0200 Subject: [PATCH 01/12] Add input color component --- package-lock.json | 12 ++++ packages/uui-input-color/README.md | 31 ++++++++++ packages/uui-input-color/lib/index.ts | 1 + .../lib/uui-input-color.element.ts | 56 +++++++++++++++++++ .../lib/uui-input-color.story.ts | 36 ++++++++++++ .../lib/uui-input-color.test.ts | 18 ++++++ packages/uui-input-color/package.json | 44 +++++++++++++++ packages/uui-input-color/rollup.config.js | 5 ++ packages/uui-input-color/tsconfig.json | 17 ++++++ packages/uui/lib/index.ts | 1 + 10 files changed, 221 insertions(+) create mode 100644 packages/uui-input-color/README.md create mode 100644 packages/uui-input-color/lib/index.ts create mode 100644 packages/uui-input-color/lib/uui-input-color.element.ts create mode 100644 packages/uui-input-color/lib/uui-input-color.story.ts create mode 100644 packages/uui-input-color/lib/uui-input-color.test.ts create mode 100644 packages/uui-input-color/package.json create mode 100644 packages/uui-input-color/rollup.config.js create mode 100644 packages/uui-input-color/tsconfig.json diff --git a/package-lock.json b/package-lock.json index f0f60f8fc..fffa64553 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4197,6 +4197,10 @@ "resolved": "packages/uui-input", "link": true }, + "node_modules/@umbraco-ui/uui-input-color": { + "resolved": "packages/uui-input-color", + "link": true + }, "node_modules/@umbraco-ui/uui-input-file": { "resolved": "packages/uui-input-file", "link": true @@ -20091,6 +20095,14 @@ "@umbraco-ui/uui-base": "1.14.1" } }, + "packages/uui-input-color": { + "name": "@umbraco-ui/uui-input-color", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@umbraco-ui/uui-base": "1.14.1" + } + }, "packages/uui-input-file": { "name": "@umbraco-ui/uui-input-file", "version": "1.14.1", diff --git a/packages/uui-input-color/README.md b/packages/uui-input-color/README.md new file mode 100644 index 000000000..416b08e0f --- /dev/null +++ b/packages/uui-input-color/README.md @@ -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 `` 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 + +``` diff --git a/packages/uui-input-color/lib/index.ts b/packages/uui-input-color/lib/index.ts new file mode 100644 index 000000000..d549c20f4 --- /dev/null +++ b/packages/uui-input-color/lib/index.ts @@ -0,0 +1 @@ +export * from './uui-input-color.element'; diff --git a/packages/uui-input-color/lib/uui-input-color.element.ts b/packages/uui-input-color/lib/uui-input-color.element.ts new file mode 100644 index 000000000..2318825af --- /dev/null +++ b/packages/uui-input-color/lib/uui-input-color.element.ts @@ -0,0 +1,56 @@ +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, state } from 'lit/decorators.js'; + +/** + * @element uui-input-color + * @extends uui-input + */ +@defineElement('uui-input-color') +export class UUIInputColorElement extends UUIInputElement { + @state() + private inputType: InputType = 'color'; + + // this overrides the inherited type property, and moves the input's type handling to the passwordType state. + @property() + get type() { + return this.inputType; + } + set type(newValue) { + this.inputType = newValue; + } + + connectedCallback(): void { + super.connectedCallback(); + + demandCustomElement(this, 'uui-swatch'); + } + + renderPrepend() { + return html` + `; + } + + static styles = [...UUIInputElement.styles, css``]; + + /*render(){ + return html` +
+ + + + +
`; + }*/ +} + +declare global { + interface HTMLElementTagNameMap { + 'uui-input-color': UUIInputColorElement; + } +} diff --git a/packages/uui-input-color/lib/uui-input-color.story.ts b/packages/uui-input-color/lib/uui-input-color.story.ts new file mode 100644 index 000000000..7fbf99419 --- /dev/null +++ b/packages/uui-input-color/lib/uui-input-color.story.ts @@ -0,0 +1,36 @@ +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'; + +const meta: Meta = { + id: 'uui-input-color', + title: 'Inputs/Input Color', + component: 'uui-input-color', + parameters: { + readme: { markdown: readme }, + docs: { + source: { + code: ``, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Overview: Story = {}; + +export const Disabled: Story = { + args: { + disabled: true, + }, +}; + +export const Readonly: Story = { + args: { + readonly: true, + }, +}; diff --git a/packages/uui-input-color/lib/uui-input-color.test.ts b/packages/uui-input-color/lib/uui-input-color.test.ts new file mode 100644 index 000000000..9fc34830c --- /dev/null +++ b/packages/uui-input-color/lib/uui-input-color.test.ts @@ -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` `); + }); + + 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(); + }); +}); diff --git a/packages/uui-input-color/package.json b/packages/uui-input-color/package.json new file mode 100644 index 000000000..b00fcbf35 --- /dev/null +++ b/packages/uui-input-color/package.json @@ -0,0 +1,44 @@ +{ + "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" + }, + "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" +} diff --git a/packages/uui-input-color/rollup.config.js b/packages/uui-input-color/rollup.config.js new file mode 100644 index 000000000..34524a90d --- /dev/null +++ b/packages/uui-input-color/rollup.config.js @@ -0,0 +1,5 @@ +import { UUIProdConfig } from '../rollup-package.config.mjs'; + +export default UUIProdConfig({ + entryPoints: ['index'], +}); diff --git a/packages/uui-input-color/tsconfig.json b/packages/uui-input-color/tsconfig.json new file mode 100644 index 000000000..40d176776 --- /dev/null +++ b/packages/uui-input-color/tsconfig.json @@ -0,0 +1,17 @@ +// 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" + } + ] +} diff --git a/packages/uui/lib/index.ts b/packages/uui/lib/index.ts index aa3f630c3..14afbf7af 100644 --- a/packages/uui/lib/index.ts +++ b/packages/uui/lib/index.ts @@ -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'; From bd6a5fb6748edfa107aa49fe48d8882eb13e01d5 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Wed, 23 Jul 2025 14:52:55 +0200 Subject: [PATCH 02/12] Update stories --- packages/uui-input-color/lib/uui-input-color.element.ts | 6 +++--- packages/uui-input-color/lib/uui-input-color.story.ts | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/uui-input-color/lib/uui-input-color.element.ts b/packages/uui-input-color/lib/uui-input-color.element.ts index 2318825af..ba3faae92 100644 --- a/packages/uui-input-color/lib/uui-input-color.element.ts +++ b/packages/uui-input-color/lib/uui-input-color.element.ts @@ -25,15 +25,15 @@ export class UUIInputColorElement extends UUIInputElement { connectedCallback(): void { super.connectedCallback(); - demandCustomElement(this, 'uui-swatch'); + demandCustomElement(this, 'uui-color-swatch'); } renderPrepend() { - return html` - `; + `; } static styles = [...UUIInputElement.styles, css``]; diff --git a/packages/uui-input-color/lib/uui-input-color.story.ts b/packages/uui-input-color/lib/uui-input-color.story.ts index 7fbf99419..0a10384bf 100644 --- a/packages/uui-input-color/lib/uui-input-color.story.ts +++ b/packages/uui-input-color/lib/uui-input-color.story.ts @@ -23,6 +23,12 @@ type Story = StoryObj; export const Overview: Story = {}; +export const Empty: Story = { + args: { + value: '', + }, +}; + export const Disabled: Story = { args: { disabled: true, From 7eea98a76c3e8012e95232ab6b9e2be9195fb4ab Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Wed, 23 Jul 2025 16:24:32 +0200 Subject: [PATCH 03/12] Adjust markup --- .../lib/uui-input-color.element.ts | 61 +++++++++++++------ .../lib/uui-input-color.story.ts | 19 ++++-- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/packages/uui-input-color/lib/uui-input-color.element.ts b/packages/uui-input-color/lib/uui-input-color.element.ts index ba3faae92..3e4146974 100644 --- a/packages/uui-input-color/lib/uui-input-color.element.ts +++ b/packages/uui-input-color/lib/uui-input-color.element.ts @@ -11,7 +11,7 @@ import { property, state } from 'lit/decorators.js'; @defineElement('uui-input-color') export class UUIInputColorElement extends UUIInputElement { @state() - private inputType: InputType = 'color'; + private inputType: InputType = 'text'; // this overrides the inherited type property, and moves the input's type handling to the passwordType state. @property() @@ -22,6 +22,11 @@ export class UUIInputColorElement extends UUIInputElement { this.inputType = newValue; } + onChange(e: Event): void { + const target = e.target as HTMLInputElement; + this.value = target.value; + } + connectedCallback(): void { super.connectedCallback(); @@ -29,24 +34,46 @@ export class UUIInputColorElement extends UUIInputElement { } renderPrepend() { - return html` - `; + return html``; } - static styles = [...UUIInputElement.styles, css``]; - - /*render(){ - return html` -
- - - - -
`; - }*/ + static styles = [ + ...UUIInputElement.styles, + css` + :host { + } + + #color-picker { + cursor: pointer; + position: relative; + border-right: var(--uui-input-border-width, 1px) solid + var(--uui-input-border-color, var(--uui-color-border)); + } + + #color-input { + visibility: hidden; + appearance: none; + } + + uui-color-swatch { + margin-left: 0.25rem; + margin-right: 0.25rem; + } + `, + ]; } declare global { diff --git a/packages/uui-input-color/lib/uui-input-color.story.ts b/packages/uui-input-color/lib/uui-input-color.story.ts index 0a10384bf..2def4fa6b 100644 --- a/packages/uui-input-color/lib/uui-input-color.story.ts +++ b/packages/uui-input-color/lib/uui-input-color.story.ts @@ -3,17 +3,26 @@ 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 { renderSlots, spread } from '../../../storyhelpers'; +/** + * uui-input-color extends uui-input. See [uui-input](/docs/uui-input--docs) for more details. + */ const meta: Meta = { id: 'uui-input-color', title: 'Inputs/Input Color', component: 'uui-input-color', + args: { + label: 'Label', + }, + render: args => + html`${renderSlots(args)}`, parameters: { - readme: { markdown: readme }, - docs: { - source: { - code: ``, - }, + readme: { + markdown: readme, }, }, }; From f9a8d48b0cab562d101feb4f81748a99eb7dde36 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Wed, 23 Jul 2025 16:43:52 +0200 Subject: [PATCH 04/12] Change variable name --- .../lib/uui-input-password.element.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/uui-input-password/lib/uui-input-password.element.ts b/packages/uui-input-password/lib/uui-input-password.element.ts index c4f4d96f7..713111a30 100644 --- a/packages/uui-input-password/lib/uui-input-password.element.ts +++ b/packages/uui-input-password/lib/uui-input-password.element.ts @@ -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. @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'; } } @@ -46,7 +46,7 @@ export class UUIInputPasswordElement extends UUIInputElement { } renderIcon() { - return this.passwordType === 'password' + return this.inputType === 'password' ? html`` : html` From 45f4bfe362091a0c00adeb7b9876fb1fe627a8b0 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 24 Jul 2025 12:48:58 +0200 Subject: [PATCH 05/12] Adjustments --- .../lib/uui-input-color.element.ts | 59 ++++++++++++++----- .../lib/uui-input-color.story.ts | 16 ++--- .../lib/uui-input-password.element.ts | 2 +- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/packages/uui-input-color/lib/uui-input-color.element.ts b/packages/uui-input-color/lib/uui-input-color.element.ts index 3e4146974..eb558f8c4 100644 --- a/packages/uui-input-color/lib/uui-input-color.element.ts +++ b/packages/uui-input-color/lib/uui-input-color.element.ts @@ -2,7 +2,8 @@ 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, state } from 'lit/decorators.js'; +import { property, query, state } from 'lit/decorators.js'; +import type { UUIColorPickerElement } from '@umbraco-ui/uui-color-picker/lib'; /** * @element uui-input-color @@ -13,7 +14,27 @@ export class UUIInputColorElement extends UUIInputElement { @state() private inputType: InputType = 'text'; - // this overrides the inherited type property, and moves the input's type handling to the passwordType state. + @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; @@ -22,9 +43,13 @@ export class UUIInputColorElement extends UUIInputElement { this.inputType = newValue; } - onChange(e: Event): void { - const target = e.target as HTMLInputElement; - this.value = target.value; + #onColorClick() { + this._colorPicker.click(); + } + + #onColorChange(event: Event) { + event.stopPropagation(); + this.value = this._colorPicker.value; } connectedCallback(): void { @@ -34,20 +59,21 @@ export class UUIInputColorElement extends UUIInputElement { } renderPrepend() { - return html`