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..506af6ecf --- /dev/null +++ b/packages/uui-input-color/lib/uui-input-color.element.ts @@ -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'); + } + + renderPrepend() { + return html`
+ + +
`; + } + + 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; + } +} 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..833f1026f --- /dev/null +++ b/packages/uui-input-color/lib/uui-input-color.story.ts @@ -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 = { + id: 'uui-input-color', + title: 'Inputs/Input Color', + component: 'uui-input-color', + args: { + label: 'Color', + value: '#d0021b', + }, + render: args => html``, + parameters: { + readme: { + markdown: readme, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Overview: Story = {}; + +export const Empty: Story = { + args: { + value: '', + }, +}; + +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..29ee05ffd --- /dev/null +++ b/packages/uui-input-color/package.json @@ -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" +} 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..846270be1 --- /dev/null +++ b/packages/uui-input-color/tsconfig.json @@ -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" + }, + { + "path": "../uui-color-swatch" + }, + { + "path": "../uui-input" + } + ] +} 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..50557dda1 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. + // 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'; } } @@ -46,7 +46,7 @@ export class UUIInputPasswordElement extends UUIInputElement { } renderIcon() { - return this.passwordType === 'password' + return this.inputType === 'password' ? html`` : html` 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';