mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-15 15:22:28 +03:00
finish up angular component and improve vue docs
This commit is contained in:
@@ -10,8 +10,8 @@ import {
|
||||
AfterViewInit,
|
||||
} from '@angular/core';
|
||||
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||
import { OverlayScrollbarsDirective } from '~/overlayscrollbars.directive';
|
||||
import type { PartialOptions, EventListeners, EventListenerMap } from 'overlayscrollbars';
|
||||
import { OverlayScrollbarsDirective } from './overlayscrollbars.directive';
|
||||
|
||||
const mergeEventListeners = (emits: EventListeners, events: EventListeners) =>
|
||||
(Object.keys(emits) as (keyof EventListeners)[]).reduce<EventListeners>(
|
||||
@@ -29,17 +29,12 @@ const mergeEventListeners = (emits: EventListeners, events: EventListeners) =>
|
||||
);
|
||||
|
||||
@Component({
|
||||
selector: '[overlay-scrollbars-component]', // https://angular.io/guide/styleguide#component-selectors
|
||||
exportAs: 'overlayScrollbars',
|
||||
selector: 'overlay-scrollbars, [overlay-scrollbars]', // https://angular.io/guide/styleguide#component-selectors
|
||||
host: { 'data-overlayscrollbars': '' },
|
||||
template: `<div
|
||||
#content
|
||||
[overlayScrollbarsDirective]
|
||||
[options]="options"
|
||||
[events]="mergeEvents(events)"
|
||||
>
|
||||
template: `<div overlayScrollbars [options]="options" [events]="mergeEvents(events)" #content>
|
||||
<ng-content></ng-content>
|
||||
</div>`,
|
||||
styles: [':host { display: block; }'],
|
||||
})
|
||||
export class OverlayScrollbarsComponent implements OnDestroy, AfterViewInit {
|
||||
@Input('options')
|
||||
@@ -91,7 +86,7 @@ export class OverlayScrollbarsComponent implements OnDestroy, AfterViewInit {
|
||||
this.osDirective?.instance()!.destroy();
|
||||
}
|
||||
|
||||
private mergeEvents(originalEvents: OverlayScrollbarsComponent['events']) {
|
||||
mergeEvents(originalEvents: OverlayScrollbarsComponent['events']) {
|
||||
return mergeEventListeners(
|
||||
{
|
||||
initialized: (...args) => this.onInitialized.emit(args),
|
||||
|
||||
@@ -5,8 +5,7 @@ import type { InitializationTarget } from 'overlayscrollbars';
|
||||
import type { OverlayScrollbarsComponent } from '~/overlayscrollbars.component';
|
||||
|
||||
@Directive({
|
||||
selector: '[overlayScrollbarsDirective]', // https://angular.io/guide/styleguide#component-selectors
|
||||
exportAs: 'overlayScrollbars',
|
||||
selector: '[overlayScrollbars]', // https://angular.io/guide/styleguide#directive-selectors
|
||||
})
|
||||
export class OverlayScrollbarsDirective implements OnChanges {
|
||||
private instanceRef: OverlayScrollbars | null = null;
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { EventListenerMap } from 'overlayscrollbars';
|
||||
@Component({
|
||||
template: `
|
||||
<div
|
||||
[overlay-scrollbars-component]
|
||||
overlay-scrollbars
|
||||
[options]="options"
|
||||
[events]="events"
|
||||
(osInitialized)="onInitialized($event)"
|
||||
@@ -70,6 +70,19 @@ class Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<span overlay-scrollbars #span>span</span>
|
||||
<overlay-scrollbars #os>span</overlay-scrollbars>
|
||||
`,
|
||||
})
|
||||
class TestTag {
|
||||
@ViewChild('span', { read: OverlayScrollbarsComponent })
|
||||
spanRef?: OverlayScrollbarsComponent;
|
||||
@ViewChild('os', { read: OverlayScrollbarsComponent })
|
||||
osRef?: OverlayScrollbarsComponent;
|
||||
}
|
||||
|
||||
describe('OverlayscrollbarsNgxComponent', () => {
|
||||
let component: OverlayScrollbarsComponent;
|
||||
let fixture: ComponentFixture<OverlayScrollbarsComponent>;
|
||||
@@ -77,7 +90,7 @@ describe('OverlayscrollbarsNgxComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
...new OverlayscrollbarsModule(),
|
||||
declarations: [OverlayScrollbarsComponent, OverlayScrollbarsDirective, Test],
|
||||
declarations: [OverlayScrollbarsComponent, OverlayScrollbarsDirective, Test, TestTag],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(OverlayScrollbarsComponent);
|
||||
@@ -349,4 +362,25 @@ describe('OverlayscrollbarsNgxComponent', () => {
|
||||
expect(onDestroyed).toHaveBeenCalledTimes(1);
|
||||
expect(onDestroyed).toHaveBeenCalledWith([jasmine.any(Object), jasmine.any(Boolean)]);
|
||||
});
|
||||
|
||||
it('has correct tags', async () => {
|
||||
const testFixture = TestBed.createComponent(TestTag);
|
||||
const testInstance = testFixture.componentInstance;
|
||||
|
||||
testFixture.detectChanges();
|
||||
|
||||
const osRef = testInstance.osRef!;
|
||||
const spanRef = testInstance.spanRef!;
|
||||
|
||||
expect(osRef).toBeDefined();
|
||||
expect(spanRef).toBeDefined();
|
||||
|
||||
expect(OverlayScrollbars.valid(osRef.instance())).toBe(true);
|
||||
expect(OverlayScrollbars.valid(spanRef.instance())).toBe(true);
|
||||
|
||||
testFixture.destroy();
|
||||
|
||||
expect(OverlayScrollbars.valid(osRef.instance())).toBe(false);
|
||||
expect(OverlayScrollbars.valid(spanRef.instance())).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -90,6 +90,22 @@ It has three optional properties: `element`, `options` and `events`.
|
||||
/>
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
Additionally to the `events` property the `OverlayScrollbarsComponent` emits "native" Vue events. To prevent name collisions with DOM events, the events are prefixed with `os`. It doesn't matter whether you use the `events` property, the Vue events or both.
|
||||
|
||||
```jsx
|
||||
// example usage
|
||||
<template>
|
||||
<OverlayScrollbarsComponent
|
||||
@os-initialized="onInitialized"
|
||||
@os-updated="onUpdated"
|
||||
@os-destroyed="onDestroyed"
|
||||
@os-scroll="onScroll"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Ref
|
||||
|
||||
The `ref` of the `OverlayScrollbarsComponent` will give you an object with which you can access the OverlayScrollbars `instance` and the root `element` of the component.
|
||||
|
||||
@@ -8,9 +8,8 @@ import type {
|
||||
import type { PropType } from 'vue';
|
||||
import type { EventListeners, EventListenerMap } from 'overlayscrollbars';
|
||||
|
||||
type EmitName<N extends keyof EventListenerMap = keyof EventListenerMap> = `os${Capitalize<N>}`;
|
||||
type EmitEventsMap = {
|
||||
[N in keyof EventListenerMap]: EmitName<N>;
|
||||
[N in keyof EventListenerMap]: `os${Capitalize<N>}`;
|
||||
};
|
||||
|
||||
const emitEvents: EmitEventsMap = {
|
||||
@@ -27,12 +26,12 @@ const props = defineProps({
|
||||
options: { type: Object as PropType<OverlayScrollbarsComponentProps['options']> },
|
||||
events: { type: Object as PropType<OverlayScrollbarsComponentProps['events']> },
|
||||
});
|
||||
const emits = defineEmits({
|
||||
osInitialized: (...args: EventListenerMap['initialized']) => true,
|
||||
osUpdated: (...args: EventListenerMap['updated']) => true,
|
||||
osDestroyed: (...args: EventListenerMap['destroyed']) => true,
|
||||
osScroll: (...args: EventListenerMap['scroll']) => true,
|
||||
} as Record<EmitName, any>);
|
||||
const emits = defineEmits<{
|
||||
(name: 'osInitialized', ...args: EventListenerMap['initialized']): void;
|
||||
(name: 'osUpdated', ...args: EventListenerMap['updated']): void;
|
||||
(name: 'osDestroyed', ...args: EventListenerMap['destroyed']): void;
|
||||
(name: 'osScroll', ...args: EventListenerMap['scroll']): void;
|
||||
}>();
|
||||
|
||||
const elementRef = shallowRef<HTMLElement | null>(null);
|
||||
const slotRef = shallowRef<HTMLElement | null>(null);
|
||||
@@ -73,8 +72,12 @@ watch(
|
||||
).reduce<EventListeners>(<N extends keyof EventListeners>(obj: EventListeners, name: N) => {
|
||||
const eventListener = currEvents[name];
|
||||
obj[name] = [
|
||||
// @ts-ignore
|
||||
(...args: EventListenerMap[N]) => emits(emitEvents[name], ...args),
|
||||
(...args: EventListenerMap[N]) =>
|
||||
emits(
|
||||
emitEvents[name],
|
||||
// @ts-ignore
|
||||
...args
|
||||
),
|
||||
...(Array.isArray(eventListener) ? eventListener : [eventListener]).filter(Boolean),
|
||||
];
|
||||
return obj;
|
||||
|
||||
Reference in New Issue
Block a user