From c9eedefba0d75b9f8fb5eaf2f96eafc73b6ec945 Mon Sep 17 00:00:00 2001 From: Martin Prinz Date: Thu, 6 Jul 2023 08:41:07 +0200 Subject: [PATCH 1/2] fix(#182): improve event handling for adding/removing options --- mwui-stencil/src/components.d.ts | 4 +- .../mw-autocomplete.stories.tsx | 8 +-- .../mw-autocomplete/mw-autocomplete.tsx | 26 ++++----- .../mw-chip-input/mw-chip-input.tsx | 26 +++++---- mwui-stencil/src/index.html | 58 +++++++++---------- 5 files changed, 63 insertions(+), 59 deletions(-) diff --git a/mwui-stencil/src/components.d.ts b/mwui-stencil/src/components.d.ts index a67a59c8..678b2fd3 100644 --- a/mwui-stencil/src/components.d.ts +++ b/mwui-stencil/src/components.d.ts @@ -1491,11 +1491,11 @@ declare namespace LocalJSX { /** * Emits an event when value of input changes */ - onMwChipListInputChange?: (event: MwChipInputCustomEvent) => void; + onInputChange?: (event: MwChipInputCustomEvent) => void; /** * Emits an event when its value changes */ - onMwChipListValueChanged?: (event: MwChipInputCustomEvent) => void; + onValueChanged?: (event: MwChipInputCustomEvent) => void; /** * Amount of currently selected options */ diff --git a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.stories.tsx b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.stories.tsx index d77f893d..714963fc 100644 --- a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.stories.tsx +++ b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.stories.tsx @@ -58,10 +58,10 @@ const IconTemplate = args => ` >
- - - - + + + +
`; diff --git a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx index 73b3ed60..ef5d6327 100644 --- a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx +++ b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx @@ -80,7 +80,7 @@ export class MwAutocomplete { /** * Currently selected options */ - @Prop({ reflect: true, mutable: false }) selected: string[] = []; + @Prop({ reflect: true, mutable: true }) selected: string[] = []; @Watch("selected") onSelectedChange(selected: string[]): void { if (!this.canAddToValues()) { @@ -116,8 +116,8 @@ export class MwAutocomplete { this.hasIconStartSlot = !!this.hostElement.querySelector("[slot='icon-start']"); } - private onInputChange = (event: MwChipInputCustomEvent | MwTextfieldCustomEvent): void => { - this.filterDropdownOptions(event.detail); + private onInputChange = (event: MwChipInputCustomEvent | MwTextfieldCustomEvent | InputEvent): void => { + this.filterDropdownOptions((event.target as HTMLMwChipInputElement).value); this.isDropdownOpen = true; }; @@ -138,22 +138,22 @@ export class MwAutocomplete { this.removeDropdownFilter(); }; - private setItemDisabledState(selected: string[]): void { + private setItemDisabledState = (selected: string[]): void => { this.hostElement.querySelectorAll("mw-menu-item").forEach(item => { const isDisabled = selected.includes(item.getAttribute("value")); item.setAttribute("disabled", `${isDisabled}`); }); - } + }; - private handleChipListValueChange(event: MwChipInputCustomEvent): void { + private handleChipListValueChange = (event: MwChipInputCustomEvent): void => { this.selected = event.detail; - } + }; - private filterDropdownOptions = (value: string): void => { + private filterDropdownOptions = (value: string | number): void => { let hasNoSuggestions = true; this.hostElement.querySelectorAll("mw-menu-item").forEach(item => { - if (item.value.toLowerCase().includes(value.toLowerCase())) { + if (item.value.toLowerCase().includes(value.toString().toLowerCase())) { item.style.display = "unset"; hasNoSuggestions = false; } else { @@ -173,9 +173,9 @@ export class MwAutocomplete { }); }; - private canAddToValues(): boolean { + private canAddToValues = (): boolean => { return !this.maximum || this.selected?.length < this.maximum; - } + }; render() { return ( @@ -201,8 +201,8 @@ export class MwAutocomplete { selectedChips={this.selected} onFocus={this.onFocus} onBlur={this.onBlur} - onMwChipListValueChanged={this.handleChipListValueChange.bind(this)} - onMwChipListInputChange={this.onInputChange.bind(this)} + onValueChanged={this.handleChipListValueChange} + onInput={this.onInputChange} slot="anchor" > {this.hasIconStartSlot && ( diff --git a/mwui-stencil/src/components/mw-chip-input/mw-chip-input.tsx b/mwui-stencil/src/components/mw-chip-input/mw-chip-input.tsx index 838673aa..3dce050b 100644 --- a/mwui-stencil/src/components/mw-chip-input/mw-chip-input.tsx +++ b/mwui-stencil/src/components/mw-chip-input/mw-chip-input.tsx @@ -14,12 +14,12 @@ export class MwChipInput { /** * Emits an event when its value changes */ - @Event({ bubbles: true, composed: false, eventName: "mwChipListValueChanged" }) valueChanged: EventEmitter; + @Event({ bubbles: true, composed: true, eventName: "valueChanged" }) valueChanged: EventEmitter; /** * Emits an event when value of input changes */ - @Event({ bubbles: true, composed: false, eventName: "mwChipListInputChange" }) inputChange: EventEmitter; + @Event({ bubbles: true, composed: true }) inputChange: EventEmitter; /** * input field name */ @@ -143,6 +143,11 @@ export class MwChipInput { this.focused = false; }; + private onRemoveSelection = (value: string): void => { + this._selection.deselect(value); + this.onValueChange(); + }; + private addMultiValue = (value: string): void => { if (value.trim()?.length === 0) { return; @@ -162,18 +167,18 @@ export class MwChipInput { this.onValueChange(); }; - private onValueChange(): void { + private onValueChange = (): void => { this.selected = this._selection.selected; this.valueChanged.emit(this.selected); - } + }; - private handleInputChange(): void { + private handleInputChange = (): void => { this.inputChange.emit(this.inputElement.value); - } + }; - private canAddToValues(): boolean { + private canAddToValues = (): boolean => { return !this.maximum || this.selected?.length < this.maximum; - } + }; render() { const { @@ -187,7 +192,6 @@ export class MwChipInput { name, clearMultiValues, selected, - handleInputChange, required, hasError, inline, @@ -229,7 +233,7 @@ export class MwChipInput {
{selected?.map(v => ( - + this.onRemoveSelection(v)} showClose={true} value={v} selected={true} toggleable={false} disabled={disabled}> {v} ))} @@ -246,7 +250,7 @@ export class MwChipInput { name={name} value={this.value} disabled={disabled} - onInput={handleInputChange.bind(this)} + onInput={this.handleInputChange} /> )}
diff --git a/mwui-stencil/src/index.html b/mwui-stencil/src/index.html index b9619ff1..8141bec1 100644 --- a/mwui-stencil/src/index.html +++ b/mwui-stencil/src/index.html @@ -463,12 +463,12 @@

Dropdown

- - + + - - - + + +
@@ -480,43 +480,43 @@

Autocomplete

- - - - - - - - + + + + + + + +
- - - - - - - - + + + + + + + +
- - - - + + + +
- - - - + + + +
From 3d5a992aa00ea2ad79ef41f70abde93211bcc2ba Mon Sep 17 00:00:00 2001 From: Martin Prinz Date: Thu, 6 Jul 2023 07:11:58 +0000 Subject: [PATCH 2/2] fix(#182): fire event on change in mw-autocomplete --- mwui-stencil/docs.json | 32 ++++++++++++++----- mwui-stencil/src/components.d.ts | 6 ++-- .../mw-autocomplete/mw-autocomplete.docs.mdx | 10 ++++++ .../mw-autocomplete/mw-autocomplete.spec.tsx | 10 +++--- .../mw-autocomplete/mw-autocomplete.tsx | 27 ++++++++-------- .../src/components/mw-autocomplete/readme.md | 8 ++--- .../src/components/mw-card-image/readme.md | 9 ++---- .../src/components/mw-chip-input/readme.md | 8 ++--- mwui-stencil/src/index.html | 5 +++ 9 files changed, 72 insertions(+), 43 deletions(-) diff --git a/mwui-stencil/docs.json b/mwui-stencil/docs.json index 89c537c0..8617c433 100644 --- a/mwui-stencil/docs.json +++ b/mwui-stencil/docs.json @@ -1,5 +1,5 @@ { - "timestamp": "2023-06-23T11:41:02", + "timestamp": "2023-07-06T07:09:39", "compiler": { "name": "@stencil/core", "version": "3.3.1", @@ -338,9 +338,9 @@ "required": false }, { - "name": "selected", + "name": "selection", "type": "string[]", - "mutable": false, + "mutable": true, "reflectToAttr": false, "docs": "Currently selected options", "docsTags": [], @@ -393,7 +393,7 @@ "methods": [], "events": [ { - "event": "mwAutocompleteValueChanged", + "event": "selectionChanged", "detail": "string", "bubbles": true, "cancelable": true, @@ -1175,6 +1175,22 @@ "optional": false, "required": false }, + { + "name": "height", + "type": "string", + "mutable": false, + "attr": "height", + "reflectToAttr": false, + "docs": "Height of image", + "docsTags": [], + "values": [ + { + "type": "string" + } + ], + "optional": true, + "required": false + }, { "name": "src", "type": "string", @@ -1773,20 +1789,20 @@ "methods": [], "events": [ { - "event": "mwChipListInputChange", + "event": "inputChange", "detail": "string", "bubbles": true, "cancelable": true, - "composed": false, + "composed": true, "docs": "Emits an event when value of input changes", "docsTags": [] }, { - "event": "mwChipListValueChanged", + "event": "valueChanged", "detail": "string[]", "bubbles": true, "cancelable": true, - "composed": false, + "composed": true, "docs": "Emits an event when its value changes", "docsTags": [] } diff --git a/mwui-stencil/src/components.d.ts b/mwui-stencil/src/components.d.ts index 678b2fd3..df3be5b0 100644 --- a/mwui-stencil/src/components.d.ts +++ b/mwui-stencil/src/components.d.ts @@ -101,7 +101,7 @@ export namespace Components { /** * Currently selected options */ - selected: string[]; + selection: string[]; /** * HTML Input type */ @@ -1192,7 +1192,7 @@ declare namespace LocalJSX { /** * Emits an event when its value changes */ - onMwAutocompleteValueChanged?: (event: MwAutocompleteCustomEvent) => void; + onSelectionChanged?: (event: MwAutocompleteCustomEvent) => void; /** * Shows how many options the user has selected as well as the allowed maximum. Only works, if `maximum` prop is defined. */ @@ -1212,7 +1212,7 @@ declare namespace LocalJSX { /** * Currently selected options */ - selected?: string[]; + selection?: string[]; /** * HTML Input type */ diff --git a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.docs.mdx b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.docs.mdx index 2a31fcf4..03ffb227 100644 --- a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.docs.mdx +++ b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.docs.mdx @@ -6,6 +6,16 @@ The autocomplete allows the user to pick from a predetermined list of options, o The dropdown options should be placed in the `dropdown-menu` slot. Additionally an icon can be added to the start of the input box using the `icon-start` slot. +## Listen to changes + +Whenever the selection is updated, a `selectionChanged` event is fired. The currently selected items can be retrieved from the element, like `event.target.selection`. + +```javascript +document.getElementById("my-autocomplete").addEventListener("selectionChanged", event => { + console.log(event.target.selection); // yields an array of strings +}); +``` + ## Examples diff --git a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.spec.tsx b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.spec.tsx index 20136acf..626705c1 100644 --- a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.spec.tsx +++ b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.spec.tsx @@ -1,4 +1,4 @@ -import { newSpecPage } from "@stencil/core/testing"; +import { SpecPage, newSpecPage } from "@stencil/core/testing"; import { h } from "@stencil/core"; import { MwAutocomplete } from "./mw-autocomplete"; @@ -7,7 +7,7 @@ describe("Given MwAutocomplete", () => { name: "some-name", label: "some-label", required: false, - selected: [], + selection: [], }; const setup = async ({ name, @@ -18,8 +18,8 @@ describe("Given MwAutocomplete", () => { inline, required, disabled, - selected, - }: Pick = defaultProps) => { + selection, + }: Pick = defaultProps): Promise => { return await newSpecPage({ components: [MwAutocomplete], template: () => ( @@ -31,7 +31,7 @@ describe("Given MwAutocomplete", () => { has-error={hasError} inline={inline} required={required} - selected={selected} + selection={selection} disabled={disabled} > ), diff --git a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx index ef5d6327..454abd46 100644 --- a/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx +++ b/mwui-stencil/src/components/mw-autocomplete/mw-autocomplete.tsx @@ -12,7 +12,7 @@ export class MwAutocomplete { /** * Emits an event when its value changes */ - @Event({ bubbles: true, composed: false, eventName: "mwAutocompleteValueChanged" }) valueChanged: EventEmitter; + @Event({ bubbles: true, composed: false, eventName: "selectionChanged" }) valueChanged: EventEmitter; /** * HTML Input type */ @@ -80,16 +80,17 @@ export class MwAutocomplete { /** * Currently selected options */ - @Prop({ reflect: true, mutable: true }) selected: string[] = []; - @Watch("selected") - onSelectedChange(selected: string[]): void { + @Prop({ reflect: true, mutable: true }) selection: string[] = []; + @Watch("selection") + onSelectedChange(selection: string[]): void { if (!this.canAddToValues()) { this.hostElement.querySelectorAll("mw-menu-item").forEach(item => { item.setAttribute("disabled", `true`); }); } else { - this.setItemDisabledState(selected); + this.setItemDisabledState(selection); } + this.valueChanged.emit(); } @State() focused = false; @@ -134,19 +135,19 @@ export class MwAutocomplete { return; } - this.selected = [...this.selected, value]; + this.selection = [...this.selection, value]; this.removeDropdownFilter(); }; - private setItemDisabledState = (selected: string[]): void => { + private setItemDisabledState = (selection: string[]): void => { this.hostElement.querySelectorAll("mw-menu-item").forEach(item => { - const isDisabled = selected.includes(item.getAttribute("value")); + const isDisabled = selection.includes(item.getAttribute("value")); item.setAttribute("disabled", `${isDisabled}`); }); }; private handleChipListValueChange = (event: MwChipInputCustomEvent): void => { - this.selected = event.detail; + this.selection = event.detail; }; private filterDropdownOptions = (value: string | number): void => { @@ -174,7 +175,7 @@ export class MwAutocomplete { }; private canAddToValues = (): boolean => { - return !this.maximum || this.selected?.length < this.maximum; + return !this.maximum || this.selection?.length < this.maximum; }; render() { @@ -198,7 +199,7 @@ export class MwAutocomplete { disabled={this.disabled} hasError={this.hasError} maximum={this.maximum} - selectedChips={this.selected} + selectedChips={this.selection} onFocus={this.onFocus} onBlur={this.onBlur} onValueChanged={this.handleChipListValueChange} @@ -226,7 +227,7 @@ export class MwAutocomplete { name={this.name} hasError={this.hasError} placeholder={this.placeholder} - onMwTextfieldValueChanged={this.onInputChange.bind(this)} + onMwTextfieldValueChanged={this.onInputChange} slot="anchor" > {this.hasIconStartSlot && ( @@ -261,7 +262,7 @@ export class MwAutocomplete {
- {this.maximum && this.optionCounter && } + {this.maximum && this.optionCounter && }
diff --git a/mwui-stencil/src/components/mw-autocomplete/readme.md b/mwui-stencil/src/components/mw-autocomplete/readme.md index b97d34cb..c3e00983 100644 --- a/mwui-stencil/src/components/mw-autocomplete/readme.md +++ b/mwui-stencil/src/components/mw-autocomplete/readme.md @@ -20,15 +20,15 @@ | `placeholder` | `placeholder` | Placeholder to be displayed | `string` | `undefined` | | `readOnly` | `read-only` | Whether user can't type in input field | `boolean` | `false` | | `required` | `required` | Mark input as required | `boolean` | `false` | -| `selected` | -- | Currently selected options | `string[]` | `[]` | +| `selection` | -- | Currently selected options | `string[]` | `[]` | | `type` | `type` | HTML Input type | `string` | `"text"` | | `value` | `value` | input field value | `number \| string` | `undefined` | ## Events -| Event | Description | Type | -| ---------------------------- | ------------------------------------- | --------------------- | -| `mwAutocompleteValueChanged` | Emits an event when its value changes | `CustomEvent` | +| Event | Description | Type | +| ------------------ | ------------------------------------- | --------------------- | +| `selectionChanged` | Emits an event when its value changes | `CustomEvent` | ## Dependencies diff --git a/mwui-stencil/src/components/mw-card-image/readme.md b/mwui-stencil/src/components/mw-card-image/readme.md index a2b64177..ca8fcea9 100644 --- a/mwui-stencil/src/components/mw-card-image/readme.md +++ b/mwui-stencil/src/components/mw-card-image/readme.md @@ -1,18 +1,15 @@ # mw-card-image - - - ## Properties | Property | Attribute | Description | Type | Default | | -------- | --------- | ---------------------- | -------- | ----------- | | `alt` | `alt` | Alt text for the image | `string` | `undefined` | +| `height` | `height` | Height of image | `string` | `undefined` | | `src` | `src` | Image source | `string` | `undefined` | +--- ----------------------------------------------- - -*Built with [StencilJS](https://stenciljs.com/)* +_Built with [StencilJS](https://stenciljs.com/)_ diff --git a/mwui-stencil/src/components/mw-chip-input/readme.md b/mwui-stencil/src/components/mw-chip-input/readme.md index 1fed211d..15c6e234 100644 --- a/mwui-stencil/src/components/mw-chip-input/readme.md +++ b/mwui-stencil/src/components/mw-chip-input/readme.md @@ -21,10 +21,10 @@ ## Events -| Event | Description | Type | -| ------------------------ | ------------------------------------------ | ----------------------- | -| `mwChipListInputChange` | Emits an event when value of input changes | `CustomEvent` | -| `mwChipListValueChanged` | Emits an event when its value changes | `CustomEvent` | +| Event | Description | Type | +| -------------- | ------------------------------------------ | ----------------------- | +| `inputChange` | Emits an event when value of input changes | `CustomEvent` | +| `valueChanged` | Emits an event when its value changes | `CustomEvent` | ## Dependencies diff --git a/mwui-stencil/src/index.html b/mwui-stencil/src/index.html index 8141bec1..2846df18 100644 --- a/mwui-stencil/src/index.html +++ b/mwui-stencil/src/index.html @@ -528,6 +528,11 @@

Login

const cards = document.getElementsByTagName("mw-card"); const chips = document.getElementsByTagName("mw-chip"); const tabs = document.getElementsByTagName("mw-tabs"); + const autocomplete = document.getElementsByTagName("mw-autocomplete")[0]; + + autocomplete.addEventListener("change", event => { + console.log("autocomplete changed", event.target.selection); + }); for (var i = 0; i < cards.length; i++) { cards[i].addEventListener("click", event => {