diff --git a/stencil-workspace/src/components.d.ts b/stencil-workspace/src/components.d.ts index 94966d374..1946b5d2d 100644 --- a/stencil-workspace/src/components.d.ts +++ b/stencil-workspace/src/components.d.ts @@ -1743,6 +1743,10 @@ export namespace Components { * (optional) Disable usage of `tab` key to focus elements inside a tree view. Use `Arrow Up/Down` for focussing a tree item and `Shift + Arrow Right` for focussing a checkbox inside the item. */ "disableTabbing": boolean; + /** + * (optional) Sets draggable state to be true to all the children + */ + "enableReordering": boolean; /** * (optional) Set expanded tree items */ @@ -2044,6 +2048,7 @@ declare global { interface HTMLModusAutocompleteElementEventMap { "optionSelected": string; "valueChange": string | string[]; + "valueError": string; "selectionsChanged": string[]; } interface HTMLModusAutocompleteElement extends Components.ModusAutocomplete, HTMLStencilElement { @@ -2414,6 +2419,7 @@ declare global { }; interface HTMLModusNumberInputElementEventMap { "valueChange": string; + "valueError": string; } interface HTMLModusNumberInputElement extends Components.ModusNumberInput, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLModusNumberInputElement, ev: ModusNumberInputCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -2471,6 +2477,7 @@ declare global { }; interface HTMLModusSelectElementEventMap { "valueChange": unknown; + "valueError": string; "inputBlur": FocusEvent; } interface HTMLModusSelectElement extends Components.ModusSelect, HTMLStencilElement { @@ -2695,6 +2702,7 @@ declare global { }; interface HTMLModusTextInputElementEventMap { "valueChange": string; + "valueError": string; } interface HTMLModusTextInputElement extends Components.ModusTextInput, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLModusTextInputElement, ev: ModusTextInputCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -3052,6 +3060,10 @@ declare namespace LocalJSX { * An event that fires when the input value changes. Emits the value string. */ "onValueChange"?: (event: ModusAutocompleteCustomEvent) => void; + /** + * An event that fires on input value error. + */ + "onValueError"?: (event: ModusAutocompleteCustomEvent) => void; /** * The autocomplete's options. */ @@ -3919,6 +3931,10 @@ declare namespace LocalJSX { * An event that fires on input value change. */ "onValueChange"?: (event: ModusNumberInputCustomEvent) => void; + /** + * An event that fires on input value error. + */ + "onValueError"?: (event: ModusNumberInputCustomEvent) => void; /** * (optional) The input's placeholder text. */ @@ -4058,6 +4074,10 @@ declare namespace LocalJSX { * An event that fires on input value change. */ "onValueChange"?: (event: ModusSelectCustomEvent) => void; + /** + * An event that fires on input value error. + */ + "onValueError"?: (event: ModusSelectCustomEvent) => void; /** * The options for the dropdown list. */ @@ -4519,6 +4539,10 @@ declare namespace LocalJSX { * An event that fires on input value change. */ "onValueChange"?: (event: ModusTextInputCustomEvent) => void; + /** + * An event that fires on input value error. + */ + "onValueError"?: (event: ModusTextInputCustomEvent) => void; /** * (optional) The input's pattern HTML attribute. */ @@ -4803,6 +4827,10 @@ declare namespace LocalJSX { * (optional) Disable usage of `tab` key to focus elements inside a tree view. Use `Arrow Up/Down` for focussing a tree item and `Shift + Arrow Right` for focussing a checkbox inside the item. */ "disableTabbing"?: boolean; + /** + * (optional) Sets draggable state to be true to all the children + */ + "enableReordering"?: boolean; /** * (optional) Set expanded tree items */ diff --git a/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.e2e.ts b/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.e2e.ts index 71bc125e3..5d939b409 100644 --- a/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.e2e.ts +++ b/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.e2e.ts @@ -958,4 +958,20 @@ describe('modus-autocomplete', () => { expect(element).toBeDefined(); expect(element).not.toHaveAttribute('aria-label'); }); + + it('emits valueError event if error message is present', async () => { + const page = await newE2EPage(); + + await page.setContent(''); + const valueError = await page.spyOnEvent('valueError'); + const autocomplete = await page.find('modus-autocomplete >>> div.autocomplete'); + + autocomplete.setProperty('errorText', 'Error message'); + await page.waitForChanges(); + + const textInput = await page.find('modus-autocomplete >>> modus-text-input'); + await textInput.click(); + await textInput.type('apple', { delay: 20 }); + expect(valueError).toHaveReceivedEvent(); + }); }); diff --git a/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.tsx b/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.tsx index 33e80128d..a32df25fa 100644 --- a/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.tsx +++ b/stencil-workspace/src/components/modus-autocomplete/modus-autocomplete.tsx @@ -111,6 +111,9 @@ export class ModusAutocomplete { this.updateVisibleOptions(this.getValueAsString()); this.updateVisibleCustomOptions(this.getValueAsString()); } + if (this.errorText) { + this.valueError.emit(this.errorText); + } } /** An event that fires when a dropdown option is selected. Emits the option id. */ @@ -119,6 +122,9 @@ export class ModusAutocomplete { /** An event that fires when the input value changes. Emits the value string. */ @Event() valueChange: EventEmitter; + /** An event that fires on input value error. */ + @Event() valueError: EventEmitter; + /** An event that fires when an option is selected/removed. Emits the option ids. */ @Event() selectionsChanged: EventEmitter; @@ -317,6 +323,9 @@ export class ModusAutocomplete { this.updateVisibleCustomOptions(search); this.value = search; this.valueChange.emit(search); + if (this.errorText) { + this.valueError.emit(this.errorText); + } }; handleCloseClick(chipValue: ModusAutocompleteOption) { @@ -339,6 +348,9 @@ export class ModusAutocomplete { event.stopPropagation(); this.disableFiltering = !this.disableCloseOnSelect; this.handleSearchChange(event.detail); + if (this.errorText) { + this.valueError.emit(this.errorText); + } }; updateVisibleCustomOptions = (search = '') => { diff --git a/stencil-workspace/src/components/modus-number-input/modus-number-input.e2e.ts b/stencil-workspace/src/components/modus-number-input/modus-number-input.e2e.ts index 9035316a3..8355bb7a4 100644 --- a/stencil-workspace/src/components/modus-number-input/modus-number-input.e2e.ts +++ b/stencil-workspace/src/components/modus-number-input/modus-number-input.e2e.ts @@ -237,4 +237,17 @@ describe('modus-number-input', () => { expect(await element.getProperty('value')).toEqual('2'); }); + + it('emits valueError event if error message is present', async () => { + const page = await newE2EPage(); + + await page.setContent(''); + const valueError = await page.spyOnEvent('valueError'); + const numberInput = await page.find('modus-number-input >>> input'); + + numberInput.setProperty('errorText', 'Error message'); + await page.waitForChanges(); + await numberInput.type('1', { delay: 20 }); + expect(valueError).toHaveReceivedEvent(); + }); }); diff --git a/stencil-workspace/src/components/modus-number-input/modus-number-input.spec.tsx b/stencil-workspace/src/components/modus-number-input/modus-number-input.spec.tsx index 206bfd7db..43d63337c 100644 --- a/stencil-workspace/src/components/modus-number-input/modus-number-input.spec.tsx +++ b/stencil-workspace/src/components/modus-number-input/modus-number-input.spec.tsx @@ -11,7 +11,7 @@ describe('modus-number-input', () => {
-
+
diff --git a/stencil-workspace/src/components/modus-number-input/modus-number-input.tsx b/stencil-workspace/src/components/modus-number-input/modus-number-input.tsx index 652260989..3146d62e6 100644 --- a/stencil-workspace/src/components/modus-number-input/modus-number-input.tsx +++ b/stencil-workspace/src/components/modus-number-input/modus-number-input.tsx @@ -56,6 +56,9 @@ export class ModusNumberInput { /** An event that fires on input value change. */ @Event() valueChange: EventEmitter; + /** An event that fires on input value error. */ + @Event() valueError: EventEmitter; + private inputId = generateElementId() + '_number-input'; classBySize: Map = new Map([ @@ -67,6 +70,12 @@ export class ModusNumberInput { handleOnInput(): void { this.value = this.numberInput.value; this.valueChange.emit(this.value); + + if (this.errorText) { + this.valueError.emit(this.errorText); + } else { + this.valueError.emit(null); + } } /** Focus the input. */ @@ -122,7 +131,9 @@ export class ModusNumberInput { {this.helperText ? : null}
) : null} -
+
{ expect(element).toBeDefined(); expect(element).not.toHaveAttribute('aria-label'); }); + + it('emits valueError event if error message is present', async () => { + const page = await newE2EPage(); + + await page.setContent(''); + const valueError = await page.spyOnEvent('valueError'); + const select = await page.find('modus-select'); + + const options = [ + { value: '1', label: 'Option 1' }, + { value: '2', label: 'Option 2' }, + ]; + select.setProperty('options', options); + select.setProperty('optionsDisplayProp', 'display'); + select.setProperty('errorText', 'Error message'); + await page.waitForChanges(); + + const selectElement = await page.find('modus-select >>> select'); + await selectElement.focus(); + await page.waitForChanges(); + + await page.keyboard.press('ArrowDown'); + await page.keyboard.press('Enter'); + await page.waitForChanges(); + + expect(valueError).toHaveReceivedEvent(); + }); }); diff --git a/stencil-workspace/src/components/modus-select/modus-select.spec.ts b/stencil-workspace/src/components/modus-select/modus-select.spec.ts index ea8bdf50c..cb9d2abb9 100644 --- a/stencil-workspace/src/components/modus-select/modus-select.spec.ts +++ b/stencil-workspace/src/components/modus-select/modus-select.spec.ts @@ -14,7 +14,7 @@ describe('modus-select', () => {
- diff --git a/stencil-workspace/src/components/modus-select/modus-select.tsx b/stencil-workspace/src/components/modus-select/modus-select.tsx index 1be634c64..a090d213a 100644 --- a/stencil-workspace/src/components/modus-select/modus-select.tsx +++ b/stencil-workspace/src/components/modus-select/modus-select.tsx @@ -46,11 +46,17 @@ export class ModusSelect { @Watch('value') handleValueChange(newValue: unknown): void { this.internalValue = newValue; + if (this.errorText) { + this.valueError.emit(this.errorText); + } } /** An event that fires on input value change. */ @Event() valueChange: EventEmitter; + /** An event that fires on input value error. */ + @Event() valueError: EventEmitter; + /** An event that fires on input blur. */ @Event() inputBlur: EventEmitter; @@ -74,10 +80,16 @@ export class ModusSelect { connectedCallback(): void { this.internalValue = this.value; + if (this.errorText) { + this.valueError.emit(this.errorText); + } } handleOptionSelect(option: unknown): void { this.valueChange.emit(option); + if (this.errorText) { + this.valueError.emit(this.errorText); + } } handleSelectChange(event: Event): void { @@ -128,7 +140,7 @@ export class ModusSelect { {this.renderLabel()}
@@ -29,7 +29,7 @@ describe('modus-text-input', () => {
-
+
@@ -47,7 +47,7 @@ describe('modus-text-input', () => {
-
+
@@ -64,8 +64,8 @@ describe('modus-text-input', () => { expect(page.root).toEqualHtml(` -
-
+
+
@@ -83,7 +83,7 @@ describe('modus-text-input', () => {
-
+
@@ -101,7 +101,7 @@ describe('modus-text-input', () => {
-
+
diff --git a/stencil-workspace/src/components/modus-text-input/modus-text-input.tsx b/stencil-workspace/src/components/modus-text-input/modus-text-input.tsx index c06631569..a070e6ba8 100644 --- a/stencil-workspace/src/components/modus-text-input/modus-text-input.tsx +++ b/stencil-workspace/src/components/modus-text-input/modus-text-input.tsx @@ -99,6 +99,9 @@ export class ModusTextInput { /** An event that fires on input value change. */ @Event() valueChange: EventEmitter; + /** An event that fires on input value error. */ + @Event() valueError: EventEmitter; + private inputId = generateElementId() + '_text_input'; classBySize: Map = new Map([ @@ -134,6 +137,12 @@ export class ModusTextInput { this.value = value; this.valueChange.emit(value); + + if (this.errorText) { + this.valueError.emit(this.errorText); + } else { + this.valueError.emit(null); + } } handleTogglePasswordKeyDown(event: KeyboardEvent): void { @@ -211,7 +220,7 @@ export class ModusTextInput { this.size )}`} onClick={() => this.textInput.focus()} - part="input-container"> + part={`input-container ${this.errorText ? 'error' : this.validText ? 'valid' : ''}`}> {this.includeSearchIcon ? : null}