@whitesev/pops 2.4.5 → 2.4.7

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 (153) hide show
  1. package/README.md +117 -111
  2. package/dist/index.amd.js +1248 -1287
  3. package/dist/index.amd.js.map +1 -1
  4. package/dist/index.cjs.js +1248 -1287
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.esm.js +1248 -1287
  7. package/dist/index.esm.js.map +1 -1
  8. package/dist/index.iife.js +1248 -1287
  9. package/dist/index.iife.js.map +1 -1
  10. package/dist/index.system.js +1248 -1287
  11. package/dist/index.system.js.map +1 -1
  12. package/dist/index.umd.js +1248 -1287
  13. package/dist/index.umd.js.map +1 -1
  14. package/dist/types/src/Pops.d.ts +9 -10
  15. package/dist/types/src/components/panel/types/components-common.d.ts +26 -26
  16. package/dist/types/src/components/panel/types/index.d.ts +1 -1
  17. package/dist/types/src/components/rightClickMenu/index.d.ts +3 -4
  18. package/dist/types/src/components/searchSuggestion/index.d.ts +2 -2
  19. package/dist/types/src/components/searchSuggestion/types/index.d.ts +2 -2
  20. package/dist/types/src/handler/PopsHandler.d.ts +3 -3
  21. package/dist/types/src/types/PopsDOMUtilsEventType.d.ts +252 -256
  22. package/dist/types/src/types/animation.d.ts +19 -19
  23. package/dist/types/src/types/button.d.ts +187 -187
  24. package/dist/types/src/types/components.d.ts +210 -213
  25. package/dist/types/src/types/event.d.ts +63 -63
  26. package/dist/types/src/types/global.d.ts +25 -20
  27. package/dist/types/src/types/icon.d.ts +32 -32
  28. package/dist/types/src/types/inst.d.ts +24 -24
  29. package/dist/types/src/types/main.d.ts +111 -114
  30. package/dist/types/src/types/mask.d.ts +49 -49
  31. package/dist/types/src/types/position.d.ts +60 -60
  32. package/dist/types/src/utils/PopsDOMUtils.d.ts +1 -1
  33. package/dist/types/src/utils/PopsInstanceUtils.d.ts +1 -1
  34. package/dist/types/src/utils/PopsUtils.d.ts +16 -16
  35. package/index.ts +3 -0
  36. package/package.json +20 -9
  37. package/src/Pops.ts +206 -0
  38. package/src/PopsAnimation.ts +32 -0
  39. package/src/PopsCSS.ts +51 -0
  40. package/src/PopsCore.ts +64 -0
  41. package/src/PopsIcon.ts +95 -0
  42. package/src/PopsInst.ts +21 -0
  43. package/src/components/alert/config.ts +62 -0
  44. package/src/components/alert/index.css +0 -0
  45. package/src/components/alert/index.ts +163 -0
  46. package/src/components/alert/types/index.ts +23 -0
  47. package/src/components/confirm/config.ts +90 -0
  48. package/src/components/confirm/index.css +0 -0
  49. package/src/components/confirm/index.ts +166 -0
  50. package/src/components/confirm/types/index.ts +17 -0
  51. package/src/components/drawer/config.ts +89 -0
  52. package/src/components/drawer/index.css +37 -0
  53. package/src/components/drawer/index.ts +237 -0
  54. package/src/components/drawer/types/index.ts +61 -0
  55. package/src/components/folder/config.ts +147 -0
  56. package/src/components/folder/folderIcon.ts +28 -0
  57. package/src/components/folder/index.css +303 -0
  58. package/src/components/folder/index.ts +929 -0
  59. package/src/components/folder/types/index.ts +97 -0
  60. package/src/components/iframe/config.ts +60 -0
  61. package/src/components/iframe/index.css +76 -0
  62. package/src/components/iframe/index.ts +334 -0
  63. package/src/components/iframe/types/index.ts +139 -0
  64. package/src/components/loading/config.ts +29 -0
  65. package/src/components/loading/index.css +66 -0
  66. package/src/components/loading/index.ts +99 -0
  67. package/src/components/loading/types/index.ts +34 -0
  68. package/src/components/panel/config.ts +519 -0
  69. package/src/components/panel/handlerComponents.ts +2900 -0
  70. package/src/components/panel/index.css +1222 -0
  71. package/src/components/panel/index.ts +207 -0
  72. package/src/components/panel/types/components-button.ts +68 -0
  73. package/src/components/panel/types/components-common.ts +50 -0
  74. package/src/components/panel/types/components-deepMenu.ts +84 -0
  75. package/src/components/panel/types/components-forms.ts +44 -0
  76. package/src/components/panel/types/components-input.ts +78 -0
  77. package/src/components/panel/types/components-own.ts +30 -0
  78. package/src/components/panel/types/components-select.ts +93 -0
  79. package/src/components/panel/types/components-selectMultiple.ts +130 -0
  80. package/src/components/panel/types/components-slider.ts +77 -0
  81. package/src/components/panel/types/components-switch.ts +56 -0
  82. package/src/components/panel/types/components-textarea.ts +68 -0
  83. package/src/components/panel/types/index.ts +177 -0
  84. package/src/components/prompt/config.ts +94 -0
  85. package/src/components/prompt/index.css +34 -0
  86. package/src/components/prompt/index.ts +216 -0
  87. package/src/components/prompt/types/index.ts +55 -0
  88. package/src/components/rightClickMenu/config.ts +98 -0
  89. package/src/components/rightClickMenu/index.css +112 -0
  90. package/src/components/rightClickMenu/index.ts +602 -0
  91. package/src/components/rightClickMenu/types/index.ts +97 -0
  92. package/src/components/searchSuggestion/config.ts +56 -0
  93. package/src/components/searchSuggestion/index.ts +856 -0
  94. package/src/components/searchSuggestion/types/index.ts +239 -0
  95. package/src/components/tooltip/config.ts +34 -0
  96. package/src/components/tooltip/index.css +199 -0
  97. package/src/components/tooltip/index.ts +604 -0
  98. package/src/components/tooltip/types/index.ts +117 -0
  99. package/src/config/CommonCSSClassName.ts +17 -0
  100. package/src/config/GlobalConfig.ts +63 -0
  101. package/src/css/animation.css +987 -0
  102. package/src/css/button.css +551 -0
  103. package/src/css/common.css +48 -0
  104. package/src/css/index.css +253 -0
  105. package/src/css/ninePalaceGridPosition.css +50 -0
  106. package/src/css/scrollbar.css +22 -0
  107. package/src/handler/PopsElementHandler.ts +304 -0
  108. package/src/handler/PopsHandler.ts +589 -0
  109. package/src/svg/arrowLeft.svg +4 -0
  110. package/src/svg/arrowRight.svg +4 -0
  111. package/src/svg/chromeFilled.svg +11 -0
  112. package/src/svg/circleClose.svg +8 -0
  113. package/src/svg/close.svg +5 -0
  114. package/src/svg/cpu.svg +8 -0
  115. package/src/svg/delete.svg +5 -0
  116. package/src/svg/documentCopy.svg +5 -0
  117. package/src/svg/edit.svg +8 -0
  118. package/src/svg/eleme.svg +5 -0
  119. package/src/svg/elemePlus.svg +5 -0
  120. package/src/svg/headset.svg +5 -0
  121. package/src/svg/hide.svg +8 -0
  122. package/src/svg/keyboard.svg +8 -0
  123. package/src/svg/loading.svg +5 -0
  124. package/src/svg/max.svg +5 -0
  125. package/src/svg/min.svg +5 -0
  126. package/src/svg/mise.svg +5 -0
  127. package/src/svg/monitor.svg +5 -0
  128. package/src/svg/next.svg +5 -0
  129. package/src/svg/picture.svg +8 -0
  130. package/src/svg/prev.svg +5 -0
  131. package/src/svg/search.svg +5 -0
  132. package/src/svg/share.svg +5 -0
  133. package/src/svg/upload.svg +5 -0
  134. package/src/svg/videoPause.svg +5 -0
  135. package/src/svg/videoPlay.svg +5 -0
  136. package/src/svg/view.svg +5 -0
  137. package/src/types/PopsDOMUtilsEventType.d.ts +252 -0
  138. package/src/types/animation.d.ts +19 -0
  139. package/src/types/button.d.ts +187 -0
  140. package/src/types/components.d.ts +210 -0
  141. package/src/types/event.d.ts +63 -0
  142. package/src/types/global.d.ts +25 -0
  143. package/src/types/icon.d.ts +32 -0
  144. package/src/types/inst.d.ts +24 -0
  145. package/src/types/main.d.ts +111 -0
  146. package/src/types/mask.d.ts +49 -0
  147. package/src/types/position.d.ts +60 -0
  148. package/src/utils/PopsDOMUtils.ts +2408 -0
  149. package/src/utils/PopsDOMUtilsEventsConfig.ts +4 -0
  150. package/src/utils/PopsInstanceUtils.ts +688 -0
  151. package/src/utils/PopsMathUtils.ts +71 -0
  152. package/src/utils/PopsSafeUtils.ts +22 -0
  153. package/src/utils/PopsUtils.ts +406 -0
