Skip to content

Commit

Permalink
Merge 13d7511 into 6927cd5
Browse files Browse the repository at this point in the history
  • Loading branch information
bennypowers authored Jul 9, 2024
2 parents 6927cd5 + 13d7511 commit 88b059e
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 29 deletions.
16 changes: 16 additions & 0 deletions .changeset/fluffy-papers-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@patternfly/pfe-core": minor
---
**Decorators**: Added `@listen`. Use it to attach element event listeners to
class methods.

```ts
@customElement('custom-input')
class CustomInput extends LitElement {
@property({ type: Boolean }) dirty = false;
@listen('keyup', { once: true })
protected onKeyup() {
this.dirty = true;
}
}
```
21 changes: 21 additions & 0 deletions .changeset/poor-years-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"@patternfly/pfe-core": minor
---
**Decorators**: Added `@observes`. Use it to add property change callback by
decorating them with the name of the property to observe

```ts
@customElement('custom-button')
class CustomButton extends LitElement {
#internals = this.attachInternals();

@property({ type: Boolean }) disabled = false;

@observes('disabled')
protected disabledChanged() {
this.#internals.ariaDisabled =
this.disabled ? 'true'
: this.ariaDisabled ?? 'false';
}
}
```
2 changes: 2 additions & 0 deletions core/pfe-core/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export * from './decorators/bound.js';
export * from './decorators/cascades.js';
export * from './decorators/deprecation.js';
export * from './decorators/initializer.js';
export * from './decorators/listen.js';
export * from './decorators/observed.js';
export * from './decorators/observes.js';
export * from './decorators/time.js';
export * from './decorators/trace.js';
26 changes: 26 additions & 0 deletions core/pfe-core/decorators/listen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { LitElement } from 'lit';

/**
* Listens for a given event on the custom element.
* equivalent to calling `this.addEventListener` in the constructor
* @param type event type e.g. `click`
* @param options event listener options object e.g. `{ passive: true }`
*/
export function listen(type: string, options?: EventListenerOptions) {
return function(
proto: LitElement,
methodName: string,
) {
const origConnected = proto.connectedCallback;
const origDisconnected = proto.disconnectedCallback;
const listener = (proto as any)[methodName] as EventListener;
proto.connectedCallback = function() {
origConnected();
this.addEventListener(type, listener, options);
};
proto.disconnectedCallback = function() {
origDisconnected();
this.removeEventListener(type, listener, options);
};
};
}
30 changes: 30 additions & 0 deletions core/pfe-core/decorators/observes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { ReactiveElement } from 'lit';

import type { ChangeCallback } from '@patternfly/pfe-core/controllers/property-observer-controller.js';

/**
* Observes changes on the given property and calls the decorated method
* with the old and new values when it changes.
* @param propertyName property to react to
*/
export function observes<T extends ReactiveElement>(propertyName: string & keyof T) {
return function(proto: T, methodName: string) {
const method = proto[methodName as keyof T] as ChangeCallback<T>;
if (typeof method !== 'function') {
throw new Error('@observes must decorate a class method');
}
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyName);
Object.defineProperty(proto, propertyName, {
...descriptor,
configurable: true,
set(this: T, newVal: T[keyof T]) {
const oldVal = this[propertyName as keyof T];
// first, call any pre-existing setters, e.g. `@property`
descriptor?.set?.call(this, newVal);
method.call(this, oldVal, newVal);
},
});
};
}


20 changes: 12 additions & 8 deletions elements/pf-accordion/pf-accordion.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LitElement, html } from 'lit';
import { observed } from '@patternfly/pfe-core/decorators.js';
import { listen, observes } from '@patternfly/pfe-core/decorators.js';
import { property } from 'lit/decorators/property.js';
import { customElement } from 'lit/decorators/custom-element.js';

