@haloduck/util
Version:
HaloDuck Util Library - Angular
1 lines • 14.4 kB
Source Map (JSON)
{"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":["\nexport 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 =\n 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 (\n a.length === b.length && a.every((val, i) => isEqual(val, b[i]))\n );\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n return (\n keysA.length === keysB.length &&\n keysA.every((key) => isEqual(a[key], b[key]))\n );\n }\n return false;\n}\n","import {\n Injectable,\n inject,\n InjectionToken,\n Provider,\n EnvironmentInjector,\n} from '@angular/core';\n\nexport const FILE_ICON_SET = new InjectionToken<Record<string, string>>(\n 'FILE_ICON_SET',\n {\n providedIn: 'root',\n factory: () => ({\n pdf: 'assets/pdf.svg',\n stl: 'assets/stl.svg',\n default: 'assets/default.svg',\n }),\n },\n);\n\nexport function provideHaloduckUtilIconSet(\n iconSet: Record<string, string>,\n): 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(private readonly elRef: ElementRef<HTMLElement>, private readonly zone: NgZone) {\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 = () => 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, { childList: true, characterData: true, subtree: true });\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 = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : (cb: FrameRequestCallback) => 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 ? Math.min(this.hddFitTextMaxPx, originalFontSizePx) : 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\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":"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"}