Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions packages/koenig-lexical/src/components/ui/ButtonGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import React from 'react';
import {Tooltip} from './Tooltip';
import {usePreviousFocus} from '../../hooks/usePreviousFocus';

export function ButtonGroup({buttons = [], selectedName, onClick}) {
export function ButtonGroup({buttons = [], selectedName, onClick, hasTooltip = true}) {
return (
<div className="flex">
<ul className="flex items-center justify-evenly gap-[.6rem] rounded-lg font-sans text-md font-normal text-white">
{buttons.map(({label, name, Icon, dataTestId}) => (
<IconButton
<ul className="flex items-center justify-evenly rounded-lg bg-grey-100 font-sans text-md font-normal text-white dark:bg-grey-900" role="menubar">
{buttons.map(({label, name, Icon, dataTestId, ariaLabel}) => (
<ButtonGroupIconButton
key={`${name}-${label}`}
ariaLabel={ariaLabel}
dataTestId={dataTestId}
hasTooltip={hasTooltip}
Icon={Icon}
label={label}
name={name}
Expand All @@ -24,28 +26,39 @@ export function ButtonGroup({buttons = [], selectedName, onClick}) {
);
}

export function IconButton({dataTestId, onClick, label, name, selectedName, Icon}) {
export function ButtonGroupIconButton({dataTestId, onClick, label, ariaLabel, name, selectedName, Icon, hasTooltip}) {
const isActive = name === selectedName;

const {handleMousedown, handleClick} = usePreviousFocus(onClick, name);

return (
<li className="mb-0">
<button
aria-label={label}
className={`group relative flex h-7 w-8 cursor-pointer items-center justify-center rounded-lg hover:bg-grey-150 dark:hover:bg-grey-900 ${isActive ? 'bg-grey-150 text-green-600 dark:bg-grey-900 dark:text-white' : 'text-black dark:text-white' } ${Icon ? '' : 'text-[1.3rem] font-bold'}`}
aria-checked={isActive}
aria-label={ariaLabel || label}
className={`group relative flex h-7 w-8 cursor-pointer items-center justify-center rounded-lg text-black dark:text-white ${isActive ? 'border border-grey-300 bg-white shadow-xs dark:border-grey-800 dark:bg-grey-950' : '' } ${Icon ? '' : 'text-[1.3rem] font-bold'}`}
data-testid={dataTestId}
role="menuitemradio"
type="button"
onClick={handleClick}
onMouseDown={handleMousedown}
>
{Icon ? <Icon className="size-4 stroke-2" /> : label}
{(Icon && label) && <Tooltip label={label} />}
{(Icon && label && hasTooltip) && <Tooltip label={label} />}
</button>
</li>
);
}

ButtonGroup.propTypes = {
selectedName: PropTypes.oneOf(['regular', 'wide', 'full', 'split', 'center', 'left', 'small', 'medium', 'large', 'grid', 'list'])
selectedName: PropTypes.oneOf(['regular', 'wide', 'full', 'split', 'center', 'left', 'small', 'medium', 'large', 'grid', 'list', 'minimal', 'immersive']).isRequired,
hasTooltip: PropTypes.bool,
onClick: PropTypes.func.isRequired,
buttons: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string,
name: PropTypes.string.isRequired,
Icon: PropTypes.elementType,
dataTestId: PropTypes.string,
ariaLabel: PropTypes.string
}))
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import ImgFullIcon from '../../assets/icons/kg-img-full.svg?react';
import ImgRegularIcon from '../../assets/icons/kg-img-regular.svg?react';
import ImgWideIcon from '../../assets/icons/kg-img-wide.svg?react';
import React from 'react';
import {ButtonGroup, IconButton} from './ButtonGroup';
import {ButtonGroup, ButtonGroupIconButton} from './ButtonGroup';

const story = {
title: 'Generic/Button group',
title: 'Generic/Button group (beta)',
component: ButtonGroup,
subcomponents: {IconButton},
subcomponents: {ButtonGroupIconButton},
parameters: {
status: {
type: 'functional'
Expand Down
64 changes: 0 additions & 64 deletions packages/koenig-lexical/src/components/ui/ButtonGroupBeta.jsx

This file was deleted.

This file was deleted.

85 changes: 62 additions & 23 deletions packages/koenig-lexical/src/components/ui/ColorOptionButtons.jsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,70 @@
import PlusIcon from '../../assets/icons/plus.svg?react';
import React from 'react';
import React, {useState} from 'react';
import {Tooltip} from './Tooltip';
import {useClickOutside} from '../../hooks/useClickOutside';
import {usePreviousFocus} from '../../hooks/usePreviousFocus';

export function ColorOptionButtons({buttons = [], selectedName, onClick}) {
const [isOpen, setIsOpen] = useState(false);
const componentRef = React.useRef(null);

const selectedButton = buttons.find(button => button.name === selectedName);

// Close the swatch popover when clicking outside of it
useClickOutside(isOpen, componentRef, () => setIsOpen(false));

return (
<div className="flex">
<ul className="flex w-full items-center justify-between rounded-md font-sans text-md font-normal text-white">
{buttons.map(({label, name, color}) => (
name !== 'image' ?
<ColorButton
key={`${name}-${label}`}
color={color}
label={label}
name={name}
selectedName={selectedName}
onClick={onClick}
/>
:
<li key='background-image' className={`flex size-[3rem] cursor-pointer items-center justify-center rounded-full border-2 ${selectedName === name ? 'border-green' : 'border-transparent'}`} data-testid="background-image-color-button" type="button" onClick={() => onClick(name)}>
<span className="border-1 flex size-6 items-center justify-center rounded-full border border-black/5">
<PlusIcon className="size-3 stroke-grey-700 stroke-2 dark:stroke-grey-500 dark:group-hover:stroke-grey-100" />
</span>
</li>
<div ref={componentRef} className="relative">
<button
className={`relative size-6 cursor-pointer rounded-full ${selectedName ? 'p-[2px]' : 'border border-grey-200 dark:border-grey-800'}`}
data-testid="color-options-button"
type="button"
onClick={() => setIsOpen(!isOpen)}
>
{selectedName && (
<div className="absolute inset-0 rounded-full bg-clip-content p-[3px]" style={{
background: 'conic-gradient(hsl(360,100%,50%),hsl(315,100%,50%),hsl(270,100%,50%),hsl(225,100%,50%),hsl(180,100%,50%),hsl(135,100%,50%),hsl(90,100%,50%),hsl(45,100%,50%),hsl(0,100%,50%))',
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
WebkitMaskComposite: 'xor',
mask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
maskComposite: 'exclude'
}} />
)}
<span
className={`${selectedButton?.color || ''} block size-full rounded-full border-2 border-white dark:border-grey-950`}
></span>
</button>

))}
</ul>
{/* Color options popover */}
{isOpen && (
<div className="absolute -right-3 bottom-full z-10 mb-2 rounded-lg bg-white px-3 py-2 shadow dark:bg-grey-900" data-testid="color-options-popover">
<div className="flex">
<ul className="flex w-full items-center justify-between rounded-md font-sans text-md font-normal text-white">
{buttons.map(({label, name, color}) => (
name !== 'image' ?
<ColorButton
key={`${name}-${label}`}
color={color}
data-testid={`color-options-${name}-button`}
label={label}
name={name}
selectedName={selectedName}
onClick={(title) => {
onClick(title);
setIsOpen(false);
}}
/>
:
<li key='background-image' className={`mb-0 flex size-[3rem] cursor-pointer items-center justify-center rounded-full border-2 ${selectedName === name ? 'border-green' : 'border-transparent'}`} data-testid="background-image-color-button" type="button" onClick={() => onClick(name)}>
<span className="border-1 flex size-6 items-center justify-center rounded-full border border-black/5">
<PlusIcon className="size-3 stroke-grey-700 stroke-2 dark:stroke-grey-500 dark:group-hover:stroke-grey-100" />
</span>
</li>
))}
</ul>
</div>
</div>
)}
</div>
);
}
Expand All @@ -35,11 +74,11 @@ export function ColorButton({onClick, label, name, color, selectedName}) {

const {handleMousedown, handleClick} = usePreviousFocus(onClick, name);
return (
<li>
<li className="mb-0">
<button
aria-label={label}
className={`group relative flex size-6 cursor-pointer items-center justify-center rounded-full border-2 ${isActive ? 'border-green' : 'border-transparent'}`}
data-test-id={`color-picker-${name}`}
data-testid={`color-picker-${name}`}
type="button"
onClick={handleClick}
onMouseDown={handleMousedown}
Expand Down

This file was deleted.

Loading
Loading