diff --git a/demo/src/options/options26.html b/demo/src/options/options26.html index 03b67babd..fa0bb9ac4 100644 --- a/demo/src/options/options26.html +++ b/demo/src/options/options26.html @@ -1,7 +1,7 @@

- The Styler + The Styler / CSS Styler Code @@ -66,4 +66,25 @@

+ +
+ + +
+ +
+
diff --git a/demo/src/options/options26.ts b/demo/src/options/options26.ts index 9b5817f09..089529df3 100644 --- a/demo/src/options/options26.ts +++ b/demo/src/options/options26.ts @@ -3,6 +3,7 @@ import { multipleSelect, OptionRowData, OptGroupRowData, MultipleSelectInstance export default class Example { ms1?: MultipleSelectInstance; ms2?: MultipleSelectInstance; + ms3?: MultipleSelectInstance; mount() { this.ms1 = multipleSelect('#basic', { @@ -28,13 +29,27 @@ export default class Example { return null; }, }) as MultipleSelectInstance; + + this.ms3 = multipleSelect('#select3', { + cssStyler: (row: OptionRowData | OptGroupRowData) => { + if (+(row?.value ?? 0) === 2) { + return { backgroundColor: '#6fbeff', color: '#0014ff', fontStyle: 'italic' } as CSSStyleDeclaration; + } + if (+(row?.value ?? 0) === 4) { + return { backgroundColor: '#972727', color: '#fff' } as CSSStyleDeclaration; + } + return null; + }, + }) as MultipleSelectInstance; } unmount() { // destroy ms instance(s) to avoid DOM leaks this.ms1?.destroy(); this.ms2?.destroy(); + this.ms3?.destroy(); this.ms1 = undefined; this.ms2 = undefined; + this.ms3 = undefined; } } diff --git a/lib/src/MultipleSelectInstance.ts b/lib/src/MultipleSelectInstance.ts index c8b2868d9..de6cddc41 100644 --- a/lib/src/MultipleSelectInstance.ts +++ b/lib/src/MultipleSelectInstance.ts @@ -15,7 +15,7 @@ import { toggleElement, } from './utils/domUtils'; import type { HtmlElementPosition } from './utils/domUtils'; -import type { MultipleSelectOption } from './interfaces/multipleSelectOption.interface'; +import type { CSSStyleDeclarationWritable, MultipleSelectOption } from './interfaces/multipleSelectOption.interface'; import type { MultipleSelectLocales, OptGroupRowData, OptionDataObject, OptionRowData } from './interfaces'; import { BindingEventService, VirtualScroll } from './services'; @@ -576,6 +576,12 @@ export class MultipleSelectInstance { } applyParsedStyleToElement(liElm, style); + const customStyleCss = this.options.cssStyler?.(row); + if (customStyleCss) { + for (const styleProp of Object.keys(customStyleCss)) { + liElm.style[styleProp as CSSStyleDeclarationWritable] = customStyleCss[styleProp as CSSStyleDeclarationWritable]; + } + } const labelClasses = `${row.disabled ? 'disabled' : ''}`; const labelElm = document.createElement('label'); if (labelClasses) { diff --git a/lib/src/interfaces/multipleSelectOption.interface.ts b/lib/src/interfaces/multipleSelectOption.interface.ts index 13437a7d9..eecf684ca 100644 --- a/lib/src/interfaces/multipleSelectOption.interface.ts +++ b/lib/src/interfaces/multipleSelectOption.interface.ts @@ -7,6 +7,16 @@ export interface MultipleSelectView { instance: any; } +export type CSSStyleDeclarationReadonly = + | 'length' + | 'parentRule' + | 'getPropertyPriority' + | 'getPropertyValue' + | 'item' + | 'removeProperty' + | 'setProperty'; +export type CSSStyleDeclarationWritable = keyof Omit; + export interface MultipleSelectOption extends MultipleSelectLocale { /** @deprecated @alias `displayTitle` Add a title. By default this option is set to false. */ addTitle?: boolean; @@ -176,7 +186,10 @@ export interface MultipleSelectOption extends MultipleSelectLocale { /** Customize the filter method, for example we use startWith */ customFilter(options: LabelFilter | TextFilter): boolean; - /** The item styler function, return style string to custom the item style such as background: red. The function take one parameter: value. */ + /** The item styler function, return style string to customize the item style such as background: red. The function take one parameter: value. */ + cssStyler?: (value: OptionRowData | OptGroupRowData) => CSSStyleDeclaration | null; + + /** @deprecated @use `cssStyler`. The item styler function, return style string to customize the item style such as background: red. The function take one parameter: value. */ styler: (value: OptionRowData | OptGroupRowData) => string | boolean | null; /** Returns HTML label attribute of a DOM element */ diff --git a/playwright/e2e/options26.spec.ts b/playwright/e2e/options26.spec.ts index 004496976..8613a44c3 100644 --- a/playwright/e2e/options26.spec.ts +++ b/playwright/e2e/options26.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from '@playwright/test'; -test.describe('Options 26 - The Styler', () => { +test.describe('Options 26 - The Styler / CSS Styler', () => { test.beforeEach(async ({ page }) => { await page.goto('#/options26'); }); @@ -32,4 +32,21 @@ test.describe('Options 26 - The Styler', () => { const dropLoc2 = await page.locator('[data-test=select2] .ms-choice span', { hasText: '[Group 1: Option 1]' }); await dropLoc2.waitFor(); }); + + test('third select has February & April with custom CSS styler', async ({ page }) => { + await page.locator('[data-test=select3].ms-parent').click(); + const optionLoc2 = await page.locator('[data-test=select3] .ms-drop ul li').nth(1); + optionLoc2.click(); + expect(optionLoc2).toHaveText('February'); + await expect(optionLoc2).toHaveCSS('color', 'rgb(0, 20, 255)'); + await expect(optionLoc2).toHaveCSS('background-color', 'rgb(111, 190, 255)'); + + const optionLoc4 = await page.locator('[data-test=select3] .ms-drop ul li').nth(3); + optionLoc4.click(); + expect(optionLoc4).toHaveText('April'); + await expect(optionLoc4).toHaveCSS('color', 'rgb(255, 255, 255)'); + await expect(optionLoc4).toHaveCSS('background-color', 'rgb(151, 39, 39)'); + const selectedText3 = page.locator('[data-test=select3] .ms-choice span', { hasText: 'February, April' }); + await selectedText3.waitFor(); + }); });