Skip to content

Commit

Permalink
feat(react): add useLayer hook (#11654)
Browse files Browse the repository at this point in the history
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
joshblack and kodiakhq[bot] authored Jun 21, 2022
1 parent 524845d commit 8a9c11e
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8704,6 +8704,7 @@ Map {
"unstable_useContextMenu" => Object {},
"unstable_useFeatureFlag" => Object {},
"unstable_useFeatureFlags" => Object {},
"useLayer" => Object {},
"usePrefix" => Object {},
"useTheme" => Object {},
}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ describe('Carbon Components React', () => {
"unstable_useContextMenu",
"unstable_useFeatureFlag",
"unstable_useFeatureFlags",
"useLayer",
"usePrefix",
"useTheme",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,26 @@ import { ArgsTable, Canvas, Story } from '@storybook/addon-docs';
## Table of Contents

- [Overview](#overview)
- [Setting a custom level](#setting-a-custom-level)
- [Get the current layer](#get-the-current-layer)
- [Component API](#component-api)
- [Layer as](#layer-as)
- [Feedback](#feedback)

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

- You can nest layer components, up to the max
- TODO: can you explicitly set the layer
- What styles do I need to bring into my project for this to work
- How do I set the layer background?

## Overview

The `Layer` component complements the layering model for the Carbon Design
System. It is used to render components on different "layers" in order to
correctly map contextual tokens to their correct values. In general, this means
that areas of a page that are "on top of" other areas of a page will need to use
this component.

Any component that is rendered as a child to `Layer` will automatically map the
correct colors. For your own custom components to follow this model, make sure
they're using the contextual tokens.
The `Layer` component is used to render components on different layers. Each
layer has a specific set of token values associated with it. You can use these
tokens directly, or use contextual tokens from our styles package like `$layer`
or `$field`.

<Canvas>
<Story id="components-layer--default" />
</Canvas>

## Setting a custom level

<Canvas>
<Story id="components-layer--custom-level" />
</Canvas>

## Overview

The `Layer` component is used to render components on different layers. Each
layer has a specific set of token values associated with it. You can use these
tokens directly, or use contextual tokens from our styles package like `$layer`
or `$field`.

The `Layer` component accepts `children` as a prop. Each child of a `Layer`
component is rendered using the layer tokens at that layer. `Layer` components
Expand All @@ -67,6 +47,41 @@ can be nested indefinitely, but the token sets typically end after 3 layers.
</Layer>
```

## Setting a custom level

You can override the `level` of a `Layer` if you would like to change the presentation of a layer in your application. This is particularly helpful if you would like to reset the `Layer` level back to `0` or if you want to make sure a part of a page always renders in a certain level.

To do this, you can use the `level` prop:

```jsx
<Layer>
<ChildComponent />
<Layer level={0}>
<ChildComponent />
</Layer>
</Layer>
```

## Get the current layer

If you are building a component and would like to know what layer the component
resides within, you can use the `useLayer` hook.

This hook returns an object with the current `level` of the layer:

```jsx
function ExampleComponent() {
const { level } = useLayer();

// ...
}
```

If the structure of `Layer` components in your app change, the hook will automatically update with the new `level`.

The `level` value can be one of: `0`, `1`, or `2` and will correspond to the level of
the current layer. This value mirrors the `level` prop on the `Layer` component.

## Component API

<ArgsTable />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import './Layer-story.scss';
import React from 'react';
import { Layer } from '../../Layer';
import { Layer, useLayer } from '../Layer';
import mdx from './Layer.mdx';

export default {
Expand Down Expand Up @@ -73,6 +73,30 @@ export const CustomLevel = () => {
);
};

export const UseLayer = () => {
function ExampleComponent() {
const { level } = useLayer();
return (
<div style={{ padding: '1rem', background: 'var(--cds-layer)' }}>
The current layer level is: {level}
</div>
);
}

return (
<>
<ExampleComponent />
<Layer>
<ExampleComponent />
</Layer>
</>
);
};

UseLayer.story = {
name: 'useLayer',
};

const PlaygroundStory = (args) => {
function TestComponent() {
return <div className="example-layer-test-component">Test component</div>;
Expand Down
64 changes: 64 additions & 0 deletions packages/react/src/components/Layer/__tests__/useLayer-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* 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 { Layer, useLayer } from '../../Layer';

describe('useLayer', () => {
test('default value', () => {
const values = [];

function TestComponent() {
const value = useLayer();
values.push(value);
return null;
}

render(<TestComponent />);

expect(values).toEqual([
{
level: 1,
},
]);
});

test('nesting', () => {
const values = [];

function TestComponent() {
const value = useLayer();
values.push(value);
return null;
}

render(
<>
<TestComponent />
<Layer>
<TestComponent />
<Layer>
<TestComponent />
</Layer>
</Layer>
</>
);

expect(values).toEqual([
{
level: 1,
},
{
level: 2,
},
{
level: 2,
},
]);
});
});
12 changes: 12 additions & 0 deletions packages/react/src/components/Layer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ import { LayerContext } from './LayerContext';
const levels = ['one', 'two', 'three'];
const MAX_LEVEL = levels.length - 1;

/**
* A custom hook that will return information about the current layer. A common
* field to pull from this is the `level` for the layer that the component that
* calls this hook is currently in
*/
export function useLayer() {
const level = React.useContext(LayerContext);
return {
level,
};
}

export function Layer({
as: BaseComponent = 'div',
className: customClassName,
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export {
} from './components/FeatureFlags';
export { Heading, Section } from './components/Heading';
export { IconButton } from './components/IconButton';
export { Layer } from './components/Layer';
export { Layer, useLayer } from './components/Layer';
export unstable_Menu, {
MenuDivider as unstable_MenuDivider,
MenuGroup as unstable_MenuGroup,
Expand Down

0 comments on commit 8a9c11e

Please sign in to comment.