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,326 +0,0 @@
1
- /*#
2
- # tabs
3
-
4
- `<xin-tabs>` creates a `tabpanel` for its children, creating a `tab` for each based on its
5
- `name` attribute.
6
-
7
- ```js
8
- [...preview.querySelectorAll('div[name]')].forEach(div => {
9
- div.style.color = `hsl(${(Math.random() * 360).toFixed(0)} 50% 50%)`
10
- })
11
-
12
- const { div, button } = xinjs.elements
13
- const tabSelector = preview.querySelector('xin-tabs')
14
-
15
- tabSelector.onCloseTab = body => {
16
- if (!confirm(`Are you sure you want to close the ${body.getAttribute('name')} tab?`)) {
17
- return false
18
- }
19
- }
20
-
21
- let bodycount = 0
22
- preview.querySelector('.add').addEventListener('click', () => {
23
- const name = `new tab ${++bodycount}`
24
- const body = div(
25
- {name, dataClose: true},
26
- name,
27
- )
28
- tabSelector.addTabBody(body, true)
29
- })
30
- ```
31
- ```html
32
- <xin-tabs>
33
- <div name="first">first body</div>
34
- <div name="second" data-close>
35
- <template role="tab">
36
- <xin-icon
37
- style="
38
- display: inline-block;
39
- width: 16px;
40
- height: 16px;
41
- transform: translateY(2px);
42
- margin-right: 4px;
43
- stroke: var(--brand-color);
44
- "
45
- icon="eye"
46
- ></xin-icon>
47
- <span>Ooooh!!!</span>
48
- </template>
49
- look at the html…
50
- </div>
51
- <div name="third">third body</div>
52
- <button class="add" slot="after-tabs">
53
- <xin-icon icon="plus"></xin-icon>
54
- </button>
55
- </xin-tabs>
56
- ```
57
- ```css
58
- .preview xin-tabs {
59
- height: 100%;
60
- }
61
-
62
- .preview div[name] {
63
- padding: 20px;
64
- text-align: center;
65
- height: 100%;
66
- font-size: 200%;
67
- }
68
-
69
- .preview .add {
70
- width: 38px;
71
- line-height: 38px;
72
- height: 38px;
73
- padding: 0;
74
- }
75
- ```
76
-
77
- The `<xin-tabs>`s `value` is the index of its active body.
78
-
79
- A `<xin-tabs>` has `addTabBody(body: HTMLElement, select?: boolean)` and
80
- `removeTabBody(body: number | HTMLElement)` methods for updating its content.
81
-
82
- You can also just insert or remove tab bodies directly and call `setupTabs()`.
83
-
84
- ## Closeable Tabs
85
-
86
- Adding the `data-close` attribute to a tab will make it closeable.
87
-
88
- When a tab is closed, the `<xin-tabs>` element's `onCloseTab: (tabBody: Element) => boolean | undefined | void`
89
- will be called. If you override this method and return `false`, the tab will
90
- not be closed (e.g. if you want to implement save/cancel behavior).
91
-
92
- ## Custom Tab Content
93
-
94
- You can specify the exact content of the tab for a given body by
95
- adding a `<template role="tab">` to that body. The contents of that
96
- template will be cloned into the tab.
97
-
98
- ## Localized Support
99
-
100
- ```html
101
- <xin-tabs localized>
102
- <div name="localize"><h2>localize!</h2></div>
103
- <div name="tabs"><h2>tabs</h2></div>
104
- </xin-tabs>
105
- ```
106
-
107
- `<xin-tabs>` supports the `localized` attribute. It will automatically localize
108
- tab names (but it won't override custom tab content, so localizing that is on you).
109
- */
110
- import { Component as WebComponent, elements, vars, } from 'xinjs';
111
- import { xinLocalized, XinLocalized } from './localize';
112
- import { icons } from '../src';
113
- const { div, slot, span, button } = elements;
114
- export class TabSelector extends WebComponent {
115
- value = 0;
116
- localized = false;
117
- makeTab(tabs, tabBody, bodyId) {
118
- const tabName = tabBody.getAttribute('name');
119
- const tabContent = tabBody.querySelector('template[role="tab"]')?.content.cloneNode(true) ||
120
- (this.localized ? xinLocalized(tabName) : span(tabName));
121
- const tab = div(tabContent, {
122
- part: 'tab',
123
- tabindex: 0,
124
- role: 'tab',
125
- ariaControls: bodyId,
126
- }, tabBody.hasAttribute('data-close')
127
- ? button({
128
- title: 'close',
129
- class: 'close',
130
- }, icons.x())
131
- : {});
132
- return tab;
133
- }
134
- static styleSpec = {
135
- ':host': {
136
- display: 'flex',
137
- flexDirection: 'column',
138
- position: 'relative',
139
- overflow: 'hidden',
140
- boxShadow: 'none !important',
141
- },
142
- slot: {
143
- position: 'relative',
144
- display: 'block',
145
- flex: '1',
146
- overflow: 'hidden',
147
- overflowY: 'auto',
148
- },
149
- 'slot[name="after-tabs"]': {
150
- flex: '0 0 auto',
151
- },
152
- '::slotted([hidden])': {
153
- display: 'none !important',
154
- },
155
- ':host::part(tabpanel)': {
156
- display: 'flex',
157
- flexDirection: 'column',
158
- overflowX: 'auto',
159
- },
160
- ':host::part(tabrow)': {
161
- display: 'flex',
162
- },
163
- ':host .tabs': {
164
- display: 'flex',
165
- userSelect: 'none',
166
- whiteSpace: 'nowrap',
167
- },
168
- ':host .tabs > div': {
169
- padding: `${vars.spacing50} ${vars.spacing}`,
170
- cursor: 'default',
171
- display: 'flex',
172
- alignItems: 'baseline',
173
- },
174
- ':host .tabs > [aria-selected="true"]': {
175
- '--text-color': vars.xinTabsSelectedColor,
176
- color: vars.textColor,
177
- },
178
- ':host .elastic': {
179
- flex: '1',
180
- },
181
- ':host .border': {
182
- background: 'var(--xin-tabs-bar-color, #ccc)',
183
- },
184
- ':host .border > .selected': {
185
- content: ' ',
186
- width: 0,
187
- height: 'var(--xin-tabs-bar-height, 2px)',
188
- background: vars.xinTabsSelectedColor,
189
- transition: 'ease-out 0.2s',
190
- },
191
- ':host button.close': {
192
- border: 0,
193
- background: 'transparent',
194
- textAlign: 'center',
195
- marginLeft: vars.spacing50,
196
- padding: 0,
197
- },
198
- ':host button.close > svg': {
199
- height: '12px',
200
- },
201
- };
202
- onCloseTab = null;
203
- content = [
204
- div({ role: 'tabpanel', part: 'tabpanel' }, div({ part: 'tabrow' }, div({ class: 'tabs', part: 'tabs' }), div({ class: 'elastic' }), slot({ name: 'after-tabs' })), div({ class: 'border' }, div({ class: 'selected', part: 'selected' }))),
205
- slot(),
206
- ];
207
- constructor() {
208
- super();
209
- this.initAttributes('localized');
210
- }
211
- addTabBody(body, selectTab = false) {
212
- if (!body.hasAttribute('name')) {
213
- console.error('element has no name attribute', body);
214
- throw new Error('element has no name attribute');
215
- }
216
- this.append(body);
217
- this.setupTabs();
218
- if (selectTab) {
219
- this.value = this.bodies.length - 1;
220
- }
221
- this.queueRender();
222
- }
223
- removeTabBody(body) {
224
- body.remove();
225
- this.setupTabs();
226
- this.queueRender();
227
- }
228
- keyTab = (event) => {
229
- const { tabs } = this.parts;
230
- const tabIndex = [...tabs.children].indexOf(event.target);
231
- switch (event.key) {
232
- case 'ArrowLeft':
233
- this.value =
234
- (tabIndex + Number(tabs.children.length) - 1) % tabs.children.length;
235
- tabs.children[this.value].focus();
236
- event.preventDefault();
237
- break;
238
- case 'ArrowRight':
239
- this.value = (tabIndex + 1) % tabs.children.length;
240
- tabs.children[this.value].focus();
241
- event.preventDefault();
242
- break;
243
- case ' ':
244
- this.pickTab(event);
245
- event.preventDefault();
246
- break;
247
- default:
248
- // console.log(event.key)
249
- }
250
- };
251
- get bodies() {
252
- return [...this.children].filter((elt) => elt.hasAttribute('name'));
253
- }
254
- pickTab = (event) => {
255
- const { tabs } = this.parts;
256
- const target = event.target;
257
- const isCloseEvent = target.closest('button.close') !== null;
258
- const tab = target.closest('.tabs > div');
259
- const tabIndex = [...tabs.children].indexOf(tab);
260
- if (isCloseEvent) {
261
- const body = this.bodies[tabIndex];
262
- if (!this.onCloseTab || this.onCloseTab(body) !== false) {
263
- this.removeTabBody(this.bodies[tabIndex]);
264
- }
265
- }
266
- else {
267
- if (tabIndex > -1) {
268
- this.value = tabIndex;
269
- }
270
- }
271
- };
272
- setupTabs = () => {
273
- const { tabs } = this.parts;
274
- const tabBodies = [...this.children].filter((child) => !child.hasAttribute('slot') && child.hasAttribute('name'));
275
- tabs.textContent = '';
276
- if (this.value >= tabBodies.length) {
277
- this.value = tabBodies.length - 1;
278
- }
279
- for (const index in tabBodies) {
280
- const tabBody = tabBodies[index];
281
- const bodyId = `${this.instanceId}-${index}`;
282
- tabBody.id = bodyId;
283
- const tab = this.makeTab(this, tabBody, bodyId);
284
- tabs.append(tab);
285
- }
286
- };
287
- connectedCallback() {
288
- super.connectedCallback();
289
- const { tabs } = this.parts;
290
- tabs.addEventListener('click', this.pickTab);
291
- tabs.addEventListener('keydown', this.keyTab);
292
- this.setupTabs();
293
- XinLocalized.allInstances.add(this);
294
- }
295
- disconnectedCallback() {
296
- super.disconnectedCallback();
297
- XinLocalized.allInstances.delete(this);
298
- }
299
- localeChanged = () => {
300
- this.queueRender();
301
- };
302
- onResize() {
303
- this.queueRender();
304
- }
305
- render() {
306
- const { tabs, selected } = this.parts;
307
- const tabBodies = this.bodies;
308
- for (let i = 0; i < tabBodies.length; i++) {
309
- const tabBody = tabBodies[i];
310
- const tab = tabs.children[i];
311
- if (this.value === Number(i)) {
312
- tab.setAttribute('aria-selected', 'true');
313
- selected.style.marginLeft = `${tab.offsetLeft - tabs.offsetLeft}px`;
314
- selected.style.width = `${tab.offsetWidth}px`;
315
- tabBody.toggleAttribute('hidden', false);
316
- }
317
- else {
318
- tab.toggleAttribute('aria-selected', false);
319
- tabBody.toggleAttribute('hidden', true);
320
- }
321
- }
322
- }
323
- }
324
- export const tabSelector = TabSelector.elementCreator({
325
- tag: 'xin-tabs',
326
- });
package/dist/tag-list.js DELETED
@@ -1,375 +0,0 @@
1
- /*#
2
- # tag-list
3
-
4
- Building a tag-list from standard HTML elements is a bit of a nightmare.
5
-
6
- `<xin-tag-list>` allows you to display an editable or read-only tag list (represented either
7
- as a comma-delimited string or an array of strings).
8
-
9
- ```html
10
- <label style="position: absolute; right: 10px; top: 10px; display: block">
11
- <input type="checkbox" class="disable-toggle">
12
- <b>Disable All</b>
13
- </label>
14
- <label>
15
- <b>Display Only</b>
16
- <xin-tag-list
17
- value="this,that,,the-other"
18
- ></xin-tag-list>
19
- </label>
20
- <xin-tag-list
21
- class="compact"
22
- value="this,that,,the-other"
23
- ></xin-tag-list>
24
- <br>
25
- <label>
26
- <b>Editable</b>
27
- <xin-tag-list
28
- class="editable-tag-list"
29
- value="belongs,also belongs,custom"
30
- editable
31
- available-tags="belongs,also belongs,not initially chosen"
32
- ></xin-tag-list>
33
- </label>
34
- <br>
35
- <b>Text-Entry</b>
36
- <xin-tag-list
37
- value="this,that,the-other,not,enough,space"
38
- editable
39
- text-entry
40
- available-tags="tomasina,dick,,harriet"
41
- ></xin-tag-list>
42
- ```
43
- ```css
44
- .preview .compact {
45
- --spacing: 8px;
46
- --font-size: 12px;
47
- --line-height: 18px;
48
- }
49
- .preview label {
50
- display: flex;
51
- flex-direction: column;
52
- align-items: flex-start;
53
- }
54
- ```
55
- ```js
56
- preview.addEventListener('change', (event) => {
57
- if (event.target.matches('xin-tag-list')) {
58
- console.log(event.target, event.target.value)
59
- }
60
- }, true)
61
- preview.querySelector('.disable-toggle').addEventListener('change', (event) => {
62
- const tagLists = Array.from(preview.querySelectorAll('xin-tag-list'))
63
- for(const tagList of tagLists) {
64
- tagList.disabled = event.target.checked
65
- }
66
- })
67
- ```
68
-
69
- ## Properties
70
-
71
- ### `value`: string | string[]
72
-
73
- A list of tags
74
-
75
- ### `tags`: string[]
76
-
77
- ## `popSelectMenu`: () => void
78
-
79
- This is the method called when the user clicks the menu button. By default is displays a
80
- pick list of tags, but if you wish to customize the behavior, just replace this method.
81
-
82
- A read-only property giving the value as an array.
83
-
84
- ### `available-tags`: string | string[]
85
-
86
- A list of tags that will be displayed in the popup menu by default. The popup menu
87
- will always display custom tags (allowing their removal).
88
-
89
- ### `editable`: boolean
90
-
91
- Allows the tag list to be modified via menu and removing tags.
92
-
93
- ### `text-entry`: boolean
94
-
95
- If `editable`, an input field is provided for entering tags directly.
96
-
97
- ### `placeholder`: string = 'enter tags'
98
-
99
- Placeholder shown on input field.
100
- */
101
- import { Component as WebComponent, elements, vars, varDefault, } from 'xinjs';
102
- import { popMenu } from './menu';
103
- import { icons } from './icons';
104
- const { div, input, span, button } = elements;
105
- export class XinTag extends WebComponent {
106
- caption = '';
107
- removeable = false;
108
- removeCallback = () => {
109
- this.remove();
110
- };
111
- content = () => [
112
- span({ part: 'caption' }, this.caption),
113
- button(icons.x(), {
114
- part: 'remove',
115
- hidden: !this.removeable,
116
- onClick: this.removeCallback,
117
- }),
118
- ];
119
- constructor() {
120
- super();
121
- this.initAttributes('caption', 'removeable');
122
- }
123
- }
124
- export const xinTag = XinTag.elementCreator({
125
- tag: 'xin-tag',
126
- styleSpec: {
127
- ':host': {
128
- '--tag-close-button-color': '#000c',
129
- '--tag-close-button-bg': '#fffc',
130
- '--tag-button-opacity': '0.5',
131
- '--tag-button-hover-opacity': '0.75',
132
- '--tag-bg': varDefault.brandColor('blue'),
133
- '--tag-text-color': varDefault.brandTextColor('white'),
134
- display: 'inline-flex',
135
- borderRadius: varDefault.tagRoundedRadius(vars.spacing50),
136
- color: vars.tagTextColor,
137
- background: vars.tagBg,
138
- padding: `0 ${vars.spacing75} 0 ${vars.spacing75}`,
139
- height: `calc(${vars.lineHeight} + ${vars.spacing50})`,
140
- lineHeight: `calc(${vars.lineHeight} + ${vars.spacing50})`,
141
- },
142
- ':host > [part="caption"]': {
143
- position: 'relative',
144
- whiteSpace: 'nowrap',
145
- overflow: 'hidden',
146
- flex: '1 1 auto',
147
- fontSize: varDefault.fontSize('16px'),
148
- color: vars.tagTextColor,
149
- textOverflow: 'ellipsis',
150
- },
151
- ':host [part="remove"]': {
152
- boxShadow: 'none',
153
- margin: `0 ${vars.spacing_50} 0 ${vars.spacing25}`,
154
- padding: 0,
155
- display: 'inline-flex',
156
- alignItems: 'center',
157
- alignSelf: 'center',
158
- justifyContent: 'center',
159
- height: vars.spacing150,
160
- width: vars.spacing150,
161
- '--text-color': vars.tagCloseButtonColor,
162
- background: vars.tagCloseButtonBg,
163
- borderRadius: varDefault.tagCloseButtonRadius('99px'),
164
- opacity: vars.tagButtonOpacity,
165
- },
166
- ':host [part="remove"]:hover': {
167
- background: vars.tagCloseButtonBg,
168
- opacity: vars.tagButtonHoverOpacity,
169
- },
170
- },
171
- });
172
- export class XinTagList extends WebComponent {
173
- disabled = false;
174
- name = '';
175
- availableTags = [];
176
- value = [];
177
- textEntry = false;
178
- editable = false;
179
- placeholder = 'enter tags';
180
- get tags() {
181
- return typeof this.value === 'string'
182
- ? this.value
183
- .split(',')
184
- .map((tag) => tag.trim())
185
- .filter((tag) => tag !== '')
186
- : this.value;
187
- }
188
- constructor() {
189
- super();
190
- this.initAttributes('name', 'value', 'textEntry', 'availableTags', 'editable', 'placeholder', 'disabled');
191
- }
192
- addTag = (tag) => {
193
- if (tag.trim() === '') {
194
- return;
195
- }
196
- const { tags } = this;
197
- if (!tags.includes(tag)) {
198
- tags.push(tag);
199
- }
200
- this.value = tags;
201
- this.queueRender(true);
202
- };
203
- toggleTag = (toggled) => {
204
- if (this.tags.includes(toggled)) {
205
- this.value = this.tags.filter((tag) => tag !== toggled);
206
- }
207
- else {
208
- this.addTag(toggled);
209
- }
210
- this.queueRender(true);
211
- };
212
- enterTag = (event) => {
213
- const { tagInput } = this.parts;
214
- switch (event.key) {
215
- case ',':
216
- {
217
- const tag = tagInput.value.split(',')[0];
218
- this.addTag(tag);
219
- }
220
- break;
221
- case 'Enter':
222
- {
223
- const tag = tagInput.value.split(',')[0];
224
- this.addTag(tag);
225
- }
226
- event.stopPropagation();
227
- event.preventDefault();
228
- break;
229
- default:
230
- // do nothing
231
- }
232
- };
233
- popSelectMenu = () => {
234
- const { toggleTag } = this;
235
- const { tagMenu } = this.parts;
236
- const tags = typeof this.availableTags === 'string'
237
- ? this.availableTags.split(',')
238
- : this.availableTags;
239
- const extraTags = this.tags.filter((tag) => !tags.includes(tag));
240
- if (extraTags.length) {
241
- tags.push(null, ...extraTags);
242
- }
243
- const menuItems = tags.map((tag) => {
244
- if (tag === '' || tag === null) {
245
- return null;
246
- }
247
- else if (typeof tag === 'object') {
248
- return {
249
- checked: () => this.tags.includes(tag.value),
250
- caption: tag.caption,
251
- action() {
252
- toggleTag(tag.value);
253
- },
254
- };
255
- }
256
- else {
257
- return {
258
- checked: () => this.tags.includes(tag),
259
- caption: tag,
260
- action() {
261
- toggleTag(tag);
262
- },
263
- };
264
- }
265
- });
266
- popMenu({
267
- target: tagMenu,
268
- width: 'auto',
269
- menuItems,
270
- });
271
- };
272
- content = () => [
273
- // this button is simply here to eat click events sent via a label
274
- button({ style: { visibility: 'hidden' }, tabindex: -1 }),
275
- div({
276
- part: 'tagContainer',
277
- class: 'row',
278
- }),
279
- input({
280
- part: 'tagInput',
281
- class: 'elastic',
282
- onKeydown: this.enterTag,
283
- }),
284
- button({
285
- title: 'add tag',
286
- part: 'tagMenu',
287
- onClick: this.popSelectMenu,
288
- }, icons.chevronDown()),
289
- ];
290
- removeTag = (event) => {
291
- if (this.editable && !this.disabled) {
292
- const tag = event.target.closest(XinTag.tagName);
293
- this.value = this.tags.filter((value) => value !== tag.caption);
294
- tag.remove();
295
- this.queueRender(true);
296
- }
297
- event.stopPropagation();
298
- event.preventDefault();
299
- };
300
- render() {
301
- super.render();
302
- const { tagContainer, tagMenu, tagInput } = this.parts;
303
- tagMenu.disabled = this.disabled;
304
- tagInput.value = '';
305
- tagInput.setAttribute('placeholder', this.placeholder);
306
- if (this.editable && !this.disabled) {
307
- tagMenu.toggleAttribute('hidden', false);
308
- tagInput.toggleAttribute('hidden', !this.textEntry);
309
- }
310
- else {
311
- tagMenu.toggleAttribute('hidden', true);
312
- tagInput.toggleAttribute('hidden', true);
313
- }
314
- tagContainer.textContent = '';
315
- const { tags } = this;
316
- for (const tag of tags) {
317
- tagContainer.append(xinTag({
318
- caption: tag,
319
- removeable: this.editable && !this.disabled,
320
- removeCallback: this.removeTag,
321
- }));
322
- }
323
- }
324
- }
325
- export const xinTagList = XinTagList.elementCreator({
326
- tag: 'xin-tag-list',
327
- styleSpec: {
328
- ':host': {
329
- '--tag-list-bg': '#f8f8f8',
330
- '--touch-size': '44px',
331
- '--spacing': '16px',
332
- display: 'grid',
333
- gridTemplateColumns: 'auto',
334
- alignItems: 'center',
335
- background: vars.tagListBg,
336
- gap: vars.spacing25,
337
- borderRadius: varDefault.taglistRoundedRadius(vars.spacing50),
338
- overflow: 'hidden',
339
- },
340
- ':host[editable]': {
341
- gridTemplateColumns: `0px auto ${vars.touchSize}`,
342
- },
343
- ':host[editable][text-entry]': {
344
- gridTemplateColumns: `0px 2fr 1fr ${vars.touchSize}`,
345
- },
346
- ':host [part="tagContainer"]': {
347
- display: 'flex',
348
- content: '" "',
349
- alignItems: 'center',
350
- background: vars.inputBg,
351
- borderRadius: varDefault.tagContainerRadius(vars.spacing50),
352
- boxShadow: vars.borderShadow,
353
- flexWrap: 'nowrap',
354
- overflow: 'auto hidden',
355
- gap: vars.spacing25,
356
- minHeight: `calc(${vars.lineHeight} + ${vars.spacing})`,
357
- padding: vars.spacing25,
358
- },
359
- ':host [part="tagMenu"]': {
360
- width: vars.touchSize,
361
- height: vars.touchSize,
362
- lineHeight: vars.touchSize,
363
- textAlign: 'center',
364
- padding: 0,
365
- margin: 0,
366
- },
367
- ':host [hidden]': {
368
- display: 'none !important',
369
- },
370
- ':host button[part="tagMenu"]': {
371
- background: vars.brandColor,
372
- color: vars.brandTextColor,
373
- },
374
- },
375
- });