Skip to content

Commit

Permalink
Merge branch 'main' into tech/port-share
Browse files Browse the repository at this point in the history
  • Loading branch information
ala-n authored Apr 10, 2024
2 parents fa87258 + 073fec3 commit 7079f7b
Show file tree
Hide file tree
Showing 30 changed files with 613 additions and 286 deletions.
1 change: 1 addition & 0 deletions .commitlintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ rules:
- esl-trigger
- esl-utils
- site
- patch
- deps
- deps-dev
- lint
Expand Down
2 changes: 1 addition & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extends:
- 'eslint:recommended'
- 'plugin:import/typescript'
- 'plugin:@typescript-eslint/recommended'
- 'plugin:@exadel/esl/default-4'
- 'plugin:@exadel/esl/default'

# Library base set
- './linting/codestyle.eslintrc.yml'
Expand Down
32 changes: 9 additions & 23 deletions eslint/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
import deprecatedAlertActionParams from './rules/4/deprecated.alert-action-params';
import deprecatedGenerateUid from './rules/4/deprecated.generate-uid';
import deprecatedDeepCompare from './rules/4/deprecated.deep-compare';
import deprecatedEventUtils from './rules/4/deprecated.event-utils';
import deprecatedPanelActionParams from './rules/4/deprecated.panel-action-params';
import deprecatedPopupActionParams from './rules/4/deprecated.popup-action-params';
import deprecatedTraversingQuery from './rules/4/deprecated.traversing-query';
import deprecatedToggleableActionParams from './rules/4/deprecated.toggleable-action-params';
import deprecatedTooltipActionParams from './rules/4/deprecated.tooltip-action-params';
import DEPRECATED_4_RULES from './rules/4/all.rules';
import DEPRECATED_5_RULES from './rules/5/all.rules';

import type {Rule} from 'eslint';

export type logLevel = 'warn' | 'error';

const DEPRECATED_4_RULES = {
'deprecated-4/alert-action-params': deprecatedAlertActionParams,
'deprecated-4/generate-uid': deprecatedGenerateUid,
'deprecated-4/deep-compare': deprecatedDeepCompare,
'deprecated-4/event-utils': deprecatedEventUtils,
'deprecated-4/panel-action-params': deprecatedPanelActionParams,
'deprecated-4/popup-action-params': deprecatedPopupActionParams,
'deprecated-4/traversing-query': deprecatedTraversingQuery,
'deprecated-4/toggleable-action-params': deprecatedToggleableActionParams,
'deprecated-4/tooltip-action-params': deprecatedTooltipActionParams
};

