From 8df1b5359b7090666fbc7f04b87ea50c55797bea Mon Sep 17 00:00:00 2001
From: German Shteinardt <shteinardt@yandex-team.ru>
Date: Thu, 9 May 2024 11:52:57 +0200
Subject: [PATCH] fix: fixed comments after review

---
 src/hooks/index.ts                            |  2 +-
 src/hooks/useColorGenerator/README.md         | 26 +++++++
 .../__stories__/ColorGenerator.scss           | 12 ++++
 .../__stories__/ColoredAvatar.tsx             | 36 ++++++++++
 .../__stories__/useColorGenerator.stories.tsx | 69 +++++++++++++++++++
 .../__tests__/getHue.test.ts                  | 24 +++++++
 .../__tests__/randomIndex.test.ts             | 23 +++++++
 .../__tests__}/utils/randomString.ts          |  0
 .../utils => useColorGenerator}/color.ts      | 55 +++++++++------
 .../utils => useColorGenerator}/constants.ts  |  2 +-
 src/hooks/useColorGenerator/index.ts          |  2 +
 .../types.ts                                  |  2 +-
 .../useColorGenerator.ts}                     | 12 ++--
 src/hooks/useColorGenerator/utils.ts          | 51 ++++++++++++++
 src/hooks/useGeneratorColor/README.md         | 28 --------
 .../useGeneratorColor/__stories__/Color.tsx   | 30 --------
 .../__stories__/GeneratorColor.scss           | 18 -----
 .../__stories__/UseGeneratorColor.stories.tsx | 57 ---------------
 .../__stories__/constants.ts                  |  5 --
 src/hooks/useGeneratorColor/index.ts          |  2 -
 src/hooks/useGeneratorColor/utils/getHue.ts   |  9 ---
 .../useGeneratorColor/utils/hashFnv32a.ts     | 12 ----
 src/hooks/useGeneratorColor/utils/mathFrac.ts |  2 -
 .../useGeneratorColor/utils/normalizeHash.ts  |  7 --
 .../useGeneratorColor/utils/randomIndex.ts    | 18 -----
 25 files changed, 285 insertions(+), 219 deletions(-)
 create mode 100644 src/hooks/useColorGenerator/README.md
 create mode 100644 src/hooks/useColorGenerator/__stories__/ColorGenerator.scss
 create mode 100644 src/hooks/useColorGenerator/__stories__/ColoredAvatar.tsx
 create mode 100644 src/hooks/useColorGenerator/__stories__/useColorGenerator.stories.tsx
 create mode 100644 src/hooks/useColorGenerator/__tests__/getHue.test.ts
 create mode 100644 src/hooks/useColorGenerator/__tests__/randomIndex.test.ts
 rename src/hooks/{useGeneratorColor/__stories__ => useColorGenerator/__tests__}/utils/randomString.ts (100%)
 rename src/hooks/{useGeneratorColor/utils => useColorGenerator}/color.ts (71%)
 rename src/hooks/{useGeneratorColor/utils => useColorGenerator}/constants.ts (91%)
 create mode 100644 src/hooks/useColorGenerator/index.ts
 rename src/hooks/{useGeneratorColor => useColorGenerator}/types.ts (92%)
 rename src/hooks/{useGeneratorColor/useGeneratorColor.ts => useColorGenerator/useColorGenerator.ts} (71%)
 create mode 100644 src/hooks/useColorGenerator/utils.ts
 delete mode 100644 src/hooks/useGeneratorColor/README.md
 delete mode 100644 src/hooks/useGeneratorColor/__stories__/Color.tsx
 delete mode 100644 src/hooks/useGeneratorColor/__stories__/GeneratorColor.scss
 delete mode 100644 src/hooks/useGeneratorColor/__stories__/UseGeneratorColor.stories.tsx
 delete mode 100644 src/hooks/useGeneratorColor/__stories__/constants.ts
 delete mode 100644 src/hooks/useGeneratorColor/index.ts
 delete mode 100644 src/hooks/useGeneratorColor/utils/getHue.ts
 delete mode 100644 src/hooks/useGeneratorColor/utils/hashFnv32a.ts
 delete mode 100644 src/hooks/useGeneratorColor/utils/mathFrac.ts
 delete mode 100644 src/hooks/useGeneratorColor/utils/normalizeHash.ts
 delete mode 100644 src/hooks/useGeneratorColor/utils/randomIndex.ts

diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 4d204ced02..8773b9f976 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -2,7 +2,7 @@ export * from './useActionHandlers';
 export * from './useAsyncActionHandler';
 export * from './useBodyScrollLock';
 export * from './useControlledState';
-export * from './useGeneratorColor';
+export * from './useColorGenerator';
 export * from './useFileInput';
 export * from './useFocusWithin';
 export * from './useForkRef';
diff --git a/src/hooks/useColorGenerator/README.md b/src/hooks/useColorGenerator/README.md
new file mode 100644
index 0000000000..28c077d7a4
--- /dev/null
+++ b/src/hooks/useColorGenerator/README.md
@@ -0,0 +1,26 @@
+<!--GITHUB_BLOCK-->
+
+# useColorGenerator
+
+<!--/GITHUB_BLOCK-->
+
+```tsx
+import {useColorGenerator} from '@gravity-ui/uikit';
+```
+
+The `useColorGenerator` a hook that generates a unique (but consistent) background color based on some unique attribute (e.g., name, id, email). The background color remains unchanged with each update.
+
+## Properties
+
+| Name      | Description                                                                                                                                | Type                               |   Default   |     |     |
+| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- | :---------: | --- | --- |
+| mode      | Value to control color saturation                                                                                                          | `saturated` `unsaturated` `bright` | `saturated` |
+| token     | Unique attribute of the entity (e.g., name, id, email)                                                                                     | `string`                           |             |     |     |
+| colorKeys | If an array of colors is passed, an index is generated from the token passed, and the value from the color array at that index is returned | `string[]`                         |             |     |     |
+
+## Result
+
+`useColorGenerator` returns an object with exactly two values:
+
+1. color - unique color from a token.
+2. textColor - text color (dark or light), ensurring higher contrast on generated color.
diff --git a/src/hooks/useColorGenerator/__stories__/ColorGenerator.scss b/src/hooks/useColorGenerator/__stories__/ColorGenerator.scss
new file mode 100644
index 0000000000..100143912f
--- /dev/null
+++ b/src/hooks/useColorGenerator/__stories__/ColorGenerator.scss
@@ -0,0 +1,12 @@
+@use '../../../components/variables.scss';
+
+$block: '.#{variables.$ns}color-generator';
+
+#{$block} {
+    &__color-items {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 10px;
+        margin-block-start: 20px;
+    }
+}
diff --git a/src/hooks/useColorGenerator/__stories__/ColoredAvatar.tsx b/src/hooks/useColorGenerator/__stories__/ColoredAvatar.tsx
new file mode 100644
index 0000000000..6c9bde9bd8
--- /dev/null
+++ b/src/hooks/useColorGenerator/__stories__/ColoredAvatar.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+
+import {Avatar} from '../../../components/Avatar';
+import type {AvatarProps} from '../../../components/Avatar';
+import type {UseColorGeneratorProps} from '../types';
+import {useColorGenerator} from '../useColorGenerator';
+
+type ColoredAvatarProps = AvatarProps & {
+    withText: boolean;
+    mode: UseColorGeneratorProps['mode'];
+    token: UseColorGeneratorProps['token'];
+};
+
+export const ColoredAvatar = ({
+    mode,
+    theme,
+    token,
+    withText,
+    ...avatarProps
+}: ColoredAvatarProps) => {
+    const {color, textColor} = useColorGenerator({
+        token,
+        mode,
+    });
+
+    return (
+        <Avatar
+            {...avatarProps}
+            theme={theme}
+            text={withText ? token : undefined}
+            color={withText ? textColor : undefined}
+            backgroundColor={color}
+            size="l"
+        />
+    );
+};
diff --git a/src/hooks/useColorGenerator/__stories__/useColorGenerator.stories.tsx b/src/hooks/useColorGenerator/__stories__/useColorGenerator.stories.tsx
new file mode 100644
index 0000000000..b33e997719
--- /dev/null
+++ b/src/hooks/useColorGenerator/__stories__/useColorGenerator.stories.tsx
@@ -0,0 +1,69 @@
+import React from 'react';
+
+import type {Meta, StoryObj} from '@storybook/react';
+
+import {Button} from '../../../components/Button';
+import {block} from '../../../components/utils/cn';
+import {randomString} from '../__tests__/utils/randomString';
+
+import {ColoredAvatar} from './ColoredAvatar';
+
+import './ColorGenerator.scss';
+
+const b = block('color-generator');
+
+const meta: Meta = {
+    title: 'Hooks/useColorGenerator',
+    argTypes: {
+        mode: {
+            options: ['unsaturated', 'saturated', 'bright'],
+            control: {type: 'radio'},
+        },
+        withText: {
+            control: 'boolean',
+        },
+    },
+};
+
+export default meta;
+
+type Story = StoryObj<typeof ColoredAvatar>;
+
+const initValues = () => {
+    const result = Array.from({length: 10}, () => randomString(16));
+
+    return result;
+};
+
+const Template = (args: React.ComponentProps<typeof ColoredAvatar>) => {
+    const {mode, withText} = args;
+    const [tokens, setTokens] = React.useState<string[]>(initValues);
+
+    const onClick = React.useCallback(() => {
+        const newToken = randomString(16);
+        setTokens((prev) => [newToken, ...prev]);
+    }, []);
+
+    return (
+        <React.Fragment>
+            <Button title="generate color" onClick={onClick}>
+                Generate color
+            </Button>
+            <div className={b('color-items')}>
+                {tokens.map((token) => (
+                    <ColoredAvatar key={token} token={token} mode={mode} withText={withText} />
+                ))}
+            </div>
+        </React.Fragment>
+    );
+};
+
+export const Default: Story = {
+    render: (args) => {
+        return <Template {...args} />;
+    },
+    args: {
+        mode: 'unsaturated',
+        withText: false,
+    },
+};
diff --git a/src/hooks/useColorGenerator/__tests__/getHue.test.ts b/src/hooks/useColorGenerator/__tests__/getHue.test.ts
new file mode 100644
index 0000000000..60972e7ac0
--- /dev/null
+++ b/src/hooks/useColorGenerator/__tests__/getHue.test.ts
@@ -0,0 +1,24 @@
+import {getHue} from '../utils'; // Подставьте правильное имя файла
+
+describe('getHue', () => {
+    test('returns values within the range [0, 360)', () => {
+        const MIN_HASH = -Math.pow(2, 31);
+        const MAX_HASH = Math.pow(2, 31);
+
+        for (let i = 0; i < 1000; i++) {
+            const hash = Math.random() * (MAX_HASH - MIN_HASH) + MIN_HASH;
+            const hue = getHue(hash);
+
+            expect(hue).toBeGreaterThanOrEqual(0);
+            expect(hue).toBeLessThan(360);
+        }
+
+        const maxHue = getHue(MAX_HASH);
+        const minHue = getHue(MIN_HASH);
+
+        expect(maxHue).toBeGreaterThanOrEqual(0);
+        expect(maxHue).toBeLessThan(360);
+        expect(minHue).toBeGreaterThanOrEqual(0);
+        expect(minHue).toBeLessThan(360);
+    });
+});
diff --git a/src/hooks/useColorGenerator/__tests__/randomIndex.test.ts b/src/hooks/useColorGenerator/__tests__/randomIndex.test.ts
new file mode 100644
index 0000000000..6f1d25e98d
--- /dev/null
+++ b/src/hooks/useColorGenerator/__tests__/randomIndex.test.ts
@@ -0,0 +1,23 @@
+import {randomIndex} from '../utils';
+
+import {randomString} from './utils/randomString';
+
+describe('randomIndex', () => {
+    test('returns numbers within the range [0, max)', () => {
+        const MAX_VALUE = 500;
+
+        for (let i = 0; i <= 1000; i++) {
+            const token = randomString(16);
+            const index = randomIndex(token, MAX_VALUE);
+
+            expect(index).toBeGreaterThanOrEqual(0);
+            expect(index).toBeLessThan(MAX_VALUE);
+        }
+
+        const zeroIndex = randomIndex('test', 0);
+        expect(zeroIndex).toBe(0);
+
+        const oneIndex = randomIndex('test', 1);
+        expect(oneIndex).toBe(0);
+    });
+});
diff --git a/src/hooks/useGeneratorColor/__stories__/utils/randomString.ts b/src/hooks/useColorGenerator/__tests__/utils/randomString.ts
similarity index 100%
rename from src/hooks/useGeneratorColor/__stories__/utils/randomString.ts
rename to src/hooks/useColorGenerator/__tests__/utils/randomString.ts
diff --git a/src/hooks/useGeneratorColor/utils/color.ts b/src/hooks/useColorGenerator/color.ts
similarity index 71%
rename from src/hooks/useGeneratorColor/utils/color.ts
rename to src/hooks/useColorGenerator/color.ts
index 1715137284..782c393f6d 100644
--- a/src/hooks/useGeneratorColor/utils/color.ts
+++ b/src/hooks/useColorGenerator/color.ts
@@ -1,13 +1,9 @@
 /* eslint-disable no-bitwise */
