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: remove deprecated didChange events where possible #3253

Merged
merged 4 commits into from
Nov 28, 2024
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
5 changes: 4 additions & 1 deletion src/elements/autocomplete/autocomplete-base-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ export abstract class SbbAutocompleteBaseElement extends SbbNegativeMixin(

if (this.triggerElement) {
// Set the option value
this.triggerElement.value = target.value as string;
// In order to support React onChange event, we have to get the setter and call it.
// https://github.com/facebook/react/issues/11600#issuecomment-345813130
const setValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!;
setValue.call(this.triggerElement, target.value);

// Manually trigger the change events
this.triggerElement.dispatchEvent(new Event('change', { bubbles: true }));
Expand Down
2 changes: 0 additions & 2 deletions src/elements/checkbox/checkbox-panel/checkbox-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export type SbbCheckboxPanelStateChange = Extract<
* @slot subtext - Slot used to render a subtext under the label (only visible within a selection panel).
* @slot suffix - Slot used to render additional content after the label (only visible within a selection panel).
* @slot badge - Use this slot to provide a `sbb-card-badge` (optional).
* @event {CustomEvent<void>} didChange - Deprecated. used for React. Will probably be removed once React 19 is available.
* @event {Event} change - Event fired on change.
* @event {InputEvent} input - Event fired on input.
*/
Expand All @@ -52,7 +51,6 @@ class SbbCheckboxPanelElement extends SbbPanelMixin(

// FIXME using ...super.events requires: https://github.com/sbb-design-systems/lyne-components/issues/2600
public static readonly events = {
didChange: 'didChange',
stateChange: 'stateChange',
panelConnected: 'panelConnected',
} as const;
Expand Down
9 changes: 4 additions & 5 deletions src/elements/checkbox/checkbox-panel/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,10 @@ If you don't want the label to appear next to the checkbox, you can use `aria-la

## Events

| Name | Type | Description | Inherited From |
| ----------- | ------------------- | -------------------------------------------------------------------------------- | -------------- |
| `change` | `Event` | Event fired on change. | |
| `didChange` | `CustomEvent<void>` | Deprecated. used for React. Will probably be removed once React 19 is available. | |
| `input` | `InputEvent` | Event fired on input. | |
| Name | Type | Description | Inherited From |
| -------- | ------------ | ---------------------- | -------------- |
| `change` | `Event` | Event fired on change. | |
| `input` | `InputEvent` | Event fired on input. | |

## Slots

Expand Down
5 changes: 0 additions & 5 deletions src/elements/checkbox/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import '../../visual-checkbox.js';
*
* @slot - Use the unnamed slot to add content to the `sbb-checkbox`.
* @slot icon - Slot used to render the checkbox icon (disabled inside a selection panel).
* @event {CustomEvent<void>} didChange - Deprecated. used for React. Will probably be removed once React 19 is available.
* @event {Event} change - Event fired on change.
* @event {InputEvent} input - Event fired on input.
*/
Expand All @@ -29,10 +28,6 @@ export
class SbbCheckboxElement extends SbbCheckboxCommonElementMixin(SbbIconNameMixin(LitElement)) {
public static override styles: CSSResultGroup = [checkboxCommonStyle, checkboxStyle];

public static readonly events = {
didChange: 'didChange',
} as const;

/** Size variant. */
@property({ reflect: true })
@getOverride((i, v) => i.group?.size ?? v)
Expand Down
9 changes: 4 additions & 5 deletions src/elements/checkbox/checkbox/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,10 @@ If you don't want the label to appear next to the checkbox, you can use `aria-la

## Events

| Name | Type | Description | Inherited From |
| ----------- | ------------------- | -------------------------------------------------------------------------------- | -------------- |
| `change` | `Event` | Event fired on change. | |
| `didChange` | `CustomEvent<void>` | Deprecated. used for React. Will probably be removed once React 19 is available. | |
| `input` | `InputEvent` | Event fired on input. | |
| Name | Type | Description | Inherited From |
| -------- | ------------ | ---------------------- | -------------- |
| `change` | `Event` | Event fired on change. | |
| `input` | `InputEvent` | Event fired on input. | |

## Slots

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ export const SbbFormAssociatedCheckboxMixin = <T extends Constructor<LitElement>

this.dispatchEvent(new InputEvent('input', { composed: true, bubbles: true }));
this.dispatchEvent(new Event('change', { bubbles: true }));
this.dispatchEvent(new CustomEvent('didChange', { bubbles: true }));
};
}

Expand Down
4 changes: 4 additions & 0 deletions src/elements/datepicker/datepicker/datepicker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ describe(`sbb-datepicker`, () => {

it('renders and emit event on value change', async () => {
const changeSpy = new EventSpy('change', element);
const inputSpy = new EventSpy('input', element);
typeInElement(input, '20/01/2023');
expect(inputSpy.count).to.be.equal(10);

button.focus();
await changeSpy.calledOnce();
expect(input.value).to.be.equal('Fr, 20.01.2023');
expect(changeSpy.count).to.be.equal(1);
expect(inputSpy.count).to.be.equal(11);
});

it('renders and interpret two digit year correctly in 2000s', async () => {
Expand Down
29 changes: 15 additions & 14 deletions src/elements/datepicker/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { SbbConnectedAbortController, SbbLanguageController } from '../../core/c
import { type DateAdapter, defaultDateAdapter } from '../../core/datetime.js';
import { forceType } from '../../core/decorators.js';
import { findInput, findReferencedElement } from '../../core/dom.js';
import { EventEmitter } from '../../core/eventing.js';
import { EventEmitter, forwardEventToHost } from '../../core/eventing.js';
import { i18nDateChangedTo, i18nDatePickerPlaceholder } from '../../core/i18n.js';
import type { SbbDateLike, SbbValidationChangeEvent } from '../../core/interfaces.js';
import type { SbbDatepickerButton } from '../common.js';
Expand Down Expand Up @@ -56,8 +56,8 @@ export const datepickerControlRegisteredEventFactory = (): CustomEvent =>
/**
* Combined with a native input, it displays the input's value as a formatted date.
*
* @event {CustomEvent<void>} didChange - Deprecated. used for React. Will probably be removed once React 19 is available.
* @event {CustomEvent<void>} change - Notifies that the connected input has changes.
* @event {CustomEvent<void>} input - Notifies that the connected input fired the input event.
* @event {CustomEvent<SbbInputUpdateEvent>} inputUpdated - Notifies that the attributes of the input connected to the datepicker have changes.
* @event {CustomEvent<void>} datePickerUpdated - Notifies that the attributes of the datepicker have changes.
* @event {CustomEvent<SbbValidationChangeEvent>} validationChange - Emits whenever the internal validation state changes.
Expand All @@ -67,7 +67,6 @@ export
class SbbDatepickerElement<T = Date> extends LitElement {
public static override styles: CSSResultGroup = style;
public static readonly events = {
didChange: 'didChange',
change: 'change',
inputUpdated: 'inputUpdated',
datePickerUpdated: 'datePickerUpdated',
Expand Down Expand Up @@ -111,14 +110,6 @@ class SbbDatepickerElement<T = Date> extends LitElement {
}
private _valueAsDate?: T | null;

/**
* @deprecated only used for React. Will probably be removed once React 19 is available.
*/
private _didChange: EventEmitter = new EventEmitter(this, SbbDatepickerElement.events.didChange, {
bubbles: true,
cancelable: true,
});

/** Notifies that the connected input has changes. */
private _change: EventEmitter = new EventEmitter(this, SbbDatepickerElement.events.change, {
bubbles: true,
Expand Down Expand Up @@ -249,7 +240,14 @@ class SbbDatepickerElement<T = Date> extends LitElement {
}

const options: AddEventListenerOptions = { signal: this._datePickerController.signal };
input.addEventListener('input', () => this._parseInput(), options);
input.addEventListener(
'input',
(e) => {
forwardEventToHost(e, this);
this._parseInput();
},
options,
);
input.addEventListener('change', () => this._handleInputChange(), options);
this._parseInput(true);
this._tryApplyFormatToInput();
Expand All @@ -269,7 +267,6 @@ class SbbDatepickerElement<T = Date> extends LitElement {
this._validateDate();
this._setAriaLiveMessage();
this._change.emit();
this._didChange.emit();
}

private _tryApplyFormatToInput(): boolean {
Expand All @@ -279,7 +276,11 @@ class SbbDatepickerElement<T = Date> extends LitElement {

const formattedDate = this.valueAsDate ? this._dateAdapter.format(this.valueAsDate!) : '';
if (formattedDate && this._inputElement.value !== formattedDate) {
this._inputElement.value = formattedDate;
// In order to support React onChange event, we have to get the setter and call it.
// https://github.com/facebook/react/issues/11600#issuecomment-345813130
const setValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!;
setValue.call(this._inputElement, formattedDate);

this._inputElement.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));
this._inputElement.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/elements/datepicker/datepicker/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,6 @@ Whenever the validation state changes (e.g., a valid value becomes invalid or vi
| ------------------- | --------------------------------------- | ----------------------------------------------------------------------------------- | -------------- |
| `change` | `CustomEvent<void>` | Notifies that the connected input has changes. | |
| `datePickerUpdated` | `CustomEvent<void>` | Notifies that the attributes of the datepicker have changes. | |
| `didChange` | `CustomEvent<void>` | Deprecated. used for React. Will probably be removed once React 19 is available. | |
| `input` | `CustomEvent<void>` | Notifies that the connected input fired the input event. | |
| `inputUpdated` | `CustomEvent<SbbInputUpdateEvent>` | Notifies that the attributes of the input connected to the datepicker have changes. | |
| `validationChange` | `CustomEvent<SbbValidationChangeEvent>` | Emits whenever the internal validation state changes. | |
19 changes: 16 additions & 3 deletions src/elements/form-field/form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,23 @@
signal: this._inputAbortController.signal,
});

inputFocusElement = (this._input as SbbSelectElement).inputElement;
const selectInput = this._input as SbbSelectElement;
inputFocusElement = selectInput.inputElement;

// If inputElement is not yet ready, try a second time after updating.
if (!inputFocusElement) {
const controller = {
hostUpdated: () => {
selectInput.removeController(controller);
this._registerInputListener();
},
};

selectInput.addController(controller);
}

Check warning on line 303 in src/elements/form-field/form-field/form-field.ts

View check run for this annotation

Codecov / codecov/patch

src/elements/form-field/form-field/form-field.ts#L295-L303

Added lines #L295 - L303 were not covered by tests
}

inputFocusElement.addEventListener(
inputFocusElement?.addEventListener(
'focusin',
() => {
this.toggleAttribute('data-input-focused', true);
Expand All @@ -304,7 +317,7 @@
},
);

inputFocusElement.addEventListener(
inputFocusElement?.addEventListener(
'focusout',
() =>
['data-focus-origin', 'data-input-focused'].forEach((name) => this.removeAttribute(name)),
Expand Down
17 changes: 8 additions & 9 deletions src/elements/select/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,14 @@ Opened panel:

## Events

| Name | Type | Description | Inherited From |
| ----------- | ------------------- | -------------------------------------------------------------------------------- | ----------------------- |
| `change` | `CustomEvent<void>` | Notifies that the component's value has changed. | |
| `didChange` | `CustomEvent<void>` | Deprecated. used for React. Will probably be removed once React 19 is available. | |
| `didClose` | `CustomEvent<void>` | Emits whenever the `sbb-select` is closed. | SbbOpenCloseBaseElement |
| `didOpen` | `CustomEvent<void>` | Emits whenever the `sbb-select` is opened. | SbbOpenCloseBaseElement |
| `input` | `CustomEvent<void>` | Notifies that an option value has been selected. | |
| `willClose` | `CustomEvent<void>` | Emits whenever the `sbb-select` begins the closing transition. Can be canceled. | SbbOpenCloseBaseElement |
| `willOpen` | `CustomEvent<void>` | Emits whenever the `sbb-select` starts the opening transition. Can be canceled. | SbbOpenCloseBaseElement |
| Name | Type | Description | Inherited From |
| ----------- | ------------------- | ------------------------------------------------------------------------------- | ----------------------- |
| `change` | `CustomEvent<void>` | Notifies that the component's value has changed. | |
| `didClose` | `CustomEvent<void>` | Emits whenever the `sbb-select` is closed. | SbbOpenCloseBaseElement |
| `didOpen` | `CustomEvent<void>` | Emits whenever the `sbb-select` is opened. | SbbOpenCloseBaseElement |
| `input` | `CustomEvent<void>` | Notifies that an option value has been selected. | |
| `willClose` | `CustomEvent<void>` | Emits whenever the `sbb-select` begins the closing transition. Can be canceled. | SbbOpenCloseBaseElement |
| `willOpen` | `CustomEvent<void>` | Emits whenever the `sbb-select` starts the opening transition. Can be canceled. | SbbOpenCloseBaseElement |

## CSS Properties

Expand Down
9 changes: 0 additions & 9 deletions src/elements/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export interface SelectChange {
* It displays a panel with selectable options.
*
* @slot - Use the unnamed slot to add options.
* @event {CustomEvent<void>} didChange - Deprecated. used for React. Will probably be removed once React 19 is available.
* @event {CustomEvent<void>} change - Notifies that the component's value has changed.
* @event {CustomEvent<void>} input - Notifies that an option value has been selected.
* @event {CustomEvent<void>} willOpen - Emits whenever the `sbb-select` starts the opening transition. Can be canceled.
Expand Down Expand Up @@ -77,7 +76,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(

// FIXME using ...super.events requires: https://github.com/sbb-design-systems/lyne-components/issues/2600
public static override readonly events = {
didChange: 'didChange',
change: 'change',
input: 'input',
stateChange: 'stateChange',
Expand Down Expand Up @@ -113,11 +111,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(
/** The value displayed by the component. */
@state() private accessor _displayValue: string | null = null;

/**
* @deprecated only used for React. Will probably be removed once React 19 is available.
*/
private _didChange: EventEmitter = new EventEmitter(this, SbbSelectElement.events.didChange);

/** Notifies that the component's value has changed. */
private _change: EventEmitter = new EventEmitter(this, SbbSelectElement.events.change);

Expand Down Expand Up @@ -519,7 +512,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(

this._input.emit();
this._change.emit();
this._didChange.emit();
}

/** When an option is unselected in `multiple`, removes it from value and updates displayValue. */
Expand All @@ -531,7 +523,6 @@ class SbbSelectElement extends SbbUpdateSchedulerMixin(

this._input.emit();
this._change.emit();
this._didChange.emit();
}
}

Expand Down
18 changes: 15 additions & 3 deletions src/elements/time-input/time-input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,25 @@ describe(`sbb-time-input`, () => {
it('should emit form events', async () => {
const changeSpy = new EventSpy('change', element);
const inputSpy = new EventSpy('input', element);
const nativeInputSpy = new EventSpy('input', input);
const nativeChangeSpy = new EventSpy('change', input);

typeInElement(input, '1');
input.focus();
await sendKeys({ press: '1' });
input.blur();
await waitForLitRender(element);

expect(changeSpy.count).to.be.greaterThan(0);
expect(inputSpy.count).to.be.greaterThan(0);
await nativeChangeSpy.calledOnce().then(() => {
expect(input.value).to.be.equal('01:00');
});
await changeSpy.calledOnce().then(() => {
expect(input.value).to.be.equal('01:00');
});

expect(inputSpy.count, 'sbb-time-input input event').to.be.equal(2);
expect(changeSpy.count, 'sbb-time-input change event').to.be.equal(1);
expect(nativeInputSpy.count, 'input input event').to.be.equal(2);
expect(nativeChangeSpy.count, 'input change event').to.be.equal(1);
});

it('should emit validation change event', async () => {
Expand Down
27 changes: 18 additions & 9 deletions src/elements/time-input/time-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,22 @@ class SbbTimeInputElement extends LitElement {
);
this._inputElement.addEventListener(
'change',
(event: Event) => this._updateValueAndEmitChange(event),
(event: Event) => this._updateValue((event.target as HTMLInputElement).value),
{
signal: this._abortController.signal,
capture: true,
},
);
this._inputElement.addEventListener(
'change',
(event: Event) => {
this._emitChange(event);
this._updateAccessibilityMessage();
},
{
signal: this._abortController.signal,
},
);
}

/** Applies the correct format to values and triggers event dispatch. */
private _updateValueAndEmitChange(event: Event): void {
this._updateValue((event.target as HTMLInputElement).value);
this._emitChange(event);
this._updateAccessibilityMessage();
}

/**
Expand All @@ -175,7 +179,12 @@ class SbbTimeInputElement extends LitElement {
const isTimeValid = !!time && this._isTimeValid(time);
const isEmptyOrValid = !value || value.trim() === '' || isTimeValid;
if (isEmptyOrValid && time) {
this._inputElement.value = this._formatValue(time);
// In order to support React onChange event, we have to get the setter and call it.
// https://github.com/facebook/react/issues/11600#issuecomment-345813130
const setValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!;
setValue.call(this._inputElement, this._formatValue(time));

this._inputElement.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));
}

const wasValid = !this._inputElement.hasAttribute('data-sbb-invalid');
Expand Down
Loading
Loading