const buildDefault = (definition: Record<string, Rule.RuleModule>, level: logLevel): Record<string, logLevel> => {
const config: Record<string, logLevel> = {};
for (const name of Object.keys(definition)) {
Expand All @@ -33,7 +14,7 @@ const buildDefault = (definition: Record<string, Rule.RuleModule>, level: logLev
return config;
};

export const rules = Object.assign({}, DEPRECATED_4_RULES);
export const rules = Object.assign({}, DEPRECATED_4_RULES, DEPRECATED_5_RULES);

export const configs = {
'default-4': {
Expand All @@ -43,7 +24,12 @@ export const configs = {
},
'default-5': {
rules: {
...buildDefault(DEPRECATED_4_RULES, 'error')
...buildDefault(DEPRECATED_5_RULES, 'warn')
}
},
'default': {
rules: {
...buildDefault(DEPRECATED_5_RULES, 'warn')
}
}
};
13 changes: 13 additions & 0 deletions eslint/src/rules/4/all.rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import deprecatedGenerateUid from './deprecated.generate-uid';
import deprecatedDeepCompare from './deprecated.deep-compare';
import deprecatedEventUtils from './deprecated.event-utils';
import deprecatedTraversingQuery from './deprecated.traversing-query';
import deprecatedToggleableActionParams from './deprecated.toggleable-action-params';

export default {
'deprecated-4/generate-uid': deprecatedGenerateUid,
'deprecated-4/deep-compare': deprecatedDeepCompare,
'deprecated-4/event-utils': deprecatedEventUtils,
'deprecated-4/traversing-query': deprecatedTraversingQuery,
'deprecated-4/toggleable-action-params': deprecatedToggleableActionParams
};
11 changes: 11 additions & 0 deletions eslint/src/rules/5/all.rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import deprecatedAlertActionParams from './deprecated.alert-action-params';
import deprecatedPanelActionParams from './deprecated.panel-action-params';
import deprecatedPopupActionParams from './deprecated.popup-action-params';
import deprecatedTooltipActionParams from './deprecated.tooltip-action-params';

export default {
'deprecated-5/alert-action-params': deprecatedAlertActionParams,
'deprecated-5/panel-action-params': deprecatedPanelActionParams,
'deprecated-5/popup-action-params': deprecatedPopupActionParams,
'deprecated-5/tooltip-action-params': deprecatedTooltipActionParams
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"scope": "@exadel"
},
"files": [
"modules/**/*",
"polyfills/**/*",
"modules/**/*.{js,ts,less,css,md}",
"polyfills/**/*.{js,ts,less,css,md}",
"tsconfig.json",
"CLA.md"
],
Expand Down
2 changes: 1 addition & 1 deletion site/11ty/env.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const isDev = env === 'development' || isE2E;
const date = new Date();

const buildVersion = process.env['BUILD_VERSION'] || 'local';
const packageVersion = process.env.npm_package_version;
const packageVersion = require('@exadel/esl/package.json').version;
const version = `${packageVersion}-${buildVersion}`; // e.g. 1.0.0-123

const context = {isDev, isE2E, version, env, date, buildVersion, packageVersion};
Expand Down
8 changes: 4 additions & 4 deletions src/modules/esl-event-listener/core/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {wrap} from '../../esl-utils/misc/array';
import {isElement} from '../../esl-utils/dom/api';
import {isPassiveByDefault} from '../../esl-utils/dom/events/misc';
import {resolveProperty} from '../../esl-utils/misc/functions';
import {isObject, isSimilar} from '../../esl-utils/misc/object';
import {isObject, isObjectLike, isSimilar} from '../../esl-utils/misc/object';
import {resolveDomTarget} from '../../esl-utils/abstract/dom-target';
import {memoize} from '../../esl-utils/decorators/memoize';
import {ESLTraversingQuery} from '../../esl-traversing-query/core';
Expand Down Expand Up @@ -149,14 +149,14 @@ export class ESLEventListener implements ESLListenerDefinition, EventListenerObj
* Supports additional filtration criteria
*/
public static get(host?: object, ...criteria: ESLListenerCriteria[]): ESLEventListener[] {
if (!isObject(host)) return [];
if (!isObjectLike(host)) return [];
const listeners = ((host as any)[LISTENERS] || []) as ESLEventListener[];
if (!criteria.length) return listeners;
return listeners.filter((listener) => criteria.every(listener.matches, listener));
}
/** Adds a listener to the listener store of the host object */
protected static add(host: object, instance: ESLEventListener): void {
if (!isObject(host)) return;
if (!isObjectLike(host)) return;
if (!Object.hasOwnProperty.call(host, LISTENERS)) (host as any)[LISTENERS] = [];
(host as any)[LISTENERS].push(instance);
}
Expand Down Expand Up @@ -201,7 +201,7 @@ export class ESLEventListener implements ESLListenerDefinition, EventListenerObj
handler: ESLListenerHandler,
desc: ESLListenerDescriptor
): ESLEventListener[] {
if (!isObject(host)) return [];
if (!isObjectLike(host)) return [];
const eventString = resolveProperty(desc.event, host);
const listeners: ESLEventListener[] = [];
for (const event of splitEvents(eventString)) {
Expand Down
11 changes: 11 additions & 0 deletions src/modules/esl-event-listener/core/targets/swipe.target.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {SyntheticEventTarget} from '../../../esl-utils/dom/events/target';
import {getParentScrollOffsets, isOffsetChanged} from '../../../esl-utils/dom/scroll';
import {getTouchPoint, isMouseEvent, isTouchEvent} from '../../../esl-utils/dom/events/misc';
import {resolveDomTarget} from '../../../esl-utils/abstract/dom-target';
import {isElement} from '../../../esl-utils/dom/api';
Expand All @@ -7,6 +8,7 @@ import {resolveCSSSize} from '../../../esl-utils/dom/units';
import {ESLEventListener} from '../listener';
import {ESLSwipeGestureEvent} from './swipe.target.event';

import type {ElementScrollOffset} from '../../../esl-utils/dom//scroll';
import type {CSSSize} from '../../../esl-utils/dom/units';
import type {SwipeDirection, ESLSwipeGestureEventInfo} from './swipe.target.event';
import type {ESLDomElementTarget} from '../../../esl-utils/abstract/dom-target';
Expand All @@ -17,6 +19,8 @@ export {ESLSwipeGestureEvent};
* Describes settings object that could be passed to {@link ESLSwipeGestureTarget.for} as optional parameter
*/
export interface ESLSwipeGestureSetting {
/** Flag to indicate if the swipe event should not be dispatched if a scroll of content was detected (true by default) */
skipOnScroll?: boolean;
/** The minimum distance to accept swipe (supports `px`, `vw` and `vh` units) */
threshold?: CSSSize;
/** The maximum duration between `ponterdown` and `pointerup` events */
Expand All @@ -28,6 +32,7 @@ export interface ESLSwipeGestureSetting {
*/
export class ESLSwipeGestureTarget extends SyntheticEventTarget {
protected static defaultConfig: Required<ESLSwipeGestureSetting> = {
skipOnScroll: true,
threshold: '20px',
timeout: 500
};
Expand All @@ -49,6 +54,7 @@ export class ESLSwipeGestureTarget extends SyntheticEventTarget {
protected readonly config: Required<ESLSwipeGestureSetting>;

protected startEvent: PointerEvent;
protected startEventOffset: ElementScrollOffset[];

protected constructor(
protected readonly target: Element,
Expand All @@ -70,6 +76,7 @@ export class ESLSwipeGestureTarget extends SyntheticEventTarget {
* @param startEvent - initial pointer event
*/
protected handleStart(startEvent: PointerEvent): void {
this.startEventOffset = this.config.skipOnScroll ? getParentScrollOffsets(startEvent.target as Element, this.target) : [];
this.startEvent = startEvent;
ESLEventListener.subscribe(this, this.handleEnd, {
event: this.endEventName,
Expand Down Expand Up @@ -119,6 +126,10 @@ export class ESLSwipeGestureTarget extends SyntheticEventTarget {

// return if swipe took too long or distance is too short
if (!this.isGestureAcceptable(eventDetails)) return;
if (this.config.skipOnScroll) {
const offsets = getParentScrollOffsets(endEvent.target as Element, this.target);
if (isOffsetChanged(this.startEventOffset.concat(offsets))) return;
}

const event = ESLSwipeGestureEvent.fromConfig(this.target, eventDetails);
// fire `swipe` event on the element that started the swipe
Expand Down
15 changes: 15 additions & 0 deletions src/modules/esl-event-listener/core/targets/wheel.target.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {SyntheticEventTarget} from '../../../esl-utils/dom/events/target';
import {resolveDomTarget} from '../../../esl-utils/abstract/dom-target';
import {getParentScrollOffsets, isOffsetChanged} from '../../../esl-utils/dom/scroll';
import {isElement} from '../../../esl-utils/dom/api';
import {bind} from '../../../esl-utils/decorators/bind';
import {aggregate} from '../../../esl-utils/async/aggregate';
Expand All @@ -9,13 +10,16 @@ import {ESLWheelEvent} from './wheel.target.event';

import type {ESLWheelEventInfo} from './wheel.target.event';
import type {ESLDomElementTarget} from '../../../esl-utils/abstract/dom-target';
import type {ElementScrollOffset} from '../../../esl-utils/dom/scroll';

export {ESLWheelEvent};

/**
* Describes settings object that could be passed to {@link ESLWheelTarget.for} as optional parameter
*/
export interface ESLWheelTargetSetting {
/** Flag to indicate if the `longwheel` event shouldn't be dispatched if scroll of content was detected (true by default) */
skipOnScroll?: boolean;
/** The minimum distance to accept as a long scroll */
distance?: number;
/** The maximum duration of the wheel events to consider it inertial */
Expand All @@ -27,12 +31,15 @@ export interface ESLWheelTargetSetting {
*/
export class ESLWheelTarget extends SyntheticEventTarget {
protected static defaultConfig: Required<ESLWheelTargetSetting> = {
skipOnScroll: true,
distance: 400,
timeout: 100
};

protected readonly config: Required<ESLWheelTargetSetting>;

protected scrollData: ElementScrollOffset[] = [];

/** Function for aggregating wheel events into array of events */
protected aggregateWheel: (event: WheelEvent) => void;

Expand Down Expand Up @@ -63,12 +70,20 @@ export class ESLWheelTarget extends SyntheticEventTarget {
/** Handles wheel events */
@bind
protected _onWheel(event: WheelEvent): void {
if (this.config.skipOnScroll) {
const offsets = getParentScrollOffsets(event.target as Element, this.target);
this.scrollData = this.scrollData.concat(offsets);
}
this.aggregateWheel(event);
}

/** Handles aggregated wheel events */
protected handleAggregatedWheel(events: WheelEvent[]): void {
const wheelInfo = this.resolveEventDetails(events);

const isBlocked = isOffsetChanged(this.scrollData);
this.scrollData = [];
if (isBlocked) return;
if (Math.abs(wheelInfo.deltaX) >= this.config.distance) this.dispatchWheelEvent('x', wheelInfo);
if (Math.abs(wheelInfo.deltaY) >= this.config.distance) this.dispatchWheelEvent('y', wheelInfo);
}
Expand Down
29 changes: 29 additions & 0 deletions src/modules/esl-event-listener/test/listener.subscribe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,33 @@ describe('ESLEventUtils:subscribe tests', () => {
ESLEventUtils.subscribe(host, {event: 'click'}, handle);
expect(ESLEventUtils.listeners(host).length).toBe(0);
});

describe('ESLEventListener subscribes correctly for any object-like host', () => {
test.each([
{},
Object.create(null),
function hostFunction() {},
class HostClass {},
new (class HostClassInst {})()
])('ESLEventListener subscribes correctly for %o host', (host) => {
const handle = jest.fn();
ESLEventUtils.subscribe(host, {event: 'click', target: document.body}, handle);
expect(ESLEventUtils.listeners(host).length).toBe(1);
ESLEventUtils.unsubscribe(host);
});

test('ESLEventListener can not subscribe for primitive host', () => {
jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
const handle = jest.fn();
const count = ESLEventUtils.subscribe(1 as any, {event: 'click', target: document.body}, handle).length;
expect(count).toBe(0);
});

test('ESLEventListener can not subscribe for null host', () => {
jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
const handle = jest.fn();
const count = ESLEventUtils.subscribe(null as any, {event: 'click', target: document.body}, handle).length;
expect(count).toBe(0);
});
});
});
27 changes: 9 additions & 18 deletions src/modules/esl-share/core/esl-share.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {ExportNs} from '../../esl-utils/environment/export-ns';
import {attr, boolAttr, jsonAttr, prop, ready} from '../../esl-utils/decorators';
import {ESLTraversingQuery} from '../../esl-traversing-query/core';
import {ESLTrigger} from '../../esl-trigger/core';
import {ESLBaseTrigger} from '../../esl-trigger/core';

import {ESLSharePopup} from './esl-share-popup';

import type {ESLToggleable} from '../../esl-toggleable/core/esl-toggleable';
import type {ESLSharePopupActionParams} from './esl-share-popup';

export type {ESLShareTagShape} from './esl-share.shape';

/**
Expand All @@ -16,9 +16,9 @@ export type {ESLShareTagShape} from './esl-share.shape';
* ESLShare is a component that allows triggering {@link ESLSharePopup} instance state changes.
*/
@ExportNs('Share')
export class ESLShare extends ESLTrigger {
export class ESLShare extends ESLBaseTrigger {
public static override is = 'esl-share';
public static override observedAttributes = ['list'];
public static observedAttributes = ['list'];

/** Register {@link ESLShare} component and dependent {@link ESLSharePopup} */
public static override register(): void {
Expand Down Expand Up @@ -51,7 +51,6 @@ export class ESLShare extends ESLTrigger {
public override get $target(): ESLToggleable | null {
return ESLSharePopup.sharedInstance;
}
public override set $target(value: any) {}

/** Checks that the target is in active state */
public override get isTargetActive(): boolean {
Expand All @@ -78,7 +77,10 @@ export class ESLShare extends ESLTrigger {
@ready
protected override connectedCallback(): void {
super.connectedCallback();
this.onReady();
if (!this.ready) {
this.$$attr('ready', true);
this.$$fire(this.SHARE_READY_EVENT, {bubbles: false});
}
}

protected override attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string | null): void {
Expand All @@ -92,9 +94,6 @@ export class ESLShare extends ESLTrigger {
this.$target?.hide();
}

/** Updates `$target` Toggleable from `target` selector */
public override updateTargetFromSelector(): void {}

/** Gets attribute value from the closest element with group behavior settings */
protected getClosestRelatedAttr(attrName: string): string | null {
const relatedAttrName = `${this.baseTagName}-${attrName}`;
Expand All @@ -104,22 +103,14 @@ export class ESLShare extends ESLTrigger {

/** Merges params to pass to the toggleable */
protected override mergeToggleableParams(this: ESLShare, ...params: ESLSharePopupActionParams[]): ESLSharePopupActionParams {
return Object.assign({
return super.mergeToggleableParams({
initiator: 'share',
activator: this,
containerEl: this.$containerEl,
list: this.list,
dir: this.currentDir,
lang: this.currentLang
}, this.popupParams, ...params);
}

/** Actions on complete init and ready component */
private onReady(): void {
if (this.ready) return;
this.$$attr('ready', true);
this.$$fire(this.SHARE_READY_EVENT, {bubbles: false});
}
}

declare global {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/esl-tab/core/esl-tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {ESLTrigger} from '../../esl-trigger/core';
export class ESLTab extends ESLTrigger {
public static override is = 'esl-tab';

@attr({defaultValue: 'show'}) public override mode: string;
@attr({defaultValue: 'show'}) public override mode: 'show' | 'toggle' | 'hide';
@attr({defaultValue: 'active'}) public override activeClass: string;

public override initA11y(): void {
Expand Down
Loading

0 comments on commit 7079f7b

Please sign in to comment.