diff --git a/package.json b/package.json
index 2beb194..a4485c6 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,9 @@
"peerDependencies": {
"react": "*"
},
+ "dependencies": {
+ "classnames": "^2.5.1"
+ },
"devDependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.0.0",
@@ -52,8 +55,5 @@
"type": "git",
"url": "git+https://github.com/rain-cafe/react-utils.git"
},
- "license": "MIT",
- "dependencies": {
- "classnames": "^2.5.1"
- }
+ "license": "MIT"
}
diff --git a/src/hooks/__tests__/use-cached-state.spec.tsx b/src/hooks/__tests__/use-cached-state.spec.tsx
index 17b82c1..5f369a8 100644
--- a/src/hooks/__tests__/use-cached-state.spec.tsx
+++ b/src/hooks/__tests__/use-cached-state.spec.tsx
@@ -1,23 +1,19 @@
import { render } from '@testing-library/react';
-import { useCachedState, useReadOnlyCachedState } from '../use-cached-state';
+import { useCachedState, useClassNames, useReadOnlyCachedState } from '../use-cached-state';
import Chance from 'chance';
const chance = new Chance();
-type ExampleComponentProps = {
- value: string;
-};
-
describe('Cached State Hooks', () => {
describe('hook(useCachedState)', () => {
- function ExampleComponent({
- value
- }: ExampleComponentProps) {
+ type ExampleComponentProps = {
+ value: string;
+ };
+
+ function ExampleComponent({ value }: ExampleComponentProps) {
const [internalValue] = useCachedState(() => value, [value]);
- return (
-
{internalValue}
- );
+ return {internalValue}
;
}
it('should cache the value', () => {
@@ -30,14 +26,14 @@ describe('Cached State Hooks', () => {
});
describe('hook(useReadOnlyCachedState)', () => {
- function ExampleComponent({
- value
- }: ExampleComponentProps) {
+ type ExampleComponentProps = {
+ value: string;
+ };
+
+ function ExampleComponent({ value }: ExampleComponentProps) {
const internalValue = useReadOnlyCachedState(() => value, [value]);
- return (
- {internalValue}
- );
+ return {internalValue}
;
}
it('should cache the value', () => {
@@ -48,4 +44,28 @@ describe('Cached State Hooks', () => {
expect(component.getByText(expectedValue)).toBeTruthy();
});
});
+
+ describe('hook(useClassNames)', () => {
+ type ExampleComponentProps = {
+ sticky?: boolean;
+ };
+
+ function ExampleComponent({ sticky }: ExampleComponentProps) {
+ const classes = useClassNames(['my-class', sticky && 'sticky']);
+
+ return ;
+ }
+
+ it('should support base classes', () => {
+ const component = render();
+
+ expect(component.getByTestId('example').className).toEqual('my-class');
+ });
+
+ it('should support conditional classes', () => {
+ const component = render();
+
+ expect(component.getByTestId('example').className).toEqual('my-class sticky');
+ });
+ });
});
diff --git a/src/hooks/use-cached-state.ts b/src/hooks/use-cached-state.ts
index d16f499..4f0885d 100644
--- a/src/hooks/use-cached-state.ts
+++ b/src/hooks/use-cached-state.ts
@@ -1,3 +1,4 @@
+import classNames, { ArgumentArray } from 'classnames';
import { DependencyList, Dispatch, SetStateAction, useEffect, useState } from 'react';
export function useCachedState(
@@ -16,3 +17,9 @@ export function useReadOnlyCachedState(supplier: () => T, deps: DependencyLis
return value;
}
+
+export function useClassNames(deps: ArgumentArray): string {
+ return useReadOnlyCachedState(() => {
+ return classNames(deps);
+ }, deps);
+}