···11+import type { AriaButtonProps } from '@react-aria/button';
22+import { useButton as useAriaButton } from '@react-aria/button';
13import type { ButtonHTMLAttributes, ForwardedRef } from 'react';
22-import { forwardRef } from 'react';
44+import { forwardRef, useRef } from 'react';
3546////////////////////////////////////////////////////////////////////////////////
5768/**
79 * Button
810 *
99- * Buttons are an interactive element activated by a user with a
1111+ * @description Buttons are an interactive element activated by a user with a
1012 * mouse, keyboard, finger, voice command, or other assistive technology. Once
1113 * activated, it then performs a programmable action, such as submitting a form
1214 * or opening a dialog.
1315 *
1414- * @see https://example.com/package/button
1616+ * @see https://luke-ui.vercel.app/package/button
1517 */
16181719const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
1820 props: ButtonProps,
1921 forwardedRef: ForwardedRef<HTMLButtonElement>
2022) {
2121- return <button {...props} ref={forwardedRef} />;
2323+ const { children, tabIndex, ...useButtonProps } = props;
2424+ const { buttonProps } = useButton(useButtonProps);
2525+2626+ return (
2727+ <button ref={forwardedRef} tabIndex={tabIndex} {...buttonProps}>
2828+ {children}
2929+ </button>
3030+ );
2231});
23322433type NativeButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;
2534type ButtonProps = {
2635 /**
2736 * Identifies the element (or elements) whose contents or presence are
2828- * controlled by the element on which this attribute is set.
2929- *
3030- * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-controls
3737+ * controlled by the current element.
3838+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-controls)
3139 */
3240 'aria-controls'?: NativeButtonProps['aria-controls'];
3341 /**
3434- * Identifies the element (or elements) that describes the element on which
3535- * the attribute is set.
3636- *
3737- * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby
4242+ * Identifies the element (or elements) that labels the current element.
4343+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby)
3844 */
3945 'aria-describedby'?: NativeButtonProps['aria-describedby'];
4046 /**
4141- * Indicates if a control is expanded or collapsed, and whether or not its
4242- * child elements are displayed or hidden.
4343- *
4444- * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded
4747+ * Identifies the element (or elements) that provide a detailed, extended
4848+ * description for the object.
4949+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-details)
5050+ */
5151+ 'aria-details'?: NativeButtonProps['aria-details'];
5252+ /**
5353+ * Indicates whether the element, or another grouping element it controls, is
5454+ * currently expanded or collapsed.
5555+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)
4556 */
4657 'aria-expanded'?: NativeButtonProps['aria-expanded'];
4758 /**
4848- * Indicates the availability and type of interactive popup element that can
4949- * be triggered by the element on which the attribute is set.
5050- *
5151- * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-haspopup
5959+ * Indicates the availability and type of interactive popup element, such as
6060+ * menu or dialog, that can be triggered by an element.
6161+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-haspopup)
5262 */
5363 'aria-haspopup'?: NativeButtonProps['aria-haspopup'];
5464 /**
5555- * Defines a string value that labels an interactive element.
5656- *
5757- * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label
5858- */
6565+ * Defines a string value that labels the current element.
6666+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label)
6767+ * */
5968 'aria-label'?: NativeButtonProps['aria-label'];
6969+ /**
7070+ * Identifies the element (or elements) that labels the current element.
7171+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)
7272+ * */
7373+ 'aria-labelledby'?: NativeButtonProps['aria-labelledby'];
7474+ /**
7575+ * Indicates the current "pressed" state of toggle buttons.
7676+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed)
7777+ */
7878+ 'aria-pressed'?: NativeButtonProps['aria-pressed'];
7979+ /** Whether the element should receive focus on render. */
8080+ 'autoFocus'?: NativeButtonProps['autoFocus'];
8181+ /**
8282+ * The content to display in the button.
8383+ */
6084 'children': NativeButtonProps['children'];
6185 // "data": NativeButtonProps['data']
6262- /**
6363- * When disabled, prevents the user from interacting with the button
6464- * (it cannot be pressed or focused).
6565- */
8686+ /** Whether the button is disabled. */
6687 'disabled'?: NativeButtonProps['disabled'];
6788 /**
6868- * Defines an identifier (ID) which must be unique in the whole document.
6969- * Its purpose is to identify the element when linking (using a
7070- * [fragment identifier](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web#fragment)),
7171- * scripting, or styling (with CSS).
8989+ * The element's unique identifier.
9090+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).
7291 */
7392 'id'?: NativeButtonProps['id'];
7474- // "loading": NativeButtonProps['loading']
7593 /**
7694 * The name of the button, submitted as a pair with the button's value as part
7795 * of the form data, when that button is used to submit the form.
7896 */
7997 'name'?: NativeButtonProps['name'];
8080- 'onClick'?: NativeButtonProps['onClick'];
8181- 'onKeyDown'?: NativeButtonProps['onKeyDown'];
8282- 'onKeyUp'?: NativeButtonProps['onKeyUp'];
8383- // "prominence": NativeButtonProps['prominence']
8484- // "size": NativeButtonProps['size']
8585- /** Represents the tab order of the current element. */
9898+ /** Handler that is called when the element loses focus. */
9999+ 'onBlur'?: AriaButtonProps['onBlur'];
100100+ /** Handler that is called when the element receives focus. */
101101+ 'onFocus'?: AriaButtonProps['onFocus'];
102102+ /** Handler that is called when the press is released over the target. */
103103+ 'onPress'?: AriaButtonProps['onPress'];
104104+ /** Handler that is called when a press interaction starts. */
105105+ 'onPressStart'?: AriaButtonProps['onPressStart'];
106106+ /**
107107+ * Handler that is called when a press interaction ends, either
108108+ * over the target or when the pointer leaves the target.
109109+ */
110110+ 'onPressEnd'?: AriaButtonProps['onPressEnd'];
111111+ /** Handler that is called when the press state changes. */
112112+ 'onPressChange'?: AriaButtonProps['onPressChange'];
113113+ /**
114114+ * Handler that is called when a press is released over the target, regardless of
115115+ * whether it started on the target or not.
116116+ */
117117+ 'onPressUp'?: AriaButtonProps['onPressUp'];
118118+ /**
119119+ * Indicates that its element can be focused, and where it participates in
120120+ * sequential keyboard navigation (usually with the "Tab" key).
121121+ * @see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex)
122122+ */
86123 'tabIndex'?: NativeButtonProps['tabIndex'];
8787- // "tone": NativeButtonProps['tone']
8888- /** The default behavior of the button. */
124124+ /**
125125+ * The behavior of the button when used in an HTML form.
126126+ * @default 'button'
127127+ */
89128 'type'?: NativeButtonProps['type'];
90129 /**
91130 * Defines the value associated with the button's name when it's submitted
92131 * with the form data.
93132 */
94133 'value'?: NativeButtonProps['value'];
134134+135135+ /** @todo add these props */
136136+ // "loading": NativeButtonProps['loading']
137137+ // "prominence": NativeButtonProps['prominence']
138138+ // "size": NativeButtonProps['size']
139139+ // "tone": NativeButtonProps['tone']
95140};
141141+142142+////////////////////////////////////////////////////////////////////////////////
143143+144144+/**
145145+ * useButton
146146+ *
147147+ * @description Provides the behavior and accessibility implementation for a
148148+ * button component.
149149+ * Handles mouse, keyboard, and touch interactions, focus behavior, and ARIA
150150+ * props for both native button elements and custom element types.
151151+ */
152152+153153+export function useButton(props: UseButtonProps) {
154154+ const ref = useRef(null);
155155+ return useAriaButton(
156156+ {
157157+ ...props,
158158+ isDisabled: props.disabled,
159159+ },
160160+ ref
161161+ );
162162+}
163163+164164+export type UseButtonProps = Omit<ButtonProps, 'children' | 'tabIndex'>;
9616597166////////////////////////////////////////////////////////////////////////////////
98167
+2-2
packages/button/src/index.ts
···11-export { Button } from './button';
11+export { Button, useButton } from './button';
2233// types
4455-export type { ButtonProps } from './button';
55+export type { ButtonProps, UseButtonProps } from './button';