@oxyhq/core 9.2.3 → 10.0.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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/i18n/index.js +22 -2
- package/dist/cjs/i18n/locales/en-US.json +4 -1
- package/dist/cjs/i18n/locales/es-ES.json +4 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +4 -1
- package/dist/cjs/i18n/locales/locales/es-ES.json +4 -1
- package/dist/cjs/index.js +10 -5
- package/dist/cjs/mixins/OxyServices.assets.js +10 -6
- package/dist/cjs/mixins/OxyServices.language.js +11 -10
- package/dist/cjs/mixins/OxyServices.privacy.js +6 -0
- package/dist/cjs/mixins/OxyServices.user.js +40 -0
- package/dist/cjs/server/safeFetch.js +3 -3
- package/dist/cjs/session/SessionClient.js +1 -1
- package/dist/cjs/shared/utils/colorUtils.js +9 -9
- package/dist/cjs/utils/languageUtils.js +195 -158
- package/dist/cjs/utils/platform.js +9 -2
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/i18n/index.js +22 -2
- package/dist/esm/i18n/locales/en-US.json +4 -1
- package/dist/esm/i18n/locales/es-ES.json +4 -1
- package/dist/esm/i18n/locales/locales/en-US.json +4 -1
- package/dist/esm/i18n/locales/locales/es-ES.json +4 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/mixins/OxyServices.assets.js +10 -6
- package/dist/esm/mixins/OxyServices.language.js +12 -11
- package/dist/esm/mixins/OxyServices.privacy.js +6 -0
- package/dist/esm/mixins/OxyServices.user.js +40 -0
- package/dist/esm/server/safeFetch.js +3 -3
- package/dist/esm/session/SessionClient.js +1 -1
- package/dist/esm/shared/utils/colorUtils.js +9 -9
- package/dist/esm/utils/languageUtils.js +189 -156
- package/dist/esm/utils/platform.js +9 -2
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/mixins/OxyServices.language.d.ts +4 -4
- package/dist/types/mixins/OxyServices.user.d.ts +30 -0
- package/dist/types/models/interfaces.d.ts +8 -0
- package/dist/types/session/accountDialogController.d.ts +1 -1
- package/dist/types/utils/languageUtils.d.ts +86 -24
- package/package.json +3 -3
- package/src/HttpService.ts +2 -2
- package/src/crypto/keyManager.ts +3 -3
- package/src/crypto/recoveryPhrase.ts +1 -1
- package/src/i18n/index.ts +21 -2
- package/src/i18n/locales/en-US.json +4 -1
- package/src/i18n/locales/es-ES.json +4 -1
- package/src/index.ts +8 -2
- package/src/mixins/OxyServices.assets.ts +15 -11
- package/src/mixins/OxyServices.language.ts +31 -17
- package/src/mixins/OxyServices.privacy.ts +6 -0
- package/src/mixins/OxyServices.security.ts +1 -1
- package/src/mixins/OxyServices.user.ts +57 -0
- package/src/models/interfaces.ts +8 -0
- package/src/server/safeFetch.ts +3 -3
- package/src/session/SessionClient.ts +1 -1
- package/src/session/accountDialogController.ts +1 -1
- package/src/shared/utils/colorUtils.ts +11 -11
- package/src/shared/utils/errorUtils.ts +1 -1
- package/src/utils/__tests__/languageUtils.test.ts +219 -0
- package/src/utils/avatarUtils.ts +1 -1
- package/src/utils/languageUtils.ts +223 -162
- package/src/utils/platform.ts +21 -3
- package/src/utils/requestUtils.ts +3 -3
- package/src/utils/sessionUtils.ts +2 -2
package/dist/esm/i18n/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import jaJP from './locales/ja-JP.json' with { type: "json" };
|
|
|
9
9
|
import koKR from './locales/ko-KR.json' with { type: "json" };
|
|
10
10
|
import zhCN from './locales/zh-CN.json' with { type: "json" };
|
|
11
11
|
import arSA from './locales/ar-SA.json' with { type: "json" };
|
|
12
|
+
import { getBaseLanguage } from '../utils/languageUtils.js';
|
|
12
13
|
const DICTS = {
|
|
13
14
|
'en': enUS,
|
|
14
15
|
'en-US': enUS,
|
|
@@ -34,11 +35,30 @@ const DICTS = {
|
|
|
34
35
|
'ar-SA': arSA,
|
|
35
36
|
};
|
|
36
37
|
const FALLBACK = 'en-US';
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a locale tag to the key of the dictionary that should serve it.
|
|
40
|
+
*
|
|
41
|
+
* Account locales are full BCP-47 tags (e.g. `es-MX`, `pt-BR`, `fr-CA`), but a
|
|
42
|
+
* translation dictionary is shipped per base language. Resolution order:
|
|
43
|
+
* 1. Exact dictionary for the tag (e.g. `es-ES`).
|
|
44
|
+
* 2. Dictionary for the base subtag (e.g. `es-MX` → `es`).
|
|
45
|
+
* 3. The English fallback.
|
|
46
|
+
*/
|
|
47
|
+
function resolveLang(locale) {
|
|
48
|
+
if (locale) {
|
|
49
|
+
if (DICTS[locale])
|
|
50
|
+
return locale;
|
|
51
|
+
const base = getBaseLanguage(locale);
|
|
52
|
+
if (DICTS[base])
|
|
53
|
+
return base;
|
|
54
|
+
}
|
|
55
|
+
return FALLBACK;
|
|
56
|
+
}
|
|
37
57
|
function getNested(obj, path) {
|
|
38
58
|
return path.split('.').reduce((acc, key) => (acc && acc[key] != null ? acc[key] : undefined), obj);
|
|
39
59
|
}
|
|
40
60
|
export function translate(locale, key, vars) {
|
|
41
|
-
const lang = locale
|
|
61
|
+
const lang = resolveLang(locale);
|
|
42
62
|
const dict = DICTS[lang] || DICTS[FALLBACK];
|
|
43
63
|
let val = getNested(dict, key);
|
|
44
64
|
// Per-key fallback to the English dictionary when a key is missing from the
|
|
@@ -58,6 +78,6 @@ export function translate(locale, key, vars) {
|
|
|
58
78
|
return val;
|
|
59
79
|
}
|
|
60
80
|
export function hasKey(locale, key) {
|
|
61
|
-
const lang = locale
|
|
81
|
+
const lang = resolveLang(locale);
|
|
62
82
|
return getNested(DICTS[lang], key) != null || getNested(DICTS[FALLBACK], key) != null;
|
|
63
83
|
}
|
|
@@ -169,9 +169,12 @@
|
|
|
169
169
|
},
|
|
170
170
|
"language": {
|
|
171
171
|
"title": "Language",
|
|
172
|
-
"subtitle": "Choose your
|
|
172
|
+
"subtitle": "Choose the languages you use. The first is your primary interface language.",
|
|
173
173
|
"current": "Current Language",
|
|
174
|
+
"selected": "Your languages",
|
|
174
175
|
"available": "Available Languages",
|
|
176
|
+
"primary": "Primary",
|
|
177
|
+
"remove": "Remove",
|
|
175
178
|
"changed": "Language changed to {{lang}}",
|
|
176
179
|
"saveFailed": "Failed to save language preference",
|
|
177
180
|
"search": "Search languages"
|
|
@@ -123,9 +123,12 @@
|
|
|
123
123
|
},
|
|
124
124
|
"language": {
|
|
125
125
|
"title": "Idioma",
|
|
126
|
-
"subtitle": "Elige tu idioma
|
|
126
|
+
"subtitle": "Elige los idiomas que usas. El primero es tu idioma de interfaz principal.",
|
|
127
127
|
"current": "Idioma actual",
|
|
128
|
+
"selected": "Tus idiomas",
|
|
128
129
|
"available": "Idiomas disponibles",
|
|
130
|
+
"primary": "Principal",
|
|
131
|
+
"remove": "Quitar",
|
|
129
132
|
"changed": "Idioma cambiado a {{lang}}",
|
|
130
133
|
"saveFailed": "Error al guardar la preferencia de idioma",
|
|
131
134
|
"search": "Buscar idiomas"
|
|
@@ -169,9 +169,12 @@
|
|
|
169
169
|
},
|
|
170
170
|
"language": {
|
|
171
171
|
"title": "Language",
|
|
172
|
-
"subtitle": "Choose your
|
|
172
|
+
"subtitle": "Choose the languages you use. The first is your primary interface language.",
|
|
173
173
|
"current": "Current Language",
|
|
174
|
+
"selected": "Your languages",
|
|
174
175
|
"available": "Available Languages",
|
|
176
|
+
"primary": "Primary",
|
|
177
|
+
"remove": "Remove",
|
|
175
178
|
"changed": "Language changed to {{lang}}",
|
|
176
179
|
"saveFailed": "Failed to save language preference",
|
|
177
180
|
"search": "Search languages"
|
|
@@ -123,9 +123,12 @@
|
|
|
123
123
|
},
|
|
124
124
|
"language": {
|
|
125
125
|
"title": "Idioma",
|
|
126
|
-
"subtitle": "Elige tu idioma
|
|
126
|
+
"subtitle": "Elige los idiomas que usas. El primero es tu idioma de interfaz principal.",
|
|
127
127
|
"current": "Idioma actual",
|
|
128
|
+
"selected": "Tus idiomas",
|
|
128
129
|
"available": "Idiomas disponibles",
|
|
130
|
+
"primary": "Principal",
|
|
131
|
+
"remove": "Quitar",
|
|
129
132
|
"changed": "Idioma cambiado a {{lang}}",
|
|
130
133
|
"saveFailed": "Error al guardar la preferencia de idioma",
|
|
131
134
|
"search": "Buscar idiomas"
|
package/dist/esm/index.js
CHANGED
|
@@ -75,7 +75,7 @@ export { TopicType, TopicSource } from './models/Topic.js';
|
|
|
75
75
|
// ---------------------------------------------------------------------------
|
|
76
76
|
// Languages
|
|
77
77
|
// ---------------------------------------------------------------------------
|
|
78
|
-
export { SUPPORTED_LANGUAGES, getLanguageMetadata, getLanguageName, getNativeLanguageName,
|
|
78
|
+
export { SUPPORTED_LANGUAGES, FALLBACK_LOCALE, getBaseLanguage, normalizeLocale, isSupportedLocale, getLanguageMetadata, getLanguageName, getNativeLanguageName, isRTLLocale, getUserLanguages, getPrimaryLanguage, } from './utils/languageUtils.js';
|
|
79
79
|
// ---------------------------------------------------------------------------
|
|
80
80
|
// Platform detection
|
|
81
81
|
// ---------------------------------------------------------------------------
|
|
@@ -365,14 +365,18 @@ export function OxyServicesAssetsMixin(Base) {
|
|
|
365
365
|
errorMessage = error.message || errorMessage;
|
|
366
366
|
}
|
|
367
367
|
else if (error && typeof error === 'object') {
|
|
368
|
-
|
|
369
|
-
|
|
368
|
+
const errObj = error;
|
|
369
|
+
if ('message' in errObj) {
|
|
370
|
+
errorMessage = String(errObj.message) || errorMessage;
|
|
370
371
|
}
|
|
371
|
-
else if (
|
|
372
|
-
errorMessage =
|
|
372
|
+
else if (typeof errObj.error === 'string') {
|
|
373
|
+
errorMessage = errObj.error;
|
|
373
374
|
}
|
|
374
|
-
else if (
|
|
375
|
-
|
|
375
|
+
else if (errObj.data && typeof errObj.data === 'object') {
|
|
376
|
+
const dataObj = errObj.data;
|
|
377
|
+
if (dataObj.message) {
|
|
378
|
+
errorMessage = String(dataObj.message);
|
|
379
|
+
}
|
|
376
380
|
}
|
|
377
381
|
}
|
|
378
382
|
else if (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Language Methods Mixin
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { normalizeLocale, getPrimaryLanguage, getLanguageMetadata, getLanguageName, getNativeLanguageName } from '../utils/languageUtils.js';
|
|
5
5
|
import { loadAsyncStorage } from '@oxyhq/protocol';
|
|
6
6
|
import { isDev } from '../shared/utils/debugUtils.js';
|
|
7
7
|
export function OxyServicesLanguageMixin(Base) {
|
|
@@ -55,29 +55,30 @@ export function OxyServicesLanguageMixin(Base) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* Get the current
|
|
58
|
+
* Get the current locale from the user profile or local storage.
|
|
59
59
|
* @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
|
|
60
|
-
* @returns The current
|
|
60
|
+
* @returns The current BCP-47 locale (e.g., 'en-US') or null if not set
|
|
61
61
|
*/
|
|
62
62
|
async getCurrentLanguage(storageKeyPrefix = 'oxy_session') {
|
|
63
63
|
try {
|
|
64
|
-
// First try
|
|
64
|
+
// First try the authenticated user's primary account locale.
|
|
65
65
|
try {
|
|
66
66
|
const user = await this.getCurrentUser();
|
|
67
|
-
const
|
|
68
|
-
if (
|
|
69
|
-
return
|
|
67
|
+
const primary = getPrimaryLanguage(user);
|
|
68
|
+
if (primary) {
|
|
69
|
+
return primary;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
catch
|
|
73
|
-
//
|
|
72
|
+
catch {
|
|
73
|
+
// Not authenticated or the profile fetch failed — fall through to the
|
|
74
|
+
// locally stored preference below.
|
|
74
75
|
}
|
|
75
|
-
// Fall back to
|
|
76
|
+
// Fall back to the locally stored locale preference.
|
|
76
77
|
const storage = await this.getStorage();
|
|
77
78
|
const storageKey = `${storageKeyPrefix}_language`;
|
|
78
79
|
const storedLanguage = await storage.getItem(storageKey);
|
|
79
80
|
if (storedLanguage) {
|
|
80
|
-
return
|
|
81
|
+
return normalizeLocale(storedLanguage) ?? storedLanguage;
|
|
81
82
|
}
|
|
82
83
|
return null;
|
|
83
84
|
}
|
|
@@ -70,6 +70,9 @@ export function OxyServicesPrivacyMixin(Base) {
|
|
|
70
70
|
cache: false,
|
|
71
71
|
});
|
|
72
72
|
this.clearCacheEntry('GET:/privacy/blocked');
|
|
73
|
+
// The block changed the viewer's graph (`blockedIds`) — bust the cached
|
|
74
|
+
// consolidated `GET /users/me/graph` so the next read reflects it.
|
|
75
|
+
this.clearCacheEntry('GET:/users/me/graph');
|
|
73
76
|
return result;
|
|
74
77
|
}
|
|
75
78
|
catch (error) {
|
|
@@ -93,6 +96,9 @@ export function OxyServicesPrivacyMixin(Base) {
|
|
|
93
96
|
cache: false,
|
|
94
97
|
});
|
|
95
98
|
this.clearCacheEntry('GET:/privacy/blocked');
|
|
99
|
+
// Symmetric to blockUser: the unblock changed the viewer's `blockedIds`,
|
|
100
|
+
// so bust the consolidated `GET /users/me/graph` cache.
|
|
101
|
+
this.clearCacheEntry('GET:/users/me/graph');
|
|
96
102
|
return result;
|
|
97
103
|
}
|
|
98
104
|
catch (error) {
|
|
@@ -509,6 +509,10 @@ export function OxyServicesUserMixin(Base) {
|
|
|
509
509
|
try {
|
|
510
510
|
const result = await this.makeRequest('POST', `/users/${userId}/follow`, undefined, { cache: false });
|
|
511
511
|
this.clearCacheEntry(`GET:/users/${userId}/follow-status`);
|
|
512
|
+
// The follow changed the viewer's graph — bust the cached consolidated
|
|
513
|
+
// `GET /users/me/graph` so the next read reflects the new following/
|
|
514
|
+
// mutual set instead of the stale pre-write snapshot.
|
|
515
|
+
this.clearCacheEntry('GET:/users/me/graph');
|
|
512
516
|
return result;
|
|
513
517
|
}
|
|
514
518
|
catch (error) {
|
|
@@ -533,6 +537,8 @@ export function OxyServicesUserMixin(Base) {
|
|
|
533
537
|
for (const id of userIds) {
|
|
534
538
|
this.clearCacheEntry(`GET:/users/${id}/follow-status`);
|
|
535
539
|
}
|
|
540
|
+
// The batch changed the viewer's graph — bust the consolidated cache.
|
|
541
|
+
this.clearCacheEntry('GET:/users/me/graph');
|
|
536
542
|
return result;
|
|
537
543
|
}
|
|
538
544
|
catch (error) {
|
|
@@ -557,6 +563,8 @@ export function OxyServicesUserMixin(Base) {
|
|
|
557
563
|
for (const id of userIds) {
|
|
558
564
|
this.clearCacheEntry(`GET:/users/${id}/follow-status`);
|
|
559
565
|
}
|
|
566
|
+
// The batch changed the viewer's graph — bust the consolidated cache.
|
|
567
|
+
this.clearCacheEntry('GET:/users/me/graph');
|
|
560
568
|
return result;
|
|
561
569
|
}
|
|
562
570
|
catch (error) {
|
|
@@ -571,6 +579,8 @@ export function OxyServicesUserMixin(Base) {
|
|
|
571
579
|
const result = await this.makeRequest('DELETE', `/users/${userId}/follow`, undefined, { cache: false });
|
|
572
580
|
// Bust the cached follow-status so a remount reads fresh truth (see `followUser`).
|
|
573
581
|
this.clearCacheEntry(`GET:/users/${userId}/follow-status`);
|
|
582
|
+
// The unfollow changed the viewer's graph — bust the consolidated cache.
|
|
583
|
+
this.clearCacheEntry('GET:/users/me/graph');
|
|
574
584
|
return result;
|
|
575
585
|
}
|
|
576
586
|
catch (error) {
|
|
@@ -702,6 +712,36 @@ export function OxyServicesUserMixin(Base) {
|
|
|
702
712
|
throw this.handleError(error);
|
|
703
713
|
}
|
|
704
714
|
}
|
|
715
|
+
/**
|
|
716
|
+
* Get the authenticated VIEWER's OWN social graph — the accounts they follow,
|
|
717
|
+
* the subset who follow back (mutuals), and the accounts they have blocked —
|
|
718
|
+
* as ONE ids-only payload. The viewer is derived server-side from the SDK's
|
|
719
|
+
* auth token (never a param).
|
|
720
|
+
*
|
|
721
|
+
* Consolidates what were three separate round trips (`getUserFollowing` /
|
|
722
|
+
* `getMutualUserIds` / `getBlockedUsers`) into a single request so a consumer
|
|
723
|
+
* can prime its whole viewer graph at once. Mirrors {@link getMutualUserIds}'s
|
|
724
|
+
* caching posture (2-minute identity-scoped cache); the follow/unfollow/block/
|
|
725
|
+
* unblock write methods bust this entry so a local mutation is reflected
|
|
726
|
+
* immediately. An anonymous caller resolves to empty lists.
|
|
727
|
+
*/
|
|
728
|
+
async getViewerGraph() {
|
|
729
|
+
try {
|
|
730
|
+
const response = await this.makeRequest('GET', '/users/me/graph', undefined, {
|
|
731
|
+
cache: true,
|
|
732
|
+
cacheTTL: 2 * 60 * 1000, // 2 minutes cache
|
|
733
|
+
});
|
|
734
|
+
const graph = response.data;
|
|
735
|
+
return {
|
|
736
|
+
followingIds: graph?.followingIds || [],
|
|
737
|
+
mutualIds: graph?.mutualIds || [],
|
|
738
|
+
blockedIds: graph?.blockedIds || [],
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
catch (error) {
|
|
742
|
+
throw this.handleError(error);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
705
745
|
/**
|
|
706
746
|
* Get notifications
|
|
707
747
|
*/
|
|
@@ -155,7 +155,7 @@ function ipv6ToGroups(ip) {
|
|
|
155
155
|
for (const part of segment.split(':')) {
|
|
156
156
|
if (!/^[0-9a-fA-F]{1,4}$/.test(part))
|
|
157
157
|
return null;
|
|
158
|
-
groups.push(parseInt(part, 16));
|
|
158
|
+
groups.push(Number.parseInt(part, 16));
|
|
159
159
|
}
|
|
160
160
|
return groups;
|
|
161
161
|
};
|
|
@@ -205,8 +205,8 @@ function extractEmbeddedIpv4(ip) {
|
|
|
205
205
|
// Hex form "::ffff:0102:0304" → 1.2.3.4
|
|
206
206
|
const hexMapped = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
|
|
207
207
|
if (hexMapped) {
|
|
208
|
-
const hi = parseInt(hexMapped[1], 16);
|
|
209
|
-
const lo = parseInt(hexMapped[2], 16);
|
|
208
|
+
const hi = Number.parseInt(hexMapped[1], 16);
|
|
209
|
+
const lo = Number.parseInt(hexMapped[2], 16);
|
|
210
210
|
return `${(hi >> 8) & 0xff}.${hi & 0xff}.${(lo >> 8) & 0xff}.${lo & 0xff}`;
|
|
211
211
|
}
|
|
212
212
|
return null;
|
|
@@ -274,7 +274,7 @@ export class SessionClient {
|
|
|
274
274
|
transports: ['websocket'],
|
|
275
275
|
autoConnect: true,
|
|
276
276
|
reconnection: true,
|
|
277
|
-
reconnectionAttempts:
|
|
277
|
+
reconnectionAttempts: Number.POSITIVE_INFINITY,
|
|
278
278
|
reconnectionDelay: 1000,
|
|
279
279
|
reconnectionDelayMax: 10000,
|
|
280
280
|
auth: (cb) => {
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
*/
|
|
22
22
|
export const darkenColor = (color, factor = 0.6) => {
|
|
23
23
|
const hex = color.replace('#', '');
|
|
24
|
-
const r = parseInt(hex.substring(0, 2), 16);
|
|
25
|
-
const g = parseInt(hex.substring(2, 4), 16);
|
|
26
|
-
const b = parseInt(hex.substring(4, 6), 16);
|
|
24
|
+
const r = Number.parseInt(hex.substring(0, 2), 16);
|
|
25
|
+
const g = Number.parseInt(hex.substring(2, 4), 16);
|
|
26
|
+
const b = Number.parseInt(hex.substring(4, 6), 16);
|
|
27
27
|
const newR = Math.max(0, Math.round(r * (1 - factor)));
|
|
28
28
|
const newG = Math.max(0, Math.round(g * (1 - factor)));
|
|
29
29
|
const newB = Math.max(0, Math.round(b * (1 - factor)));
|
|
@@ -43,9 +43,9 @@ export const darkenColor = (color, factor = 0.6) => {
|
|
|
43
43
|
*/
|
|
44
44
|
export const lightenColor = (color, factor = 0.3) => {
|
|
45
45
|
const hex = color.replace('#', '');
|
|
46
|
-
const r = parseInt(hex.substring(0, 2), 16);
|
|
47
|
-
const g = parseInt(hex.substring(2, 4), 16);
|
|
48
|
-
const b = parseInt(hex.substring(4, 6), 16);
|
|
46
|
+
const r = Number.parseInt(hex.substring(0, 2), 16);
|
|
47
|
+
const g = Number.parseInt(hex.substring(2, 4), 16);
|
|
48
|
+
const b = Number.parseInt(hex.substring(4, 6), 16);
|
|
49
49
|
const newR = Math.min(255, Math.round(r + (255 - r) * factor));
|
|
50
50
|
const newG = Math.min(255, Math.round(g + (255 - g) * factor));
|
|
51
51
|
const newB = Math.min(255, Math.round(b + (255 - b) * factor));
|
|
@@ -66,9 +66,9 @@ export const hexToRgb = (hex) => {
|
|
|
66
66
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
67
67
|
return result
|
|
68
68
|
? {
|
|
69
|
-
r: parseInt(result[1], 16),
|
|
70
|
-
g: parseInt(result[2], 16),
|
|
71
|
-
b: parseInt(result[3], 16),
|
|
69
|
+
r: Number.parseInt(result[1], 16),
|
|
70
|
+
g: Number.parseInt(result[2], 16),
|
|
71
|
+
b: Number.parseInt(result[3], 16),
|
|
72
72
|
}
|
|
73
73
|
: null;
|
|
74
74
|
};
|