@foxford/sdk 5.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/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@foxford/sdk",
3
+ "version": "5.0.0",
4
+ "description": "Foxford sdk for external projects",
5
+ "keywords": [],
6
+ "license": "MIT",
7
+ "author": "Foxford Co",
8
+ "homepage": "https://github.com/foxford/frontend-platform",
9
+ "bugs": "https://github.com/foxford/frontend-platform/issues",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/foxford/frontend-platform.git"
13
+ },
14
+ "maintainers": [
15
+ {
16
+ "name": "Roman Olin",
17
+ "email": "r.v.olin@foxford.ru",
18
+ "team": "@frontend/core"
19
+ }
20
+ ],
21
+ "type": "module",
22
+ "flowTypes": "./index.js.flow",
23
+ "peerDependencies": {
24
+ "camelcase-keys-deep": "^0.1.0",
25
+ "decamelize-keys-deep": "^0.1.1",
26
+ "js-levenshtein": "^1.1.6",
27
+ "lodash": "^4.17.23",
28
+ "@foxford/services": "1.5.0",
29
+ "@foxford/types": "1.2.0"
30
+ },
31
+ "main": "./index.js",
32
+ "module": "./index.mjs",
33
+ "exports": {
34
+ ".": {
35
+ "flowTypes": "./index.js.flow",
36
+ "import": "./index.mjs",
37
+ "require": "./index.js",
38
+ "types": "./index.d.ts"
39
+ },
40
+ "./plugins/autocomplete-email": {
41
+ "flowTypes": "./plugins/autocomplete-email.js.flow",
42
+ "import": "./plugins/autocomplete-email.mjs",
43
+ "require": "./plugins/autocomplete-email.js",
44
+ "types": "./plugins/autocomplete-email.d.ts"
45
+ },
46
+ "./plugins/confirm-phone": {
47
+ "flowTypes": "./plugins/confirm-phone.js.flow",
48
+ "import": "./plugins/confirm-phone.mjs",
49
+ "require": "./plugins/confirm-phone.js",
50
+ "types": "./plugins/confirm-phone.d.ts"
51
+ }
52
+ },
53
+ "files": [
54
+ "README.mdx",
55
+ "index.cjs",
56
+ "index.d.cts",
57
+ "index.d.ts",
58
+ "index.js",
59
+ "index.js.flow",
60
+ "package.json",
61
+ "plugins"
62
+ ],
63
+ "sha": "673ae4d",
64
+ "scripts": {}
65
+ }
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/plugins/autocomplete-email/index.ts
31
+ var autocomplete_email_exports = {};
32
+ __export(autocomplete_email_exports, {
33
+ EmailAutocomplete: () => EmailAutocomplete
34
+ });
35
+ module.exports = __toCommonJS(autocomplete_email_exports);
36
+ var import_js_levenshtein = __toESM(require("js-levenshtein"), 1);
37
+ var import_merge = __toESM(require("lodash/merge"), 1);
38
+ var DEFAULT_DOMAINS = [
39
+ "gmail.com",
40
+ "mail.ru",
41
+ "yandex.ru",
42
+ "icloud.com",
43
+ "bk.ru",
44
+ "list.ru",
45
+ "inbox.ru",
46
+ "rambler.ru",
47
+ "internet.ru",
48
+ "ya.ru",
49
+ "mail.com",
50
+ "yandex.com",
51
+ "foxford.ru",
52
+ "hotmail.com",
53
+ "vk.com",
54
+ "yahoo.com",
55
+ "outlook.com",
56
+ "yandex.by",
57
+ "yandex.kz",
58
+ "xmail.ru",
59
+ "tut.by",
60
+ "msn.com",
61
+ "me.com"
62
+ ];
63
+ var DEFAULT_OPTIONS = {
64
+ emailDomains: DEFAULT_DOMAINS,
65
+ suggestionClass: "emailAutoSugg",
66
+ suggestionColor: "var(--silver, #b8b8b8)",
67
+ suitableColor: "var(--silver, #b8b8b8)",
68
+ suitableEmailColor: "var(--accent, #1A96F6)",
69
+ suitableFontSize: "12px",
70
+ suitableLevenshteinTreshold: 5,
71
+ suitableLineHeight: "1.7"
72
+ };
73
+ var KEY_CODES = {
74
+ BACKSPACE: "Backspace",
75
+ DELETE: "Delete",
76
+ DOWN_ARROW: "ArrowDown",
77
+ ENTER: "Enter",
78
+ RIGHT_ARROW: "ArrowRight",
79
+ TAB: "Tab"
80
+ };
81
+ var EmailAutocomplete = class {
82
+ constructor(node, options) {
83
+ this.options = DEFAULT_OPTIONS;
84
+ this.containerValue = null;
85
+ this.suggOverlay = null;
86
+ this.value = "";
87
+ this.suggestion = "";
88
+ this.leftOffset = null;
89
+ this.suitableExists = false;
90
+ this.suitableContainer = null;
91
+ this.bindListeners = () => {
92
+ if (this.suggOverlay) this.suggOverlay.addEventListener("mousedown touchstart", this.onFocus);
93
+ this.node.addEventListener("keyup", this.displaySuggestion);
94
+ this.node.addEventListener("paste", this.onPaste);
95
+ this.node.addEventListener("blur", this.autocomplete);
96
+ this.node.addEventListener("keydown", this.onKeydown);
97
+ };
98
+ this.onFocus = () => {
99
+ this.node.focus();
100
+ };
101
+ this.onKeydown = (e) => {
102
+ if ([KEY_CODES.BACKSPACE, KEY_CODES.DELETE].includes(e.code)) {
103
+ this.hideSuitableEmail();
104
+ return;
105
+ }
106
+ if (![KEY_CODES.DOWN_ARROW, KEY_CODES.ENTER, KEY_CODES.RIGHT_ARROW, KEY_CODES.TAB].includes(e.code) || KEY_CODES.TAB === e.code && !this.suggestion)
107
+ return;
108
+ this.node.addEventListener("blur", this.autocomplete);
109
+ const { target } = e;
110
+ if (target instanceof HTMLElement) {
111
+ target.blur();
112
+ }
113
+ };
114
+ this.onPaste = (e) => {
115
+ if (!e.clipboardData) throw new Error("Not found clipboardData");
116
+ const text = e.clipboardData.getData("text/plain");
117
+ this.value = text;
118
+ this.node.removeEventListener("blur", this.autocomplete);
119
+ const list = this.findSuitableEmails(text);
120
+ this.showSuitableEmail(list);
121
+ };
122
+ this.findSuitableEmails = (text) => {
123
+ const strArr = text.split("@");
124
+ let lastPart = text;
125
+ if (strArr.length <= 1) return [];
126
+ lastPart = strArr.pop() || "";
127
+ const distances = (this.options.emailDomains || []).map((item) => ({ distance: (0, import_js_levenshtein.default)(lastPart, item), item }));
128
+ const treshold = this.options.suitableLevenshteinTreshold;
129
+ const preparedDistances = distances.sort((a, b) => a.distance - b.distance).filter((item) => item.distance <= treshold);
130
+ const suitableList = preparedDistances.slice(0, 3).map((obj) => `${strArr.join("")}@${obj.item}`);
131
+ return suitableList;
132
+ };
133
+ this.showSuitableEmail = (suitableList) => {
134
+ if (suitableList.length === 0) return;
135
+ if (this.suitableContainer) this.hideSuitableEmail();
136
+ const suitableEmail = suitableList[0];
137
+ if (this.value === suitableEmail) return;
138
+ const text = document.createTextNode("\u0412\u043E\u0437\u043C\u043E\u0436\u043D\u043E, \u0432\u044B \u0438\u043C\u0435\u043B\u0438 \u0432 \u0432\u0438\u0434\u0443 ");
139
+ const email = document.createElement("span");
140
+ const suitableMessage = document.createElement("span");
141
+ suitableMessage.style.display = "block";
142
+ suitableMessage.style.fontFamily = this.nodeStyle.getPropertyValue("font-family");
143
+ suitableMessage.style.fontWeight = this.nodeStyle.getPropertyValue("font-weight");
144
+ suitableMessage.style.letterSpacing = this.nodeStyle.getPropertyValue("letter-spacing");
145
+ suitableMessage.style.color = this.options.suitableColor || "";
146
+ suitableMessage.style.fontSize = this.options.suitableFontSize || "";
147
+ suitableMessage.style.lineHeight = this.options.suitableLineHeight || "";
148
+ email.style.fontFamily = this.nodeStyle.getPropertyValue("font-family");
149
+ email.style.fontWeight = this.nodeStyle.getPropertyValue("font-weight");
150
+ email.style.letterSpacing = this.nodeStyle.getPropertyValue("letter-spacing");
151
+ email.style.color = this.options.suitableEmailColor || "";
152
+ email.style.fontSize = this.options.suitableFontSize || "";
153
+ email.style.lineHeight = this.options.suitableLineHeight || "";
154
+ email.style.cursor = "pointer";
155
+ if (suitableEmail) email.textContent = suitableEmail;
156
+ suitableMessage.append(text);
157
+ suitableMessage.append(email);
158
+ this.suitableContainer = suitableMessage;
159
+ this.node.after(this.suitableContainer);
160
+ email.addEventListener("click", this.onClickSuitableEmail, { once: true });
161
+ this.suitableExists = true;
162
+ if (typeof this.options.onShowSuitableEmail === "function") this.options.onShowSuitableEmail();
163
+ };
164
+ this.hideSuitableEmail = () => {
165
+ if (this.suitableContainer) {
166
+ this.suitableContainer.remove();
167
+ this.suitableContainer = null;
168
+ }
169
+ if (this.suggOverlay) {
170
+ this.suggOverlay.textContent = "";
171
+ }
172
+ this.suitableExists = false;
173
+ if (typeof this.options.onHideSuitableEmail === "function") this.options.onHideSuitableEmail();
174
+ };
175
+ this.onClickSuitableEmail = (e) => {
176
+ e.preventDefault();
177
+ e.stopPropagation();
178
+ if (!(e.target instanceof HTMLSpanElement)) return;
179
+ this.changeValue(e.target.textContent || "");
180
+ this.hideSuitableEmail();
181
+ this.node.addEventListener("blur", this.autocomplete);
182
+ if (typeof this.options.onClickSuitableEmail === "function") this.options.onClickSuitableEmail();
183
+ };
184
+ this.autocomplete = (e) => {
185
+ e.stopPropagation();
186
+ if (this.suitableExists) this.hideSuitableEmail();
187
+ if (typeof this.suggestion === "undefined" || typeof this.suggestion === "string" && this.suggestion.length < 1) {
188
+ const list = this.findSuitableEmails(this.value || "");
189
+ this.showSuitableEmail(list);
190
+ return false;
191
+ }
192
+ const value = `${this.value || ""}${this.suggestion || ""}`;
193
+ this.clear();
194
+ this.changeValue(value);
195
+ return true;
196
+ };
197
+ this.changeValue = (value) => {
198
+ if (typeof this.options.onAutocomplete === "function") this.options.onAutocomplete(value);
199
+ else this.node.value = value;
200
+ };
201
+ this.displaySuggestion = (event) => {
202
+ this.value = this.node.value;
203
+ this.suggestion = this.suggest(this.value);
204
+ if (!this.suggOverlay || !this.containerValue) return;
205
+ if (!this.suggestion.length) {
206
+ this.suggOverlay.textContent = "";
207
+ } else {
208
+ event.preventDefault();
209
+ }
210
+ this.suggOverlay.textContent = this.suggestion;
211
+ this.containerValue.textContent = this.value || "";
212
+ if (this.leftOffset === null) {
213
+ let w = this.node.clientWidth;
214
+ w -= parseFloat(this.nodeStyle.paddingLeft) + parseFloat(this.nodeStyle.paddingRight);
215
+ this.leftOffset = (this.node.offsetWidth - w) / 2;
216
+ }
217
+ const cvalWidth = this.containerValue.clientWidth;
218
+ if (this.node.offsetWidth > cvalWidth) {
219
+ this.suggOverlay.style.left = `${this.leftOffset + cvalWidth}px`;
220
+ }
221
+ };
222
+ this.destroy = () => {
223
+ var _a;
224
+ (_a = this.suggOverlay) == null ? void 0 : _a.removeEventListener("mousedown touchstart", this.onFocus);
225
+ this.node.removeEventListener("keyup", this.displaySuggestion);
226
+ this.node.removeEventListener("paste", this.onPaste);
227
+ this.node.removeEventListener("blur", this.autocomplete);
228
+ this.node.removeEventListener("keydown", this.onKeydown);
229
+ this.suggOverlay = null;
230
+ this.containerValue = null;
231
+ this.suitableContainer = null;
232
+ };
233
+ this.clear = () => {
234
+ if (this.suggOverlay instanceof HTMLSpanElement) this.suggOverlay.textContent = "";
235
+ if (this.containerValue instanceof HTMLSpanElement) this.containerValue.textContent = "";
236
+ };
237
+ if (!(node instanceof HTMLInputElement)) throw new TypeError("Node must be html input element");
238
+ this.node = node;
239
+ this.nodeRects = this.node.getBoundingClientRect();
240
+ this.options = (0, import_merge.default)(this.options, options);
241
+ this.suggOverlay = document.createElement("span");
242
+ this.containerValue = document.createElement("span");
243
+ this.suitableContainer = document.createElement("span");
244
+ this.nodeStyle = getComputedStyle(this.node);
245
+ }
246
+ apply() {
247
+ if (this.node.eac !== void 0 && this.node.eac !== null) return;
248
+ this.node.eac = this;
249
+ const parentNode = this.node.parentElement;
250
+ let topOffset = 0;
251
+ if (parentNode) {
252
+ const parentRects = parentNode.getBoundingClientRect();
253
+ topOffset = Math.abs(parentRects.top - this.nodeRects.top);
254
+ }
255
+ this.containerValue = document.createElement("span");
256
+ this.containerValue.style.visibility = "hidden";
257
+ this.containerValue.style.position = "absolute";
258
+ this.containerValue.style.display = "inline-block";
259
+ this.containerValue.style.fontFamily = this.nodeStyle.getPropertyValue("font-family");
260
+ this.containerValue.style.fontWeight = this.nodeStyle.getPropertyValue("font-weight");
261
+ this.containerValue.style.fontSize = this.nodeStyle.getPropertyValue("font-size");
262
+ this.containerValue.style.letterSpacing = this.nodeStyle.getPropertyValue("letter-spacing");
263
+ const border = (this.node.offsetHeight - this.node.clientHeight) / 2;
264
+ this.suggOverlay = document.createElement("span");
265
+ if (typeof this.options.suggestionClass === "string") this.suggOverlay.classList.add(this.options.suggestionClass);
266
+ this.suggOverlay.style.display = "flex";
267
+ this.suggOverlay.style.alignItems = "center";
268
+ this.suggOverlay.style.position = "absolute";
269
+ this.suggOverlay.style.top = `${topOffset}px`;
270
+ this.suggOverlay.style.left = "0";
271
+ this.suggOverlay.style.height = `${this.node.offsetHeight}px`;
272
+ this.suggOverlay.style.paddingTop = `${parseInt(this.nodeStyle.getPropertyValue("padding-top"), 10) + border}px`;
273
+ this.suggOverlay.style.paddingBottom = `${parseInt(this.nodeStyle.getPropertyValue("padding-bottom"), 10) + border}px`;
274
+ this.suggOverlay.style.lineHeight = this.nodeStyle.getPropertyValue("line-height");
275
+ this.suggOverlay.style.fontSize = this.nodeStyle.getPropertyValue("font-size");
276
+ this.suggOverlay.style.color = this.options.suggestionColor || "";
277
+ this.containerValue.style.fontFamily = this.nodeStyle.getPropertyValue("font-family");
278
+ this.containerValue.style.fontWeight = this.nodeStyle.getPropertyValue("font-weight");
279
+ this.containerValue.style.fontSize = this.nodeStyle.getPropertyValue("font-size");
280
+ this.containerValue.style.letterSpacing = this.nodeStyle.getPropertyValue("letter-spacing");
281
+ this.node.after(this.containerValue);
282
+ this.containerValue.after(this.suggOverlay);
283
+ this.bindListeners();
284
+ }
285
+ suggest(str) {
286
+ const strArr = str.split("@");
287
+ let lastPart = str;
288
+ if (strArr.length > 1) {
289
+ lastPart = strArr.pop() || "";
290
+ if (!lastPart.length) {
291
+ return "";
292
+ }
293
+ } else {
294
+ return "";
295
+ }
296
+ const match = (this.options.emailDomains || []).filter((domain) => {
297
+ return domain.indexOf(lastPart) === 0;
298
+ }).shift() || "";
299
+ return match.replace(lastPart, "");
300
+ }
301
+ };
302
+ // Annotate the CommonJS export names for ESM import in node:
303
+ 0 && (module.exports = {
304
+ EmailAutocomplete
305
+ });
@@ -0,0 +1,49 @@
1
+ import { S as SdkPlugin } from './types-CFv3gSlt.cjs';
2
+ import '@foxford/services';
3
+ import '@foxford/types';
4
+
5
+ interface EacOptions {
6
+ emailDomains?: Array<string>;
7
+ suggestionClass?: string;
8
+ suggestionColor?: string;
9
+ onAutocomplete?: (_value: string) => void;
10
+ onShowSuitableEmail?: () => void;
11
+ onClickSuitableEmail?: () => void;
12
+ onHideSuitableEmail?: () => void;
13
+ suitableColor?: string;
14
+ suitableEmailColor?: string;
15
+ suitableFontSize?: string;
16
+ suitableLineHeight?: string;
17
+ suitableLevenshteinTreshold?: number;
18
+ }
19
+ declare class EmailAutocomplete implements SdkPlugin {
20
+ private node;
21
+ private nodeRects;
22
+ private nodeStyle;
23
+ private options;
24
+ private containerValue;
25
+ private suggOverlay;
26
+ private value;
27
+ private suggestion;
28
+ private leftOffset;
29
+ private suitableExists;
30
+ private suitableContainer;
31
+ constructor(node: HTMLInputElement, options?: EacOptions);
32
+ apply(): void;
33
+ private bindListeners;
34
+ private onFocus;
35
+ private onKeydown;
36
+ private onPaste;
37
+ private findSuitableEmails;
38
+ private showSuitableEmail;
39
+ private hideSuitableEmail;
40
+ private onClickSuitableEmail;
41
+ private suggest;
42
+ private autocomplete;
43
+ private changeValue;
44
+ private displaySuggestion;
45
+ destroy: () => void;
46
+ clear: () => void;
47
+ }
48
+
49
+ export { EmailAutocomplete };
@@ -0,0 +1,49 @@
1
+ import type { SdkPlugin } from '../index.d.ts';
2
+ import '@foxford/services';
3
+ import '@foxford/types';
4
+
5
+ interface EacOptions {
6
+ emailDomains?: Array<string>;
7
+ suggestionClass?: string;
8
+ suggestionColor?: string;
9
+ onAutocomplete?: (_value: string) => void;
10
+ onShowSuitableEmail?: () => void;
11
+ onClickSuitableEmail?: () => void;
12
+ onHideSuitableEmail?: () => void;
13
+ suitableColor?: string;
14
+ suitableEmailColor?: string;
15
+ suitableFontSize?: string;
16
+ suitableLineHeight?: string;
17
+ suitableLevenshteinTreshold?: number;
18
+ }
19
+ declare class EmailAutocomplete implements SdkPlugin {
20
+ private node;
21
+ private nodeRects;
22
+ private nodeStyle;
23
+ private options;
24
+ private containerValue;
25
+ private suggOverlay;
26
+ private value;
27
+ private suggestion;
28
+ private leftOffset;
29
+ private suitableExists;
30
+ private suitableContainer;
31
+ constructor(node: HTMLInputElement, options?: EacOptions);
32
+ apply(): void;
33
+ private bindListeners;
34
+ private onFocus;
35
+ private onKeydown;
36
+ private onPaste;
37
+ private findSuitableEmails;
38
+ private showSuitableEmail;
39
+ private hideSuitableEmail;
40
+ private onClickSuitableEmail;
41
+ private suggest;
42
+ private autocomplete;
43
+ private changeValue;
44
+ private displaySuggestion;
45
+ destroy: () => void;
46
+ clear: () => void;
47
+ }
48
+
49
+ export { EmailAutocomplete };