@codecademy/gamut 67.6.5-alpha.e8ee42.0 → 67.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/ConnectedForm/ConnectedFormGroup.d.ts +2 -8
  2. package/dist/ConnectedForm/ConnectedFormGroup.js +1 -1
  3. package/dist/ConnectedForm/ConnectedInputs/ConnectedCheckbox.js +0 -2
  4. package/dist/Form/elements/FormGroupLabel.d.ts +2 -2
  5. package/dist/Form/elements/FormGroupLabel.js +3 -10
  6. package/dist/Form/inputs/Checkbox.d.ts +0 -7
  7. package/dist/Form/inputs/Checkbox.js +11 -27
  8. package/dist/Form/inputs/Radio.d.ts +5 -9
  9. package/dist/Form/inputs/Radio.js +10 -13
  10. package/dist/Form/styles/Radio-styles.d.ts +3 -0
  11. package/dist/Form/styles/Radio-styles.js +6 -0
  12. package/dist/Form/styles/shared-system-props.d.ts +0 -7
  13. package/dist/Form/styles/shared-system-props.js +0 -11
  14. package/dist/GridForm/GridFormInputGroup/GridFormRadioGroupInput/index.js +0 -2
  15. package/dist/GridForm/GridFormInputGroup/__fixtures__/renderers.d.ts +0 -4
  16. package/dist/GridForm/types.d.ts +2 -7
  17. package/dist/Tip/InfoTip/InfoTipButton.js +2 -5
  18. package/dist/Tip/InfoTip/elements.d.ts +12 -0
  19. package/dist/Tip/InfoTip/elements.js +9 -0
  20. package/dist/Tip/InfoTip/index.d.ts +2 -39
  21. package/dist/Tip/InfoTip/index.js +67 -50
  22. package/dist/Tip/__tests__/helpers.d.ts +26 -5
  23. package/dist/Tip/shared/FloatingTip.js +3 -3
  24. package/dist/Tip/shared/InlineTip.js +1 -4
  25. package/dist/Tip/shared/types.d.ts +1 -1
  26. package/dist/Tip/shared/utils.d.ts +0 -19
  27. package/dist/Tip/shared/utils.js +0 -104
  28. package/package.json +8 -8
  29. package/dist/Form/__tests__/testUtils.d.ts +0 -22
  30. package/dist/Tip/InfoTip/type-utils.d.ts +0 -35
  31. package/dist/Tip/InfoTip/type-utils.js +0 -72
@@ -1,5 +1,11 @@
1
1
  import { css, theme, timing, transitionConcat, variant } from '@codecademy/gamut-styles';
2
2
  import { formBaseComponentStyles, formFieldBaseDisabledStyles, InputSelectors } from '.';
