ngx-zoneless-scrollbar 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,172 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, signal, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
3
+
4
+ /**
5
+ * NgxZonelessScrollbar
6
+ *
7
+ * A lightweight, zoneless-compatible scrollbar component for Angular.
8
+ * Uses native browser scrolling with CSS-styled scrollbars.
9
+ *
10
+ * Features:
11
+ * - Uses native browser scrolling (100% reliable in zoneless mode)
12
+ * - CSS-styled scrollbars for modern browsers (Chrome, Firefox, Safari)
13
+ * - Detects if content is scrollable and exposes this via signals
14
+ * - Emits events after content updates
15
+ * - Touch-friendly with momentum scrolling
16
+ *
17
+ * @example
18
+ * ```html
19
+ * <ngx-zoneless-scrollbar (afterUpdate)="onScrollbarUpdated($event)">
20
+ * <div>Your scrollable content here</div>
21
+ * </ngx-zoneless-scrollbar>
22
+ * ```
23
+ */
24
+ class NgxZonelessScrollbar {
25
+ viewportRef;
26
+ contentRef;
27
+ /**
28
+ * Orientation of scrolling
29
+ * - 'vertical': Only vertical scrolling (default)
30
+ * - 'horizontal': Only horizontal scrolling
31
+ * - 'auto': Both directions as needed
32
+ */
33
+ orientation = input('vertical');
34
+ /**
35
+ * Emits after the scrollbar state is updated with scrollability info
36
+ */
37
+ afterUpdate = output();
38
+ /**
39
+ * Signal indicating if content is vertically scrollable
40
+ */
41
+ isVerticallyScrollable = signal(false);
42
+ /**
43
+ * Signal indicating if content is horizontally scrollable
44
+ */
45
+ isHorizontallyScrollable = signal(false);
46
+ resizeObserver = null;
47
+ ngAfterViewInit() {
48
+ // Initial check after view is ready
49
+ this.checkScrollability();
50
+ // Set up ResizeObserver to detect content changes
51
+ if (typeof ResizeObserver !== 'undefined') {
52
+ this.resizeObserver = new ResizeObserver(() => {
53
+ this.checkScrollability();
54
+ });
55
+ // Observe both viewport and content for size changes
56
+ this.resizeObserver.observe(this.viewportRef.nativeElement);
57
+ this.resizeObserver.observe(this.contentRef.nativeElement);
58
+ }
59
+ }
60
+ ngOnDestroy() {
61
+ this.resizeObserver?.disconnect();
62
+ }
63
+ /**
64
+ * Check if content is scrollable and emit update event
65
+ */
66
+ checkScrollability() {
67
+ const viewport = this.viewportRef?.nativeElement;
68
+ const content = this.contentRef?.nativeElement;
69
+ if (!viewport || !content)
70
+ return;
71
+ const isVertical = content.scrollHeight > viewport.clientHeight;
72
+ const isHorizontal = content.scrollWidth > viewport.clientWidth;
73
+ // Only update and emit if values changed
74
+ const prevVertical = this.isVerticallyScrollable();
75
+ const prevHorizontal = this.isHorizontallyScrollable();
76
+ if (isVertical !== prevVertical || isHorizontal !== prevHorizontal) {
77
+ this.isVerticallyScrollable.set(isVertical);
78
+ this.isHorizontallyScrollable.set(isHorizontal);
79
+ this.afterUpdate.emit({
80
+ isVerticallyScrollable: isVertical,
81
+ isHorizontallyScrollable: isHorizontal
82
+ });
83
+ }
84
+ }
85
+ /**
86
+ * Scroll to a specific position
87
+ * @param options - ScrollToOptions with top, left, and behavior
88
+ * @returns Promise that resolves when scroll is complete
89
+ */
90
+ scrollTo(options) {
91
+ return new Promise((resolve) => {
92
+ this.viewportRef?.nativeElement?.scrollTo({
93
+ top: options.top ?? 0,
94
+ left: options.left ?? 0,
95
+ behavior: options.behavior ?? 'smooth'
96
+ });
97
+ // Resolve after a short delay for smooth scroll
98
+ setTimeout(resolve, options.behavior === 'instant' ? 0 : 300);
99
+ });
100
+ }
101
+ /**
102
+ * Manually trigger an update check
103
+ */
104
+ update() {
105
+ this.checkScrollability();
106
+ }
107
+ /**
108
+ * Get the viewport element for direct access if needed
109
+ */
110
+ get viewportElement() {
111
+ return this.viewportRef?.nativeElement ?? null;
112
+ }
113
+ /**
114
+ * Get the current scroll position
115
+ */
116
+ get scrollTop() {
117
+ return this.viewportRef?.nativeElement?.scrollTop ?? 0;
118
+ }
119
+ /**
120
+ * Get the current horizontal scroll position
121
+ */
122
+ get scrollLeft() {
123
+ return this.viewportRef?.nativeElement?.scrollLeft ?? 0;
124
+ }
125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: NgxZonelessScrollbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
126
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.18", type: NgxZonelessScrollbar, isStandalone: true, selector: "ngx-zoneless-scrollbar", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { afterUpdate: "afterUpdate" }, host: { properties: { "attr.orientation": "orientation()" } }, viewQueries: [{ propertyName: "viewportRef", first: true, predicate: ["viewport"], descendants: true }, { propertyName: "contentRef", first: true, predicate: ["content"], descendants: true }], ngImport: i0, template: `
127
+ <div
128
+ #viewport
129
+ class="ngx-zoneless-scrollbar-viewport"
130
+ [class.vertical-scrollable]="isVerticallyScrollable()"
131
+ [class.horizontal-scrollable]="isHorizontallyScrollable()"
132
+ >
133
+ <div #content class="ngx-zoneless-scrollbar-content">
134
+ <ng-content></ng-content>
135
+ </div>
136
+ </div>
137
+ `, isInline: true, styles: [":host{display:block;height:100%;width:100%;position:relative;--scrollbar-size: 7px;--scrollbar-track-color: transparent;--scrollbar-track-radius: 4px;--scrollbar-thumb-color: rgba(0, 0, 0, .3);--scrollbar-thumb-color-hover: rgba(0, 0, 0, .5);--scrollbar-thumb-radius: 4px}.ngx-zoneless-scrollbar-viewport{height:100%;width:100%;overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;&::-webkit-scrollbar{width:var(--scrollbar-size);height:var(--scrollbar-size)}&::-webkit-scrollbar-track{background:var(--scrollbar-track-color);border-radius:var(--scrollbar-track-radius)}&::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-color);border-radius:var(--scrollbar-thumb-radius);transition:background .2s ease}&::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-color-hover)}scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb-color) var(--scrollbar-track-color)}:host([orientation=\"vertical\"]) .ngx-zoneless-scrollbar-viewport{overflow-x:hidden;overflow-y:auto}:host([orientation=\"horizontal\"]) .ngx-zoneless-scrollbar-viewport{overflow-x:auto;overflow-y:hidden}.ngx-zoneless-scrollbar-content{min-height:100%;min-width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
138
+ }
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: NgxZonelessScrollbar, decorators: [{
140
+ type: Component,
141
+ args: [{ selector: 'ngx-zoneless-scrollbar', standalone: true, template: `
142
+ <div
143
+ #viewport
144
+ class="ngx-zoneless-scrollbar-viewport"
145
+ [class.vertical-scrollable]="isVerticallyScrollable()"
146
+ [class.horizontal-scrollable]="isHorizontallyScrollable()"
147
+ >
148
+ <div #content class="ngx-zoneless-scrollbar-content">
149
+ <ng-content></ng-content>
150
+ </div>
151
+ </div>
152
+ `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
153
+ '[attr.orientation]': 'orientation()'
154
+ }, styles: [":host{display:block;height:100%;width:100%;position:relative;--scrollbar-size: 7px;--scrollbar-track-color: transparent;--scrollbar-track-radius: 4px;--scrollbar-thumb-color: rgba(0, 0, 0, .3);--scrollbar-thumb-color-hover: rgba(0, 0, 0, .5);--scrollbar-thumb-radius: 4px}.ngx-zoneless-scrollbar-viewport{height:100%;width:100%;overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;&::-webkit-scrollbar{width:var(--scrollbar-size);height:var(--scrollbar-size)}&::-webkit-scrollbar-track{background:var(--scrollbar-track-color);border-radius:var(--scrollbar-track-radius)}&::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-color);border-radius:var(--scrollbar-thumb-radius);transition:background .2s ease}&::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-color-hover)}scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb-color) var(--scrollbar-track-color)}:host([orientation=\"vertical\"]) .ngx-zoneless-scrollbar-viewport{overflow-x:hidden;overflow-y:auto}:host([orientation=\"horizontal\"]) .ngx-zoneless-scrollbar-viewport{overflow-x:auto;overflow-y:hidden}.ngx-zoneless-scrollbar-content{min-height:100%;min-width:100%}\n"] }]
155
+ }], propDecorators: { viewportRef: [{
156
+ type: ViewChild,
157
+ args: ['viewport']
158
+ }], contentRef: [{
159
+ type: ViewChild,
160
+ args: ['content']
161
+ }] } });
162
+
163
+ /*
164
+ * Public API Surface of ngx-zoneless-scrollbar
165
+ */
166
+
167
+ /**
168
+ * Generated bundle index. Do not edit.
169
+ */
170
+
171
+ export { NgxZonelessScrollbar };
172
+ //# sourceMappingURL=ngx-zoneless-scrollbar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-zoneless-scrollbar.mjs","sources":["../../../projects/ngx-zoneless-scrollbar/src/lib/ngx-zoneless-scrollbar.component.ts","../../../projects/ngx-zoneless-scrollbar/src/public-api.ts","../../../projects/ngx-zoneless-scrollbar/src/ngx-zoneless-scrollbar.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n OnDestroy,\n output,\n signal,\n ViewChild,\n WritableSignal\n} from '@angular/core';\nimport { ScrollbarOrientation, ScrollbarUpdateEvent } from './ngx-zoneless-scrollbar.models';\n\n/**\n * NgxZonelessScrollbar\n *\n * A lightweight, zoneless-compatible scrollbar component for Angular.\n * Uses native browser scrolling with CSS-styled scrollbars.\n *\n * Features:\n * - Uses native browser scrolling (100% reliable in zoneless mode)\n * - CSS-styled scrollbars for modern browsers (Chrome, Firefox, Safari)\n * - Detects if content is scrollable and exposes this via signals\n * - Emits events after content updates\n * - Touch-friendly with momentum scrolling\n *\n * @example\n * ```html\n * <ngx-zoneless-scrollbar (afterUpdate)=\"onScrollbarUpdated($event)\">\n * <div>Your scrollable content here</div>\n * </ngx-zoneless-scrollbar>\n * ```\n */\n@Component({\n selector: 'ngx-zoneless-scrollbar',\n standalone: true,\n template: `\n <div\n #viewport\n class=\"ngx-zoneless-scrollbar-viewport\"\n [class.vertical-scrollable]=\"isVerticallyScrollable()\"\n [class.horizontal-scrollable]=\"isHorizontallyScrollable()\"\n >\n <div #content class=\"ngx-zoneless-scrollbar-content\">\n <ng-content></ng-content>\n </div>\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n height: 100%;\n width: 100%;\n position: relative;\n\n /* CSS Custom Properties for easy customization */\n --scrollbar-size: 7px;\n --scrollbar-track-color: transparent;\n --scrollbar-track-radius: 4px;\n --scrollbar-thumb-color: rgba(0, 0, 0, 0.3);\n --scrollbar-thumb-color-hover: rgba(0, 0, 0, 0.5);\n --scrollbar-thumb-radius: 4px;\n }\n\n .ngx-zoneless-scrollbar-viewport {\n height: 100%;\n width: 100%;\n overflow: auto;\n -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */\n overscroll-behavior: contain; /* Prevent scroll chaining */\n\n /* Custom scrollbar styling for webkit browsers (Chrome, Safari, Edge) */\n &::-webkit-scrollbar {\n width: var(--scrollbar-size);\n height: var(--scrollbar-size);\n }\n\n &::-webkit-scrollbar-track {\n background: var(--scrollbar-track-color);\n border-radius: var(--scrollbar-track-radius);\n }\n\n &::-webkit-scrollbar-thumb {\n background: var(--scrollbar-thumb-color);\n border-radius: var(--scrollbar-thumb-radius);\n transition: background 0.2s ease;\n }\n\n &::-webkit-scrollbar-thumb:hover {\n background: var(--scrollbar-thumb-color-hover);\n }\n\n /* Firefox scrollbar styling */\n scrollbar-width: thin;\n scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-track-color);\n }\n\n /* Orientation-specific overflow behavior */\n :host([orientation='vertical']) .ngx-zoneless-scrollbar-viewport {\n overflow-x: hidden;\n overflow-y: auto;\n }\n\n :host([orientation='horizontal']) .ngx-zoneless-scrollbar-viewport {\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n .ngx-zoneless-scrollbar-content {\n min-height: 100%;\n min-width: 100%;\n }\n `\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.orientation]': 'orientation()'\n }\n})\nexport class NgxZonelessScrollbar implements AfterViewInit, OnDestroy {\n @ViewChild('viewport') viewportRef!: ElementRef<HTMLElement>;\n @ViewChild('content') contentRef!: ElementRef<HTMLElement>;\n\n /**\n * Orientation of scrolling\n * - 'vertical': Only vertical scrolling (default)\n * - 'horizontal': Only horizontal scrolling\n * - 'auto': Both directions as needed\n */\n readonly orientation = input<ScrollbarOrientation>('vertical');\n\n /**\n * Emits after the scrollbar state is updated with scrollability info\n */\n readonly afterUpdate = output<ScrollbarUpdateEvent>();\n\n /**\n * Signal indicating if content is vertically scrollable\n */\n readonly isVerticallyScrollable: WritableSignal<boolean> = signal(false);\n\n /**\n * Signal indicating if content is horizontally scrollable\n */\n readonly isHorizontallyScrollable: WritableSignal<boolean> = signal(false);\n\n private resizeObserver: ResizeObserver | null = null;\n\n ngAfterViewInit(): void {\n // Initial check after view is ready\n this.checkScrollability();\n\n // Set up ResizeObserver to detect content changes\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => {\n this.checkScrollability();\n });\n\n // Observe both viewport and content for size changes\n this.resizeObserver.observe(this.viewportRef.nativeElement);\n this.resizeObserver.observe(this.contentRef.nativeElement);\n }\n }\n\n ngOnDestroy(): void {\n this.resizeObserver?.disconnect();\n }\n\n /**\n * Check if content is scrollable and emit update event\n */\n private checkScrollability(): void {\n const viewport = this.viewportRef?.nativeElement;\n const content = this.contentRef?.nativeElement;\n\n if (!viewport || !content) return;\n\n const isVertical = content.scrollHeight > viewport.clientHeight;\n const isHorizontal = content.scrollWidth > viewport.clientWidth;\n\n // Only update and emit if values changed\n const prevVertical = this.isVerticallyScrollable();\n const prevHorizontal = this.isHorizontallyScrollable();\n\n if (isVertical !== prevVertical || isHorizontal !== prevHorizontal) {\n this.isVerticallyScrollable.set(isVertical);\n this.isHorizontallyScrollable.set(isHorizontal);\n\n this.afterUpdate.emit({\n isVerticallyScrollable: isVertical,\n isHorizontallyScrollable: isHorizontal\n });\n }\n }\n\n /**\n * Scroll to a specific position\n * @param options - ScrollToOptions with top, left, and behavior\n * @returns Promise that resolves when scroll is complete\n */\n scrollTo(options: ScrollToOptions): Promise<void> {\n return new Promise((resolve) => {\n this.viewportRef?.nativeElement?.scrollTo({\n top: options.top ?? 0,\n left: options.left ?? 0,\n behavior: options.behavior ?? 'smooth'\n });\n // Resolve after a short delay for smooth scroll\n setTimeout(resolve, options.behavior === 'instant' ? 0 : 300);\n });\n }\n\n /**\n * Manually trigger an update check\n */\n update(): void {\n this.checkScrollability();\n }\n\n /**\n * Get the viewport element for direct access if needed\n */\n get viewportElement(): HTMLElement | null {\n return this.viewportRef?.nativeElement ?? null;\n }\n\n /**\n * Get the current scroll position\n */\n get scrollTop(): number {\n return this.viewportRef?.nativeElement?.scrollTop ?? 0;\n }\n\n /**\n * Get the current horizontal scroll position\n */\n get scrollLeft(): number {\n return this.viewportRef?.nativeElement?.scrollLeft ?? 0;\n }\n}\n","/*\n * Public API Surface of ngx-zoneless-scrollbar\n */\n\nexport * from './lib/ngx-zoneless-scrollbar.component';\nexport * from './lib/ngx-zoneless-scrollbar.models';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="ngx-zoneless-scrollbar" />
5
+ export * from './public-api';
@@ -0,0 +1,77 @@
1
+ import { AfterViewInit, ElementRef, OnDestroy, WritableSignal } from '@angular/core';
2
+ import { ScrollbarOrientation, ScrollbarUpdateEvent } from './ngx-zoneless-scrollbar.models';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * NgxZonelessScrollbar
6
+ *
7
+ * A lightweight, zoneless-compatible scrollbar component for Angular.
8
+ * Uses native browser scrolling with CSS-styled scrollbars.
9
+ *
10
+ * Features:
11
+ * - Uses native browser scrolling (100% reliable in zoneless mode)
12
+ * - CSS-styled scrollbars for modern browsers (Chrome, Firefox, Safari)
13
+ * - Detects if content is scrollable and exposes this via signals
14
+ * - Emits events after content updates
15
+ * - Touch-friendly with momentum scrolling
16
+ *
17
+ * @example
18
+ * ```html
19
+ * <ngx-zoneless-scrollbar (afterUpdate)="onScrollbarUpdated($event)">
20
+ * <div>Your scrollable content here</div>
21
+ * </ngx-zoneless-scrollbar>
22
+ * ```
23
+ */
24
+ export declare class NgxZonelessScrollbar implements AfterViewInit, OnDestroy {
25
+ viewportRef: ElementRef<HTMLElement>;
26
+ contentRef: ElementRef<HTMLElement>;
27
+ /**
28
+ * Orientation of scrolling
29
+ * - 'vertical': Only vertical scrolling (default)
30
+ * - 'horizontal': Only horizontal scrolling
31
+ * - 'auto': Both directions as needed
32
+ */
33
+ readonly orientation: import("@angular/core").InputSignal<ScrollbarOrientation>;
34
+ /**
35
+ * Emits after the scrollbar state is updated with scrollability info
36
+ */
37
+ readonly afterUpdate: import("@angular/core").OutputEmitterRef<ScrollbarUpdateEvent>;
38
+ /**
39
+ * Signal indicating if content is vertically scrollable
40
+ */
41
+ readonly isVerticallyScrollable: WritableSignal<boolean>;
42
+ /**
43
+ * Signal indicating if content is horizontally scrollable
44
+ */
45
+ readonly isHorizontallyScrollable: WritableSignal<boolean>;
46
+ private resizeObserver;
47
+ ngAfterViewInit(): void;
48
+ ngOnDestroy(): void;
49
+ /**
50
+ * Check if content is scrollable and emit update event
51
+ */
52
+ private checkScrollability;
53
+ /**
54
+ * Scroll to a specific position
55
+ * @param options - ScrollToOptions with top, left, and behavior
56
+ * @returns Promise that resolves when scroll is complete
57
+ */
58
+ scrollTo(options: ScrollToOptions): Promise<void>;
59
+ /**
60
+ * Manually trigger an update check
61
+ */
62
+ update(): void;
63
+ /**
64
+ * Get the viewport element for direct access if needed
65
+ */
66
+ get viewportElement(): HTMLElement | null;
67
+ /**
68
+ * Get the current scroll position
69
+ */
70
+ get scrollTop(): number;
71
+ /**
72
+ * Get the current horizontal scroll position
73
+ */
74
+ get scrollLeft(): number;
75
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgxZonelessScrollbar, never>;
76
+ static ɵcmp: i0.ɵɵComponentDeclaration<NgxZonelessScrollbar, "ngx-zoneless-scrollbar", never, { "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; }, { "afterUpdate": "afterUpdate"; }, never, ["*"], true, never>;
77
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Event emitted when scrollbar state is updated
3
+ */
4
+ export interface ScrollbarUpdateEvent {
5
+ /** Whether content is vertically scrollable */
6
+ isVerticallyScrollable: boolean;
7
+ /** Whether content is horizontally scrollable */
8
+ isHorizontallyScrollable: boolean;
9
+ }
10
+ /**
11
+ * Orientation options for the scrollbar
12
+ */
13
+ export type ScrollbarOrientation = 'vertical' | 'horizontal' | 'auto';
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "ngx-zoneless-scrollbar",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight, zoneless-compatible scrollbar component for Angular. Uses native browser scrolling with CSS-styled scrollbars, designed for Angular's zoneless change detection mode.",
5
+ "keywords": [
6
+ "angular",
7
+ "scrollbar",
8
+ "zoneless",
9
+ "native-scrollbar",
10
+ "custom-scrollbar",
11
+ "angular-scrollbar",
12
+ "ngx-scrollbar",
13
+ "signals",
14
+ "standalone",
15
+ "css-scrollbar",
16
+ "resize-observer"
17
+ ],
18
+ "author": "Legalfina",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/Legalfina/ngx-zoneless-scrollbar"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Legalfina/ngx-zoneless-scrollbar/issues"
26
+ },
27
+ "homepage": "https://github.com/Legalfina/ngx-zoneless-scrollbar#readme",
28
+ "peerDependencies": {
29
+ "@angular/common": ">=19.0.0",
30
+ "@angular/core": ">=19.0.0"
31
+ },
32
+ "dependencies": {
33
+ "tslib": "^2.3.0"
34
+ },
35
+ "sideEffects": false,
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "module": "fesm2022/ngx-zoneless-scrollbar.mjs",
40
+ "typings": "index.d.ts",
41
+ "exports": {
42
+ "./package.json": {
43
+ "default": "./package.json"
44
+ },
45
+ ".": {
46
+ "types": "./index.d.ts",
47
+ "default": "./fesm2022/ngx-zoneless-scrollbar.mjs"
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,2 @@
1
+ export * from './lib/ngx-zoneless-scrollbar.component';
2
+ export * from './lib/ngx-zoneless-scrollbar.models';