playbook_ui 18.2.0.pre.alpha.PLAY3330requiredtypeaheadvalidationbug20501 → 18.2.0.pre.alpha.PLAY3330requiredtypeaheadvalidationbug20513
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +126 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +15 -10
- data/dist/ai/forms.json +1 -1
- data/dist/ai/index.json +2 -2
- data/dist/chunks/{_typeahead-DNfFwTns.js → _typeahead-BDjppKc1.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f9a07c8fc62bc1d10aa56006d9eeeb75205676445028b7bd80aef17e361c8973
|
|
4
|
+
data.tar.gz: 0314b68de5cd6b14230b1879806806078a120fec39ed60489c1523b489347b93
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b122cf616f2f43a735c51aafb13ca40fe5ad44e639dae5289abb33c0de7a7afbf679338889ee2ef3c397551c41bfacc5801b610709138ae4dd7c148df7830e9
|
|
7
|
+
data.tar.gz: ce7c196c03bfca844e78e3651e1be09804b7373890a69cfeceb671592b75bed78c3d976b3e5978e8ff81459d23c3d6a010faf88044ae4e0119b12550ea30202c
|
|
@@ -630,3 +630,129 @@ test(':set calls onChange but does not dispatch result-option-select', async ()
|
|
|
630
630
|
selectHandler,
|
|
631
631
|
)
|
|
632
632
|
})
|
|
633
|
+
|
|
634
|
+
test('required Typeahead in validated form shows its own error and stays mounted after selection', async () => {
|
|
635
|
+
render(
|
|
636
|
+
<form data-pb-form-validation="true">
|
|
637
|
+
<Typeahead
|
|
638
|
+
data={{ testid: 'required-validated-typeahead' }}
|
|
639
|
+
isMulti={false}
|
|
640
|
+
name="favorite_color"
|
|
641
|
+
options={options}
|
|
642
|
+
required
|
|
643
|
+
validation={{ message: 'Please select a color' }}
|
|
644
|
+
/>
|
|
645
|
+
</form>
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
const kit = screen.getByTestId('required-validated-typeahead')
|
|
649
|
+
const requiredInput = kit.querySelector('input[required]')
|
|
650
|
+
expect(requiredInput).toBeInTheDocument()
|
|
651
|
+
|
|
652
|
+
act(() => {
|
|
653
|
+
requiredInput.dispatchEvent(new Event('invalid', { bubbles: false, cancelable: true }))
|
|
654
|
+
})
|
|
655
|
+
|
|
656
|
+
await waitFor(() => {
|
|
657
|
+
expect(kit.querySelector('.pb_body_kit_negative')).toHaveTextContent('Please select a color')
|
|
658
|
+
})
|
|
659
|
+
|
|
660
|
+
// PbFormValidation must not own this input — no injected sibling error on the
|
|
661
|
+
// react-select RequiredInput parent (that path caused removeChild crashes).
|
|
662
|
+
const injectedSibling = Array.from(requiredInput.parentElement.children).find(
|
|
663
|
+
(child) => child.classList?.contains('pb_body_kit_negative')
|
|
664
|
+
)
|
|
665
|
+
expect(injectedSibling).toBeUndefined()
|
|
666
|
+
|
|
667
|
+
const control = kit.querySelector('.typeahead-kit-select__control')
|
|
668
|
+
fireEvent.mouseDown(control)
|
|
669
|
+
|
|
670
|
+
await waitFor(() => {
|
|
671
|
+
expect(document.querySelector('.typeahead-kit-select__option')).toBeInTheDocument()
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
fireEvent.click(screen.getByText('Orange'))
|
|
675
|
+
|
|
676
|
+
await waitFor(() => {
|
|
677
|
+
expect(screen.getByTestId('required-validated-typeahead')).toBeInTheDocument()
|
|
678
|
+
expect(
|
|
679
|
+
screen.getByTestId('required-validated-typeahead').querySelector('.pb_body_kit_negative')
|
|
680
|
+
).not.toBeInTheDocument()
|
|
681
|
+
})
|
|
682
|
+
})
|
|
683
|
+
|
|
684
|
+
test('required Typeahead restores validation error after clear and resubmit', async () => {
|
|
685
|
+
render(
|
|
686
|
+
<form data-pb-form-validation="true">
|
|
687
|
+
<Typeahead
|
|
688
|
+
data={{ testid: 'required-clear-resubmit-typeahead' }}
|
|
689
|
+
defaultValue={options[0]}
|
|
690
|
+
isMulti={false}
|
|
691
|
+
name="favorite_color"
|
|
692
|
+
options={options}
|
|
693
|
+
required
|
|
694
|
+
validation={{ message: 'Please select a color' }}
|
|
695
|
+
/>
|
|
696
|
+
</form>
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
const kit = screen.getByTestId('required-clear-resubmit-typeahead')
|
|
700
|
+
const clearIndicator = kit.querySelector('.typeahead-kit-select__clear-indicator')
|
|
701
|
+
expect(clearIndicator).toBeInTheDocument()
|
|
702
|
+
fireEvent.mouseDown(clearIndicator)
|
|
703
|
+
|
|
704
|
+
await waitFor(() => {
|
|
705
|
+
expect(kit.querySelector('input[required]')).toBeInTheDocument()
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
const requiredInput = kit.querySelector('input[required]')
|
|
709
|
+
act(() => {
|
|
710
|
+
requiredInput.dispatchEvent(new Event('invalid', { bubbles: false, cancelable: true }))
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
await waitFor(() => {
|
|
714
|
+
expect(kit.querySelector('.pb_body_kit_negative')).toHaveTextContent('Please select a color')
|
|
715
|
+
})
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
test('required Typeahead suppresses native invalid UI only inside validated Playbook forms', () => {
|
|
719
|
+
const { unmount } = render(
|
|
720
|
+
<form data-pb-form-validation="true">
|
|
721
|
+
<Typeahead
|
|
722
|
+
data={{ testid: 'native-invalid-validated' }}
|
|
723
|
+
isMulti={false}
|
|
724
|
+
name="color"
|
|
725
|
+
options={options}
|
|
726
|
+
required
|
|
727
|
+
/>
|
|
728
|
+
</form>
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
let requiredInput = screen.getByTestId('native-invalid-validated').querySelector('input[required]')
|
|
732
|
+
const validatedEvent = new Event('invalid', { bubbles: false, cancelable: true })
|
|
733
|
+
act(() => {
|
|
734
|
+
requiredInput.dispatchEvent(validatedEvent)
|
|
735
|
+
})
|
|
736
|
+
expect(validatedEvent.defaultPrevented).toBe(true)
|
|
737
|
+
|
|
738
|
+
unmount()
|
|
739
|
+
|
|
740
|
+
render(
|
|
741
|
+
<form>
|
|
742
|
+
<Typeahead
|
|
743
|
+
data={{ testid: 'native-invalid-unvalidated' }}
|
|
744
|
+
isMulti={false}
|
|
745
|
+
name="color"
|
|
746
|
+
options={options}
|
|
747
|
+
required
|
|
748
|
+
/>
|
|
749
|
+
</form>
|
|
750
|
+
)
|
|
751
|
+
|
|
752
|
+
requiredInput = screen.getByTestId('native-invalid-unvalidated').querySelector('input[required]')
|
|
753
|
+
const unvalidatedEvent = new Event('invalid', { bubbles: false, cancelable: true })
|
|
754
|
+
act(() => {
|
|
755
|
+
requiredInput.dispatchEvent(unvalidatedEvent)
|
|
756
|
+
})
|
|
757
|
+
expect(unvalidatedEvent.defaultPrevented).toBe(false)
|
|
758
|
+
})
|
|
@@ -541,20 +541,25 @@ const resolvedLoadOptions =
|
|
|
541
541
|
|
|
542
542
|
const [contextValue, setContextValue] = useState("")
|
|
543
543
|
|
|
544
|
-
//
|
|
544
|
+
// Track form submit validation for react-rendered Typeahead (own error UI).
|
|
545
|
+
// When inside pb_form_with validate: true, suppress the browser's native
|
|
546
|
+
// invalid UI — PbFormValidation skips this kit so it must not double-show.
|
|
545
547
|
useEffect(() => {
|
|
546
548
|
const handleInvalid = (event: Event) => {
|
|
547
549
|
const target = event.target as HTMLInputElement
|
|
548
|
-
|
|
549
|
-
'[data-pb-react-component="Typeahead"]',
|
|
550
|
-
)
|
|
550
|
+
if (!kitContainerRef.current?.contains(target)) return
|
|
551
551
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
552
|
+
// Match by name so we do not have to require ids
|
|
553
|
+
const invalidInputName = target.name || target.getAttribute("name")
|
|
554
|
+
if (invalidInputName !== name) return
|
|
555
|
+
|
|
556
|
+
setFormSubmitted(true)
|
|
557
|
+
|
|
558
|
+
const validatedForm = target.closest(
|
|
559
|
+
'form[data-pb-form-validation="true"]',
|
|
560
|
+
)
|
|
561
|
+
if (validatedForm) {
|
|
562
|
+
event.preventDefault()
|
|
558
563
|
}
|
|
559
564
|
}
|
|
560
565
|
document.addEventListener("invalid", handleInvalid, true)
|
data/dist/ai/forms.json
CHANGED
data/dist/ai/index.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "18.2.0-alpha.
|
|
2
|
+
"version": "18.2.0-alpha.PLAY3330requiredtypeaheadvalidationbug20513",
|
|
3
3
|
"metadataVersion": 1,
|
|
4
4
|
"forms": "forms.json",
|
|
5
|
-
"generated": "2026-10-
|
|
5
|
+
"generated": "2026-10-26T18:47:24.653Z",
|
|
6
6
|
"schemas": {
|
|
7
7
|
"globalProps": "global-props.schema.json",
|
|
8
8
|
"globalEventProps": "global-event-props.schema.json",
|