@oardi/ts-utils 0.0.21 → 0.0.22
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.
- package/extensions/array-extension.d.ts +13 -0
- package/extensions/array-extension.d.ts.map +1 -0
- package/extensions/date-extension.d.ts +18 -0
- package/extensions/date-extension.d.ts.map +1 -0
- package/extensions/{index.ts → index.d.ts} +1 -0
- package/extensions/index.d.ts.map +1 -0
- package/extensions/string-extensions.d.ts +9 -0
- package/extensions/string-extensions.d.ts.map +1 -0
- package/helpers/browser/browser-type.enum.d.ts +14 -0
- package/helpers/browser/browser-type.enum.d.ts.map +1 -0
- package/helpers/browser/browser.helper.d.ts +16 -0
- package/helpers/browser/browser.helper.d.ts.map +1 -0
- package/helpers/browser/{index.ts → index.d.ts} +1 -0
- package/helpers/browser/index.d.ts.map +1 -0
- package/helpers/clipboard.helper.d.ts +2 -0
- package/helpers/clipboard.helper.d.ts.map +1 -0
- package/helpers/csv.helper.d.ts +6 -0
- package/helpers/csv.helper.d.ts.map +1 -0
- package/helpers/download.helper.d.ts +14 -0
- package/helpers/download.helper.d.ts.map +1 -0
- package/helpers/enum.helper.d.ts +6 -0
- package/helpers/enum.helper.d.ts.map +1 -0
- package/helpers/file.helper.d.ts +16 -0
- package/helpers/file.helper.d.ts.map +1 -0
- package/helpers/{index.ts → index.d.ts} +1 -0
- package/helpers/index.d.ts.map +1 -0
- package/helpers/local-storage.helper.d.ts +8 -0
- package/helpers/local-storage.helper.d.ts.map +1 -0
- package/helpers/logger/index.d.ts +4 -0
- package/helpers/logger/index.d.ts.map +1 -0
- package/helpers/logger/logger-type.enum.d.ts +8 -0
- package/helpers/logger/logger-type.enum.d.ts.map +1 -0
- package/helpers/logger/logger.helper.d.ts +15 -0
- package/helpers/logger/logger.helper.d.ts.map +1 -0
- package/helpers/logger/{logger.types.ts → logger.types.d.ts} +4 -5
- package/helpers/logger/logger.types.d.ts.map +1 -0
- package/helpers/sort.helper.d.ts +2 -0
- package/helpers/sort.helper.d.ts.map +1 -0
- package/helpers/token/{index.ts → index.d.ts} +1 -0
- package/helpers/token/index.d.ts.map +1 -0
- package/helpers/token/{token-type.enum.ts → token-type.enum.d.ts} +1 -0
- package/helpers/token/token-type.enum.d.ts.map +1 -0
- package/helpers/token/token.helper.d.ts +7 -0
- package/helpers/token/token.helper.d.ts.map +1 -0
- package/index.cjs.js +15 -0
- package/{index.ts → index.d.ts} +1 -0
- package/index.d.ts.map +1 -0
- package/index.es.js +1126 -0
- package/index.umd.js +15 -0
- package/interfaces/{index.ts → index.d.ts} +1 -0
- package/interfaces/index.d.ts.map +1 -0
- package/interfaces/keyvalue.interface.d.ts +5 -0
- package/interfaces/keyvalue.interface.d.ts.map +1 -0
- package/package.json +1 -1
- package/readme.md +15 -0
- package/services/browser/browser.consts.d.ts +3 -0
- package/services/browser/browser.consts.d.ts.map +1 -0
- package/services/browser/browser.interface.d.ts +6 -0
- package/services/browser/browser.interface.d.ts.map +1 -0
- package/services/browser/browser.service.d.ts +30 -0
- package/services/browser/browser.service.d.ts.map +1 -0
- package/services/browser/{browser.types.ts → browser.types.d.ts} +1 -1
- package/services/browser/browser.types.d.ts.map +1 -0
- package/services/browser/{index.ts → index.d.ts} +1 -0
- package/services/browser/index.d.ts.map +1 -0
- package/services/index.d.ts +2 -0
- package/services/index.d.ts.map +1 -0
- package/types/index.d.ts +9 -0
- package/types/index.d.ts.map +1 -0
- package/vite.config.d.ts +3 -0
- package/vite.config.d.ts.map +1 -0
- package/extensions/array-extension.ts +0 -54
- package/extensions/date-extension.ts +0 -69
- package/extensions/string-extensions.ts +0 -21
- package/helpers/browser/browser-type.enum.ts +0 -13
- package/helpers/browser/browser.helper.ts +0 -95
- package/helpers/clipboard.helper.ts +0 -3
- package/helpers/csv.helper.ts +0 -23
- package/helpers/download.helper.ts +0 -127
- package/helpers/enum.helper.ts +0 -20
- package/helpers/file.helper.ts +0 -105
- package/helpers/local-storage.helper.ts +0 -30
- package/helpers/logger/index.ts +0 -1
- package/helpers/logger/logger-type.enum.ts +0 -7
- package/helpers/logger/logger.helper.ts +0 -63
- package/helpers/sort.helper.ts +0 -33
- package/helpers/token/token.helper.ts +0 -16
- package/interfaces/keyvalue.interface.ts +0 -7
- package/services/browser/browser.consts.ts +0 -11
- package/services/browser/browser.interface.ts +0 -6
- package/services/browser/browser.service.ts +0 -119
- package/services/index.ts +0 -1
- package/tsconfig.json +0 -33
- package/types/index.ts +0 -11
- package/vite.config.ts +0 -21
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
export type SaveSource = Blob | ArrayBuffer | Uint8Array | string;
|
|
2
|
-
|
|
3
|
-
export interface SaveOptions {
|
|
4
|
-
mimeType?: string; /** MIME-Type, falls `source` kein Blob ist (z. B. "application/pdf") */
|
|
5
|
-
showSaveFilePicker?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* save file on client
|
|
10
|
-
*
|
|
11
|
-
* 1) File System Access API (showSaveFilePicker) – if supported
|
|
12
|
-
* 2) Fallback: <a download> + blob: URL
|
|
13
|
-
* 3) iOS-/Safari-Fallback: open new Tab if download-attribute is being ignored
|
|
14
|
-
*/
|
|
15
|
-
export async function saveAs(source: SaveSource, fileName: string, options?: SaveOptions): Promise<void> {
|
|
16
|
-
const mime: string = options?.mimeType ?? guessMimeFromFilename(fileName);
|
|
17
|
-
const blob: Blob = ensureBlob(source, mime);
|
|
18
|
-
|
|
19
|
-
// 1) experimental - feature check
|
|
20
|
-
if ('showSaveFilePicker' in window && options?.showSaveFilePicker) {
|
|
21
|
-
try {
|
|
22
|
-
const handle: FileSystemFileHandle = await (
|
|
23
|
-
window as unknown as {
|
|
24
|
-
showSaveFilePicker: (opts: {
|
|
25
|
-
suggestedName?: string;
|
|
26
|
-
types?: { description?: string; accept: Record<string, string[]> }[];
|
|
27
|
-
}) => Promise<FileSystemFileHandle>;
|
|
28
|
-
}
|
|
29
|
-
).showSaveFilePicker({
|
|
30
|
-
suggestedName: fileName,
|
|
31
|
-
types: [{ description: 'Datei', accept: { [mime]: [`.${extOf(fileName)}`] } }],
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const writable: FileSystemWritableFileStream = await handle.createWritable();
|
|
35
|
-
await writable.write(blob);
|
|
36
|
-
await writable.close();
|
|
37
|
-
return;
|
|
38
|
-
} catch (err) {
|
|
39
|
-
// Abbruch durch Nutzer oder fehlende Berechtigung -> auf Fallback gehen
|
|
40
|
-
// (keine Early-Return mitten in der Funktion – wir laufen weiter)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 2) classic: <a download> + blob: URL
|
|
45
|
-
const url: string = URL.createObjectURL(blob);
|
|
46
|
-
|
|
47
|
-
// In iOS Safari kann `download` für blob:-URLs ignoriert werden.
|
|
48
|
-
// Wir versuchen es zuerst regulär, und fallbacken dann auf "neuen Tab öffnen".
|
|
49
|
-
const anchor: HTMLAnchorElement = document.createElement('a');
|
|
50
|
-
anchor.href = url;
|
|
51
|
-
anchor.download = fileName;
|
|
52
|
-
anchor.rel = 'noopener'; // gute Praxis
|
|
53
|
-
anchor.style.display = 'none';
|
|
54
|
-
document.body.appendChild(anchor);
|
|
55
|
-
|
|
56
|
-
triggerClick(anchor);
|
|
57
|
-
|
|
58
|
-
// Kurzer Delay, dann Cleanup + optionaler iOS-Fallback
|
|
59
|
-
window.setTimeout(() => {
|
|
60
|
-
document.body.removeChild(anchor);
|
|
61
|
-
URL.revokeObjectURL(url);
|
|
62
|
-
}, 0);
|
|
63
|
-
|
|
64
|
-
// Heuristik: Wenn Safari das download-Attribut ignoriert, bleibt häufig dieselbe Seite,
|
|
65
|
-
// ohne dass ein Download-Dialog erscheint. Wir bieten dann eine Sicht-Alternative an.
|
|
66
|
-
// (Bewusst defensiv: wir öffnen nur, wenn `download` potenziell ignoriert wird.)
|
|
67
|
-
if (isProbablyIOSorOldSafari()) {
|
|
68
|
-
// Öffnet die Ressource in einem neuen Tab, damit der Nutzer manuell speichern kann.
|
|
69
|
-
// (Für PDFs & Bilder oft ausreichend; für Binärdateien hilft korrekter MIME-Type.)
|
|
70
|
-
window.open(url, '_blank', 'noopener,noreferrer');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function ensureBlob(source: SaveSource, mime: string): Blob {
|
|
75
|
-
if (source instanceof Blob) {
|
|
76
|
-
return source.type ? source : new Blob([source], { type: mime });
|
|
77
|
-
}
|
|
78
|
-
if (source instanceof ArrayBuffer || source instanceof Uint8Array) {
|
|
79
|
-
const buf: Uint8Array<ArrayBufferLike> = source instanceof Uint8Array ? source : new Uint8Array(source);
|
|
80
|
-
return new Blob([buf as BlobPart], { type: mime });
|
|
81
|
-
}
|
|
82
|
-
// string -> als Text-BLOB speichern
|
|
83
|
-
return new Blob([source], { type: mime || 'text/plain;charset=utf-8' });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function guessMimeFromFilename(filename: string): string {
|
|
87
|
-
const ext: string = extOf(filename).toLowerCase();
|
|
88
|
-
switch (ext) {
|
|
89
|
-
case 'txt':
|
|
90
|
-
return 'text/plain;charset=utf-8';
|
|
91
|
-
case 'csv':
|
|
92
|
-
return 'text/csv;charset=utf-8';
|
|
93
|
-
case 'json':
|
|
94
|
-
return 'application/json;charset=utf-8';
|
|
95
|
-
case 'pdf':
|
|
96
|
-
return 'application/pdf';
|
|
97
|
-
case 'png':
|
|
98
|
-
return 'image/png';
|
|
99
|
-
case 'jpg':
|
|
100
|
-
case 'jpeg':
|
|
101
|
-
return 'image/jpeg';
|
|
102
|
-
case 'svg':
|
|
103
|
-
return 'image/svg+xml';
|
|
104
|
-
case 'zip':
|
|
105
|
-
return 'application/zip';
|
|
106
|
-
default:
|
|
107
|
-
return 'application/octet-stream';
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function extOf(filename: string): string {
|
|
112
|
-
const idx: number = filename.lastIndexOf('.');
|
|
113
|
-
return idx >= 0 && idx < filename.length - 1 ? filename.slice(idx + 1) : '';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function triggerClick(el: HTMLElement): void {
|
|
117
|
-
const evt: MouseEvent = document.createEvent('MouseEvents');
|
|
118
|
-
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
|
119
|
-
el.dispatchEvent(evt);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function isProbablyIOSorOldSafari(): boolean {
|
|
123
|
-
const userAgent: string = navigator.userAgent;
|
|
124
|
-
const isIOS: boolean = /iPad|iPhone|iPod/.test(userAgent);
|
|
125
|
-
const isSafari: boolean = /^((?!chrome|android).)*safari/i.test(userAgent);
|
|
126
|
-
return isIOS || isSafari;
|
|
127
|
-
}
|
package/helpers/enum.helper.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { IKeyValue } from '../interfaces/keyvalue.interface';
|
|
2
|
-
|
|
3
|
-
export class EnumHelper {
|
|
4
|
-
static getEnumValue<T extends object>(enumObj: T, key: string): T[keyof T] {
|
|
5
|
-
if (!(key in enumObj)) {
|
|
6
|
-
throw Error(`${key} not found in ${enumObj}`);
|
|
7
|
-
} else {
|
|
8
|
-
return enumObj[key as keyof T];
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
static getKeyValues<T extends object>(enumObj: T): IKeyValue<string>[] {
|
|
13
|
-
return Object.keys(enumObj)
|
|
14
|
-
.filter(key => !isNaN(Number(key)))
|
|
15
|
-
.map(key => ({
|
|
16
|
-
key: Number(key),
|
|
17
|
-
value: enumObj[key as unknown as keyof T] as string,
|
|
18
|
-
}));
|
|
19
|
-
}
|
|
20
|
-
}
|
package/helpers/file.helper.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { saveAs } from './download.helper';
|
|
2
|
-
|
|
3
|
-
export class FileHelper {
|
|
4
|
-
static getFileExtension(filename: string): string {
|
|
5
|
-
let result: string = '';
|
|
6
|
-
const index: number = filename.lastIndexOf('.');
|
|
7
|
-
const hasExtension: boolean = index > 0 && index < filename.length - 1; // index > 0 verhindert z.B.: ".bashrc" als Extension
|
|
8
|
-
if (hasExtension) {
|
|
9
|
-
const ext: string = filename.substring(index + 1);
|
|
10
|
-
result = `.${ext.toLowerCase()}`;
|
|
11
|
-
}
|
|
12
|
-
return result;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* read content from a file or blob
|
|
17
|
-
*/
|
|
18
|
-
static readAsText(file: File): Promise<string> {
|
|
19
|
-
const fileReader: FileReader = new FileReader();
|
|
20
|
-
return new Promise((resolve, reject) => {
|
|
21
|
-
fileReader.onload = (): void => {
|
|
22
|
-
fileReader.onload = null;
|
|
23
|
-
fileReader.onerror = null;
|
|
24
|
-
if (typeof fileReader.result === 'string') {
|
|
25
|
-
resolve(fileReader.result);
|
|
26
|
-
} else {
|
|
27
|
-
reject(new Error('Unexpected result type'));
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
fileReader.onerror = (): void => {
|
|
31
|
-
const error = fileReader.error ?? new Error('FileReader error');
|
|
32
|
-
fileReader.onload = null;
|
|
33
|
-
fileReader.onerror = null;
|
|
34
|
-
reject(error);
|
|
35
|
-
};
|
|
36
|
-
fileReader.readAsText(file);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
static readAsArrayBuffer(file: File): Promise<ArrayBuffer> {
|
|
41
|
-
const fileReader: FileReader = new FileReader();
|
|
42
|
-
return new Promise((resolve, reject) => {
|
|
43
|
-
fileReader.onload = (): void => {
|
|
44
|
-
fileReader.onload = null;
|
|
45
|
-
fileReader.onerror = null;
|
|
46
|
-
if (fileReader.result instanceof ArrayBuffer) {
|
|
47
|
-
resolve(fileReader.result);
|
|
48
|
-
} else {
|
|
49
|
-
reject(new Error('Unexpected result type'));
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
fileReader.onerror = (): void => {
|
|
53
|
-
const error = fileReader.error ?? new Error('FileReader error');
|
|
54
|
-
fileReader.onload = null;
|
|
55
|
-
fileReader.onerror = null;
|
|
56
|
-
reject(error);
|
|
57
|
-
};
|
|
58
|
-
fileReader.readAsArrayBuffer(file);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
static readAsDataUrl(file: File): Promise<ProgressEvent<FileReader>> {
|
|
63
|
-
const reader: FileReader = new FileReader();
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
reader.onload = (event: ProgressEvent<FileReader>): void => {
|
|
66
|
-
resolve(event);
|
|
67
|
-
};
|
|
68
|
-
reader.onerror = (error): void => reject(error);
|
|
69
|
-
reader.readAsDataURL(file);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** usage:
|
|
74
|
-
* const file = new File(['Hello'], 'test.txt');
|
|
75
|
-
* FileHelper.formatFileSize(file.size);
|
|
76
|
-
* */
|
|
77
|
-
static formatFileSize(bytes: number, decimals: number = 2, unit?: 'Bytes' | 'KB' | 'MB' | 'GB' | 'TB'): string {
|
|
78
|
-
if (bytes === 0) {
|
|
79
|
-
return '0 Bytes';
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const k = 1024;
|
|
83
|
-
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
84
|
-
|
|
85
|
-
let i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
86
|
-
|
|
87
|
-
if (unit && sizes.includes(unit)) {
|
|
88
|
-
i = sizes.indexOf(unit);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const value = bytes / Math.pow(k, i);
|
|
92
|
-
const fixed = parseFloat(value.toFixed(decimals));
|
|
93
|
-
|
|
94
|
-
return `${fixed} ${sizes[i]}`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
static save(content: BlobPart, fileName: string, fileType: string): void {
|
|
98
|
-
const blob: Blob = new Blob([content], { type: fileType });
|
|
99
|
-
saveAs(blob, fileName);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// usage
|
|
104
|
-
// const extension: string = FileHelper.getFileExtension('asdf.txt');
|
|
105
|
-
// -> .txt
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export class LocalStorageHelper {
|
|
2
|
-
static set<T>(key: string, value: T): void {
|
|
3
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
static get<T>(key: string): Nullable<T> {
|
|
7
|
-
let result: Nullable<T> = null;
|
|
8
|
-
const local: Nullable<string> = localStorage.getItem(key);
|
|
9
|
-
if (local) {
|
|
10
|
-
result = JSON.parse(local);
|
|
11
|
-
}
|
|
12
|
-
return result;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static remove(key: string): boolean {
|
|
16
|
-
let result: boolean = !!LocalStorageHelper.get(key);
|
|
17
|
-
if (result) {
|
|
18
|
-
localStorage.removeItem(key);
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static removeAll(): void {
|
|
24
|
-
localStorage.clear();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static getKeysBy(key: string): string[] {
|
|
28
|
-
return Object.keys(localStorage).filter(k => k.startsWith(key));
|
|
29
|
-
}
|
|
30
|
-
}
|
package/helpers/logger/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './logger.helper';
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { LoggerType } from './logger-type.enum';
|
|
2
|
-
import { LoggerListener, LoggerPayload } from './logger.types';
|
|
3
|
-
|
|
4
|
-
export class LoggerHelper {
|
|
5
|
-
private static listeners: Set<LoggerListener> = new Set();
|
|
6
|
-
|
|
7
|
-
public static log(...args: unknown[]): void {
|
|
8
|
-
LoggerHelper.doLog(LoggerType.log, args);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public static info(...args: unknown[]): void {
|
|
12
|
-
LoggerHelper.doLog(LoggerType.info, args);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public static warn(...args: unknown[]): void {
|
|
16
|
-
LoggerHelper.doLog(LoggerType.warn, args);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public static debug(...args: unknown[]): void {
|
|
20
|
-
LoggerHelper.doLog(LoggerType.debug, args);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public static error(...args: unknown[]): void {
|
|
24
|
-
LoggerHelper.doLog(LoggerType.error, args);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private static doLog(level: LoggerType, args: unknown[]): void {
|
|
28
|
-
const payload: LoggerPayload = {
|
|
29
|
-
type: level,
|
|
30
|
-
args,
|
|
31
|
-
timestamp: new Date().toISOString(),
|
|
32
|
-
};
|
|
33
|
-
for (const listener of LoggerHelper.listeners) {
|
|
34
|
-
try {
|
|
35
|
-
const res = listener(payload);
|
|
36
|
-
if (res === false) {
|
|
37
|
-
return; // cancelled by listener
|
|
38
|
-
}
|
|
39
|
-
} catch {
|
|
40
|
-
// swallow listener errors so logging never breaks the app
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
(console as Console)[level].apply(console, args);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
public static onLog(listener: LoggerListener, once = false): () => void {
|
|
48
|
-
if (once) {
|
|
49
|
-
const wrapper: LoggerListener = (payload) => {
|
|
50
|
-
try {
|
|
51
|
-
return listener(payload);
|
|
52
|
-
} finally {
|
|
53
|
-
LoggerHelper.listeners.delete(wrapper);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
LoggerHelper.listeners.add(wrapper);
|
|
57
|
-
return () => LoggerHelper.listeners.delete(wrapper);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
LoggerHelper.listeners.add(listener);
|
|
61
|
-
return () => LoggerHelper.listeners.delete(listener);
|
|
62
|
-
}
|
|
63
|
-
}
|
package/helpers/sort.helper.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
enum SortOrder {
|
|
2
|
-
NONE = 0,
|
|
3
|
-
ASC = 1,
|
|
4
|
-
DESC = -1,
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const compareString = (valA: string, valB: string, ascending: boolean | undefined): number => {
|
|
8
|
-
return valA.localeCompare(valB) * (ascending ? SortOrder.ASC : SortOrder.DESC);
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const getSortOrder = <T>(valA: T, valB: T): SortOrder => {
|
|
12
|
-
return valA < valB ? SortOrder.DESC : valA === valB ? SortOrder.NONE : SortOrder.ASC;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const compareNonString = <T>(valA: T, valB: T, ascending: boolean | undefined): number => {
|
|
16
|
-
return getSortOrder(valA, valB) * (ascending ? SortOrder.ASC : SortOrder.DESC);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const getValue = <T>(valA: T, valB: T, ascending: boolean | undefined): number => {
|
|
20
|
-
let result: number = 0;
|
|
21
|
-
if (typeof valA === 'string' && typeof valB === 'string') {
|
|
22
|
-
result = compareString(valA, valB, ascending);
|
|
23
|
-
} else {
|
|
24
|
-
result = compareNonString(valA, valB, ascending);
|
|
25
|
-
}
|
|
26
|
-
return result;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const sortHelper = <T, G>(a: T, b: T, valueGetter: (a: T) => G, ascending?: boolean): number => {
|
|
30
|
-
const valA: G = valueGetter(a);
|
|
31
|
-
const valB: G = valueGetter(b);
|
|
32
|
-
return getValue(valA, valB, ascending);
|
|
33
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { LocalStorageHelper } from '../local-storage.helper';
|
|
2
|
-
import { TokenType } from './token-type.enum';
|
|
3
|
-
|
|
4
|
-
export class TokenHelper {
|
|
5
|
-
static get(key: TokenType): string | null {
|
|
6
|
-
return LocalStorageHelper.get<string>(key);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
static set(key: TokenType, token: string): void {
|
|
10
|
-
LocalStorageHelper.set(key, token);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
static remove(key: TokenType): void {
|
|
14
|
-
LocalStorageHelper.remove(key);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { Size } from '../../types';
|
|
2
|
-
import { ScreenBreakpoints } from './browser.consts';
|
|
3
|
-
import { IScreenBreakpoint } from './browser.interface';
|
|
4
|
-
import { OnResizeCallback, ResizeCallback } from './browser.types';
|
|
5
|
-
|
|
6
|
-
// TODO - extract into Resize and breakpoint separated?
|
|
7
|
-
|
|
8
|
-
export class BrowserService {
|
|
9
|
-
private screenBreakpoints!: Record<Size, number>;
|
|
10
|
-
private screenWidth: number = 0;
|
|
11
|
-
private lastBreakpoint!: IScreenBreakpoint;
|
|
12
|
-
private resizeListener!: (event: UIEvent) => void;
|
|
13
|
-
private breakpointChangeCallbacks: Set<ResizeCallback> = new Set(); // feuert nur bei Breakpoint-Änderung
|
|
14
|
-
private onResizeCallbacks: Set<OnResizeCallback> = new Set(); // feuert bei jedem throttled Resize
|
|
15
|
-
private rafId: number | null = null;
|
|
16
|
-
private emitTimeoutId: number | null = null; // für debounce der onResizeCallbacks
|
|
17
|
-
private pendingWidth?: number;
|
|
18
|
-
private pendingBreakpoint?: IScreenBreakpoint;
|
|
19
|
-
private duplicateThresholdMs = 60;
|
|
20
|
-
|
|
21
|
-
constructor(screenBreakpoints?: Record<Size, number>) {
|
|
22
|
-
if (typeof window !== 'undefined') {
|
|
23
|
-
this.screenBreakpoints = screenBreakpoints || ScreenBreakpoints;
|
|
24
|
-
|
|
25
|
-
this.screenWidth = window.innerWidth;
|
|
26
|
-
this.resizeListener = this.onResize.bind(this);
|
|
27
|
-
|
|
28
|
-
window.addEventListener('resize', this.resizeListener, { passive: true }); // passive: true für bessere Scroll/Resize-Performance
|
|
29
|
-
this.lastBreakpoint = this.getBreakpointByScreenWidth(this.screenWidth);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public destroy(): void {
|
|
34
|
-
if (typeof window !== 'undefined') {
|
|
35
|
-
window.removeEventListener('resize', this.resizeListener);
|
|
36
|
-
}
|
|
37
|
-
this.breakpointChangeCallbacks.clear();
|
|
38
|
-
this.onResizeCallbacks.clear();
|
|
39
|
-
if (this.rafId !== null) {
|
|
40
|
-
cancelAnimationFrame(this.rafId);
|
|
41
|
-
this.rafId = null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public getCurrentScreenWidth(): number {
|
|
46
|
-
return this.screenWidth;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
public getCurrentBreakpoint(): IScreenBreakpoint {
|
|
50
|
-
return this.lastBreakpoint;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public onBreakpointChange(callback: ResizeCallback): void {
|
|
54
|
-
this.breakpointChangeCallbacks.add(callback);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
public offBreakpointChange(callback: ResizeCallback): void {
|
|
58
|
-
this.breakpointChangeCallbacks.delete(callback);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public onResizeChange(callback: OnResizeCallback): void {
|
|
62
|
-
this.onResizeCallbacks.add(callback);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
public offResizeChange(callback: OnResizeCallback): void {
|
|
66
|
-
this.onResizeCallbacks.delete(callback);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public getBreakpointByScreenWidth(width: number = this.screenWidth): IScreenBreakpoint {
|
|
70
|
-
let result: Size = 'xs';
|
|
71
|
-
for (const key of Object.keys(this.screenBreakpoints) as Size[]) {
|
|
72
|
-
if (this.screenBreakpoints[key] <= width) {
|
|
73
|
-
result = key;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return { breakpoint: result, screenWidth: this.screenBreakpoints[result] };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public isScreenGreaterThan(size: Size): boolean {
|
|
80
|
-
return this.screenWidth > this.screenBreakpoints[size];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public isScreenSmallerThan(size: Size): boolean {
|
|
84
|
-
return this.screenWidth < this.screenBreakpoints[size];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
public getBreakpoint(size: Size): IScreenBreakpoint {
|
|
88
|
-
return {
|
|
89
|
-
breakpoint: size,
|
|
90
|
-
screenWidth: this.screenBreakpoints[size],
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
private onResize = (): void => {
|
|
95
|
-
if (typeof window === 'undefined') return;
|
|
96
|
-
|
|
97
|
-
const width: number = window.innerWidth;
|
|
98
|
-
const breakpoint: IScreenBreakpoint = this.getBreakpointByScreenWidth(width);
|
|
99
|
-
|
|
100
|
-
if (this.lastBreakpoint?.breakpoint !== breakpoint?.breakpoint) {
|
|
101
|
-
this.lastBreakpoint = breakpoint;
|
|
102
|
-
breakpoint && this.breakpointChangeCallbacks.forEach((cb) => cb(breakpoint));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
this.pendingWidth = width;
|
|
106
|
-
this.pendingBreakpoint = breakpoint;
|
|
107
|
-
|
|
108
|
-
if (this.emitTimeoutId) clearTimeout(this.emitTimeoutId);
|
|
109
|
-
|
|
110
|
-
this.emitTimeoutId = window.setTimeout(() => {
|
|
111
|
-
if (this.pendingBreakpoint) {
|
|
112
|
-
this.onResizeCallbacks.forEach((cb) => cb(this.pendingWidth!, this.pendingBreakpoint!));
|
|
113
|
-
}
|
|
114
|
-
this.pendingWidth = undefined;
|
|
115
|
-
this.pendingBreakpoint = undefined;
|
|
116
|
-
this.emitTimeoutId = null;
|
|
117
|
-
}, this.duplicateThresholdMs);
|
|
118
|
-
};
|
|
119
|
-
}
|
package/services/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './browser';
|
package/tsconfig.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"declaration": true,
|
|
4
|
-
"declarationMap": true,
|
|
5
|
-
"emitDeclarationOnly": true,
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
|
|
8
|
-
"target": "ES2022",
|
|
9
|
-
"useDefineForClassFields": true,
|
|
10
|
-
"module": "ESNext",
|
|
11
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
|
|
14
|
-
/* Bundler mode */
|
|
15
|
-
"moduleResolution": "bundler",
|
|
16
|
-
"allowImportingTsExtensions": true,
|
|
17
|
-
"isolatedModules": true,
|
|
18
|
-
"moduleDetection": "force",
|
|
19
|
-
"noEmit": true,
|
|
20
|
-
|
|
21
|
-
/* Linting */
|
|
22
|
-
"strict": true,
|
|
23
|
-
"noImplicitAny": true,
|
|
24
|
-
"noImplicitOverride": true,
|
|
25
|
-
"noPropertyAccessFromIndexSignature": true,
|
|
26
|
-
"noImplicitReturns": true,
|
|
27
|
-
"noFallthroughCasesInSwitch": true,
|
|
28
|
-
"noUnusedLocals": true,
|
|
29
|
-
"noUnusedParameters": true
|
|
30
|
-
},
|
|
31
|
-
"include": ["**/*"],
|
|
32
|
-
"exclude": ["node_modules", "dist"]
|
|
33
|
-
}
|
package/types/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type Dictionary<T> = Record<string, T>;
|
|
2
|
-
|
|
3
|
-
export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl';
|
|
4
|
-
|
|
5
|
-
declare global {
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
-
export type UnknownObject = any;
|
|
8
|
-
export type Nullable<T> = T | null;
|
|
9
|
-
export type Optional<T> = T | undefined;
|
|
10
|
-
export const InstallTrigger: unknown;
|
|
11
|
-
}
|
package/vite.config.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import dts from 'vite-plugin-dts';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
root: './lib',
|
|
6
|
-
build: {
|
|
7
|
-
lib: {
|
|
8
|
-
entry: 'index.ts',
|
|
9
|
-
name: 'ts-utils',
|
|
10
|
-
fileName: (format) => `index.${format}.js`,
|
|
11
|
-
formats: ['es', 'cjs', 'umd'],
|
|
12
|
-
},
|
|
13
|
-
outDir: '../dist/lib',
|
|
14
|
-
emptyOutDir: true,
|
|
15
|
-
},
|
|
16
|
-
plugins: [
|
|
17
|
-
dts({
|
|
18
|
-
insertTypesEntry: true,
|
|
19
|
-
}),
|
|
20
|
-
],
|
|
21
|
-
});
|