prlg-ui 1.3.0 → 1.3.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.
- package/dist/SortDownFillIcon-7Z207bxw.js +270 -0
- package/dist/SortDownFillIcon-CSQH3vsY.cjs +1 -0
- package/dist/fonts/Roboto/Roboto-Black.woff +0 -0
- package/dist/fonts/Roboto/Roboto-Black.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-Bold.woff +0 -0
- package/dist/fonts/Roboto/Roboto-Bold.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-ExtraBold.woff +0 -0
- package/dist/fonts/Roboto/Roboto-ExtraBold.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-ExtraLight.woff +0 -0
- package/dist/fonts/Roboto/Roboto-ExtraLight.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-Light.woff +0 -0
- package/dist/fonts/Roboto/Roboto-Light.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-Medium.woff +0 -0
- package/dist/fonts/Roboto/Roboto-Medium.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-Regular.woff +0 -0
- package/dist/fonts/Roboto/Roboto-Regular.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-SemiBold.woff +0 -0
- package/dist/fonts/Roboto/Roboto-SemiBold.woff2 +0 -0
- package/dist/fonts/Roboto/Roboto-Thin.woff +0 -0
- package/dist/fonts/Roboto/Roboto-Thin.woff2 +0 -0
- package/dist/icons/index.cjs.js +1 -0
- package/dist/icons/index.es.js +1095 -0
- package/dist/icons.d.ts +150 -0
- package/dist/index.d.ts +1035 -0
- package/dist/prlg-ui.cjs.js +1 -0
- package/dist/prlg-ui.css +1 -0
- package/dist/prlg-ui.es.js +2804 -0
- package/dist/scss/colors.scss +134 -0
- package/dist/scss/fonts.scss +3 -0
- package/dist/scss/main.scss +36 -0
- package/dist/scss/mixins.scss +177 -0
- package/dist/scss/reset.scss +51 -0
- package/dist/scss/root-vars.scss +4 -0
- package/dist/useBodyScroll.util-BgQeA8Dg.js +82 -0
- package/dist/useBodyScroll.util-D-eNxODy.cjs +1 -0
- package/dist/utils/Portal/Portal.vue +27 -0
- package/dist/utils/Portal/index.ts +3 -0
- package/dist/utils/Portal.vue +27 -0
- package/dist/utils/date.util.ts +30 -0
- package/dist/utils/dayjs.util.ts +26 -0
- package/dist/utils/eventBus.util.ts +43 -0
- package/dist/utils/index.cjs.js +1 -0
- package/dist/utils/index.es.js +2346 -0
- package/dist/utils/index.ts +3 -0
- package/dist/utils/isClient.util.ts +3 -0
- package/dist/utils/onClickOutside.util.ts +57 -0
- package/dist/utils/parseDate.util.ts +41 -0
- package/dist/utils/price.util.ts +21 -0
- package/dist/utils/useBodyScroll.util.ts +33 -0
- package/dist/utils.d.ts +93 -0
- package/dist/vite.svg +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface OnClickOutsideOptions {
|
|
2
|
+
ignore?: (() => (HTMLElement | string | null | undefined)[]) | (HTMLElement | string | null | undefined)[];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const activeListeners = new WeakMap<HTMLElement, () => void>();
|
|
6
|
+
|
|
7
|
+
export function onClickOutside(
|
|
8
|
+
target: HTMLElement | null | undefined,
|
|
9
|
+
handler: (event: MouseEvent | TouchEvent) => void,
|
|
10
|
+
options: OnClickOutsideOptions = {}
|
|
11
|
+
): () => void {
|
|
12
|
+
if (!target) return () => {};
|
|
13
|
+
|
|
14
|
+
// Remove existing listener if present
|
|
15
|
+
const existingCleanup = activeListeners.get(target);
|
|
16
|
+
if (existingCleanup) {
|
|
17
|
+
existingCleanup();
|
|
18
|
+
activeListeners.delete(target);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const listener = (event: MouseEvent | TouchEvent) => {
|
|
22
|
+
const targetNode = event.target instanceof Node ? event.target : null;
|
|
23
|
+
if (!targetNode) return;
|
|
24
|
+
|
|
25
|
+
const rawIgnores = typeof options.ignore === 'function' ? options.ignore() : options.ignore ?? [];
|
|
26
|
+
const ignoreElements = rawIgnores
|
|
27
|
+
.map(el => {
|
|
28
|
+
if (typeof el === 'string') {
|
|
29
|
+
return document.querySelector(el) as HTMLElement | null;
|
|
30
|
+
}
|
|
31
|
+
return el instanceof HTMLElement ? el : null;
|
|
32
|
+
})
|
|
33
|
+
.filter((el): el is HTMLElement => el !== null && el !== undefined);
|
|
34
|
+
|
|
35
|
+
if (
|
|
36
|
+
target.contains(targetNode) ||
|
|
37
|
+
ignoreElements.some(ignoreEl => ignoreEl.contains(targetNode))
|
|
38
|
+
) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
handler(event);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
document.addEventListener('mousedown', listener, { capture: true });
|
|
46
|
+
document.addEventListener('touchstart', listener, { capture: true });
|
|
47
|
+
|
|
48
|
+
// Store cleanup function and return it
|
|
49
|
+
const cleanup = () => {
|
|
50
|
+
document.removeEventListener('mousedown', listener, { capture: true });
|
|
51
|
+
document.removeEventListener('touchstart', listener, { capture: true });
|
|
52
|
+
activeListeners.delete(target);
|
|
53
|
+
};
|
|
54
|
+
activeListeners.set(target, cleanup);
|
|
55
|
+
|
|
56
|
+
return cleanup;
|
|
57
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function parseDurationToSeconds(duration: string): number {
|
|
2
|
+
const regex = /^(\d+)(s|m|h|d|day|month|year)$/;
|
|
3
|
+
const match = duration.match(regex);
|
|
4
|
+
|
|
5
|
+
if (!match) {
|
|
6
|
+
throw new Error('Invalid duration format. Use formats like 30d, 1m, 1h, 1day, 1month, 1year');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const value = parseInt(match[1], 10);
|
|
10
|
+
const unit = match[2];
|
|
11
|
+
|
|
12
|
+
switch (unit) {
|
|
13
|
+
case 's':
|
|
14
|
+
return value; // seconds
|
|
15
|
+
case 'm':
|
|
16
|
+
return value * 60; // minutes
|
|
17
|
+
case 'h':
|
|
18
|
+
return value * 3600; // hours
|
|
19
|
+
case 'd':
|
|
20
|
+
case 'day':
|
|
21
|
+
return value * 86400; // days
|
|
22
|
+
case 'month':
|
|
23
|
+
return value * 2592000; // months (30 days)
|
|
24
|
+
case 'year':
|
|
25
|
+
return value * 31536000; // years (365 days)
|
|
26
|
+
default:
|
|
27
|
+
throw new Error('Unsupported time unit');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default parseDurationToSeconds;
|
|
32
|
+
|
|
33
|
+
/** Примеры использования */
|
|
34
|
+
/** example
|
|
35
|
+
console.log(parseDurationToSeconds('30d')); // 2592000
|
|
36
|
+
console.log(parseDurationToSeconds('1m')); // 60
|
|
37
|
+
console.log(parseDurationToSeconds('1h')); // 3600
|
|
38
|
+
console.log(parseDurationToSeconds('1day')); // 86400
|
|
39
|
+
console.log(parseDurationToSeconds('1month')); // 2592000
|
|
40
|
+
console.log(parseDurationToSeconds('1year')); // 31536000
|
|
41
|
+
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Преобразует число в форматированную строку с валютой (по умолчанию: ₽)
|
|
3
|
+
*/
|
|
4
|
+
export function formatPrice(value: number, currency = "₽"): string {
|
|
5
|
+
return `${value.toLocaleString("ru-RU")} ${currency}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Возвращает сумму всех значений (например, для корзины)
|
|
10
|
+
*/
|
|
11
|
+
export function sumPrices(items: number[]): number {
|
|
12
|
+
return items.reduce((total, price) => total + price, 0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Делает безопасное преобразование строки в число (цены из инпута)
|
|
17
|
+
*/
|
|
18
|
+
export function parsePrice(input: string): number {
|
|
19
|
+
const normalized = input.replace(/[^\d.,]/g, "").replace(",", ".");
|
|
20
|
+
return parseFloat(normalized) || 0;
|
|
21
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function useBodyScroll() {
|
|
2
|
+
let originalOverflow: string | null = null;
|
|
3
|
+
let originalPaddingRight: string | null = null;
|
|
4
|
+
|
|
5
|
+
const lockScroll = () => {
|
|
6
|
+
if (typeof window === 'undefined') return;
|
|
7
|
+
|
|
8
|
+
const body = document.body;
|
|
9
|
+
const scrollbarWidth = window.innerWidth - body.clientWidth;
|
|
10
|
+
|
|
11
|
+
if (originalOverflow === null) {
|
|
12
|
+
originalOverflow = body.style.overflow;
|
|
13
|
+
originalPaddingRight = body.style.paddingRight;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
body.style.overflow = 'hidden';
|
|
17
|
+
body.style.paddingRight = `${scrollbarWidth}px`;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const unlockScroll = () => {
|
|
21
|
+
if (typeof window === 'undefined') return;
|
|
22
|
+
|
|
23
|
+
if (originalOverflow !== null && originalPaddingRight !== null) {
|
|
24
|
+
const body = document.body;
|
|
25
|
+
body.style.overflow = originalOverflow;
|
|
26
|
+
body.style.paddingRight = originalPaddingRight;
|
|
27
|
+
originalOverflow = null;
|
|
28
|
+
originalPaddingRight = null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return { lockScroll, unlockScroll };
|
|
33
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ComponentOptionsMixin } from 'vue';
|
|
2
|
+
import { ComponentProvideOptions } from 'vue';
|
|
3
|
+
import { default as dayjs } from 'dayjs';
|
|
4
|
+
import { DefineComponent } from 'vue';
|
|
5
|
+
import { PublicProps } from 'vue';
|
|
6
|
+
|
|
7
|
+
declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
|
|
9
|
+
declare type __VLS_Props = {
|
|
10
|
+
appendTo?: 'self' | string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare function __VLS_template(): {
|
|
15
|
+
attrs: Partial<{}>;
|
|
16
|
+
slots: {
|
|
17
|
+
default?(_: {}): any;
|
|
18
|
+
default?(_: {}): any;
|
|
19
|
+
};
|
|
20
|
+
refs: {};
|
|
21
|
+
rootEl: any;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
declare type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
25
|
+
|
|
26
|
+
declare type __VLS_WithTemplateSlots<T, S> = T & {
|
|
27
|
+
new (): {
|
|
28
|
+
$slots: S;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export { dayjs }
|
|
33
|
+
|
|
34
|
+
export declare function EventBus<Events extends Record<string, any>>(): TypedEventBus<Events>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Форматирует дату в человекочитаемый вид: 20 июня 2025
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatDateReadable(date: string | Date): string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Форматирует дату для отображения времени: 20 июня, 14:30
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatDateWithTime(date: string | Date): string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Преобразует число в форматированную строку с валютой (по умолчанию: ₽)
|
|
48
|
+
*/
|
|
49
|
+
export declare function formatPrice(value: number, currency?: string): string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Возвращает разницу между датами в днях
|
|
53
|
+
*/
|
|
54
|
+
export declare function getDaysBetween(start: string | Date, end: string | Date): number;
|
|
55
|
+
|
|
56
|
+
export declare type Handler<T> = (event: T) => void;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Проверяет, истекла ли дата
|
|
60
|
+
*/
|
|
61
|
+
export declare function isExpired(date: string | Date): boolean;
|
|
62
|
+
|
|
63
|
+
export declare function onClickOutside(target: HTMLElement | null | undefined, handler: (event: MouseEvent | TouchEvent) => void, options?: OnClickOutsideOptions): () => void;
|
|
64
|
+
|
|
65
|
+
export declare interface OnClickOutsideOptions {
|
|
66
|
+
ignore?: (() => (HTMLElement | string | null | undefined)[]) | (HTMLElement | string | null | undefined)[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Делает безопасное преобразование строки в число (цены из инпута)
|
|
71
|
+
*/
|
|
72
|
+
export declare function parsePrice(input: string): number;
|
|
73
|
+
|
|
74
|
+
export declare const Portal: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Возвращает сумму всех значений (например, для корзины)
|
|
78
|
+
*/
|
|
79
|
+
export declare function sumPrices(items: number[]): number;
|
|
80
|
+
|
|
81
|
+
export declare interface TypedEventBus<Events extends Record<string, any>> {
|
|
82
|
+
on<K extends keyof Events>(type: K, handler: Handler<Events[K]>): void;
|
|
83
|
+
off<K extends keyof Events>(type: K, handler: Handler<Events[K]>): void;
|
|
84
|
+
emit<K extends keyof Events>(type: K, evt?: Events[K]): void;
|
|
85
|
+
clear(): void;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export declare function useBodyScroll(): {
|
|
89
|
+
lockScroll: () => void;
|
|
90
|
+
unlockScroll: () => void;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export { }
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|