feat: Keyboard accessible property pane header (#11339)
This commit is contained in:
parent
bd9636f514
commit
2ad121a092
|
|
@ -378,7 +378,8 @@ const ButtonStyles = css<ThemeProp & ButtonProps>`
|
||||||
fill: ${(props) => btnColorStyles(props, "main").txtColor};
|
fill: ${(props) => btnColorStyles(props, "main").txtColor};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover,
|
||||||
|
&:focus {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-color: ${(props) => btnColorStyles(props, "hover").bgColor};
|
background-color: ${(props) => btnColorStyles(props, "hover").bgColor};
|
||||||
color: ${(props) => btnColorStyles(props, "hover").txtColor};
|
color: ${(props) => btnColorStyles(props, "hover").txtColor};
|
||||||
|
|
|
||||||
|
|
@ -687,14 +687,6 @@ export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
||||||
maxHeight={props.dropdownMaxHeight || "auto"}
|
maxHeight={props.dropdownMaxHeight || "auto"}
|
||||||
>
|
>
|
||||||
{options.map((option: DropdownOption, index: number) => {
|
{options.map((option: DropdownOption, index: number) => {
|
||||||
if (renderOption) {
|
|
||||||
return renderOption({
|
|
||||||
option,
|
|
||||||
index,
|
|
||||||
optionClickHandler,
|
|
||||||
optionWidth,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let isSelected = false;
|
let isSelected = false;
|
||||||
if (
|
if (
|
||||||
props.isMultiSelect &&
|
props.isMultiSelect &&
|
||||||
|
|
@ -708,6 +700,15 @@ export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
||||||
isSelected =
|
isSelected =
|
||||||
(props.selected as DropdownOption).value === option.value;
|
(props.selected as DropdownOption).value === option.value;
|
||||||
}
|
}
|
||||||
|
if (renderOption) {
|
||||||
|
return renderOption({
|
||||||
|
option,
|
||||||
|
index,
|
||||||
|
optionClickHandler,
|
||||||
|
optionWidth,
|
||||||
|
isSelectedNode: isSelected,
|
||||||
|
});
|
||||||
|
}
|
||||||
return !option.isSectionHeader ? (
|
return !option.isSectionHeader ? (
|
||||||
<OptionWrapper
|
<OptionWrapper
|
||||||
aria-selected={isSelected}
|
aria-selected={isSelected}
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,11 @@ const StyledDiv = styled.div`
|
||||||
props.theme.spaces[7]}px;
|
props.theme.spaces[7]}px;
|
||||||
margin: ${(props) => props.theme.spaces[2]}px 0px;
|
margin: ${(props) => props.theme.spaces[2]}px 0px;
|
||||||
|
|
||||||
a:first-child {
|
button:first-child {
|
||||||
margin-top: ${(props) => props.theme.spaces[2]}px;
|
margin-top: ${(props) => props.theme.spaces[2]}px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
a:nth-child(2) {
|
button:nth-child(2) {
|
||||||
border: none;
|
border: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
|
|
@ -43,7 +44,7 @@ const StyledDiv = styled.div`
|
||||||
${(props) => getTypographyByKey(props, "p3")}
|
${(props) => getTypographyByKey(props, "p3")}
|
||||||
margin-top: ${(props) => props.theme.spaces[2]}px;
|
margin-top: ${(props) => props.theme.spaces[2]}px;
|
||||||
|
|
||||||
:hover {
|
:hover, :focus {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,11 +96,15 @@ function ConnectDataCTA(props: ConnectDataCTAProps) {
|
||||||
category={Category.primary}
|
category={Category.primary}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
size={Size.large}
|
size={Size.large}
|
||||||
|
tabIndex={0}
|
||||||
|
tag="button"
|
||||||
text="CONNECT DATA"
|
text="CONNECT DATA"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
category={Category.tertiary}
|
category={Category.tertiary}
|
||||||
onClick={openHelpModal}
|
onClick={openHelpModal}
|
||||||
|
tabIndex={0}
|
||||||
|
tag="button"
|
||||||
text="Learn more"
|
text="Learn more"
|
||||||
/>
|
/>
|
||||||
</StyledDiv>
|
</StyledDiv>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { memo, useMemo, useCallback } from "react";
|
import React, { memo, useMemo, useCallback, useEffect } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Icon, { IconSize } from "components/ads/Icon";
|
import Icon, { IconSize } from "components/ads/Icon";
|
||||||
import Dropdown, {
|
import Dropdown, {
|
||||||
|
|
@ -125,6 +125,7 @@ const OptionWrapper = styled.div<{ hasError: boolean; fillIconColor: boolean }>`
|
||||||
|
|
||||||
const OptionContentWrapper = styled.div<{
|
const OptionContentWrapper = styled.div<{
|
||||||
hasError: boolean;
|
hasError: boolean;
|
||||||
|
isSelected: boolean;
|
||||||
}>`
|
}>`
|
||||||
padding: ${(props) => props.theme.spaces[2] + 1}px
|
padding: ${(props) => props.theme.spaces[2] + 1}px
|
||||||
${(props) => props.theme.spaces[5]}px;
|
${(props) => props.theme.spaces[5]}px;
|
||||||
|
|
@ -134,6 +135,10 @@ const OptionContentWrapper = styled.div<{
|
||||||
line-height: 8px;
|
line-height: 8px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
background-color: ${(props) =>
|
||||||
|
props.isSelected &&
|
||||||
|
!props.hasError &&
|
||||||
|
props.theme.colors.dropdown.hovered.bg};
|
||||||
|
|
||||||
span:first-child {
|
span:first-child {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
|
@ -210,7 +215,7 @@ const useDependencyList = (name: string) => {
|
||||||
const dependencyOptions =
|
const dependencyOptions =
|
||||||
entityDependencies?.directDependencies.map((e) => ({
|
entityDependencies?.directDependencies.map((e) => ({
|
||||||
label: e,
|
label: e,
|
||||||
value: getEntityId(e),
|
value: getEntityId(e) ?? e,
|
||||||
})) ?? [];
|
})) ?? [];
|
||||||
const inverseDependencyOptions =
|
const inverseDependencyOptions =
|
||||||
entityDependencies?.inverseDependencies.map((e) => ({
|
entityDependencies?.inverseDependencies.map((e) => ({
|
||||||
|
|
@ -245,12 +250,28 @@ function OptionNode(props: any) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (!props.isSelectedNode) return;
|
||||||
|
if (e.key === " " || e.key === "Enter") onClick();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("keydown", handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [props.isSelectedNode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OptionWrapper
|
<OptionWrapper
|
||||||
fillIconColor={!entityInfo?.datasourceName}
|
fillIconColor={!entityInfo?.datasourceName}
|
||||||
hasError={!!entityInfo?.hasError}
|
hasError={!!entityInfo?.hasError}
|
||||||
>
|
>
|
||||||
<OptionContentWrapper hasError={!!entityInfo?.hasError} onClick={onClick}>
|
<OptionContentWrapper
|
||||||
|
hasError={!!entityInfo?.hasError}
|
||||||
|
isSelected={props.isSelectedNode}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
<span>{entityInfo?.icon}</span>
|
<span>{entityInfo?.icon}</span>
|
||||||
<Text type={TextType.H6}>
|
<Text type={TextType.H6}>
|
||||||
{props.option.label}{" "}
|
{props.option.label}{" "}
|
||||||
|
|
@ -297,6 +318,7 @@ const TriggerNode = memo((props: TriggerNodeProps) => {
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={tooltipText}
|
content={tooltipText}
|
||||||
disabled={props.isOpen}
|
disabled={props.isOpen}
|
||||||
|
openOnTargetFocus={false}
|
||||||
position={props.tooltipPosition}
|
position={props.tooltipPosition}
|
||||||
>
|
>
|
||||||
{props.entityCount ? `${props.entityCount} ${ENTITY}` : "No Entity"}
|
{props.entityCount ? `${props.entityCount} ${ENTITY}` : "No Entity"}
|
||||||
|
|
@ -360,7 +382,12 @@ function PropertyPaneConnections(props: PropertyPaneConnectionsProps) {
|
||||||
height={`${CONNECTION_HEIGHT}px`}
|
height={`${CONNECTION_HEIGHT}px`}
|
||||||
options={dependencies.dependencyOptions}
|
options={dependencies.dependencyOptions}
|
||||||
renderOption={(optionProps) => {
|
renderOption={(optionProps) => {
|
||||||
return <OptionNode option={optionProps.option} />;
|
return (
|
||||||
|
<OptionNode
|
||||||
|
isSelectedNode={optionProps.isSelectedNode}
|
||||||
|
option={optionProps.option}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
selected={selectedOption}
|
selected={selectedOption}
|
||||||
showDropIcon={false}
|
showDropIcon={false}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ function PropertyPaneView(
|
||||||
tooltipPosition: "bottom-right",
|
tooltipPosition: "bottom-right",
|
||||||
icon: (
|
icon: (
|
||||||
<button
|
<button
|
||||||
className="p-1 hover:bg-warmGray-100 group t--copy-widget"
|
className="p-1 hover:bg-warmGray-100 focus:bg-warmGray-100 group t--copy-widget"
|
||||||
onClick={onCopy}
|
onClick={onCopy}
|
||||||
>
|
>
|
||||||
<CopyIcon className="w-4 h-4 text-gray-500" />
|
<CopyIcon className="w-4 h-4 text-gray-500" />
|
||||||
|
|
@ -85,7 +85,7 @@ function PropertyPaneView(
|
||||||
tooltipPosition: "bottom-right",
|
tooltipPosition: "bottom-right",
|
||||||
icon: (
|
icon: (
|
||||||
<button
|
<button
|
||||||
className="p-1 hover:bg-warmGray-100 group t--delete-widget"
|
className="p-1 hover:bg-warmGray-100 focus:bg-warmGray-100 group t--delete-widget"
|
||||||
onClick={onDelete}
|
onClick={onDelete}
|
||||||
>
|
>
|
||||||
<DeleteIcon className="w-4 h-4 text-gray-500" />
|
<DeleteIcon className="w-4 h-4 text-gray-500" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user