From 3fe727ace54fa2e144fb9d5bf818cd12981a1e4d Mon Sep 17 00:00:00 2001 From: Evan Johnson Date: Thu, 5 Aug 2021 09:15:52 -0400 Subject: [PATCH] Add initial AccessibleButton component --- packages/core/src/components/_index.scss | 1 + .../components/button/_accessible-button.scss | 12 +++ .../components/button/accessibleButton.tsx | 83 +++++++++++++++++++ packages/core/src/components/button/button.md | 26 ++++-- packages/core/src/components/index.ts | 1 + .../examples/core-examples/buttonsExample.tsx | 24 +++++- 6 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 packages/core/src/components/button/_accessible-button.scss create mode 100644 packages/core/src/components/button/accessibleButton.tsx diff --git a/packages/core/src/components/_index.scss b/packages/core/src/components/_index.scss index 9f63f1f171..bc76beecb5 100644 --- a/packages/core/src/components/_index.scss +++ b/packages/core/src/components/_index.scss @@ -3,6 +3,7 @@ @import "alert/alert"; @import "breadcrumbs/breadcrumbs"; +@import "button/accessible-button"; @import "button/button"; @import "button/button-group"; @import "callout/callout"; diff --git a/packages/core/src/components/button/_accessible-button.scss b/packages/core/src/components/button/_accessible-button.scss new file mode 100644 index 0000000000..37159d0222 --- /dev/null +++ b/packages/core/src/components/button/_accessible-button.scss @@ -0,0 +1,12 @@ +// Copyright 2021 Palantir Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. + +@import "../../common/variables"; + +.#{$ns}-accessible-button { + cursor: pointer; + + &.#{$ns}-disabled { + cursor: not-allowed; + } +} diff --git a/packages/core/src/components/button/accessibleButton.tsx b/packages/core/src/components/button/accessibleButton.tsx new file mode 100644 index 0000000000..c9b05771c4 --- /dev/null +++ b/packages/core/src/components/button/accessibleButton.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2021 Palantir Technologies, Inc. All rights reserved. + * + * Licensed 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 classNames from "classnames"; +import * as React from "react"; + +import { Classes, Keys } from "../../common"; +import { DISPLAYNAME_PREFIX, removeNonHTMLProps } from "../../common/props"; + +interface AccessibleButtonProps { + /** Tag name used to render button */ + tagName?: keyof JSX.IntrinsicElements; + + /** + * prevents onClick from firing and hooks up not-allowed cursor, + * consumer is responsible for applying other disabled styling + */ + disabled?: boolean; + + className?: string; + + /** event may be mouse event or keyboard event if triggered by enter or space key when focused */ + onClick: (event: React.MouseEvent | React.KeyboardEvent) => void; +} + +export const AccessibleButton: React.FC = props => { + const { disabled, tagName = "span", className, onClick: onClickFromProps, children, ...htmlProps } = props; + + const NS = Classes.getClassNamespace(); + + const onClick = React.useCallback( + (event: React.MouseEvent | React.KeyboardEvent) => { + if (disabled) { + return; + } + + if (onClickFromProps) { + onClickFromProps(event); + } + }, + [disabled, onClickFromProps], + ); + + const onKeyDown = React.useCallback( + (event: React.KeyboardEvent) => { + if (Keys.isKeyboardClick(event.keyCode)) { + event.preventDefault(); + onClick(event); + } + }, + [onClick], + ); + + return React.createElement( + tagName, + { + tabIndex: 0, + ...removeNonHTMLProps(htmlProps), + // below props should not be overridden + onClick, + onKeyDown, + className: classNames(className, `${NS}-accessible-button`, { [Classes.DISABLED]: disabled }), + role: "button", + "aria-disabled": disabled, + }, + children, + ); +}; + +AccessibleButton.displayName = `${DISPLAYNAME_PREFIX}.AccessibleButton`; diff --git a/packages/core/src/components/button/button.md b/packages/core/src/components/button/button.md index 124fab0fc0..b97c584713 100644 --- a/packages/core/src/components/button/button.md +++ b/packages/core/src/components/button/button.md @@ -4,6 +4,15 @@ Buttons trigger actions when clicked. @reactExample ButtonsExample +### `AccessibleButton` + +```tsx + console.log("clicked")} /> +// renders: + +// and hooks up onKeyDown listener for enter and space presses +``` + ### `AnchorButton` ```tsx @@ -24,13 +33,14 @@ Buttons trigger actions when clicked.

Disabled `Button` prevents all interaction +

Use `AnchorButton` if you need mouse interaction events (such as hovering) on a disabled button. `Button` uses the native `disabled` attribute on the `