Skip to content

Commit

Permalink
Fix types for translateWithId() methods. (#17055)
Browse files Browse the repository at this point in the history
* fix: translateWithId() parameter types

Add proper types for parameter to translateWithId() methods.

Each component's translateWithId() method can only take a certain
list of keys, not any string.  Update the Typescript to notate this.

For historical reasons most of the existing translation keys are
declared in a convoluted way.  For example:

export const translationIds = {
  'increment.number': 'increment.number',
  'decrement.number': 'decrement.number',
};

type TranslationKey = keyof typeof translationIds;

The simpler way is just:

type TranslationKey = 'increment.number' |  'decrement.number’;

I didn’t update that in this PR, but it’s something to consider for the future.
Note that TableToolbarSearch.tsx and MultiSelect.tsx don’t suffer from this
problem.

Refs #12513.

* chore: extend InternationalProps instead of declaring translateWithId()

Refs #12513.

* chore: rename InternationalProps

---------

Co-authored-by: Taylor Jones <[email protected]>
  • Loading branch information
wkeese and tay1orjones authored Jul 31, 2024
1 parent 50e88bc commit df0e941
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 141 deletions.
31 changes: 23 additions & 8 deletions packages/react/src/components/ComboBox/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import deprecate from '../../prop-types/deprecate';
import { usePrefix } from '../../internal/usePrefix';
import { FormContext } from '../FluidForm';
import { useFloating, flip, autoUpdate } from '@floating-ui/react';
import { TranslateWithId } from '../../types/common';

const {
InputBlur,
Expand Down Expand Up @@ -129,9 +130,23 @@ interface OnChangeData<ItemType> {
inputValue?: string | null;
}

/**
* Message ids that will be passed to translateWithId().
* Combination of message ids from ListBox/next/ListBoxSelection.js and
* ListBox/next/ListBoxTrigger.js, but we can't access those values directly
* because those components aren't Typescript. (If you try, TranslationKey
* ends up just being defined as "string".)
*/
type TranslationKey =
| 'close.menu'
| 'open.menu'
| 'clear.all'
| 'clear.selection';

type ItemToStringHandler<ItemType> = (item: ItemType | null) => string;
export interface ComboBoxProps<ItemType>
extends Omit<InputHTMLAttributes<HTMLInputElement>, ExcludedAttributes> {
extends Omit<InputHTMLAttributes<HTMLInputElement>, ExcludedAttributes>,
TranslateWithId<TranslationKey> {
/**
* Specify whether or not the ComboBox should allow a value that is
* not in the list to be entered in the input
Expand Down Expand Up @@ -295,12 +310,6 @@ export interface ComboBoxProps<ItemType>
*/
titleText?: ReactNode;

/**
* Specify a custom translation function that takes in a message identifier
* and returns the localized string for the message
*/
translateWithId?: (id: string) => string;

/**
* Specify whether the control is currently in warning state
*/
Expand Down Expand Up @@ -661,7 +670,13 @@ const ComboBox = forwardRef(
'aria-label': deprecatedAriaLabel || ariaLabel,
ref: autoAlign ? refs.setFloating : null,
}),
[autoAlign, deprecatedAriaLabel, ariaLabel]
[
autoAlign,
deprecatedAriaLabel,
ariaLabel,
getMenuProps,
refs.setFloating,
]
);

return (
Expand Down
14 changes: 7 additions & 7 deletions packages/react/src/components/ComboButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,22 @@ import {
} from '@floating-ui/react';
import mergeRefs from '../../tools/mergeRefs';
import { MenuAlignment } from '../MenuButton';
import { TranslateWithId } from '../../types/common';

const defaultTranslations = {
'carbon.combo-button.additional-actions': 'Additional actions',
};

/**
* Message ids that will be passed to translateWithId().
*/
type TranslationKey = keyof typeof defaultTranslations;

function defaultTranslateWithId(messageId: string) {
return defaultTranslations[messageId];
}

interface ComboButtonProps {
interface ComboButtonProps extends TranslateWithId<TranslationKey> {
/**
* A collection of `MenuItems` to be rendered as additional actions for this `ComboButton`.
*/
Expand Down Expand Up @@ -72,12 +78,6 @@ interface ComboButtonProps {
* Specify how the trigger tooltip should be aligned.
*/
tooltipAlignment?: React.ComponentProps<typeof IconButton>['align'];

/**
* Optional method that takes in a message `id` and returns an
* internationalized string.
*/
translateWithId?: (id: string) => string;
}

const ComboButton = React.forwardRef<HTMLDivElement, ComboButtonProps>(
Expand Down
12 changes: 9 additions & 3 deletions packages/react/src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import TableToolbarAction from './TableToolbarAction';
import TableToolbarContent from './TableToolbarContent';
import TableToolbarSearch from './TableToolbarSearch';
import TableToolbarMenu from './TableToolbarMenu';
import { TranslateWithId } from '../../types/common';

const getInstanceId = setupGetInstanceId();

Expand All @@ -49,7 +50,12 @@ const translationKeys = {
unselectAll: 'carbon.table.all.unselect',
selectRow: 'carbon.table.row.select',
unselectRow: 'carbon.table.row.unselect',
};
} as const;

/**
* Message ids that will be passed to translateWithId().
*/
type TranslationKey = (typeof translationKeys)[keyof typeof translationKeys];

const defaultTranslations = {
[translationKeys.expandAll]: 'Expand all rows',
Expand Down Expand Up @@ -211,7 +217,8 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
radio: boolean | undefined;
}

export interface DataTableProps<RowType, ColTypes extends any[]> {
export interface DataTableProps<RowType, ColTypes extends any[]>
extends TranslateWithId<TranslationKey> {
children?: (
renderProps: DataTableRenderProps<RowType, ColTypes>
) => React.ReactElement;
Expand Down Expand Up @@ -243,7 +250,6 @@ export interface DataTableProps<RowType, ColTypes extends any[]> {
}
) => number;
stickyHeader?: boolean;
translateWithId?: (id: string) => string;
useStaticWidth?: boolean;
useZebraStyles?: boolean;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/DataTable/TableBatchActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Button from '../Button';
import TableActionList from './TableActionList';
import { Text } from '../Text';
import { usePrefix } from '../../internal/usePrefix';
import type { InternationalProps } from '../../types/common';
import type { TranslateWithId } from '../../types/common';

const TableBatchActionsTranslationKeys = [
'carbon.table.batch.cancel',
Expand All @@ -31,7 +31,7 @@ export interface TableBatchActionsTranslationArgs {

export interface TableBatchActionsProps
extends React.HTMLAttributes<HTMLDivElement>,
InternationalProps<
TranslateWithId<
TableBatchActionsTranslationKey,
TableBatchActionsTranslationArgs
> {
Expand Down
18 changes: 6 additions & 12 deletions packages/react/src/components/DataTable/TableHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import classNames from 'classnames';
import { sortStates } from './state/sorting';
import { useId } from '../../internal/useId';
import { usePrefix } from '../../internal/usePrefix';
import { ReactAttr } from '../../types/common';
import { TranslateWithId, ReactAttr } from '../../types/common';
import { DataTableSortState } from './state/sortStates';

const defaultScope = 'col';
Expand Down Expand Up @@ -64,7 +64,11 @@ const sortDirections: { [key: string]: 'none' | 'ascending' | 'descending' } = {
};

interface TableHeaderProps
extends ReactAttr<HTMLTableCellElement & HTMLButtonElement> {
extends ReactAttr<HTMLTableCellElement & HTMLButtonElement>,
TranslateWithId<
TableHeaderTranslationKey,
{ header; sortDirection; isSortHeader; sortStates }
> {
/**
* Pass in children that will be embedded in the table header label
*/
Expand Down Expand Up @@ -119,16 +123,6 @@ interface TableHeaderProps
* NONE, or ASC.
*/
sortDirection?: string;

/**
* Supply a method to translate internal strings with your i18n tool of
* choice. Translation keys are available on the `translationKeys` field for
* this component.
*/
translateWithId?: (
key: TableHeaderTranslationKey,
{ header, sortDirection, isSortHeader, sortStates }
) => string;
}

const TableHeader = React.forwardRef(function TableHeader(
Expand Down
12 changes: 7 additions & 5 deletions packages/react/src/components/DataTable/TableToolbarSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import cx from 'classnames';
import PropTypes from 'prop-types';
import React, {
ChangeEvent,
useMemo,
useRef,
useState,
useEffect,
Expand All @@ -21,18 +20,21 @@ import Search, { SearchProps } from '../Search';
import { useId } from '../../internal/useId';
import { usePrefix } from '../../internal/usePrefix';
import { noopFn } from '../../internal/noopFn';
import { InternationalProps } from '../../types/common';
import { TranslateWithId } from '../../types/common';

/**
* Message ids that will be passed to translateWithId().
*/
export type TableToolbarTranslationKey =
| 'carbon.table.toolbar.search.label'
| 'carbon.table.toolbar.search.placeholder';

const translationKeys = {
const translationKeys: Record<TableToolbarTranslationKey, string> = {
'carbon.table.toolbar.search.label': 'Filter table',
'carbon.table.toolbar.search.placeholder': 'Filter table',
};

const translateWithId = (id: string): string => {
const translateWithId = (id: TableToolbarTranslationKey): string => {
return translationKeys[id];
};

Expand All @@ -52,7 +54,7 @@ export type TableToolbarSearchHandleExpand = (

export interface TableToolbarSearchProps
extends Omit<SearchProps, ExcludedInheritedProps>,
InternationalProps<TableToolbarTranslationKey> {
TranslateWithId<TableToolbarTranslationKey> {
/**
* Specifies if the search should initially render in an expanded state
*/
Expand Down
13 changes: 3 additions & 10 deletions packages/react/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import mergeRefs from '../../tools/mergeRefs';
import deprecate from '../../prop-types/deprecate';
import { usePrefix } from '../../internal/usePrefix';
import { FormContext } from '../FluidForm';
import { ReactAttr } from '../../types/common';
import { TranslateWithId, ReactAttr } from '../../types/common';
import { useId } from '../../internal/useId';
import {
useFloating,
Expand Down Expand Up @@ -85,7 +85,8 @@ export interface OnChangeData<ItemType> {
}

export interface DropdownProps<ItemType>
extends Omit<ReactAttr<HTMLDivElement>, ExcludedAttributes> {
extends Omit<ReactAttr<HTMLDivElement>, ExcludedAttributes>,
TranslateWithId<ListBoxMenuIconTranslationKey> {
/**
* Specify a label to be read by screen readers on the container node
* 'aria-label' of the ListBox component.
Expand Down Expand Up @@ -220,14 +221,6 @@ export interface DropdownProps<ItemType>
*/
titleText?: ReactNode;

/**
* Callback function for translating ListBoxMenuIcon SVG title
*/
translateWithId?(
messageId: ListBoxMenuIconTranslationKey,
args?: Record<string, unknown>
): string;

/**
* The dropdown type, `default` or `inline`
*/
Expand Down
14 changes: 3 additions & 11 deletions packages/react/src/components/ListBox/ListBoxMenuIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { ChevronDown } from '@carbon/icons-react';
import { usePrefix } from '../../internal/usePrefix';
import { TranslateWithId } from '../../types/common';

export type ListBoxMenuIconTranslationKey = 'close.menu' | 'open.menu';

Expand All @@ -21,22 +22,13 @@ const defaultTranslations: Record<ListBoxMenuIconTranslationKey, string> = {
const defaultTranslateWithId = (id: ListBoxMenuIconTranslationKey): string =>
defaultTranslations[id];

export interface ListBoxMenuIconProps {
export interface ListBoxMenuIconProps
extends TranslateWithId<ListBoxMenuIconTranslationKey> {
/**
* Specify whether the menu is currently open, which will influence the
* direction of the menu icon
*/
isOpen: boolean;

/**
* i18n hook used to provide the appropriate description for the given menu
* icon. This function takes in a ListBoxMenuIconTranslationKey and should
* return a string message for that given message id.
*/
translateWithId?(
messageId: ListBoxMenuIconTranslationKey,
args?: Record<string, unknown>
): string;
}

export type ListBoxMenuIconComponent = React.FC<ListBoxMenuIconProps>;
Expand Down
17 changes: 8 additions & 9 deletions packages/react/src/components/ListBox/ListBoxSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import PropTypes from 'prop-types';
import { Close } from '@carbon/icons-react';
import { usePrefix } from '../../internal/usePrefix';
import { KeyboardEvent, MouseEvent } from 'react';
import { TranslateWithId } from '../../types/common';

export interface ListBoxSelectionProps {
export interface ListBoxSelectionProps extends TranslateWithId<TranslationKey> {
/**
* Specify a function to be invoked when a user interacts with the clear
* selection element.
Expand Down Expand Up @@ -44,21 +45,19 @@ export interface ListBoxSelectionProps {
* whether the selection should display a badge or a single clear icon.
*/
selectionCount?: number;

/**
* i18n hook used to provide the appropriate description for the given menu
* icon. This function takes in an id defined in `translationIds` and should
* return a string message for that given message id.
*/
translateWithId?(messageId: string, args?: Record<string, unknown>): string;
}

export type ListBoxSelectionComponent = React.FC<ListBoxSelectionProps>;

export const translationIds = {
'clear.all': 'clear.all',
'clear.selection': 'clear.selection',
};
} as const;

/**
* Message ids that will be passed to translateWithId().
*/
type TranslationKey = keyof typeof translationIds;

const defaultTranslations = {
[translationIds['clear.all']]: 'Clear all selected items',
Expand Down
Loading

0 comments on commit df0e941

Please sign in to comment.