@codecademy/gamut 67.4.2-alpha.b3304f.0 → 67.4.2-alpha.b7c260.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.
@@ -8,14 +8,17 @@ export const InfoTipButton = /*#__PURE__*/forwardRef(({
8
8
  active,
9
9
  children,
10
10
  emphasis,
11
+ 'aria-label': ariaLabel,
12
+ 'aria-labelledby': ariaLabelledby,
11
13
  ...props
12
14
  }, ref) => {
13
15
  const Icon = emphasis === 'high' ? MiniInfoCircleIcon : MiniInfoOutlineIcon;
14
16
  return /*#__PURE__*/_jsxs(InfoTipButtonBase, {
17
+ ...props,
15
18
  active: active,
16
19
  "aria-expanded": active,
17
- "aria-label": "Show information",
18
- ...props,
20
+ "aria-label": ariaLabel,
21
+ "aria-labelledby": ariaLabelledby,
19
22
  ref: ref,
20
23
  children: [Icon && /*#__PURE__*/_jsx(Icon, {
21
24
  "aria-hidden": true,
@@ -2,6 +2,14 @@
2
2
  import { TipBaseAlignment, TipBaseProps } from '../shared/types';
3
3
  export type InfoTipProps = TipBaseProps & {
4
4
  alignment?: TipBaseAlignment;
5
+ /**
6
+ * Accessible label for the InfoTip button. Its recommended to provide either `ariaLabel` or `ariaLabelledby`.
7
+ */
8
+ ariaLabel?: string;
9
+ /**
10
+ * ID of an element that labels the InfoTip button. Its recommended to provide either `ariaLabel` or `ariaLabelledby`.
11
+ */
12
+ ariaLabelledby?: string;
5
13
  emphasis?: 'low' | 'high';
6
14
  /**
7
15
  * Called when the info tip is clicked - the onClick function is called after the DOM updates and the tip is mounted.
@@ -1,16 +1,15 @@
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';
4
3
  import { FloatingTip } from '../shared/FloatingTip';
5
4
  import { InlineTip } from '../shared/InlineTip';
6
5
  import { tipDefaultProps } from '../shared/types';
7
- import { ScreenreaderNavigableText } from './elements';
8
6
  import { InfoTipButton } from './InfoTipButton';
9
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
10
- const ARIA_HIDDEN_DELAY_MS = 1000;
7
+ import { jsx as _jsx } from "react/jsx-runtime";
11
8
  const MODAL_SELECTOR = 'dialog[open],[role="dialog"],[role="alertdialog"]';
12
9
  export const InfoTip = ({
13
10
  alignment = 'top-right',
11
+ ariaLabel,
12
+ ariaLabelledby,
14
13
  emphasis = 'low',
15
14
  info,
16
15
  onClick,
@@ -19,25 +18,14 @@ export const InfoTip = ({
19
18
  }) => {
20
19
  const isFloating = placement === 'floating';
21
20
  const [isTipHidden, setHideTip] = useState(true);
22
- const [isAriaHidden, setIsAriaHidden] = useState(false);
23
- const [shouldAnnounce, setShouldAnnounce] = useState(false);
24
21
  const [loaded, setLoaded] = useState(false);
25
22
  const wrapperRef = useRef(null);
26
23
  const buttonRef = useRef(null);
27
24
  const popoverContentNodeRef = useRef(null);
28
25
  const isInitialMount = useRef(true);
29
- const ariaHiddenTimeoutRef = useRef(null);
30
- const announceTimeoutRef = useRef(null);
31
26
  const getFocusableElements = useCallback(() => {
32
27
  return getFocusableElementsUtil(popoverContentNodeRef.current);
33
28
  }, []);
34
- const clearAndSetTimeout = useCallback((timeoutRef, callback, delay) => {
35
- clearTimeout(timeoutRef.current ?? undefined);
36
- timeoutRef.current = setTimeout(() => {
37
- callback();
38
- timeoutRef.current = null;
39
- }, delay);
40
- }, []);
41
29
  const popoverContentRef = useCallback(node => {
42
30
  popoverContentNodeRef.current = node;
43
31
  if (node && !isTipHidden && isFloating) {
@@ -48,24 +36,10 @@ export const InfoTip = ({
48
36
  }, [onClick, isTipHidden, isFloating]);
49
37
  useEffect(() => {
50
38
  setLoaded(true);
51
- const ariaHiddenTimeout = ariaHiddenTimeoutRef.current;
52
- const announceTimeout = announceTimeoutRef.current;
53
- return () => {
54
- clearTimeout(ariaHiddenTimeout ?? undefined);
55
- clearTimeout(announceTimeout ?? undefined);
56
- };
57
39
  }, []);
58
40
  const setTipIsHidden = useCallback(nextTipState => {
59
41
  setHideTip(nextTipState);
60
- if (!nextTipState && !isFloating) {
61
- clearAndSetTimeout(ariaHiddenTimeoutRef, () => setIsAriaHidden(true), ARIA_HIDDEN_DELAY_MS);
62
- } else if (nextTipState) {
63
- if (isAriaHidden) setIsAriaHidden(false);
64
- setShouldAnnounce(false);
65
- clearTimeout(ariaHiddenTimeoutRef.current ?? undefined);
66
- ariaHiddenTimeoutRef.current = null;
67
- }
68
- }, [isAriaHidden, isFloating, clearAndSetTimeout]);
42
+ }, []);
69
43
  const handleOutsideClick = useCallback(e => {
70
44
  const wrapper = wrapperRef.current;
71
45
  const isOutside = wrapper && (!(e.target instanceof HTMLElement) || !wrapper.contains(e.target));
@@ -76,10 +50,7 @@ export const InfoTip = ({
76
50
  const clickHandler = useCallback(() => {
77
51
  const currentTipState = !isTipHidden;
78
52
  setTipIsHidden(currentTipState);
79
- if (!currentTipState) {
80
- clearAndSetTimeout(announceTimeoutRef, () => setShouldAnnounce(true), 0);
81
- }
82
- }, [isTipHidden, setTipIsHidden, clearAndSetTimeout]);
53
+ }, [isTipHidden, setTipIsHidden]);
83
54
  useLayoutEffect(() => {
84
55
  if (isInitialMount.current) {
85
56
  isInitialMount.current = false;
@@ -117,7 +88,18 @@ export const InfoTip = ({
117
88
  const handleTabKeyInPopover = event => {
118
89
  if (event.key !== 'Tab' || event.shiftKey) return;
119
90
  const focusableElements = getFocusableElements();
120
- if (focusableElements.length === 0) return;
91
+ const {
92
+ activeElement
93
+ } = document;
94
+
95
+ // If no focusable elements and popover itself has focus, wrap to button
96
+ if (focusableElements.length === 0) {
97
+ if (activeElement === popoverContentNodeRef.current) {
98
+ event.preventDefault();
99
+ buttonRef.current?.focus();
100
+ }
101
+ return;
102
+ }
121
103
  const lastElement = focusableElements[focusableElements.length - 1];
122
104
 
123
105
  // Only wrap forward: if on last element, wrap to button
@@ -137,46 +119,36 @@ export const InfoTip = ({
137
119
  document.removeEventListener('keydown', handleGlobalEscapeKey, true);
138
120
  };
139
121
  }
140
- return () => document.removeEventListener('keydown', handleGlobalEscapeKey, true);
141
- }, [isTipHidden, isFloating, setTipIsHidden, getFocusableElements]);
122
+ return () => document.removeEventListener('keydown', handleGlobalEscapeKey);
123
+ }, [isTipHidden, isFloating, getFocusableElements, setTipIsHidden]);
124
+ useEffect(() => {
125
+ if (isTipHidden) return;
126
+ const timeoutId = setTimeout(() => {
127
+ popoverContentNodeRef.current?.focus();
128
+ }, 0);
129
+ return () => clearTimeout(timeoutId);
130
+ }, [isTipHidden]);
142
131
  const Tip = loaded && isFloating ? FloatingTip : InlineTip;
143
132
  const tipProps = useMemo(() => ({
144
133
  alignment,
145
134
  info,
146
135
  isTipHidden,
136
+ contentRef: popoverContentRef,
147
137
  wrapperRef,
148
- ...(isFloating && {
149
- popoverContentRef
150
- }),
151
138
  ...rest
152
- }), [alignment, info, isTipHidden, wrapperRef, isFloating, popoverContentRef, rest]);
153
- const extractedTextContent = useMemo(() => extractTextContent(info), [info]);
154
- const screenreaderInfo = shouldAnnounce && !isTipHidden ? extractedTextContent : '\xa0';
155
- const screenreaderText = useMemo(() => /*#__PURE__*/_jsx(ScreenreaderNavigableText, {
156
- "aria-hidden": isAriaHidden,
157
- "aria-live": "assertive",
158
- screenreader: true,
159
- children: screenreaderInfo
160
- }), [isAriaHidden, screenreaderInfo]);
161
- const button = useMemo(() => /*#__PURE__*/_jsx(InfoTipButton, {
162
- active: !isTipHidden,
163
- "aria-expanded": !isTipHidden,
164
- emphasis: emphasis,
165
- ref: buttonRef,
166
- onClick: clickHandler
167
- }), [isTipHidden, emphasis, clickHandler]);
168
-
169
- /*
170
- * For floating placement, screenreader text comes before button to maintain
171
- * correct DOM order despite Portal rendering. See GMT-64 for planned fix.
172
- */
139
+ }), [alignment, info, isTipHidden, popoverContentRef, wrapperRef, rest]);
173
140
  return /*#__PURE__*/_jsx(Tip, {
174
141
  ...tipProps,
175
142
  type: "info",
176
- children: isFloating && alignment.includes('top') ? /*#__PURE__*/_jsxs(_Fragment, {
177
- children: [screenreaderText, button]
178
- }) : /*#__PURE__*/_jsxs(_Fragment, {
179
- children: [button, screenreaderText]
143
+ children: /*#__PURE__*/_jsx(InfoTipButton, {
144
+ active: !isTipHidden,
145
+ "aria-expanded": !isTipHidden,
146
+ "aria-label": ariaLabel,
147
+ "aria-labelledby": ariaLabelledby,
148
+ "aria-roledescription": "More information button",
149
+ emphasis: emphasis,
150
+ ref: buttonRef,
151
+ onClick: clickHandler
180
152
  })
181
153
  });
182
154
  };
@@ -48,13 +48,10 @@ export declare const pressKey: (key: string) => Promise<void>;
48
48
  export declare const waitForLinkToHaveFocus: ({ view, linkText, }: ViewParam & LinkTextParam) => Promise<HTMLElement>;
49
49
  export declare const openTipAndWaitForLink: ({ view, linkText, }: ViewParam & LinkTextParam) => Promise<HTMLElement>;
50
50
  export declare const openTipTabToLinkAndWaitForFocus: (view: InfoTipView, linkText: string) => Promise<HTMLElement>;
51
- export declare const testShowTipOnClick: ({ view, info, placement, }: ViewParam & InfoParam & PlacementParam) => Promise<void>;
52
- export declare const testEscapeKeyReturnsFocus: ({ view, info, placement, }: ViewParam & InfoParam & PlacementParam) => Promise<void>;
53
- export declare const testFocusWrap: ({ view, containerRef, direction, }: ViewParam & {
54
- containerRef: RefObject<HTMLDivElement>;
51
+ export declare const testFocusWrap: ({ view, direction, }: ViewParam & {
55
52
  direction: 'forward' | 'backward';
56
53
  }) => Promise<void>;
57
- export declare const getTipContent: (view: InfoTipView, text: string, useQuery?: boolean) => HTMLElement;
54
+ export declare const testTabFromPopoverWithNoInteractiveElements: (view: InfoTipView) => Promise<void>;
58
55
  export declare const testTabbingBetweenLinks: ({ view, firstLinkText, secondLinkText, placement, }: ViewParam & {
59
56
  firstLinkText: string;
60
57
  secondLinkText: string;
@@ -86,18 +83,6 @@ type ViewWithQueries = {
86
83
  getAllByText: (text: string) => HTMLElement[];
87
84
  getAllByLabelText: (text: string) => HTMLElement[];
88
85
  };
89
- export declare const getVisibleTip: ({ text, placement, }: {
90
- text: string;
91
- placement?: "inline" | "floating" | undefined;
92
- }) => HTMLElement | undefined;
93
- export declare const expectTipToBeVisible: ({ text, placement, }: {
94
- text: string;
95
- placement?: "inline" | "floating" | undefined;
96
- }) => void;
97
- export declare const expectTipToBeClosed: ({ text, placement, }: {
98
- text: string;
99
- placement?: "inline" | "floating" | undefined;
100
- }) => void;
101
86
  export declare const openInfoTipsWithKeyboard: ({ view, count, }: {
102
87
  view: ViewWithQueries;
103
88
  count: number;
@@ -106,8 +91,5 @@ export declare const expectTipsVisible: (tips: {
106
91
  text: string;
107
92
  placement?: 'inline' | 'floating';
108
93
  }[]) => void;
109
- export declare const expectTipsClosed: (tips: {
110
- text: string;
111
- placement?: 'inline' | 'floating';
112
- }[]) => void;
94
+ export declare const expectTipsClosed: () => void;
113
95
  export {};
@@ -5,6 +5,8 @@ import { ToolTipProps } from '../ToolTip';
5
5
  export declare const ToolTipMock: React.FC<ToolTipProps & ComponentProps<typeof FillButton>>;
6
6
  export declare const InfoTipInsideModalMock: React.FC<Pick<InfoTipProps, 'info' | 'placement'>>;
7
7
  export declare const MultipleInfoTipsMock: React.FC<{
8
- tips: Array<Pick<InfoTipProps, 'info' | 'placement'>>;
8
+ tips: (Pick<InfoTipProps, 'info' | 'placement'> & {
9
+ id: string;
10
+ })[];
9
11
  includeOutsideElement?: boolean;
10
12
  }>;
@@ -18,7 +18,7 @@ export const FloatingTip = ({
18
18
  loading,
19
19
  narrow,
20
20
  overline,
21
- popoverContentRef,
21
+ contentRef,
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 ? e => escapeKeyPressHandler(e) : undefined,
126
+ onKeyDown: escapeKeyPressHandler,
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: popoverContentRef,
137
+ popoverContainerRef: contentRef,
138
138
  skipFocusTrap: true,
139
139
  targetRef: ref,
140
140
  variant: "secondary",
@@ -17,6 +17,7 @@ export const InlineTip = ({
17
17
  loading,
18
18
  narrow,
19
19
  overline,
20
+ contentRef,
20
21
  truncateLines,
21
22
  type,
22
23
  username,
@@ -42,7 +43,7 @@ export const InlineTip = ({
42
43
  height: inheritDims ? 'inherit' : undefined,
43
44
  ref: wrapperRef,
44
45
  width: inheritDims ? 'inherit' : undefined,
45
- onKeyDown: escapeKeyPressHandler ? e => escapeKeyPressHandler(e) : undefined,
46
+ onKeyDown: escapeKeyPressHandler,
46
47
  children: children
47
48
  });
48
49
  const tipBody = /*#__PURE__*/_jsx(InlineTipBodyWrapper, {
@@ -55,7 +56,9 @@ export const InlineTip = ({
55
56
  color: "currentColor",
56
57
  horizNarrow: narrow && isHorizontalCenter,
57
58
  id: id,
59
+ ref: contentRef,
58
60
  role: type === 'tool' ? 'tooltip' : undefined,
61
+ tabIndex: type === 'info' ? -1 : undefined,
59
62
  width: narrow && !isHorizontalCenter ? narrowWidth : 'max-content',
60
63
  zIndex: "auto",
61
64
  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
- popoverContentRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
49
+ contentRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
50
50
  type: 'info' | 'tool' | 'preview';
51
51
  wrapperRef?: React.RefObject<HTMLDivElement>;
52
52
  zIndex?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codecademy/gamut",
3
3
  "description": "Styleguide & Component library for Codecademy",
4
- "version": "67.4.2-alpha.b3304f.0",
4
+ "version": "67.4.2-alpha.b7c260.0",
5
5
  "author": "Codecademy Engineering <dev@codecademy.com>",
6
6
  "dependencies": {
7
7
  "@codecademy/gamut-icons": "9.52.1",
@@ -56,5 +56,5 @@
56
56
  "dist/**/[A-Z]**/[A-Z]*.js",
57
57
  "dist/**/[A-Z]**/index.js"
58
58
  ],
59
- "gitHead": "6b3b4d9e8f8c69654e70ccd8890133eb772cc86c"
59
+ "gitHead": "6432656246ee13d3f609f32fda6f67d9ae69aaef"
60
60
  }
@@ -1,12 +0,0 @@
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
- }, {}, {}>;
@@ -1,9 +0,0 @@
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,18 +0,0 @@
1
- /**
2
- * Recursively extracts plain text content from React children.
3
- *
4
- * Useful for converting JSX to plain text for accessibility purposes
5
- * like screenreader announcements or aria-labels.
6
- *
7
- * @param children - React children to extract text from
8
- * @returns Plain text string with all text content joined by spaces
9
- *
10
- * @example
11
- * ```tsx
12
- * const text = extractTextContent(
13
- * <div>Hello <strong>world</strong>!</div>
14
- * );
15
- * // Returns: "Hello world !"
16
- * ```
17
- */
18
- export declare const extractTextContent: (children: React.ReactNode) => string;
@@ -1,36 +0,0 @@
1
- import { Children, isValidElement } from 'react';
2
-
3
- /**
4
- * Recursively extracts plain text content from React children.
5
- *
6
- * Useful for converting JSX to plain text for accessibility purposes
7
- * like screenreader announcements or aria-labels.
8
- *
9
- * @param children - React children to extract text from
10
- * @returns Plain text string with all text content joined by spaces
11
- *
12
- * @example
13
- * ```tsx
14
- * const text = extractTextContent(
15
- * <div>Hello <strong>world</strong>!</div>
16
- * );
17
- * // Returns: "Hello world !"
18
- * ```
19
- */
20
- export const extractTextContent = children => {
21
- if (typeof children === 'string' || typeof children === 'number') {
22
- return String(children);
23
- }
24
- return Children.toArray(children).map(child => {
25
- if (typeof child === 'string' || typeof child === 'number') {
26
- return String(child);
27
- }
28
- if (typeof child === 'boolean' || child == null) {
29
- return '';
30
- }
31
- if (/*#__PURE__*/isValidElement(child)) {
32
- return extractTextContent(child.props.children);
33
- }
34
- return '';
35
- }).filter(Boolean).join(' ');
36
- };