@haloduck/util 2.1.0 → 2.1.1

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,220 @@
1
+ import { Validators } from '@angular/forms';
2
+ import * as i0 from '@angular/core';
3
+ import { InjectionToken, inject, Injectable, Input, Directive } from '@angular/core';
4
+
5
+ function download(href) {
6
+ const link = document.createElement('a');
7
+ link.href = href;
8
+ link.target = '_blank';
9
+ document.body.appendChild(link);
10
+ link.click();
11
+ document.body.removeChild(link);
12
+ }
13
+
14
+ function hasRequired(control) {
15
+ return control?.hasValidator(Validators.required);
16
+ }
17
+ function hasError(control, errorType) {
18
+ return control?.touched && (control?.hasError(errorType) ?? false);
19
+ }
20
+ function getDirtyValues(fg) {
21
+ const dirtyValues = Object.keys(fg.controls)
22
+ .filter((key) => fg.controls[key].dirty)
23
+ .reduce((acc, key) => {
24
+ acc[key] = fg.controls[key].value;
25
+ return acc;
26
+ }, {});
27
+ return dirtyValues;
28
+ }
29
+ const englishAndNumberOnlyValidator = Validators.pattern(/^[0-9A-Za-z\s]*$/);
30
+ function isEqual(a, b) {
31
+ if (a === b)
32
+ return true;
33
+ if (!a || !b)
34
+ return false;
35
+ if (Array.isArray(a) && Array.isArray(b)) {
36
+ return a.length === b.length && a.every((val, i) => isEqual(val, b[i]));
37
+ }
38
+ if (typeof a === 'object' && typeof b === 'object') {
39
+ const keysA = Object.keys(a);
40
+ const keysB = Object.keys(b);
41
+ return keysA.length === keysB.length && keysA.every((key) => isEqual(a[key], b[key]));
42
+ }
43
+ return false;
44
+ }
45
+
46
+ const FILE_ICON_SET = new InjectionToken('FILE_ICON_SET', {
47
+ providedIn: 'root',
48
+ factory: () => ({
49
+ pdf: 'assets/pdf.svg',
50
+ stl: 'assets/stl.svg',
51
+ default: 'assets/default.svg',
52
+ }),
53
+ });
54
+ function provideHaloduckUtilIconSet(iconSet) {
55
+ return {
56
+ provide: FILE_ICON_SET,
57
+ useValue: iconSet,
58
+ };
59
+ }
60
+ class UtilService {
61
+ // private readonly environmentInjector = inject(EnvironmentInjector);
62
+ iconSet = inject(FILE_ICON_SET);
63
+ getFileIconUrl(filename) {
64
+ const extension = filename.split('.').pop()?.toLowerCase();
65
+ return this.iconSet[extension || ''] || this.iconSet['default'];
66
+ }
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: UtilService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
68
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: UtilService, providedIn: 'root' });
69
+ }
70
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: UtilService, decorators: [{
71
+ type: Injectable,
72
+ args: [{
73
+ providedIn: 'root',
74
+ }]
75
+ }] });
76
+
77
+ /**
78
+ * Shrinks the font-size so the text fits within the element's width.
79
+ * - Only scales down; never scales up beyond the computed font size
80
+ * - Observes element resize and text mutations
81
+ */
82
+ class FitTextDirective {
83
+ elRef;
84
+ zone;
85
+ hddFitTextMinPx = 6; // reasonable minimum for small cards
86
+ hddFitTextMaxPx; // if provided, caps the max font size
87
+ host;
88
+ resizeObserver;
89
+ mutationObserver;
90
+ destroyed = false;
91
+ removeWindowResizeListener;
92
+ rafId = null;
93
+ scheduled = false;
94
+ handleWindowResize = () => this.scheduleFit();
95
+ constructor(elRef, zone) {
96
+ this.elRef = elRef;
97
+ this.zone = zone;
98
+ this.host = elRef.nativeElement;
99
+ }
100
+ ngAfterViewInit() {
101
+ // Avoid layout thrash during Angular change detection
102
+ this.zone.runOutsideAngular(() => {
103
+ // Ensure single line to match width-fit semantics
104
+ this.host.style.whiteSpace = this.host.style.whiteSpace || 'nowrap';
105
+ // Trigger initial fit after current microtask
106
+ setTimeout(() => this.scheduleFit(), 0);
107
+ // Observe element size changes
108
+ if (typeof ResizeObserver !== 'undefined') {
109
+ this.resizeObserver = new ResizeObserver(() => this.scheduleFit());
110
+ this.resizeObserver.observe(this.host);
111
+ }
112
+ else if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
113
+ window.addEventListener('resize', this.handleWindowResize);
114
+ this.removeWindowResizeListener = () => window.removeEventListener('resize', this.handleWindowResize);
115
+ }
116
+ // Observe text/content changes
117
+ this.mutationObserver = new MutationObserver(() => this.scheduleFit());
118
+ this.mutationObserver.observe(this.host, {
119
+ childList: true,
120
+ characterData: true,
121
+ subtree: true,
122
+ });
123
+ });
124
+ }
125
+ ngOnDestroy() {
126
+ this.destroyed = true;
127
+ if (this.resizeObserver) {
128
+ this.resizeObserver.disconnect();
129
+ }
130
+ this.removeWindowResizeListener?.();
131
+ this.mutationObserver?.disconnect();
132
+ if (this.rafId !== null) {
133
+ cancelAnimationFrame(this.rafId);
134
+ this.rafId = null;
135
+ }
136
+ }
137
+ scheduleFit = () => {
138
+ if (this.destroyed || this.scheduled)
139
+ return;
140
+ this.scheduled = true;
141
+ const raf = typeof requestAnimationFrame === 'function'
142
+ ? requestAnimationFrame
143
+ : (cb) => setTimeout(() => cb(performance.now()), 16);
144
+ this.rafId = raf(() => {
145
+ this.rafId = null;
146
+ this.scheduled = false;
147
+ this.fit();
148
+ });
149
+ };
150
+ fit = () => {
151
+ if (this.destroyed)
152
+ return;
153
+ const element = this.host;
154
+ const availableWidth = element.clientWidth;
155
+ if (!availableWidth)
156
+ return;
157
+ const computed = window.getComputedStyle(element);
158
+ const originalFontSizePx = this.parsePx(computed.fontSize) || 16;
159
+ const maxPx = this.hddFitTextMaxPx
160
+ ? Math.min(this.hddFitTextMaxPx, originalFontSizePx)
161
+ : originalFontSizePx;
162
+ let low = this.hddFitTextMinPx;
163
+ let high = Math.max(low, Math.floor(maxPx));
164
+ // Quick accept if it already fits
165
+ element.style.fontSize = `${high}px`;
166
+ if (this.scrollsWithin(element, availableWidth)) {
167
+ return;
168
+ }
169
+ // Binary search for the largest font-size that fits
170
+ while (low < high) {
171
+ const mid = Math.floor((low + high) / 2);
172
+ element.style.fontSize = `${mid}px`;
173
+ if (this.scrollsWithin(element, availableWidth)) {
174
+ low = mid + 1; // try bigger
175
+ }
176
+ else {
177
+ high = mid - 1; // too big
178
+ }
179
+ }
180
+ // After loop, test final candidates
181
+ for (let size = Math.min(high, maxPx); size >= this.hddFitTextMinPx; size--) {
182
+ element.style.fontSize = `${size}px`;
183
+ if (this.scrollsWithin(element, availableWidth)) {
184
+ break;
185
+ }
186
+ }
187
+ };
188
+ scrollsWithin(element, availableWidth) {
189
+ // Add a small epsilon for sub-pixel rounding
190
+ return element.scrollWidth <= Math.ceil(availableWidth + 0.5);
191
+ }
192
+ parsePx(value) {
193
+ const num = Number(String(value || '').replace('px', ''));
194
+ return isFinite(num) ? num : 0;
195
+ }
196
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FitTextDirective, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
197
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.4", type: FitTextDirective, isStandalone: true, selector: "[haloduckFitText]", inputs: { hddFitTextMinPx: "hddFitTextMinPx", hddFitTextMaxPx: "hddFitTextMaxPx" }, ngImport: i0 });
198
+ }
199
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FitTextDirective, decorators: [{
200
+ type: Directive,
201
+ args: [{
202
+ selector: '[haloduckFitText]',
203
+ standalone: true,
204
+ }]
205
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { hddFitTextMinPx: [{
206
+ type: Input
207
+ }], hddFitTextMaxPx: [{
208
+ type: Input
209
+ }] } });
210
+
211
+ /*
212
+ * Public API Surface of util
213
+ */
214
+
215
+ /**
216
+ * Generated bundle index. Do not edit.
217
+ */
218
+
219
+ export { FILE_ICON_SET, FitTextDirective, UtilService, download, englishAndNumberOnlyValidator, getDirtyValues, hasError, hasRequired, isEqual, provideHaloduckUtilIconSet };
220
+ //# sourceMappingURL=haloduck-util.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"haloduck-util.mjs","sources":["../../../../projects/haloduck/util/src/lib/function/util.file.ts","../../../../projects/haloduck/util/src/lib/function/util.form.ts","../../../../projects/haloduck/util/src/lib/service/util.service.ts","../../../../projects/haloduck/util/src/lib/directive/fit-text.directive.ts","../../../../projects/haloduck/util/src/public-api.ts","../../../../projects/haloduck/util/src/haloduck-util.ts"],"sourcesContent":["export function download(href: string) {\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n}\n","import { AbstractControl, Validators, FormGroup } from '@angular/forms';\n\nexport function hasRequired(control: AbstractControl<any, any> | null) {\n return control?.hasValidator(Validators.required);\n}\n\nexport function hasError(\n control: AbstractControl<any, any> | null,\n errorType: string,\n): boolean | undefined {\n return control?.touched && (control?.hasError(errorType) ?? false);\n}\n\nexport function getDirtyValues(fg: FormGroup) {\n const dirtyValues = Object.keys(fg.controls)\n .filter((key) => fg.controls[key].dirty)\n .reduce((acc: { [key: string]: any }, key) => {\n acc[key] = fg.controls[key].value;\n return acc;\n }, {});\n\n return dirtyValues;\n}\n\nexport const englishAndNumberOnlyValidator = Validators.pattern(/^[0-9A-Za-z\\s]*$/);\n\nexport function isEqual(a: any, b: any): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((val, i) => isEqual(val, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n return keysA.length === keysB.length && keysA.every((key) => isEqual(a[key], b[key]));\n }\n return false;\n}\n","import { Injectable, inject, InjectionToken, Provider, EnvironmentInjector } from '@angular/core';\n\nexport const FILE_ICON_SET = new InjectionToken<Record<string, string>>('FILE_ICON_SET', {\n providedIn: 'root',\n factory: () => ({\n pdf: 'assets/pdf.svg',\n stl: 'assets/stl.svg',\n default: 'assets/default.svg',\n }),\n});\n\nexport function provideHaloduckUtilIconSet(iconSet: Record<string, string>): Provider {\n return {\n provide: FILE_ICON_SET,\n useValue: iconSet,\n };\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class UtilService {\n // private readonly environmentInjector = inject(EnvironmentInjector);\n iconSet = inject(FILE_ICON_SET);\n\n getFileIconUrl(filename: string): string {\n const extension = filename.split('.').pop()?.toLowerCase();\n return this.iconSet[extension || ''] || this.iconSet['default'];\n }\n}\n","import { AfterViewInit, Directive, ElementRef, Input, NgZone, OnDestroy } from '@angular/core';\n\n/**\n * Shrinks the font-size so the text fits within the element's width.\n * - Only scales down; never scales up beyond the computed font size\n * - Observes element resize and text mutations\n */\n@Directive({\n selector: '[haloduckFitText]',\n standalone: true,\n})\nexport class FitTextDirective implements AfterViewInit, OnDestroy {\n @Input() hddFitTextMinPx = 6; // reasonable minimum for small cards\n @Input() hddFitTextMaxPx?: number; // if provided, caps the max font size\n\n private readonly host: HTMLElement;\n private resizeObserver?: ResizeObserver;\n private mutationObserver?: MutationObserver;\n private destroyed = false;\n private removeWindowResizeListener?: () => void;\n private rafId: number | null = null;\n private scheduled = false;\n private readonly handleWindowResize = () => this.scheduleFit();\n\n constructor(\n private readonly elRef: ElementRef<HTMLElement>,\n private readonly zone: NgZone,\n ) {\n this.host = elRef.nativeElement;\n }\n\n ngAfterViewInit(): void {\n // Avoid layout thrash during Angular change detection\n this.zone.runOutsideAngular(() => {\n // Ensure single line to match width-fit semantics\n this.host.style.whiteSpace = this.host.style.whiteSpace || 'nowrap';\n // Trigger initial fit after current microtask\n setTimeout(() => this.scheduleFit(), 0);\n\n // Observe element size changes\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => this.scheduleFit());\n this.resizeObserver.observe(this.host);\n } else if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {\n window.addEventListener('resize', this.handleWindowResize);\n this.removeWindowResizeListener = () =>\n window.removeEventListener('resize', this.handleWindowResize);\n }\n\n // Observe text/content changes\n this.mutationObserver = new MutationObserver(() => this.scheduleFit());\n this.mutationObserver.observe(this.host, {\n childList: true,\n characterData: true,\n subtree: true,\n });\n });\n }\n\n ngOnDestroy(): void {\n this.destroyed = true;\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n }\n this.removeWindowResizeListener?.();\n this.mutationObserver?.disconnect();\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n private scheduleFit = (): void => {\n if (this.destroyed || this.scheduled) return;\n this.scheduled = true;\n const raf =\n typeof requestAnimationFrame === 'function'\n ? requestAnimationFrame\n : (cb: FrameRequestCallback) =>\n setTimeout(() => cb(performance.now()), 16) as unknown as number;\n this.rafId = raf(() => {\n this.rafId = null;\n this.scheduled = false;\n this.fit();\n });\n };\n\n private fit = (): void => {\n if (this.destroyed) return;\n\n const element = this.host;\n const availableWidth = element.clientWidth;\n if (!availableWidth) return;\n\n const computed = window.getComputedStyle(element);\n const originalFontSizePx = this.parsePx(computed.fontSize) || 16;\n const maxPx = this.hddFitTextMaxPx\n ? Math.min(this.hddFitTextMaxPx, originalFontSizePx)\n : originalFontSizePx;\n let low = this.hddFitTextMinPx;\n let high = Math.max(low, Math.floor(maxPx));\n\n // Quick accept if it already fits\n element.style.fontSize = `${high}px`;\n if (this.scrollsWithin(element, availableWidth)) {\n return;\n }\n\n // Binary search for the largest font-size that fits\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n element.style.fontSize = `${mid}px`;\n if (this.scrollsWithin(element, availableWidth)) {\n low = mid + 1; // try bigger\n } else {\n high = mid - 1; // too big\n }\n }\n // After loop, test final candidates\n for (let size = Math.min(high, maxPx); size >= this.hddFitTextMinPx; size--) {\n element.style.fontSize = `${size}px`;\n if (this.scrollsWithin(element, availableWidth)) {\n break;\n }\n }\n };\n\n private scrollsWithin(element: HTMLElement, availableWidth: number): boolean {\n // Add a small epsilon for sub-pixel rounding\n return element.scrollWidth <= Math.ceil(availableWidth + 0.5);\n }\n\n private parsePx(value: string): number {\n const num = Number(String(value || '').replace('px', ''));\n return isFinite(num) ? num : 0;\n }\n}\n","/*\n * Public API Surface of util\n */\n\nexport * from './lib';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAAM,SAAU,QAAQ,CAAC,IAAY,EAAA;IACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC;AACxC,IAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,IAAA,IAAI,CAAC,MAAM,GAAG,QAAQ;AACtB,IAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE;AACZ,IAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACjC;;ACLM,SAAU,WAAW,CAAC,OAAyC,EAAA;IACnE,OAAO,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC;AACnD;AAEM,SAAU,QAAQ,CACtB,OAAyC,EACzC,SAAiB,EAAA;AAEjB,IAAA,OAAO,OAAO,EAAE,OAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;AACpE;AAEM,SAAU,cAAc,CAAC,EAAa,EAAA;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ;AACxC,SAAA,MAAM,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK;AACtC,SAAA,MAAM,CAAC,CAAC,GAA2B,EAAE,GAAG,KAAI;AAC3C,QAAA,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK;AACjC,QAAA,OAAO,GAAG;KACX,EAAE,EAAE,CAAC;AAER,IAAA,OAAO,WAAW;AACpB;AAEO,MAAM,6BAA6B,GAAG,UAAU,CAAC,OAAO,CAAC,kBAAkB;AAE5E,SAAU,OAAO,CAAC,CAAM,EAAE,CAAM,EAAA;IACpC,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAAE,QAAA,OAAO,KAAK;AAC1B,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACxC,QAAA,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;IAEzE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,QAAA,OAAO,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;AAEvF,IAAA,OAAO,KAAK;AACd;;MCpCa,aAAa,GAAG,IAAI,cAAc,CAAyB,eAAe,EAAE;AACvF,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,OAAO;AACd,QAAA,GAAG,EAAE,gBAAgB;AACrB,QAAA,GAAG,EAAE,gBAAgB;AACrB,QAAA,OAAO,EAAE,oBAAoB;KAC9B,CAAC;AACH,CAAA;AAEK,SAAU,0BAA0B,CAAC,OAA+B,EAAA;IACxE,OAAO;AACL,QAAA,OAAO,EAAE,aAAa;AACtB,QAAA,QAAQ,EAAE,OAAO;KAClB;AACH;MAKa,WAAW,CAAA;;AAEtB,IAAA,OAAO,GAAG,MAAM,CAAC,aAAa,CAAC;AAE/B,IAAA,cAAc,CAAC,QAAgB,EAAA;AAC7B,QAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE;AAC1D,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;;uGANtD,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAX,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAW,cAFV,MAAM,EAAA,CAAA;;2FAEP,WAAW,EAAA,UAAA,EAAA,CAAA;kBAHvB,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;AClBD;;;;AAIG;MAKU,gBAAgB,CAAA;AAcR,IAAA,KAAA;AACA,IAAA,IAAA;AAdV,IAAA,eAAe,GAAG,CAAC,CAAC;IACpB,eAAe,CAAU;AAEjB,IAAA,IAAI;AACb,IAAA,cAAc;AACd,IAAA,gBAAgB;IAChB,SAAS,GAAG,KAAK;AACjB,IAAA,0BAA0B;IAC1B,KAAK,GAAkB,IAAI;IAC3B,SAAS,GAAG,KAAK;IACR,kBAAkB,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE;IAE9D,WAAA,CACmB,KAA8B,EAC9B,IAAY,EAAA;QADZ,IAAA,CAAA,KAAK,GAAL,KAAK;QACL,IAAA,CAAA,IAAI,GAAJ,IAAI;AAErB,QAAA,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,aAAa;;IAGjC,eAAe,GAAA;;AAEb,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAK;;AAE/B,YAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,QAAQ;;YAEnE,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;;AAGvC,YAAA,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE;AACzC,gBAAA,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;gBAClE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;AACjC,iBAAA,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,gBAAgB,KAAK,UAAU,EAAE;gBACzF,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC;AAC1D,gBAAA,IAAI,CAAC,0BAA0B,GAAG,MAChC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC;;;AAIjE,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACtE,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;AACvC,gBAAA,SAAS,EAAE,IAAI;AACf,gBAAA,aAAa,EAAE,IAAI;AACnB,gBAAA,OAAO,EAAE,IAAI;AACd,aAAA,CAAC;AACJ,SAAC,CAAC;;IAGJ,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,QAAA,IAAI,IAAI,CAAC,cAAc,EAAE;AACvB,YAAA,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;;AAElC,QAAA,IAAI,CAAC,0BAA0B,IAAI;AACnC,QAAA,IAAI,CAAC,gBAAgB,EAAE,UAAU,EAAE;AACnC,QAAA,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE;AACvB,YAAA,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC;AAChC,YAAA,IAAI,CAAC,KAAK,GAAG,IAAI;;;IAIb,WAAW,GAAG,MAAW;AAC/B,QAAA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS;YAAE;AACtC,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,QAAA,MAAM,GAAG,GACP,OAAO,qBAAqB,KAAK;AAC/B,cAAE;cACA,CAAC,EAAwB,KACvB,UAAU,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAsB;AACxE,QAAA,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,MAAK;AACpB,YAAA,IAAI,CAAC,KAAK,GAAG,IAAI;AACjB,YAAA,IAAI,CAAC,SAAS,GAAG,KAAK;YACtB,IAAI,CAAC,GAAG,EAAE;AACZ,SAAC,CAAC;AACJ,KAAC;IAEO,GAAG,GAAG,MAAW;QACvB,IAAI,IAAI,CAAC,SAAS;YAAE;AAEpB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI;AACzB,QAAA,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW;AAC1C,QAAA,IAAI,CAAC,cAAc;YAAE;QAErB,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC;AACjD,QAAA,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;AAChE,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC;cACf,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,kBAAkB;cACjD,kBAAkB;AACtB,QAAA,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe;AAC9B,QAAA,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;;QAG3C,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAA,EAAG,IAAI,IAAI;QACpC,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE;YAC/C;;;AAIF,QAAA,OAAO,GAAG,GAAG,IAAI,EAAE;AACjB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC;YACxC,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAA,EAAG,GAAG,IAAI;YACnC,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE;AAC/C,gBAAA,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;;iBACT;AACL,gBAAA,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC;;;;QAInB,KAAK,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE;YAC3E,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAA,EAAG,IAAI,IAAI;YACpC,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE;gBAC/C;;;AAGN,KAAC;IAEO,aAAa,CAAC,OAAoB,EAAE,cAAsB,EAAA;;AAEhE,QAAA,OAAO,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;;AAGvD,IAAA,OAAO,CAAC,KAAa,EAAA;AAC3B,QAAA,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AACzD,QAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;;uGA3HrB,gBAAgB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,UAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAhB,gBAAgB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAJ5B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;oGAEU,eAAe,EAAA,CAAA;sBAAvB;gBACQ,eAAe,EAAA,CAAA;sBAAvB;;;ACbH;;AAEG;;ACFH;;AAEG;;;;"}
Binary file
package/index.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ import * as _angular_forms from '@angular/forms';
2
+ import { AbstractControl, FormGroup } from '@angular/forms';
3
+ import * as i0 from '@angular/core';
4
+ import { InjectionToken, Provider, AfterViewInit, OnDestroy, ElementRef, NgZone } from '@angular/core';
5
+
6
+ declare function download(href: string): void;
7
+
8
+ declare function hasRequired(control: AbstractControl<any, any> | null): boolean | undefined;
9
+ declare function hasError(control: AbstractControl<any, any> | null, errorType: string): boolean | undefined;
10
+ declare function getDirtyValues(fg: FormGroup): {
11
+ [key: string]: any;
12
+ };
13
+ declare const englishAndNumberOnlyValidator: _angular_forms.ValidatorFn;
14
+ declare function isEqual(a: any, b: any): boolean;
15
+
16
+ declare const FILE_ICON_SET: InjectionToken<Record<string, string>>;
17
+ declare function provideHaloduckUtilIconSet(iconSet: Record<string, string>): Provider;
18
+ declare class UtilService {
19
+ iconSet: Record<string, string>;
20
+ getFileIconUrl(filename: string): string;
21
+ static ɵfac: i0.ɵɵFactoryDeclaration<UtilService, never>;
22
+ static ɵprov: i0.ɵɵInjectableDeclaration<UtilService>;
23
+ }
24
+
25
+ /**
26
+ * Shrinks the font-size so the text fits within the element's width.
27
+ * - Only scales down; never scales up beyond the computed font size
28
+ * - Observes element resize and text mutations
29
+ */
30
+ declare class FitTextDirective implements AfterViewInit, OnDestroy {
31
+ private readonly elRef;
32
+ private readonly zone;
33
+ hddFitTextMinPx: number;
34
+ hddFitTextMaxPx?: number;
35
+ private readonly host;
36
+ private resizeObserver?;
37
+ private mutationObserver?;
38
+ private destroyed;
39
+ private removeWindowResizeListener?;
40
+ private rafId;
41
+ private scheduled;
42
+ private readonly handleWindowResize;
43
+ constructor(elRef: ElementRef<HTMLElement>, zone: NgZone);
44
+ ngAfterViewInit(): void;
45
+ ngOnDestroy(): void;
46
+ private scheduleFit;
47
+ private fit;
48
+ private scrollsWithin;
49
+ private parsePx;
50
+ static ɵfac: i0.ɵɵFactoryDeclaration<FitTextDirective, never>;
51
+ static ɵdir: i0.ɵɵDirectiveDeclaration<FitTextDirective, "[haloduckFitText]", never, { "hddFitTextMinPx": { "alias": "hddFitTextMinPx"; "required": false; }; "hddFitTextMaxPx": { "alias": "hddFitTextMaxPx"; "required": false; }; }, {}, never, never, true, never>;
52
+ }
53
+
54
+ export { FILE_ICON_SET, FitTextDirective, UtilService, download, englishAndNumberOnlyValidator, getDirtyValues, hasError, hasRequired, isEqual, provideHaloduckUtilIconSet };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haloduck/util",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "HaloDuck Util Library - Angular",
5
5
  "keywords": [
6
6
  "angular",
@@ -27,13 +27,6 @@
27
27
  "esm2022": "fesm2022/haloduck-util.mjs",
28
28
  "fesm2022": "fesm2022/haloduck-util.mjs",
29
29
  "typings": "index.d.ts",
30
- "scripts": {
31
- "build": "ng build @haloduck/util",
32
- "build:prod": "ng build @haloduck/util --configuration production",
33
- "test": "ng test @haloduck/util",
34
- "lint": "ng lint @haloduck/util",
35
- "prepublishOnly": "npm run build:prod"
36
- },
37
30
  "peerDependencies": {
38
31
  "@angular/common": "^20.0.0",
39
32
  "@angular/core": "^20.0.0",
@@ -45,5 +38,14 @@
45
38
  "sideEffects": false,
46
39
  "publishConfig": {
47
40
  "access": "public"
41
+ },
42
+ "exports": {
43
+ "./package.json": {
44
+ "default": "./package.json"
45
+ },
46
+ ".": {
47
+ "types": "./index.d.ts",
48
+ "default": "./fesm2022/haloduck-util.mjs"
49
+ }
48
50
  }
49
- }
51
+ }