Skip to content

Commit 8ad2b28

Browse files
authored
feat: add cssStyler option to use typed CSSStyleDeclaration props (#148)
1 parent c3154f0 commit 8ad2b28

5 files changed

Lines changed: 76 additions & 4 deletions

File tree

demo/src/options/options26.html

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="row mb-2">
22
<div class="col-md-12 title-desc">
33
<h2 class="bd-title">
4-
The Styler
4+
The Styler / CSS Styler
55
<span class="float-end links">
66
Code <span class="fa fa-link"></span>
77
<span class="small">
@@ -66,4 +66,25 @@ <h2 class="bd-title">
6666
</select>
6767
</div>
6868
</div>
69+
70+
<div class="mb-3 row">
71+
<label class="col-sm-2"> CSS Styler </label>
72+
73+
<div class="col-sm-10">
74+
<select id="select3" multiple="multiple" class="full-width" data-test="select3">
75+
<option value="1">January</option>
76+
<option value="2">February</option>
77+
<option value="3">March</option>
78+
<option value="4">April</option>
79+
<option value="5">May</option>
80+
<option value="6">June</option>
81+
<option value="7">July</option>
82+
<option value="8">August</option>
83+
<option value="9">September</option>
84+
<option value="10">October</option>
85+
<option value="11">November</option>
86+
<option value="12">December</option>
87+
</select>
88+
</div>
89+
</div>
6990
</div>

demo/src/options/options26.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { multipleSelect, OptionRowData, OptGroupRowData, MultipleSelectInstance
33
export default class Example {
44
ms1?: MultipleSelectInstance;
55
ms2?: MultipleSelectInstance;
6+
ms3?: MultipleSelectInstance;
67

78
mount() {
89
this.ms1 = multipleSelect('#basic', {
@@ -28,13 +29,27 @@ export default class Example {
2829
return null;
2930
},
3031
}) as MultipleSelectInstance;
32+
33+
this.ms3 = multipleSelect('#select3', {
34+
cssStyler: (row: OptionRowData | OptGroupRowData) => {
35+
if (+(row?.value ?? 0) === 2) {
36+
return { backgroundColor: '#6fbeff', color: '#0014ff', fontStyle: 'italic' } as CSSStyleDeclaration;
37+
}
38+
if (+(row?.value ?? 0) === 4) {
39+
return { backgroundColor: '#972727', color: '#fff' } as CSSStyleDeclaration;
40+
}
41+
return null;
42+
},
43+
}) as MultipleSelectInstance;
3144
}
3245

3346
unmount() {
3447
// destroy ms instance(s) to avoid DOM leaks
3548
this.ms1?.destroy();
3649
this.ms2?.destroy();
50+
this.ms3?.destroy();
3751
this.ms1 = undefined;
3852
this.ms2 = undefined;
53+
this.ms3 = undefined;
3954
}
4055
}

lib/src/MultipleSelectInstance.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
toggleElement,
1616
} from './utils/domUtils';
1717
import type { HtmlElementPosition } from './utils/domUtils';
18-
import type { MultipleSelectOption } from './interfaces/multipleSelectOption.interface';
18+
import type { CSSStyleDeclarationWritable, MultipleSelectOption } from './interfaces/multipleSelectOption.interface';
1919
import type { MultipleSelectLocales, OptGroupRowData, OptionDataObject, OptionRowData } from './interfaces';
2020
import { BindingEventService, VirtualScroll } from './services';
2121

@@ -576,6 +576,12 @@ export class MultipleSelectInstance {
576576
}
577577
applyParsedStyleToElement(liElm, style);
578578

579+
const customStyleCss = this.options.cssStyler?.(row);
580+
if (customStyleCss) {
581+
for (const styleProp of Object.keys(customStyleCss)) {
582+
liElm.style[styleProp as CSSStyleDeclarationWritable] = customStyleCss[styleProp as CSSStyleDeclarationWritable];
583+
}
584+
}
579585
const labelClasses = `${row.disabled ? 'disabled' : ''}`;
580586
const labelElm = document.createElement('label');
581587
if (labelClasses) {

lib/src/interfaces/multipleSelectOption.interface.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ export interface MultipleSelectView {
77
instance: any;
88
}
99

10+
export type CSSStyleDeclarationReadonly =
11+
| 'length'
12+
| 'parentRule'
13+
| 'getPropertyPriority'
14+
| 'getPropertyValue'
15+
| 'item'
16+
| 'removeProperty'
17+
| 'setProperty';
18+
export type CSSStyleDeclarationWritable = keyof Omit<CSSStyleDeclaration, CSSStyleDeclarationReadonly>;
19+
1020
export interface MultipleSelectOption extends MultipleSelectLocale {
1121
/** @deprecated @alias `displayTitle` Add a title. By default this option is set to false. */
1222
addTitle?: boolean;
@@ -176,7 +186,10 @@ export interface MultipleSelectOption extends MultipleSelectLocale {
176186
/** Customize the filter method, for example we use startWith */
177187
customFilter(options: LabelFilter | TextFilter): boolean;
178188

179-
/** The item styler function, return style string to custom the item style such as background: red. The function take one parameter: value. */
189+
/** The item styler function, return style string to customize the item style such as background: red. The function take one parameter: value. */
190+
cssStyler?: (value: OptionRowData | OptGroupRowData) => CSSStyleDeclaration | null;
191+
192+
/** @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. */
180193
styler: (value: OptionRowData | OptGroupRowData) => string | boolean | null;
181194

182195
/** Returns HTML label attribute of a DOM element */

playwright/e2e/options26.spec.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect } from '@playwright/test';
22

3-
test.describe('Options 26 - The Styler', () => {
3+
test.describe('Options 26 - The Styler / CSS Styler', () => {
44
test.beforeEach(async ({ page }) => {
55
await page.goto('#/options26');
66
});
@@ -32,4 +32,21 @@ test.describe('Options 26 - The Styler', () => {
3232
const dropLoc2 = await page.locator('[data-test=select2] .ms-choice span', { hasText: '[Group 1: Option 1]' });
3333
await dropLoc2.waitFor();
3434
});
35+
36+
test('third select has February & April with custom CSS styler', async ({ page }) => {
37+
await page.locator('[data-test=select3].ms-parent').click();
38+
const optionLoc2 = await page.locator('[data-test=select3] .ms-drop ul li').nth(1);
39+
optionLoc2.click();
40+
expect(optionLoc2).toHaveText('February');
41+
await expect(optionLoc2).toHaveCSS('color', 'rgb(0, 20, 255)');
42+
await expect(optionLoc2).toHaveCSS('background-color', 'rgb(111, 190, 255)');
43+
44+
const optionLoc4 = await page.locator('[data-test=select3] .ms-drop ul li').nth(3);
45+
optionLoc4.click();
46+
expect(optionLoc4).toHaveText('April');
47+
await expect(optionLoc4).toHaveCSS('color', 'rgb(255, 255, 255)');
48+
await expect(optionLoc4).toHaveCSS('background-color', 'rgb(151, 39, 39)');
49+
const selectedText3 = page.locator('[data-test=select3] .ms-choice span', { hasText: 'February, April' });
50+
await selectedText3.waitFor();
51+
});
3552
});

0 commit comments

Comments
 (0)