Skip to content

Commit

Permalink
Update multiple functional components to useGeneratedHtmlId hook (#5195)
Browse files Browse the repository at this point in the history
* [Fix] EuiButtonGroup generated ID

* [Fix] EuiCard aria IDs

* [Fix] EuiTour title ID

* [Fix] EuiKeyPadMenuItem generated ID

* [Fix] Multiple EuiNotificationEvent generated IDs

* [Fix] EuiHeaderAlert generated ID

* [Fix] EuiMarkdownEditor checkboxes generated IDs

* [Refactor] EuiMarkdownEditor ID

- remove existing useMemo hook in favor of new helper

- behavior should remain same as before

* [Refactor] EuiResizeableContainer IDs

- replace useRefs with new hook

- behavior should remain same as before

* [Refactor] EuiSwitch IDs

- replace useState with new hook

- behavior should remain same as before

* Add changelog entry
  • Loading branch information
Constance committed Sep 21, 2021
1 parent 987d269 commit 91baf67
Show file tree
Hide file tree
Showing 15 changed files with 62 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

- Fixed `EuiDataGrid` focus ring to be contained in the cell ([#5194](https://github.com/elastic/eui/pull/5194))
- Fixed `EuiDataGrid` cells when focused getting a higher `z-index` which was causing long content to overlap surrounding cells ([#5194](https://github.com/elastic/eui/pull/5194))
- Fixed multiple components unnecessarily rerendering generated IDs on every update ([#5195](https://github.com/elastic/eui/pull/5195), [#5196](https://github.com/elastic/eui/pull/5196), [#5197](https://github.com/elastic/eui/pull/5197), [#5200](https://github.com/elastic/eui/pull/#5200), [#5201](https://github.com/elastic/eui/pull/#5201))

**Theme: Amsterdam**

Expand Down
4 changes: 2 additions & 2 deletions src/components/button/button_group/button_group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { EuiButtonGroupButton } from './button_group_button';
import { colorToClassNameMap, ButtonColor } from '../button';
import { EuiButtonContentProps } from '../button_content';
import { CommonProps } from '../../common';
import { htmlIdGenerator } from '../../../services';
import { useGeneratedHtmlId } from '../../../services';

export interface EuiButtonGroupOptionProps
extends EuiButtonContentProps,
Expand Down Expand Up @@ -156,7 +156,7 @@ export const EuiButtonGroup: FunctionComponent<Props> = ({
);

const typeIsSingle = type === 'single';
const nameIfSingle = name || htmlIdGenerator()();
const nameIfSingle = useGeneratedHtmlId({ conditionalId: name });

return (
<fieldset className={classes} {...rest} disabled={isDisabled}>
Expand Down
6 changes: 3 additions & 3 deletions src/components/button/button_group/button_group_button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
*/

import classNames from 'classnames';
import React, { FunctionComponent, useRef } from 'react';
import React, { FunctionComponent } from 'react';
import { EuiButtonDisplay } from '../button';
import { EuiButtonGroupOptionProps, EuiButtonGroupProps } from './button_group';
import { useInnerText } from '../../inner_text';
import { htmlIdGenerator } from '../../../services';
import { useGeneratedHtmlId } from '../../../services';

type Props = EuiButtonGroupOptionProps & {
/**
Expand Down Expand Up @@ -65,7 +65,7 @@ export const EuiButtonGroupButton: FunctionComponent<Props> = ({
}) => {
// Force element to be a button if disabled
const el = isDisabled ? 'button' : element;
const newId = useRef(htmlIdGenerator()()).current;
const newId = useGeneratedHtmlId();

let elementProps = {};
let singleInput;
Expand Down
4 changes: 2 additions & 2 deletions src/components/card/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
EuiCardSelectProps,
euiCardSelectableColor,
} from './card_select';
import { htmlIdGenerator } from '../../services/accessibility';
import { useGeneratedHtmlId } from '../../services/accessibility';
import { validateHref } from '../../services/security/href_validator';
import { EuiPanel, EuiPanelProps } from '../panel';

Expand Down Expand Up @@ -244,7 +244,7 @@ export const EuiCard: FunctionComponent<EuiCardProps> = ({
className
);

const ariaId = htmlIdGenerator()();
const ariaId = useGeneratedHtmlId();
const ariaDesc = description ? `${ariaId}Description` : '';

/**
Expand Down
7 changes: 3 additions & 4 deletions src/components/form/switch/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ import React, {
HTMLAttributes,
FunctionComponent,
ReactNode,
useState,
useCallback,
} from 'react';
import classNames from 'classnames';

import { CommonProps } from '../../common';
import { htmlIdGenerator } from '../../../services/accessibility';
import { useGeneratedHtmlId } from '../../../services/accessibility';
import { EuiIcon } from '../../icon';

export type EuiSwitchEvent = React.BaseSyntheticEvent<
Expand Down Expand Up @@ -65,8 +64,8 @@ export const EuiSwitch: FunctionComponent<EuiSwitchProps> = ({
labelProps,
...rest
}) => {
const [switchId] = useState(id || htmlIdGenerator()());
const [labelId] = useState(labelProps?.id || htmlIdGenerator()());
const switchId = useGeneratedHtmlId({ conditionalId: id });
const labelId = useGeneratedHtmlId({ conditionalId: labelProps?.id });

const onClick = useCallback(
(e: React.MouseEvent<HTMLButtonElement | HTMLParagraphElement>) => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/header/header_alert/header_alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import classNames from 'classnames';
import { CommonProps } from '../../common';

import { EuiFlexGroup, EuiFlexItem } from '../../flex';
import { htmlIdGenerator } from '../../../services';
import { useGeneratedHtmlId } from '../../../services';

export type EuiHeaderAlertProps = CommonProps &
Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {
Expand Down Expand Up @@ -40,7 +40,7 @@ export const EuiHeaderAlert: FunctionComponent<EuiHeaderAlertProps> = ({
}) => {
const classes = classNames('euiHeaderAlert', className);

const ariaId = htmlIdGenerator()();
const ariaId = useGeneratedHtmlId();

return (
<article aria-labelledby={`${ariaId}-title`} className={classes} {...rest}>
Expand Down
4 changes: 2 additions & 2 deletions src/components/key_pad_menu/key_pad_menu_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {

import { EuiBetaBadge } from '../badge/beta_badge';

import { getSecureRelForTarget, htmlIdGenerator } from '../../services';
import { getSecureRelForTarget, useGeneratedHtmlId } from '../../services';

import { IconType } from '../icon';
import { EuiRadio, EuiCheckbox } from '../form';
Expand Down Expand Up @@ -184,7 +184,7 @@ export const EuiKeyPadMenuItem: FunctionComponent<EuiKeyPadMenuItemProps> = ({
if (checkable) Element = 'label';
type ElementType = ReactElementType<typeof Element>;

const itemId = id || htmlIdGenerator()();
const itemId = useGeneratedHtmlId({ conditionalId: id });

const renderCheckableElement = () => {
if (!checkable) return;
Expand Down
6 changes: 2 additions & 4 deletions src/components/markdown_editor/markdown_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
} from './markdown_editor_text_area';
import { EuiMarkdownFormat, EuiMarkdownFormatProps } from './markdown_format';
import { EuiMarkdownEditorDropZone } from './markdown_editor_drop_zone';
import { htmlIdGenerator } from '../../services/';
import { useGeneratedHtmlId } from '../../services/';

import { MARKDOWN_MODE, MODE_EDITING, MODE_VIEWING } from './markdown_modes';
import {
Expand Down Expand Up @@ -214,9 +214,7 @@ export const EuiMarkdownEditor = forwardRef<
ref
) => {
const [viewMode, setViewMode] = useState<MARKDOWN_MODE>(initialViewMode);
const editorId = useMemo(() => _editorId || htmlIdGenerator()(), [
_editorId,
]);
const editorId = useGeneratedHtmlId({ conditionalId: _editorId });

const [pluginEditorPlugin, setPluginEditorPlugin] = useState<
EuiMarkdownEditorUiPlugin | undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import React, { FunctionComponent, useContext } from 'react';
import { EuiCheckbox } from '../../../form/checkbox';
import { EuiMarkdownContext } from '../../markdown_context';
import { htmlIdGenerator } from '../../../../services/accessibility';
import { useGeneratedHtmlId } from '../../../../services/accessibility';
import { EuiMarkdownAstNodePosition } from '../../markdown_types';
import { CheckboxNodeDetails } from './types';

Expand All @@ -21,7 +21,7 @@ export const CheckboxMarkdownRenderer: FunctionComponent<
const { replaceNode } = useContext(EuiMarkdownContext);
return (
<EuiCheckbox
id={htmlIdGenerator()()}
id={useGeneratedHtmlId()}
checked={isChecked}
label={children}
onChange={() => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/notification/notification_event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
import { EuiButtonEmpty, EuiButtonEmptyProps } from '../button';
import { EuiLink } from '../link';
import { EuiContextMenuItem, EuiContextMenuItemProps } from '../context_menu';
import { htmlIdGenerator } from '../../services';
import { useGeneratedHtmlId } from '../../services';
import { EuiNotificationEventReadIcon } from './notification_event_read_icon';

export type EuiNotificationHeadingLevel = 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
Expand Down Expand Up @@ -113,7 +113,7 @@ export const EuiNotificationEvent: FunctionComponent<EuiNotificationEventProps>
'euiNotificationEvent__title--isRead': isRead,
});

const randomHeadingId = htmlIdGenerator()();
const randomHeadingId = useGeneratedHtmlId();

const titleProps = {
id: randomHeadingId,
Expand Down
8 changes: 6 additions & 2 deletions src/components/notification/notification_event_messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import React, { FunctionComponent, useState } from 'react';
import { EuiAccordion } from '../accordion';
import { htmlIdGenerator } from '../../services';
import { useGeneratedHtmlId } from '../../services';
import { useEuiI18n } from '../i18n';
import { EuiText } from '../text';

Expand All @@ -30,6 +30,10 @@ export const EuiNotificationEventMessages: FunctionComponent<EuiNotificationEven
const [isOpen, setIsOpen] = useState(false);
const messagesLength = messages.length;

const accordionId = useGeneratedHtmlId({
prefix: 'euiNotificationEventMessagesAccordion',
});

const accordionButtonText = useEuiI18n(
'euiNotificationEventMessages.accordionButtonText',
'+ {messagesLength} more',
Expand Down Expand Up @@ -69,7 +73,7 @@ export const EuiNotificationEventMessages: FunctionComponent<EuiNotificationEven
<EuiAccordion
onToggle={setIsOpen}
buttonProps={{ 'aria-label': accordionAriaLabelButtonText }}
id={htmlIdGenerator('euiNotificationEventMessagesAccordion')()}
id={accordionId}
className="euiNotificationEventMessages__accordion"
buttonContent={buttonContentText}
buttonClassName="euiNotificationEventMessages__accordionButton"
Expand Down
4 changes: 2 additions & 2 deletions src/components/notification/notification_event_meta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
EuiContextMenuPanel,
} from '../context_menu';
import { EuiI18n } from '../i18n';
import { htmlIdGenerator } from '../../services';
import { useGeneratedHtmlId } from '../../services';

export type EuiNotificationEventMetaProps = {
id: string;
Expand Down Expand Up @@ -85,7 +85,7 @@ export const EuiNotificationEventMeta: FunctionComponent<EuiNotificationEventMet
ReturnType<NonNullable<typeof onOpenContextMenu>>
>([]);

const randomPopoverId = htmlIdGenerator()();
const randomPopoverId = useGeneratedHtmlId();

const ariaAttribute = iconAriaLabel
? { 'aria-label': iconAriaLabel }
Expand Down
26 changes: 12 additions & 14 deletions src/components/resizable_container/resizable_button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import classNames from 'classnames';

import { CommonProps } from '../common';
import { EuiI18n } from '../i18n';
import { htmlIdGenerator } from '../../services';
import { useGeneratedHtmlId } from '../../services';
import { useEuiResizableContainerContext } from './context';
import {
EuiResizableButtonController,
Expand Down Expand Up @@ -47,8 +47,6 @@ export interface EuiResizableButtonProps
CommonProps,
Partial<EuiResizableButtonControls> {}

const generatePanelId = htmlIdGenerator('resizable-button');

export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
isHorizontal,
className,
Expand All @@ -59,15 +57,16 @@ export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
onBlur,
...rest
}) => {
const resizerId = useRef(id || generatePanelId());
const resizerId = useGeneratedHtmlId({
prefix: 'resizable-button',
conditionalId: id,
});
const {
registry: { resizers } = { resizers: {} },
} = useEuiResizableContainerContext();
const isDisabled = useMemo(
() =>
disabled ||
(resizers[resizerId.current] && resizers[resizerId.current].isDisabled),
[resizers, disabled]
() => disabled || (resizers[resizerId] && resizers[resizerId].isDisabled),
[resizers, resizerId, disabled]
);
const classes = classNames(
'euiResizableButton',
Expand All @@ -83,30 +82,29 @@ export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
const onRef = useCallback(
(ref: HTMLElement | null) => {
if (!registration) return;
const id = resizerId.current;
if (ref) {
previousRef.current = ref;
registration.register({
id,
id: resizerId,
ref,
isFocused: false,
isDisabled: disabled || false,
});
} else {
if (previousRef.current != null) {
registration.deregister(id);
registration.deregister(resizerId);
previousRef.current = undefined;
}
}
},
[registration, disabled]
[registration, resizerId, disabled]
);

const setFocus = (e: MouseEvent<HTMLButtonElement>) =>
e.currentTarget.focus();

const handleFocus = () => {
onFocus && onFocus(resizerId.current);
onFocus && onFocus(resizerId);
};

return (
Expand All @@ -122,7 +120,7 @@ export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
>
{([horizontalResizerAriaLabel, verticalResizerAriaLabel]: string[]) => (
<button
id={resizerId.current}
id={resizerId}
ref={onRef}
aria-label={
isHorizontal ? horizontalResizerAriaLabel : verticalResizerAriaLabel
Expand Down
Loading

0 comments on commit 91baf67

Please sign in to comment.