@openedx/paragon 22.13.0 → 22.15.0
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/dist/Alert/_variables.scss +2 -1
- package/dist/Annotation/index.js.map +1 -1
- package/dist/Annotation/index.scss +6 -5
- package/dist/Avatar/index.js.map +1 -1
- package/dist/AvatarButton/index.js.map +1 -1
- package/dist/Breadcrumb/index.js.map +1 -1
- package/dist/Bubble/index.js +1 -0
- package/dist/Bubble/index.js.map +1 -1
- package/dist/Bubble/index.scss +3 -2
- package/dist/Button/deprecated/index.js.map +1 -1
- package/dist/Button/index.scss +19 -18
- package/dist/Card/CardCarousel/CardCarouselHeader.js +2 -2
- package/dist/Card/CardCarousel/CardCarouselHeader.js.map +1 -1
- package/dist/Card/CardFooter.js.map +1 -1
- package/dist/Card/CardHeader.js +1 -1
- package/dist/Card/CardHeader.js.map +1 -1
- package/dist/Card/CardImageCap.js.map +1 -1
- package/dist/Card/CardStatus.js.map +1 -1
- package/dist/Card/_variables.scss +3 -2
- package/dist/Card/index.js.map +1 -1
- package/dist/Card/index.scss +10 -9
- package/dist/Chip/ChipIcon.d.ts +1 -1
- package/dist/Chip/index.js +1 -0
- package/dist/Chip/index.js.map +1 -1
- package/dist/ChipCarousel/index.js.map +1 -1
- package/dist/Collapsible/index.js.map +1 -1
- package/dist/ColorPicker/index.js +1 -1
- package/dist/ColorPicker/index.js.map +1 -1
- package/dist/ColorPicker/index.scss +2 -1
- package/dist/DataTable/CollapsibleButtonGroup.js +2 -2
- package/dist/DataTable/CollapsibleButtonGroup.js.map +1 -1
- package/dist/DataTable/DropdownFilters.js +1 -1
- package/dist/DataTable/DropdownFilters.js.map +1 -1
- package/dist/DataTable/TableRow.js.map +1 -1
- package/dist/DataTable/filters/CheckboxFilter.js.map +1 -1
- package/dist/DataTable/filters/DropdownFilter.js.map +1 -1
- package/dist/DataTable/filters/MultiSelectDropdownFilter.js.map +1 -1
- package/dist/DataTable/filters/TextFilter.js.map +1 -1
- package/dist/DataTable/index.scss +14 -13
- package/dist/DataTable/utils/getVisibleColumns.js +1 -1
- package/dist/DataTable/utils/getVisibleColumns.js.map +1 -1
- package/dist/Dropdown/_variables.scss +2 -1
- package/dist/Dropdown/deprecated/DropdownMenu.js +15 -19
- package/dist/Dropdown/deprecated/DropdownMenu.js.map +1 -1
- package/dist/Dropdown/deprecated/index.js +1 -1
- package/dist/Dropdown/deprecated/index.js.map +1 -1
- package/dist/Dropdown/index.js.map +1 -1
- package/dist/Dropzone/DefaultContent.js.map +1 -1
- package/dist/Dropzone/UploadProgress.js.map +1 -1
- package/dist/Dropzone/index.scss +3 -2
- package/dist/Fieldset/index.js.map +1 -1
- package/dist/Form/FormAutosuggest.js +1 -1
- package/dist/Form/FormAutosuggest.js.map +1 -1
- package/dist/Form/FormControl.js.map +1 -1
- package/dist/Form/FormControlDecorator.js.map +1 -1
- package/dist/Form/FormGroupContext.d.ts +1 -1
- package/dist/Form/FormGroupContext.js.map +1 -1
- package/dist/Form/FormText.js.map +1 -1
- package/dist/Form/_index.scss +9 -7
- package/dist/Form/_variables.scss +4 -2
- package/dist/Form/fieldUtils.js.map +1 -1
- package/dist/Hyperlink/index.d.ts +10 -5
- package/dist/Hyperlink/index.js +57 -25
- package/dist/Hyperlink/index.js.map +1 -1
- package/dist/Hyperlink/index.scss +3 -1
- package/dist/Icon/index.js.map +1 -1
- package/dist/IconButton/index.d.ts +13 -8
- package/dist/IconButton/index.js.map +1 -1
- package/dist/IconButtonToggle/index.js.map +1 -1
- package/dist/IconButtonToggle/index.scss +3 -1
- package/dist/Input/index.js.map +1 -1
- package/dist/InputSelect/index.js.map +1 -1
- package/dist/Layout/index.js.map +1 -1
- package/dist/ListBox/index.js.map +1 -1
- package/dist/ListBoxOption/index.js.map +1 -1
- package/dist/Menu/SelectMenu.js +1 -1
- package/dist/Menu/SelectMenu.js.map +1 -1
- package/dist/Menu/index.js +1 -1
- package/dist/Menu/index.js.map +1 -1
- package/dist/Modal/ModalContext.d.ts +1 -1
- package/dist/Modal/ModalDialog.d.ts +1 -1
- package/dist/Modal/ModalDialog.js.map +1 -1
- package/dist/Modal/ModalDialogBody.js +1 -1
- package/dist/Modal/ModalDialogBody.js.map +1 -1
- package/dist/Modal/ModalDialogHeroBackground.js.map +1 -1
- package/dist/Modal/ModalLayer.d.ts +3 -3
- package/dist/Modal/ModalLayer.js.map +1 -1
- package/dist/Modal/ModalPopup.js.map +1 -1
- package/dist/Modal/_ModalDialog.scss +3 -1
- package/dist/Modal/index.js +3 -1
- package/dist/Modal/index.js.map +1 -1
- package/dist/Modal/index.scss +3 -5
- package/dist/Nav/_mixins.scss +3 -1
- package/dist/Overlay/index.d.ts +2 -2
- package/dist/PageBanner/index.js.map +1 -1
- package/dist/PageBanner/index.scss +2 -1
- package/dist/Pagination/PaginationContext.js.map +1 -1
- package/dist/Pagination/index.js.map +1 -1
- package/dist/Popover/_variables.scss +2 -1
- package/dist/Popover/index.js.map +1 -1
- package/dist/ProductTour/Checkpoint.scss +9 -8
- package/dist/ProductTour/index.js +1 -1
- package/dist/ProductTour/index.js.map +1 -1
- package/dist/ProgressBar/index.js.map +1 -1
- package/dist/Scrollable/index.js +1 -1
- package/dist/Scrollable/index.js.map +1 -1
- package/dist/SearchField/SearchFieldAdvanced.js.map +1 -1
- package/dist/SearchField/index.scss +2 -1
- package/dist/SelectableBox/SelectableBoxSet.js.map +1 -1
- package/dist/Sheet/index.js.map +1 -1
- package/dist/Stack/index.js.map +1 -1
- package/dist/StatefulButton/index.js.map +1 -1
- package/dist/StatusAlert/index.js.map +1 -1
- package/dist/Stepper/StepperHeader.js +1 -1
- package/dist/Stepper/StepperHeader.js.map +1 -1
- package/dist/Stepper/StepperHeaderStep.js.map +1 -1
- package/dist/Sticky/index.js.map +1 -1
- package/dist/Table/_variables.scss +2 -1
- package/dist/Tabs/deprecated/index.js.map +1 -1
- package/dist/Tabs/index.js +1 -1
- package/dist/Tabs/index.js.map +1 -1
- package/dist/Toast/ToastContainer.scss +1 -1
- package/dist/Toast/index.scss +2 -2
- package/dist/Truncate/index.js +1 -1
- package/dist/Truncate/index.js.map +1 -1
- package/dist/ValidationFormGroup/index.js.map +1 -1
- package/dist/asInput/index.js.map +1 -1
- package/dist/hooks/{useArrowKeyNavigation.js → useArrowKeyNavigationHook.js} +5 -1
- package/dist/hooks/useArrowKeyNavigationHook.js.map +1 -0
- package/dist/hooks/{useIndexOfLastVisibleChild.js → useIndexOfLastVisibleChildHook.js} +5 -1
- package/dist/hooks/useIndexOfLastVisibleChildHook.js.map +1 -0
- package/dist/hooks/{useIsVisible.js → useIsVisibleHook.js} +1 -1
- package/dist/hooks/useIsVisibleHook.js.map +1 -0
- package/dist/hooks/{useToggle.js → useToggleHook.js} +5 -1
- package/dist/hooks/useToggleHook.js.map +1 -0
- package/dist/hooks/{useWindowSize.js → useWindowSizeHook.js} +1 -1
- package/dist/hooks/useWindowSizeHook.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/paragon.css +1 -45
- package/dist/utils/newId.js.map +1 -1
- package/dist/withDeprecatedProps.js.map +1 -1
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/CHANGELOG.md +50 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/LICENSE +7 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/README.md +37 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/dist/index.d.ts +20 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/dist/index.js +79 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/dist/index.js.map +1 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/package.json +40 -0
- package/icons/node_modules/@svgr/babel-plugin-add-jsx-attribute/tsconfig.json +4 -0
- package/icons/package.json +1 -1
- package/package.json +12 -19
- package/scss/core/_exports.module.scss +7 -6
- package/scss/core/_functions.scss +9 -7
- package/scss/core/_typography.scss +2 -1
- package/scss/core/_utilities.scss +2 -1
- package/scss/core/_variables.scss +98 -95
- package/src/Alert/_variables.scss +2 -1
- package/src/Annotation/index.scss +6 -5
- package/src/Breadcrumb/Breadcrumb.test.jsx +3 -2
- package/src/Bubble/index.scss +3 -2
- package/src/Bubble/index.tsx +1 -0
- package/src/Button/Button.test.tsx +6 -1
- package/src/Button/deprecated/Button.test.jsx +6 -4
- package/src/Button/index.scss +19 -18
- package/src/Card/CardCarousel/tests/CardCarouselControls.test.jsx +6 -4
- package/src/Card/_variables.scss +3 -2
- package/src/Card/index.scss +10 -9
- package/src/Chip/index.tsx +1 -0
- package/src/Collapsible/Collapsible.test.jsx +15 -7
- package/src/ColorPicker/ColorPicker.test.jsx +9 -16
- package/src/ColorPicker/index.jsx +1 -1
- package/src/ColorPicker/index.scss +2 -1
- package/src/DataTable/CollapsibleButtonGroup.jsx +2 -2
- package/src/DataTable/DropdownFilters.jsx +1 -1
- package/src/DataTable/dataviews.mdx +1 -8
- package/src/DataTable/index.scss +14 -13
- package/src/DataTable/selection/tests/ControlledSelectHeader.test.jsx +6 -4
- package/src/DataTable/tests/BulkActions.test.jsx +2 -4
- package/src/DataTable/tests/DataViewToggle.test.jsx +3 -7
- package/src/DataTable/tests/DropdownFilters.test.jsx +1 -1
- package/src/DataTable/tests/TableActions.test.jsx +1 -1
- package/src/Dropdown/_variables.scss +2 -1
- package/src/Dropdown/deprecated/Dropdown.test.jsx +43 -27
- package/src/Dropzone/README.md +3 -3
- package/src/Dropzone/index.scss +3 -2
- package/src/Dropzone/tests/__snapshots__/Dropzone.test.jsx.snap +10 -1
- package/src/Form/FormAutosuggest.jsx +1 -1
- package/src/Form/FormGroupContext.tsx +1 -1
- package/src/Form/_index.scss +9 -7
- package/src/Form/_variables.scss +4 -2
- package/src/Form/tests/FormAutosuggest.test.jsx +76 -57
- package/src/Form/tests/FormCheckboxSet.test.jsx +3 -2
- package/src/Form/tests/FormControl.test.jsx +9 -6
- package/src/Form/tests/FormRadioSet.test.jsx +3 -2
- package/src/Hyperlink/Hyperlink.test.tsx +50 -20
- package/src/Hyperlink/README.md +14 -1
- package/src/Hyperlink/index.scss +3 -1
- package/src/Hyperlink/index.tsx +71 -30
- package/src/IconButtonToggle/IconButtonToggle.test.jsx +3 -2
- package/src/IconButtonToggle/index.scss +3 -1
- package/src/ListBox/ListBox.test.jsx +8 -4
- package/src/MailtoLink/MailtoLink.test.jsx +12 -3
- package/src/Menu/Menu.test.jsx +27 -19
- package/src/Menu/SelectMenu.jsx +1 -1
- package/src/Menu/SelectMenu.test.jsx +35 -16
- package/src/Menu/__snapshots__/Menu.test.jsx.snap +0 -1
- package/src/Menu/index.jsx +1 -1
- package/src/Modal/ModalDialogBody.jsx +1 -1
- package/src/Modal/_ModalDialog.scss +3 -1
- package/src/Modal/index.jsx +2 -0
- package/src/Modal/index.scss +3 -5
- package/src/Modal/tests/ModalLayer.test.tsx +3 -2
- package/src/Nav/_mixins.scss +3 -1
- package/src/OverflowScroll/data/tests/useOverflowScroll.test.jsx +1 -2
- package/src/OverflowScroll/data/tests/useOverflowScrollActions.test.jsx +1 -1
- package/src/OverflowScroll/data/tests/useOverflowScrollElementAttributes.test.jsx +1 -1
- package/src/OverflowScroll/data/tests/useOverflowScrollEventListeners.test.jsx +1 -2
- package/src/PageBanner/index.scss +2 -1
- package/src/Pagination/Pagination.test.jsx +36 -28
- package/src/Popover/_variables.scss +2 -1
- package/src/ProductTour/Checkpoint.scss +9 -8
- package/src/ProductTour/Checkpoint.test.jsx +3 -2
- package/src/ProductTour/ProductTour.test.jsx +11 -24
- package/src/ProductTour/index.jsx +1 -1
- package/src/Scrollable/Scrollable.test.jsx +2 -2
- package/src/Scrollable/index.jsx +1 -1
- package/src/SearchField/index.scss +2 -1
- package/src/SelectableBox/tests/SelectableBox.test.jsx +3 -2
- package/src/StatusAlert/StatusAlert.test.jsx +6 -2
- package/src/Stepper/StepperHeader.jsx +1 -1
- package/src/Stepper/tests/Stepper.test.jsx +1 -1
- package/src/Table/_variables.scss +2 -1
- package/src/Tabs/Tabs.test.jsx +1 -1
- package/src/Tabs/deprecated/Tabs.test.jsx +6 -4
- package/src/Tabs/index.jsx +1 -1
- package/src/Toast/ToastContainer.scss +1 -1
- package/src/Toast/index.scss +2 -2
- package/src/Truncate/index.jsx +1 -1
- package/src/hooks/tests/useToggle.test.tsx +1 -1
- package/src/hooks/{useArrowKeyNavigation.tsx → useArrowKeyNavigationHook.tsx} +4 -0
- package/src/hooks/{useIndexOfLastVisibleChild.tsx → useIndexOfLastVisibleChildHook.tsx} +4 -0
- package/src/hooks/{useToggle.tsx → useToggleHook.tsx} +4 -0
- package/src/index.d.ts +6 -6
- package/src/index.js +6 -6
- package/dist/hooks/useArrowKeyNavigation.js.map +0 -1
- package/dist/hooks/useIndexOfLastVisibleChild.js.map +0 -1
- package/dist/hooks/useIsVisible.js.map +0 -1
- package/dist/hooks/useToggle.js.map +0 -1
- package/dist/hooks/useWindowSize.js.map +0 -1
- package/src/DataTable/tests/utils.js +0 -9
- /package/dist/hooks/{useArrowKeyNavigation.d.ts → useArrowKeyNavigationHook.d.ts} +0 -0
- /package/dist/hooks/{useIndexOfLastVisibleChild.d.ts → useIndexOfLastVisibleChildHook.d.ts} +0 -0
- /package/dist/hooks/{useIsVisible.d.ts → useIsVisibleHook.d.ts} +0 -0
- /package/dist/hooks/{useToggle.d.ts → useToggleHook.d.ts} +0 -0
- /package/dist/hooks/{useWindowSize.d.ts → useWindowSizeHook.d.ts} +0 -0
- /package/src/hooks/{useIsVisible.tsx → useIsVisibleHook.tsx} +0 -0
- /package/src/hooks/{useWindowSize.tsx → useWindowSizeHook.tsx} +0 -0
package/src/Form/_index.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
@use "sass:string";
|
|
1
3
|
@import "variables";
|
|
2
4
|
@import "~bootstrap/scss/forms";
|
|
3
5
|
@import "~bootstrap/scss/input-group";
|
|
@@ -60,7 +62,7 @@ $select-icon-padding: .5625rem !default;
|
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
@media (min-width: map
|
|
65
|
+
@media (min-width: map.get($grid-breakpoints, "sm")) {
|
|
64
66
|
margin-inline-end: $custom-control-gutter;
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -306,7 +308,7 @@ $select-icon-padding: .5625rem !default;
|
|
|
306
308
|
text-align: right;
|
|
307
309
|
}
|
|
308
310
|
|
|
309
|
-
&:not(:focus
|
|
311
|
+
&:not(:focus, .has-value) {
|
|
310
312
|
color: transparent;
|
|
311
313
|
}
|
|
312
314
|
|
|
@@ -318,17 +320,17 @@ $select-icon-padding: .5625rem !default;
|
|
|
318
320
|
}
|
|
319
321
|
}
|
|
320
322
|
|
|
321
|
-
.form-control:not(:focus
|
|
323
|
+
.form-control:not(:focus, .has-value) {
|
|
322
324
|
&::placeholder,
|
|
323
325
|
&::-webkit-datetime-edit {
|
|
324
326
|
opacity: 0;
|
|
325
327
|
}
|
|
326
328
|
}
|
|
327
329
|
|
|
328
|
-
select.form-control:not(.has-value
|
|
330
|
+
select.form-control:not(.has-value, :focus) {
|
|
329
331
|
// color: rgba(0,0,0,0); Force the rgba syntax to appear in the output rather
|
|
330
332
|
// than transparent. IE11 does not understand color: transparent here.
|
|
331
|
-
color: unquote("rgba(0,0,0,0)");
|
|
333
|
+
color: string.unquote("rgba(0,0,0,0)");
|
|
332
334
|
}
|
|
333
335
|
}
|
|
334
336
|
|
|
@@ -545,7 +547,7 @@ select.form-control {
|
|
|
545
547
|
.input-group:not(.has-validation) > .input-group-append:not(:last-child) > .input-group-text,
|
|
546
548
|
.input-group.has-validation > .input-group-append:nth-last-child(n+3) > .btn,
|
|
547
549
|
.input-group.has-validation > .input-group-append:nth-last-child(n+3) > .input-group-text,
|
|
548
|
-
.input-group > .input-group-append:last-child > .btn:not(:last-child
|
|
550
|
+
.input-group > .input-group-append:last-child > .btn:not(:last-child, .dropdown-toggle),
|
|
549
551
|
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {
|
|
550
552
|
[dir="rtl"] & {
|
|
551
553
|
border-radius: 0 $input-border-radius $input-border-radius 0;
|
|
@@ -588,7 +590,7 @@ select.form-control {
|
|
|
588
590
|
.pgn__form-autosuggest__dropdown {
|
|
589
591
|
@include pgn-box-shadow(1, "centered");
|
|
590
592
|
|
|
591
|
-
@media (min-width: map
|
|
593
|
+
@media (min-width: map.get($grid-breakpoints, "sm")) {
|
|
592
594
|
margin-inline-end: $custom-control-gutter;
|
|
593
595
|
}
|
|
594
596
|
|
package/src/Form/_variables.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "sass:color";
|
|
2
|
+
@use "sass:map";
|
|
1
3
|
$input-padding-y: $input-btn-padding-y !default;
|
|
2
4
|
$input-padding-x: $input-btn-padding-x !default;
|
|
3
5
|
$input-font-family: $input-btn-font-family !default;
|
|
@@ -198,7 +200,7 @@ $custom-range-thumb-border-radius: 1rem !default;
|
|
|
198
200
|
$custom-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;
|
|
199
201
|
$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;
|
|
200
202
|
$custom-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge
|
|
201
|
-
$custom-range-thumb-active-bg:
|
|
203
|
+
$custom-range-thumb-active-bg: color.adjust($component-active-bg, $lightness: 35%) !default;
|
|
202
204
|
$custom-range-thumb-disabled-bg: theme-color("gray", "default") !default;
|
|
203
205
|
|
|
204
206
|
$custom-file-height: $input-height !default;
|
|
@@ -238,7 +240,7 @@ $form-feedback-icon-invalid: str-replace(url("data:image/svg+xml,%3csvg x
|
|
|
238
240
|
|
|
239
241
|
$form-validation-states: () !default;
|
|
240
242
|
// stylelint-disable-next-line scss/dollar-variable-default
|
|
241
|
-
$form-validation-states: map
|
|
243
|
+
$form-validation-states: map.merge(
|
|
242
244
|
(
|
|
243
245
|
"valid": (
|
|
244
246
|
"color": $form-feedback-valid-color,
|
|
@@ -89,59 +89,64 @@ describe('render behavior', () => {
|
|
|
89
89
|
expect(screen.getByDisplayValue('Test Value')).toBeInTheDocument();
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
-
it('renders component with options', () => {
|
|
92
|
+
it('renders component with options', async () => {
|
|
93
|
+
const user = userEvent.setup();
|
|
93
94
|
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
94
95
|
const input = getByTestId('autosuggest-textbox-input');
|
|
95
|
-
|
|
96
|
+
await user.click(input);
|
|
96
97
|
const list = queryAllByTestId('autosuggest-optionitem');
|
|
97
98
|
expect(list.length).toBe(3);
|
|
98
99
|
});
|
|
99
100
|
|
|
100
|
-
it('renders with value required error msg', () => {
|
|
101
|
+
it('renders with value required error msg', async () => {
|
|
102
|
+
const user = userEvent.setup();
|
|
101
103
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent isValueRequired />);
|
|
102
104
|
const input = getByTestId('autosuggest-textbox-input');
|
|
103
105
|
|
|
104
106
|
// if you click into the input and click outside, you should see the error message
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
await user.click(input);
|
|
108
|
+
await user.click(document.body);
|
|
107
109
|
|
|
108
110
|
const formControlFeedback = getByText('Example value required error message');
|
|
109
111
|
|
|
110
112
|
expect(formControlFeedback).toBeInTheDocument();
|
|
111
113
|
});
|
|
112
114
|
|
|
113
|
-
it('renders with selection required error msg', () => {
|
|
115
|
+
it('renders with selection required error msg', async () => {
|
|
116
|
+
const user = userEvent.setup();
|
|
114
117
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent isSelectionRequired />);
|
|
115
118
|
const input = getByTestId('autosuggest-textbox-input');
|
|
116
119
|
|
|
117
120
|
// if you click into the input and click outside, you should see the error message
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
await user.click(input);
|
|
122
|
+
await user.type(input, '1');
|
|
123
|
+
await user.click(document.body);
|
|
121
124
|
|
|
122
125
|
const formControlFeedback = getByText('Example selection required error message');
|
|
123
126
|
|
|
124
127
|
expect(formControlFeedback).toBeInTheDocument();
|
|
125
128
|
});
|
|
126
129
|
|
|
127
|
-
it('renders with custom error msg', () => {
|
|
130
|
+
it('renders with custom error msg', async () => {
|
|
131
|
+
const user = userEvent.setup();
|
|
128
132
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent hasCustomError />);
|
|
129
133
|
const input = getByTestId('autosuggest-textbox-input');
|
|
130
134
|
|
|
131
135
|
// if you click into the input and click outside, you should see the error message
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
await user.click(input);
|
|
137
|
+
await user.click(document.body);
|
|
134
138
|
|
|
135
139
|
const formControlFeedback = getByText('Example custom error message');
|
|
136
140
|
|
|
137
141
|
expect(formControlFeedback).toBeInTheDocument();
|
|
138
142
|
});
|
|
139
143
|
|
|
140
|
-
it('renders component with options that all have IDs', () => {
|
|
144
|
+
it('renders component with options that all have IDs', async () => {
|
|
145
|
+
const user = userEvent.setup();
|
|
141
146
|
const { getByTestId, getAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
142
147
|
const input = getByTestId('autosuggest-textbox-input');
|
|
143
148
|
|
|
144
|
-
|
|
149
|
+
await user.click(input);
|
|
145
150
|
const optionItemIds = getAllByTestId('autosuggest-optionitem').map(item => item.id);
|
|
146
151
|
|
|
147
152
|
expect(optionItemIds).not.toContain(null);
|
|
@@ -154,12 +159,13 @@ describe('render behavior', () => {
|
|
|
154
159
|
expect(getByTestId('autosuggest-screen-reader-options-count').getAttribute('aria-live')).toEqual('assertive');
|
|
155
160
|
});
|
|
156
161
|
|
|
157
|
-
it('displays correct amount of options found to screen readers', () => {
|
|
162
|
+
it('displays correct amount of options found to screen readers', async () => {
|
|
163
|
+
const user = userEvent.setup();
|
|
158
164
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent />);
|
|
159
165
|
const input = getByTestId('autosuggest-textbox-input');
|
|
160
166
|
|
|
161
167
|
expect(getByText('0 options found')).toBeInTheDocument();
|
|
162
|
-
|
|
168
|
+
await user.click(input);
|
|
163
169
|
|
|
164
170
|
expect(getByText('3 options found')).toBeInTheDocument();
|
|
165
171
|
});
|
|
@@ -172,167 +178,180 @@ describe('render behavior', () => {
|
|
|
172
178
|
});
|
|
173
179
|
|
|
174
180
|
describe('controlled behavior', () => {
|
|
175
|
-
it('sets input value based on clicked option', () => {
|
|
181
|
+
it('sets input value based on clicked option', async () => {
|
|
182
|
+
const user = userEvent.setup();
|
|
176
183
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent />);
|
|
177
184
|
const input = getByTestId('autosuggest-textbox-input');
|
|
178
185
|
|
|
179
|
-
|
|
186
|
+
await user.click(input);
|
|
180
187
|
const menuItem = getByText('Option 1');
|
|
181
|
-
|
|
188
|
+
await user.click(menuItem);
|
|
182
189
|
|
|
183
190
|
expect(input.value).toEqual('Option 1');
|
|
184
191
|
});
|
|
185
192
|
|
|
186
|
-
it('calls onChange based on clicked option', () => {
|
|
193
|
+
it('calls onChange based on clicked option', async () => {
|
|
194
|
+
const user = userEvent.setup();
|
|
187
195
|
const onChange = jest.fn();
|
|
188
196
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent onChange={onChange} />);
|
|
189
197
|
const input = getByTestId('autosuggest-textbox-input');
|
|
190
198
|
|
|
191
|
-
|
|
199
|
+
await user.click(input);
|
|
192
200
|
const menuItem = getByText('Option 1');
|
|
193
|
-
|
|
201
|
+
await user.click(menuItem);
|
|
194
202
|
|
|
195
203
|
expect(onChange).toHaveBeenCalledWith({ selectionId: 'option-1-id', selectionValue: 'Option 1', userProvidedText: 'Option 1' });
|
|
196
204
|
expect(onChange).toHaveBeenCalledTimes(1);
|
|
197
205
|
});
|
|
198
206
|
|
|
199
|
-
it('calls onChange when the textbox is cleared', () => {
|
|
207
|
+
it('calls onChange when the textbox is cleared', async () => {
|
|
208
|
+
const user = userEvent.setup();
|
|
200
209
|
const onChange = jest.fn();
|
|
201
210
|
const { getByTestId } = render(<FormAutosuggestTestComponent onChange={onChange} />);
|
|
202
211
|
const input = getByTestId('autosuggest-textbox-input');
|
|
203
212
|
|
|
204
|
-
|
|
205
|
-
|
|
213
|
+
await user.type(input, '1');
|
|
214
|
+
await user.type(input, '{backspace}');
|
|
206
215
|
|
|
207
216
|
expect(onChange).toHaveBeenCalledWith({ selectionId: '', selectionValue: '', userProvidedText: '' });
|
|
208
217
|
});
|
|
209
218
|
|
|
210
|
-
it('calls the function passed to onClick when an option with it is selected', () => {
|
|
219
|
+
it('calls the function passed to onClick when an option with it is selected', async () => {
|
|
220
|
+
const user = userEvent.setup();
|
|
211
221
|
const onClick = jest.fn();
|
|
212
222
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent onClick={onClick} />);
|
|
213
223
|
const input = getByTestId('autosuggest-textbox-input');
|
|
214
224
|
|
|
215
|
-
|
|
225
|
+
await user.click(input);
|
|
216
226
|
const menuItem = getByText('Option 2');
|
|
217
|
-
|
|
227
|
+
await user.click(menuItem);
|
|
218
228
|
|
|
219
229
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
220
230
|
});
|
|
221
231
|
|
|
222
|
-
it('does not call onClick when an option without it is selected', () => {
|
|
232
|
+
it('does not call onClick when an option without it is selected', async () => {
|
|
233
|
+
const user = userEvent.setup();
|
|
223
234
|
const onClick = jest.fn();
|
|
224
235
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent onClick={onClick} />);
|
|
225
236
|
const input = getByTestId('autosuggest-textbox-input');
|
|
226
237
|
|
|
227
|
-
|
|
238
|
+
await user.click(input);
|
|
228
239
|
const menuItem = getByText('Option 1');
|
|
229
|
-
|
|
240
|
+
await user.click(menuItem);
|
|
230
241
|
|
|
231
242
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
232
243
|
});
|
|
233
244
|
|
|
234
|
-
it('should set the correct activedescendant', () => {
|
|
245
|
+
it('should set the correct activedescendant', async () => {
|
|
246
|
+
const user = userEvent.setup();
|
|
235
247
|
const { getByTestId, getAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
236
248
|
const input = getByTestId('autosuggest-textbox-input');
|
|
237
249
|
|
|
238
|
-
|
|
250
|
+
await user.click(input);
|
|
239
251
|
const expectedOptionId = getAllByTestId('autosuggest-optionitem')[0].id;
|
|
240
|
-
|
|
252
|
+
await user.keyboard('{arrowdown}');
|
|
241
253
|
|
|
242
254
|
expect(input.getAttribute('aria-activedescendant')).toEqual(expectedOptionId);
|
|
243
255
|
});
|
|
244
256
|
|
|
245
|
-
it('filters dropdown based on typed field value with one match', () => {
|
|
257
|
+
it('filters dropdown based on typed field value with one match', async () => {
|
|
258
|
+
const user = userEvent.setup();
|
|
246
259
|
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
247
260
|
const input = getByTestId('autosuggest-textbox-input');
|
|
248
261
|
|
|
249
|
-
|
|
250
|
-
|
|
262
|
+
await user.click(input);
|
|
263
|
+
await user.type(input, 'Option 1');
|
|
251
264
|
|
|
252
265
|
const list = queryAllByTestId('autosuggest-optionitem');
|
|
253
266
|
expect(list.length).toBe(1);
|
|
254
267
|
});
|
|
255
268
|
|
|
256
|
-
it('toggles options list', () => {
|
|
269
|
+
it('toggles options list', async () => {
|
|
270
|
+
const user = userEvent.setup();
|
|
257
271
|
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
258
272
|
const dropdownBtn = getByTestId('autosuggest-iconbutton');
|
|
259
273
|
|
|
260
|
-
|
|
274
|
+
await user.click(dropdownBtn);
|
|
261
275
|
const list = queryAllByTestId('autosuggest-optionitem');
|
|
262
276
|
expect(list.length).toBe(3);
|
|
263
277
|
|
|
264
|
-
|
|
278
|
+
await user.click(dropdownBtn);
|
|
265
279
|
const updatedList = queryAllByTestId('autosuggest-optionitem');
|
|
266
280
|
expect(updatedList.length).toBe(0);
|
|
267
281
|
|
|
268
|
-
|
|
282
|
+
await user.click(dropdownBtn);
|
|
269
283
|
const reopenedList = queryAllByTestId('autosuggest-optionitem');
|
|
270
284
|
expect(reopenedList.length).toBe(3);
|
|
271
285
|
});
|
|
272
286
|
|
|
273
|
-
it('filters dropdown based on typed field value with multiple matches', () => {
|
|
287
|
+
it('filters dropdown based on typed field value with multiple matches', async () => {
|
|
288
|
+
const user = userEvent.setup();
|
|
274
289
|
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
275
290
|
const input = getByTestId('autosuggest-textbox-input');
|
|
276
291
|
|
|
277
|
-
|
|
278
|
-
|
|
292
|
+
await user.click(input);
|
|
293
|
+
await user.type(input, '1');
|
|
279
294
|
|
|
280
295
|
const list = queryAllByTestId('autosuggest-optionitem');
|
|
281
296
|
expect(list.length).toBe(2);
|
|
282
297
|
});
|
|
283
298
|
|
|
284
|
-
it('closes options list on click outside', () => {
|
|
299
|
+
it('closes options list on click outside', async () => {
|
|
300
|
+
const user = userEvent.setup();
|
|
285
301
|
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
286
302
|
const input = getByTestId('autosuggest-textbox-input');
|
|
287
303
|
|
|
288
|
-
|
|
304
|
+
await user.click(input);
|
|
289
305
|
const list = queryAllByTestId('autosuggest-optionitem');
|
|
290
306
|
expect(list.length).toBe(3);
|
|
291
307
|
|
|
292
|
-
|
|
308
|
+
await user.click(document.body);
|
|
293
309
|
const updatedList = queryAllByTestId('autosuggest-optionitem');
|
|
294
310
|
expect(updatedList.length).toBe(0);
|
|
295
311
|
});
|
|
296
312
|
|
|
297
|
-
it('updates screen reader option count based on typed field value with multiple matches', () => {
|
|
313
|
+
it('updates screen reader option count based on typed field value with multiple matches', async () => {
|
|
314
|
+
const user = userEvent.setup();
|
|
298
315
|
const { getByText, getByTestId } = render(<FormAutosuggestTestComponent />);
|
|
299
316
|
const input = getByTestId('autosuggest-textbox-input');
|
|
300
317
|
|
|
301
318
|
expect(getByText('0 options found')).toBeInTheDocument();
|
|
302
|
-
|
|
319
|
+
await user.click(input);
|
|
303
320
|
|
|
304
321
|
expect(getByText('3 options found')).toBeInTheDocument();
|
|
305
322
|
|
|
306
|
-
|
|
307
|
-
|
|
323
|
+
await user.click(input);
|
|
324
|
+
await user.type(input, '1');
|
|
308
325
|
|
|
309
326
|
expect(getByText('2 options found')).toBeInTheDocument();
|
|
310
327
|
});
|
|
311
328
|
|
|
312
|
-
it('closes options list when tabbed out and the input is no longer active', () => {
|
|
329
|
+
it('closes options list when tabbed out and the input is no longer active', async () => {
|
|
330
|
+
const user = userEvent.setup();
|
|
313
331
|
const { getByTestId, queryAllByTestId } = render(<FormAutosuggestTestComponent />);
|
|
314
332
|
const input = getByTestId('autosuggest-textbox-input');
|
|
315
333
|
|
|
316
|
-
|
|
334
|
+
await user.click(input);
|
|
317
335
|
expect(document.activeElement).toBe(getByTestId('autosuggest-textbox-input'));
|
|
318
336
|
|
|
319
337
|
const list = queryAllByTestId('autosuggest-optionitem');
|
|
320
338
|
expect(list.length).toBe(3);
|
|
321
339
|
|
|
322
|
-
|
|
340
|
+
await user.tab();
|
|
323
341
|
expect(document.activeElement).not.toBe(getByTestId('autosuggest-textbox-input'));
|
|
324
342
|
|
|
325
343
|
const updatedList = queryAllByTestId('autosuggest-optionitem');
|
|
326
344
|
expect(updatedList.length).toBe(0);
|
|
327
345
|
});
|
|
328
346
|
|
|
329
|
-
it('check focus on input after esc', () => {
|
|
347
|
+
it('check focus on input after esc', async () => {
|
|
348
|
+
const user = userEvent.setup();
|
|
330
349
|
const { getByTestId } = render(<FormAutosuggestTestComponent />);
|
|
331
350
|
const input = getByTestId('autosuggest-textbox-input');
|
|
332
351
|
const dropdownBtn = getByTestId('autosuggest-iconbutton');
|
|
333
|
-
|
|
352
|
+
await user.click(dropdownBtn);
|
|
334
353
|
|
|
335
|
-
|
|
354
|
+
await user.keyboard('{Escape}');
|
|
336
355
|
|
|
337
356
|
expect(input.matches(':focus')).toBe(true);
|
|
338
357
|
});
|
|
@@ -166,7 +166,8 @@ describe('FormCheckboxSet', () => {
|
|
|
166
166
|
});
|
|
167
167
|
});
|
|
168
168
|
|
|
169
|
-
it('checks if onClick is called once in FormCheckboxSet', () => {
|
|
169
|
+
it('checks if onClick is called once in FormCheckboxSet', async () => {
|
|
170
|
+
const user = userEvent.setup();
|
|
170
171
|
const handleChange = jest.fn();
|
|
171
172
|
const { getByLabelText } = render(
|
|
172
173
|
<FormGroup controlId="my-field">
|
|
@@ -181,7 +182,7 @@ describe('FormCheckboxSet', () => {
|
|
|
181
182
|
</FormGroup>,
|
|
182
183
|
);
|
|
183
184
|
|
|
184
|
-
|
|
185
|
+
await user.click(getByLabelText('Red'));
|
|
185
186
|
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
186
187
|
});
|
|
187
188
|
});
|
|
@@ -28,7 +28,8 @@ function Component({ isClearValue }) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
describe('FormControl', () => {
|
|
31
|
-
it('textarea changes its height with autoResize prop', () => {
|
|
31
|
+
it('textarea changes its height with autoResize prop', async () => {
|
|
32
|
+
const user = userEvent.setup();
|
|
32
33
|
const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref);
|
|
33
34
|
const onChangeFunc = jest.fn();
|
|
34
35
|
const inputText = 'new text';
|
|
@@ -45,25 +46,27 @@ describe('FormControl', () => {
|
|
|
45
46
|
expect(useReferenceSpy).toHaveBeenCalledTimes(1);
|
|
46
47
|
expect(ref.current.style.height).toBe('0px');
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
await user.type(textarea, inputText);
|
|
49
50
|
|
|
50
51
|
expect(onChangeFunc).toHaveBeenCalledTimes(inputText.length);
|
|
51
52
|
expect(ref.current.style.height).toEqual(`${ref.current.scrollHeight + ref.current.offsetHeight}px`);
|
|
52
53
|
});
|
|
53
54
|
|
|
54
|
-
it('should apply and accept input mask for phone numbers', () => {
|
|
55
|
+
it('should apply and accept input mask for phone numbers', async () => {
|
|
56
|
+
const user = userEvent.setup();
|
|
55
57
|
render(<Component />);
|
|
56
58
|
|
|
57
59
|
const input = screen.getByTestId('form-control-with-mask');
|
|
58
|
-
|
|
60
|
+
await user.type(input, '5555555555');
|
|
59
61
|
expect(input.value).toBe('+1 (555) 555-5555');
|
|
60
62
|
});
|
|
61
63
|
|
|
62
|
-
it('should be cleared from the mask elements value', () => {
|
|
64
|
+
it('should be cleared from the mask elements value', async () => {
|
|
65
|
+
const user = userEvent.setup();
|
|
63
66
|
render(<Component isClearValue />);
|
|
64
67
|
|
|
65
68
|
const input = screen.getByTestId('form-control-with-mask');
|
|
66
|
-
|
|
69
|
+
await user.type(input, '5555555555');
|
|
67
70
|
|
|
68
71
|
expect(input.value).toBe('+1 (555) 555-5555');
|
|
69
72
|
expect(unmaskedInputValue).toBe('15555555555');
|
|
@@ -109,7 +109,8 @@ describe('FormRadioSet', () => {
|
|
|
109
109
|
expect(deciduousRadio).toHaveAttribute('name', 'trees');
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
it('checks if onClick is called once in FormRadioSet', () => {
|
|
112
|
+
it('checks if onClick is called once in FormRadioSet', async () => {
|
|
113
|
+
const user = userEvent.setup();
|
|
113
114
|
const handleChange = jest.fn();
|
|
114
115
|
const { getByLabelText } = render(
|
|
115
116
|
<FormGroup>
|
|
@@ -124,7 +125,7 @@ describe('FormRadioSet', () => {
|
|
|
124
125
|
</FormGroup>,
|
|
125
126
|
);
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
await user.click(getByLabelText('Red'));
|
|
128
129
|
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
129
130
|
});
|
|
130
131
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { IntlProvider } from 'react-intl';
|
|
2
2
|
import { render } from '@testing-library/react';
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
4
|
|
|
5
|
-
import Hyperlink from '.';
|
|
5
|
+
import Hyperlink, { HyperlinkProps } from '.';
|
|
6
6
|
|
|
7
|
-
const destination = 'destination';
|
|
7
|
+
const destination = 'http://destination.example';
|
|
8
8
|
const content = 'content';
|
|
9
|
-
const onClick = jest.fn();
|
|
9
|
+
const onClick = jest.fn().mockImplementation((e) => e.preventDefault());
|
|
10
10
|
const props = {
|
|
11
11
|
destination,
|
|
12
12
|
onClick,
|
|
@@ -20,13 +20,37 @@ const externalLinkProps = {
|
|
|
20
20
|
...props,
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
interface LinkProps extends HyperlinkProps {
|
|
24
|
+
to: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function Link({ to, children, ...rest }: LinkProps) {
|
|
28
|
+
return (
|
|
29
|
+
<a
|
|
30
|
+
data-testid="custom-hyperlink-element"
|
|
31
|
+
href={to}
|
|
32
|
+
{...rest}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</a>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function HyperlinkWrapper({ children, ...rest }: HyperlinkProps) {
|
|
40
|
+
return (
|
|
41
|
+
<IntlProvider locale="en">
|
|
42
|
+
<Hyperlink {...rest}>{children}</Hyperlink>
|
|
43
|
+
</IntlProvider>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
23
47
|
describe('correct rendering', () => {
|
|
24
48
|
beforeEach(() => {
|
|
25
|
-
|
|
49
|
+
jest.clearAllMocks();
|
|
26
50
|
});
|
|
27
51
|
|
|
28
52
|
it('renders Hyperlink', async () => {
|
|
29
|
-
const { getByRole } = render(<
|
|
53
|
+
const { getByRole } = render(<HyperlinkWrapper {...props}>{content}</HyperlinkWrapper>);
|
|
30
54
|
const wrapper = getByRole('link');
|
|
31
55
|
expect(wrapper).toBeInTheDocument();
|
|
32
56
|
|
|
@@ -36,12 +60,29 @@ describe('correct rendering', () => {
|
|
|
36
60
|
expect(wrapper).toHaveAttribute('href', destination);
|
|
37
61
|
expect(wrapper).toHaveAttribute('target', '_self');
|
|
38
62
|
|
|
63
|
+
// Clicking on the link should call the onClick handler
|
|
39
64
|
await userEvent.click(wrapper);
|
|
40
65
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
41
66
|
});
|
|
42
67
|
|
|
68
|
+
it('renders with custom element type via "as" prop', () => {
|
|
69
|
+
const propsWithoutDestination = {
|
|
70
|
+
to: destination, // `to` simulates common `Link` components' prop
|
|
71
|
+
};
|
|
72
|
+
const { getByRole } = render(<HyperlinkWrapper as={Link} {...propsWithoutDestination}>{content}</HyperlinkWrapper>);
|
|
73
|
+
const wrapper = getByRole('link');
|
|
74
|
+
expect(wrapper).toBeInTheDocument();
|
|
75
|
+
|
|
76
|
+
expect(wrapper).toHaveClass('pgn__hyperlink');
|
|
77
|
+
expect(wrapper).toHaveClass('standalone-link');
|
|
78
|
+
expect(wrapper).toHaveTextContent(content);
|
|
79
|
+
expect(wrapper).toHaveAttribute('href', destination);
|
|
80
|
+
expect(wrapper).toHaveAttribute('target', '_self');
|
|
81
|
+
expect(wrapper).toHaveAttribute('data-testid', 'custom-hyperlink-element');
|
|
82
|
+
});
|
|
83
|
+
|
|
43
84
|
it('renders an underlined Hyperlink', async () => {
|
|
44
|
-
const { getByRole } = render(<
|
|
85
|
+
const { getByRole } = render(<HyperlinkWrapper isInline {...props}>{content}</HyperlinkWrapper>);
|
|
45
86
|
const wrapper = getByRole('link');
|
|
46
87
|
expect(wrapper).toBeInTheDocument();
|
|
47
88
|
expect(wrapper).toHaveClass('pgn__hyperlink');
|
|
@@ -50,7 +91,7 @@ describe('correct rendering', () => {
|
|
|
50
91
|
});
|
|
51
92
|
|
|
52
93
|
it('renders external Hyperlink', () => {
|
|
53
|
-
const { getByRole, getByTestId } = render(<
|
|
94
|
+
const { getByRole, getByTestId } = render(<HyperlinkWrapper {...externalLinkProps}>{content}</HyperlinkWrapper>);
|
|
54
95
|
const wrapper = getByRole('link');
|
|
55
96
|
const icon = getByTestId('hyperlink-icon');
|
|
56
97
|
const iconSvg = icon.querySelector('svg');
|
|
@@ -66,19 +107,8 @@ describe('correct rendering', () => {
|
|
|
66
107
|
|
|
67
108
|
describe('security', () => {
|
|
68
109
|
it('prevents reverse tabnabbing for links with target="_blank"', () => {
|
|
69
|
-
const { getByRole } = render(<
|
|
110
|
+
const { getByRole } = render(<HyperlinkWrapper {...externalLinkProps}>{content}</HyperlinkWrapper>);
|
|
70
111
|
const wrapper = getByRole('link');
|
|
71
112
|
expect(wrapper).toHaveAttribute('rel', 'noopener noreferrer');
|
|
72
113
|
});
|
|
73
114
|
});
|
|
74
|
-
|
|
75
|
-
describe('event handlers are triggered correctly', () => {
|
|
76
|
-
it('should fire onClick', async () => {
|
|
77
|
-
const spy = jest.fn();
|
|
78
|
-
const { getByRole } = render(<Hyperlink {...props} onClick={spy}>{content}</Hyperlink>);
|
|
79
|
-
const wrapper = getByRole('link');
|
|
80
|
-
expect(spy).toHaveBeenCalledTimes(0);
|
|
81
|
-
await userEvent.click(wrapper);
|
|
82
|
-
expect(spy).toHaveBeenCalledTimes(1);
|
|
83
|
-
});
|
|
84
|
-
});
|
package/src/Hyperlink/README.md
CHANGED
|
@@ -7,7 +7,7 @@ categories:
|
|
|
7
7
|
- Buttonlike
|
|
8
8
|
status: 'Needs Work'
|
|
9
9
|
designStatus: 'Done'
|
|
10
|
-
devStatus: '
|
|
10
|
+
devStatus: 'Done'
|
|
11
11
|
notes: |
|
|
12
12
|
Improve prop naming. Deprecate content prop.
|
|
13
13
|
Use React.forwardRef for ref forwarding.
|
|
@@ -100,3 +100,16 @@ notes: |
|
|
|
100
100
|
</div>
|
|
101
101
|
</div>
|
|
102
102
|
```
|
|
103
|
+
|
|
104
|
+
## with custom link element (e.g., using a router)
|
|
105
|
+
|
|
106
|
+
``Hyperlink`` typically relies on the standard HTML anchor tag (i.e., ``a``); however, this behavior may be overriden when the destination link is to an internal route where it should be using routing instead (e.g., ``Link`` from React Router).
|
|
107
|
+
|
|
108
|
+
```jsx live
|
|
109
|
+
<Hyperlink
|
|
110
|
+
as={GatsbyLink}
|
|
111
|
+
to="/components/button"
|
|
112
|
+
>
|
|
113
|
+
Button
|
|
114
|
+
</Hyperlink>
|
|
115
|
+
```
|
package/src/Hyperlink/index.scss
CHANGED