diff --git a/packages/react/src/components/Avatar/Avatar.stories.mdx b/packages/react/src/components/Avatar/Avatar.stories.mdx index 3d33b80b..7ad9348e 100644 --- a/packages/react/src/components/Avatar/Avatar.stories.mdx +++ b/packages/react/src/components/Avatar/Avatar.stories.mdx @@ -1,7 +1,9 @@ import {ArgsTable, Source, Story, Canvas, Meta} from '@storybook/addon-docs'; import dedent from 'ts-dedent'; import StoryConfig from '../../../.storybook/story-config.ts'; +import Stack from '@mui/material/Stack'; import Avatar from './Avatar.tsx'; +import {BoltIcon, BriefcaseIcon, CameraIcon, CloudNodesIcon, DatabaseIcon, EclipseIcon} from "@oxygen-ui/react-icons"; export const meta = { component: Avatar, @@ -17,6 +19,9 @@ export const Template = args => ; - [Overview](#overview) - [Props](#props) - [Usage](#usage) +- [Variants](#variants) + - [Random Colors](#random-colors) + - [Random Colors with a supplied randomizer](#random-colors-with-a-supplied-randomizer) ## Overview @@ -45,3 +50,63 @@ Import and use the `Avatar` component in your components as follows. format code={dedent`import Avatar from '@oxygen-ui/react/Avatar';\n`} /> + +## Variants + +### Random Colors + +The Avatar component can be used with random colors as follows. Use the `randomBackgroundColor` prop to get a random color for the Avatar. + + + + + XZ + Q4 + H + OT + OT + OT + + + + +### Random Colors with a supplied randomizer + +You can pass in a string to the `backgroundColorRandomizer` prop to get a consistent random color for the same string. + + + + + Icon Avatars + + + + + + + + + + + + + + + + + + + + + Text Avatars + + XZ + Q4 + H + OT + OT + OT + + + + diff --git a/packages/react/src/components/Avatar/Avatar.tsx b/packages/react/src/components/Avatar/Avatar.tsx index e841274f..dec40e81 100644 --- a/packages/react/src/components/Avatar/Avatar.tsx +++ b/packages/react/src/components/Avatar/Avatar.tsx @@ -18,21 +18,58 @@ import MuiAvatar, {AvatarProps as MuiAvatarProps} from '@mui/material/Avatar'; import clsx from 'clsx'; -import {FC, ReactElement} from 'react'; +import {ElementType, FC, ReactElement, useMemo} from 'react'; +import usePastelColorGenerator from 'src/hooks/use-pastel-color-generator'; import {WithWrapperProps} from '../../models'; import {composeComponentDisplayName} from '../../utils'; import './avatar.scss'; -export type AvatarProps = MuiAvatarProps; +export type AvatarProps = { + /** + * Text for the random background color generator. + */ + backgroundColorRandomizer?: string; + /** + * The component used for the root node. Either a string to use a HTML element or a component. + */ + component?: C; + /** + * If `true`, the background color will be randomly generated. + */ + randomBackgroundColor?: boolean; +} & Omit, 'component'>; const COMPONENT_NAME: string = 'Avatar'; -const Avatar: FC & WithWrapperProps = (props: AvatarProps): ReactElement => { - const {className, ...rest} = props; +const Avatar: FC & WithWrapperProps = (props: AvatarProps): ReactElement => { + const {className, children, component, randomBackgroundColor, backgroundColorRandomizer, ...rest} = props; + + const colorRandomizer: string = useMemo(() => { + if (backgroundColorRandomizer) { + return backgroundColorRandomizer; + } + + if (typeof children === 'string') { + return children; + } + + return ''; + }, [children, backgroundColorRandomizer]); + + const {color} = usePastelColorGenerator(colorRandomizer); const classes: string = clsx('oxygen-avatar', className); - return ; + return ( + + {children} + + ); }; Avatar.displayName = composeComponentDisplayName(COMPONENT_NAME); diff --git a/packages/react/src/components/Switch/switch.scss b/packages/react/src/components/Switch/switch.scss index c02ccf11..5daadc79 100644 --- a/packages/react/src/components/Switch/switch.scss +++ b/packages/react/src/components/Switch/switch.scss @@ -37,9 +37,6 @@ .MuiSwitch-thumb { background: var(--oxygen-palette-common-white); - transition-property: transform; - transition-duration: 200ms; - border-radius: inherit; width: var(--oxygen-switch-thumb-width); height: var(--oxygen-switch-thumb-width); border-width: 0.125rem; diff --git a/packages/react/src/hooks/use-pastel-color-generator.ts b/packages/react/src/hooks/use-pastel-color-generator.ts new file mode 100644 index 00000000..6658dda5 --- /dev/null +++ b/packages/react/src/hooks/use-pastel-color-generator.ts @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {useEffect, useState} from 'react'; +import generatePastelColor from '../utils/generate-pastel-color'; + +export interface UsePastelColorGenerator { + /** + * Generated color. + */ + color: string; + /** + * Function to update the text. + * @param newText - New text to generate the color from. + * @returns void + */ + updateText: (newText: string) => void; +} + +/** + * Hook to generate a pastel color based on the given text. + * + * @example + * const {color, updateText} = usePastelColorGenerator('John Doe'); + * console.log(color); // hsl(0 70% 80% / 50%) + * updateText('Jane Doe'); + * console.log(color); // hsl(240 70% 80% / 50%) + * + * @param initialText - Text to generate the color from. + * @returns Generated color and a function to update the text. + */ +const usePastelColorGenerator = (initialText: string): UsePastelColorGenerator => { + const [text, setText] = useState(initialText); + const [color, setColor] = useState(generatePastelColor(initialText)); + + useEffect(() => { + setColor(generatePastelColor(text)); + }, [text]); + + const updateText = (newText: string): void => { + setText(newText); + }; + + return {color, updateText}; +}; + +export default usePastelColorGenerator; diff --git a/packages/react/src/utils/generate-pastel-color.ts b/packages/react/src/utils/generate-pastel-color.ts new file mode 100644 index 00000000..d3580ffd --- /dev/null +++ b/packages/react/src/utils/generate-pastel-color.ts @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const hues: { + [key: string]: number; +} = { + A: 0, + B: 60, + C: 120, + D: 180, + E: 240, + F: 300, +}; + +type GenerateColor = (display: string) => string; + +// Simple cache to store generated colors +const colorCache: {[key: string]: string} = {}; + +/** + * Generate a pastel color based on the given text. + * + * @example + * const color = generatePastelColor('John Doe'); + * console.log(color); // hsl(0 70% 80% / 50%) + * + * @param text - Text to generate the color from. + * @returns Generated color. + */ +const generatePastelColor: GenerateColor = (text: string): string | null => { + // Check if the color is already in the cache + if (colorCache[text]) { + return colorCache[text]; + } + + // Check if the text is a non-empty string and return `null` if it is. + if (typeof text !== 'string' || text.trim() === '') { + return null; + } + + const hash: number = text.split('').reduce((acc: number, char: string) => acc + char.charCodeAt(0), 0); + const baseHue: number = hash % 360; + + const firstChar: string = text[0].toUpperCase(); + const predefinedHue: number = hues[firstChar] || baseHue; + + const saturation: number = Math.random() * (80 - 70) + 70; + const divisor: number = Math.random() * (100 - 90) + 90; + + // Generate the color + const color: string = `hsl(${predefinedHue} 80% ${saturation}% / ${divisor}%)`; + + // Cache the color for future use + colorCache[text] = color; + + return color; +}; + +export default generatePastelColor;