Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(select): change label on slot change #233

Merged
merged 4 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import type { OdsSelectOptionAttribute } from './interfaces/attributes';
import type { OdsSelectOptionEvent, OdsSelectOptionClickEventDetail } from './interfaces/events';
import type { OdsSelectOptionMethod } from './interfaces/methods';
import type { OsdsSelect } from '../osds-select/osds-select';
import { Component, Element, Event, EventEmitter, Host, Method, Prop, State, Watch, h } from '@stencil/core';
import { OdsLogger } from '@ovhcloud/ods-common-core';
import { Component, Element, Event, EventEmitter, Host, Method, Prop, State, h } from '@stencil/core';
import { DEFAULT_ATTRIBUTE as SELECT_DEFAULT_ATTRIBUTE } from '../osds-select/constants/default-attributes';
import { DEFAULT_ATTRIBUTE } from './constants/default-attributes';

Expand All @@ -18,7 +17,6 @@ import { DEFAULT_ATTRIBUTE } from './constants/default-attributes';
shadow: true,
})
export class OsdsSelectOption implements OdsSelectOptionAttribute, OdsSelectOptionEvent, OdsSelectOptionMethod {
private logger = new OdsLogger('OsdsSelectOption');
private selectParent: (HTMLStencilElement & OsdsSelect) | null = null;

@Element() el!: HTMLStencilElement;
Expand Down Expand Up @@ -73,23 +71,12 @@ export class OsdsSelectOption implements OdsSelectOptionAttribute, OdsSelectOpti
return this.el.innerText;
}

@Watch('value')
watchValue(value: OdsInputValue) {
this.logger.log(`[select=${this.value}]`, 'value changed', { value });
}

@Watch('selected')
updateSelectGroupValue(selected: boolean) {
this.logger.log(`[select=${this.value}]`, 'selected changed.', { selected });
}

emitClick(value: OdsInputValue) {
this.odsSelectOptionClick.emit({ value });
}

handleClick(event: MouseEvent) {
event.stopPropagation();
this.logger.log(`[select=${this.value}]`, 'option clicked.');
this.emitClick(this.value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ describe('e2e:osds-select', () => {

expect(selectedLabel).toBe(null);
});

it('should change the selected value text', async () => {
await setup({ attributes: { value: '42' } });
await page.waitForChanges();

const options = await page.findAll('osds-select > osds-select-option');
options.forEach((option) => {
option.innerHTML = `NewValue${option.getAttribute('value')}`
});
await page.waitForChanges();

const label = await page.find('osds-select >>> .select-trigger__label');
expect(label.innerText.trim()).toBe('NewValue42');
});
});

// TODO getValidity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import { DEFAULT_VALIDITY_STATE } from './constants/default-validity-state';
import { ODS_SELECT_SIZE } from './constants/select-size';
import { OsdsSelect } from './osds-select';

const mutationObserverMock = jest.fn(function MutationObserver(callback) {
this.observe = jest.fn();
this.disconnect = jest.fn();
// Optionally add a trigger() method to manually trigger a change
this.trigger = (mockedMutationsList) => {
callback(mockedMutationsList, this);
};
});
// @ts-ignore
global.MutationObserver = mutationObserverMock;

const logger = new OdsLogger('osds-select-spec');

// mock validity property that does not exist when stencil mock HTMLInputElement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type { ODS_SELECT_SIZE } from './constants/select-size';
import type { OsdsSelectOption } from '../osds-select-option/osds-select-option';
import type { OdsSelectOptionClickEventDetail } from '../osds-select-option/interfaces/events';
import { Component, Element, Event, EventEmitter, Host, Listen, Method, Prop, State, Watch, h } from '@stencil/core';
import { OdsLogger } from '@ovhcloud/ods-common-core';
import { ODS_ICON_NAME, ODS_ICON_SIZE } from '@ovhcloud/ods-component-icon';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import { ocdkAssertEventTargetIsNode, ocdkDefineCustomElements, ocdkIsSurface } from '@ovhcloud/ods-cdk';
Expand All @@ -28,13 +27,13 @@ ocdkDefineCustomElements()
shadow: true,
})
export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelectMethod {
private logger = new OdsLogger('OsdsSelect');
controller: OdsSelectController = new OdsSelectController(this);
anchor!: HTMLElement;
surface: OcdkSurface | undefined = undefined;
/** is the select was touched by the user */
dirty = false;
selectedLabelSlot: HTMLElement | null = null;
observer?: MutationObserver;

@Element() el!: HTMLStencilElement;

Expand Down Expand Up @@ -103,28 +102,27 @@ export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelect
}

