diff --git a/stencil-workspace/src/components/modus-button-group/modus-button-group.constants.ts b/stencil-workspace/src/components/modus-button-group/modus-button-group.constants.ts
index 719d7c22d..45dd8e5b7 100644
--- a/stencil-workspace/src/components/modus-button-group/modus-button-group.constants.ts
+++ b/stencil-workspace/src/components/modus-button-group/modus-button-group.constants.ts
@@ -1,3 +1,4 @@
export const SINGLE_SELECTION_TYPE = 'single';
export const MULTIPLE_SELECTION_TYPE = 'multiple';
export const DEFAULT_SELECTION_TYPE = 'none';
+export const SELECTION_ATTRIBUTE = 'selected';
diff --git a/stencil-workspace/src/components/modus-button-group/modus-button-group.e2e.ts b/stencil-workspace/src/components/modus-button-group/modus-button-group.e2e.ts
index fcb7fd048..c676e1460 100644
--- a/stencil-workspace/src/components/modus-button-group/modus-button-group.e2e.ts
+++ b/stencil-workspace/src/components/modus-button-group/modus-button-group.e2e.ts
@@ -245,4 +245,28 @@ describe('modus-button-group', () => {
expect(buttonGroup.getAttribute('aria-label')).toBe('Group Label');
expect(buttonGroup.getAttribute('aria-disabled')).toBe('true');
});
+
+ it('should remove active state from buttons when selected attribute is removed or set to false', async () => {
+ const page = await newE2EPage();
+
+ await page.setContent(`
+
+ Button 1
+
+ `);
+ const modusButton = await page.find('modus-button');
+ const buttonElement = await page.find('modus-button >>> button');
+
+ modusButton.removeAttribute('selected');
+ await page.waitForChanges();
+ expect(buttonElement).not.toHaveClass('active');
+
+ modusButton.setAttribute('selected', 'true');
+ await page.waitForChanges();
+ expect(buttonElement).toHaveClass('active');
+
+ modusButton.setAttribute('selected', 'false');
+ await page.waitForChanges();
+ expect(buttonElement).not.toHaveClass('active');
+ });
});
diff --git a/stencil-workspace/src/components/modus-button-group/modus-button-group.spec.ts b/stencil-workspace/src/components/modus-button-group/modus-button-group.spec.ts
index 84c62f6dd..970085254 100644
--- a/stencil-workspace/src/components/modus-button-group/modus-button-group.spec.ts
+++ b/stencil-workspace/src/components/modus-button-group/modus-button-group.spec.ts
@@ -2,6 +2,21 @@ import { newSpecPage } from '@stencil/core/testing';
import { ModusButtonGroup } from './modus-button-group';
describe('modus-button-group', () => {
+ beforeAll(() => {
+ class MutationObserverMock {
+ observe() {}
+ disconnect() {}
+ takeRecords() {
+ return [];
+ }
+ }
+ global.MutationObserver = MutationObserverMock;
+ });
+
+ afterAll(() => {
+ delete global.MutationObserver;
+ });
+
it('renders', async () => {
const { root } = await newSpecPage({
components: [ModusButtonGroup],
diff --git a/stencil-workspace/src/components/modus-button-group/modus-button-group.tsx b/stencil-workspace/src/components/modus-button-group/modus-button-group.tsx
index 79db3a680..c71af605d 100644
--- a/stencil-workspace/src/components/modus-button-group/modus-button-group.tsx
+++ b/stencil-workspace/src/components/modus-button-group/modus-button-group.tsx
@@ -1,8 +1,13 @@
// eslint-disable-next-line
-import { Component, h, Prop, Element, Event, EventEmitter, Host, Listen, Watch } from '@stencil/core';
-import { ButtonGroupSelectionType } from './modus-button-group.models';
-import { DEFAULT_SELECTION_TYPE, SINGLE_SELECTION_TYPE, MULTIPLE_SELECTION_TYPE } from './modus-button-group.constants';
+import { Component, Element, Event, EventEmitter, h, Host, Listen, Prop, Watch } from '@stencil/core';
import { ButtonColor, ButtonSize, ButtonStyle, ButtonType } from '../modus-button/modus-button.models';
+import {
+ DEFAULT_SELECTION_TYPE,
+ MULTIPLE_SELECTION_TYPE,
+ SELECTION_ATTRIBUTE,
+ SINGLE_SELECTION_TYPE,
+} from './modus-button-group.constants';
+import { ButtonGroupSelectionType } from './modus-button-group.models';
@Component({
tag: 'modus-button-group',
@@ -12,6 +17,7 @@ import { ButtonColor, ButtonSize, ButtonStyle, ButtonType } from '../modus-butto
export class ModusButtonGroup {
/** Array to store selected buttons */
selectedButtons: HTMLModusButtonElement[] = [];
+ private observer: MutationObserver | null = null;
@Element() host: HTMLElement;
@@ -65,6 +71,15 @@ export class ModusButtonGroup {
this.setupButtons();
}
+ componentDidLoad() {
+ this.observer = new MutationObserver(this.handleMutations.bind(this));
+ this.observer.observe(this.host, { subtree: true, attributes: true, attributeFilter: [SELECTION_ATTRIBUTE] });
+ }
+
+ disconnectedCallback() {
+ this.observer?.disconnect();
+ }
+
@Listen('slotchange')
handleSlotChange() {
this.setupButtons();
@@ -90,9 +105,31 @@ export class ModusButtonGroup {
this.buttonGroupClick.emit({ button: clickedButton, isSelected: this.selectedButtons.includes(clickedButton) });
}
+ handleMutations(mutationList: MutationRecord[]) {
+ for (const mutation of mutationList) {
+ if (mutation.type === 'attributes' && mutation.attributeName === SELECTION_ATTRIBUTE) {
+ this.setupButtons();
+ }
+ }
+ }
+
+ handleButtonSelection(button, isSelected) {
+ if (isSelected) {
+ button.setActive(true);
+ this.selectedButtons.push(button);
+ } else {
+ button.setActive(false);
+ if (this.selectedButtons.includes(button)) {
+ this.selectedButtons = this.selectedButtons.filter((selectedButton) => selectedButton !== button);
+ }
+ }
+ }
+
setupButtons(reset?: boolean) {
- const buttons = this.host.querySelectorAll('modus-button');
- this.renderButtons(buttons, reset);
+ customElements.whenDefined('modus-button').then(() => {
+ const buttons = this.host.querySelectorAll('modus-button');
+ this.renderButtons(buttons, reset);
+ });
}
renderButtons(buttons: NodeListOf, reset: boolean) {
@@ -111,15 +148,13 @@ export class ModusButtonGroup {
button.color = this.color;
button.size = this.size;
button.type = buttonType;
- if (button.hasAttribute('selected') && !foundSelected && this.selectionType == SINGLE_SELECTION_TYPE) {
- button.setActive(true);
- this.selectedButtons.push(button);
+ if (button.hasAttribute(SELECTION_ATTRIBUTE) && !foundSelected && this.selectionType == SINGLE_SELECTION_TYPE) {
+ this.handleButtonSelection(button, button.getAttribute(SELECTION_ATTRIBUTE) !== 'false');
foundSelected = true;
- } else if (button.hasAttribute('selected') && this.selectionType == MULTIPLE_SELECTION_TYPE) {
- button.setActive(true);
- if (!this.selectedButtons.includes(button)) {
- this.selectedButtons.push(button);
- }
+ } else if (button.hasAttribute(SELECTION_ATTRIBUTE) && this.selectionType == MULTIPLE_SELECTION_TYPE) {
+ this.handleButtonSelection(button, button.getAttribute(SELECTION_ATTRIBUTE) !== 'false');
+ } else {
+ this.handleButtonSelection(button, false);
}
});
}
diff --git a/stencil-workspace/src/components/modus-number-input/readme.md b/stencil-workspace/src/components/modus-number-input/readme.md
index 2bc66099d..54e860574 100644
--- a/stencil-workspace/src/components/modus-number-input/readme.md
+++ b/stencil-workspace/src/components/modus-number-input/readme.md
@@ -10,10 +10,12 @@
| Property | Attribute | Description | Type | Default |
| ------------- | ------------- | ------------------------------------------------------------- | --------------------- | ----------- |
| `ariaLabel` | `aria-label` | (optional) The input's aria-label. | `string` | `undefined` |
+| `currency` | `currency` | (optional) The input's currency | `string` | `undefined` |
| `disabled` | `disabled` | (optional) Whether the input is disabled. | `boolean` | `undefined` |
| `errorText` | `error-text` | (optional) The input's error state text. | `string` | `undefined` |
| `helperText` | `helper-text` | (optional) The input's helper text displayed below the input. | `string` | `undefined` |
| `label` | `label` | (optional) The input's label. | `string` | `undefined` |
+| `locale` | `locale` | (optional) The input's locale | `string` | `undefined` |
| `maxValue` | `max-value` | (optional) The input's maximum value. | `number` | `undefined` |
| `minValue` | `min-value` | (optional) The input's minimum value. | `number` | `undefined` |
| `placeholder` | `placeholder` | (optional) The input's placeholder text. | `string` | `undefined` |