@topvisor/ui 0.0.34 → 0.0.35

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.
Files changed (267) hide show
  1. package/.storybook/TopTheme.js +82 -0
  2. package/.storybook/TopThemeManager.js +44 -0
  3. package/.storybook/main.ts +43 -0
  4. package/.storybook/manager.ts +28 -0
  5. package/.storybook/preview-head.html +16 -0
  6. package/.storybook/preview.ts +48 -0
  7. package/.storybook/vue/coreDecorator.ts +19 -0
  8. package/.storybook/vue/vModelDecorator.ts +27 -0
  9. package/.vscode/extensions.json +11 -0
  10. package/.vscode/keybindings.example.json +121 -0
  11. package/.vscode/settings.json +46 -0
  12. package/Dockerfile +3 -0
  13. package/NPM.md +25 -0
  14. package/PUBLISH.md +18 -0
  15. package/README.md +19 -52
  16. package/STORYBOOK.md +27 -0
  17. package/USE_IN_PROJECT.md +29 -0
  18. package/build/afterBuild.sh +12 -0
  19. package/build/cssModules.ts +39 -0
  20. package/build/plugin/amdFix.ts +46 -0
  21. package/build/rollup.config.ts +18 -0
  22. package/nbproject/project.properties +11 -0
  23. package/nbproject/project.xml +9 -0
  24. package/package.json +68 -19
  25. package/public/README.md +63 -0
  26. package/src/components/common/common.ts +1 -0
  27. package/src/components/common/icon/icon.ts +4 -0
  28. package/src/components/common/icon/icon.vue +15 -0
  29. package/src/components/component.ts +133 -0
  30. package/src/components/forms/button/button.stories.ts +112 -0
  31. package/src/components/forms/button/button.ts +51 -0
  32. package/src/components/forms/button/button.vue +75 -0
  33. package/src/components/forms/button/stories/README.md +35 -0
  34. package/src/components/forms/button/stories/overview.vue +33 -0
  35. package/src/components/forms/button/style/button.css +124 -0
  36. package/src/components/forms/button/style/style-outline.css +42 -0
  37. package/src/components/forms/button/style/style-soft.css +31 -0
  38. package/src/components/forms/button/style/style-transparent.css +35 -0
  39. package/src/components/forms/checkbox/checkbox.stories.ts +33 -0
  40. package/src/components/forms/checkbox/checkbox.ts +23 -0
  41. package/src/components/forms/checkbox/checkbox.vue +135 -0
  42. package/src/components/forms/checkbox/stories/overview.vue +171 -0
  43. package/src/components/forms/controlLabel/controlLabel.stories.ts +38 -0
  44. package/src/components/forms/controlLabel/controlLabel.ts +4 -0
  45. package/src/components/forms/controlLabel/controlLabel.vue +48 -0
  46. package/src/components/forms/forms.ts +10 -0
  47. package/src/components/forms/helpers.ts +10 -0
  48. package/src/components/forms/hint/hint.stories.ts +46 -0
  49. package/src/components/forms/hint/hint.ts +8 -0
  50. package/src/components/forms/hint/hint.vue +32 -0
  51. package/src/components/forms/input/input.stories.ts +31 -0
  52. package/src/components/forms/input/input.ts +34 -0
  53. package/src/components/forms/input/input.vue +170 -0
  54. package/src/components/forms/input/stories/overview.vue +61 -0
  55. package/src/components/forms/inputDate/datepicker.css +233 -0
  56. package/src/components/forms/inputDate/datepicker.ts +101 -0
  57. package/src/components/forms/inputDate/inputDate.stories.ts +41 -0
  58. package/src/components/forms/inputDate/inputDate.ts +4 -0
  59. package/src/components/forms/inputDate/inputDate.vue +127 -0
  60. package/src/components/forms/inputDate/stories/overview.vue +35 -0
  61. package/src/components/forms/radio/radio.stories.ts +34 -0
  62. package/src/components/forms/radio/radio.ts +15 -0
  63. package/src/components/forms/radio/radio.vue +107 -0
  64. package/src/components/forms/radio/stories/overview.vue +79 -0
  65. package/src/components/forms/select/select.stories.ts +34 -0
  66. package/src/components/forms/select/select.ts +36 -0
  67. package/src/components/forms/select/select.vue +253 -0
  68. package/src/components/forms/select/stories/exampleOptions.ts +71 -0
  69. package/src/components/forms/select/stories/overview.vue +60 -0
  70. package/src/components/forms/switcher/stories/overview.vue +139 -0
  71. package/src/components/forms/switcher/switcher.stories.ts +33 -0
  72. package/src/components/forms/switcher/switcher.ts +22 -0
  73. package/src/components/forms/switcher/switcher.vue +113 -0
  74. package/src/components/forms/textarea/stories/overview.vue +62 -0
  75. package/src/components/forms/textarea/textarea.stories.ts +33 -0
  76. package/src/components/forms/textarea/textarea.ts +38 -0
  77. package/src/components/forms/textarea/textarea.vue +119 -0
  78. package/src/components/formsExt/editArea/editArea.stories.ts +72 -0
  79. package/src/components/formsExt/editArea/editArea.ts +25 -0
  80. package/src/components/formsExt/editArea/editArea.vue +172 -0
  81. package/src/components/formsExt/editArea/stories/README.md +17 -0
  82. package/src/components/formsExt/editArea/stories/overview.vue +66 -0
  83. package/src/components/formsExt/editInput/editInput.stories.ts +36 -0
  84. package/src/components/formsExt/editInput/editInput.ts +20 -0
  85. package/src/components/formsExt/editInput/editInput.vue +57 -0
  86. package/src/components/formsExt/editInput/stories/overview.vue +54 -0
  87. package/src/components/formsExt/formsExt.ts +3 -0
  88. package/src/components/formsExt/radioGroup/radioGroup.stories.ts +51 -0
  89. package/src/components/formsExt/radioGroup/radioGroup.ts +28 -0
  90. package/src/components/formsExt/radioGroup/radioGroup.vue +143 -0
  91. package/src/components/formsExt/radioGroup/stories/overview.vue +78 -0
  92. package/src/components/formsExt/radioGroup/styles/top-scrollBar.css +52 -0
  93. package/src/components/helper.js +10 -0
  94. package/src/components/helpersStories.ts +151 -0
  95. package/src/components/popup/lib/popup.globalEvents.js +205 -0
  96. package/src/components/popup/lib/popup.js +702 -0
  97. package/src/components/popup/lib/worker.globalEvents.js +78 -0
  98. package/src/components/popup/lib/worker.js +232 -0
  99. package/src/components/popup/popup/listItem.vue +42 -0
  100. package/src/components/popup/popup/opener.vue +74 -0
  101. package/src/components/popup/popup/popup.stories.ts +68 -0
  102. package/src/components/popup/popup/popup.ts +93 -0
  103. package/src/components/popup/popup/popup.vue +95 -0
  104. package/src/components/popup/popup/stories/README.md +34 -0
  105. package/src/components/popup/popup/stories/listItems.vue +44 -0
  106. package/src/components/popup/popup/stories/listSubItems.vue +52 -0
  107. package/src/components/popup/popup/stories/overview.vue +208 -0
  108. package/src/components/popup/popup/style/popup.css +243 -0
  109. package/src/components/popup/popup/style/popup.m.css +71 -0
  110. package/src/components/popup/popup/style/popup.pc.css +28 -0
  111. package/src/components/popup/popup.ts +3 -0
  112. package/src/components/popup/worker.ts +1 -0
  113. package/src/components/tabs/tabs/content.vue +24 -0
  114. package/src/components/tabs/tabs/stories/README.md +10 -0
  115. package/src/components/tabs/tabs/tab.vue +52 -0
  116. package/src/components/tabs/tabs/tabs.stories.ts +171 -0
  117. package/src/components/tabs/tabs/tabs.ts +22 -0
  118. package/src/components/tabs/tabs/tabs.vue +64 -0
  119. package/src/components/tabs/tabs.ts +3 -0
  120. package/src/core/base/Colors.stories.ts +15 -0
  121. package/src/core/base/Layout.stories.ts +15 -0
  122. package/src/core/base/Properties.stories.ts +15 -0
  123. package/src/core/base/base.mdx +21 -0
  124. package/src/core/core/core.ts +144 -0
  125. package/src/core/core/events.ts +54 -0
  126. package/src/core/core/options.ts +15 -0
  127. package/src/core/core/state.ts +44 -0
  128. package/src/core/directives/tooltip.ts +55 -0
  129. package/src/core/theme/Colors.stories.ts +15 -0
  130. package/src/core/theme/Properties.stories.ts +15 -0
  131. package/src/core/theme/theme.mdx +15 -0
  132. package/src/core/utils/date.ts +164 -0
  133. package/src/core/utils/device.ts +48 -0
  134. package/src/core/utils/dom.ts +185 -0
  135. package/src/core//320/235/320/260/320/261/320/276/321/200 /320/270/320/272/320/276/320/275/320/276/320/272/gallery.vue" +72 -0
  136. package/src/core//320/235/320/260/320/261/320/276/321/200 /320/270/320/272/320/276/320/275/320/276/320/272//320/235/320/260/320/261/320/276/321/200 /320/270/320/272/320/276/320/275/320/276/320/272.mdx" +31 -0
  137. package/src/core//320/235/320/260/320/261/320/276/321/200 /320/270/320/272/320/276/320/275/320/276/320/272//320/235/320/260/320/261/320/276/321/200 /320/270/320/272/320/276/320/275/320/276/320/272.stories.ts" +14 -0
  138. package/src/docs/CSS/FAQ.mdx +43 -0
  139. package/src/docs/CSS//320/236/320/261/321/211/320/270/320/265 /320/274/320/276/320/264/320/270/321/204/320/270/320/272/320/260/321/202/320/276/321/200/321/213.mdx" +156 -0
  140. package/src/docs/CSS//320/237/320/265/321/200/320/265/320/274/320/265/320/275/320/275/321/213/320/265.mdx +47 -0
  141. package/src/docs/CSS//320/237/321/200/320/265/320/264/320/277/321/200/320/276/321/206/320/265/321/201/321/201/320/276/321/200/321/213.mdx +15 -0
  142. package/src/docs/CSS//320/240/320/265/320/272/320/276/320/274/320/265/320/275/320/264/320/260/321/206/320/270/320/270 /320/221/320/255/320/234.mdx" +49 -0
  143. package/src/docs/CSS//320/241/321/202/320/270/320/273/320/270.md +53 -0
  144. package/src/docs/CSS//320/241/321/202/320/270/320/273/320/270.mdx +4 -0
  145. package/src/docs/CSS//320/247/321/202/320/276 /321/202/320/260/320/272/320/276/320/265 css /320/274/320/276/320/264/321/203/320/273/321/214.mdx" +53 -0
  146. package/src/docs/ROADMAP.md +17 -0
  147. package/src/docs/Roadmap.mdx +4 -0
  148. package/src/docs//320/222/320/262/320/265/320/264/320/265/320/275/320/270/320/265 /320/262 Storybook.mdx" +323 -0
  149. package/src/docs//320/232/320/276/320/274/320/277/320/276/320/275/320/265/320/275/321/202/321/213.mdx +20 -0
  150. package/src/docs//320/237/320/276/320/273/320/265/320/267/320/275/320/260/321/217 /320/270/320/275/321/204/320/276/321/200/320/274/320/260/321/206/320/270/321/217.mdx" +8 -0
  151. package/src/docs//320/241/321/202/320/260/320/275/320/264/320/260/321/200/321/202/321/213 /320/272/320/276/320/264/320/260/IDE.mdx" +42 -0
  152. package/src/docs//320/241/321/202/320/260/320/275/320/264/320/260/321/200/321/202/321/213 /320/272/320/276/320/264/320/260//320/233/320/270/320/275/321/202/320/265/321/200.mdx" +72 -0
  153. package/src/docs//320/241/321/202/320/260/320/275/320/264/320/260/321/200/321/202/321/213 /320/272/320/276/320/264/320/260//320/241/321/202/320/260/320/275/320/264/320/260/321/200/321/202/321/213 /320/272/320/276/320/264/320/260.mdx" +29 -0
  154. package/src/globals.d.ts +1 -0
  155. package/{icomoon → src/resources/icomoon}/demo-files/demo.css +161 -161
  156. package/{icomoon → src/resources/icomoon}/demo-files/demo.js +30 -30
  157. package/{icomoon → src/resources/icomoon}/demo.html +2945 -2945
  158. package/{icomoon → src/resources/icomoon}/fonts/Topvisor-2.svg +232 -232
  159. package/{icomoon → src/resources/icomoon}/style.css +647 -647
  160. package/src/resources/styles/core/colors.css +204 -0
  161. package/src/resources/styles/core/components.css +70 -0
  162. package/src/resources/styles/core/core.ts +10 -0
  163. package/src/resources/styles/core/forms/clear.css +19 -0
  164. package/src/resources/styles/core/forms/controls.css +20 -0
  165. package/src/resources/styles/core/forms/focusable.css +26 -0
  166. package/src/resources/styles/core/forms/forms.css +100 -0
  167. package/src/resources/styles/core/icon.css +58 -0
  168. package/src/resources/styles/core/layout.css +40 -0
  169. package/src/resources/styles/core/modifiers/as.css +9 -0
  170. package/src/resources/styles/core/modifiers/ellipsis.css +18 -0
  171. package/src/resources/styles/core/modifiers/modifiers.css +81 -0
  172. package/src/resources/styles/core/modifiers/only.css +19 -0
  173. package/src/resources/styles/core/select.css +16 -0
  174. package/src/resources/styles/jquery-ui.min.css +6 -0
  175. package/src/resources/styles/storybook.css +11 -0
  176. package/src/resources/styles/themes/dark/theme.css +139 -0
  177. package/src/resources/styles/themes/dark.ts +1 -0
  178. package/src/resources/styles/themes/light/theme.css +139 -0
  179. package/src/resources/styles/themes/light.ts +1 -0
  180. package/src/storybook/components/color.vue +45 -0
  181. package/src/storybook/components/colors.vue +34 -0
  182. package/src/storybook/components/icomoon.ts +38 -0
  183. package/src/storybook/components/properties.vue +82 -0
  184. package/src/storybook/resources/accessibility.png +0 -0
  185. package/src/storybook/resources/accessibility.svg +5 -0
  186. package/src/storybook/resources/addon-library.png +0 -0
  187. package/src/storybook/resources/assets.png +0 -0
  188. package/src/storybook/resources/context.png +0 -0
  189. package/src/storybook/resources/discord.svg +15 -0
  190. package/src/storybook/resources/docs.png +0 -0
  191. package/src/storybook/resources/figma-plugin.png +0 -0
  192. package/src/storybook/resources/github.svg +3 -0
  193. package/src/storybook/resources/share.png +0 -0
  194. package/src/storybook/resources/styling.png +0 -0
  195. package/src/storybook/resources/testing.png +0 -0
  196. package/src/storybook/resources/theming.png +0 -0
  197. package/src/storybook/resources/tutorials.svg +12 -0
  198. package/src/storybook/resources/youtube.svg +4 -0
  199. package/src//320/224/320/276/320/261/321/200/320/276 /320/277/320/276/320/266/320/260/320/273/320/276/320/262/320/260/321/202/321/214.mdx" +3 -0
  200. package/tsconfig.json +62 -0
  201. package/vite.config.ts +91 -0
  202. package/.chunks/datepicker-0b648b9f.es.js +0 -275
  203. package/.chunks/datepicker-0b648b9f.es.js.map +0 -1
  204. package/.chunks/datepicker-0e9a0541.amd.js +0 -234
  205. package/.chunks/datepicker-0e9a0541.amd.js.map +0 -1
  206. package/.chunks/forms-02202302.amd.js +0 -3
  207. package/.chunks/forms-02202302.amd.js.map +0 -1
  208. package/.chunks/forms-eb00d0c1.es.js +0 -946
  209. package/.chunks/forms-eb00d0c1.es.js.map +0 -1
  210. package/.chunks/popup-6f73b4b2.es.js +0 -700
  211. package/.chunks/popup-6f73b4b2.es.js.map +0 -1
  212. package/.chunks/popup-e1f34511.amd.js +0 -341
  213. package/.chunks/popup-e1f34511.amd.js.map +0 -1
  214. package/common/common.amd.js +0 -2
  215. package/common/common.amd.js.map +0 -1
  216. package/common/common.js +0 -2
  217. package/common/common.js.map +0 -1
  218. package/core/core.amd.js +0 -2
  219. package/core/core.amd.js.map +0 -1
  220. package/core/core.js +0 -6
  221. package/core/core.js.map +0 -1
  222. package/core.css +0 -1
  223. package/dark.css +0 -1
  224. package/forms/forms.amd.js +0 -2
  225. package/forms/forms.amd.js.map +0 -1
  226. package/forms/forms.js +0 -15
  227. package/forms/forms.js.map +0 -1
  228. package/forms/helpers.amd.js +0 -2
  229. package/forms/helpers.amd.js.map +0 -1
  230. package/forms/helpers.js +0 -9
  231. package/forms/helpers.js.map +0 -1
  232. package/forms.css +0 -1
  233. package/formsExt/formsExt.amd.js +0 -3
  234. package/formsExt/formsExt.amd.js.map +0 -1
  235. package/formsExt/formsExt.js +0 -152
  236. package/formsExt/formsExt.js.map +0 -1
  237. package/formsExt.css +0 -1
  238. package/light.css +0 -1
  239. package/popup/popup.amd.js +0 -3
  240. package/popup/popup.amd.js.map +0 -1
  241. package/popup/popup.js +0 -144
  242. package/popup/popup.js.map +0 -1
  243. package/popup/worker.amd.js +0 -2
  244. package/popup/worker.amd.js.map +0 -1
  245. package/popup/worker.js +0 -154
  246. package/popup/worker.js.map +0 -1
  247. package/popup.css +0 -1
  248. package/tabs/tabs.amd.js +0 -3
  249. package/tabs/tabs.amd.js.map +0 -1
  250. package/tabs/tabs.js +0 -97
  251. package/tabs/tabs.js.map +0 -1
  252. package/tabs.css +0 -1
  253. package/utils/date.amd.js +0 -2
  254. package/utils/date.amd.js.map +0 -1
  255. package/utils/date.js +0 -6
  256. package/utils/date.js.map +0 -1
  257. package/utils/device.amd.js +0 -2
  258. package/utils/device.amd.js.map +0 -1
  259. package/utils/device.js +0 -6
  260. package/utils/device.js.map +0 -1
  261. package/utils/dom.amd.js +0 -2
  262. package/utils/dom.amd.js.map +0 -1
  263. package/utils/dom.js +0 -64
  264. package/utils/dom.js.map +0 -1
  265. /package/{icomoon → src/resources/icomoon}/fonts/Topvisor-2.ttf +0 -0
  266. /package/{icomoon → src/resources/icomoon}/fonts/Topvisor-2.woff +0 -0
  267. /package/{icomoon → src/resources/icomoon}/selection.json +0 -0
