@rainersoft/utils 1.3.0 → 1.4.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.
package/dist/index.mjs CHANGED
@@ -1,10 +1,12 @@
1
- import React from 'react';
1
+ import React, { useRef, useState, useCallback, useEffect } from 'react';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
5
  var __export = (target, all) => {
5
6
  for (var name in all)
6
7
  __defProp(target, name, { get: all[name], enumerable: true });
7
8
  };
9
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
8
10
 
9
11
  // src/types.ts
10
12
  var DEFAULT_LOCALE = "pt-BR";
@@ -14,153 +16,77 @@ var CURRENCY_MAP = {
14
16
  "es-ES": "EUR"
15
17
  };
16
18
 
17
- // src/text/index.ts
18
- var text_exports = {};
19
- __export(text_exports, {
20
- calculateReadingTime: () => calculateReadingTime,
21
- capitalize: () => capitalize,
22
- cleanText: () => cleanText,
23
- countWords: () => countWords,
24
- extractInitials: () => extractInitials,
25
- generateAvatarUrl: () => generateAvatarUrl,
26
- generateDynamicAvatarUrl: () => generateDynamicAvatarUrl,
27
- generateUniqueId: () => generateUniqueId,
28
- getAvatarColorFromName: () => getAvatarColorFromName,
29
- isEmpty: () => isEmpty,
30
- isValidAvatarUrl: () => isValidAvatarUrl,
31
- normalizeSpaces: () => normalizeSpaces,
32
- truncateText: () => truncateText
33
- });
34
- function extractInitials(name, maxChars = 2) {
35
- if (!name || !name.trim()) {
36
- return "";
37
- }
38
- const words = name.trim().split(/\s+/);
39
- const initials = words.slice(0, maxChars).map((word) => word.charAt(0).toUpperCase()).join("");
40
- return initials;
41
- }
42
- function generateAvatarUrl(name, size = 200, backgroundColor = "0891b2", textColor = "fff") {
43
- const encodedName = encodeURIComponent(name);
44
- return `https://ui-avatars.com/api/?name=${encodedName}&size=${size}&background=${backgroundColor}&color=${textColor}&font-size=0.5`;
45
- }
46
- function isValidAvatarUrl(url) {
47
- if (!url || typeof url !== "string") {
48
- return false;
49
- }
50
- try {
51
- new URL(url);
52
- return true;
53
- } catch {
54
- return false;
55
- }
56
- }
57
- function getAvatarColorFromName(name) {
58
- if (!name || typeof name !== "string") {
59
- return "#0891b2";
60
- }
61
- let hash = 0;
62
- for (let i = 0; i < name.length; i++) {
63
- hash = name.charCodeAt(i) + ((hash << 5) - hash);
64
- }
65
- const colors = [
66
- "#0891b2",
67
- // cyan-600
68
- "#9333ea",
69
- // purple-600
70
- "#db2777",
71
- // pink-600
72
- "#059669",
73
- // emerald-600
74
- "#2563eb",
75
- // blue-600
76
- "#f97316",
77
- // orange-500
78
- "#dc2626",
79
- // red-600
80
- "#7c3aed"
81
- // violet-600
82
- ];
83
- const index = Math.abs(hash) % colors.length;
84
- return colors[index];
85
- }
86
- function generateDynamicAvatarUrl(name, size = 200) {
87
- const color = getAvatarColorFromName(name);
88
- const colorHex = color.replace("#", "");
89
- return generateAvatarUrl(name, size, colorHex, "fff");
90
- }
91
- function generateUniqueId(text, prefix = "", suffix = "") {
92
- const slug = text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim().substring(0, 50);
93
- const parts = [prefix, slug, suffix].filter(Boolean);
94
- return parts.join("-");
95
- }
96
- function truncateText(text, maxLength, suffix = "...") {
97
- if (!text || text.length <= maxLength) {
98
- return text || "";
19
+ // src/accessibility/index.ts
20
+ function hexToRgb(hex) {
21
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
22
+ if (!result) {
23
+ throw new Error(`Invalid hex color: ${hex}`);
99
24
  }
100
- return text.substring(0, maxLength - suffix.length) + suffix;
101
- }
102
- function capitalize(text, options = {}) {
103
- if (!text) return "";
104
- const { firstWordOnly = false, lowerRest = false } = options;
105
- if (firstWordOnly) {
106
- return text.charAt(0).toUpperCase() + (lowerRest ? text.slice(1).toLowerCase() : text.slice(1));
107
- }
108
- if (lowerRest) {
109
- return text.replace(/\b\w/g, (char) => char.toUpperCase()).toLowerCase();
110
- }
111
- return text.replace(/\b\w/g, (char) => char.toUpperCase());
112
- }
113
- function cleanText(text, allowSpaces = true) {
114
- if (!text) return "";
115
- const pattern = allowSpaces ? /[^\w\s]/g : /[^\w]/g;
116
- return text.replace(pattern, "");
25
+ return {
26
+ r: parseInt(result[1], 16),
27
+ g: parseInt(result[2], 16),
28
+ b: parseInt(result[3], 16)
29
+ };
117
30
  }
118
- function countWords(text) {
119
- if (!text || !text.trim()) {
120
- return 0;
31
+ function getLuminance(r, g, b) {
32
+ const [rs, gs, bs] = [r, g, b].map((val) => {
33
+ const v = val / 255;
34
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
35
+ });
36
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
37
+ }
38
+ function getContrast(color1, color2) {
39
+ const rgb1 = hexToRgb(color1);
40
+ const rgb2 = hexToRgb(color2);
41
+ const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
42
+ const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
43
+ const lighter = Math.max(lum1, lum2);
44
+ const darker = Math.min(lum1, lum2);
45
+ return (lighter + 0.05) / (darker + 0.05);
46
+ }
47
+ function getContrastInfo(foreground, background) {
48
+ const contrast = getContrast(foreground, background);
49
+ const meetsAA = contrast >= 4.5;
50
+ const meetsAALarge = contrast >= 3;
51
+ const meetsAAA = contrast >= 7;
52
+ const meetsAAALarge = contrast >= 4.5;
53
+ let level = "Fail";
54
+ if (meetsAAA) {
55
+ level = "AAA";
56
+ } else if (meetsAAALarge) {
57
+ level = "AAA Large";
58
+ } else if (meetsAA) {
59
+ level = "AA";
60
+ } else if (meetsAALarge) {
61
+ level = "AA Large";
121
62
  }
122
- return text.trim().split(/\s+/).length;
123
- }
124
- function isEmpty(text) {
125
- return !text || !text.trim();
63
+ return {
64
+ contrast,
65
+ meetsAA,
66
+ meetsAALarge,
67
+ meetsAAA,
68
+ meetsAAALarge,
69
+ level
70
+ };
126
71
  }
127
- function normalizeSpaces(text, options = {}) {
128
- if (!text) return "";
129
- const { newlines = false } = options;
130
- let cleaned = text;
131
- if (newlines) {
132
- cleaned = cleaned.replace(/\s+/g, " ");
72
+ function validateContrast(foreground, background, options = {}) {
73
+ const { requireAAA = false, largeText = false } = options;
74
+ const info = getContrastInfo(foreground, background);
75
+ let valid = false;
76
+ let message = "";
77
+ if (requireAAA) {
78
+ valid = largeText ? info.meetsAAALarge : info.meetsAAA;
79
+ message = valid ? `Contraste v\xE1lido (WCAG AAA${largeText ? " - Texto Grande" : ""})` : `Contraste insuficiente para WCAG AAA${largeText ? " - Texto Grande" : ""}. Requerido: ${largeText ? "4.5:1" : "7:1"}, atual: ${info.contrast.toFixed(2)}:1`;
133
80
  } else {
134
- cleaned = cleaned.replace(/\s+/g, " ");
81
+ valid = largeText ? info.meetsAALarge : info.meetsAA;
82
+ message = valid ? `Contraste v\xE1lido (WCAG AA${largeText ? " - Texto Grande" : ""})` : `Contraste insuficiente para WCAG AA${largeText ? " - Texto Grande" : ""}. Requerido: ${largeText ? "3:1" : "4.5:1"}, atual: ${info.contrast.toFixed(2)}:1`;
135
83
  }
136
- return cleaned.trim();
137
- }
138
- function calculateReadingTime(content, wordsPerMinute = 200) {
139
- let text = "";
140
- if (typeof content === "object" && content !== null) {
141
- const extractText = (node) => {
142
- if (!node) return "";
143
- let result = "";
144
- if (node.text) {
145
- result += node.text + " ";
146
- }
147
- if (Array.isArray(node.content)) {
148
- result += node.content.map(extractText).join(" ");
149
- }
150
- return result;
151
- };
152
- text = extractText(content);
153
- } else if (typeof content === "string") {
154
- text = content.replace(/<[^>]*>/g, "");
155
- }
156
- const words = text.trim().split(/\s+/).filter((word) => word.length > 0).length;
157
- const time = Math.ceil(words / wordsPerMinute);
158
- return time > 0 ? time : 1;
159
- }
160
-
161
- // src/string/index.ts
162
- function textToSlug(text) {
163
- return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-");
84
+ return {
85
+ valid,
86
+ level: info.level,
87
+ contrast: info.contrast,
88
+ message
89
+ };
164
90
  }
165
91
 
166
92
  // src/date/index.ts
@@ -264,30 +190,6 @@ function isValidDate(date) {
264
190
  return date instanceof Date && !isNaN(date.getTime());
265
191
  }
266
192
 
267
- // src/number/index.ts
268
- function formatCurrency(value, locale = DEFAULT_LOCALE, options) {
269
- const currency = CURRENCY_MAP[locale];
270
- return new Intl.NumberFormat(locale, {
271
- style: "currency",
272
- currency,
273
- ...options
274
- }).format(value);
275
- }
276
- function formatNumber(value, decimals = 0, locale = DEFAULT_LOCALE) {
277
- return new Intl.NumberFormat(locale, {
278
- minimumFractionDigits: decimals,
279
- maximumFractionDigits: decimals
280
- }).format(value);
281
- }
282
- function formatCompact(value, decimals = 1, locale = DEFAULT_LOCALE) {
283
- return new Intl.NumberFormat(locale, {
284
- notation: "compact",
285
- compactDisplay: "short",
286
- minimumFractionDigits: decimals,
287
- maximumFractionDigits: decimals
288
- }).format(value);
289
- }
290
-
291
193
  // src/status/index.ts
292
194
  var status_exports = {};
293
195
  __export(status_exports, {
@@ -656,6 +558,198 @@ function validateMessage(message, options = {}, locale = DEFAULT_LOCALE) {
656
558
  }, locale);
657
559
  }
658
560
 
561
+ // src/content/tiptap-utils.ts
562
+ function extractTextFromTiptap(content) {
563
+ function extractFromNode(node) {
564
+ if ("text" in node && typeof node.text === "string") {
565
+ return node.text;
566
+ }
567
+ if ("content" in node && Array.isArray(node.content)) {
568
+ return node.content.map((child) => extractFromNode(child)).join(" ");
569
+ }
570
+ return "";
571
+ }
572
+ return extractFromNode(content).trim();
573
+ }
574
+ function generateExcerpt(content, maxLength = 160) {
575
+ const text = extractTextFromTiptap(content);
576
+ if (text.length <= maxLength) {
577
+ return text;
578
+ }
579
+ return text.substring(0, maxLength).trim() + "...";
580
+ }
581
+ function createEmptyTiptapContent() {
582
+ return {
583
+ type: "doc",
584
+ content: []
585
+ };
586
+ }
587
+ function isContentEmpty(content) {
588
+ if (!content || !content.content || content.content.length === 0) {
589
+ return true;
590
+ }
591
+ const text = extractTextFromTiptap(content);
592
+ return text.trim().length === 0;
593
+ }
594
+ function countWords(content) {
595
+ const text = extractTextFromTiptap(content);
596
+ return text.trim().split(/\s+/).filter((word) => word.length > 0).length;
597
+ }
598
+ function countCharacters(content) {
599
+ return extractTextFromTiptap(content).length;
600
+ }
601
+ function getReadingTime(content, wordsPerMinute = 200) {
602
+ const wordCount = countWords(content);
603
+ return Math.ceil(wordCount / wordsPerMinute);
604
+ }
605
+ function getContentStats(content) {
606
+ const wordCount = countWords(content);
607
+ const characterCount = extractTextFromTiptap(content).length;
608
+ const readingTime = getReadingTime(content);
609
+ return {
610
+ wordCount,
611
+ characterCount,
612
+ readingTime
613
+ };
614
+ }
615
+ function containsText(content, searchText) {
616
+ const text = extractTextFromTiptap(content).toLowerCase();
617
+ return text.includes(searchText.toLowerCase());
618
+ }
619
+ function replaceText(content, searchText, replaceText2) {
620
+ function processNode(node) {
621
+ const newNode = { ...node };
622
+ if ("text" in node && typeof node.text === "string") {
623
+ newNode.text = node.text.replace(
624
+ new RegExp(searchText, "gi"),
625
+ replaceText2
626
+ );
627
+ }
628
+ if ("content" in node && Array.isArray(node.content)) {
629
+ newNode.content = node.content.map((child) => processNode(child));
630
+ }
631
+ return newNode;
632
+ }
633
+ const newContent = {
634
+ ...content,
635
+ content: content.content.map((node) => processNode(node))
636
+ };
637
+ return newContent;
638
+ }
639
+
640
+ // src/color/index.ts
641
+ function hexToRgb2(hex) {
642
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
643
+ if (!result) {
644
+ throw new Error(`Invalid hex color: ${hex}`);
645
+ }
646
+ return {
647
+ r: parseInt(result[1], 16),
648
+ g: parseInt(result[2], 16),
649
+ b: parseInt(result[3], 16)
650
+ };
651
+ }
652
+ function rgbToHex(r, g, b) {
653
+ const toHex = (n) => {
654
+ const hex = Math.round(Math.max(0, Math.min(255, n))).toString(16);
655
+ return hex.length === 1 ? "0" + hex : hex;
656
+ };
657
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
658
+ }
659
+ function hexToHsl(hex) {
660
+ const rgb = hexToRgb2(hex);
661
+ const r = rgb.r / 255;
662
+ const g = rgb.g / 255;
663
+ const b = rgb.b / 255;
664
+ const max = Math.max(r, g, b);
665
+ const min = Math.min(r, g, b);
666
+ let h = 0;
667
+ let s = 0;
668
+ const l = (max + min) / 2;
669
+ if (max !== min) {
670
+ const d = max - min;
671
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
672
+ switch (max) {
673
+ case r:
674
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
675
+ break;
676
+ case g:
677
+ h = ((b - r) / d + 2) / 6;
678
+ break;
679
+ case b:
680
+ h = ((r - g) / d + 4) / 6;
681
+ break;
682
+ }
683
+ }
684
+ return {
685
+ h: Math.round(h * 360),
686
+ s: Math.round(s * 100),
687
+ l: Math.round(l * 100)
688
+ };
689
+ }
690
+ function hslToHex(h, s, l) {
691
+ h = h / 360;
692
+ s = s / 100;
693
+ l = l / 100;
694
+ let r, g, b;
695
+ if (s === 0) {
696
+ r = g = b = l;
697
+ } else {
698
+ const hue2rgb = (p2, q2, t) => {
699
+ if (t < 0) t += 1;
700
+ if (t > 1) t -= 1;
701
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
702
+ if (t < 1 / 2) return q2;
703
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
704
+ return p2;
705
+ };
706
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
707
+ const p = 2 * l - q;
708
+ r = hue2rgb(p, q, h + 1 / 3);
709
+ g = hue2rgb(p, q, h);
710
+ b = hue2rgb(p, q, h - 1 / 3);
711
+ }
712
+ return rgbToHex(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255));
713
+ }
714
+ function adjustBrightness(hex, amount) {
715
+ const hsl = hexToHsl(hex);
716
+ const newL = Math.max(0, Math.min(100, hsl.l + amount));
717
+ return hslToHex(hsl.h, hsl.s, newL);
718
+ }
719
+ function adjustSaturation(hex, amount) {
720
+ const hsl = hexToHsl(hex);
721
+ const newS = Math.max(0, Math.min(100, hsl.s + amount));
722
+ return hslToHex(hsl.h, newS, hsl.l);
723
+ }
724
+ function adjustHue(hex, degrees) {
725
+ const hsl = hexToHsl(hex);
726
+ const newH = (hsl.h + degrees) % 360;
727
+ return hslToHex(newH < 0 ? newH + 360 : newH, hsl.s, hsl.l);
728
+ }
729
+ function lighten(hex, amount) {
730
+ return adjustBrightness(hex, amount);
731
+ }
732
+ function darken(hex, amount) {
733
+ return adjustBrightness(hex, -amount);
734
+ }
735
+ function hexToRgba(hex, alpha) {
736
+ const rgb = hexToRgb2(hex);
737
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
738
+ }
739
+ function getComplementary(hex) {
740
+ return adjustHue(hex, 180);
741
+ }
742
+ function getAnalogousPalette(hex, count = 5) {
743
+ const hsl = hexToHsl(hex);
744
+ const step = 30;
745
+ const palette = [];
746
+ for (let i = 0; i < count; i++) {
747
+ const hue = (hsl.h + (i - Math.floor(count / 2)) * step) % 360;
748
+ palette.push(hslToHex(hue < 0 ? hue + 360 : hue, hsl.s, hsl.l));
749
+ }
750
+ return palette;
751
+ }
752
+
659
753
  // src/dom/index.ts
660
754
  function prefersReducedMotion() {
661
755
  if (typeof window === "undefined") return false;
@@ -833,9 +927,314 @@ function downloadFile(blob, filename) {
833
927
  document.body.removeChild(link);
834
928
  URL.revokeObjectURL(url);
835
929
  }
930
+ var DEFAULT_CONFIG = {
931
+ autoRefresh: true,
932
+ refreshInterval: 15 * 60 * 1e3,
933
+ // 15 minutes
934
+ tokenStorageKey: "auth_token",
935
+ userStorageKey: "auth_user",
936
+ apiEndpoint: "/api/auth",
937
+ onAuthChange: () => {
938
+ },
939
+ onError: () => {
940
+ }
941
+ };
942
+ var AuthStorage = class {
943
+ static setItem(key, value) {
944
+ if (!this.isClient) return;
945
+ try {
946
+ localStorage.setItem(key, value);
947
+ } catch (error) {
948
+ console.warn("Failed to save to localStorage:", error);
949
+ }
950
+ }
951
+ static getItem(key) {
952
+ if (!this.isClient) return null;
953
+ try {
954
+ return localStorage.getItem(key);
955
+ } catch (error) {
956
+ console.warn("Failed to read from localStorage:", error);
957
+ return null;
958
+ }
959
+ }
960
+ static removeItem(key) {
961
+ if (!this.isClient) return;
962
+ try {
963
+ localStorage.removeItem(key);
964
+ } catch (error) {
965
+ console.warn("Failed to remove from localStorage:", error);
966
+ }
967
+ }
968
+ static setUser(user, key) {
969
+ this.setItem(key, JSON.stringify(user));
970
+ }
971
+ static getUser(key) {
972
+ const data = this.getItem(key);
973
+ if (!data) return null;
974
+ try {
975
+ return JSON.parse(data);
976
+ } catch {
977
+ this.removeItem(key);
978
+ return null;
979
+ }
980
+ }
981
+ static removeUser(key) {
982
+ this.removeItem(key);
983
+ }
984
+ };
985
+ __publicField(AuthStorage, "isClient", typeof window !== "undefined");
986
+ var TokenManager = class {
987
+ static decodeToken(token) {
988
+ try {
989
+ const payload = token.split(".")[1];
990
+ const decoded = atob(payload);
991
+ return JSON.parse(decoded);
992
+ } catch {
993
+ return null;
994
+ }
995
+ }
996
+ static isTokenExpired(token) {
997
+ const decoded = this.decodeToken(token);
998
+ if (!decoded) return true;
999
+ const now = Date.now() / 1e3;
1000
+ return decoded.exp < now;
1001
+ }
1002
+ };
1003
+ function useAuth(config = {}) {
1004
+ const configRef = useRef({ ...DEFAULT_CONFIG, ...config });
1005
+ const cfg = configRef.current;
1006
+ const [user, setUser] = useState(null);
1007
+ const [loading, setLoading] = useState(false);
1008
+ const [error, setError] = useState(null);
1009
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
1010
+ const refreshTimerRef = useRef(null);
1011
+ const storeToken = useCallback((token, refreshToken2) => {
1012
+ AuthStorage.setItem(cfg.tokenStorageKey, token);
1013
+ if (refreshToken2) {
1014
+ AuthStorage.setItem(`${cfg.tokenStorageKey}_refresh`, refreshToken2);
1015
+ }
1016
+ }, [cfg.tokenStorageKey]);
1017
+ const getStoredToken = useCallback(() => {
1018
+ return AuthStorage.getItem(cfg.tokenStorageKey);
1019
+ }, [cfg.tokenStorageKey]);
1020
+ const clearTokens = useCallback(() => {
1021
+ AuthStorage.removeItem(cfg.tokenStorageKey);
1022
+ AuthStorage.removeItem(`${cfg.tokenStorageKey}_refresh`);
1023
+ }, [cfg.tokenStorageKey]);
1024
+ const apiCall = useCallback(async (endpoint, options = {}) => {
1025
+ const token = getStoredToken();
1026
+ const url = `${cfg.apiEndpoint}${endpoint}`;
1027
+ const response = await fetch(url, {
1028
+ ...options,
1029
+ headers: {
1030
+ "Content-Type": "application/json",
1031
+ ...token && { Authorization: `Bearer ${token}` },
1032
+ ...options.headers
1033
+ }
1034
+ });
1035
+ if (!response.ok) {
1036
+ const error2 = await response.text();
1037
+ throw new Error(error2 || `HTTP ${response.status}`);
1038
+ }
1039
+ return response.json();
1040
+ }, [cfg.apiEndpoint, getStoredToken]);
1041
+ const login = useCallback(async (credentials) => {
1042
+ setLoading(true);
1043
+ setError(null);
1044
+ try {
1045
+ const response = await apiCall("/login", {
1046
+ method: "POST",
1047
+ body: JSON.stringify(credentials)
1048
+ });
1049
+ if (response.success && response.user && response.token) {
1050
+ setUser(response.user);
1051
+ setIsAuthenticated(true);
1052
+ storeToken(response.token, response.refreshToken);
1053
+ if (cfg.onAuthChange) {
1054
+ cfg.onAuthChange(response.user);
1055
+ }
1056
+ return { success: true, user: response.user, token: response.token };
1057
+ } else {
1058
+ const errorMsg = response.error || "Login failed";
1059
+ setError(errorMsg);
1060
+ if (cfg.onError) cfg.onError(errorMsg);
1061
+ return { success: false, error: errorMsg };
1062
+ }
1063
+ } catch (error2) {
1064
+ const errorMsg = error2 instanceof Error ? error2.message : "Login failed";
1065
+ setError(errorMsg);
1066
+ if (cfg.onError) cfg.onError(errorMsg);
1067
+ return { success: false, error: errorMsg };
1068
+ } finally {
1069
+ setLoading(false);
1070
+ }
1071
+ }, [apiCall, setUser, storeToken, cfg]);
1072
+ const logout = useCallback(async (options = {}) => {
1073
+ try {
1074
+ if (options.invalidateAllSessions) {
1075
+ await apiCall("/logout", { method: "POST" });
1076
+ }
1077
+ } catch (error2) {
1078
+ console.warn("Logout API call failed:", error2);
1079
+ } finally {
1080
+ setUser(null);
1081
+ setIsAuthenticated(false);
1082
+ clearTokens();
1083
+ if (refreshTimerRef.current) {
1084
+ clearInterval(refreshTimerRef.current);
1085
+ refreshTimerRef.current = null;
1086
+ }
1087
+ if (cfg.onAuthChange) {
1088
+ cfg.onAuthChange(null);
1089
+ }
1090
+ }
1091
+ }, [apiCall, clearTokens, cfg]);
1092
+ const register = useCallback(async (userData) => {
1093
+ setLoading(true);
1094
+ setError(null);
1095
+ try {
1096
+ const response = await apiCall("/register", {
1097
+ method: "POST",
1098
+ body: JSON.stringify(userData)
1099
+ });
1100
+ if (response.success && response.user && response.token) {
1101
+ setUser(response.user);
1102
+ setIsAuthenticated(true);
1103
+ storeToken(response.token, response.refreshToken);
1104
+ if (cfg.onAuthChange) {
1105
+ cfg.onAuthChange(response.user);
1106
+ }
1107
+ return { success: true, user: response.user, token: response.token };
1108
+ } else {
1109
+ const errorMsg = response.error || "Registration failed";
1110
+ setError(errorMsg);
1111
+ if (cfg.onError) cfg.onError(errorMsg);
1112
+ return { success: false, error: errorMsg };
1113
+ }
1114
+ } catch (error2) {
1115
+ const errorMsg = error2 instanceof Error ? error2.message : "Registration failed";
1116
+ setError(errorMsg);
1117
+ if (cfg.onError) cfg.onError(errorMsg);
1118
+ return { success: false, error: errorMsg };
1119
+ } finally {
1120
+ setLoading(false);
1121
+ }
1122
+ }, [apiCall, setUser, storeToken, cfg]);
1123
+ const updateProfile = useCallback(async (data) => {
1124
+ if (!user) {
1125
+ const error2 = "No user logged in";
1126
+ setError(error2);
1127
+ if (cfg.onError) cfg.onError(error2);
1128
+ return { success: false, error: error2 };
1129
+ }
1130
+ setLoading(true);
1131
+ setError(null);
1132
+ try {
1133
+ const response = await apiCall("/profile", {
1134
+ method: "PUT",
1135
+ body: JSON.stringify(data)
1136
+ });
1137
+ if (response.success && response.user) {
1138
+ setUser(response.user);
1139
+ if (cfg.onAuthChange) {
1140
+ cfg.onAuthChange(response.user);
1141
+ }
1142
+ return { success: true, user: response.user };
1143
+ } else {
1144
+ const errorMsg = response.error || "Profile update failed";
1145
+ setError(errorMsg);
1146
+ if (cfg.onError) cfg.onError(errorMsg);
1147
+ return { success: false, error: errorMsg };
1148
+ }
1149
+ } catch (error2) {
1150
+ const errorMsg = error2 instanceof Error ? error2.message : "Profile update failed";
1151
+ setError(errorMsg);
1152
+ if (cfg.onError) cfg.onError(errorMsg);
1153
+ return { success: false, error: errorMsg };
1154
+ } finally {
1155
+ setLoading(false);
1156
+ }
1157
+ }, [apiCall, user, setUser, cfg]);
1158
+ const refreshToken = useCallback(async () => {
1159
+ const refreshToken2 = AuthStorage.getItem(`${cfg.tokenStorageKey}_refresh`);
1160
+ if (!refreshToken2) {
1161
+ return { success: false, error: "No refresh token available" };
1162
+ }
1163
+ try {
1164
+ const response = await apiCall("/refresh", {
1165
+ method: "POST",
1166
+ body: JSON.stringify({ refreshToken: refreshToken2 })
1167
+ });
1168
+ if (response.success && response.token && response.user) {
1169
+ setUser(response.user);
1170
+ storeToken(response.token, response.refreshToken);
1171
+ if (cfg.onAuthChange) {
1172
+ cfg.onAuthChange(response.user);
1173
+ }
1174
+ return { success: true, user: response.user, token: response.token };
1175
+ } else {
1176
+ await logout();
1177
+ return { success: false, error: "Session expired" };
1178
+ }
1179
+ } catch (error2) {
1180
+ await logout();
1181
+ return { success: false, error: "Session expired" };
1182
+ }
1183
+ }, [apiCall, setUser, storeToken, logout, cfg]);
1184
+ const resetError = useCallback(() => {
1185
+ setError(null);
1186
+ }, []);
1187
+ useEffect(() => {
1188
+ const token = getStoredToken();
1189
+ const storedUser = AuthStorage.getUser(cfg.userStorageKey);
1190
+ if (token && storedUser && !TokenManager.isTokenExpired(token)) {
1191
+ setUser(storedUser);
1192
+ setIsAuthenticated(true);
1193
+ if (cfg.onAuthChange) {
1194
+ cfg.onAuthChange(storedUser);
1195
+ }
1196
+ } else if (token && TokenManager.isTokenExpired(token)) {
1197
+ refreshToken();
1198
+ } else {
1199
+ setLoading(false);
1200
+ }
1201
+ return () => {
1202
+ if (refreshTimerRef.current) {
1203
+ clearInterval(refreshTimerRef.current);
1204
+ }
1205
+ };
1206
+ }, []);
1207
+ return {
1208
+ user,
1209
+ loading,
1210
+ error,
1211
+ isAuthenticated,
1212
+ login,
1213
+ logout,
1214
+ register,
1215
+ updateProfile,
1216
+ refreshToken,
1217
+ resetError
1218
+ };
1219
+ }
1220
+ function useIsAuthenticated() {
1221
+ const { isAuthenticated } = useAuth();
1222
+ return isAuthenticated;
1223
+ }
1224
+ function useCurrentUser() {
1225
+ const { user } = useAuth();
1226
+ return user;
1227
+ }
1228
+ function useHasRole(role) {
1229
+ const { user } = useAuth();
1230
+ return user?.role === role;
1231
+ }
1232
+ function useIsAdmin() {
1233
+ return useHasRole("admin" /* ADMIN */);
1234
+ }
836
1235
 
837
1236
  // src/stats/index.ts
838
- function formatNumber2(num) {
1237
+ function formatNumber(num) {
839
1238
  if (num >= 1e6) {
840
1239
  return (num / 1e6).toFixed(1) + "M";
841
1240
  }
@@ -893,9 +1292,9 @@ function findMinMax(data, field) {
893
1292
  };
894
1293
  }
895
1294
 
896
- // src/auth/index.ts
897
- var auth_exports = {};
898
- __export(auth_exports, {
1295
+ // src/authentication/index.ts
1296
+ var authentication_exports = {};
1297
+ __export(authentication_exports, {
899
1298
  getRefreshToken: () => getRefreshToken,
900
1299
  getToken: () => getToken,
901
1300
  getTokens: () => getTokens,
@@ -1039,6 +1438,109 @@ function calculateSimilarity(str1, str2) {
1039
1438
  const similarity = common / Math.max(str1.length, str2.length);
1040
1439
  return similarity;
1041
1440
  }
1441
+
1442
+ // src/string/index.ts
1443
+ function textToSlug(text) {
1444
+ return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s-]/g, "").trim().replace(/^-+|-+$/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
1445
+ }
1446
+ function truncate(text, maxLength, suffix = "...") {
1447
+ if (text.length <= maxLength) return text;
1448
+ return text.slice(0, maxLength - suffix.length) + suffix;
1449
+ }
1450
+ function getInitials(name, maxInitials = 2) {
1451
+ return name.split(" ").filter((word) => word.length > 0).map((word) => word[0]).join("").toUpperCase().slice(0, maxInitials);
1452
+ }
1453
+ function formatPhone(phone) {
1454
+ const digits = phone.replace(/\D/g, "");
1455
+ if (digits.length === 11) {
1456
+ return digits.replace(/(\d{2})(\d{5})(\d{4})/, "($1) $2-$3");
1457
+ }
1458
+ return digits.replace(/(\d{2})(\d{4})(\d{4})/, "($1) $2-$3");
1459
+ }
1460
+ function formatCPF(cpf) {
1461
+ const digits = cpf.replace(/\D/g, "");
1462
+ return digits.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4");
1463
+ }
1464
+ function formatCNPJ(cnpj) {
1465
+ const digits = cnpj.replace(/\D/g, "");
1466
+ return digits.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, "$1.$2.$3/$4-$5");
1467
+ }
1468
+ function isCPF(cpf) {
1469
+ const digits = cpf.replace(/\D/g, "");
1470
+ if (digits.length !== 11 || /^(\d)\1{10}$/.test(digits)) {
1471
+ return false;
1472
+ }
1473
+ let sum = 0;
1474
+ for (let i = 0; i < 9; i++) {
1475
+ sum += parseInt(digits.charAt(i)) * (10 - i);
1476
+ }
1477
+ let remainder = sum * 10 % 11;
1478
+ if (remainder === 10 || remainder === 11) remainder = 0;
1479
+ if (remainder !== parseInt(digits.charAt(9))) {
1480
+ return false;
1481
+ }
1482
+ sum = 0;
1483
+ for (let i = 0; i < 10; i++) {
1484
+ sum += parseInt(digits.charAt(i)) * (11 - i);
1485
+ }
1486
+ remainder = sum * 10 % 11;
1487
+ if (remainder === 10 || remainder === 11) remainder = 0;
1488
+ if (remainder !== parseInt(digits.charAt(10))) {
1489
+ return false;
1490
+ }
1491
+ return true;
1492
+ }
1493
+ function isCNPJ(cnpj) {
1494
+ const digits = cnpj.replace(/\D/g, "");
1495
+ if (digits.length !== 14 || /^(\d)\1{13}$/.test(digits)) {
1496
+ return false;
1497
+ }
1498
+ const weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
1499
+ let sum = 0;
1500
+ for (let i = 0; i < 12; i++) {
1501
+ sum += parseInt(digits.charAt(i)) * weights1[i];
1502
+ }
1503
+ let remainder = sum % 11;
1504
+ const digit1 = remainder < 2 ? 0 : 11 - remainder;
1505
+ if (digit1 !== parseInt(digits.charAt(12))) {
1506
+ return false;
1507
+ }
1508
+ const weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
1509
+ sum = 0;
1510
+ for (let i = 0; i < 13; i++) {
1511
+ sum += parseInt(digits.charAt(i)) * weights2[i];
1512
+ }
1513
+ remainder = sum % 11;
1514
+ const digit2 = remainder < 2 ? 0 : 11 - remainder;
1515
+ if (digit2 !== parseInt(digits.charAt(13))) {
1516
+ return false;
1517
+ }
1518
+ return true;
1519
+ }
1520
+
1521
+ // src/number/index.ts
1522
+ function formatCurrency(value, locale = DEFAULT_LOCALE, options) {
1523
+ const currency = CURRENCY_MAP[locale];
1524
+ return new Intl.NumberFormat(locale, {
1525
+ style: "currency",
1526
+ currency,
1527
+ ...options
1528
+ }).format(value);
1529
+ }
1530
+ function formatNumber2(value, decimals = 0, locale = DEFAULT_LOCALE) {
1531
+ return new Intl.NumberFormat(locale, {
1532
+ minimumFractionDigits: decimals,
1533
+ maximumFractionDigits: decimals
1534
+ }).format(value);
1535
+ }
1536
+ function formatCompact(value, decimals = 1, locale = DEFAULT_LOCALE) {
1537
+ return new Intl.NumberFormat(locale, {
1538
+ notation: "compact",
1539
+ compactDisplay: "short",
1540
+ minimumFractionDigits: decimals,
1541
+ maximumFractionDigits: decimals
1542
+ }).format(value);
1543
+ }
1042
1544
  function usePasswordStrength(password, options = {}) {
1043
1545
  const {
1044
1546
  minLength = 8,
@@ -1229,6 +1731,7 @@ function usePasswordStrength(password, options = {}) {
1229
1731
  // src/pt-br.ts
1230
1732
  var pt_br_exports = {};
1231
1733
  __export(pt_br_exports, {
1734
+ default: () => pt_br_default,
1232
1735
  formatCompact: () => formatCompact2,
1233
1736
  formatCurrency: () => formatCurrency2,
1234
1737
  formatDate: () => formatDate2,
@@ -1250,7 +1753,7 @@ function formatCurrency2(value, options) {
1250
1753
  return formatCurrency(value, "pt-BR", options);
1251
1754
  }
1252
1755
  function formatNumber3(value, decimals = 0) {
1253
- return formatNumber(value, decimals, "pt-BR");
1756
+ return formatNumber2(value, decimals, "pt-BR");
1254
1757
  }
1255
1758
  function formatCompact2(value, decimals = 1) {
1256
1759
  return formatCompact(value, decimals, "pt-BR");
@@ -1258,13 +1761,166 @@ function formatCompact2(value, decimals = 1) {
1258
1761
  function translateStatus2(status) {
1259
1762
  return translateStatus(status, "pt-BR");
1260
1763
  }
1764
+ var pt_br_default = {
1765
+ formatDate: formatDate2,
1766
+ formatDateTime: formatDateTime2,
1767
+ formatRelativeDate: formatRelativeDate2,
1768
+ formatCurrency: formatCurrency2,
1769
+ formatNumber: formatNumber3,
1770
+ formatCompact: formatCompact2,
1771
+ translateStatus: translateStatus2
1772
+ };
1773
+
1774
+ // src/text/index.ts
1775
+ var text_exports = {};
1776
+ __export(text_exports, {
1777
+ calculateReadingTime: () => calculateReadingTime,
1778
+ capitalize: () => capitalize,
1779
+ cleanText: () => cleanText2,
1780
+ countWords: () => countWords2,
1781
+ extractInitials: () => extractInitials,
1782
+ generateAvatarUrl: () => generateAvatarUrl,
1783
+ generateDynamicAvatarUrl: () => generateDynamicAvatarUrl,
1784
+ generateUniqueId: () => generateUniqueId,
1785
+ getAvatarColorFromName: () => getAvatarColorFromName,
1786
+ isEmpty: () => isEmpty,
1787
+ isValidAvatarUrl: () => isValidAvatarUrl,
1788
+ normalizeSpaces: () => normalizeSpaces,
1789
+ truncateText: () => truncateText
1790
+ });
1791
+ function extractInitials(name, maxChars = 2) {
1792
+ if (!name || !name.trim()) {
1793
+ return "";
1794
+ }
1795
+ const words = name.trim().split(/\s+/);
1796
+ const initials = words.slice(0, maxChars).map((word) => word.charAt(0).toUpperCase()).join("");
1797
+ return initials;
1798
+ }
1799
+ function generateAvatarUrl(name, size = 200, backgroundColor = "0891b2", textColor = "fff") {
1800
+ const encodedName = encodeURIComponent(name);
1801
+ return `https://ui-avatars.com/api/?name=${encodedName}&size=${size}&background=${backgroundColor}&color=${textColor}&font-size=0.5`;
1802
+ }
1803
+ function isValidAvatarUrl(url) {
1804
+ if (!url || typeof url !== "string") {
1805
+ return false;
1806
+ }
1807
+ try {
1808
+ new URL(url);
1809
+ return true;
1810
+ } catch {
1811
+ return false;
1812
+ }
1813
+ }
1814
+ function getAvatarColorFromName(name) {
1815
+ if (!name || typeof name !== "string") {
1816
+ return "#0891b2";
1817
+ }
1818
+ let hash = 0;
1819
+ for (let i = 0; i < name.length; i++) {
1820
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
1821
+ }
1822
+ const colors = [
1823
+ "#0891b2",
1824
+ // cyan-600
1825
+ "#9333ea",
1826
+ // purple-600
1827
+ "#db2777",
1828
+ // pink-600
1829
+ "#059669",
1830
+ // emerald-600
1831
+ "#2563eb",
1832
+ // blue-600
1833
+ "#f97316",
1834
+ // orange-500
1835
+ "#dc2626",
1836
+ // red-600
1837
+ "#7c3aed"
1838
+ // violet-600
1839
+ ];
1840
+ const index = Math.abs(hash) % colors.length;
1841
+ return colors[index];
1842
+ }
1843
+ function generateDynamicAvatarUrl(name, size = 200) {
1844
+ const color = getAvatarColorFromName(name);
1845
+ const colorHex = color.replace("#", "");
1846
+ return generateAvatarUrl(name, size, colorHex, "fff");
1847
+ }
1848
+ function generateUniqueId(text, prefix = "", suffix = "") {
1849
+ const slug = text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim().substring(0, 50);
1850
+ const parts = [prefix, slug, suffix].filter(Boolean);
1851
+ return parts.join("-");
1852
+ }
1853
+ function truncateText(text, maxLength, suffix = "...") {
1854
+ if (!text || text.length <= maxLength) {
1855
+ return text || "";
1856
+ }
1857
+ return text.substring(0, maxLength - suffix.length) + suffix;
1858
+ }
1859
+ function capitalize(text, options = {}) {
1860
+ if (!text) return "";
1861
+ const { firstWordOnly = false, lowerRest = false } = options;
1862
+ if (firstWordOnly) {
1863
+ return text.charAt(0).toUpperCase() + (lowerRest ? text.slice(1).toLowerCase() : text.slice(1));
1864
+ }
1865
+ if (lowerRest) {
1866
+ return text.replace(/\b\w/g, (char) => char.toUpperCase()).toLowerCase();
1867
+ }
1868
+ return text.replace(/\b\w/g, (char) => char.toUpperCase());
1869
+ }
1870
+ function cleanText2(text, allowSpaces = true) {
1871
+ if (!text) return "";
1872
+ const pattern = allowSpaces ? /[^\w\s]/g : /[^\w]/g;
1873
+ return text.replace(pattern, "");
1874
+ }
1875
+ function countWords2(text) {
1876
+ if (!text || !text.trim()) {
1877
+ return 0;
1878
+ }
1879
+ return text.trim().split(/\s+/).length;
1880
+ }
1881
+ function isEmpty(text) {
1882
+ return !text || !text.trim();
1883
+ }
1884
+ function normalizeSpaces(text, options = {}) {
1885
+ if (!text) return "";
1886
+ const { newlines = false } = options;
1887
+ let cleaned = text;
1888
+ if (newlines) {
1889
+ cleaned = cleaned.replace(/\s+/g, " ");
1890
+ } else {
1891
+ cleaned = cleaned.replace(/\s+/g, " ");
1892
+ }
1893
+ return cleaned.trim();
1894
+ }
1895
+ function calculateReadingTime(content, wordsPerMinute = 200) {
1896
+ let text = "";
1897
+ if (typeof content === "object" && content !== null) {
1898
+ const extractText = (node) => {
1899
+ if (!node) return "";
1900
+ let result = "";
1901
+ if (node.text) {
1902
+ result += node.text + " ";
1903
+ }
1904
+ if (Array.isArray(node.content)) {
1905
+ result += node.content.map(extractText).join(" ");
1906
+ }
1907
+ return result;
1908
+ };
1909
+ text = extractText(content);
1910
+ } else if (typeof content === "string") {
1911
+ text = content.replace(/<[^>]*>/g, "");
1912
+ }
1913
+ const words = text.trim().split(/\s+/).filter((word) => word.length > 0).length;
1914
+ const time = Math.ceil(words / wordsPerMinute);
1915
+ return time > 0 ? time : 1;
1916
+ }
1261
1917
 
1262
1918
  // src/index.ts
1263
1919
  var textProcessing = text_exports;
1264
1920
  var datetime = date_exports;
1265
- var authentication = auth_exports;
1921
+ var authentication = authentication_exports;
1266
1922
  var stateManagement = status_exports;
1267
1923
 
1268
- export { CURRENCY_MAP, DEFAULT_LOCALE, authentication, calculateChange, calculateMovingAverage, calculateReadingTime, capitalize, cleanText, copyToClipboard, countWords, datetime, downloadFile, extractInitials, findMinMax, formatCurrency, formatDate, formatDateTime, formatNumber2 as formatNumber, formatPercentage, formatRelativeDate, fuzzySearch, generateAvatarUrl, generateDynamicAvatarUrl, generateMockChartData, generateUniqueId, getAvatarColorFromName, getElementPosition, getRefreshToken, getStatusColor, getStatusVariant, getToken, getTokens, groupDataByPeriod, hasToken, isDarkMode, isElementVisible, isEmpty, isMobile, isValidAvatarUrl, isValidDate, normalizeSpaces, onDarkModeChange, onReducedMotionChange, prefersReducedMotion, pt_br_exports as ptBR, removeToken, scrollToElement, scrollToPosition, scrollToTop, searchContent, searchWithScore, setRefreshToken, setToken, setTokens, smoothScrollTo, stateManagement, textProcessing, textToSlug, toISOString, translatePostStatus, translateStatus, truncateText, usePasswordStrength, validateEmail, validateMessage, validatePassword, validatePhone, validateSlug, validateText, validateUrl, validateUsername };
1924
+ export { CURRENCY_MAP, DEFAULT_LOCALE, adjustBrightness, adjustHue, adjustSaturation, authentication, calculateChange, calculateMovingAverage, calculateReadingTime, capitalize, cleanText2 as cleanText, containsText, copyToClipboard, countCharacters, countWords2 as countWords, createEmptyTiptapContent, darken, datetime, downloadFile, extractInitials, extractTextFromTiptap, findMinMax, formatCNPJ, formatCPF, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercentage, formatPhone, formatRelativeDate, fuzzySearch, generateAvatarUrl, generateDynamicAvatarUrl, generateExcerpt, generateMockChartData, generateUniqueId, getAnalogousPalette, getAvatarColorFromName, getComplementary, getContentStats, getElementPosition, getInitials, getReadingTime, getRefreshToken, getStatusColor, getStatusVariant, getToken, getTokens, groupDataByPeriod, hasToken, hexToHsl, hexToRgb, hexToRgba, hslToHex, isCNPJ, isCPF, isContentEmpty, isDarkMode, isElementVisible, isEmpty, isMobile, isValidAvatarUrl, isValidDate, lighten, normalizeSpaces, onDarkModeChange, onReducedMotionChange, prefersReducedMotion, pt_br_exports as ptBR, removeToken, replaceText, rgbToHex, scrollToElement, scrollToPosition, scrollToTop, searchContent, searchWithScore, setRefreshToken, setToken, setTokens, smoothScrollTo, stateManagement, textProcessing, textToSlug, toISOString, translatePostStatus, translateStatus, truncate, truncateText, useAuth, useCurrentUser, useHasRole, useIsAdmin, useIsAuthenticated, usePasswordStrength, validateContrast, validateEmail, validateMessage, validatePassword, validatePhone, validateSlug, validateText, validateUrl, validateUsername };
1269
1925
  //# sourceMappingURL=index.mjs.map
1270
1926
  //# sourceMappingURL=index.mjs.map