@aquera/nile-elements 2.0.8 → 2.0.9
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.
- package/README.md +4 -0
- package/dist/index.js +619 -252
- package/dist/nile-select/index.cjs.js +1 -1
- package/dist/nile-select/index.esm.js +1 -1
- package/dist/nile-select/nile-select.cjs.js +2 -1
- package/dist/nile-select/nile-select.cjs.js.map +1 -1
- package/dist/nile-select/nile-select.css.cjs.js +1 -1
- package/dist/nile-select/nile-select.css.cjs.js.map +1 -1
- package/dist/nile-select/nile-select.css.esm.js +126 -6
- package/dist/nile-select/nile-select.esm.js +77 -11
- package/dist/nile-select/virtual-scroll-helper.cjs.js +1 -1
- package/dist/nile-select/virtual-scroll-helper.cjs.js.map +1 -1
- package/dist/nile-select/virtual-scroll-helper.esm.js +3 -1
- package/dist/nile-virtual-select/index.cjs.js +1 -1
- package/dist/nile-virtual-select/index.esm.js +1 -1
- package/dist/nile-virtual-select/nile-virtual-select.cjs.js +4 -3
- package/dist/nile-virtual-select/nile-virtual-select.cjs.js.map +1 -1
- package/dist/nile-virtual-select/nile-virtual-select.css.cjs.js +1 -1
- package/dist/nile-virtual-select/nile-virtual-select.css.cjs.js.map +1 -1
- package/dist/nile-virtual-select/nile-virtual-select.css.esm.js +126 -6
- package/dist/nile-virtual-select/nile-virtual-select.esm.js +71 -12
- package/dist/src/nile-select/nile-select.css.js +126 -6
- package/dist/src/nile-select/nile-select.css.js.map +1 -1
- package/dist/src/nile-select/nile-select.d.ts +43 -5
- package/dist/src/nile-select/nile-select.js +445 -106
- package/dist/src/nile-select/nile-select.js.map +1 -1
- package/dist/src/nile-select/nile-select.test.d.ts +1 -0
- package/dist/src/nile-select/nile-select.test.js +342 -1
- package/dist/src/nile-select/nile-select.test.js.map +1 -1
- package/dist/src/nile-select/virtual-scroll-helper.js +3 -1
- package/dist/src/nile-select/virtual-scroll-helper.js.map +1 -1
- package/dist/src/nile-virtual-select/nile-virtual-select.css.js +126 -6
- package/dist/src/nile-virtual-select/nile-virtual-select.css.js.map +1 -1
- package/dist/src/nile-virtual-select/nile-virtual-select.d.ts +45 -4
- package/dist/src/nile-virtual-select/nile-virtual-select.js +385 -59
- package/dist/src/nile-virtual-select/nile-virtual-select.js.map +1 -1
- package/dist/src/nile-virtual-select/nile-virtual-select.test.js +253 -1
- package/dist/src/nile-virtual-select/nile-virtual-select.test.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/nile-select/nile-select.css.ts +126 -6
- package/src/nile-select/nile-select.test.ts +478 -1
- package/src/nile-select/nile-select.ts +499 -91
- package/src/nile-select/virtual-scroll-helper.ts +3 -1
- package/src/nile-virtual-select/nile-virtual-select.css.ts +126 -6
- package/src/nile-virtual-select/nile-virtual-select.test.ts +352 -1
- package/src/nile-virtual-select/nile-virtual-select.ts +460 -55
- package/vscode-html-custom-data.json +40 -6
|
@@ -20,6 +20,9 @@ export class VirtualScrollHelper {
|
|
|
20
20
|
.name=${component.name}
|
|
21
21
|
.value=${component.value}
|
|
22
22
|
.autoResize=${component.autoResize}
|
|
23
|
+
.showTooltip=${component.showTooltip}
|
|
24
|
+
.chipMinWidth=${component.chipMinWidth}
|
|
25
|
+
.chipMaxWidth=${component.chipMaxWidth}
|
|
23
26
|
.placeholder=${component.placeholder}
|
|
24
27
|
.size=${component.size}
|
|
25
28
|
.searchEnabled=${component.searchEnabled}
|
|
@@ -47,7 +50,6 @@ export class VirtualScrollHelper {
|
|
|
47
50
|
.renderItemConfig=${component.renderItemConfig}
|
|
48
51
|
.blockValueChange=${component.blockValueChange}
|
|
49
52
|
.noWidthSync=${component.noWidthSync}
|
|
50
|
-
.maxOptionsVisible=${component.maxOptionsVisible}
|
|
51
53
|
.enableTabClose=${component.enableTabClose}
|
|
52
54
|
.data=${component.data}
|
|
53
55
|
.open=${component.open}
|
|
@@ -206,7 +206,7 @@ export const styles = css`
|
|
|
206
206
|
display: flex;
|
|
207
207
|
flex: 1;
|
|
208
208
|
align-items: center;
|
|
209
|
-
flex-wrap:
|
|
209
|
+
flex-wrap: nowrap;
|
|
210
210
|
margin-inline-start: var(--nile-spacing-7px, var(--ng-spacing-md));
|
|
211
211
|
width: 100%;
|
|
212
212
|
overflow: hidden;
|
|
@@ -227,6 +227,98 @@ export const styles = css`
|
|
|
227
227
|
margin-right: var(--nile-spacing-5xl, var(--ng-spacing-5xl));
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
button.select__tags-count {
|
|
231
|
+
appearance: none;
|
|
232
|
+
-webkit-appearance: none;
|
|
233
|
+
background: none;
|
|
234
|
+
text-align: inherit;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
button.select__tags-count:disabled {
|
|
238
|
+
cursor: not-allowed;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.select__tags--fitted {
|
|
242
|
+
min-width: 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.select__tags nile-lite-tooltip.select__tag-tip {
|
|
246
|
+
display: contents;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.select__tags nile-tag {
|
|
250
|
+
flex: 0 1 auto;
|
|
251
|
+
cursor: pointer;
|
|
252
|
+
min-width: 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* A chip is capped - and so truncated - only when a tooltip can reveal the
|
|
256
|
+
full value. Without one it keeps its natural width and the fit pass moves
|
|
257
|
+
the surplus into the +N button instead. */
|
|
258
|
+
:host([showtooltip]) .select__tags nile-tag {
|
|
259
|
+
max-width: var(--nile-width-180px, var(--ng-height-180px));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Only the fitted layout can move a chip into the +N button, so only there
|
|
263
|
+
can a chip refuse to shrink. */
|
|
264
|
+
:host(:not([showtooltip])) .select__tags--fitted nile-tag {
|
|
265
|
+
flex-shrink: 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.select__tags nile-tag::part(base) {
|
|
269
|
+
max-width: 100%;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.select__tags nile-tag::part(prefix_content_wrapper) {
|
|
273
|
+
flex: 1 1 auto;
|
|
274
|
+
min-width: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.select__tags nile-tag::part(content) {
|
|
278
|
+
display: block;
|
|
279
|
+
flex: 1 1 auto;
|
|
280
|
+
min-width: 0;
|
|
281
|
+
/* The tag's line-height of 1 leaves the clip box shorter than the glyph
|
|
282
|
+
box, so descenders are cut. Pad the clip box, negate it in layout. */
|
|
283
|
+
padding-block: 3px;
|
|
284
|
+
margin-block: -3px;
|
|
285
|
+
overflow: hidden;
|
|
286
|
+
white-space: nowrap;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
:host([showtooltip]) .select__tags nile-tag::part(content) {
|
|
290
|
+
text-overflow: ellipsis;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.select__tags nile-tag::part(remove-button) {
|
|
294
|
+
flex: 0 0 auto;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.select__tags--fitted nile-tag:focus-visible {
|
|
298
|
+
outline: 2px solid var(--nile-colors-primary-600, var(--ng-colors-border-brand));
|
|
299
|
+
outline-offset: 1px;
|
|
300
|
+
border-radius: var(--nile-radius-sm, var(--ng-radius-sm));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.select__tags--fitted .select__tags-count {
|
|
304
|
+
flex: 0 0 auto;
|
|
305
|
+
margin: 0;
|
|
306
|
+
padding: 0 var(--nile-spacing-xsmall, var(--ng-spacing-md));
|
|
307
|
+
height: var(--nile-height-26px, var(--ng-height-26px));
|
|
308
|
+
display: inline-flex;
|
|
309
|
+
align-items: center;
|
|
310
|
+
white-space: nowrap;
|
|
311
|
+
cursor: pointer;
|
|
312
|
+
border: 1px dashed
|
|
313
|
+
var(--nile-colors-neutral-500, var(--ng-colors-border-secondary));
|
|
314
|
+
border-radius: var(--nile-radius-sm, var(--ng-radius-sm));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.select__tags--fitted .select__tags-count:focus-visible {
|
|
318
|
+
outline: 2px solid var(--nile-colors-primary-600, var(--ng-colors-border-brand));
|
|
319
|
+
outline-offset: 1px;
|
|
320
|
+
}
|
|
321
|
+
|
|
230
322
|
.select__tags::slotted(nile-tag) {
|
|
231
323
|
cursor: pointer !important;
|
|
232
324
|
}
|
|
@@ -457,9 +549,41 @@ export const styles = css`
|
|
|
457
549
|
flex-direction: row;
|
|
458
550
|
align-items: center;
|
|
459
551
|
padding: var(--nile-spacing-md, var(--ng-spacing-md)) var(--nile-spacing-lg, var(--ng-spacing-lg));
|
|
460
|
-
gap: var(--nile-spacing-
|
|
552
|
+
gap: var(--nile-spacing-none, var(--ng-spacing-none));
|
|
461
553
|
justify-content: space-between;
|
|
462
554
|
box-sizing: unset;
|
|
555
|
+
container-type: inline-size;
|
|
556
|
+
container-name: nile-select-footer;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.select__footer-action,
|
|
560
|
+
.select__footer .select__clear {
|
|
561
|
+
display: inline-flex;
|
|
562
|
+
align-items: center;
|
|
563
|
+
gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
|
|
564
|
+
min-width: 0;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.select__footer-glyph {
|
|
568
|
+
flex: 0 0 auto;
|
|
569
|
+
display: inline-flex;
|
|
570
|
+
vertical-align: middle;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.select__footer-label {
|
|
574
|
+
white-space: nowrap;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
@container nile-select-footer (max-width: 148px) {
|
|
578
|
+
.select__clear .select__footer-label {
|
|
579
|
+
display: none;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
@container nile-select-footer (max-width: 113px) {
|
|
584
|
+
.select__footer-label {
|
|
585
|
+
display: none;
|
|
586
|
+
}
|
|
463
587
|
}
|
|
464
588
|
|
|
465
589
|
.tag__prefix[slot='prefix'] {
|
|
@@ -496,10 +620,6 @@ export const styles = css`
|
|
|
496
620
|
}
|
|
497
621
|
}
|
|
498
622
|
|
|
499
|
-
.select__invisible{
|
|
500
|
-
opacity: 0;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
623
|
.select__prefix--from-options {
|
|
504
624
|
margin-inline-end: var(--nile-spacing-lg, var(--ng-spacing-md));
|
|
505
625
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, fixture, html } from '@open-wc/testing';
|
|
1
|
+
import { aTimeout, expect, fixture, html, nextFrame } from '@open-wc/testing';
|
|
2
2
|
import './nile-virtual-select';
|
|
3
3
|
import type { NileVirtualSelect } from './nile-virtual-select';
|
|
4
4
|
|
|
@@ -104,3 +104,354 @@ describe('NileVirtualSelect', () => {
|
|
|
104
104
|
it('99. no nile-calendar', async () => { const el = await fixture<NileVirtualSelect>(html`<nile-virtual-select></nile-virtual-select>`); expect(el.shadowRoot!.querySelector('nile-calendar')).to.be.null; });
|
|
105
105
|
it('100. full integration', async () => { const el = await fixture<NileVirtualSelect>(html`<nile-virtual-select class="vs" id="vs1"></nile-virtual-select>`); expect(el.id).to.equal('vs1'); expect(el.shadowRoot).to.not.be.null; expect(el.shadowRoot!.querySelector('nile-popup')).to.exist; expect(el.shadowRoot!.querySelector('.select__combobox')).to.exist; });
|
|
106
106
|
});
|
|
107
|
+
|
|
108
|
+
describe('NileVirtualSelect chip fitting behaviour matrix', () => {
|
|
109
|
+
const LABELS = [
|
|
110
|
+
'Engineering Operations Team',
|
|
111
|
+
'Human Resources Department',
|
|
112
|
+
'Finance And Accounting Group',
|
|
113
|
+
'Customer Success Organisation',
|
|
114
|
+
'Product Design Studio Unit'
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const DATA = LABELS.map(label => ({ label, value: label }));
|
|
118
|
+
|
|
119
|
+
async function settle(el: NileVirtualSelect) {
|
|
120
|
+
await el.updateComplete;
|
|
121
|
+
await nextFrame();
|
|
122
|
+
await nextFrame();
|
|
123
|
+
await el.updateComplete;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function tagsRoot(el: NileVirtualSelect) {
|
|
127
|
+
return el.shadowRoot!.querySelector('.select__tags');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function chips(el: NileVirtualSelect) {
|
|
131
|
+
return Array.from(
|
|
132
|
+
el.shadowRoot!.querySelectorAll('.select__tags nile-tag')
|
|
133
|
+
) as HTMLElement[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function hiddenChips(el: NileVirtualSelect) {
|
|
137
|
+
return chips(el).filter(chip => chip.style.display === 'none');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
it('V1. multiple + no max-options-visible + autoResize=false renders fitted chips', async () => {
|
|
141
|
+
const host = await fixture<HTMLElement>(
|
|
142
|
+
html`<div style="width: 320px">
|
|
143
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}>
|
|
144
|
+
</nile-virtual-select>
|
|
145
|
+
</div>`
|
|
146
|
+
);
|
|
147
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
148
|
+
await settle(el);
|
|
149
|
+
|
|
150
|
+
expect(el.autoResize).to.be.false;
|
|
151
|
+
expect(tagsRoot(el)!.classList.contains('select__tags--fitted')).to.be.true;
|
|
152
|
+
expect(el.shadowRoot!.querySelector('button.select__tags-count')).to.exist;
|
|
153
|
+
expect(chips(el).length).to.equal(LABELS.length);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('V2. multiple + no max-options-visible + autoResize=true refits when the container resizes', async () => {
|
|
157
|
+
const host = await fixture<HTMLElement>(
|
|
158
|
+
html`<div style="width: 480px">
|
|
159
|
+
<nile-virtual-select multiple autoresize .data=${DATA} .value=${LABELS}>
|
|
160
|
+
</nile-virtual-select>
|
|
161
|
+
</div>`
|
|
162
|
+
);
|
|
163
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
164
|
+
await settle(el);
|
|
165
|
+
|
|
166
|
+
expect(el.autoResize).to.be.true;
|
|
167
|
+
expect(tagsRoot(el)!.classList.contains('select__tags--fitted')).to.be.true;
|
|
168
|
+
const wideHidden = hiddenChips(el).length;
|
|
169
|
+
|
|
170
|
+
host.style.width = '180px';
|
|
171
|
+
await aTimeout(200);
|
|
172
|
+
await settle(el);
|
|
173
|
+
|
|
174
|
+
expect(hiddenChips(el).length).to.be.at.least(wideHidden);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('V3. explicit max-options-visible switches to fixed-count layout', async () => {
|
|
178
|
+
const host = await fixture<HTMLElement>(
|
|
179
|
+
html`<div style="width: 320px">
|
|
180
|
+
<nile-virtual-select
|
|
181
|
+
multiple
|
|
182
|
+
max-options-visible="2"
|
|
183
|
+
.data=${DATA}
|
|
184
|
+
.value=${LABELS}
|
|
185
|
+
></nile-virtual-select>
|
|
186
|
+
</div>`
|
|
187
|
+
);
|
|
188
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
189
|
+
await settle(el);
|
|
190
|
+
|
|
191
|
+
expect(el.maxOptionsVisible).to.equal(2);
|
|
192
|
+
expect(tagsRoot(el)!.classList.contains('select__tags--fitted')).to.be.false;
|
|
193
|
+
expect(chips(el).length).to.equal(2);
|
|
194
|
+
expect(el.shadowRoot!.querySelector('span.select__tags-count')).to.exist;
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('V3b. max-options-visible set as a property also switches to fixed-count layout', async () => {
|
|
198
|
+
const host = await fixture<HTMLElement>(
|
|
199
|
+
html`<div style="width: 320px">
|
|
200
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}>
|
|
201
|
+
</nile-virtual-select>
|
|
202
|
+
</div>`
|
|
203
|
+
);
|
|
204
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
205
|
+
await settle(el);
|
|
206
|
+
expect(tagsRoot(el)!.classList.contains('select__tags--fitted')).to.be.true;
|
|
207
|
+
|
|
208
|
+
el.maxOptionsVisible = 1;
|
|
209
|
+
await settle(el);
|
|
210
|
+
|
|
211
|
+
expect(tagsRoot(el)!.classList.contains('select__tags--fitted')).to.be.false;
|
|
212
|
+
expect(chips(el).length).to.equal(1);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('V3c. the default max-options-visible is still 3 and reading it does not opt out', async () => {
|
|
216
|
+
const host = await fixture<HTMLElement>(
|
|
217
|
+
html`<div style="width: 320px">
|
|
218
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}>
|
|
219
|
+
</nile-virtual-select>
|
|
220
|
+
</div>`
|
|
221
|
+
);
|
|
222
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
223
|
+
await settle(el);
|
|
224
|
+
|
|
225
|
+
expect(el.maxOptionsVisible).to.equal(3);
|
|
226
|
+
expect(el.maxOptionsVisible).to.equal(3);
|
|
227
|
+
await settle(el);
|
|
228
|
+
expect(tagsRoot(el)!.classList.contains('select__tags--fitted')).to.be.true;
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('V5. autoresize works as a markup attribute', async () => {
|
|
232
|
+
const b = await fixture<NileVirtualSelect>(
|
|
233
|
+
html`<nile-virtual-select multiple autoresize></nile-virtual-select>`
|
|
234
|
+
);
|
|
235
|
+
await b.updateComplete;
|
|
236
|
+
expect(b.autoResize).to.be.true;
|
|
237
|
+
|
|
238
|
+
const c = await fixture<NileVirtualSelect>(
|
|
239
|
+
html`<nile-virtual-select multiple></nile-virtual-select>`
|
|
240
|
+
);
|
|
241
|
+
await c.updateComplete;
|
|
242
|
+
expect(c.autoResize).to.be.false;
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('V6. the +N button count matches the number of hidden chips', async () => {
|
|
246
|
+
const host = await fixture<HTMLElement>(
|
|
247
|
+
html`<div style="width: 220px">
|
|
248
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}>
|
|
249
|
+
</nile-virtual-select>
|
|
250
|
+
</div>`
|
|
251
|
+
);
|
|
252
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
253
|
+
await settle(el);
|
|
254
|
+
|
|
255
|
+
const overflow = el.shadowRoot!.querySelector(
|
|
256
|
+
'button.select__tags-count'
|
|
257
|
+
) as HTMLElement | null;
|
|
258
|
+
const hidden = hiddenChips(el).length;
|
|
259
|
+
|
|
260
|
+
if (hidden > 0) {
|
|
261
|
+
expect(overflow).to.exist;
|
|
262
|
+
expect(overflow!.textContent!.trim()).to.equal(`+${hidden}`);
|
|
263
|
+
expect(overflow!.getAttribute('aria-label')).to.equal(
|
|
264
|
+
`${hidden} more selected`
|
|
265
|
+
);
|
|
266
|
+
} else {
|
|
267
|
+
// Nothing overflows, so the button is not rendered at all.
|
|
268
|
+
expect(overflow).to.not.exist;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('V7. nile-select and nile-virtual-select agree on when fitting is active', async () => {
|
|
273
|
+
const host = await fixture<HTMLElement>(
|
|
274
|
+
html`<div style="width: 320px">
|
|
275
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}>
|
|
276
|
+
</nile-virtual-select>
|
|
277
|
+
<nile-virtual-select
|
|
278
|
+
multiple
|
|
279
|
+
max-options-visible="2"
|
|
280
|
+
.data=${DATA}
|
|
281
|
+
.value=${LABELS}
|
|
282
|
+
></nile-virtual-select>
|
|
283
|
+
</div>`
|
|
284
|
+
);
|
|
285
|
+
const [fitted, fixed] = Array.from(
|
|
286
|
+
host.querySelectorAll('nile-virtual-select')
|
|
287
|
+
) as NileVirtualSelect[];
|
|
288
|
+
await settle(fitted);
|
|
289
|
+
await settle(fixed);
|
|
290
|
+
|
|
291
|
+
expect(tagsRoot(fitted)!.classList.contains('select__tags--fitted')).to.be
|
|
292
|
+
.true;
|
|
293
|
+
expect(tagsRoot(fixed)!.classList.contains('select__tags--fitted')).to.be
|
|
294
|
+
.false;
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// The tooltip is opt-in: `showtooltip` present, and the chip's text clipped.
|
|
298
|
+
function tips(el: NileVirtualSelect) {
|
|
299
|
+
return Array.from(
|
|
300
|
+
el.shadowRoot!.querySelectorAll('.select__tag-tip')
|
|
301
|
+
) as HTMLElement[];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function liveTips(el: NileVirtualSelect) {
|
|
305
|
+
return tips(el).filter(tip => !tip.hasAttribute('disabled'));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Truncation is bound to the tooltip: a clipped chip is only acceptable when
|
|
309
|
+
// something can reveal the value it hid. A chip wider than the whole field is
|
|
310
|
+
// the one exception - there is nowhere for it to go.
|
|
311
|
+
function chipContent(chip: HTMLElement) {
|
|
312
|
+
return chip.shadowRoot!.querySelector('[part~="content"]') as HTMLElement;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function clippedChipCount(el: NileVirtualSelect) {
|
|
316
|
+
return chips(el)
|
|
317
|
+
.filter(chip => chip.style.display !== 'none')
|
|
318
|
+
.filter(chip => {
|
|
319
|
+
const content = chipContent(chip);
|
|
320
|
+
return content.scrollWidth > content.clientWidth + 1;
|
|
321
|
+
}).length;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
it('V12. without showtooltip a fitted chip is never truncated', async () => {
|
|
325
|
+
const host = await fixture<HTMLElement>(
|
|
326
|
+
html`<div style="width: 480px">
|
|
327
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}></nile-virtual-select>
|
|
328
|
+
</div>`
|
|
329
|
+
);
|
|
330
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
331
|
+
await settle(el);
|
|
332
|
+
|
|
333
|
+
expect(el.showTooltip).to.be.false;
|
|
334
|
+
expect(clippedChipCount(el)).to.equal(0);
|
|
335
|
+
// The chips that could not fit went into the +N button, not into an ellipsis.
|
|
336
|
+
expect(hiddenChips(el).length).to.be.greaterThan(0);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('V13. showtooltip is what allows a fitted chip to be truncated', async () => {
|
|
340
|
+
const host = await fixture<HTMLElement>(
|
|
341
|
+
html`<div style="width: 480px">
|
|
342
|
+
<nile-virtual-select
|
|
343
|
+
multiple
|
|
344
|
+
showtooltip
|
|
345
|
+
.data=${DATA}
|
|
346
|
+
.value=${LABELS}
|
|
347
|
+
></nile-virtual-select>
|
|
348
|
+
</div>`
|
|
349
|
+
);
|
|
350
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
351
|
+
await settle(el);
|
|
352
|
+
|
|
353
|
+
expect(el.showTooltip).to.be.true;
|
|
354
|
+
expect(clippedChipCount(el)).to.be.greaterThan(0);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('V8. no showtooltip attribute hides the chip tooltip', async () => {
|
|
358
|
+
const host = await fixture<HTMLElement>(
|
|
359
|
+
html`<div style="width: 200px">
|
|
360
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}></nile-virtual-select>
|
|
361
|
+
</div>`
|
|
362
|
+
);
|
|
363
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
364
|
+
await settle(el);
|
|
365
|
+
|
|
366
|
+
expect(el.showTooltip).to.be.false;
|
|
367
|
+
expect(el.hasAttribute('showtooltip')).to.be.false;
|
|
368
|
+
expect(tips(el).length).to.be.greaterThan(0);
|
|
369
|
+
expect(liveTips(el).length).to.equal(0);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('V9. showtooltip shows the chip tooltip', async () => {
|
|
373
|
+
const host = await fixture<HTMLElement>(
|
|
374
|
+
html`<div style="width: 200px">
|
|
375
|
+
<nile-virtual-select multiple showtooltip .data=${DATA} .value=${LABELS}></nile-virtual-select>
|
|
376
|
+
</div>`
|
|
377
|
+
);
|
|
378
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
379
|
+
await settle(el);
|
|
380
|
+
|
|
381
|
+
expect(el.showTooltip).to.be.true;
|
|
382
|
+
expect(liveTips(el).length).to.be.greaterThan(0);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('V10. removing showtooltip hides the chip tooltip again', async () => {
|
|
386
|
+
const host = await fixture<HTMLElement>(
|
|
387
|
+
html`<div style="width: 200px">
|
|
388
|
+
<nile-virtual-select multiple showtooltip .data=${DATA} .value=${LABELS}></nile-virtual-select>
|
|
389
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}></nile-virtual-select>
|
|
390
|
+
</div>`
|
|
391
|
+
);
|
|
392
|
+
const [el, control] = Array.from(
|
|
393
|
+
host.querySelectorAll('nile-virtual-select')
|
|
394
|
+
) as NileVirtualSelect[];
|
|
395
|
+
await settle(el);
|
|
396
|
+
await settle(control);
|
|
397
|
+
|
|
398
|
+
expect(liveTips(el).length).to.be.greaterThan(0);
|
|
399
|
+
|
|
400
|
+
el.removeAttribute('showtooltip');
|
|
401
|
+
await settle(el);
|
|
402
|
+
|
|
403
|
+
expect(el.showTooltip).to.be.false;
|
|
404
|
+
expect(liveTips(el).length).to.equal(0);
|
|
405
|
+
// Removing the attribute must land back on the default.
|
|
406
|
+
expect(tips(el).map(tip => tip.hasAttribute('disabled'))).to.deep.equal(
|
|
407
|
+
tips(control).map(tip => tip.hasAttribute('disabled'))
|
|
408
|
+
);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('V11. the overflow button label and text never disagree, including first paint', async () => {
|
|
412
|
+
const host = await fixture<HTMLElement>(
|
|
413
|
+
html`<div style="width: 220px">
|
|
414
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS}>
|
|
415
|
+
</nile-virtual-select>
|
|
416
|
+
</div>`
|
|
417
|
+
);
|
|
418
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
419
|
+
|
|
420
|
+
// Before the layout frame runs, no button may claim a count it cannot back up.
|
|
421
|
+
await el.updateComplete;
|
|
422
|
+
const early = el.shadowRoot!.querySelector('button.select__tags-count');
|
|
423
|
+
if (early) {
|
|
424
|
+
const shown = early.textContent!.trim().replace('+', '');
|
|
425
|
+
expect(early.getAttribute('aria-label')).to.equal(
|
|
426
|
+
`${shown} more selected`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
await settle(el);
|
|
431
|
+
|
|
432
|
+
const overflow = el.shadowRoot!.querySelector(
|
|
433
|
+
'button.select__tags-count'
|
|
434
|
+
) as HTMLElement | null;
|
|
435
|
+
expect(overflow).to.exist;
|
|
436
|
+
const shown = overflow!.textContent!.trim().replace('+', '');
|
|
437
|
+
expect(overflow!.getAttribute('aria-label')).to.equal(
|
|
438
|
+
`${shown} more selected`
|
|
439
|
+
);
|
|
440
|
+
expect(Number(shown)).to.equal(hiddenChips(el).length);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('V12. no overflow button is rendered when every chip fits', async () => {
|
|
444
|
+
const host = await fixture<HTMLElement>(
|
|
445
|
+
html`<div style="width: 1200px">
|
|
446
|
+
<nile-virtual-select multiple .data=${DATA} .value=${LABELS.slice(0, 1)}>
|
|
447
|
+
</nile-virtual-select>
|
|
448
|
+
</div>`
|
|
449
|
+
);
|
|
450
|
+
const el = host.querySelector('nile-virtual-select') as NileVirtualSelect;
|
|
451
|
+
await settle(el);
|
|
452
|
+
|
|
453
|
+
expect(hiddenChips(el).length).to.equal(0);
|
|
454
|
+
expect(el.shadowRoot!.querySelector('button.select__tags-count')).to.not
|
|
455
|
+
.exist;
|
|
456
|
+
});
|
|
457
|
+
});
|