3
+ export const radioWrapper = css({
4
+ margin: '0.25rem 0',
5
+ width: '100%',
6
+ fontWeight: 'normal',
7
+ display: 'flex'
8
+ });
3
9
  const consistentLabelStyles = {
4
10
  content: '""',
5
11
  display: 'block',
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  export type conditionalStyleProps = {
3
2
  error?: boolean;
4
3
  activated?: boolean;
@@ -92,12 +91,6 @@ export declare const formBaseFieldStylesObject: {
92
91
  export declare const formBaseFieldStyles: (props: {
93
92
  theme?: import("@emotion/react").Theme | undefined;
94
93
  }) => import("@codecademy/variance").CSSObject;
95
- export declare const InputWrapper: import("@emotion/styled").StyledComponent<{
96
- theme?: import("@emotion/react").Theme | undefined;
97
- as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
98
- } & {
99
- theme?: import("@emotion/react").Theme | undefined;
100
- }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
101
94
  export declare const formFieldStyles: (props: {
102
95
  theme?: import("@emotion/react").Theme | undefined;
103
96
  }) => import("@codecademy/variance").CSSObject;
@@ -1,4 +1,3 @@
1
- import _styled from "@emotion/styled/base";
2
1
  import { css, theme, transitionConcat, variant } from '@codecademy/gamut-styles';
3
2
  export let InputSelectors = /*#__PURE__*/function (InputSelectors) {
4
3
  InputSelectors["HOVER"] = "&:hover";
@@ -67,16 +66,6 @@ export const formBaseFieldStylesObject = {
67
66
  }
68
67
  };
69
68
  export const formBaseFieldStyles = css(formBaseFieldStylesObject);
70
- const inputWrapper = css({
71
- margin: '0.25rem 0',
72
- width: '100%',
73
- fontWeight: 'normal',
74
- display: 'flex'
75
- });
76
- export const InputWrapper = /*#__PURE__*/_styled("div", {
77
- target: "e1o3jdqp0",
78
- label: "InputWrapper"
79
- })(inputWrapper, process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9Gb3JtL3N0eWxlcy9zaGFyZWQtc3lzdGVtLXByb3BzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXNHNEIiLCJmaWxlIjoiLi4vLi4vLi4vc3JjL0Zvcm0vc3R5bGVzL3NoYXJlZC1zeXN0ZW0tcHJvcHMudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBjc3MsXG4gIHRoZW1lLFxuICB0cmFuc2l0aW9uQ29uY2F0LFxuICB2YXJpYW50LFxufSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuXG5leHBvcnQgdHlwZSBjb25kaXRpb25hbFN0eWxlUHJvcHMgPSB7XG4gIGVycm9yPzogYm9vbGVhbjtcbiAgYWN0aXZhdGVkPzogYm9vbGVhbjtcbiAgaXNGb2N1c2VkPzogYm9vbGVhbiB8IG51bGw7XG4gIGlzRGlzYWJsZWQ/OiBib29sZWFuIHwgbnVsbDtcbn07XG5cbmV4cG9ydCBlbnVtIElucHV0U2VsZWN0b3JzIHtcbiAgSE9WRVIgPSAnJjpob3ZlcicsXG4gIEFDVElWRSA9ICcmOmFjdGl2ZScsXG4gIFBMQUNFSE9MREVSID0gJyY6cGxhY2Vob2xkZXInLFxuICBGT0NVUyA9ICcmOmZvY3VzJyxcbiAgRk9DVVNfTEFCRUxfRElWX0NISUxEID0gJyY6Zm9jdXMgKyBsYWJlbCA+IGRpdicsXG4gIERJU0FCTEVEID0gXCImOmRpc2FibGVkLCAmW2FyaWEtZGlzYWJsZWQ9J3RydWUnXVwiLFxuICBCRUZPUkUgPSAnJjo6YmVmb3JlJyxcbiAgQUZURVIgPSAnJjo6YWZ0ZXInLFxuICBCRUZPUkVfQU5EX0FGVEVSID0gJyY6OmJlZm9yZSwgJjo6YWZ0ZXInLFxuICBDSEVDS0VEX0JFRk9SRSA9ICcmOmNoZWNrZWQgKyBsYWJlbDo6YmVmb3JlJyxcbiAgQ0hFQ0tFRF9BRlRFUiA9ICcmOmNoZWNrZWQgKyBsYWJlbDo6YWZ0ZXInLFxuICBIT1ZFUl9GT0NVU19CRUZPUkUgPSAnJjpob3ZlciArIGxhYmVsOjpiZWZvcmUsICY6Zm9jdXMgKyBsYWJlbDo6YmVmb3JlJyxcbn1cblxuZXhwb3J0IGNvbnN0IGZvcm1CYXNlU3R5bGVzID0ge1xuICBmb250V2VpZ2h0OiAnYmFzZScsXG4gIGZvbnRTaXplOiAxNixcbiAgY29sb3I6ICd0ZXh0Jyxcbn0gYXMgY29uc3Q7XG5cbmV4cG9ydCBjb25zdCBmb3JtQmFzZUNvbXBvbmVudFN0eWxlcyA9IHtcbiAgd2lkdGg6IDEsXG4gIG91dGxpbmU6ICdub25lJyxcbiAgYmc6ICdiYWNrZ3JvdW5kJyxcbiAgbWluV2lkdGg6ICdhdXRvJyxcbiAgLi4uZm9ybUJhc2VTdHlsZXMsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgY29uc3QgZm9ybUZpZWxkRm9jdXNTdHlsZXMgPSB7XG4gIGJvcmRlckNvbG9yOiAncHJpbWFyeScsXG4gIGJveFNoYWRvdzogYGluc2V0IDAgMCAwIDFweCAke3RoZW1lLmNvbG9ycy5wcmltYXJ5fWAsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgY29uc3QgZm9ybUZpZWxkVGV4dERpc2FibGVkU3R5bGVzID0ge1xuICBjb2xvcjogJ3RleHQtZGlzYWJsZWQnLFxuICBjdXJzb3I6ICdub3QtYWxsb3dlZCcsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgY29uc3QgZm9ybUZpZWxkQmFzZURpc2FibGVkU3R5bGVzID0ge1xuICBib3JkZXJDb2xvcjogJ2N1cnJlbnRDb2xvcicsXG4gIG9wYWNpdHk6IDEsXG4gIC4uLmZvcm1GaWVsZFRleHREaXNhYmxlZFN0eWxlcyxcbn0gYXMgY29uc3Q7XG5cbmV4cG9ydCBjb25zdCBmb3JtRmllbGREaXNhYmxlZFN0eWxlcyA9IHtcbiAgLi4uZm9ybUZpZWxkQmFzZURpc2FibGVkU3R5bGVzLFxuICBiZzogJ2JhY2tncm91bmQtZGlzYWJsZWQnLFxuICBbSW5wdXRTZWxlY3RvcnMuSE9WRVJdOiB7XG4gICAgYm9yZGVyQ29sb3I6ICdjdXJyZW50Q29sb3InLFxuICB9LFxufSBhcyBjb25zdDtcblxuZXhwb3J0IGNvbnN0IGZvcm1GaWVsZFBhZGRpbmdTdHlsZXMgPSB7XG4gIHB5OiAxMixcbiAgcHg6IDgsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgY29uc3QgZm9ybUJhc2VGaWVsZFN0eWxlc09iamVjdCA9IHtcbiAgLi4uZm9ybUJhc2VDb21wb25lbnRTdHlsZXMsXG4gIHRyYW5zaXRpb246IHRyYW5zaXRpb25Db25jYXQoXG4gICAgWydiYWNrZ3JvdW5kLWNvbG9yJywgJ2JveC1zaGFkb3cnXSxcbiAgICAnc2xvdycsXG4gICAgJ2Vhc2UtaW4tb3V0J1xuICApLFxuICBib3JkZXI6IDEsXG4gIGJvcmRlclJhZGl1czogJ21kJyxcbiAgW0lucHV0U2VsZWN0b3JzLkhPVkVSXToge1xuICAgIGJvcmRlckNvbG9yOiAncHJpbWFyeScsXG4gIH0sXG4gIFtJbnB1dFNlbGVjdG9ycy5QTEFDRUhPTERFUl06IHtcbiAgICBmb250U3R5bGU6ICdpdGFsaWMnLFxuICB9LFxuICBbSW5wdXRTZWxlY3RvcnMuRElTQUJMRURdOiB7XG4gICAgLi4uZm9ybUZpZWxkRGlzYWJsZWRTdHlsZXMsXG4gIH0sXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgY29uc3QgZm9ybUJhc2VGaWVsZFN0eWxlcyA9IGNzcyhmb3JtQmFzZUZpZWxkU3R5bGVzT2JqZWN0KTtcblxuY29uc3QgaW5wdXRXcmFwcGVyID0gY3NzKHtcbiAgbWFyZ2luOiAnMC4yNXJlbSAwJyxcbiAgd2lkdGg6ICcxMDAlJyxcbiAgZm9udFdlaWdodDogJ25vcm1hbCcsXG4gIGRpc3BsYXk6ICdmbGV4Jyxcbn0pO1xuXG5leHBvcnQgY29uc3QgSW5wdXRXcmFwcGVyID0gc3R5bGVkLmRpdihpbnB1dFdyYXBwZXIpO1xuXG5leHBvcnQgY29uc3QgZm9ybUZpZWxkU3R5bGVzID0gY3NzKHtcbiAgLi4uZm9ybUJhc2VGaWVsZFN0eWxlc09iamVjdCxcbiAgLi4uZm9ybUZpZWxkUGFkZGluZ1N0eWxlcyxcbiAgbGluZUhlaWdodDogJ2Jhc2UnLFxuICBbSW5wdXRTZWxlY3RvcnMuRk9DVVNdOiBmb3JtRmllbGRGb2N1c1N0eWxlcyxcbn0pO1xuXG5leHBvcnQgY29uc3QgY29uZGl0aW9uYWxTdHlsZXMgPSB2YXJpYW50KHtcbiAgdmFyaWFudHM6IHtcbiAgICBlcnJvcjoge1xuICAgICAgYm9yZGVyQ29sb3I6ICdmZWVkYmFjay1lcnJvcicsXG4gICAgICBbSW5wdXRTZWxlY3RvcnMuSE9WRVJdOiB7XG4gICAgICAgIGJvcmRlckNvbG9yOiAnZmVlZGJhY2stZXJyb3InLFxuICAgICAgfSxcbiAgICAgIFtJbnB1dFNlbGVjdG9ycy5GT0NVU106IHtcbiAgICAgICAgYm9yZGVyQ29sb3I6ICdmZWVkYmFjay1lcnJvcicsXG4gICAgICAgIGJveFNoYWRvdzogYGluc2V0IDAgMCAwIDFweCAke3RoZW1lLmNvbG9yc1snZmVlZGJhY2stZXJyb3InXX1gLFxuICAgICAgfSxcbiAgICB9LFxuICAgIGFjdGl2YXRlZDogeyBib3JkZXJDb2xvcjogJ2N1cnJlbnRDb2xvcicgfSxcbiAgfSxcbn0pO1xuXG5leHBvcnQgY29uc3QgY29uZGl0aW9uYWxTdHlsZVN0YXRlID0gKGVycm9yOiBib29sZWFuLCBhY3RpdmF0ZWQ6IGJvb2xlYW4pID0+IHtcbiAgcmV0dXJuIGVycm9yID8gJ2Vycm9yJyA6IGFjdGl2YXRlZCA/ICdhY3RpdmF0ZWQnIDogdW5kZWZpbmVkO1xufTtcblxuZXhwb3J0IGNvbnN0IGlucHV0U2l6ZVN0eWxlcyA9IHZhcmlhbnQoe1xuICBwcm9wOiAnaW5wdXRTaXplJyxcbiAgZGVmYXVsdFZhcmlhbnQ6ICdiYXNlJyxcbiAgYmFzZToge1xuICAgIHB4OiA4LFxuICB9LFxuICB2YXJpYW50czoge1xuICAgIGJhc2U6IHtcbiAgICAgIC4uLmZvcm1GaWVsZFBhZGRpbmdTdHlsZXMsXG4gICAgfSxcbiAgICBzbWFsbDoge1xuICAgICAgcHk6IDMgYXMgYW55LFxuICAgIH0sXG4gICAgc21hbGxGaWxlOiB7XG4gICAgICBweTogMiBhcyBhbnksXG4gICAgfSxcbiAgfSxcbn0pO1xuIl19 */");
80
69
  export const formFieldStyles = css({
81
70
  ...formBaseFieldStylesObject,
82
71
  ...formFieldPaddingStyles,
@@ -31,14 +31,12 @@ export const GridFormRadioGroupInput = ({
31
31
  children: field.options.map(({
32
32
  label,
33
33
  value,
34
- infotip,
35
34
  ...rest
36
35
  }) => /*#__PURE__*/_createElement(Radio, {
37
36
  ...register(field.name, field.validation),
38
37
  disabled: disabled,
39
38
  error: error,
40
39
  id: field.id,
41
- infotip: infotip,
42
40
  key: value,
43
41
  label: label,
44
42
  value: value,
@@ -21,10 +21,6 @@ export declare const getComponent: (componentName: string) => {
21
21
  };
22
22
  type GridFormInputGroupTestComponentProps = GridFormInputGroupProps & {
23
23
  mode?: 'onSubmit' | 'onChange';
24
- externalLabel?: {
25
- id: string;
26
- text: string;
27
- };
28
24
  };
29
25
  export declare const GridFormInputGroupTestComponent: React.FC<GridFormInputGroupTestComponentProps>;
30
26
  export {};
@@ -5,7 +5,7 @@ import { MinimalCheckboxProps } from '../ConnectedForm';
5
5
  import { CheckboxLabelUnion, TextAreaProps } from '../Form';
6
6
  import { CheckboxPaddingProps } from '../Form/types';
7
7
  import { ColumnProps } from '../Layout';
8
- import { InfoTipSubComponentProps } from '../Tip/InfoTip/type-utils';
8
+ import { InfoTipProps } from '../Tip/InfoTip';
9
9
  import { Text, TextProps } from '../Typography/Text';
10
10
  export interface BaseFormInputProps {
11
11
  className?: string;
@@ -25,12 +25,7 @@ export type BaseFormField<Value> = {
25
25
  * HTML id to use instead of the name.
26
26
  */
27
27
  id?: string;
28
- /**
29
- * InfoTip to display next to the field label. The InfoTip button is
30
- * automatically labelled by the field label. To override this behavior,
31
- * provide `ariaLabel` or `ariaLabelledby`.
32
- */
33
- infotip?: InfoTipSubComponentProps;
28
+ infotip?: InfoTipProps;
34
29
  isSoloField?: boolean;
35
30
  name: string;
36
31
  onUpdate?: (value: Value) => void;
@@ -8,17 +8,14 @@ export const InfoTipButton = /*#__PURE__*/forwardRef(({
8
8
  active,
9
9
  children,
10
10
  emphasis,
11
- 'aria-label': ariaLabel,
12
- 'aria-labelledby': ariaLabelledby,
13
11
  ...props
14
12
  }, ref) => {
15
13
  const Icon = emphasis === 'high' ? MiniInfoCircleIcon : MiniInfoOutlineIcon;
16
14
  return /*#__PURE__*/_jsxs(InfoTipButtonBase, {
17
- ...props,
18
15
  active: active,
19
16
  "aria-expanded": active,
20
- "aria-label": ariaLabel,
21
- "aria-labelledby": ariaLabelledby,
17
+ "aria-label": "Show information",
18
+ ...props,
22
19
  ref: ref,
23
20
  children: [Icon && /*#__PURE__*/_jsx(Icon, {
24
21
  "aria-hidden": true,
@@ -0,0 +1,12 @@
1
+ /// <reference types="react" />
2
+ export declare const ScreenreaderNavigableText: import("@emotion/styled").StyledComponent<(((Omit<{
3
+ theme?: import("@emotion/react").Theme | undefined;
4
+ as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
5
+ } & import("../..").TextTruncateProps & Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "slot" | "style" | "title" | "dir" | "children" | "className" | "aria-hidden" | "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "content" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onResize" | "onResizeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | keyof import("react").ClassAttributes<HTMLSpanElement>>, "ref"> | Omit<{
6
+ theme?: import("@emotion/react").Theme | undefined;
7
+ as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
8
+ } & import("../..").TextNoTruncateProps & Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "slot" | "style" | "title" | "dir" | "children" | "className" | "aria-hidden" | "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "content" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onResize" | "onResizeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | keyof import("react").ClassAttributes<HTMLSpanElement>>, "ref">) & import("react").RefAttributes<HTMLSpanElement>) & {
9
+ theme?: import("@emotion/react").Theme | undefined;
10
+ }) & {
11
+ theme?: import("@emotion/react").Theme | undefined;
12
+ }, {}, {}>;
@@ -0,0 +1,9 @@
1
+ import _styled from "@emotion/styled/base";
2
+ import { css } from '@codecademy/gamut-styles';
3
+ import { Text } from '../../Typography';
4
+ export const ScreenreaderNavigableText = /*#__PURE__*/_styled(Text, {
5
+ target: "e1rvjfdo0",
6
+ label: "ScreenreaderNavigableText"
7
+ })(css({
8
+ position: 'absolute'
9
+ }), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9UaXAvSW5mb1RpcC9lbGVtZW50cy50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS3lDIiwiZmlsZSI6Ii4uLy4uLy4uL3NyYy9UaXAvSW5mb1RpcC9lbGVtZW50cy50c3giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuXG5pbXBvcnQgeyBUZXh0IH0gZnJvbSAnLi4vLi4vVHlwb2dyYXBoeSc7XG5cbmV4cG9ydCBjb25zdCBTY3JlZW5yZWFkZXJOYXZpZ2FibGVUZXh0ID0gc3R5bGVkKFRleHQpKFxuICBjc3MoeyBwb3NpdGlvbjogJ2Fic29sdXRlJyB9KVxuKTtcbiJdfQ== */");
@@ -1,50 +1,13 @@
1
1
  /// <reference types="react" />
2
2
  import { TipBaseAlignment, TipBaseProps } from '../shared/types';
3
- /**
4
- * Base props shared by all InfoTip variants.
5
- * Contains all common props except the aria-* specific props.
6
- */
7
- export type InfoTipBaseProps = TipBaseProps & {
3
+ export type InfoTipProps = TipBaseProps & {
8
4
  alignment?: TipBaseAlignment;
9
- /**
10
- * Accessible role description for the InfoTip button. Useful for translation.
11
- * @default "More information button"
12
- */
13
- ariaRoleDescription?: string;
14
5
  emphasis?: 'low' | 'high';
15
6
  /**
16
- * Called when the InfoTip button is clicked - the onClick function is called after the DOM updates and the tip is mounted.
7
+ * Called when the info tip is clicked - the onClick function is called after the DOM updates and the tip is mounted.
17
8
  */
18
9
  onClick?: (arg0: {
19
10
  isTipHidden: boolean;
20
11
  }) => void;
21
- /**
22
- * Use the camelCase syntax to pass aria-* props to the InfoTip button.
23
- */
24
- 'aria-label'?: never;
25
- /**
26
- * Use the camelCase syntax to pass aria-* props to the InfoTip button.
27
- */
28
- 'aria-labelledby'?: never;
29
- /**
30
- * Use the camelCase syntax to pass aria-* props to the InfoTip button.
31
- */
32
- 'aria-roledescription'?: never;
33
- };
34
- type InfoTipPropsWithAriaLabel = InfoTipBaseProps & {
35
- /**
36
- * Accessible label for the InfoTip button. ariaLabel or ariaLabelledby should be provided for accessibility.
37
- */
38
- ariaLabel?: string;
39
- ariaLabelledby?: never;
40
- };
41
- type InfoTipPropsWithAriaLabelledby = InfoTipBaseProps & {
42
- ariaLabel?: never;
43
- /**
44
- * ID of an element that labels the InfoTip button.
45
- */
46
- ariaLabelledby?: string;
47
12
  };
48
- export type InfoTipProps = InfoTipPropsWithAriaLabel | InfoTipPropsWithAriaLabelledby;
49
13
  export declare const InfoTip: React.FC<InfoTipProps>;
50
- export {};
@@ -1,22 +1,19 @@
1
1
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
2
2
  import { getFocusableElements as getFocusableElementsUtil } from '../../utils/focus';
3
+ import { extractTextContent } from '../../utils/react';
3
4
  import { FloatingTip } from '../shared/FloatingTip';
4
5
  import { InlineTip } from '../shared/InlineTip';
5
6
  import { tipDefaultProps } from '../shared/types';
6
- import { isFloatingElementOpen } from '../shared/utils';
7
+ import { isElementVisible } from '../shared/utils';
8
+ import { ScreenreaderNavigableText } from './elements';
7
9
  import { InfoTipButton } from './InfoTipButton';
10
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const ARIA_HIDDEN_DELAY_MS = 1000;
8
12
 
9
- /**
10
- * Base props shared by all InfoTip variants.
11
- * Contains all common props except the aria-* specific props.
12
- */
13
- import { jsx as _jsx } from "react/jsx-runtime";
13
+ // Match native dialogs with open attribute, and role-based dialogs that aren't aria-hidden
14
14
  const MODAL_SELECTOR = 'dialog[open],[role="dialog"]:not([aria-hidden="true"]),[role="alertdialog"]:not([aria-hidden="true"])';
15
15
  export const InfoTip = ({
16
16
  alignment = 'top-right',
17
- ariaLabel,
18
- ariaLabelledby,
19
- ariaRoleDescription = 'More information button',
20
17
  emphasis = 'low',
21
18
  info,
22
19
  onClick,
@@ -25,14 +22,25 @@ export const InfoTip = ({
25
22
  }) => {
26
23
  const isFloating = placement === 'floating';
27
24
  const [isTipHidden, setHideTip] = useState(true);
25
+ const [isAriaHidden, setIsAriaHidden] = useState(false);
26
+ const [shouldAnnounce, setShouldAnnounce] = useState(false);
28
27
  const [loaded, setLoaded] = useState(false);
29
28
  const wrapperRef = useRef(null);
30
29
  const buttonRef = useRef(null);
31
30
  const popoverContentNodeRef = useRef(null);
32
31
  const isInitialMount = useRef(true);
32
+ const ariaHiddenTimeoutRef = useRef(null);
33
+ const announceTimeoutRef = useRef(null);
33
34
  const getFocusableElements = useCallback(() => {
34
35
  return getFocusableElementsUtil(popoverContentNodeRef.current);
35
36
  }, []);
37
+ const clearAndSetTimeout = useCallback((timeoutRef, callback, delay) => {
38
+ clearTimeout(timeoutRef.current ?? undefined);
39
+ timeoutRef.current = setTimeout(() => {
40
+ callback();
41
+ timeoutRef.current = null;
42
+ }, delay);
43
+ }, []);
36
44
  const popoverContentRef = useCallback(node => {
37
45
  popoverContentNodeRef.current = node;
38
46
  if (node && !isTipHidden && isFloating) {
@@ -43,10 +51,24 @@ export const InfoTip = ({
43
51
  }, [onClick, isTipHidden, isFloating]);
44
52
  useEffect(() => {
45
53
  setLoaded(true);
54
+ const ariaHiddenTimeout = ariaHiddenTimeoutRef.current;
55
+ const announceTimeout = announceTimeoutRef.current;
56
+ return () => {
57
+ clearTimeout(ariaHiddenTimeout ?? undefined);
58
+ clearTimeout(announceTimeout ?? undefined);
59
+ };
46
60
  }, []);
47
61
  const setTipIsHidden = useCallback(nextTipState => {
48
62
  setHideTip(nextTipState);
49
- }, []);
63
+ if (!nextTipState && !isFloating) {
64
+ clearAndSetTimeout(ariaHiddenTimeoutRef, () => setIsAriaHidden(true), ARIA_HIDDEN_DELAY_MS);
65
+ } else if (nextTipState) {
66
+ if (isAriaHidden) setIsAriaHidden(false);
67
+ setShouldAnnounce(false);
68
+ clearTimeout(ariaHiddenTimeoutRef.current ?? undefined);
69
+ ariaHiddenTimeoutRef.current = null;
70
+ }
71
+ }, [isAriaHidden, isFloating, clearAndSetTimeout]);
50
72
  const handleOutsideClick = useCallback(e => {
51
73
  const wrapper = wrapperRef.current;
52
74
  const isOutside = wrapper && (!(e.target instanceof HTMLElement) || !wrapper.contains(e.target));
@@ -57,7 +79,10 @@ export const InfoTip = ({
57
79
  const clickHandler = useCallback(() => {
58
80
  const currentTipState = !isTipHidden;
59
81
  setTipIsHidden(currentTipState);
60
- }, [isTipHidden, setTipIsHidden]);
82
+ if (!currentTipState) {
83
+ clearAndSetTimeout(announceTimeoutRef, () => setShouldAnnounce(true), 0);
84
+ }
85
+ }, [isTipHidden, setTipIsHidden, clearAndSetTimeout]);
61
86
  useLayoutEffect(() => {
62
87
  if (isInitialMount.current) {
63
88
  isInitialMount.current = false;
@@ -83,14 +108,7 @@ export const InfoTip = ({
83
108
  const handleGlobalEscapeKey = e => {
84
109
  if (e.key !== 'Escape') return;
85
110
  const openModals = document.querySelectorAll(MODAL_SELECTOR);
86
- const hasUnrelatedModal = Array.from(openModals).some(modal => {
87
- // Only consider floating elements that are actually open
88
- if (!isFloatingElementOpen(modal)) {
89
- return false;
90
- }
91
- // Check if it's unrelated to this InfoTip
92
- return wrapperRef.current && !modal.contains(wrapperRef.current);
93
- });
111
+ const hasUnrelatedModal = Array.from(openModals).some(modal => isElementVisible(modal) && wrapperRef.current && !modal.contains(wrapperRef.current));
94
112
  if (hasUnrelatedModal) return;
95
113
  e.preventDefault();
96
114
  e.stopPropagation();
@@ -102,18 +120,7 @@ export const InfoTip = ({
102
120
  const handleTabKeyInPopover = event => {
103
121
  if (event.key !== 'Tab' || event.shiftKey) return;
104
122
  const focusableElements = getFocusableElements();
105
- const {
106
- activeElement
107
- } = document;
108
-
109
- // If no focusable elements and popover itself has focus, wrap to button
110
- if (focusableElements.length === 0) {
111
- if (activeElement === popoverContentNodeRef.current) {
112
- event.preventDefault();
113
- buttonRef.current?.focus();
114
- }
115
- return;
116
- }
123
+ if (focusableElements.length === 0) return;
117
124
  const lastElement = focusableElements[focusableElements.length - 1];
118
125
 
119
126
  // Only wrap forward: if on last element, wrap to button
@@ -134,35 +141,45 @@ export const InfoTip = ({
134
141
  };
135
142
  }
136
143
  return () => document.removeEventListener('keydown', handleGlobalEscapeKey, true);
137
- }, [isTipHidden, isFloating, getFocusableElements, setTipIsHidden]);
138
- useEffect(() => {
139
- if (isTipHidden) return;
140
- const timeoutId = setTimeout(() => {
141
- popoverContentNodeRef.current?.focus();
142
- }, 0);
143
- return () => clearTimeout(timeoutId);
144
- }, [isTipHidden]);
144
+ }, [isTipHidden, isFloating, setTipIsHidden, getFocusableElements]);
145
145
  const Tip = loaded && isFloating ? FloatingTip : InlineTip;
146
146
  const tipProps = useMemo(() => ({
147
147
  alignment,
148
148
  info,
149
149
  isTipHidden,
150
- contentRef: popoverContentRef,
151
150
  wrapperRef,
151
+ ...(isFloating && {
152
+ popoverContentRef
153
+ }),
152
154
  ...rest
153
- }), [alignment, info, isTipHidden, popoverContentRef, wrapperRef, rest]);
155
+ }), [alignment, info, isTipHidden, wrapperRef, isFloating, popoverContentRef, rest]);
156
+ const extractedTextContent = useMemo(() => extractTextContent(info), [info]);
157
+ const screenreaderInfo = shouldAnnounce && !isTipHidden ? extractedTextContent : '\xa0';
158
+ const screenreaderText = useMemo(() => /*#__PURE__*/_jsx(ScreenreaderNavigableText, {
159
+ "aria-hidden": isAriaHidden,
160
+ "aria-live": "assertive",
161
+ screenreader: true,
162
+ children: screenreaderInfo
163
+ }), [isAriaHidden, screenreaderInfo]);
164
+ const button = useMemo(() => /*#__PURE__*/_jsx(InfoTipButton, {
165
+ active: !isTipHidden,
166
+ "aria-expanded": !isTipHidden,
167
+ emphasis: emphasis,
168
+ ref: buttonRef,
169
+ onClick: clickHandler
170
+ }), [isTipHidden, emphasis, clickHandler]);
171
+
172
+ /*
173
+ * For floating placement, screenreader text comes before button to maintain
174
+ * correct DOM order despite Portal rendering. See GMT-64 for planned fix.
175
+ */
154
176
  return /*#__PURE__*/_jsx(Tip, {
155
177
  ...tipProps,
156
178
  type: "info",
157
- children: /*#__PURE__*/_jsx(InfoTipButton, {
158
- active: !isTipHidden,
159
- "aria-expanded": !isTipHidden,
160
- "aria-label": ariaLabel,
161
- "aria-labelledby": ariaLabelledby,
162
- "aria-roledescription": ariaRoleDescription,
163
- emphasis: emphasis,
164
- ref: buttonRef,
165
- onClick: clickHandler
179
+ children: isFloating && alignment.includes('top') ? /*#__PURE__*/_jsxs(_Fragment, {
180
+ children: [screenreaderText, button]
181
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
182
+ children: [button, screenreaderText]
166
183
  })
167
184
  });
168
185
  };
@@ -1,8 +1,9 @@
1
1
  import { setupRtl } from '@codecademy/gamut-tests';
2
2
  import { RefObject } from 'react';
3
- import { InfoTip } from '../InfoTip';
3
+ import { InfoTip, InfoTipProps } from '../InfoTip';
4
4
  import { TipPlacements } from '../shared/types';
5
5
  type InfoTipView = ReturnType<ReturnType<typeof setupRtl<typeof InfoTip>>>['view'];
6
+ type Placement = NonNullable<InfoTipProps['placement']>;
6
7
  type ViewParam = {
7
8
  view: InfoTipView;
8
9
  };
@@ -13,7 +14,7 @@ type InfoParam = {
13
14
  info: string;
14
15
  };
15
16
  type PlacementParam = {
16
- placement: TipPlacements;
17
+ placement: Placement;
17
18
  };
18
19
  export declare const createFocusOnClick: (ref: RefObject<HTMLDivElement>) => ({ isTipHidden }: {
19
20
  isTipHidden: boolean;
@@ -45,10 +46,13 @@ export declare const pressKey: (key: string) => Promise<void>;
45
46
  export declare const waitForLinkToHaveFocus: ({ view, linkText, }: ViewParam & LinkTextParam) => Promise<HTMLElement>;
46
47
  export declare const openTipAndWaitForLink: ({ view, linkText, }: ViewParam & LinkTextParam) => Promise<HTMLElement>;
47
48
  export declare const openTipTabToLinkAndWaitForFocus: (view: InfoTipView, linkText: string) => Promise<HTMLElement>;
48
- export declare const testFocusWrap: ({ view, direction, }: ViewParam & {
49
+ export declare const testShowTipOnClick: ({ view, info, placement, }: ViewParam & InfoParam & PlacementParam) => Promise<void>;
50
+ export declare const testEscapeKeyReturnsFocus: ({ view, info, placement, }: ViewParam & InfoParam & PlacementParam) => Promise<void>;
51
+ export declare const testFocusWrap: ({ view, containerRef, direction, }: ViewParam & {
52
+ containerRef: RefObject<HTMLDivElement>;
49
53
  direction: 'forward' | 'backward';
50
54
  }) => Promise<void>;
51
- export declare const testTabFromPopoverWithNoInteractiveElements: (view: InfoTipView) => Promise<void>;
55
+ export declare const getTipContent: (view: InfoTipView, text: string, useQuery?: boolean) => HTMLElement;
52
56
  export declare const testTabbingBetweenLinks: ({ view, firstLinkText, secondLinkText, placement, }: ViewParam & {
53
57
  firstLinkText: string;
54
58
  secondLinkText: string;
@@ -56,6 +60,7 @@ export declare const testTabbingBetweenLinks: ({ view, firstLinkText, secondLink
56
60
  }) => Promise<void>;
57
61
  export declare const setupLinkTestWithPlacement: (linkText: string, placement: TipPlacements, renderView: ReturnType<typeof setupRtl<typeof InfoTip>>) => {
58
62
  view: import("@testing-library/react").RenderResult;
63
+ containerRef: RefObject<HTMLDivElement>;
59
64
  info: import("react/jsx-runtime").JSX.Element;
60
65
  onClick: ({ isTipHidden }: {
61
66
  isTipHidden: boolean;
@@ -79,12 +84,28 @@ type ViewWithQueries = {
79
84
  getAllByText: (text: string) => HTMLElement[];
80
85
  getAllByLabelText: (text: string) => HTMLElement[];
81
86
  };
87
+ export declare const getVisibleTip: ({ text, placement, }: {
88
+ text: string;
89
+ placement?: "inline" | "floating" | undefined;
90
+ }) => HTMLElement | undefined;
91
+ export declare const expectTipToBeVisible: ({ text, placement, }: {
92
+ text: string;
93
+ placement?: "inline" | "floating" | undefined;
94
+ }) => void;
95
+ export declare const expectTipToBeClosed: ({ text, placement, }: {
96
+ text: string;
97
+ placement?: "inline" | "floating" | undefined;
98
+ }) => void;
82
99
  export declare const openInfoTipsWithKeyboard: ({ view, count, }: {
83
100
  view: ViewWithQueries;
84
101
  count: number;
85
102
  }) => Promise<void>;
86
103
  export declare const expectTipsVisible: (tips: {
87
104
  text: string;
105
+ placement?: 'inline' | 'floating';
106
+ }[]) => void;
107
+ export declare const expectTipsClosed: (tips: {
108
+ text: string;
109
+ placement?: 'inline' | 'floating';
88
110
  }[]) => void;
89
- export declare const expectTipsClosed: () => void;
90
111
  export {};
@@ -18,7 +18,7 @@ export const FloatingTip = ({
18
18
  loading,
19
19
  narrow,
20
20
  overline,
21
- contentRef,
21
+ popoverContentRef,
22
22
  truncateLines,
23
23
  type,
24
24
  username,
@@ -123,7 +123,7 @@ export const FloatingTip = ({
123
123
  width: inheritDims ? 'inherit' : undefined,
124
124
  onBlur: toolOnlyEventFunc,
125
125
  onFocus: toolOnlyEventFunc,
126
- onKeyDown: escapeKeyPressHandler,
126
+ onKeyDown: escapeKeyPressHandler ? e => escapeKeyPressHandler(e) : undefined,
127
127
  onMouseDown: e => e.preventDefault(),
128
128
  onMouseEnter: toolOnlyEventFunc,
129
129
  children: children
@@ -134,7 +134,7 @@ export const FloatingTip = ({
134
134
  horizontalOffset: offset,
135
135
  isOpen: isPopoverOpen,
136
136
  outline: true,
137
- popoverContainerRef: contentRef,
137
+ popoverContainerRef: popoverContentRef,
138
138
  skipFocusTrap: true,
139
139
  targetRef: ref,
140
140
  variant: "secondary",
@@ -17,7 +17,6 @@ export const InlineTip = ({
17
17
  loading,
18
18
  narrow,
19
19
  overline,
20
- contentRef,
21
20
  truncateLines,
22
21
  type,
23
22
  username,
@@ -43,7 +42,7 @@ export const InlineTip = ({
43
42
  height: inheritDims ? 'inherit' : undefined,
44
43
  ref: wrapperRef,
45
44
  width: inheritDims ? 'inherit' : undefined,
46
- onKeyDown: escapeKeyPressHandler,
45
+ onKeyDown: escapeKeyPressHandler ? e => escapeKeyPressHandler(e) : undefined,
47
46
  children: children
48
47
  });
49
48
  const tipBody = /*#__PURE__*/_jsx(InlineTipBodyWrapper, {
@@ -56,9 +55,7 @@ export const InlineTip = ({
56
55
  color: "currentColor",
57
56
  horizNarrow: narrow && isHorizontalCenter,
58
57
  id: id,
59
- ref: contentRef,
60
58
  role: type === 'tool' ? 'tooltip' : undefined,
61
- tabIndex: type === 'info' ? -1 : undefined,
62
59
  width: narrow && !isHorizontalCenter ? narrowWidth : 'max-content',
63
60
  zIndex: "auto",
64
61
  children: type === 'preview' ? /*#__PURE__*/_jsxs(_Fragment, {
@@ -46,7 +46,7 @@ export type TipPlacementComponentProps = Omit<TipNewBaseProps, 'placement' | 'em
46
46
  escapeKeyPressHandler?: (event: React.KeyboardEvent<HTMLDivElement>) => void;
47
47
  id?: string;
48
48
  isTipHidden?: boolean;
49
- contentRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
49
+ popoverContentRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
50
50
  type: 'info' | 'tool' | 'preview';
51
51
  wrapperRef?: React.RefObject<HTMLDivElement>;
52
52
  zIndex?: number;
@@ -6,22 +6,3 @@ export declare const escapeKeyPressHandler: (event: React.KeyboardEvent<HTMLDivE
6
6
  * Uses the modern checkVisibility API with a fallback for older browsers.
7
7
  */
8
8
  export declare const isElementVisible: (element: Element) => boolean;
9
- /**
10
- * Check if a floating element (modal, dialog, popover, overlay, etc.) is actually open and blocking.
11
- *
12
- * A floating element is considered "open" and blocking if:
13
- * 1. It's a <dialog> element with the open attribute (always blocking per HTML spec), OR
14
- * 2. It has role="alertdialog" (always blocking per ARIA spec), OR
15
- * 3. It has role="dialog" AND:
16
- * - It's not aria-hidden="true", AND
17
- * - It doesn't have aria-expanded="false" (for collapsible dialogs), AND
18
- * - It's actually visible (not just in DOM), AND
19
- * - It has aria-modal="true" (indicates blocking modal per ARIA spec)
20
- *
21
- * Non-blocking popovers and collapsible dialogs without aria-modal="true" are not considered
22
- * blocking and should not prevent InfoTip from closing.
23
- *
24
- * @param element - The DOM element to check
25
- * @returns `true` if the floating element is actually open and blocking, `false` otherwise
26
- */
27
- export declare const isFloatingElementOpen: (element: Element) => boolean;