From 37180039a77d908acd731c89067ecfce3f23955f Mon Sep 17 00:00:00 2001 From: Nantawat Poothong <102957966+Nantawat-Poothong@users.noreply.github.com> Date: Wed, 31 Aug 2022 14:47:43 +0700 Subject: [PATCH] feat(color-picker): add color picker (#444) * feat(color-picker): add color picker * fix(color-dialog): import test path * chore(color-picker): update code style * fix(color-picker): update snapshot ignore style * fix(color-picker): add missing end tag * chore(color-picker): rename test file --- documents/src/pages/elements/color-picker.md | 56 ++++ .../src/custom-elements/ef-color-picker.less | 33 +++ packages/elements/package.json | 5 + .../__test__/color-dialog.test.js | 4 +- .../__test__/color-helpers.test.js | 2 +- .../src/color-dialog/elements/palettes.ts | 3 +- .../src/color-dialog/helpers/color-helpers.ts | 17 -- .../src/color-dialog/helpers/value-model.ts | 3 +- packages/elements/src/color-dialog/index.ts | 3 +- .../src/color-picker/__demo__/index.html | 65 +++++ .../color-picker/__snapshots__/ColorPicker.md | 42 +++ .../__test__/color-picker.test.js | 114 ++++++++ packages/elements/src/color-picker/index.ts | 252 ++++++++++++++++++ .../src/custom-elements/ef-color-picker.less | 7 + packages/phrasebook/package.json | 5 + .../phrasebook/src/locale/de/color-picker.ts | 11 + .../phrasebook/src/locale/en/color-picker.ts | 11 + .../phrasebook/src/locale/ja/color-picker.ts | 11 + .../src/locale/zh-hant/color-picker.ts | 11 + .../phrasebook/src/locale/zh/color-picker.ts | 11 + .../src/custom-elements/ef-color-picker.less | 7 + packages/utils/src/color.ts | 1 + packages/utils/src/color/color.ts | 16 ++ 23 files changed, 664 insertions(+), 26 deletions(-) create mode 100644 documents/src/pages/elements/color-picker.md create mode 100644 packages/elemental-theme/src/custom-elements/ef-color-picker.less create mode 100644 packages/elements/src/color-picker/__demo__/index.html create mode 100644 packages/elements/src/color-picker/__snapshots__/ColorPicker.md create mode 100644 packages/elements/src/color-picker/__test__/color-picker.test.js create mode 100644 packages/elements/src/color-picker/index.ts create mode 100644 packages/halo-theme/src/custom-elements/ef-color-picker.less create mode 100644 packages/phrasebook/src/locale/de/color-picker.ts create mode 100644 packages/phrasebook/src/locale/en/color-picker.ts create mode 100644 packages/phrasebook/src/locale/ja/color-picker.ts create mode 100644 packages/phrasebook/src/locale/zh-hant/color-picker.ts create mode 100644 packages/phrasebook/src/locale/zh/color-picker.ts create mode 100644 packages/solar-theme/src/custom-elements/ef-color-picker.less create mode 100644 packages/utils/src/color/color.ts diff --git a/documents/src/pages/elements/color-picker.md b/documents/src/pages/elements/color-picker.md new file mode 100644 index 0000000000..18454ac4f1 --- /dev/null +++ b/documents/src/pages/elements/color-picker.md @@ -0,0 +1,56 @@ + + +# Color Picker +:: +```javascript +::color-picker:: +``` +```css + +``` +```html +
+ + + + +
+``` +:: + +`ef-color-picker` allows users to pick any colours from colour dialog. + +### Basic usage +You can set an initial value via `value` attribute. The `value` must be a string of hex colour code. + +```html + +``` + +### Getting value +A value of Color picker can be accessed through `value` property. It will fire `value-changed` event when users picked a new colour. `value` will be an empty string if users choose No Color. + +### 'No Color' option +In some circumstances, it might be necessary that the component should allow user to select "no color". This can be done by using a property/attribute `allow-nocolor` to activate this feature. + +Color picker will set attribute/property `value` to `""` when users select no-color from the colour dialog. + +```html + +``` diff --git a/packages/elemental-theme/src/custom-elements/ef-color-picker.less b/packages/elemental-theme/src/custom-elements/ef-color-picker.less new file mode 100644 index 0000000000..f6b46685b1 --- /dev/null +++ b/packages/elemental-theme/src/custom-elements/ef-color-picker.less @@ -0,0 +1,33 @@ + +@import 'element:ef-color-dialog'; +@import '../responsive'; + +:host { + @color-picker-size: @button-height; + @color-picker-border: @control-border-color; + @color-picker-focused-border-color: @scheme-color-primary; + + outline: none; + box-sizing: border-box; + height: @color-picker-size; + min-width: @color-picker-size; + border: 1px solid @color-picker-border; + + &[disabled], &[readonly] { + border-color: @input-disabled-border-color; + } + + [part="color-item"] { + cursor: pointer; + height: 100%; + } + + &[disabled] [part="color-item"], + &[readonly] [part="color-item"] { + pointer-events: none; + } + + &[focused=visible] { + border-color: @color-picker-focused-border-color; + } +} \ No newline at end of file diff --git a/packages/elements/package.json b/packages/elements/package.json index 38815b0f69..6e71645f3c 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -91,6 +91,11 @@ "./color-dialog/themes/halo/light": "./lib/color-dialog/themes/halo/light/index.js", "./color-dialog/themes/solar/charcoal": "./lib/color-dialog/themes/solar/charcoal/index.js", "./color-dialog/themes/solar/pearl": "./lib/color-dialog/themes/solar/pearl/index.js", + "./color-picker": "./lib/color-picker/index.js", + "./color-picker/themes/halo/dark": "./lib/color-picker/themes/halo/dark/index.js", + "./color-picker/themes/halo/light": "./lib/color-picker/themes/halo/light/index.js", + "./color-picker/themes/solar/charcoal": "./lib/color-picker/themes/solar/charcoal/index.js", + "./color-picker/themes/solar/pearl": "./lib/color-picker/themes/solar/pearl/index.js", "./combo-box": "./lib/combo-box/index.js", "./combo-box/themes/halo/dark": "./lib/combo-box/themes/halo/dark/index.js", "./combo-box/themes/halo/light": "./lib/combo-box/themes/halo/light/index.js", diff --git a/packages/elements/src/color-dialog/__test__/color-dialog.test.js b/packages/elements/src/color-dialog/__test__/color-dialog.test.js index 1987cfbc07..e0a45b69a6 100644 --- a/packages/elements/src/color-dialog/__test__/color-dialog.test.js +++ b/packages/elements/src/color-dialog/__test__/color-dialog.test.js @@ -5,8 +5,8 @@ import '@refinitiv-ui/elements/color-dialog'; import '@refinitiv-ui/elemental-theme/light/ef-color-dialog'; import '@refinitiv-ui/elemental-theme/light/ef-text-field'; import '@refinitiv-ui/elemental-theme/light/ef-number-field'; -import { rgb } from '@refinitiv-ui/utils'; -import { COLOR_ITEMS, removeHashSign } from '../../../lib/color-dialog/helpers/color-helpers'; +import { rgb, removeHashSign } from '@refinitiv-ui/utils/color.js'; +import { COLOR_ITEMS } from '../../../lib/color-dialog/helpers/color-helpers'; describe('color-dialog/ColorDialog', () => { describe('Default Color Dialog', () => { diff --git a/packages/elements/src/color-dialog/__test__/color-helpers.test.js b/packages/elements/src/color-dialog/__test__/color-helpers.test.js index 48358ac28d..6192222efb 100644 --- a/packages/elements/src/color-dialog/__test__/color-helpers.test.js +++ b/packages/elements/src/color-dialog/__test__/color-helpers.test.js @@ -1,4 +1,4 @@ -import { isHex } from '../../../lib/color-dialog/helpers/color-helpers.js'; +import { isHex } from '@refinitiv-ui/utils/color.js'; import { expect } from '@refinitiv-ui/test-helpers'; describe('color-dialog/Helpers', () => { diff --git a/packages/elements/src/color-dialog/elements/palettes.ts b/packages/elements/src/color-dialog/elements/palettes.ts index be1460a24c..d668ee67f8 100644 --- a/packages/elements/src/color-dialog/elements/palettes.ts +++ b/packages/elements/src/color-dialog/elements/palettes.ts @@ -6,8 +6,7 @@ import { import { property } from '@refinitiv-ui/core/decorators/property.js'; import { query } from '@refinitiv-ui/core/decorators/query.js'; import { VERSION } from '../../version.js'; -import { rgb } from '@refinitiv-ui/utils/color.js'; -import { isHex } from '../helpers/color-helpers.js'; +import { rgb, isHex } from '@refinitiv-ui/utils/color.js'; /** * Element base class usually used diff --git a/packages/elements/src/color-dialog/helpers/color-helpers.ts b/packages/elements/src/color-dialog/helpers/color-helpers.ts index 442398035e..5ca173857a 100644 --- a/packages/elements/src/color-dialog/helpers/color-helpers.ts +++ b/packages/elements/src/color-dialog/helpers/color-helpers.ts @@ -146,20 +146,3 @@ export const GRAYSCALE_ITEMS = [ ]; export const NOCOLOR_POINTS = '6, 2, 15, 6, 15, 17, 6, 21, -3, 17, -3, 6'; - -const HEX_REGEXP = /^#([0-9A-F]{3}){1,2}$/i; // used to validate HEX -export const isHex = (value: string): boolean => HEX_REGEXP.test(value); - -/** - * Remove hash (#) sign from hex value - * @param hex Hex to check - * @returns hex value without # sign - */ -export const removeHashSign = (hex: string): string => { - if (hex) { - if (hex.startsWith('#')) { - hex = hex.slice(1); - } - } - return hex; -}; diff --git a/packages/elements/src/color-dialog/helpers/value-model.ts b/packages/elements/src/color-dialog/helpers/value-model.ts index 774c8f7495..5a4e18d243 100644 --- a/packages/elements/src/color-dialog/helpers/value-model.ts +++ b/packages/elements/src/color-dialog/helpers/value-model.ts @@ -1,5 +1,4 @@ -import { rgb } from '@refinitiv-ui/utils/color.js'; -import { isHex } from './color-helpers.js'; +import { rgb, isHex } from '@refinitiv-ui/utils/color.js'; const rgbNumberToString = (value: number): string => isNaN(value) ? '' : `${value}`; // replace NaN with empty string diff --git a/packages/elements/src/color-dialog/index.ts b/packages/elements/src/color-dialog/index.ts index 0be7c4ec37..f8cc22846b 100644 --- a/packages/elements/src/color-dialog/index.ts +++ b/packages/elements/src/color-dialog/index.ts @@ -10,13 +10,12 @@ import { customElement } from '@refinitiv-ui/core/decorators/custom-element.js'; import { property } from '@refinitiv-ui/core/decorators/property.js'; import { query } from '@refinitiv-ui/core/decorators/query.js'; import { styleMap } from '@refinitiv-ui/core/directives/style-map.js'; -import { rgb } from '@refinitiv-ui/utils/color.js'; +import { rgb, isHex, removeHashSign } from '@refinitiv-ui/utils/color.js'; import { VERSION } from '../version.js'; import type { NumberField } from '../number-field'; import type { TextField } from '../text-field'; import type { Palettes } from './elements/palettes'; import { ValueModel } from './helpers/value-model.js'; -import { isHex, removeHashSign } from './helpers/color-helpers.js'; import '../button/index.js'; import '../number-field/index.js'; import '../text-field/index.js'; diff --git a/packages/elements/src/color-picker/__demo__/index.html b/packages/elements/src/color-picker/__demo__/index.html new file mode 100644 index 0000000000..625b1cf3d5 --- /dev/null +++ b/packages/elements/src/color-picker/__demo__/index.html @@ -0,0 +1,65 @@ + + + + + + Color Picker + + + + + + + + +
+ Default Hex Value (Optional): +
+
+

Output:

+ +
+ +
+ + + + + + diff --git a/packages/elements/src/color-picker/__snapshots__/ColorPicker.md b/packages/elements/src/color-picker/__snapshots__/ColorPicker.md new file mode 100644 index 0000000000..096d56590c --- /dev/null +++ b/packages/elements/src/color-picker/__snapshots__/ColorPicker.md @@ -0,0 +1,42 @@ +# `color-picker/ColorPicker` + +## `DOM structure` + +#### `DOM structure is correct` + +```html +
+
+ +``` + +#### `DOM structure is correct when opened` + +```html +
+
+ + + + + + + +``` + diff --git a/packages/elements/src/color-picker/__test__/color-picker.test.js b/packages/elements/src/color-picker/__test__/color-picker.test.js new file mode 100644 index 0000000000..dfbe9533cf --- /dev/null +++ b/packages/elements/src/color-picker/__test__/color-picker.test.js @@ -0,0 +1,114 @@ +import { fixture, expect, elementUpdated, keyboardEvent, oneEvent } from '@refinitiv-ui/test-helpers'; +// import element and theme +import '@refinitiv-ui/elements/color-picker'; +import '@refinitiv-ui/elemental-theme/light/ef-color-picker'; + +describe('color-picker/ColorPicker', () => { + + describe('DOM structure', () => { + it('DOM structure is correct', async () => { + const el = await fixture(''); + expect(el).shadowDom.to.equalSnapshot(); + }); + it('DOM structure is correct when opened', async () => { + const el = await fixture(''); + expect(el).shadowDom.to.equalSnapshot({ ignoreAttributes: ['class', 'style'] }); + }); + }); + + describe('Value property', () => { + it('Should have default value', async () => { + const el = await fixture(''); + expect(el.value).to.equal(''); + }); + it('Should update value when set hex color', async () => { + const el = await fixture(''); + expect(el.value).to.equal('#001EFF'); + }); + it('Should reset to default value when value is invalid', async () => { + const el = await fixture(''); + expect(el.value).to.equal(''); + }); + it("Should not fires value-changed event when programmatically changes value", async () => { + const value = '#001EFF'; + const el = await fixture(''); + + let eventFired = false; + el.addEventListener('value-changed', () => { + eventFired = true; + }); + el.value = value; + expect(el.value).to.equal(value); + expect(eventFired).to.equal(false); + }); + it('Should fires value-changed event when value change by user interactions', async () => { + const el = await fixture(''); + const dialogEl = el.dialogEl; + const redInput = dialogEl.shadowRoot.getElementById('redInput'); + const confirmBtn = dialogEl.shadowRoot.getElementById('confirmButton'); + redInput.value = 200; + redInput.dispatchEvent(new Event('value-changed')); + await elementUpdated(); + setTimeout(() => confirmBtn.click()); + await oneEvent(el, 'value-changed'); + await elementUpdated(); + expect(el.value).to.equal('#c81eff'); + }); + }); + + describe('No color property', () => { + it('Should not have allow-nocolor property on color dialog', async () => { + const el = await fixture(''); + el.opened = true; + await elementUpdated(el); + expect(el.dialogEl.hasAttribute('allow-nocolor')).to.be.equal(false); + }); + it('Should pass allow-nocolor property to color dialog', async () => { + const el = await fixture(''); + el.opened = true; + await elementUpdated(el); + expect(el.dialogEl.hasAttribute('allow-nocolor')).to.be.equal(true); + }); + }); + + describe('Color dialog', () => { + it('Should open dialog when click on color picker', async () => { + const el = await fixture(''); + el.click(); + await elementUpdated(el); + expect(el.dialogEl.opened).to.be.equal(true, 'clicking on color picker should open color dialog'); + }); + it('Should open dialog when opened programmatically', async () => { + const el = await fixture(''); + el.opened = true; + await elementUpdated(el); + expect(el.dialogEl.hasAttribute('opened')).to.be.equal(true); + }); + it('Should not open color dialog when disabled', async () => { + const el = await fixture(''); + el.click(); + expect(el.opened).to.be.equal(false, 'clicking on disabled should do nothing'); + }); + it('Should not open color dialog when readonly', async () => { + const el = await fixture(''); + el.click(); + expect(el.opened).to.be.equal(false, 'clicking on readonly should do nothing'); + }); + }); + + describe('Navigation', () => { + it('Should open dialog when press enter key', async () => { + const el = await fixture(''); + el.dispatchEvent(keyboardEvent('keydown', { key: 'Enter' })); + await elementUpdated(el); + expect(el.dialogEl.opened).to.be.equal(true, 'Enter should open dialog'); + }); + it('Should open dialog when press spacebar key', async () => { + const el = await fixture(''); + el.dispatchEvent(keyboardEvent('keydown', { key: 'Spacebar' })); + await elementUpdated(el); + expect(el.dialogEl.opened).to.be.equal(true, 'Spacebar should open dialog'); + }); + }); +}); + diff --git a/packages/elements/src/color-picker/index.ts b/packages/elements/src/color-picker/index.ts new file mode 100644 index 0000000000..cb3c40a7d6 --- /dev/null +++ b/packages/elements/src/color-picker/index.ts @@ -0,0 +1,252 @@ +import { + ControlElement, + html, + css, + PropertyValues, + TemplateResult, + TapEvent, + CSSResult, + WarningNotice +} from '@refinitiv-ui/core'; +import { customElement } from '@refinitiv-ui/core/decorators/custom-element.js'; +import type { OpenedChangedEvent, ValueChangedEvent } from '../events'; +import { property } from '@refinitiv-ui/core/decorators/property.js'; +import { query } from '@refinitiv-ui/core/decorators/query.js'; +import { styleMap } from '@refinitiv-ui/core/directives/style-map.js'; +import { ifDefined } from '@refinitiv-ui/core/directives/if-defined.js'; +import { VERSION } from '../version.js'; +import { isHex } from '@refinitiv-ui/utils/color.js'; +import '../color-dialog/index.js'; +import type { ColorDialog } from '../color-dialog/index.js'; +import '@refinitiv-ui/phrasebook/locale/en/color-picker.js'; + +const DIALOG_POSITION = ['right-start', 'right-end', 'right-middle', 'left-start', 'left-end', 'left-middle']; + +/** + * + * Color picker control + * @fires value-changed - Dispatched when value changes + * + * @attr {boolean} readonly - Set readonly state + * @prop {boolean} [readonly=false] - Set readonly state + * + * @attr {boolean} disabled - Set disabled state + * @prop {boolean} [disabled=false] - Set disabled state + */ +@customElement('ef-color-picker', { + alias: 'emerald-color-picker' +}) +export class ColorPicker extends ControlElement { + /** + * Element version number + * @returns version number + */ + static get version (): string { + return VERSION; + } + + /** + * Set the color dialog to activate no-color option + */ + @property({ type: Boolean, attribute: 'allow-nocolor' }) + public allowNocolor = false; + + /** + * Set lang to color dialog + * @ignore + */ + @property({ type: String }) + public lang = ''; + + /** + * A `CSSResult` that will be used + * to style the host, slotted children + * and the internal template of the element. + * @returns CSS template + */ + static get styles (): CSSResult | CSSResult[] { + return css` + :host { + display: inline-block; + } + [part=color-item][no-color] { + background: linear-gradient(to bottom right, transparent calc(50% - 1px), + var(--no-color-line-color, #ff0000) calc(50% - 1px), + var(--no-color-line-color, #ff0000) calc(50% + 1px), + transparent calc(50% + 1px)); + } + `; + } + + private lazyRendered = false; /* speed up rendering by not populating color dialog on first load */ + + /** + * Toggles the opened state of the dialog + */ + @property({ type: Boolean, reflect: true }) + public opened = false; + + @query('[part=dialog]') private dialogEl?: ColorDialog | null; + + /** + * Check if value is valid HEX value (including #) + * @param value Value to check + * @returns true if value is valid + */ + protected isValidValue (value: string): boolean { + return value === '' || isHex(value); + } + + /** + * Used to show a warning when the value does not pass the validation + * @param value that is invalid + * @returns {void} + */ + protected warnInvalidValue (value: string): void { + new WarningNotice(`The specified value "${value}" is not valid value. The correct value should look like "#fff" or "#ffffff".`).show(); + } + + /** + * Return true if popup can be opened + */ + private get canOpenPopup (): boolean { + return !(this.disabled || this.readonly); + } + + /** + * Called after the component is first rendered + * @param changedProperties Properties which have changed + * @returns {void} + */ + protected firstUpdated (changedProperties: PropertyValues): void { + super.firstUpdated(changedProperties); + this.addEventListener('tap', this.onTap); + this.addEventListener('keydown', this.onKeyDown); + } + + /** + * Updates the element + * @param changedProperties Properties that has changed + * @returns {void} + */ + protected update (changedProperties: PropertyValues): void { + if (changedProperties.has('opened') && this.opened) { + this.lazyRendered = true; + } + // make sure to close dialog for disabled + if (this.opened && !this.canOpenPopup) { + this.opened = false; /* this cannot be nor stopped nor listened */ + } + + super.update(changedProperties); + } + + /** + * Run on tap event + * @param event Tap event + * @returns {void} + */ + private onTap (event: TapEvent): void { + const path = event.composedPath(); + if ((this.dialogEl && path.includes(this.dialogEl)) || event.defaultPrevented) { + return; /* dialog is managed separately */ + } + this.setOpened(!this.opened); + } + + /** + * Handles key input on color picker + * @param event Key down event object + * @returns {void} + */ + private onKeyDown (event: KeyboardEvent): void { + if (event.defaultPrevented) { + return; + } + switch (event.key) { + case 'Enter': + case ' ': + case 'Spacebar': + this.setOpened(true); + break; + default: + return; + } + event.preventDefault(); + } + + /** + * Set opened state with event + * @param opened True if opened + * @returns {void} + */ + private setOpened (opened: boolean): void { + if (opened && !this.canOpenPopup) { /* never allow to open popup if cannot do so */ + return; + } + if (this.opened !== opened) { + this.opened = opened; + } + } + + /** + * Run on color dialog value-changed event + * @param event value-changed event + * @returns {void} + */ + private onColorDialogValueChanged (event: ValueChangedEvent): void { + const value = event.detail.value; + this.value = value; + this.setAttribute('value', this.value); + this.notifyPropertyChange('value', this.value); + this.setOpened(false); + } + + /** + * Run on color dialog opened-changed event + * @param event opened-changed event + * @returns {void} + */ + private onColorDialogOpenedChanged (event: OpenedChangedEvent): void { + this.setOpened(event.detail.value); + } + + /** + * Color dialog template + */ + private get dialogTemplate (): TemplateResult | undefined { + if (this.lazyRendered) { + return html``; + } + } + + /** + * Color item template + */ + private get colorItemTemplate (): TemplateResult | undefined { + return html`
`; + } + + /** + * A `TemplateResult` that will be used + * to render the updated internal template. + * @return Render template + */ + protected render (): TemplateResult { + return html` + ${this.colorItemTemplate} + ${this.dialogTemplate} + `; + } +} diff --git a/packages/halo-theme/src/custom-elements/ef-color-picker.less b/packages/halo-theme/src/custom-elements/ef-color-picker.less new file mode 100644 index 0000000000..ce9740c1f2 --- /dev/null +++ b/packages/halo-theme/src/custom-elements/ef-color-picker.less @@ -0,0 +1,7 @@ +@import '@refinitiv-ui/elemental-theme/src/custom-elements/ef-color-picker'; + +:host { + &:not([readonly]):not([disabled]):not([focused]):hover { + border-color: @input-hover-border-color; + } +} diff --git a/packages/phrasebook/package.json b/packages/phrasebook/package.json index 150f7c1ecf..d796a42a8f 100644 --- a/packages/phrasebook/package.json +++ b/packages/phrasebook/package.json @@ -26,6 +26,7 @@ "./locale/de/calendar.js": "./lib/locale/de/calendar.js", "./locale/de/clock.js": "./lib/locale/de/clock.js", "./locale/de/color-dialog.js": "./lib/locale/de/color-dialog.js", + "./locale/de/color-picker.js": "./lib/locale/de/color-picker.js", "./locale/de/combo-box.js": "./lib/locale/de/combo-box.js", "./locale/de/datetime-field.js": "./lib/locale/de/datetime-field.js", "./locale/de/dialog.js": "./lib/locale/de/dialog.js", @@ -43,6 +44,7 @@ "./locale/en/calendar.js": "./lib/locale/en/calendar.js", "./locale/en/clock.js": "./lib/locale/en/clock.js", "./locale/en/color-dialog.js": "./lib/locale/en/color-dialog.js", + "./locale/en/color-picker.js": "./lib/locale/en/color-picker.js", "./locale/en/combo-box.js": "./lib/locale/en/combo-box.js", "./locale/en/datetime-field.js": "./lib/locale/en/datetime-field.js", "./locale/en/dialog.js": "./lib/locale/en/dialog.js", @@ -60,6 +62,7 @@ "./locale/ja/calendar.js": "./lib/locale/ja/calendar.js", "./locale/ja/clock.js": "./lib/locale/ja/clock.js", "./locale/ja/color-dialog.js": "./lib/locale/ja/color-dialog.js", + "./locale/ja/color-picker.js": "./lib/locale/ja/color-picker.js", "./locale/ja/combo-box.js": "./lib/locale/ja/combo-box.js", "./locale/ja/datetime-field.js": "./lib/locale/ja/datetime-field.js", "./locale/ja/dialog.js": "./lib/locale/ja/dialog.js", @@ -77,6 +80,7 @@ "./locale/zh/calendar.js": "./lib/locale/zh/calendar.js", "./locale/zh/clock.js": "./lib/locale/zh/clock.js", "./locale/zh/color-dialog.js": "./lib/locale/zh/color-dialog.js", + "./locale/zh/color-picker.js": "./lib/locale/zh/color-picker.js", "./locale/zh/combo-box.js": "./lib/locale/zh/combo-box.js", "./locale/zh/datetime-field.js": "./lib/locale/zh/datetime-field.js", "./locale/zh/dialog.js": "./lib/locale/zh/dialog.js", @@ -94,6 +98,7 @@ "./locale/zh-hant/calendar.js": "./lib/locale/zh-hant/calendar.js", "./locale/zh-hant/clock.js": "./lib/locale/zh-hant/clock.js", "./locale/zh-hant/color-dialog.js": "./lib/locale/zh-hant/color-dialog.js", + "./locale/zh-hant/color-picker.js": "./lib/locale/zh-hant/color-picker.js", "./locale/zh-hant/combo-box.js": "./lib/locale/zh-hant/combo-box.js", "./locale/zh-hant/datetime-field.js": "./lib/locale/zh-hant/datetime-field.js", "./locale/zh-hant/dialog.js": "./lib/locale/zh-hant/dialog.js", diff --git a/packages/phrasebook/src/locale/de/color-picker.ts b/packages/phrasebook/src/locale/de/color-picker.ts new file mode 100644 index 0000000000..f198f8713f --- /dev/null +++ b/packages/phrasebook/src/locale/de/color-picker.ts @@ -0,0 +1,11 @@ +// Component docs https://elf.int.refinitiv.com/elements/color-picker.html +import { Phrasebook } from '../../translation.js'; +import './shared.js'; +import './color-dialog.js'; + +const translations = { +}; + +Phrasebook.define('de', 'ef-color-picker', translations); + +export default translations; diff --git a/packages/phrasebook/src/locale/en/color-picker.ts b/packages/phrasebook/src/locale/en/color-picker.ts new file mode 100644 index 0000000000..d11ccc5ff9 --- /dev/null +++ b/packages/phrasebook/src/locale/en/color-picker.ts @@ -0,0 +1,11 @@ +// Component docs https://elf.int.refinitiv.com/elements/color-picker.html +import { Phrasebook } from '../../translation.js'; +import './shared.js'; +import './color-dialog.js'; + +const translations = { +}; + +Phrasebook.define('en', 'ef-color-picker', translations); + +export default translations; diff --git a/packages/phrasebook/src/locale/ja/color-picker.ts b/packages/phrasebook/src/locale/ja/color-picker.ts new file mode 100644 index 0000000000..50e901cd91 --- /dev/null +++ b/packages/phrasebook/src/locale/ja/color-picker.ts @@ -0,0 +1,11 @@ +// Component docs https://elf.int.refinitiv.com/elements/color-picker.html +import { Phrasebook } from '../../translation.js'; +import './shared.js'; +import './color-dialog.js'; + +const translations = { +}; + +Phrasebook.define('ja', 'ef-color-picker', translations); + +export default translations; diff --git a/packages/phrasebook/src/locale/zh-hant/color-picker.ts b/packages/phrasebook/src/locale/zh-hant/color-picker.ts new file mode 100644 index 0000000000..7f6ab4db4f --- /dev/null +++ b/packages/phrasebook/src/locale/zh-hant/color-picker.ts @@ -0,0 +1,11 @@ +// Component docs https://elf.int.refinitiv.com/elements/color-picker.html +import { Phrasebook } from '../../translation.js'; +import './shared.js'; +import './color-dialog.js'; + +const translations = { +}; + +Phrasebook.define('zh-hant', 'ef-color-picker', translations); + +export default translations; diff --git a/packages/phrasebook/src/locale/zh/color-picker.ts b/packages/phrasebook/src/locale/zh/color-picker.ts new file mode 100644 index 0000000000..3ec5bb3135 --- /dev/null +++ b/packages/phrasebook/src/locale/zh/color-picker.ts @@ -0,0 +1,11 @@ +// Component docs https://elf.int.refinitiv.com/elements/color-picker.html +import { Phrasebook } from '../../translation.js'; +import './shared.js'; +import './color-dialog.js'; + +const translations = { +}; + +Phrasebook.define('zh', 'ef-color-picker', translations); + +export default translations; diff --git a/packages/solar-theme/src/custom-elements/ef-color-picker.less b/packages/solar-theme/src/custom-elements/ef-color-picker.less new file mode 100644 index 0000000000..93e89bb015 --- /dev/null +++ b/packages/solar-theme/src/custom-elements/ef-color-picker.less @@ -0,0 +1,7 @@ +@import '@refinitiv-ui/elemental-theme/src/custom-elements/ef-color-picker'; + +:host { + &[focused=visible] { + border-style: dotted; + } +} \ No newline at end of file diff --git a/packages/utils/src/color.ts b/packages/utils/src/color.ts index 515db86d33..98403a6944 100644 --- a/packages/utils/src/color.ts +++ b/packages/utils/src/color.ts @@ -1 +1,2 @@ export * from './color/d3-color.js'; +export { isHex, removeHashSign } from './color/color.js'; diff --git a/packages/utils/src/color/color.ts b/packages/utils/src/color/color.ts new file mode 100644 index 0000000000..bc18eeda1a --- /dev/null +++ b/packages/utils/src/color/color.ts @@ -0,0 +1,16 @@ +const HEX_REGEXP = /^#([0-9A-F]{3}){1,2}$/i; // used to validate HEX +export const isHex = (value: string): boolean => HEX_REGEXP.test(value); + +/** + * Remove hash (#) sign from hex value + * @param hex Hex to check + * @returns hex value without # sign + */ +export const removeHashSign = (hex: string): string => { + if (hex) { + if (hex.startsWith('#')) { + hex = hex.slice(1); + } + } + return hex; +};