Expand Down Expand Up @@ -114,9 +114,6 @@ export class PfAccordion extends LitElement {
@property({ type: Boolean, reflect: true }) bordered = false;

/** Whether to apply the `large` style variant */
@observed(function largeChanged(this: PfAccordion) {
[...this.headers, ...this.panels].forEach(el => el.toggleAttribute('large', this.large));
})
@property({ type: Boolean, reflect: true }) large = false;

@property({ type: Boolean, reflect: true }) fixed = false;
Expand Down Expand Up @@ -183,7 +180,6 @@ export class PfAccordion extends LitElement {

connectedCallback() {
super.connectedCallback();
this.addEventListener('change', this.#onChange as EventListener);
this.#mo.observe(this, { childList: true });
this.#init();
}
Expand Down Expand Up @@ -221,6 +217,13 @@ export class PfAccordion extends LitElement {
return c && results.every(Boolean);
}

@observes('large')
protected largeChanged() {
for (const el of [...this.headers, ...this.panels]) {
el.toggleAttribute('large', this.large);
}
}

/**
* Initialize the accordion by connecting headers and panels
* with aria controls and labels; set up the default disclosure
Expand Down Expand Up @@ -280,7 +283,8 @@ export class PfAccordion extends LitElement {
panel.hidden = true;
}

#onChange(event: PfAccordionHeaderChangeEvent) {
@listen('change')
protected onChange(event: PfAccordionHeaderChangeEvent) {
if (event instanceof PfAccordionHeaderChangeEvent && event.accordion === this) {
const index = this.#getIndex(event.target);
if (event.expanded) {
Expand Down Expand Up @@ -358,8 +362,8 @@ export class PfAccordion extends LitElement {
}

// If the header and panel exist, open both
this.#expandHeader(header, index),
this.#expandPanel(panel),
this.#expandHeader(header, index);
this.#expandPanel(panel);

header.focus();

Expand Down
19 changes: 9 additions & 10 deletions elements/pf-jump-links/pf-jump-links-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { InternalsController } from '@patternfly/pfe-core/controllers/internals-

import style from './pf-jump-links-item.css';

import { observed } from '@patternfly/pfe-core/decorators/observed.js';
import { observes } from '@patternfly/pfe-core/decorators/observes.js';

/**
* @cssprop --pf-c-jump-links__link--PaddingTop -- padding around the link
Expand All @@ -28,29 +28,28 @@ export class PfJumpLinksItem extends LitElement {
};

/** Whether this item is active. */
@observed('activeChanged')
@property({ type: Boolean, reflect: true }) active = false;

/** hypertext reference for this link */
@property({ reflect: true }) href?: string;

#internals = InternalsController.of(this, { role: 'listitem' });

override connectedCallback() {
super.connectedCallback();
this.activeChanged();
}
#internals = InternalsController.of(this, {
role: 'listitem',
});

render() {
return html`
<a href="${ifDefined(this.href)}" @focus="${this.#onFocus}" @click="${this.#onClick}">
<a href="${ifDefined(this.href)}"
@focus="${this.#onFocus}"
@click="${this.#onClick}">
<slot></slot>
</a>
<slot name="subsection"></slot>
`;
}

private activeChanged() {
@observes('active')
protected activeChanged() {
this.#internals.ariaCurrent = this.active ? 'location' : null;
}

Expand Down
12 changes: 6 additions & 6 deletions elements/pf-modal/pf-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { classMap } from 'lit/directives/class-map.js';

import { ComposedEvent } from '@patternfly/pfe-core';
import { bound, initializer, observed } from '@patternfly/pfe-core/decorators.js';
import { bound, initializer, observes } from '@patternfly/pfe-core/decorators.js';
import { getRandomId } from '@patternfly/pfe-core/functions/random.js';

import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js';
Expand Down Expand Up @@ -67,7 +67,7 @@ export class ModalOpenEvent extends ComposedEvent {
*/
@customElement('pf-modal')
export class PfModal extends LitElement implements HTMLDialogElement {
static override readonly shadowRootOptions = {
static override readonly shadowRootOptions: ShadowRootInit = {
...LitElement.shadowRootOptions,
delegatesFocus: true,
};
Expand All @@ -88,11 +88,9 @@ export class PfModal extends LitElement implements HTMLDialogElement {
*/
@property({ reflect: true }) position?: 'top';

@observed
@property({ type: Boolean, reflect: true }) open = false;

/** Optional ID of the trigger element */
@observed
@property() trigger?: string;

/** @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/returnValue */
Expand Down Expand Up @@ -190,7 +188,8 @@ export class PfModal extends LitElement implements HTMLDialogElement {
}
}

protected async _openChanged(oldValue?: boolean, newValue?: boolean) {
@observes('open')
protected async openChanged(oldValue?: boolean, newValue?: boolean) {
// loosening types to prevent running these effects in unexpected circumstances
// eslint-disable-next-line eqeqeq
if (oldValue == null || newValue == null || oldValue == newValue) {
Expand All @@ -216,7 +215,8 @@ export class PfModal extends LitElement implements HTMLDialogElement {
}
}

protected _triggerChanged() {
@observes('trigger')
protected triggerChanged() {
if (this.trigger) {
this.#triggerElement = (this.getRootNode() as Document | ShadowRoot)
.getElementById(this.trigger);
Expand Down
10 changes: 5 additions & 5 deletions elements/pf-tabs/pf-tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { queryAssignedElements } from 'lit/decorators/query-assigned-elements.js
import { classMap } from 'lit/directives/class-map.js';
import { consume } from '@lit/context';

import { observed } from '@patternfly/pfe-core/decorators.js';
import { observes } from '@patternfly/pfe-core/decorators.js';
import { getRandomId } from '@patternfly/pfe-core/functions/random.js';

import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js';
Expand Down Expand Up @@ -65,10 +65,8 @@ export class PfTab extends LitElement {
@queryAssignedElements({ slot: 'icon', flatten: true })
private icons!: HTMLElement[];

@observed
@property({ reflect: true, type: Boolean }) active = false;

@observed
@property({ reflect: true, type: Boolean }) disabled = false;

@consume({ context, subscribe: true })
Expand Down Expand Up @@ -144,14 +142,16 @@ export class PfTab extends LitElement {
return this.dispatchEvent(new TabExpandEvent(this));
}

private _activeChanged(old: boolean) {
@observes('active')
protected activeChanged(old: boolean) {
this.#internals.ariaSelected = String(!!this.active);
if (this.active && !old) {
this.#activate();
}
}

private _disabledChanged() {
@observes('disabled')
protected disabledChanged() {
this.#internals.ariaDisabled = this.disabled ? 'true' : this.ariaDisabled ?? 'false';
}
}
Expand Down

0 comments on commit 88b059e

Please sign in to comment.