@instructure/ui-select 10.18.2-snapshot-0 → 10.18.2-snapshot-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.
package/CHANGELOG.md CHANGED
@@ -3,9 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [10.18.2-snapshot-0](https://github.com/instructure/instructure-ui/compare/v10.18.1...v10.18.2-snapshot-0) (2025-06-02)
6
+ ## [10.18.2-snapshot-2](https://github.com/instructure/instructure-ui/compare/v10.18.1...v10.18.2-snapshot-2) (2025-06-03)
7
7
 
8
- **Note:** Version bump only for package @instructure/ui-select
8
+
9
+ ### Bug Fixes
10
+
11
+ * **many:** fix "not a valid selector" exception when an option ID contains quotes ([78e0b96](https://github.com/instructure/instructure-ui/commit/78e0b96edf29f3d476ba30b03134f1726bbdd0f4))
9
12
 
10
13
 
11
14
 
@@ -1,4 +1,4 @@
1
- var _Select, _Select2, _Select3, _Select4, _Select5, _Select6, _Select7;
1
+ var _Select$Option, _Select, _Select2, _Select3, _Select4, _Select5, _Select6, _Select7;
2
2
  /*
3
3
  * The MIT License (MIT)
4
4
  *
@@ -207,43 +207,67 @@ describe('<Select />', () => {
207
207
  afterEach(() => {
208
208
  consoleErrorMock.mockRestore();
209
209
  });
210
+ it('should not crash for weird option ids', async () => {
211
+ const weirdID = 'some_`w@ei:r|!@#$%^&*(()|\\.l/d"id';
212
+ vi.useFakeTimers();
213
+ const _render = render(_jsxs(Select, {
214
+ renderLabel: "Choose an option",
215
+ scrollToHighlightedOption: true,
216
+ isShowingOptions: true,
217
+ children: [_jsx(Select.Option, {
218
+ id: weirdID,
219
+ value: "2",
220
+ isHighlighted: true,
221
+ children: "op1"
222
+ }, "1"), _Select$Option || (_Select$Option = _jsx(Select.Option, {
223
+ id: "sdfsdfsd",
224
+ value: "2",
225
+ children: "op2"
226
+ }, "2"))]
227
+ })),
228
+ container = _render.container;
229
+ vi.advanceTimersToNextFrame();
230
+ vi.useRealTimers();
231
+ const input = container.querySelector('input');
232
+ expect(input).toBeInTheDocument();
233
+ });
210
234
  it('should have role button in Safari without onInputChange', async () => {
211
- const _render = render(_jsx(Select, {
235
+ const _render2 = render(_jsx(Select, {
212
236
  renderLabel: "Choose an option",
213
237
  children: getOptions()
214
238
  })),
215
- container = _render.container;
239
+ container = _render2.container;
216
240
  const input = container.querySelector('input');
217
241
  expect(input).toHaveAttribute('role', 'button');
218
242
  });
219
243
  it('should have role combobox in different browsers than Safari without onInputChange', async () => {
220
244
  mockUtils.isSafari = vi.fn(() => false);
221
- const _render2 = render(_jsx(Select, {
245
+ const _render3 = render(_jsx(Select, {
222
246
  renderLabel: "Choose an option",
223
247
  children: getOptions()
224
248
  })),
225
- container = _render2.container;
249
+ container = _render3.container;
226
250
  const input = container.querySelector('input');
227
251
  expect(input).toHaveAttribute('role', 'combobox');
228
252
  });
229
253
  it('should have role combobox with onInputChange', async () => {
230
- const _render3 = render(_jsx(Select, {
254
+ const _render4 = render(_jsx(Select, {
231
255
  renderLabel: "Choose an option",
232
256
  onInputChange: () => {},
233
257
  children: getOptions()
234
258
  })),
235
- container = _render3.container;
259
+ container = _render4.container;
236
260
  const input = container.querySelector('input');
237
261
  expect(input).toHaveAttribute('role', 'combobox');
238
262
  });
239
263
  it('should render an input and a list', async () => {
240
- const _render4 = render(_jsx(Select, {
264
+ const _render5 = render(_jsx(Select, {
241
265
  renderLabel: "Choose an option",
242
266
  isShowingOptions: true,
243
267
  "data-testid": "subidubi",
244
268
  children: getOptions()
245
269
  })),
246
- container = _render4.container;
270
+ container = _render5.container;
247
271
  const select = container.querySelector('span[class$="-select"]');
248
272
  const label = screen.getByLabelText('Choose an option');
249
273
  const input = container.querySelector('input[id^="Select_"]');
@@ -336,20 +360,20 @@ describe('<Select />', () => {
336
360
  });
337
361
  describe('input', () => {
338
362
  it('should render with a generated id by default', () => {
339
- const _render5 = render(_Select3 || (_Select3 = _jsx(Select, {
363
+ const _render6 = render(_Select3 || (_Select3 = _jsx(Select, {
340
364
  renderLabel: "Choose an option"
341
365
  }))),
342
- container = _render5.container;
366
+ container = _render6.container;
343
367
  const input = container.querySelector('input[id^="Select_"]');
344
368
  expect(input).toBeInTheDocument();
345
369
  expect(input).toHaveAttribute('id', expect.stringContaining('Select_'));
346
370
  });
347
371
  it('should render with a custom id if given', () => {
348
- const _render6 = render(_Select4 || (_Select4 = _jsx(Select, {
372
+ const _render7 = render(_Select4 || (_Select4 = _jsx(Select, {
349
373
  renderLabel: "Choose an option",
350
374
  id: "customSelect"
351
375
  }))),
352
- container = _render6.container;
376
+ container = _render7.container;
353
377
  const input = container.querySelector('input[id^="customSelect"]');
354
378
  expect(input).toBeInTheDocument();
355
379
  expect(input.getAttribute('id')).toEqual('customSelect');
@@ -455,11 +479,11 @@ describe('<Select />', () => {
455
479
  expect(input).toHaveAttribute('data-custom-attr', 'true');
456
480
  });
457
481
  it('should allow override of autoComplete prop', () => {
458
- const _render7 = render(_jsx(Select, {
482
+ const _render8 = render(_jsx(Select, {
459
483
  renderLabel: "Choose an option",
460
484
  children: getOptions()
461
485
  })),
462
- rerender = _render7.rerender;
486
+ rerender = _render8.rerender;
463
487
  const input = screen.getByLabelText('Choose an option');
464
488
  expect(input).toHaveAttribute('autocomplete', 'off');
465
489
  rerender(_jsx(Select, {
@@ -482,170 +506,170 @@ describe('<Select />', () => {
482
506
  });
483
507
  });
484
508
  it("should not render option's before content in input field when isOptionContentAppliedToInput is set to false", async () => {
485
- const _render8 = render(_jsx(Select, {
509
+ const _render9 = render(_jsx(Select, {
486
510
  renderLabel: "Choose an option",
487
511
  isOptionContentAppliedToInput: false,
488
512
  inputValue: optionsWithBeforeContent[0].label,
489
513
  children: getOptionsWithBeforeContent('opt1')
490
514
  })),
491
- container = _render8.container;
515
+ container = _render9.container;
492
516
  const beforeContent = container.querySelector('span[class$="-textInput__layout"]');
493
517
  expect(beforeContent).not.toHaveTextContent('XY');
494
518
  });
495
519
  it('should render arrow in input field when isOptionContentAppliedToInput is set to false', async () => {
496
- const _render9 = render(_jsx(Select, {
520
+ const _render10 = render(_jsx(Select, {
497
521
  renderLabel: "Choose an option",
498
522
  isOptionContentAppliedToInput: false,
499
523
  inputValue: optionsWithBeforeContent[0].label,
500
524
  children: getOptionsWithBeforeContent('opt1')
501
525
  })),
502
- container = _render9.container;
526
+ container = _render10.container;
503
527
  const spanElement = container.querySelector('span[class$="-textInput__afterElement"]');
504
528
  const svgElement = spanElement.querySelector('svg[name="IconArrowOpenDown"]');
505
529
  expect(svgElement).toBeInTheDocument();
506
530
  });
507
531
  it("should render option's before content in input field when isOptionContentAppliedToInput is set to true", async () => {
508
- const _render10 = render(_jsx(Select, {
532
+ const _render11 = render(_jsx(Select, {
509
533
  renderLabel: "Choose an option",
510
534
  isOptionContentAppliedToInput: true,
511
535
  inputValue: optionsWithBeforeContent[0].label,
512
536
  children: getOptionsWithBeforeContent('opt1')
513
537
  })),
514
- container = _render10.container;
538
+ container = _render11.container;
515
539
  const beforeContent = container.querySelector('span[class$="-textInput__layout"]');
516
540
  expect(beforeContent).toHaveTextContent('XY');
517
541
  });
518
542
  it('should render arrow icon when isOptionContentAppliedToInput is set to true with before content', async () => {
519
- const _render11 = render(_jsx(Select, {
543
+ const _render12 = render(_jsx(Select, {
520
544
  renderLabel: "Choose an option",
521
545
  isOptionContentAppliedToInput: true,
522
546
  inputValue: optionsWithBeforeContent[0].label,
523
547
  children: getOptionsWithBeforeContent('opt1')
524
548
  })),
525
- container = _render11.container;
549
+ container = _render12.container;
526
550
  const spanElement = container.querySelector('span[class$="-textInput__afterElement"]');
527
551
  const svgElement = spanElement.querySelector('svg[name="IconArrowOpenDown"]');
528
552
  expect(svgElement).toBeInTheDocument();
529
553
  });
530
554
  it("should render option's after content in input field when isOptionContentAppliedToInput is set to true", async () => {
531
- const _render12 = render(_jsx(Select, {
555
+ const _render13 = render(_jsx(Select, {
532
556
  renderLabel: "Choose an option",
533
557
  isOptionContentAppliedToInput: true,
534
558
  inputValue: optionsWithAfterContent[0].label,
535
559
  children: getOptionsWithAfterContent('opt1')
536
560
  })),
537
- container = _render12.container;
561
+ container = _render13.container;
538
562
  const beforeContent = container.querySelector('span[class$="-textInput__afterElement"]');
539
563
  expect(beforeContent).toHaveTextContent('XY');
540
564
  });
541
565
  it("should render option's before content in input field when isOptionContentAppliedToInput is set to true but renderBeforeInput is also set", async () => {
542
- const _render13 = render(_jsx(Select, {
566
+ const _render14 = render(_jsx(Select, {
543
567
  renderLabel: "Choose an option",
544
568
  isOptionContentAppliedToInput: true,
545
569
  inputValue: optionsWithBeforeContent[0].label,
546
570
  renderBeforeInput: "ZZ",
547
571
  children: getOptionsWithBeforeContent('opt1')
548
572
  })),
549
- container = _render13.container;
573
+ container = _render14.container;
550
574
  const beforeContent = container.querySelector('span[class$="-textInput__layout"]');
551
575
  expect(beforeContent).toHaveTextContent('XY');
552
576
  });
553
577
  it("should render option's after content in input field when isOptionContentAppliedToInput is set to true but renderAfterInput is also set", async () => {
554
- const _render14 = render(_jsx(Select, {
578
+ const _render15 = render(_jsx(Select, {
555
579
  renderLabel: "Choose an option",
556
580
  isOptionContentAppliedToInput: true,
557
581
  inputValue: optionsWithAfterContent[0].label,
558
582
  renderAfterInput: "ZZ",
559
583
  children: getOptionsWithAfterContent('opt1')
560
584
  })),
561
- container = _render14.container;
585
+ container = _render15.container;
562
586
  const afterContent = container.querySelector('span[class$="-textInput__afterElement"]');
563
587
  expect(afterContent).toHaveTextContent('XY');
564
588
  });
565
589
  it("should not render option's before content in input field when isOptionContentAppliedToInput is set to true but inputValue is not set", async () => {
566
- const _render15 = render(_jsx(Select, {
590
+ const _render16 = render(_jsx(Select, {
567
591
  renderLabel: "Choose an option",
568
592
  isOptionContentAppliedToInput: true,
569
593
  children: getOptionsWithBeforeContent('opt1')
570
594
  })),
571
- container = _render15.container;
595
+ container = _render16.container;
572
596
  const beforeContent = container.querySelector('span[class$="-textInput__layout"]');
573
597
  expect(beforeContent).not.toHaveTextContent('XY');
574
598
  });
575
599
  it("should render option's before content in input field when isOptionContentAppliedToInput is set to true and both optionBeforeContent and optionAfterContent are provided", async () => {
576
- const _render16 = render(_jsx(Select, {
600
+ const _render17 = render(_jsx(Select, {
577
601
  renderLabel: "Choose an option",
578
602
  isOptionContentAppliedToInput: true,
579
603
  inputValue: optionsWithBeforeAndAfterContent[0].label,
580
604
  children: getOptionsWithBeforeAndAfterContent('opt1')
581
605
  })),
582
- container = _render16.container;
606
+ container = _render17.container;
583
607
  const beforeContent = container.querySelector('span[class$="-textInput__layout"]');
584
608
  expect(beforeContent).toHaveTextContent('XY');
585
609
  });
586
610
  it("should render option's after content in input field when isOptionContentAppliedToInput is set to true and both optionBeforeContent and optionAfterContent are provided", async () => {
587
- const _render17 = render(_jsx(Select, {
611
+ const _render18 = render(_jsx(Select, {
588
612
  renderLabel: "Choose an option",
589
613
  isOptionContentAppliedToInput: true,
590
614
  inputValue: optionsWithBeforeAndAfterContent[0].label,
591
615
  children: getOptionsWithBeforeAndAfterContent('opt1')
592
616
  })),
593
- container = _render17.container;
617
+ container = _render18.container;
594
618
  const afterContent = container.querySelector('span[class$="-textInput__afterElement"]');
595
619
  expect(afterContent).toHaveTextContent('ZZ');
596
620
  });
597
621
  it('should render arrow in input field when isOptionContentAppliedToInput is set to true but inputValue is not set', async () => {
598
- const _render18 = render(_jsx(Select, {
622
+ const _render19 = render(_jsx(Select, {
599
623
  renderLabel: "Choose an option",
600
624
  isOptionContentAppliedToInput: true,
601
625
  children: getOptionsWithBeforeContent('opt1')
602
626
  })),
603
- container = _render18.container;
627
+ container = _render19.container;
604
628
  const spanElement = container.querySelector('span[class$="-textInput__afterElement"]');
605
629
  const svgElement = spanElement.querySelector('svg[name="IconArrowOpenDown"]');
606
630
  expect(svgElement).toBeInTheDocument();
607
631
  });
608
632
  it("should not render option's after content in input field when isOptionContentAppliedToInput is set to true but inputValue is not set", async () => {
609
- const _render19 = render(_jsx(Select, {
633
+ const _render20 = render(_jsx(Select, {
610
634
  renderLabel: "Choose an option",
611
635
  isOptionContentAppliedToInput: true,
612
636
  children: getOptionsWithBeforeContent('opt1')
613
637
  })),
614
- container = _render19.container;
638
+ container = _render20.container;
615
639
  const afterContent = container.querySelector('span[class$="-textInput__afterElement"]');
616
640
  expect(afterContent).not.toHaveTextContent('XY');
617
641
  });
618
642
  it("should render option's before content input field when isOptionContentAppliedToInput is set to true with group options", async () => {
619
- const _render20 = render(_jsx(Select, {
643
+ const _render21 = render(_jsx(Select, {
620
644
  renderLabel: "Choose an option",
621
645
  isOptionContentAppliedToInput: true,
622
646
  inputValue: groupOptionsWithBeforeContent.Options1[0].label,
623
647
  children: getGroupOptionsWithBeforeContent('opt1')
624
648
  })),
625
- container = _render20.container;
649
+ container = _render21.container;
626
650
  const beforeContent = container.querySelector('span[class$="-textInput__layout"]');
627
651
  expect(beforeContent).toHaveTextContent('XY');
628
652
  });
629
653
  it('should render arrow icon when isOptionContentAppliedToInput is set to true with before content and group options', async () => {
630
- const _render21 = render(_jsx(Select, {
654
+ const _render22 = render(_jsx(Select, {
631
655
  renderLabel: "Choose an option",
632
656
  isOptionContentAppliedToInput: true,
633
657
  inputValue: groupOptionsWithBeforeContent.Options1[0].label,
634
658
  children: getGroupOptionsWithBeforeContent('opt1')
635
659
  })),
636
- container = _render21.container;
660
+ container = _render22.container;
637
661
  const spanElement = container.querySelector('span[class$="-textInput__afterElement"]');
638
662
  const svgElement = spanElement.querySelector('svg[name="IconArrowOpenDown"]');
639
663
  expect(svgElement).toBeInTheDocument();
640
664
  });
641
665
  it("should render option's after content input field when isOptionContentAppliedToInput is set to true with group options", async () => {
642
- const _render22 = render(_jsx(Select, {
666
+ const _render23 = render(_jsx(Select, {
643
667
  renderLabel: "Choose an option",
644
668
  isOptionContentAppliedToInput: true,
645
669
  inputValue: groupOptionsWithAfterContent.Options2[0].label,
646
670
  children: getGroupOptionsWithAfterContent('opt4')
647
671
  })),
648
- container = _render22.container;
672
+ container = _render23.container;
649
673
  const afterContent = container.querySelector('span[class$="-textInput__afterElement"]');
650
674
  expect(afterContent).toHaveTextContent('AB');
651
675
  });
@@ -698,13 +722,13 @@ describe('<Select />', () => {
698
722
  describe('should fire onRequestShowOptions', () => {
699
723
  it('when root is clicked', async () => {
700
724
  const onRequestShowOptions = vi.fn();
701
- const _render23 = render(_jsx(Select, {
725
+ const _render24 = render(_jsx(Select, {
702
726
  renderLabel: "Choose an option",
703
727
  onRequestShowOptions: onRequestShowOptions,
704
728
  children: getOptions()
705
729
  })),
706
- container = _render23.container,
707
- rerender = _render23.rerender;
730
+ container = _render24.container,
731
+ rerender = _render24.rerender;
708
732
  const icon = container.querySelector('svg[name="IconArrowOpenDown"]');
709
733
  const label = screen.getByText('Choose an option');
710
734
  expect(icon).toBeInTheDocument();
@@ -730,12 +754,12 @@ describe('<Select />', () => {
730
754
  });
731
755
  it('when input is clicked', async () => {
732
756
  const onRequestShowOptions = vi.fn();
733
- const _render24 = render(_jsx(Select, {
757
+ const _render25 = render(_jsx(Select, {
734
758
  renderLabel: "Choose an option",
735
759
  onRequestShowOptions: onRequestShowOptions,
736
760
  children: getOptions()
737
761
  })),
738
- rerender = _render24.rerender;
762
+ rerender = _render25.rerender;
739
763
  const input = screen.getByLabelText('Choose an option');
740
764
  await userEvent.click(input);
741
765
  await waitFor(() => {
@@ -771,12 +795,12 @@ describe('<Select />', () => {
771
795
  });
772
796
  it('when space is pressed', async () => {
773
797
  const onRequestShowOptions = vi.fn();
774
- const _render25 = render(_jsx(Select, {
798
+ const _render26 = render(_jsx(Select, {
775
799
  renderLabel: "Choose an option",
776
800
  onRequestShowOptions: onRequestShowOptions,
777
801
  children: getOptions()
778
802
  })),
779
- rerender = _render25.rerender;
803
+ rerender = _render26.rerender;
780
804
  const input = screen.getByLabelText('Choose an option');
781
805
  await userEvent.type(input, '{space}');
782
806
  await waitFor(() => {
@@ -797,13 +821,13 @@ describe('<Select />', () => {
797
821
  describe('should fire onRequestHideOptions', () => {
798
822
  it('when root is clicked and isShowingOptions is true', async () => {
799
823
  const onRequestHideOptions = vi.fn();
800
- const _render26 = render(_jsx(Select, {
824
+ const _render27 = render(_jsx(Select, {
801
825
  renderLabel: "Choose an option",
802
826
  isShowingOptions: true,
803
827
  onRequestHideOptions: onRequestHideOptions,
804
828
  children: getOptions()
805
829
  })),
806
- container = _render26.container;
830
+ container = _render27.container;
807
831
  const icon = container.querySelector('svg[name="IconArrowOpenUp"]');
808
832
  const label = screen.getByText('Choose an option');
809
833
  expect(icon).toBeInTheDocument();
@@ -834,13 +858,13 @@ describe('<Select />', () => {
834
858
  });
835
859
  it('when input is clicked', async () => {
836
860
  const onRequestHideOptions = vi.fn();
837
- const _render27 = render(_jsx(Select, {
861
+ const _render28 = render(_jsx(Select, {
838
862
  renderLabel: "Choose an option",
839
863
  isShowingOptions: true,
840
864
  onRequestHideOptions: onRequestHideOptions,
841
865
  children: getOptions()
842
866
  })),
843
- rerender = _render27.rerender;
867
+ rerender = _render28.rerender;
844
868
  const input = screen.getByLabelText('Choose an option');
845
869
  await userEvent.click(input);
846
870
  await waitFor(() => {
@@ -930,8 +954,8 @@ describe('<Select />', () => {
930
954
  it.each(generatedComponents)('should be accessible with example: $description', async ({
931
955
  content
932
956
  }) => {
933
- const _render28 = render(content),
934
- container = _render28.container;
957
+ const _render29 = render(content),
958
+ container = _render29.container;
935
959
  const axeCheck = await runAxeCheck(container);
936
960
  expect(axeCheck).toBe(true);
937
961
  });
@@ -200,19 +200,18 @@ let Select = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, gen
200
200
  return selectedOptionId;
201
201
  }
202
202
  scrollToOption(id) {
203
- if (this._listView) {
204
- const option = this._listView.querySelector(`[id="${id}"]`);
205
- if (!option) return;
206
- const listItem = option.parentNode;
207
- const parentTop = getBoundingClientRect(this._listView).top;
208
- const elemTop = getBoundingClientRect(listItem).top;
209
- const parentBottom = parentTop + this._listView.clientHeight;
210
- const elemBottom = elemTop + (listItem ? listItem.clientHeight : 0);
211
- if (elemBottom > parentBottom) {
212
- this._listView.scrollTop += elemBottom - parentBottom;
213
- } else if (elemTop < parentTop) {
214
- this._listView.scrollTop -= parentTop - elemTop;
215
- }
203
+ if (!this._listView || !id) return;
204
+ const option = this._listView.querySelector(`[id="${CSS.escape(id)}"]`);
205
+ if (!option) return;
206
+ const listItem = option.parentNode;
207
+ const parentTop = getBoundingClientRect(this._listView).top;
208
+ const elemTop = getBoundingClientRect(listItem).top;
209
+ const parentBottom = parentTop + this._listView.clientHeight;
210
+ const elemBottom = elemTop + (listItem ? listItem.clientHeight : 0);
211
+ if (elemBottom > parentBottom) {
212
+ this._listView.scrollTop += elemBottom - parentBottom;
213
+ } else if (elemTop < parentTop) {
214
+ this._listView.scrollTop -= parentTop - elemTop;
216
215
  }
217
216
  }
218
217
  highlightOption(event, id) {