@gravity-ui/uikit
Version:
Gravity UI base styling and components
69 lines (68 loc) • 3.67 kB
JavaScript
'use client';
import { jsx as _jsx } from "react/jsx-runtime";
import * as React from 'react';
import { useSelect } from "../../hooks/index.js";
import { useForkRef } from "../../hooks/useForkRef/useForkRef.js";
import { Button } from "../Button/index.js";
import { block } from "../utils/cn.js";
import { filterDOMProps } from "../utils/filterDOMProps.js";
import { usePaletteGrid } from "./hooks.js";
import { getPaletteRows } from "./utils.js";
import "./Palette.css";
const b = block('palette');
export const Palette = React.forwardRef(function Palette(props, ref) {
const { size = 'm', multiple = true, options = [], columns = 6, disabled, style, className, rowClassName, optionClassName, qa, onFocus, onBlur, } = props;
const [focusedOptionIndex, setFocusedOptionIndex] = React.useState(undefined);
const focusedOption = focusedOptionIndex === undefined ? undefined : options[focusedOptionIndex];
const innerRef = React.useRef(null);
const handleRef = useForkRef(ref, innerRef);
const { value, handleSelection } = useSelect({
value: props.value,
defaultValue: props.defaultValue,
multiple,
onUpdate: props.onUpdate,
});
const rows = React.useMemo(() => getPaletteRows(options, columns), [columns, options]);
const focusOnOptionWithIndex = React.useCallback((index) => {
if (!innerRef.current)
return;
const $options = Array.from(innerRef.current.querySelectorAll(`.${b('option')}`));
if (!$options[index])
return;
$options[index].focus();
setFocusedOptionIndex(index);
}, []);
const tryToFocus = (newIndex) => {
if (newIndex === focusedOptionIndex || newIndex < 0 || newIndex >= options.length) {
return;
}
focusOnOptionWithIndex(newIndex);
};
const gridProps = usePaletteGrid({
disabled,
onFocus: (event) => {
focusOnOptionWithIndex(0);
onFocus?.(event);
},
onBlur: (event) => {
setFocusedOptionIndex(undefined);
onBlur?.(event);
},
whenFocused: focusedOptionIndex !== undefined && focusedOption
? {
selectItem: () => handleSelection(focusedOption),
nextItem: () => tryToFocus(focusedOptionIndex + 1),
previousItem: () => tryToFocus(focusedOptionIndex - 1),
nextRow: () => tryToFocus(focusedOptionIndex + columns),
previousRow: () => tryToFocus(focusedOptionIndex - columns),
}
: undefined,
});
return (_jsx("div", { ...filterDOMProps(props, { labelable: true }), ...gridProps, ref: handleRef, className: b({ size }, className), style: style, "data-qa": qa, children: rows.map((row, rowNumber) => (_jsx("div", { className: b('row', rowClassName), role: "row", children: row.map((option) => {
const isSelected = Boolean(value.includes(option.value));
const focused = option === focusedOption;
return (_jsx("div", { role: "gridcell", "aria-selected": focused ? 'true' : undefined, "aria-readonly": option.disabled, children: _jsx(Button, { className: b('option', optionClassName), tabIndex: -1, style: style, disabled: disabled || option.disabled, title: option.title, view: isSelected ? 'normal' : 'flat', selected: isSelected, value: option.value, size: size, onClick: () => handleSelection(option), children: _jsx(Button.Icon, { children: option.content ?? option.value }) }) }, option.value));
}) }, `row-${rowNumber}`))) }));
});
Palette.displayName = 'Palette';
//# sourceMappingURL=Palette.js.map