Skip to content

Commit

Permalink
feat(IdPrefix): add component, docs, tests (#12442)
Browse files Browse the repository at this point in the history
* feat(IdPrefix): add component, docs, tests

* feat(IdPrefix): add component, docs, tests

* fix(IdPrefix): update useId to use prefix, tests, and export IdPrefix

* chore: update snaps

* docs(IdPrefix): fix stories

* test(snaps): update snap

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
tay1orjones and kodiakhq[bot] authored Nov 14, 2022
1 parent d3f351d commit 133d294
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 3 deletions.
11 changes: 11 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3935,6 +3935,16 @@ Map {
},
"render": [Function],
},
"IdPrefix" => Object {
"propTypes": Object {
"children": Object {
"type": "node",
},
"prefix": Object {
"type": "string",
},
},
},
"InlineLoading" => Object {
"propTypes": Object {
"className": Object {
Expand Down Expand Up @@ -9984,6 +9994,7 @@ Map {
"unstable_useFeatureFlag" => Object {},
"unstable_useFeatureFlags" => Object {},
"unstable_useLayoutDirection" => Object {},
"useIdPrefix" => Object {},
"useLayer" => Object {},
"usePrefix" => Object {},
"useTheme" => Object {},
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe('Carbon Components React', () => {
"IconButton",
"IconSkeleton",
"IconTab",
"IdPrefix",
"InlineLoading",
"InlineNotification",
"Layer",
Expand Down Expand Up @@ -248,6 +249,7 @@ describe('Carbon Components React', () => {
"unstable_useFeatureFlag",
"unstable_useFeatureFlags",
"unstable_useLayoutDirection",
"useIdPrefix",
"useLayer",
"usePrefix",
"useTheme",
Expand Down
56 changes: 56 additions & 0 deletions packages/react/src/components/IdPrefix/IdPrefix.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Story, Props, Source, Preview } from '@storybook/addon-docs/blocks';
import { IdPrefix } from '../IdPrefix';

# Prefix

[Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/ClassPrefix)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

## Table of Contents

- [Overview](#overview)
- [Component API](#component-api)
- [Feedback](#feedback)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

The `IdPrefix` component is used to change the prefix applied to the
automatically generated `id` attributes placed on certain DOM elements.

<Preview>
<Story id="components-idprefix--default" />
</Preview>

This component is used intended to be used in limited cases, primarily only if
you have id conflics when using v10 and v11 packages at the same time during
migration.

In React, you can use `IdPrefix` anywhere in your component tree and specify the
prefix with the `prefix` prop. Most often it's used in the project root wrapping
the entire project:

```jsx
import { IdPrefix } from '@carbon/react';

export default function MyApp() {
return (
<IdPrefix prefix="custom">
<Page />
</IdPrefix>
);
}
```

## Component API

<Props />

## Feedback

Help us improve this component by providing feedback, asking questions on Slack,
or updating this file on
[GitHub](https://github.com/carbon-design-system/carbon/edit/main/packages/react/src/components/ClassPrefix/ClassPrefix.mdx).
37 changes: 37 additions & 0 deletions packages/react/src/components/IdPrefix/IdPrefix.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import { IdPrefix } from '.';
import { useIdPrefix } from '../../internal/useIdPrefix';
import mdx from './IdPrefix.mdx';

export default {
title: 'Components/IdPrefix',
component: IdPrefix,
parameters: {
docs: {
page: mdx,
},
},
};

export const Default = () => {
function ExampleComponent() {
const idPrefix = useIdPrefix();
return <p>The current id prefix is: {idPrefix}</p>;
}

return (
<>
<ExampleComponent />
<IdPrefix prefix="custom">
<ExampleComponent />
</IdPrefix>
</>
);
};
31 changes: 31 additions & 0 deletions packages/react/src/components/IdPrefix/__tests__/IdPrefix-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { render } from '@testing-library/react';
import React from 'react';
import { IdPrefix } from '../../IdPrefix';
import { useIdPrefix } from '../../../internal/useIdPrefix';

describe('IdPrefix', () => {
it('should set the prefix value used by usePrefix', () => {
const calls = [];

function TestComponent() {
const prefix = useIdPrefix();
calls.push(prefix);
return null;
}

render(
<IdPrefix prefix="custom">
<TestComponent />
</IdPrefix>
);

expect(calls).toEqual(['custom']);
});
});
29 changes: 29 additions & 0 deletions packages/react/src/components/IdPrefix/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import PropTypes from 'prop-types';
import React from 'react';
import { IdPrefixContext } from '../../internal/useIdPrefix';

function IdPrefix({ children, prefix }) {
return (
<IdPrefixContext.Provider value={prefix}>
{children}
</IdPrefixContext.Provider>
);
}

IdPrefix.propTypes = {
children: PropTypes.node,

/**
* The value used to prefix the auto-generated id placed on some DOM elements
*/
prefix: PropTypes.string,
};

export { IdPrefix };
2 changes: 2 additions & 0 deletions packages/react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export FormGroup from './components/FormGroup';
export FormItem from './components/FormItem';
export FormLabel from './components/FormLabel';
export { Grid, Row, Column, ColumnHang, FlexGrid } from './components/Grid';
export { IdPrefix } from './components/IdPrefix';
export InlineLoading from './components/InlineLoading';
export Link from './components/Link';
export ListItem from './components/ListItem';
Expand Down Expand Up @@ -271,3 +272,4 @@ export {
export { DefinitionTooltip } from './components/Tooltip/next/DefinitionTooltip';
export { GlobalTheme, Theme, useTheme } from './components/Theme';
export { usePrefix } from './internal/usePrefix';
export { useIdPrefix } from './internal/useIdPrefix';
41 changes: 41 additions & 0 deletions packages/react/src/internal/__tests__/useIdPrefix-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright IBM Corp. 2020
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { cleanup, render } from '@testing-library/react';
import React from 'react';
import { useIdPrefix, IdPrefixContext } from '../useIdPrefix';

describe('usePrefix', () => {
afterEach(cleanup);

it('should emit the default prefix without context', () => {
let value = null;

function TestComponent() {
value = useIdPrefix();
return null;
}

render(<TestComponent />);
expect(value).toBe(null);
});

it('should emit the prefix in context', () => {
function TestComponent() {
const contextValue = useIdPrefix();
return <span data-testid="test">{contextValue}</span>;
}

const { getByTestId } = render(
<IdPrefixContext.Provider value="test">
<TestComponent />
</IdPrefixContext.Provider>
);

expect(getByTestId('test')).toHaveTextContent('test');
});
});
3 changes: 2 additions & 1 deletion packages/react/src/internal/__tests__/usePrefix-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ describe('usePrefix', () => {

it('should emit the prefix in context', () => {
function TestComponent() {
return <span data-testid="test">test</span>;
const contextValue = usePrefix();
return <span data-testid="test">{contextValue}</span>;
}

const { getByTestId } = render(
Expand Down
7 changes: 5 additions & 2 deletions packages/react/src/internal/useId.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import { useEffect, useLayoutEffect, useState } from 'react';
import setupGetInstanceId from '../tools/setupGetInstanceId';
import { canUseDOM } from './environment';
import { useIdPrefix } from './useIdPrefix';

const getId = setupGetInstanceId();
const useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
Expand All @@ -38,16 +39,18 @@ let serverHandoffCompleted = false;
* @returns {string}
*/
export function useId(prefix = 'id') {
const _prefix = useIdPrefix();

const [id, setId] = useState(() => {
if (serverHandoffCompleted) {
return `${prefix}-${getId()}`;
return `${_prefix ? `${_prefix}-` : ``}${prefix}-${getId()}`;
}
return null;
});

useIsomorphicLayoutEffect(() => {
if (id === null) {
setId(`${prefix}-${getId()}`);
setId(`${_prefix ? `${_prefix}-` : ``}${prefix}-${getId()}`);
}
}, [getId]);

Expand Down
14 changes: 14 additions & 0 deletions packages/react/src/internal/useIdPrefix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';

export const IdPrefixContext = React.createContext(null);

export function useIdPrefix() {
return React.useContext(IdPrefixContext);
}

0 comments on commit 133d294

Please sign in to comment.