tosijs-ui 1.0.0 → 1.0.2

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 (94) hide show
  1. package/README.md +4 -2
  2. package/dist/iife.js +70 -60
  3. package/dist/iife.js.map +42 -42
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +15 -37
  6. package/dist/index.js.map +39 -39
  7. package/dist/version.d.ts +1 -1
  8. package/package.json +2 -2
  9. package/dist/ab-test.js +0 -116
  10. package/dist/babylon-3d.js +0 -292
  11. package/dist/bodymovin-player.js +0 -172
  12. package/dist/bp-loader.js +0 -26
  13. package/dist/carousel.js +0 -308
  14. package/dist/code-editor.js +0 -102
  15. package/dist/color-input.js +0 -112
  16. package/dist/data-table.js +0 -774
  17. package/dist/drag-and-drop.js +0 -386
  18. package/dist/editable-rect.js +0 -450
  19. package/dist/filter-builder.js +0 -468
  20. package/dist/float.js +0 -170
  21. package/dist/form.js +0 -466
  22. package/dist/gamepad.js +0 -115
  23. package/dist/icon-data.js +0 -308
  24. package/dist/icon-types.js +0 -1
  25. package/dist/icons.js +0 -374
  26. package/dist/index-iife.js +0 -4
  27. package/dist/live-example.js +0 -611
  28. package/dist/localize.js +0 -381
  29. package/dist/make-sorter.js +0 -119
  30. package/dist/make-sorter.test.d.ts +0 -1
  31. package/dist/make-sorter.test.js +0 -48
  32. package/dist/mapbox.js +0 -161
  33. package/dist/markdown-viewer.js +0 -173
  34. package/dist/match-shortcut.js +0 -13
  35. package/dist/match-shortcut.test.d.ts +0 -1
  36. package/dist/match-shortcut.test.js +0 -194
  37. package/dist/menu.js +0 -614
  38. package/dist/notifications.js +0 -308
  39. package/dist/password-strength.js +0 -302
  40. package/dist/playwright.config.d.ts +0 -9
  41. package/dist/playwright.config.js +0 -73
  42. package/dist/pop-float.js +0 -231
  43. package/dist/rating.js +0 -192
  44. package/dist/rich-text.js +0 -296
  45. package/dist/segmented.js +0 -298
  46. package/dist/select.js +0 -427
  47. package/dist/side-nav.js +0 -106
  48. package/dist/size-break.js +0 -118
  49. package/dist/sizer.js +0 -92
  50. package/dist/src/ab-test.d.ts +0 -14
  51. package/dist/src/babylon-3d.d.ts +0 -53
  52. package/dist/src/bodymovin-player.d.ts +0 -32
  53. package/dist/src/bp-loader.d.ts +0 -0
  54. package/dist/src/carousel.d.ts +0 -113
  55. package/dist/src/code-editor.d.ts +0 -27
  56. package/dist/src/color-input.d.ts +0 -41
  57. package/dist/src/data-table.d.ts +0 -79
  58. package/dist/src/drag-and-drop.d.ts +0 -2
  59. package/dist/src/editable-rect.d.ts +0 -97
  60. package/dist/src/filter-builder.d.ts +0 -64
  61. package/dist/src/float.d.ts +0 -18
  62. package/dist/src/form.d.ts +0 -68
  63. package/dist/src/gamepad.d.ts +0 -34
  64. package/dist/src/icon-data.d.ts +0 -309
  65. package/dist/src/icon-types.d.ts +0 -7
  66. package/dist/src/icons.d.ts +0 -17
  67. package/dist/src/index.d.ts +0 -37
  68. package/dist/src/live-example.d.ts +0 -51
  69. package/dist/src/localize.d.ts +0 -30
  70. package/dist/src/make-sorter.d.ts +0 -3
  71. package/dist/src/mapbox.d.ts +0 -24
  72. package/dist/src/markdown-viewer.d.ts +0 -15
  73. package/dist/src/match-shortcut.d.ts +0 -9
  74. package/dist/src/menu.d.ts +0 -60
  75. package/dist/src/notifications.d.ts +0 -106
  76. package/dist/src/password-strength.d.ts +0 -35
  77. package/dist/src/pop-float.d.ts +0 -10
  78. package/dist/src/rating.d.ts +0 -62
  79. package/dist/src/rich-text.d.ts +0 -28
  80. package/dist/src/segmented.d.ts +0 -80
  81. package/dist/src/select.d.ts +0 -43
  82. package/dist/src/side-nav.d.ts +0 -36
  83. package/dist/src/size-break.d.ts +0 -18
  84. package/dist/src/sizer.d.ts +0 -34
  85. package/dist/src/tab-selector.d.ts +0 -91
  86. package/dist/src/tag-list.d.ts +0 -37
  87. package/dist/src/track-drag.d.ts +0 -5
  88. package/dist/src/version.d.ts +0 -1
  89. package/dist/src/via-tag.d.ts +0 -2
  90. package/dist/tab-selector.js +0 -326
  91. package/dist/tag-list.js +0 -375
  92. package/dist/track-drag.js +0 -143
  93. package/dist/version.js +0 -1
  94. package/dist/via-tag.js +0 -102
