tosijs-ui 1.0.1 → 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 (93) 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.js +15 -37
  5. package/dist/index.js.map +39 -39
  6. package/dist/version.d.ts +1 -1
  7. package/package.json +2 -2
  8. package/dist/ab-test.js +0 -116
  9. package/dist/babylon-3d.js +0 -292
  10. package/dist/bodymovin-player.js +0 -172
  11. package/dist/bp-loader.js +0 -26
  12. package/dist/carousel.js +0 -308
  13. package/dist/code-editor.js +0 -102
  14. package/dist/color-input.js +0 -112
  15. package/dist/data-table.js +0 -774
  16. package/dist/drag-and-drop.js +0 -386
  17. package/dist/editable-rect.js +0 -450
  18. package/dist/filter-builder.js +0 -468
  19. package/dist/float.js +0 -170
  20. package/dist/form.js +0 -466
  21. package/dist/gamepad.js +0 -115
  22. package/dist/icon-data.js +0 -308
  23. package/dist/icon-types.js +0 -1
  24. package/dist/icons.js +0 -374
  25. package/dist/index-iife.js +0 -4
  26. package/dist/live-example.js +0 -611
  27. package/dist/localize.js +0 -381
  28. package/dist/make-sorter.js +0 -119
  29. package/dist/make-sorter.test.d.ts +0 -1
  30. package/dist/make-sorter.test.js +0 -48
  31. package/dist/mapbox.js +0 -161
  32. package/dist/markdown-viewer.js +0 -173
  33. package/dist/match-shortcut.js +0 -13
  34. package/dist/match-shortcut.test.d.ts +0 -1
  35. package/dist/match-shortcut.test.js +0 -194
  36. package/dist/menu.js +0 -614
  37. package/dist/notifications.js +0 -308
  38. package/dist/password-strength.js +0 -302
  39. package/dist/playwright.config.d.ts +0 -9
  40. package/dist/playwright.config.js +0 -73
  41. package/dist/pop-float.js +0 -231
  42. package/dist/rating.js +0 -192
  43. package/dist/rich-text.js +0 -296
  44. package/dist/segmented.js +0 -298
  45. package/dist/select.js +0 -427
  46. package/dist/side-nav.js +0 -106
  47. package/dist/size-break.js +0 -118
  48. package/dist/sizer.js +0 -92
  49. package/dist/src/ab-test.d.ts +0 -14
  50. package/dist/src/babylon-3d.d.ts +0 -53
  51. package/dist/src/bodymovin-player.d.ts +0 -32
  52. package/dist/src/bp-loader.d.ts +0 -0
  53. package/dist/src/carousel.d.ts +0 -113
  54. package/dist/src/code-editor.d.ts +0 -27
  55. package/dist/src/color-input.d.ts +0 -41
  56. package/dist/src/data-table.d.ts +0 -79
  57. package/dist/src/drag-and-drop.d.ts +0 -2
  58. package/dist/src/editable-rect.d.ts +0 -97
  59. package/dist/src/filter-builder.d.ts +0 -64
  60. package/dist/src/float.d.ts +0 -18
  61. package/dist/src/form.d.ts +0 -68
  62. package/dist/src/gamepad.d.ts +0 -34
  63. package/dist/src/icon-data.d.ts +0 -309
  64. package/dist/src/icon-types.d.ts +0 -7
  65. package/dist/src/icons.d.ts +0 -17
  66. package/dist/src/index.d.ts +0 -37
  67. package/dist/src/live-example.d.ts +0 -51
  68. package/dist/src/localize.d.ts +0 -30
  69. package/dist/src/make-sorter.d.ts +0 -3
  70. package/dist/src/mapbox.d.ts +0 -24
  71. package/dist/src/markdown-viewer.d.ts +0 -15
  72. package/dist/src/match-shortcut.d.ts +0 -9
  73. package/dist/src/menu.d.ts +0 -60
  74. package/dist/src/notifications.d.ts +0 -106
  75. package/dist/src/password-strength.d.ts +0 -35
  76. package/dist/src/pop-float.d.ts +0 -10
  77. package/dist/src/rating.d.ts +0 -62
  78. package/dist/src/rich-text.d.ts +0 -28
  79. package/dist/src/segmented.d.ts +0 -80
  80. package/dist/src/select.d.ts +0 -43
  81. package/dist/src/side-nav.d.ts +0 -36
  82. package/dist/src/size-break.d.ts +0 -18
  83. package/dist/src/sizer.d.ts +0 -34
  84. package/dist/src/tab-selector.d.ts +0 -91
  85. package/dist/src/tag-list.d.ts +0 -37
  86. package/dist/src/track-drag.d.ts +0 -5
  87. package/dist/src/version.d.ts +0 -1
  88. package/dist/src/via-tag.d.ts +0 -2
  89. package/dist/tab-selector.js +0 -326
  90. package/dist/tag-list.js +0 -375
  91. package/dist/track-drag.js +0 -143
  92. package/dist/version.js +0 -1
  93. 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
- });