componentWillLoad() {
this.onDefaultValueChange();
if (this.value === '' && this.defaultValue !== undefined) {
this.value = this.defaultValue;
}
this.openedChanged(this.opened);
this.selectedLabelSlot = this.el.querySelector('[slot="selectedLabel"]');
}

disconnectedCallback(): void {
this.observer?.disconnect();
}

/**
* once the component did load, update the state depending the children,
* in order to synchronize the already set value with the placeholder
*/
async componentDidLoad() {
this.observer = new MutationObserver(async () => this.selectedOptionLabel = await this.optionSelected?.getLabel() || '');
this.setSelectOptions();
await this.updateSelectOptionStates(this.value);
}

@Watch('defaultValue')
onDefaultValueChange(defaultValue?: OdsInputValue) {
this.logger.debug(`[input=${this.value}]`, 'defaultValue', defaultValue);
}

@Watch('opened')
openedChanged(opened: boolean) {
if (this.surface) {
Expand All @@ -134,13 +132,11 @@ export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelect

@Watch('value')
async onValueChange(value: OdsInputValue, oldValue?: OdsInputValue) {
this.logger.log(`[onValueChange=${this.value}]`, 'value changed. emit new value', { value });
this.emitChange(value, oldValue);
await this.updateSelectOptionStates(value);
}

private emitChange(value: OdsInputValue, oldValue?: OdsInputValue) {
this.logger.debug('emit', { value, oldValue });
this.odsValueChange.emit({
value: value,
oldValue: oldValue,
Expand Down Expand Up @@ -225,13 +221,11 @@ export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelect
}

changeValue(value: OdsInputValue) {
this.logger.log(`[changeValue=${this.value}]`, 'value changed', { value });
this.value = value;
}

// Toggle overlay when we click on the Select.
handleSelectClick(): void {
this.logger.log('[handleSelectClick]', arguments, { validity: this.validityState });
if (this.disabled) {
return;
}
Expand All @@ -250,7 +244,6 @@ export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelect
if (!this.dirty || this.surface?.isClickOutsideSurface(ev)) {
return;
}
this.logger.log('[checkForClickOutside]', arguments, { validity: this.validityState });
this.controller.closeSurface();

this.controller.selectOptions.forEach((option) => {
Expand All @@ -268,7 +261,6 @@ export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelect

@Listen('odsSelectOptionClick')
handleValueChange(event: CustomEvent<OdsSelectOptionClickEventDetail>): void {
this.logger.log(`[odsSelectOptionClick=${this.value}]`, 'received odsSelectOptionClick event', { detail: event.detail });
this.changeValue(event.detail.value);
this.controller.closeSurface();
}
Expand All @@ -284,12 +276,14 @@ export class OsdsSelect implements OdsSelectAttribute, OdsSelectEvent, OdsSelect
this.controller.syncReferences()
}

handleSlotChange() {
async handleSlotChange(): Promise<void> {
this.setSelectOptions();
await this.updateSelectOptionStates();
}

setSelectOptions() {
this.controller.selectOptions = this.getSelectOptionList();
this.controller.selectOptions.forEach((option) => this.observer?.observe(option, { childList: true }))
}

getSelectOptionList(): (HTMLElement & OsdsSelectOption)[] {
Expand Down
5 changes: 5 additions & 0 deletions packages/components/select/src/global.dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ Object.keys(examples).forEach(k => {
// todo
// examples.select1.component && (examples.select1.component.opened = !examples.select1.component.opened);
// evt.stopPropagation()
const options = document.querySelectorAll('#select1 > osds-select-option');
options.forEach((option) => {
option.innerHTML = `NewValue${option.getAttribute('value')}`;
});
// const select = document.querySelector('#select1');
};

(window as any).select6Clear = function () {
Expand Down