@@ -0,0 +1,702 @@
1
+ // добавляет jQuery события на this.el, если jQuery загружен:
2
+ // aftershow.top-menu-popup
3
+ // afterclose.top-menu-popup
4
+
5
+ import Core from '@/core/core/core';
6
+ import Component from '@/components/component';
7
+ import DOM from '@/core/utils/dom';
8
+ import Worker from '@/components/popup/lib/worker';
9
+ import GlobalEvents from '@/components/popup/lib/popup.globalEvents';
10
+
11
+ import css from '@/components/popup/popup/style/popup.css?raw';
12
+ import cssM from '@/components/popup/popup/style/popup.m.css?raw';
13
+ import cssPC from '@/components/popup/popup/style/popup.pc.css?raw';
14
+
15
+ Core.appendStyle(css);
16
+ Core.appendStyle(cssM, 'm');
17
+ Core.appendStyle(cssPC, 'pc');
18
+
19
+ /**
20
+ * @property {Element} el - элемент, вызвавший открытие Popup
21
+ * @property {Element} elPopup - Popup .top-popup-wrapper
22
+ * @property {Element} elPopupInner - контентная часть Popup .top-popup
23
+ * @property {Element} elPopupHeader
24
+ * @property {Element} elPopupBody
25
+ * @property {Element} elPopupFooter
26
+ */
27
+ class Popup extends Component {
28
+
29
+ static componentName = 'Popup';
30
+
31
+ el; // элемент, вызвавший открытие Popup
32
+ elActiveByDefault; // элемент уже имеет класс top-active перед открытием окна
33
+ elPopup;
34
+ elPopupInner;
35
+ elPopupHeader;
36
+ elPopupBody;
37
+ elPopupFooter;
38
+ elFront;
39
+
40
+ popupParent;
41
+
42
+ $; // только, если есть jQuery
43
+
44
+ elStartPosition; // используется для useOriginal
45
+ shift = {
46
+ top: 0,
47
+ left: 0,
48
+ };
49
+ isClosed = false; // флаг того, что меню закрыто
50
+ isFirstClick = true;
51
+ type; // selector или html
52
+
53
+ options = {
54
+ popup: '', // selector, text
55
+ p: 0, // положение меню (0 - над элементом, 1 - сверху, 2 - справа, 3 - снизу, 4 слева)
56
+ notch: false, // отображать ли клювик
57
+
58
+ class: '', // класс, добавляемый меню
59
+
60
+ posBy: 'left', // способ привязки позиционирования меню (left/right - левый/правый край родителя, fixed - по окну)
61
+ frontSelector: '',
62
+ invertX: false, // базовая ордината - правая граница элемента, а не левая
63
+ openByHover: false, // открывать при наведении
64
+
65
+ useOriginal: false, // использовать оригинальный шаблон, без клонирвоания (для сохранения состояния меню)
66
+
67
+ isFullScreen: false,
68
+ i18n: {},
69
+ };
70
+
71
+ events = {};
72
+
73
+ // el - элемент, открывающий меню
74
+ constructor(el, options) {
75
+ super();
76
+
77
+ return this.init(Popup.componentName, el, options);
78
+ }
79
+
80
+ async mount() {
81
+ const vueConnector = this.vueGetComponent();
82
+
83
+ this.popupParent = Worker.getPopup(this.el.closest('.top-popup-wrapper'));
84
+
85
+ await this.mountJQuery();
86
+
87
+ if (DOM.css(this.el, 'position') !== 'absolute') {
88
+ this.el.style.position = 'relative';
89
+ }
90
+
91
+ this.el.dataset.topPopupOpened = 'opened';
92
+ this.elActiveByDefault = this.el.classList.contains('top-active');
93
+ this.el.classList.add('top-active');
94
+
95
+ if (vueConnector) {
96
+ // компонент vue Popup
97
+ this.type = 'vue';
98
+
99
+ this.options.popup = '';
100
+ this.elPopup = DOM.genEl('div', {}, this.options.popup);
101
+ } else if (this.options.popup.match(/^[#.]/)) {
102
+ // selector
103
+ this.type = 'selector';
104
+
105
+ this.elPopup = document.querySelector(`${this.options.popup}.template`);
106
+ } else {
107
+ // html
108
+ this.type = 'html';
109
+
110
+ if (this.options.useOriginal) {
111
+ throw ('Option useOriginal not allowed for text templates');
112
+ }
113
+
114
+ this.elPopup = DOM.genEl('div', {}, this.options.popup);
115
+ }
116
+
117
+ if (!this.elPopup || vueConnector?.opened) {
118
+ // возможно шаблон не найден, так как он используется в уже открытом меню
119
+ if (this.options.useOriginal || vueConnector?.opened) {
120
+ // закрыть открытое меню
121
+ if (vueConnector?.opened) {
122
+ this.elPopup = vueConnector.popup.elPopup;
123
+ } else {
124
+ this.elPopup = document.querySelector(`${this.options.popup}.top-popup-wrapper-shown`);
125
+ }
126
+
127
+ if (this.elPopup) {
128
+ this.el.dataset.topPopupOpened = '';
129
+
130
+ if (!this.elActiveByDefault) {
131
+ this.el.classList.remove('top-active');
132
+ }
133
+
134
+ Worker.close(this.elPopup);
135
+
136
+ // повторит попытку открыть меню
137
+ setTimeout(() => this.mount(), 300);
138
+
139
+ return;
140
+ }
141
+
142
+ throw ('Option useOriginal state allowed only elements .template');
143
+ }
144
+
145
+ // возможно вместо шаблона используется другой элемент
146
+ this.elPopup = document.querySelector(`${this.options.popup}:not(.top-popup-wrapper)`);
147
+ }
148
+
149
+ if (!this.elPopup) {
150
+ return;
151
+ }
152
+
153
+ if (this.options.useOriginal) {
154
+ this.elStartPosition = this.elPopup.closest('.top-popup-el-start-position');
155
+ if (!this.elStartPosition) {
156
+ this.elStartPosition = DOM.wrap(this.elPopup, 'i');
157
+ this.elStartPosition.classList.add('top-popup-el-start-position', 'hidden');
158
+ }
159
+ } else {
160
+ this.elPopup = this.elPopup.cloneNode(true);
161
+
162
+ // вывод в меню копии произвольного элемента
163
+ if (this.type === 'selector' && !this.elPopup.matches('.template')) {
164
+ this.elPopup.classList.remove('hidden');
165
+
166
+ if (!this.elPopup.querySelector(':scope > .top-popup_content')) {
167
+ this.elPopup.classList.add('top-popup_content');
168
+ }
169
+
170
+ this.elPopup = DOM.wrap(this.elPopup, 'div');
171
+ }
172
+
173
+ if (this.type === 'html') {
174
+ if (!this.elPopup.querySelector(':scope > .top-popup_content')) {
175
+ this.elPopup.classList.add('top-popup_content');
176
+
177
+ this.elPopup = DOM.wrap(this.elPopup, 'div');
178
+ }
179
+ }
180
+
181
+ // вложенный Popup
182
+ if (this.type === 'selector' && !this.elPopup.matches('.template') || this.type === 'html' || this.type === 'vue') {
183
+ DOM.querySelectorAllArray(this.elPopup, '[data-top-popup]').forEach(el => el.dataset.topPopupPosBy = 'fixed');
184
+ DOM.querySelectorAllArray(this.elPopup, '.top-popup-wrapper').forEach(el => el.remove());
185
+ }
186
+ }
187
+
188
+ Worker.decoratorBeforeOpen(this);
189
+
190
+ if (vueConnector) {
191
+ this.options.class = vueConnector.classRef.value;
192
+ }
193
+
194
+ this.elPopupInner = document.createElement('div');
195
+ this.elPopupInner.classList.add('top-popupPanel', 'top-popup');
196
+
197
+ while (this.elPopup.firstChild) {
198
+ this.elPopupInner.appendChild(this.elPopup.firstChild);
199
+ }
200
+
201
+ this.elPopup.append(this.elPopupInner);
202
+
203
+ this.elPopup.classList.add('top-popup-wrapper');
204
+
205
+ if (this.options.class) {
206
+ const classes = this.options.class.split(' ');
207
+ this.elPopup.classList.add(...classes);
208
+ }
209
+
210
+ if (this.options.notch) {
211
+ this.elPopup.classList.add('with_notch');
212
+ this.elPopup.insertAdjacentHTML('beforeend', '<i class="notch notch-border"></i><i class="notch"></i>');
213
+ }
214
+
215
+ await this.vueOpen();
216
+
217
+ this.elPopupHeader = this.elPopupInner.querySelector('.top-popup_header');
218
+ this.elPopupBody = this.elPopupInner.querySelector('.top-popup_content');
219
+ this.elPopupFooter = this.elPopupInner.querySelector('.top-popup_footer');
220
+
221
+ const existsWidgetSearch = !!this.elPopup.querySelector('[data-widget="search"]');
222
+
223
+ if (this.options.isFullScreen && !existsWidgetSearch) {
224
+ if (!this.elPopupHeader) {
225
+ this.elPopupHeader = DOM.genEl('i', { class: 'top-popup_header' });
226
+ this.elPopupInner.prepend(this.elPopupHeader);
227
+
228
+ this.elPopupHeader.prepend(DOM.genEl('i', { class: 'a closer' }, this.options.i18n.Close));
229
+ this.elPopupHeader.append(DOM.genEl('i', { class: 'top-popup_headerButton' }));
230
+ }
231
+ }
232
+
233
+ DOM.storage(this.elPopup, 'Popup', this);
234
+
235
+ if (this.options.frontSelector) {
236
+ this.elFront = document.querySelector(this.options.frontSelector);
237
+ }
238
+ if (!this.elFront) {
239
+ this.elFront = this.el.closest('.top-popup-front');
240
+ }
241
+ if (!this.elFront) {
242
+ this.elFront = document.body;
243
+ }
244
+
245
+ this.elPopup.style.width = this.el.offsetWidth + 'px';
246
+ this.elPopup.style.height = this.el.offsetHeight + 'px';
247
+ this.elPopup.style.top = this.el.offsetTop + 'px';
248
+ this.elPopup.style.right = parseInt(this.el.style.right || 0) + 'px';
249
+ this.elPopup.style.bottom = parseInt(this.el.style.bottom || 0) + 'px';
250
+
251
+ this.el.parentElement.insertBefore(this.elPopup, this.el);
252
+ this.elPopup.classList.remove('template');
253
+
254
+ if (this.options.invertX) {
255
+ this.elPopup.classList.add('invert-x');
256
+ }
257
+
258
+ let fromTop = !!this.el.closest('.modal-header');
259
+ if (!fromTop) {
260
+ fromTop = !!this.el.closest('#top_panel');
261
+ }
262
+ if (!fromTop) {
263
+ fromTop = !!this.el.closest('#secondmenu');
264
+ }
265
+ if (fromTop) {
266
+ this.elPopup.classList.add('p-from-top');
267
+ }
268
+
269
+ // появление с анимацией
270
+ setTimeout(() => this.elPopup.classList.add('top-popup-wrapper-shown'));
271
+
272
+ if (this.elFront && !this.elFront.matches('body')) {
273
+ this.elFront.append(this.elPopup);
274
+
275
+ this.shift.top = DOM.offset(this.el).top - this.el.offsetTop - DOM.offset(this.elFront).top;
276
+ this.shift.left = DOM.offset(this.el).left - this.el.offsetLeft - DOM.offset(this.elFront).left;
277
+
278
+ // position() не учитывает margin, замечено для flex
279
+ this.shift.top -= parseInt(this.el.style['margin-top'] || 0);
280
+ this.shift.left -= parseInt(this.el.style['margin-left'] || 0);
281
+
282
+ this.elPopup.style.top = parseInt(this.elPopup.style.top || '0') + this.shift.top + 'px';
283
+ this.elPopup.style.left = parseInt(this.elPopup.style.left || '0') + this.shift.left + 'px';
284
+ }
285
+
286
+ if (this.$) {
287
+ this.$.trigger('aftershow.top-menu-popup', [jQuery(this.elPopup)]);
288
+ }
289
+
290
+ this.recalcPosition();
291
+
292
+ this.elPopup.setAttribute('tabindex', 0);
293
+ this.focus();
294
+
295
+ Worker.decoratorAfterOpen(this);
296
+
297
+ this.mountEvents();
298
+ }
299
+
300
+ async mountJQuery() {
301
+ if (typeof (jQuery) !== 'function') {
302
+ return;
303
+ }
304
+
305
+ this.$ = jQuery(this.el);
306
+ }
307
+
308
+ /**
309
+ * Выполнить фокусировку на нужный элемент после открытия окна
310
+ */
311
+ focus() {
312
+ let el = DOM.querySelectorVisible(this.elPopup, '.top-popup-autofocus');
313
+
314
+ // поле ввода
315
+ if (!el) {
316
+ el = DOM.querySelectorVisible(this.elPopup, ':read-write, select:not(:disabled)');
317
+ }
318
+
319
+ // кнопка
320
+ if (!el) {
321
+ el = DOM.querySelectorVisible(this.elPopup, '.top-popup_footer .top-button');
322
+ }
323
+
324
+ if (!el) {
325
+ el = this.elPopup;
326
+ }
327
+
328
+ el.focus();
329
+ }
330
+
331
+ mountEvents() {
332
+ // закрытие при клике вне контекстного меню
333
+ this.addEventListenerWithUnmount(document, 'mousedown', (e) => this.onMousedown(e));
334
+
335
+ // закрыть другие меню
336
+ this.addEventListenerWithUnmount(this.elPopup, 'focus', (e) => this.onFocus(e));
337
+
338
+ // автоматическое закрытие при отведении мыши
339
+ if (this.options.openByHover) {
340
+ this.addEventListenerWithUnmount(this.elPopup, 'mouseleave', (e) => this.onMouseleave(e));
341
+ this.addEventListenerWithUnmount(this.elPopupInner, 'mouseleave', (e) => this.onMouseleave(e));
342
+ }
343
+
344
+ // не скроллить страницу
345
+ if (this.options.isFullScreen) {
346
+ this.addEventListenerWithUnmount(this.elPopupBody, 'touchmove', (e) => this.onTouchmove(e));
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Обработка клика вне окна
352
+ * @param {Event} e
353
+ */
354
+ onMousedown(e) {
355
+ // // не оригинальное событие
356
+ // if (!e || !e.originalEvent || !e.originalEvent.isTrusted) {
357
+ // return;
358
+ // }
359
+
360
+ // Popup уже закрыт
361
+ if (!this.elPopup) {
362
+ return;
363
+ }
364
+
365
+ // клик на внешнем элементе
366
+ if (!this.isFirstClick) {
367
+ return;
368
+ }
369
+
370
+ this.isFirstClick = false;
371
+ setTimeout(() => this.isFirstClick = true);
372
+
373
+ // клик не основной кнопкой мыши
374
+ if (e.button !== 0) {
375
+ return;
376
+ }
377
+
378
+ // открыто другое меню с posBy = fixed, сначала должно быть закрыто оно
379
+ let elPopupOpened = DOM.querySelectorVisibleLast(document.body, ':scope > .top-popup-wrapper');
380
+ if (elPopupOpened && elPopupOpened !== this.elPopup) {
381
+ return;
382
+ }
383
+
384
+ // открыто другое меню в top-popup-front, сначала должно быть закрыто оно
385
+ elPopupOpened = DOM.querySelectorVisibleLast(e.target.closest('.top-popup-front'), ':scope > .top-popup-wrapper');
386
+ if (elPopupOpened && elPopupOpened !== this.elPopup) {
387
+ return;
388
+ }
389
+
390
+ // клик внутри этого меню
391
+ if (this.elPopup.contains(e.target)) {
392
+ return;
393
+ }
394
+
395
+ // клик вне родительского диалогового окна
396
+ if (this.elPopup.closest('.ui-dialog') && !e.target.closest('.ui-dialog')) {
397
+ return;
398
+ }
399
+
400
+ if (Worker.decoratorIsIgnoreOuterClick(e)) {
401
+ return;
402
+ }
403
+
404
+ Worker.close(this.elPopup);
405
+ }
406
+
407
+ /**
408
+ * Закрыть другие Popup при фокусе на элемент формы в текущем
409
+ * @param {Event} e
410
+ */
411
+ onFocus(e) {
412
+ if (e.target.matches('input')) {
413
+ return;
414
+ }
415
+
416
+ // // не оригинальное событие
417
+ // if (!e || !e.originalEvent || !e.originalEvent.isTrusted) {
418
+ // return;
419
+ // }
420
+
421
+ // это окно уже закрывается
422
+ if (this.isClosed) {
423
+ return;
424
+ }
425
+
426
+ const elsPopups = Worker.getAllVisible();
427
+ elsPopups.forEach(elPopup => {
428
+ // фокус внутри этого окна
429
+ if (this.elPopup.contains(elPopup)) {
430
+ return;
431
+ }
432
+
433
+ // это Popup из которого был открыт Popup с фокусом
434
+ // глубина вложенности: до 3 подменю
435
+ if (
436
+ this.popupParent?.elPopup === elPopup ||
437
+ this.popupParent?.popupParent?.elPopup === elPopup
438
+ ) {
439
+ return;
440
+ }
441
+
442
+ Worker.close(elPopup);
443
+ });
444
+ }
445
+
446
+ /**
447
+ * Закрыть Popup при отведении мыши
448
+ * @param {Event} _e
449
+ */
450
+ onMouseleave(_e) {
451
+ setTimeout(() => {
452
+ if (this.elPopupInner.matches(':hover')) {
453
+ return;
454
+ }
455
+
456
+ Worker.close(this.elPopup);
457
+ }, 100);
458
+ }
459
+
460
+ /**
461
+ * Контроль положения Popup при fixed позиционировании
462
+ */
463
+ onResize() {
464
+ // на android при вызове метода append сбрасывается фокус с input внутри this.elPopup
465
+ if (this.elPopup.parentElement !== document.body) {
466
+ document.body.append(this.elPopup);
467
+ }
468
+
469
+ this.elPopup.style.top = DOM.offset(this.el).top + 'px';
470
+ this.elPopup.style.left = DOM.offset(this.el).left + 'px';
471
+ }
472
+
473
+ unmount() {
474
+ super.unmount();
475
+
476
+ this.el.dataset.topPopupOpened = '';
477
+ if (!this.elActiveByDefault) {
478
+ this.el.classList.remove('top-active');
479
+ }
480
+
481
+ let style = this.el.getAttribute('style');
482
+ if (style) {
483
+ style = style.replace(/position:[^;]*;?/g, '');
484
+ this.el.setAttribute('style', style);
485
+ }
486
+ }
487
+
488
+ // контроль за положением Popup, чтобы оно не вылезало за пределы документа
489
+ recalcPosition() {
490
+ let p = this.options.p;
491
+ let leftPos;
492
+
493
+ this.elPopup.style.height = this.el.offsetHeight + 'px';
494
+
495
+ this.elPopup.classList.remove('p0', 'p1', 'p2', 'p3', 'p4');
496
+ this.elPopup.classList.add('p' + p);
497
+
498
+ switch (this.options.posBy) {
499
+ case 'left':
500
+ leftPos = this.el.offsetLeft + parseInt(this.el.style['margin-left'] || 0);
501
+ leftPos += this.shift.left;
502
+ this.elPopup.style.left = leftPos + 'px';
503
+
504
+ break;
505
+ case 'right':
506
+ leftPos = this.el.offsetLeft + parseInt(this.el.style['margin-left'] || 0);
507
+ this.elPopup.style.right = this.el.offsetParent.offsetWidth - this.el.offsetWidth - leftPos + 'px';
508
+
509
+ break;
510
+ case 'fixed':
511
+ this.addEventListenerWithUnmount(window, 'resize', () => this.onResize());
512
+
513
+ this.onResize();
514
+
515
+ break;
516
+ default:
517
+ this.options.posBy.append(this.elPopup);
518
+ }
519
+
520
+ // контроль за пложением Popup, чтобы оно не вылезало за пределы документа
521
+ const boundingClientRect = this.elPopup.getBoundingClientRect();
522
+ this.elPopup.style.setProperty('--top-popup-height', this.elPopup.offsetHeight + 'px');
523
+ this.elPopup.style.setProperty('--top-popup-right-bounding', boundingClientRect.right + 'px');
524
+ this.elPopup.style.setProperty('--top-popup-bottom-bounding', boundingClientRect.bottom + 'px');
525
+ this.elPopup.style.setProperty('--top-popup-top', boundingClientRect.top + 'px');
526
+ this.elPopup.style.setProperty('--top-popup-left', boundingClientRect.left + 'px');
527
+
528
+ this.elPopupInner.style.maxWidth = 'unset';
529
+ this.elPopupInner.style.maxHeight = 'unset';
530
+
531
+ let outTop = false;
532
+ let outRight = false;
533
+ let outBottom = false;
534
+ let outLeft = false;
535
+
536
+ // имеет ли смысл прикреплять окно к другой стороне кнопки
537
+ let usefulInvertX = boundingClientRect.left > window.innerWidth / 2;
538
+ let usefulInvertY = boundingClientRect.top > window.innerHeight / 2;
539
+
540
+ if (p === 4) {
541
+ usefulInvertX = !usefulInvertX;
542
+ }
543
+
544
+ if (p === 1) {
545
+ usefulInvertY = !usefulInvertY;
546
+ }
547
+
548
+ const contentBoundingClientRect = this.elPopupInner.getBoundingClientRect();
549
+ const contentRight = window.innerWidth - contentBoundingClientRect.right;
550
+ const contentBottom = window.innerHeight - contentBoundingClientRect.bottom;
551
+
552
+ const margin = 8;
553
+
554
+ if (contentBoundingClientRect.top < margin) {
555
+ outTop = true;
556
+ }
557
+
558
+ if (contentRight < margin) {
559
+ outRight = true;
560
+ }
561
+
562
+ if (contentBottom < margin) {
563
+ outBottom = true;
564
+ }
565
+
566
+ if (contentBoundingClientRect.left < margin) {
567
+ outLeft = true;
568
+ }
569
+
570
+ if (outTop && (p === 0 || p === 1) && usefulInvertY) {
571
+ p = 3;
572
+ }
573
+
574
+ if (outBottom && p === 3 && usefulInvertY) {
575
+ p = 1;
576
+ }
577
+
578
+ if (outRight && p === 2 && usefulInvertX) {
579
+ p = 4;
580
+ }
581
+
582
+ if (outLeft && p === 4 && usefulInvertX) {
583
+ p = 2;
584
+ }
585
+
586
+ if (outRight && (p === 0 || p === 1 || p === 3)) {
587
+ this.elPopup.classList.add('invert-x');
588
+ }
589
+
590
+ if (outBottom && (p === 2 || p === 4) && usefulInvertY) {
591
+ // меню справа может перемещаться вверх, толкьо если есть место слева
592
+ if (p === 2 && !usefulInvertX) {
593
+ this.elPopup.classList.add('invert-y');
594
+ }
595
+
596
+ // меню слева перемещаясь вверх, должно открываться влево
597
+ if (p === 4 && !usefulInvertX) {
598
+ this.elPopup.classList.add('invert-x');
599
+ }
600
+
601
+ if (!this.elPopup.matches('.invert-y')) {
602
+ p = 1;
603
+ }
604
+ }
605
+
606
+ this.elPopup.classList.remove('p0', 'p1', 'p2', 'p3', 'p4');
607
+ this.elPopup.classList.add('p' + p);
608
+
609
+ this.elPopupInner.style.maxWidth = '';
610
+ this.elPopupInner.style.maxHeight = '';
611
+
612
+ Worker.scrollToActive(this.elPopup);
613
+ };
614
+
615
+ onTouchmove(e) {
616
+ // разрешить горизональный скролл
617
+ let hasScrollX = e.currentTarget.scrollWidth > e.currentTarget.offsetWidth;
618
+ if (hasScrollX) {
619
+ return;
620
+ }
621
+
622
+ // разрешить горизональный скролл
623
+ let hasScrollX2 = e.target.parentElement.scrollWidth > e.target.parentElement.offsetWidth;
624
+ if (hasScrollX2) {
625
+ return;
626
+ }
627
+
628
+ if (!e.currentTarget.matches('.has_scroll')) {
629
+ e.preventDefault();
630
+ }
631
+ }
632
+
633
+ close() {
634
+ if (this.isClosed) {
635
+ return;
636
+ }
637
+
638
+ this.isClosed = true;
639
+
640
+ if (this.$) {
641
+ this.$.trigger('afterclose.top-menu-popup', [jQuery(this.elPopup)]);
642
+ }
643
+
644
+ if (Worker.noClose) {
645
+ return;
646
+ }
647
+
648
+ this.unmount();
649
+
650
+ this.elPopup.classList.add('top-popup-wrapper-closed');
651
+
652
+ setTimeout(() => {
653
+ this.vueClose();
654
+
655
+ if (this.options.useOriginal) {
656
+ this.elPopup.removeAttribute('style');
657
+ this.elPopup.classList.remove('top-popup-wrapper-shown', 'top-popup-wrapper-closed');
658
+ this.elPopup.classList.add('template');
659
+ this.elStartPosition.append(this.elPopup);
660
+
661
+ this.elPopup.querySelector('div.top-popup_content.top-column')?.classList.remove('top-column');
662
+ this.elPopup.querySelector('.notch-border')?.remove();
663
+ this.elPopup.querySelector('.notch')?.remove();
664
+
665
+ this.elPopupInner.replaceWith(...this.elPopupInner.childNodes);
666
+
667
+ DOM.storageClear(this.elPopup);
668
+ } else {
669
+ DOM.storageClear(this.elPopup);
670
+
671
+ this.elPopup.remove();
672
+ delete this.elPopup;
673
+ }
674
+
675
+ const elsPopups = Worker.getAllVisible();
676
+ const elPopupLast = elsPopups.length && elsPopups[elsPopups.length - 1];
677
+
678
+ if (elPopupLast) {
679
+ Worker.getPopup(elPopupLast).focus();
680
+ } else {
681
+ document.documentElement.classList.remove('with_popup');
682
+ }
683
+ }, 300);
684
+ }
685
+
686
+ async vueOpen() {
687
+ await this.vueGetComponent()?.onOpen(this);
688
+ }
689
+
690
+ vueClose() {
691
+ this.vueGetComponent()?.onClose(this);
692
+ }
693
+
694
+ // получить vueConnectors компонента Popup
695
+ vueGetComponent() {
696
+ return Worker.vueConnectors.get(this.el.dataset.topPopupId);
697
+ }
698
+ }
699
+
700
+ GlobalEvents.init();
701
+
702
+ export default Popup;