-import type {ColorProps, ThemeColorSettings} from '../types';
-
 import {BLACK_COLOR, WHITE_COLOR, colorOptions} from './constants';
-import {getHue} from './getHue';
-import {hashFnv32a} from './hashFnv32a';
-import {normalizeHash} from './normalizeHash';
-import {randomIndex} from './randomIndex';
+import type {ColorProps, ThemeColorSettings} from './types';
+import {getHue, hashFnv32a, normalizeHash, randomIndex} from './utils';
 
-class Color {
+export class ColorGenerator {
     private _colorKeys?: string[];
     private _saturation?: number;
     private _lightness?: number;
@@ -40,14 +36,12 @@ class Color {
         return this.hslColor();
     }
 
-    get oppositeColor() {
+    get textColor() {
         if (!this._hue || !this._saturation || !this._lightness) {
             return WHITE_COLOR;
         }
 
-        const luminance = this.getLuminance(this._hue, this._saturation, this._lightness);
-
-        return luminance > 0.7 ? BLACK_COLOR : WHITE_COLOR;
+        return this.getTextColor(this._hue, this._saturation, this._lightness);
     }
 
     private getColorKeysIndex() {
@@ -58,6 +52,7 @@ class Color {
         return randomIndex(this._token, this._colorKeys.length);
     }
 
+    // https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB
     private hslToRgb = (h: number, s: number, l: number) => {
         s /= 100;
         l /= 100;
@@ -76,15 +71,35 @@ class Color {
         return [r, g, b] as [number, number, number];
     };
 
-    private rgbToLuminance(r: number, g: number, b: number) {
-        return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
-    }
-
-    private getLuminance(h: number, s: number, l: number) {
+    // https://www.w3.org/TR/WCAG20/#relativeluminancedef
+    private getTextColor(
+        h: number,
+        s: number,
+        l: number,
+        lightColor = WHITE_COLOR,
+        darkColor = BLACK_COLOR,
+    ) {
         const rgb = this.hslToRgb(h, s, l);
-        const luminance = this.rgbToLuminance(...rgb);
+        const N = rgb.length;
+        const normalizedValues = Array(N);
+
+        for (let i = 0; i < N; i++) {
+            let c = rgb[i];
+            c /= 255.0;
 
-        return luminance;
+            if (c <= 0.04045) {
+                c /= 12.92;
+            } else {
+                c = Math.pow((c + 0.055) / 1.055, 2.4);
+            }
+
+            normalizedValues[i] = c;
+        }
+
+        const [r, g, b] = normalizedValues;
+        const L = 0.2126 * r + 0.7152 * g + 0.0722 * b;
+
+        return L > 0.179 ? darkColor : lightColor;
     }
 
     private hslColor() {
@@ -113,7 +128,3 @@ class Color {
         return hash;
     }
 }
-
-export const colorGenerator = (args: ColorProps) => {
-    return new Color(args);
-};
diff --git a/src/hooks/useGeneratorColor/utils/constants.ts b/src/hooks/useColorGenerator/constants.ts
similarity index 91%
rename from src/hooks/useGeneratorColor/utils/constants.ts
rename to src/hooks/useColorGenerator/constants.ts
index 911ee89d6f..b0d6b1b0d6 100644
--- a/src/hooks/useGeneratorColor/utils/constants.ts
+++ b/src/hooks/useColorGenerator/constants.ts
@@ -1,4 +1,4 @@
-import type {ColorOptions, ThemeColorSettings} from '../types';
+import type {ColorOptions, ThemeColorSettings} from './types';
 
 const bright: ColorOptions = {
     lightness: [45, 55],
diff --git a/src/hooks/useColorGenerator/index.ts b/src/hooks/useColorGenerator/index.ts
new file mode 100644
index 0000000000..86aa3a8399
--- /dev/null
+++ b/src/hooks/useColorGenerator/index.ts
@@ -0,0 +1,2 @@
+export {useColorGenerator} from './useColorGenerator';
+export type {UseColorGeneratorProps} from './types';
diff --git a/src/hooks/useGeneratorColor/types.ts b/src/hooks/useColorGenerator/types.ts
similarity index 92%
rename from src/hooks/useGeneratorColor/types.ts
rename to src/hooks/useColorGenerator/types.ts
index 3cb87f4d7a..13fbfe20a7 100644
--- a/src/hooks/useGeneratorColor/types.ts
+++ b/src/hooks/useColorGenerator/types.ts
@@ -16,7 +16,7 @@ export type ColorProps = {
     theme: string;
 };
 
-export type UseGeneratorColorProps = {
+export type UseColorGeneratorProps = {
     colorKeys?: string[];
     mode?: 'saturated' | 'unsaturated' | 'bright';
     token: string;
diff --git a/src/hooks/useGeneratorColor/useGeneratorColor.ts b/src/hooks/useColorGenerator/useColorGenerator.ts
similarity index 71%
rename from src/hooks/useGeneratorColor/useGeneratorColor.ts
rename to src/hooks/useColorGenerator/useColorGenerator.ts
index f575354fcc..c5cbe58080 100644
--- a/src/hooks/useGeneratorColor/useGeneratorColor.ts
+++ b/src/hooks/useColorGenerator/useColorGenerator.ts
@@ -1,8 +1,8 @@
 /* eslint-disable valid-jsdoc */
 import {useThemeType} from '../../components/theme/useThemeType';
 
-import type {UseGeneratorColorProps} from './types';
-import {colorGenerator} from './utils/color';
+import {ColorGenerator} from './color';
+import type {UseColorGeneratorProps} from './types';
 
 /**
  * It is used to create a unique color from a token (string) and to obtain an inverted color (black or white), 
@@ -14,7 +14,7 @@ import {colorGenerator} from './utils/color';
     import {Avatar} from '@gravity-ui/uikit';
 
     const Component = ({ token, text, ...avatarProps }) => {
-        const {color, oppositeColor} = useGeneratorColor({
+        const {color, textColor} = useColorGenerator({
             token,
         });
 
@@ -22,17 +22,17 @@ import {colorGenerator} from './utils/color';
             <Avatar
                 {...avatarProps}
                 text={text}
-                color={text ? oppositeColor : undefined}
+                color={text ? textColor : undefined}
                 backgroundColor={color}
             />
         );
     };
 ```
 */
-export function useGeneratorColor(props: UseGeneratorColorProps) {
+export function useColorGenerator(props: UseColorGeneratorProps) {
     const theme = useThemeType();
 
-    const options = colorGenerator({
+    const options = new ColorGenerator({
         ...props,
         theme,
     });
diff --git a/src/hooks/useColorGenerator/utils.ts b/src/hooks/useColorGenerator/utils.ts
new file mode 100644
index 0000000000..4fbc48722c
--- /dev/null
+++ b/src/hooks/useColorGenerator/utils.ts
@@ -0,0 +1,51 @@
+/* eslint-disable no-bitwise */
+
+export const mathFrac = (x: number) => x - ~~x;
+
+export const getHue = (hash: number) => {
+    const sin = Math.sin(hash); // 0.12345678910 or -0.12345678910
+    const fr = sin < 0 ? mathFrac(sin * 1000) : mathFrac(sin * 10_000); // 5678910
+
+    return ~~(Math.abs(fr) * 360);
+};
+
+export const normalizeHash = (hash: number, min: number, max: number) => {
+    hash = Math.abs(hash);
+
+    const normalizedHash = Math.floor((hash % (max - min + 1)) + min);
+
+    return normalizedHash;
+};
+
+export const hashFnv32a = (token: string, start: number) => {
+    let hval = start;
+
+    for (let index = 0; index < token.length; index++) {
+        hval ^= token.charCodeAt(index);
+        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
+    }
+
+    return hval >>> 0;
+};
+
+export const getHash = (token: string) => {
+    let hash = 0;
+
+    for (let index = 0; index < token.length; index++) {
+        hash = token.charCodeAt(index) + ((hash << 5) - hash);
+    }
+
+    return hash;
+};
+
+export const randomIndex = (token: string, max: number) => {
+    if (max === 0) {
+        return 0;
+    }
+
+    const hash = getHash(token);
+
+    const number = Math.abs(hash) % max;
+
+    return number;
+};
diff --git a/src/hooks/useGeneratorColor/README.md b/src/hooks/useGeneratorColor/README.md
deleted file mode 100644
index ac3e1bb303..0000000000
--- a/src/hooks/useGeneratorColor/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--GITHUB_BLOCK-->
-
-# useGeneratorColor
-
-<!--/GITHUB_BLOCK-->
-
-```tsx
-import {useGeneratorColor} from '@gravity-ui/uikit';
-```
-
-The `useGeneratorColor` a hook that generates a unique (but consistent) background color based on some unique attribute (e.g., name, id, email). The background color remains unchanged with each update.
-
-## Properties
-
-| Name      |                         Description                          |   Type    |   Default   |
-| :-------- | :----------------------------------------------------------: | :-------: | :---------: | ------ | --------- |
-| mode      |              Value to control color saturation               | saturated | unsaturated | bright | saturated |
-| token     |    Unique attribute of the entity (e.g., name, id, email)    |  string   |             |
-| colorKeys |               If an array of colors is passed,               | string[]  |  undefined  |        |
-|           |         an index is generated from the token passed,         |           |             |
-|           | and the value from the color array at that index is returned |           |             |
-
-## Result
-
-`useGeneratorColor` returns an object with exactly two values:
-
-1. color - unique color from a token.
-2. oppositeColor - inverted color (black or white), ensuring higher text contrast compared to the current unique color, which is usually better for human perception.
diff --git a/src/hooks/useGeneratorColor/__stories__/Color.tsx b/src/hooks/useGeneratorColor/__stories__/Color.tsx
deleted file mode 100644
index 0228c709aa..0000000000
--- a/src/hooks/useGeneratorColor/__stories__/Color.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-
-import {Avatar} from '../../../components/Avatar';
-import type {AvatarProps} from '../../../components/Avatar';
-import type {UseGeneratorColorProps} from '../types';
-import {useGeneratorColor} from '../useGeneratorColor';
-
-type ColorProps = AvatarProps & {
-    withText: boolean;
-    mode: UseGeneratorColorProps['mode'];
-    token: UseGeneratorColorProps['token'];
-};
-
-export const Color = ({mode, theme, token, withText, ...avatarProps}: ColorProps) => {
-    const {color, oppositeColor} = useGeneratorColor({
-        token,
-        mode,
-    });
-
-    return (
-        <Avatar
-            {...avatarProps}
-            theme={theme}
-            text={withText ? token : undefined}
-            color={withText ? oppositeColor : undefined}
-            backgroundColor={color}
-            size="l"
-        />
-    );
-};
diff --git a/src/hooks/useGeneratorColor/__stories__/GeneratorColor.scss b/src/hooks/useGeneratorColor/__stories__/GeneratorColor.scss
deleted file mode 100644
index 85f0f846c4..0000000000
--- a/src/hooks/useGeneratorColor/__stories__/GeneratorColor.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-@use '../../../components/variables.scss';
-
-$block: '.#{variables.$ns}generator-color';
-
-#{$block} {
-    &__actions {
-        display: flex;
-        gap: 4px;
-        margin-block-end: 20px;
-        align-items: center;
-    }
-
-    &__color-items {
-        display: flex;
-        flex-wrap: wrap;
-        gap: 10px;
-    }
-}
diff --git a/src/hooks/useGeneratorColor/__stories__/UseGeneratorColor.stories.tsx b/src/hooks/useGeneratorColor/__stories__/UseGeneratorColor.stories.tsx
deleted file mode 100644
index 34057ed199..0000000000
--- a/src/hooks/useGeneratorColor/__stories__/UseGeneratorColor.stories.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from 'react';
-
-import type {Meta, StoryFn} from '@storybook/react';
-
-import {Button} from '../../../components/Button';
-import {Checkbox} from '../../../components/Checkbox';
-import {Select} from '../../../components/Select';
-import {block} from '../../../components/utils/cn';
-import type {UseGeneratorColorProps} from '../types';
-
-import {Color} from './Color';
-import {colorModes} from './constants';
-import {randomString} from './utils/randomString';
-
-import './GeneratorColor.scss';
-
-const b = block('generator-color');
-
-export default {title: 'Hooks/useGeneratorColor'} as Meta;
-
-const DefaultTemplate: StoryFn = () => {
-    const [tokens, setTokens] = React.useState<string[]>([]);
-    const [mode, setMode] = React.useState<string[]>(['unsaturated']);
-    const [withText, setWithText] = React.useState(false);
-
-    const onClick = React.useCallback(() => {
-        const newToken = randomString(16);
-        setTokens((prev) => [newToken, ...prev]);
-    }, []);
-
-    return (
-        <React.Fragment>
-            <div className={b('actions')}>
-                <Button title="generate color" onClick={onClick}>
-                    Generate color
-                </Button>
-                <Select title="select mode" value={mode} options={colorModes} onUpdate={setMode} />
-                <Checkbox checked={withText} onUpdate={setWithText}>
-                    with text
-                </Checkbox>
-            </div>
-
-            <div className={b('color-items')}>
-                {tokens.map((token) => (
-                    <Color
-                        key={token}
-                        token={token}
-                        mode={mode[0] as UseGeneratorColorProps['mode']}
-                        withText={withText}
-                    />
-                ))}
-            </div>
-        </React.Fragment>
-    );
-};
-
-export const Default = DefaultTemplate.bind({});
diff --git a/src/hooks/useGeneratorColor/__stories__/constants.ts b/src/hooks/useGeneratorColor/__stories__/constants.ts
deleted file mode 100644
index 5d132b0c76..0000000000
--- a/src/hooks/useGeneratorColor/__stories__/constants.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const colorModes = [
-    {value: 'unsaturated', content: 'unsaturated'},
-    {value: 'saturated', content: 'saturated'},
-    {value: 'bright', content: 'bright'},
-];
diff --git a/src/hooks/useGeneratorColor/index.ts b/src/hooks/useGeneratorColor/index.ts
deleted file mode 100644
index f3ae79e8aa..0000000000
--- a/src/hooks/useGeneratorColor/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export {useGeneratorColor} from './useGeneratorColor';
-export type {UseGeneratorColorProps} from './types';
diff --git a/src/hooks/useGeneratorColor/utils/getHue.ts b/src/hooks/useGeneratorColor/utils/getHue.ts
deleted file mode 100644
index 9f293ec44c..0000000000
--- a/src/hooks/useGeneratorColor/utils/getHue.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/* eslint-disable no-bitwise */
-import {mathFrac} from './mathFrac';
-
-export const getHue = (hash: number) => {
-    const sin = Math.sin(hash); // 0.12345678910 or -0.12345678910
-    const fr = sin < 0 ? mathFrac(sin * 1000) : mathFrac(sin * 10_000); // 5678910
-
-    return ~~(Math.abs(fr) * 360);
-};
diff --git a/src/hooks/useGeneratorColor/utils/hashFnv32a.ts b/src/hooks/useGeneratorColor/utils/hashFnv32a.ts
deleted file mode 100644
index 58d8a4e082..0000000000
--- a/src/hooks/useGeneratorColor/utils/hashFnv32a.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/* eslint-disable no-bitwise */
-// hash in [-2^31, 2^31 - 1]
-export const hashFnv32a = (token: string, start: number) => {
-    let hval = start;
-
-    for (let index = 0; index < token.length; index++) {
-        hval ^= token.charCodeAt(index);
-        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
-    }
-
-    return hval >>> 0;
-};
diff --git a/src/hooks/useGeneratorColor/utils/mathFrac.ts b/src/hooks/useGeneratorColor/utils/mathFrac.ts
deleted file mode 100644
index 60b5ef06ee..0000000000
--- a/src/hooks/useGeneratorColor/utils/mathFrac.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-/* eslint-disable no-bitwise */
-export const mathFrac = (x: number) => x - ~~x;
diff --git a/src/hooks/useGeneratorColor/utils/normalizeHash.ts b/src/hooks/useGeneratorColor/utils/normalizeHash.ts
deleted file mode 100644
index 322c5f7ce0..0000000000
--- a/src/hooks/useGeneratorColor/utils/normalizeHash.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export const normalizeHash = (hash: number, min: number, max: number) => {
-    hash = Math.abs(hash);
-
-    const normalizedHash = Math.floor((hash % (max - min + 1)) + min);
-
-    return normalizedHash;
-};
diff --git a/src/hooks/useGeneratorColor/utils/randomIndex.ts b/src/hooks/useGeneratorColor/utils/randomIndex.ts
deleted file mode 100644
index 34d4ba6207..0000000000
--- a/src/hooks/useGeneratorColor/utils/randomIndex.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/* eslint-disable no-bitwise */
-export const getHash = (token: string) => {
-    let hash = 0;
-
-    for (let index = 0; index < token.length; index++) {
-        hash = token.charCodeAt(index) + ((hash << 5) - hash);
-    }
-
-    return hash;
-};
-
-export const randomIndex = (token: string, max: number) => {
-    const hash = getHash(token);
-
-    const number = Math.abs(hash) % max;
-
-    return number;
-};