@@ -1,468 +0,0 @@
1
- /*#
2
- # filter
3
-
4
- Automatically creates `ArrayFilter` functions `(a: any[]) => any[]` based on the query you build using its
5
- macOS Finder-inspired interface, using an easily customizable / extensible collection of `Filter` objects.
6
-
7
- ```js
8
- const { elements } = xinjs
9
- const { dataTable, filterBuilder, availableFilters } = xinjsui
10
-
11
- const sourceWords = ['acorn', 'bubblegum', 'copper', 'daisy', 'ellipse', 'fabulous', 'gerund', 'hopscotch', 'idiom', 'joke']
12
- function randomWords () {
13
- let numWords = Math.random() * 4
14
- const words = []
15
- while (numWords > 0) {
16
- numWords -= 1
17
- words.push(sourceWords[Math.floor(Math.random() * 10)])
18
- }
19
- return [...new Set(words)]
20
- }
21
-
22
- const array = []
23
- for(let i = 0; i < 1000; i++) {
24
- array.push({
25
- date: new Date(Math.random() * Date.now()).toISOString().split('T')[0],
26
- isLucky: Math.random() < 0.1,
27
- number: Math.floor(Math.random() * 200 - 100),
28
- string: randomWords().join(' '),
29
- tags: randomWords()
30
- })
31
- }
32
-
33
- const { span } = elements
34
- const tagsBinding = {
35
- value: '^.tags',
36
- binding: {
37
- toDOM(element, value) {
38
- element.classList.add('tag-list')
39
- element.textContent = ''
40
- element.append(...value.map(tag => span(tag, {class: 'tag'})))
41
- }
42
- }
43
- }
44
-
45
- const columns = [
46
- {
47
- prop: 'date',
48
- width: 120
49
- },
50
- {
51
- prop: 'isLucky',
52
- type: 'boolean',
53
- width: 90
54
- },
55
- {
56
- prop: 'number',
57
- align: 'right',
58
- width: 90
59
- },
60
- {
61
- prop: 'string',
62
- width: 200
63
- },
64
- {
65
- prop: 'tags',
66
- width: 200,
67
- dataCell() {
68
- return elements.div({ bind: tagsBinding })
69
- }
70
- },
71
- ]
72
-
73
- const table = dataTable({ array, columns })
74
- const filter = filterBuilder({
75
- fields: columns,
76
- onChange(event) {
77
- table.filter = filter.filter
78
- }
79
- })
80
- preview.append(filter, table)
81
- ```
82
- ```css
83
- .preview {
84
- display: flex;
85
- flex-direction: column;
86
- }
87
-
88
- .preview xin-table {
89
- flex: 1 1 auto;
90
- }
91
-
92
- .preview .tag-list {
93
- display: flex;
94
- font-size: 80%;
95
- align-items: center;
96
- gap: 2px;
97
- }
98
-
99
- .preview .tag {
100
- display: inline-block;
101
- border-radius: 4px;
102
- padding: 0 5px;
103
- line-height: 20px;
104
- height: 20px;
105
- color: var(--brand-text-color);
106
- background: var(--brand-color);
107
- }
108
- ```
109
-
110
- ## serialization
111
-
112
- The current state of a `<xin-filter>` can be serialized as, and restored from, a Javascript object (which itself
113
- can easily be converted into JSON or a URL component) via its `state` property. Obviously, a `<xin-filter>` can
114
- only restore state if it has the necessary constituent `filters`.
115
-
116
- ## availableFilters
117
-
118
- `<xin-filter>` has a default set of `FilterMaker` objects which it uses to construct filter function.
119
- In the example above, the default collection of filters is reduced to `contains`, `equals`, `after`, and `isTrue`.
120
-
121
- The full collection includes:
122
-
123
- - **contains** * looks for fields containing a string (ignoring case)
124
- - **equals** * looks for fields containing equivalent values (ignoring case)
125
- - **after** * looks for fields with a date after a provided value
126
- - **greaterThan** * looks for fields with a value greater than a provided value
127
- - **truthy** * looks for fields that are true / non-zero / non-empty
128
- - **true** looks for fields that are `true`
129
- - **false** looks for fields that are `false`
130
- - **hasTags** looks for fields that are arrays containing all the (space/comma) delimited strings
131
- - **doesNotHaveTags** looks for fields that are arrays containing *none* of the strings
132
-
133
- **Note**: the filters marked with an * have negative version (e.g. does not contain).
134
-
135
- ```
136
- type ObjectTest (obj: any) => boolean
137
-
138
- interface FilterMaker {
139
- caption: string // describes the test condition
140
- negative?: string // describes the negative test condition
141
- needsValue?: boolean // if false, the filterMaker doesn't need a needle value
142
- filterMaker(needle: any) => ObjectTest // builds an ObjectTest
143
- }
144
- ```
145
- */
146
- import { Component as WebComponent, elements } from 'xinjs';
147
- import { icons } from '../src/';
148
- const { div, input, select, option, button, span } = elements;
149
- const passThru = (array) => array;
150
- const NULL_FILTER_DESCRIPTION = 'null filter, everything matches';
151
- export const availableFilters = {
152
- contains: {
153
- caption: 'contains',
154
- negative: 'does not contain',
155
- makeTest: (value) => {
156
- value = value.toLocaleLowerCase();
157
- return (obj) => String(obj).toLocaleLowerCase().includes(value);
158
- },
159
- },
160
- hasTags: {
161
- caption: 'has tags',
162
- makeTest: (value) => {
163
- const tags = value
164
- .split(/[\s,]/)
165
- .map((tag) => tag.trim().toLocaleLowerCase())
166
- .filter((tag) => tag !== '');
167
- console.log(tags);
168
- return (obj) => Array.isArray(obj) &&
169
- tags.find((tag) => !obj.includes(tag)) === undefined;
170
- },
171
- },
172
- doesNotHaveTags: {
173
- caption: 'does not have tags',
174
- makeTest: (value) => {
175
- const tags = value
176
- .split(/[\s,]/)
177
- .map((tag) => tag.trim().toLocaleLowerCase())
178
- .filter((tag) => tag !== '');
179
- console.log(tags);
180
- return (obj) => Array.isArray(obj) &&
181
- tags.find((tag) => obj.includes(tag)) === undefined;
182
- },
183
- },
184
- equals: {
185
- caption: '=',
186
- negative: '≠',
187
- makeTest: (value) => {
188
- if (isNaN(Number(value))) {
189
- value = String(value).toLocaleLowerCase();
190
- return (obj) => String(obj).toLocaleLowerCase() === value;
191
- }
192
- const num = Number(value);
193
- return (obj) => Number(obj) === num;
194
- },
195
- },
196
- after: {
197
- caption: 'is after',
198
- negative: 'is before',
199
- makeTest: (value) => {
200
- const date = new Date(value);
201
- return (obj) => new Date(obj) > date;
202
- },
203
- },
204
- greaterThan: {
205
- caption: '>',
206
- negative: '≤',
207
- makeTest: (value) => {
208
- if (!isNaN(Number(value))) {
209
- const num = Number(value);
210
- return (obj) => Number(obj) > num;
211
- }
212
- value = value.toLocaleLowerCase();
213
- return (obj) => String(obj).toLocaleLowerCase() > value;
214
- },
215
- },
216
- truthy: {
217
- caption: 'is true/non-empty/non-zero',
218
- negative: 'is false/empty/zero',
219
- needsValue: false,
220
- makeTest: () => (obj) => !!obj,
221
- },
222
- isTrue: {
223
- caption: '= true',
224
- needsValue: false,
225
- makeTest: () => (obj) => obj === true,
226
- },
227
- isFalse: {
228
- caption: '= false',
229
- needsValue: false,
230
- makeTest: () => (obj) => obj === false,
231
- },
232
- };
233
- const passAnything = {
234
- description: 'anything',
235
- test: () => true,
236
- };
237
- function getSelectText(select) {
238
- return select.options[select.selectedIndex].text;
239
- }
240
- export class FilterPart extends WebComponent {
241
- fields = [];
242
- filters = availableFilters;
243
- haystack = '*';
244
- condition = '';
245
- needle = '';
246
- content = () => [
247
- select({ part: 'haystack' }),
248
- icons.chevronDown(),
249
- select({ part: 'condition' }),
250
- icons.chevronDown(),
251
- input({ part: 'needle', type: 'search' }),
252
- span({ part: 'padding' }),
253
- button({ part: 'remove', title: 'delete' }, icons.trash()),
254
- ];
255
- filter = passAnything;
256
- constructor() {
257
- super();
258
- this.initAttributes('haystack', 'condition', 'needle');
259
- }
260
- get state() {
261
- const { haystack, needle, condition } = this.parts;
262
- return {
263
- haystack: haystack.value,
264
- needle: needle.value,
265
- condition: condition.value,
266
- };
267
- }
268
- set state(newState) {
269
- Object.assign(this, newState);
270
- }
271
- buildFilter = ( /* event: Event */) => {
272
- const { haystack, condition, needle } = this.parts;
273
- const negative = condition.value.startsWith('~');
274
- const key = negative ? condition.value.slice(1) : condition.value;
275
- const filter = this.filters[key];
276
- needle.hidden = filter.needsValue === false;
277
- const baseTest = filter.needsValue === false
278
- ? filter.makeTest(undefined)
279
- : filter.makeTest(needle.value);
280
- const field = haystack.value;
281
- let test;
282
- if (field !== '*') {
283
- test = negative
284
- ? (obj) => !baseTest(obj[field])
285
- : (obj) => baseTest(obj[field]);
286
- }
287
- else {
288
- test = negative
289
- ? (obj) => Object.values(obj).find((v) => !baseTest(v)) !== undefined
290
- : (obj) => Object.values(obj).find((v) => baseTest(v)) !== undefined;
291
- }
292
- const matchValue = filter.needsValue !== false ? ` "${needle.value}"` : '';
293
- const description = `${getSelectText(haystack)} ${getSelectText(condition)}${matchValue}`;
294
- this.filter = {
295
- description,
296
- test,
297
- };
298
- this.parentElement?.dispatchEvent(new Event('change'));
299
- };
300
- connectedCallback() {
301
- super.connectedCallback();
302
- const { haystack, condition, needle, remove } = this.parts;
303
- haystack.addEventListener('change', this.buildFilter);
304
- condition.addEventListener('change', this.buildFilter);
305
- needle.addEventListener('input', this.buildFilter);
306
- haystack.value = this.haystack;
307
- condition.value = this.condition;
308
- needle.value = this.needle;
309
- remove.addEventListener('click', () => {
310
- const { parentElement } = this;
311
- this.remove();
312
- parentElement?.dispatchEvent(new Event('change'));
313
- });
314
- }
315
- render() {
316
- super.render();
317
- const { haystack, condition, needle } = this.parts;
318
- haystack.textContent = '';
319
- haystack.append(option('any field', { value: '*' }), ...this.fields.map((field) => {
320
- const caption = field.name || field.prop;
321
- return option(`${caption}`, { value: field.prop });
322
- }));
323
- condition.textContent = '';
324
- const conditions = Object.keys(this.filters)
325
- .map((key) => {
326
- const filter = this.filters[key];
327
- return filter.negative !== undefined
328
- ? [
329
- option(filter.caption, { value: key }),
330
- option(filter.negative, { value: '~' + key }),
331
- ]
332
- : option(filter.caption, { value: key });
333
- })
334
- .flat();
335
- condition.append(...conditions);
336
- if (this.haystack !== '') {
337
- haystack.value = this.haystack;
338
- }
339
- if (this.condition !== '') {
340
- condition.value = this.condition;
341
- }
342
- if (this.needle !== '') {
343
- needle.value = this.needle;
344
- }
345
- this.buildFilter();
346
- }
347
- }
348
- export const filterPart = FilterPart.elementCreator({
349
- tag: 'xin-filter-part',
350
- styleSpec: {
351
- ':host': {
352
- display: 'flex',
353
- },
354
- ':host .xin-icon:': {
355
- verticalAlign: 'middle',
356
- pointerEvents: 'none',
357
- },
358
- ':host [part="haystack"], :host [part="condition"]': {
359
- flex: '1',
360
- },
361
- ':host [part="needle"]': {
362
- flex: 2,
363
- },
364
- ':host [hidden]+[part="padding"]': {
365
- display: 'block',
366
- content: ' ',
367
- flex: '1 1 auto',
368
- },
369
- },
370
- });
371
- export class FilterBuilder extends WebComponent {
372
- _fields = [];
373
- get fields() {
374
- return this._fields;
375
- }
376
- set fields(_fields) {
377
- this._fields = _fields;
378
- this.queueRender();
379
- }
380
- get state() {
381
- const { filterContainer } = this.parts;
382
- return [...filterContainer.children].map((part) => part.state);
383
- }
384
- set state(parts) {
385
- const { fields, filters } = this;
386
- const { filterContainer } = this.parts;
387
- filterContainer.textContent = '';
388
- for (const state of parts) {
389
- filterContainer.append(filterPart({ fields, filters, ...state }));
390
- }
391
- }
392
- filter = passThru;
393
- description = NULL_FILTER_DESCRIPTION;
394
- addFilter = () => {
395
- const { fields, filters } = this;
396
- const { filterContainer } = this.parts;
397
- filterContainer.append(filterPart({ fields, filters }));
398
- };
399
- content = () => [
400
- button({
401
- part: 'add',
402
- title: 'add filter condition',
403
- onClick: this.addFilter,
404
- class: 'round',
405
- }, icons.plus()),
406
- div({ part: 'filterContainer' }),
407
- button({ part: 'reset', title: 'reset filter', onClick: this.reset }, icons.x()),
408
- ];
409
- filters = availableFilters;
410
- reset = () => {
411
- const { fields, filters } = this;
412
- const { filterContainer } = this.parts;
413
- this.description = NULL_FILTER_DESCRIPTION;
414
- this.filter = passThru;
415
- filterContainer.textContent = '';
416
- filterContainer.append(filterPart({ fields, filters }));
417
- this.dispatchEvent(new Event('change'));
418
- };
419
- buildFilter = ( /* event: Event */) => {
420
- const { filterContainer } = this.parts;
421
- if (filterContainer.children.length === 0) {
422
- this.reset();
423
- return;
424
- }
425
- const filters = [...filterContainer.children].map((filterPart) => filterPart.filter);
426
- const tests = filters.map((filter) => filter.test);
427
- this.description = filters.map((filter) => filter.description).join(', ');
428
- this.filter = (array) => array.filter((obj) => tests.find((f) => f(obj) === false) === undefined);
429
- this.dispatchEvent(new Event('change'));
430
- };
431
- connectedCallback() {
432
- super.connectedCallback();
433
- const { filterContainer } = this.parts;
434
- filterContainer.addEventListener('change', this.buildFilter);
435
- this.reset();
436
- }
437
- render() {
438
- super.render();
439
- }
440
- }
441
- export const filterBuilder = FilterBuilder.elementCreator({
442
- tag: 'xin-filter',
443
- styleSpec: {
444
- ':host': {
445
- height: 'auto',
446
- display: 'grid',
447
- gridTemplateColumns: '32px calc(100% - 64px) 32px',
448
- alignItems: 'center',
449
- },
450
- ':host [part="filterContainer"]': {
451
- display: 'flex',
452
- flexDirection: 'column',
453
- alignItems: 'stretch',
454
- flex: '1 1 auto',
455
- },
456
- ':host [part="add"], :host [part="reset"]': {
457
- '--button-size': 'var(--touch-size, 32px)',
458
- borderRadius: '999px',
459
- height: 'var(--button-size)',
460
- lineHeight: 'var(--button-size)',
461
- margin: '0',
462
- padding: '0',
463
- textAlign: 'center',
464
- width: 'var(--button-size)',
465
- flex: '0 0 var(--button-size)',
466
- },
467
- },
468
- });
package/dist/float.js DELETED
@@ -1,170 +0,0 @@
1
- /*#
2
- # float
3
-
4
- A floating, potentially draggable user interface element.
5
-
6
- ```html
7
- <xin-float class="float" remain-on-resize="remain" remain-on-scroll="remain" drag>
8
- <h4>Drag Me</h4>
9
- <div class="no-drag balloon">🎈</div>
10
- <div class="behavior">I ignore resizing and scrolling</div>
11
- <footer style="font-size: 75%">neunundneunzig pixel-ballon</footer>
12
- </xin-float>
13
-
14
- <xin-float class="float" remain-on-scroll="remain" style="top: 50px; right: 20px;" drag>
15
- <h4>Drag Me</h4>
16
- <div class="no-drag balloon">🎈</div>
17
- <div class="behavior">I disappear on resize</div>
18
- <footer style="font-size: 75%">neunundneunzig pixel-ballon</footer>
19
- </xin-float>
20
-
21
- <xin-float class="float" remain-on-resize="remain" remain-on-scroll="remove" style="bottom: 20px; left: 50px;" drag>
22
- <h4>Drag Me</h4>
23
- <div class="no-drag balloon">🎈</div>
24
- <div class="behavior">I disappear on scroll</div>
25
- <footer style="font-size: 75%">neunundneunzig pixel-ballon</footer>
26
- </xin-float>
27
- ```
28
- ```css
29
- .preview .float {
30
- width: 220px;
31
- height: 180px;
32
- padding: 0;
33
- gap: 5px;
34
- display: flex;
35
- flex-direction: column;
36
- border-radius: 5px;
37
- background: #fff8;
38
- box-shadow: 2px 10px 20px #0004;
39
- overflow: hidden;
40
- cursor: move;
41
- }
42
-
43
- .preview h4 {
44
- margin: 0;
45
- padding: 5px 10px;
46
- color: white;
47
- background: red;
48
- }
49
-
50
- .preview .balloon {
51
- cursor: default;
52
- flex: 1 1 auto;
53
- font-size: 99px;
54
- line-height: 120px;
55
- text-align: center;
56
- height: auto;
57
- overflow: hidden;
58
- }
59
-
60
- .preview .behavior {
61
- position: absolute;
62
- bottom: 16px;
63
- left: 8px;
64
- right: 8px;
65
- background: #fffc;
66
- }
67
-
68
- .preview footer {
69
- text-align: center;
70
- background: #f008;
71
- color: white;
72
- ```
73
-
74
- ## Styling
75
-
76
- Note that the `<xin-float>` element has absolutely minimal styling. It's up to you to provide a drop
77
- shadow and background and so on.
78
-
79
- ## Attributes
80
-
81
- - `drag` false | true — to make a `<xin-float>` element draggable, simply set its `drag` attribute.
82
- - `remain-on-resize` 'remove' | 'hide' | 'remain' — by default, floats will hide if the window is resized
83
- - `remain-on-scroll` 'remain' | 'remove' | 'hide' — by default, floats will remain if the document is scrolled
84
-
85
- Note that `remain-on-scroll` behavior applies to any scrolling in the document (including within the float) so
86
- if you want finer-grained disappearing behavior triggered by scrolling, you might want to implement it yourself.
87
-
88
- To prevent dragging for an interior element (e.g. if you want a floating palette with buttons or input fields)
89
- just add the `no-drag` class to an element or its container.
90
- */
91
- import { Component as WebComponent, elements } from 'xinjs';
92
- import { trackDrag, bringToFront } from './track-drag';
93
- const { slot } = elements;
94
- export class XinFloat extends WebComponent {
95
- static floats = new Set();
96
- drag = false;
97
- remainOnResize = 'remove';
98
- remainOnScroll = 'remain';
99
- content = slot();
100
- static styleSpec = {
101
- ':host': {
102
- position: 'fixed',
103
- },
104
- };
105
- constructor() {
106
- super();
107
- this.initAttributes('drag', 'remainOnResize', 'remainOnScroll');
108
- }
109
- reposition = (event) => {
110
- const target = event.target;
111
- if (target?.closest('.no-drag')) {
112
- return;
113
- }
114
- if (this.drag) {
115
- bringToFront(this);
116
- const x = this.offsetLeft;
117
- const y = this.offsetTop;
118
- trackDrag(event, (dx, dy, pointerEvent) => {
119
- this.style.left = `${x + dx}px`;
120
- this.style.top = `${y + dy}px`;
121
- this.style.right = 'auto';
122
- this.style.bottom = 'auto';
123
- if (pointerEvent.type === 'mouseup') {
124
- return true;
125
- }
126
- });
127
- }
128
- };
129
- connectedCallback() {
130
- super.connectedCallback();
131
- XinFloat.floats.add(this);
132
- const PASSIVE = { passive: true };
133
- this.addEventListener('touchstart', this.reposition, PASSIVE);
134
- this.addEventListener('mousedown', this.reposition, PASSIVE);
135
- bringToFront(this);
136
- }
137
- disconnectedCallback() {
138
- super.disconnectedCallback();
139
- XinFloat.floats.delete(this);
140
- }
141
- }
142
- export const xinFloat = XinFloat.elementCreator({
143
- tag: 'xin-float',
144
- });
145
- window.addEventListener('resize', () => {
146
- ;
147
- [...XinFloat.floats].forEach((float) => {
148
- if (float.remainOnResize === 'hide') {
149
- float.hidden = true;
150
- }
151
- else if (float.remainOnResize === 'remove') {
152
- float.remove();
153
- }
154
- });
155
- }, { passive: true });
156
- document.addEventListener('scroll', (event) => {
157
- if (event.target instanceof HTMLElement &&
158
- event.target.closest(XinFloat.tagName)) {
159
- return;
160
- }
161
- ;
162
- [...XinFloat.floats].forEach((float) => {
163
- if (float.remainOnScroll === 'hide') {
164
- float.hidden = true;
165
- }
166
- else if (float.remainOnScroll === 'remove') {
167
- float.remove();
168
- }
169
- });
170
- }, { passive: true, capture: true });