@@ -0,0 +1,856 @@
1
+ import { PopsHandler } from "../../handler/PopsHandler";
2
+ import { popsDOMUtils } from "../../utils/PopsDOMUtils";
3
+ import { popsUtils } from "../../utils/PopsUtils";
4
+ import { searchSuggestionConfig as PopsSearchSuggestionConfig } from "./config";
5
+ import { GlobalConfig } from "../../config/GlobalConfig";
6
+ import { PopsSafeUtils } from "../../utils/PopsSafeUtils";
7
+ import type { PopsSearchSuggestionData, PopsSearchSuggestionDetails } from "./types/index";
8
+ import { PopsCSS } from "../../PopsCSS";
9
+ import type { PopsType } from "../../types/main";
10
+ import { PopsCommonCSSClassName } from "../../config/CommonCSSClassName";
11
+
12
+ export const PopsSearchSuggestion = {
13
+ init<T>(details: PopsSearchSuggestionDetails<T>) {
14
+ const guid = popsUtils.getRandomGUID();
15
+ // 设置当前类型
16
+ const popsType: PopsType = "searchSuggestion";
17
+
18
+ let config = PopsSearchSuggestionConfig();
19
+ config = popsUtils.assign(config, GlobalConfig.getGlobalConfig());
20
+ config = popsUtils.assign(config, details);
21
+ if (config.target == null) {
22
+ throw new Error("config.target 不能为空");
23
+ }
24
+ /* 做下兼容处理 */
25
+ if (config.inputTarget == null) {
26
+ config.inputTarget = config.target as HTMLInputElement;
27
+ }
28
+ if (details.data) {
29
+ (<PopsSearchSuggestionDetails<T>["data"]>config.data) = details.data;
30
+ }
31
+
32
+ const { $shadowContainer, $shadowRoot } = PopsHandler.handlerShadow(config);
33
+ PopsHandler.handleInit($shadowRoot, [
34
+ {
35
+ name: "index",
36
+ css: PopsCSS.index,
37
+ },
38
+ {
39
+ name: "anim",
40
+ css: PopsCSS.anim,
41
+ },
42
+ {
43
+ name: "common",
44
+ css: PopsCSS.common,
45
+ },
46
+ ]);
47
+
48
+ if (config.style != null) {
49
+ const cssNode = document.createElement("style");
50
+ popsDOMUtils.createElement(
51
+ "style",
52
+ {
53
+ innerHTML: config.style,
54
+ },
55
+ {
56
+ type: "text/css",
57
+ }
58
+ );
59
+ $shadowRoot.appendChild(cssNode);
60
+ }
61
+
62
+ const SearchSuggestion = {
63
+ /**
64
+ * 当前的环境,可以是document,可以是shadowroot,默认是document
65
+ */
66
+ selfDocument: config.selfDocument,
67
+ $el: {
68
+ /** 根元素 */
69
+ root: null as any as HTMLElement,
70
+ /** ul元素 */
71
+ $hintULContainer: null as any as HTMLUListElement,
72
+ /** 动态更新CSS */
73
+ $dynamicCSS: null as any as HTMLStyleElement,
74
+ },
75
+ $evt: {
76
+ offInputChangeEvtHandler: [] as ((...args: any[]) => any)[],
77
+ },
78
+ $data: {
79
+ /** 是否结果为空 */
80
+ isEmpty: true,
81
+ },
82
+ /**
83
+ * 初始化
84
+ * @param parentElement 父元素
85
+ */
86
+ init(parentElement = document.body || document.documentElement) {
87
+ SearchSuggestion.initEl();
88
+ SearchSuggestion.update(SearchSuggestion.getData());
89
+ SearchSuggestion.updateStyleSheet();
90
+
91
+ SearchSuggestion.hide();
92
+ $shadowRoot.appendChild(SearchSuggestion.$el.root);
93
+ parentElement.appendChild($shadowContainer);
94
+ },
95
+ /**
96
+ * 初始化元素变量
97
+ */
98
+ initEl() {
99
+ SearchSuggestion.$el.root = SearchSuggestion.createSearchSelectElement();
100
+ Reflect.set(SearchSuggestion.$el.root, "data-SearchSuggestion", SearchSuggestion);
101
+ SearchSuggestion.$el.$dynamicCSS =
102
+ SearchSuggestion.$el.root.querySelector<HTMLStyleElement>("style[data-dynamic]")!;
103
+ SearchSuggestion.$el.$hintULContainer = SearchSuggestion.$el.root.querySelector<HTMLUListElement>("ul")!;
104
+ },
105
+ /**
106
+ * 获取数据
107
+ */
108
+ getData(): PopsSearchSuggestionData<T>[] {
109
+ return typeof config.data === "function" ? config.data() : config.data;
110
+ },
111
+ /**
112
+ * 更新数据
113
+ * @param data 数据
114
+ */
115
+ setData(data: PopsSearchSuggestionData<T>[]) {
116
+ (<PopsSearchSuggestionDetails<T>["data"]>config.data) = data;
117
+ },
118
+ /**
119
+ * 获取显示出搜索建议框的html
120
+ */
121
+ createSearchSelectElement() {
122
+ const $el = popsDOMUtils.createElement(
123
+ "div",
124
+ {
125
+ className: `pops pops-${popsType}-search-suggestion`,
126
+ innerHTML: /*html*/ `
127
+ <style type="text/css">
128
+ .pops-${popsType}-animation{
129
+ -moz-animation: searchSelectFalIn 0.5s 1 linear;
130
+ -webkit-animation: searchSelectFalIn 0.5s 1 linear;
131
+ -o-animation: searchSelectFalIn 0.5s 1 linear;
132
+ -ms-animation: searchSelectFalIn 0.5s 1 linear;
133
+ }
134
+ </style>
135
+ <style type="text/css">
136
+ .pops-${popsType}-search-suggestion-arrow{
137
+ --suggestion-arrow-box-shadow-left-color: rgba(0, 0, 0, 0.24);
138
+ --suggestion-arrow-box-shadow-right-color: rgba(0, 0, 0, 0.12);
139
+ --suggestion-arrow--after-color: rgb(78, 78, 78);
140
+ --suggestion-arrow--after-bg-color: rgb(255, 255, 255, var(--pops-bg-opacity));
141
+ --suggestion-arrow--after-width: 10px;
142
+ --suggestion-arrow--after-height: 10px;
143
+ }
144
+ .pops-${popsType}-search-suggestion-arrow{
145
+ position: absolute;
146
+ top: 100%;
147
+ left: 50%;
148
+ overflow: hidden;
149
+ width: 100%;
150
+ height: 12.5px;
151
+ transform: translateX(-50%);
152
+ }
153
+ .pops-${popsType}-search-suggestion-arrow::after{
154
+ position: absolute;
155
+ top: 0;
156
+ left: 50%;
157
+ width: var(--suggestion-arrow--after-width);
158
+ height: var(--suggestion-arrow--after-height);
159
+ background: var(--suggestion-arrow--after-bg-color);
160
+ color: var(--suggestion-arrow--after-color);
161
+ box-shadow:
162
+ 0 1px 7px var(--suggestion-arrow-box-shadow-left-color),
163
+ 0 1px 7px var(--suggestion-arrow-box-shadow-right-color);
164
+ content: "";
165
+ transform: translateX(-50%) translateY(-50%) rotate(45deg);
166
+ }
167
+ .pops-${popsType}-search-suggestion[data-popper-placement^="top"] .pops-${popsType}-search-suggestion-arrow{
168
+ position: absolute;
169
+ top: 100%;
170
+ left: 50%;
171
+ overflow: hidden;
172
+ width: 100%;
173
+ height: 12.5px;
174
+ transform: translateX(-50%);
175
+ }
176
+ .pops-${popsType}-search-suggestion[data-popper-placement^="top"] .pops-${popsType}-search-suggestion-arrow::after{
177
+ position: absolute;
178
+ top: 0;
179
+ left: 50%;
180
+ width: var(--suggestion-arrow--after-width);
181
+ height: var(--suggestion-arrow--after-height);
182
+ background: var(--suggestion-arrow--after-bg-color);
183
+ box-shadow:
184
+ 0 1px 7px var(--suggestion-arrow-box-shadow-left-color),
185
+ 0 1px 7px var(--suggestion-arrow-box-shadow-right-color);
186
+ content: "";
187
+ transform: translateX(-50%) translateY(-50%) rotate(45deg);
188
+ }
189
+ .pops-${popsType}-search-suggestion[data-popper-placement^="bottom"] .pops-${popsType}-search-suggestion-arrow{
190
+ top: -12.5px;
191
+ left: 50%;
192
+ transform: translateX(-50%);
193
+ }
194
+ .pops-${popsType}-search-suggestion[data-popper-placement^="bottom"] .pops-${popsType}-search-suggestion-arrow::after{
195
+ position: absolute;
196
+ top: 100%;
197
+ left: 50%;
198
+ content: "";
199
+ }
200
+ </style>
201
+ <style type="text/css" data-dynamic="true">
202
+ ${SearchSuggestion.getDynamicCSS()}
203
+ </style>
204
+ <style>
205
+ .el-zoom-in-top-animation{
206
+ --el-transition-md-fade: transform 0.3s cubic-bezier(0.23, 1, 0.32, 1),
207
+ opacity 0.3s cubic-bezier(0.23, 1, 0.32, 1);
208
+ transition: var(--el-transition-md-fade);
209
+ transform-origin: center top;
210
+ }
211
+ .el-zoom-in-top-animation[data-popper-placement^="top"] {
212
+ transform-origin: center bottom;
213
+ }
214
+ .el-zoom-in-top-animation-hide{
215
+ opacity: 0;
216
+ transform: scaleY(0);
217
+ }
218
+ .el-zoom-in-top-animation-show{
219
+ opacity: 1;
220
+ transform: scaleY(1);
221
+ }
222
+ </style>
223
+ <style type="text/css" data-user-css>
224
+ ${config.style || ""}
225
+ </style>
226
+ <ul class="pops-${popsType}-search-suggestion-hint ${PopsCommonCSSClassName.userSelectNone}">${
227
+ config.toSearhNotResultHTML
228
+ }</ul>
229
+ ${config.useArrow ? /*html*/ `<div class="pops-${popsType}-search-suggestion-arrow"></div>` : ""}
230
+ `,
231
+ },
232
+ {
233
+ "data-guid": guid,
234
+ "type-value": popsType,
235
+ }
236
+ );
237
+ if (config.className !== "" && config.className != null) {
238
+ popsDOMUtils.addClassName($el, config.className);
239
+ }
240
+ if (config.isAnimation) {
241
+ popsDOMUtils.addClassName($el, `pops-${popsType}-animation`);
242
+ }
243
+ if (config.useFoldAnimation) {
244
+ popsDOMUtils.addClassName($el, "el-zoom-in-top-animation");
245
+ }
246
+ return $el;
247
+ },
248
+ /**
249
+ * 动态获取CSS
250
+ */
251
+ getDynamicCSS() {
252
+ return /*css*/ `
253
+ .pops-${popsType}-search-suggestion{
254
+ --search-suggestion-bg-color: #ffffff;
255
+ --search-suggestion-box-shadow-color: rgb(0 0 0 / 20%);
256
+ --search-suggestion-item-color: #515a6e;
257
+ --search-suggestion-item-none-color: #8e8e8e;
258
+ --search-suggestion-item-is-hover-bg-color: #f5f7fa;
259
+ --search-suggestion-item-is-select-bg-color: #409eff;
260
+ }
261
+ .pops-${popsType}-search-suggestion{
262
+ border: initial;
263
+ overflow: initial;
264
+ position: ${config.isAbsolute ? "absolute" : "fixed"};
265
+ z-index: ${PopsHandler.handleZIndex(config.zIndex)};
266
+ }
267
+ ul.pops-${popsType}-search-suggestion-hint{
268
+ max-height: ${config.maxHeight};
269
+ overflow-x: hidden;
270
+ overflow-y: auto;
271
+ padding: 5px 0;
272
+ background-color: var(--search-suggestion-bg-color);
273
+ box-sizing: border-box;
274
+ border-radius: 4px;
275
+ box-shadow: 0 1px 6px var(--search-suggestion-box-shadow-color);
276
+ }
277
+ /* 建议框在上面时 */
278
+ .pops-${popsType}-search-suggestion[data-top-reverse] ul.pops-${popsType}-search-suggestion-hint{
279
+ display: flex;
280
+ flex-direction: column-reverse;
281
+ }
282
+ .pops-${popsType}-search-suggestion[data-top-reverse] ul.pops-${popsType}-search-suggestion-hint li{
283
+ flex-shrink: 0;
284
+ }
285
+ ul.pops-${popsType}-search-suggestion-hint li{
286
+ padding: 7px;
287
+ margin: 0;
288
+ clear: both;
289
+ color: var(--search-suggestion-item-color);
290
+ font-size: 14px;
291
+ list-style: none;
292
+ cursor: pointer;
293
+ transition: background .2s ease-in-out;
294
+ overflow: hidden;
295
+ text-overflow: ellipsis;
296
+ width: 100%;
297
+ }
298
+ ul.pops-${popsType}-search-suggestion-hint li[data-none]{
299
+ text-align: center;
300
+ font-size: 12px;
301
+ color: var(--search-suggestion-item-none-color);
302
+ }
303
+ ul.pops-${popsType}-search-suggestion-hint li:not([data-none]):hover{
304
+ background-color: var(--search-suggestion-item-is-hover-bg-color);
305
+ }
306
+ @media (prefers-color-scheme: dark){
307
+ .pops-${popsType}-search-suggestion{
308
+ --search-suggestion-bg-color: #1d1e1f;
309
+ --search-suggestion-item-color: #cfd3d4;
310
+ --search-suggestion-item-is-hover-bg-color: rgba(175, 175, 175, .1);
311
+ }
312
+ }
313
+ `;
314
+ },
315
+ /**
316
+ * 获取data-value值
317
+ * @param data 数据项
318
+ */
319
+ getItemDataValue(data: PopsSearchSuggestionData<T>) {
320
+ return data;
321
+ },
322
+ /**
323
+ * 获取显示出搜索建议框的每一项的html
324
+ * @param dataItem 当前项的值
325
+ * @param dateItemIndex 当前项的下标
326
+ */
327
+ createSearchItemLiElement(dataItem: PopsSearchSuggestionData<T>, dateItemIndex: number) {
328
+ const dataValue = SearchSuggestion.getItemDataValue(dataItem);
329
+ const $li = popsDOMUtils.createElement("li", {
330
+ className: `pops-${popsType}-search-suggestion-hint-item`,
331
+ "data-index": dateItemIndex,
332
+ "data-value": dataValue,
333
+ });
334
+ Reflect.set($li, "data-index", dateItemIndex);
335
+ Reflect.set($li, "data-value", dataValue);
336
+ // 项内容
337
+ const $itemInner = dataItem.itemView(dataItem, $li, config);
338
+ if (typeof $itemInner === "string") {
339
+ PopsSafeUtils.setSafeHTML($li, $itemInner);
340
+ } else {
341
+ popsDOMUtils.append($li, $itemInner);
342
+ }
343
+ // 删除按钮
344
+ const enableDeleteButton = dataItem.enableDeleteButton;
345
+ if (typeof enableDeleteButton === "boolean" && enableDeleteButton) {
346
+ const $deleteIcon = SearchSuggestion.createItemDeleteIcon();
347
+ popsDOMUtils.append($li, $deleteIcon);
348
+ }
349
+ popsDOMUtils.addClassName($li, PopsCommonCSSClassName.flexCenter);
350
+ popsDOMUtils.addClassName($li, PopsCommonCSSClassName.flexYCenter);
351
+ return $li;
352
+ },
353
+ /**
354
+ * 设置搜索建议框每一项的点击事件
355
+ * @param $searchItem 当前项的元素
356
+ */
357
+ setSearchItemClickEvent($searchItem: HTMLLIElement) {
358
+ popsDOMUtils.on(
359
+ $searchItem,
360
+ "click",
361
+ async (event) => {
362
+ popsDOMUtils.preventEvent(event);
363
+ const $click = event.target as HTMLLIElement;
364
+ const data = SearchSuggestion.getData();
365
+ const dataItem = Reflect.get($searchItem, "data-value") as PopsSearchSuggestionData<T>;
366
+ const isDelete = Boolean($click.closest(`.pops-${popsType}-delete-icon`));
367
+ if (isDelete) {
368
+ // 删除
369
+ if (typeof dataItem.deleteButtonClickCallback === "function") {
370
+ const result = await dataItem.deleteButtonClickCallback(event, $searchItem, dataItem, config);
371
+ if (typeof result === "boolean" && result) {
372
+ data.splice(data.indexOf(dataItem), 1);
373
+ $searchItem.remove();
374
+ }
375
+ }
376
+ if (!SearchSuggestion.$el.$hintULContainer.children.length) {
377
+ /* 全删完了 */
378
+ SearchSuggestion.clear();
379
+ }
380
+ SearchSuggestion.updateStyleSheet();
381
+ } else {
382
+ // 点击选择项
383
+ if (typeof dataItem.clickCallback === "function") {
384
+ const result = await dataItem.clickCallback(event, $searchItem, dataItem, config);
385
+ if (typeof result === "boolean" && result) {
386
+ if (
387
+ config.inputTarget instanceof HTMLInputElement ||
388
+ config.inputTarget instanceof HTMLTextAreaElement
389
+ ) {
390
+ config.inputTarget.value = String(dataItem.value);
391
+ }
392
+ }
393
+ }
394
+ }
395
+ },
396
+ {
397
+ capture: true,
398
+ }
399
+ );
400
+ },
401
+ /**
402
+ * 设置搜索建议框每一项的选中事件
403
+ * @param liElement
404
+ */
405
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
406
+ setSearchItemSelectEvent(liElement: HTMLLIElement) {
407
+ // popsDOMUtils.on(
408
+ // liElement,
409
+ // "keyup",
410
+ // void 0,
411
+ // (event) => {
412
+ // let value = liElement["data-value"];
413
+ // config.selectCallBack(event, liElement, value);
414
+ // },
415
+ // {
416
+ // capture: true,
417
+ // }
418
+ // );
419
+ },
420
+ /**
421
+ * 监听输入框内容改变
422
+ */
423
+ setInputChangeEvent(
424
+ option: AddEventListenerOptions = {
425
+ capture: true,
426
+ }
427
+ ) {
428
+ /* 必须是input或者textarea才有input事件 */
429
+ if (!(config.inputTarget instanceof HTMLInputElement || config.inputTarget instanceof HTMLTextAreaElement)) {
430
+ return;
431
+ }
432
+ /* 是input输入框 */
433
+ /* 禁用输入框自动提示 */
434
+ config.inputTarget.setAttribute("autocomplete", "off");
435
+ /* 内容改变事件 */
436
+ const listenerHandler = popsDOMUtils.onInput(
437
+ config.inputTarget,
438
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
439
+ async (_event) => {
440
+ const data = SearchSuggestion.getData();
441
+ const queryDataResult = await config.inputTargetChangeRefreshShowDataCallback(
442
+ config.inputTarget.value,
443
+ data,
444
+ config
445
+ );
446
+ SearchSuggestion.update(queryDataResult);
447
+ SearchSuggestion.updateStyleSheet();
448
+ },
449
+ option
450
+ );
451
+ SearchSuggestion.$evt.offInputChangeEvtHandler.push(listenerHandler.off);
452
+ },
453
+ /**
454
+ * 移除输入框内容改变的监听
455
+ */
456
+ removeInputChangeEvent(
457
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
458
+ option: AddEventListenerOptions = {
459
+ capture: true,
460
+ }
461
+ ) {
462
+ for (let index = 0; index < SearchSuggestion.$evt.offInputChangeEvtHandler.length; index++) {
463
+ const handler = SearchSuggestion.$evt.offInputChangeEvtHandler[index];
464
+ handler();
465
+ SearchSuggestion.$evt.offInputChangeEvtHandler.splice(index, 1);
466
+ index--;
467
+ }
468
+ },
469
+ /**
470
+ * 显示搜索建议框的事件
471
+ */
472
+ showEvent() {
473
+ SearchSuggestion.updateStyleSheet();
474
+ if (config.toHideWithNotResult) {
475
+ if (SearchSuggestion.$data.isEmpty) {
476
+ SearchSuggestion.hide(true);
477
+ } else {
478
+ SearchSuggestion.show();
479
+ }
480
+ } else {
481
+ SearchSuggestion.show();
482
+ }
483
+ },
484
+ /**
485
+ * 设置显示搜索建议框的事件
486
+ */
487
+ setShowEvent(
488
+ option: AddEventListenerOptions = {
489
+ capture: true,
490
+ }
491
+ ) {
492
+ /* 焦点|点击事件*/
493
+ if (config.followPosition === "target") {
494
+ popsDOMUtils.on([config.target], ["focus", "click"], void 0, SearchSuggestion.showEvent, option);
495
+ } else if (config.followPosition === "input") {
496
+ popsDOMUtils.on([config.inputTarget], ["focus", "click"], void 0, SearchSuggestion.showEvent, option);
497
+ } else if (config.followPosition === "inputCursor") {
498
+ popsDOMUtils.on(
499
+ [config.inputTarget],
500
+ ["focus", "click", "input"],
501
+ void 0,
502
+ SearchSuggestion.showEvent,
503
+ option
504
+ );
505
+ } else {
506
+ throw new Error("未知followPosition:" + config.followPosition);
507
+ }
508
+ },
509
+ /**
510
+ * 移除显示搜索建议框的事件
511
+ */
512
+ removeShowEvent(
513
+ option: AddEventListenerOptions = {
514
+ capture: true,
515
+ }
516
+ ) {
517
+ /* 焦点|点击事件*/
518
+ popsDOMUtils.off(
519
+ [config.target, config.inputTarget],
520
+ ["focus", "click"],
521
+ void 0,
522
+ SearchSuggestion.showEvent,
523
+ option
524
+ );
525
+ /* 内容改变事件 */
526
+ popsDOMUtils.off([config.inputTarget], ["input"], void 0, SearchSuggestion.showEvent, option);
527
+ },
528
+ /**
529
+ * 隐藏搜索建议框的事件
530
+ * @param event
531
+ */
532
+ hideEvent(event: PointerEvent | MouseEvent) {
533
+ if (event.target instanceof Node) {
534
+ if ($shadowContainer.contains(event.target)) {
535
+ /* 点击在shadow上的 */
536
+ return;
537
+ }
538
+ if (config.target.contains(event.target)) {
539
+ /* 点击在目标元素内 */
540
+ return;
541
+ }
542
+ if (config.inputTarget.contains(event.target)) {
543
+ /* 点击在目标input内 */
544
+ return;
545
+ }
546
+ SearchSuggestion.hide(true);
547
+ }
548
+ },
549
+ /**
550
+ * 设置隐藏搜索建议框的事件
551
+ */
552
+ setHideEvent(
553
+ option: AddEventListenerOptions = {
554
+ capture: true,
555
+ }
556
+ ) {
557
+ /* 全局点击事件 */
558
+ /* 全局触摸屏点击事件 */
559
+ if (Array.isArray(SearchSuggestion.selfDocument)) {
560
+ SearchSuggestion.selfDocument.forEach(($checkParent) => {
561
+ popsDOMUtils.on($checkParent, ["click", "touchstart"], void 0, SearchSuggestion.hideEvent, option);
562
+ });
563
+ } else {
564
+ popsDOMUtils.on(
565
+ SearchSuggestion.selfDocument,
566
+ ["click", "touchstart"],
567
+ void 0,
568
+ SearchSuggestion.hideEvent,
569
+ option
570
+ );
571
+ }
572
+ },
573
+ /**
574
+ * 移除隐藏搜索建议框的事件
575
+ */
576
+ removeHideEvent(
577
+ option: AddEventListenerOptions = {
578
+ capture: true,
579
+ }
580
+ ) {
581
+ if (Array.isArray(SearchSuggestion.selfDocument)) {
582
+ SearchSuggestion.selfDocument.forEach(($checkParent) => {
583
+ popsDOMUtils.off($checkParent, ["click", "touchstart"], void 0, SearchSuggestion.hideEvent, option);
584
+ });
585
+ } else {
586
+ popsDOMUtils.off(
587
+ SearchSuggestion.selfDocument,
588
+ ["click", "touchstart"],
589
+ void 0,
590
+ SearchSuggestion.hideEvent,
591
+ option
592
+ );
593
+ }
594
+ },
595
+ /**
596
+ * 设置所有监听
597
+ */
598
+ setAllEvent(
599
+ option: AddEventListenerOptions = {
600
+ capture: true,
601
+ }
602
+ ) {
603
+ SearchSuggestion.setInputChangeEvent(option);
604
+ SearchSuggestion.setHideEvent(option);
605
+ SearchSuggestion.setShowEvent(option);
606
+ },
607
+ /**
608
+ * 移除所有监听
609
+ */
610
+ removeAllEvent(
611
+ option: AddEventListenerOptions = {
612
+ capture: true,
613
+ }
614
+ ) {
615
+ SearchSuggestion.removeInputChangeEvent(option);
616
+ SearchSuggestion.removeHideEvent(option);
617
+ SearchSuggestion.removeShowEvent(option);
618
+ },
619
+ /**
620
+ * 获取删除按钮的html
621
+ */
622
+ createItemDeleteIcon(size = 16, fill = "#bababa") {
623
+ const $svg = popsDOMUtils.parseTextToDOM(/*html*/ `
624
+ <svg class="pops-${popsType}-delete-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="${fill}">
625
+ <path d="M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z"></path>
626
+ <path d="M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z"></path>
627
+ </svg>
628
+ `);
629
+ return $svg;
630
+ },
631
+ /**
632
+ * 设置当前正在搜索中的提示
633
+ */
634
+ setPromptsInSearch() {
635
+ const $isSearching = popsDOMUtils.createElement("li", {
636
+ className: `pops-${popsType}-search-suggestion-hint-searching-item`,
637
+ innerHTML: config.searchingTip,
638
+ });
639
+ SearchSuggestion.addItem($isSearching);
640
+ },
641
+ /**
642
+ * 移除正在搜索中的提示
643
+ */
644
+ removePromptsInSearch() {
645
+ SearchSuggestion.$el.$hintULContainer
646
+ .querySelector<HTMLLIElement>(`li.pops-${popsType}-search-suggestion-hint-searching-item`)
647
+ ?.remove();
648
+ },
649
+ /**
650
+ * 更新搜索建议框的位置(top、left)
651
+ * 因为目标元素可能是动态隐藏的
652
+ * @param target 目标元素
653
+ * @param checkPositonAgain 是否在更新位置信息后检测更新位置信息,默认true
654
+ */
655
+ changeHintULElementPosition(target = config.target ?? config.inputTarget, checkPositonAgain: boolean = true) {
656
+ let targetRect: DOMRect | null = null;
657
+ if (config.followPosition === "inputCursor") {
658
+ targetRect = popsDOMUtils.getTextBoundingRect(
659
+ config.inputTarget,
660
+ config.inputTarget.selectionStart || 0,
661
+ config.inputTarget.selectionEnd || 0,
662
+ false
663
+ );
664
+ } else {
665
+ targetRect = config.isAbsolute ? popsDOMUtils.offset(target) : target.getBoundingClientRect();
666
+ }
667
+ if (targetRect == null) {
668
+ return;
669
+ }
670
+ // 文档最大高度
671
+ let documentHeight = document.documentElement.clientHeight;
672
+ if (config.isAbsolute) {
673
+ // 绝对定位
674
+ documentHeight = popsDOMUtils.height(document);
675
+ }
676
+ // 文档最大宽度
677
+ const documentWidth = popsDOMUtils.width(document);
678
+
679
+ let position = config.position;
680
+ if (config.position === "auto") {
681
+ // 需目标高度+搜索建议框高度大于文档高度,则显示在上面
682
+ const targetBottom = targetRect.bottom;
683
+ const searchSuggestionContainerHeight = popsDOMUtils.height(SearchSuggestion.$el.$hintULContainer);
684
+ if (targetBottom + searchSuggestionContainerHeight > documentHeight) {
685
+ // 在上面
686
+ position = "top";
687
+ } else {
688
+ // 在下面
689
+ position = "bottom";
690
+ }
691
+ }
692
+ if (position === "top") {
693
+ // 在上面
694
+ if (config.positionTopToReverse) {
695
+ // 自动翻转
696
+ SearchSuggestion.$el.root.setAttribute("data-top-reverse", "true");
697
+ }
698
+ if (config.useFoldAnimation) {
699
+ // 翻转折叠
700
+ SearchSuggestion.$el.root.setAttribute("data-popper-placement", "top");
701
+ }
702
+ const bottom = documentHeight - targetRect.top + config.topDistance;
703
+ SearchSuggestion.$el.root.style.top = "";
704
+ SearchSuggestion.$el.root.style.bottom = bottom + "px";
705
+ } else if (position === "bottom") {
706
+ // 在下面
707
+ if (config.useFoldAnimation) {
708
+ SearchSuggestion.$el.root.setAttribute("data-popper-placement", "bottom-center");
709
+ }
710
+ const top = targetRect.height + targetRect.top + config.topDistance;
711
+ SearchSuggestion.$el.root.removeAttribute("data-top-reverse");
712
+ SearchSuggestion.$el.root.style.bottom = "";
713
+ SearchSuggestion.$el.root.style.top = top + "px";
714
+ }
715
+ let left = targetRect.left;
716
+ const hintUIWidth = popsDOMUtils.width(SearchSuggestion.$el.$hintULContainer);
717
+ if (hintUIWidth > documentWidth) {
718
+ // 超出宽度
719
+ left = left + documentWidth - hintUIWidth;
720
+ }
721
+ SearchSuggestion.$el.root.style.left = left + "px";
722
+
723
+ // 如果更新前在下面的话且高度超出了屏幕
724
+ // 这时候会有滚动条,会造成位置偏移
725
+ // 更新后的位置却在上面,这时候的位置信息不对齐
726
+ // 需重新更新位置
727
+ // 此情况一般是config.position === "auto"
728
+ if (checkPositonAgain) {
729
+ SearchSuggestion.changeHintULElementPosition(target, !checkPositonAgain);
730
+ }
731
+ },
732
+ /**
733
+ * 更新搜索建议框的width
734
+ * 因为目标元素可能是动态隐藏的
735
+ * @param target 目标元素
736
+ */
737
+ changeHintULElementWidth(target = config.target ?? config.inputTarget) {
738
+ const targetRect = target.getBoundingClientRect();
739
+ if (config.followTargetWidth) {
740
+ SearchSuggestion.$el.$hintULContainer.style.width = targetRect.width + "px";
741
+ } else {
742
+ SearchSuggestion.$el.$hintULContainer.style.width = config.width;
743
+ }
744
+ },
745
+ /**
746
+ * 动态更新CSS
747
+ */
748
+ updateDynamicCSS() {
749
+ const cssText = SearchSuggestion.getDynamicCSS();
750
+ PopsSafeUtils.setSafeHTML(SearchSuggestion.$el.$dynamicCSS, cssText);
751
+ },
752
+ /**
753
+ * 数据项的数量改变时调用
754
+ *
755
+ * - 更新css
756
+ * - 更新建议框的宽度
757
+ * - 更新建议框的位置
758
+ */
759
+ updateStyleSheet() {
760
+ // 更新z-index
761
+ SearchSuggestion.updateDynamicCSS();
762
+ // 更新宽度
763
+ SearchSuggestion.changeHintULElementWidth();
764
+ // 更新位置
765
+ SearchSuggestion.changeHintULElementPosition();
766
+ },
767
+ /**
768
+ * 添加搜索结果元素
769
+ * @param $item 项元素
770
+ */
771
+ addItem($item: HTMLElement | DocumentFragment) {
772
+ SearchSuggestion.$el.$hintULContainer.appendChild($item);
773
+ },
774
+ /**
775
+ * 更新页面显示的搜索结果
776
+ * @param updateData
777
+ */
778
+ update(updateData: PopsSearchSuggestionData<T>[] = []) {
779
+ if (!Array.isArray(updateData)) {
780
+ throw new TypeError("传入的数据不是数组");
781
+ }
782
+ const data = updateData;
783
+ /* 清空已有的搜索结果 */
784
+ if (data.length) {
785
+ SearchSuggestion.$data.isEmpty = false;
786
+ if (config.toHideWithNotResult) {
787
+ SearchSuggestion.show();
788
+ }
789
+ SearchSuggestion.clear(true);
790
+ /* 添加进ul中 */
791
+ const fragment = document.createDocumentFragment();
792
+ data.forEach((item, index) => {
793
+ const $item = SearchSuggestion.createSearchItemLiElement(item, index);
794
+ SearchSuggestion.setSearchItemClickEvent($item);
795
+ SearchSuggestion.setSearchItemSelectEvent($item);
796
+ fragment.appendChild($item);
797
+ });
798
+ SearchSuggestion.addItem(fragment);
799
+ } else {
800
+ /* 清空 */
801
+ SearchSuggestion.clear();
802
+ }
803
+ },
804
+ /**
805
+ * 清空当前的搜索结果并显示无结果
806
+ * @param [onlyClearView=false] 是否仅清空元素,默认false
807
+ */
808
+ clear(onlyClearView: boolean = false) {
809
+ PopsSafeUtils.setSafeHTML(SearchSuggestion.$el.$hintULContainer, "");
810
+ if (onlyClearView) {
811
+ return;
812
+ }
813
+ SearchSuggestion.$data.isEmpty = true;
814
+ let $noResult;
815
+ if (typeof config.toSearhNotResultHTML === "string") {
816
+ $noResult = popsDOMUtils.parseTextToDOM(config.toSearhNotResultHTML);
817
+ } else {
818
+ $noResult = config.toSearhNotResultHTML();
819
+ }
820
+ SearchSuggestion.addItem($noResult);
821
+ if (config.toHideWithNotResult) {
822
+ SearchSuggestion.hide();
823
+ }
824
+ },
825
+ /**
826
+ * 隐藏搜索建议框
827
+ * @param useAnimationToHide 是否使用动画隐藏
828
+ */
829
+ hide(useAnimationToHide: boolean = false) {
830
+ if (config.useFoldAnimation) {
831
+ if (!useAnimationToHide) {
832
+ // 去掉动画
833
+ popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
834
+ }
835
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
836
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-hide");
837
+ popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-show");
838
+ } else {
839
+ SearchSuggestion.$el.root.style.display = "none";
840
+ }
841
+ },
842
+ /**
843
+ * 显示搜索建议框
844
+ */
845
+ show() {
846
+ SearchSuggestion.$el.root.style.display = "";
847
+ if (config.useFoldAnimation) {
848
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
849
+ popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-hide");
850
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-show");
851
+ }
852
+ },
853
+ };
854
+ return SearchSuggestion;
855
+ },
856
+ };