components-test-pb 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,9 @@ export type ButtonSize = 'small' | 'medium' | 'large';
7
7
  export type ButtonProps = ComponentProps<ButtonSlots> & {
8
8
  appearance?: 'secondary' | 'primary' | 'tertiary';
9
9
  disabled?: boolean;
10
+ disabledFocusable?: boolean;
10
11
  shape?: 'rounded' | 'circular' | 'square';
11
12
  size?: ButtonSize;
12
13
  };
13
14
  export type ButtonBaseProps = DistributiveOmit<ButtonProps, 'appearance' | 'size' | 'shape'>;
14
- export type ButtonState = ComponentState<ButtonSlots> & Required<Pick<ButtonProps, 'appearance' | 'disabled' | 'shape' | 'size'>>;
15
+ export type ButtonState = ComponentState<ButtonSlots> & Required<Pick<ButtonProps, 'appearance' | 'disabled' | 'disabledFocusable' | 'shape' | 'size'>>;
@@ -1,11 +1,19 @@
1
+ import { useARIAButtonProps } from '../../utilities/useARIAButtonProps.js';
1
2
  export const useButton = (props) => {
2
- const { appearance, shape, size, disabled, ...buttonProps } = props;
3
+ const { appearance, shape, size, disabled, disabledFocusable, ...buttonProps } = props;
4
+ const tag = (buttonProps.as ?? 'button');
5
+ const ariaButtonProps = useARIAButtonProps(tag, {
6
+ ...buttonProps,
7
+ disabled,
8
+ disabledFocusable,
9
+ });
3
10
  return {
4
11
  appearance: appearance ?? 'secondary',
5
12
  shape: shape ?? 'rounded',
6
13
  size: size ?? 'medium',
7
14
  disabled: disabled ?? false,
8
- components: { root: buttonProps.as ?? 'button' },
9
- root: { as: buttonProps.as ?? 'button', disabled: disabled ?? false, ...buttonProps },
15
+ disabledFocusable: disabledFocusable ?? false,
16
+ components: { root: tag },
17
+ root: { as: tag, ...ariaButtonProps },
10
18
  };
11
19
  };
@@ -93,16 +93,53 @@ const useRootStyles = makeStyles({
93
93
  }
94
94
  });
95
95
  const useRootDisabledstyles = makeStyles({
96
- base: {},
97
- primary: {},
96
+ base: {
97
+ backgroundColor: Tokens.colorNeutralBackgroundDisabled,
98
+ ...shorthands.borderColor(Tokens.colorNeutralStrokeDisabled),
99
+ color: Tokens.colorNeutralForegroundDisabled,
100
+ cursor: 'not-allowed',
101
+ ':hover': {
102
+ backgroundColor: Tokens.colorNeutralBackgroundDisabled,
103
+ ...shorthands.borderColor(Tokens.colorNeutralStrokeDisabled),
104
+ color: Tokens.colorNeutralForegroundDisabled,
105
+ cursor: 'not-allowed'
106
+ },
107
+ ':hover:active,:active:focus-visible': {
108
+ backgroundColor: Tokens.colorNeutralBackgroundDisabled,
109
+ ...shorthands.borderColor(Tokens.colorNeutralStrokeDisabled),
110
+ color: Tokens.colorNeutralForegroundDisabled,
111
+ cursor: 'not-allowed'
112
+ }
113
+ },
114
+ primary: {
115
+ ...shorthands.borderColor('transparent'),
116
+ ':hover': {
117
+ ...shorthands.borderColor('transparent')
118
+ },
119
+ ':hover:active,:active:focus-visible': {
120
+ ...shorthands.borderColor('transparent')
121
+ }
122
+ },
98
123
  secondary: {},
99
- tertiary: {}
124
+ tertiary: {
125
+ backgroundColor: 'transparent',
126
+ ...shorthands.borderColor('transparent'),
127
+ ':hover': {
128
+ backgroundColor: 'transparent',
129
+ ...shorthands.borderColor('transparent')
130
+ },
131
+ ':hover:active,:active:focus-visible': {
132
+ backgroundColor: 'transparent',
133
+ ...shorthands.borderColor('transparent')
134
+ }
135
+ }
100
136
  });
101
137
  export const useButtonStyles = (state) => {
102
138
  const rootBaseClassName = useRootBaseClassName();
103
139
  const rootStyles = useRootStyles();
104
140
  const rootDisabledStyles = useRootDisabledstyles();
105
- const { appearance, disabled, shape, size } = state;
106
- state.root.className = mergeClasses(buttonClassNames.root, rootBaseClassName, appearance && rootStyles[appearance], rootStyles[size], rootStyles[shape], disabled && rootDisabledStyles.base, appearance && disabled && rootDisabledStyles[appearance], state.root.className);
141
+ const { appearance, disabled, disabledFocusable, shape, size } = state;
142
+ const isDisabled = disabled || disabledFocusable;
143
+ state.root.className = mergeClasses(buttonClassNames.root, rootBaseClassName, appearance && rootStyles[appearance], rootStyles[size], rootStyles[shape], isDisabled && rootDisabledStyles.base, appearance && isDisabled && rootDisabledStyles[appearance], state.root.className);
107
144
  return state;
108
145
  };
package/dist/index.d.ts CHANGED
@@ -4,3 +4,5 @@ export { Button, useButton, renderButton, useButtonStyles } from './Components/B
4
4
  export type { ButtonSlots, ButtonProps, ButtonBaseProps, ButtonState } from './Components/Button/index.js';
5
5
  export * from './Types/compose/index.js';
6
6
  export * from './Types/utils/index.js';
7
+ export { useARIAButtonProps } from './utilities/index.js';
8
+ export type { ARIAButtonType, ARIAButtonProps, ARIAButtonResultProps } from './utilities/index.js';
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@ export { Text, useText, renderText, useTextStyles } from './Components/Text/inde
2
2
  export { Button, useButton, renderButton, useButtonStyles } from './Components/Button/index.js';
3
3
  export * from './Types/compose/index.js';
4
4
  export * from './Types/utils/index.js';
5
+ export { useARIAButtonProps } from './utilities/index.js';
@@ -0,0 +1,2 @@
1
+ export { useARIAButtonProps } from './useARIAButtonProps.js';
2
+ export type { ARIAButtonType, ARIAButtonProps, ARIAButtonResultProps } from './useARIAButtonProps.js';
@@ -0,0 +1 @@
1
+ export { useARIAButtonProps } from './useARIAButtonProps.js';
@@ -0,0 +1,16 @@
1
+ import type { HTMLAttributes } from '../Types/utils/types.js';
2
+ export type ARIAButtonType = 'button' | 'a' | 'div';
3
+ export type ARIAButtonProps<Tag extends ARIAButtonType = 'button'> = HTMLAttributes<HTMLElement> & {
4
+ disabled?: boolean;
5
+ disabledFocusable?: boolean;
6
+ } & (Tag extends 'a' ? {
7
+ href?: string;
8
+ } : {});
9
+ export type ARIAButtonResultProps<Tag extends ARIAButtonType = 'button'> = HTMLAttributes<HTMLElement> & {
10
+ disabled?: Tag extends 'button' ? '' | undefined : never;
11
+ 'aria-disabled'?: 'true';
12
+ role?: string;
13
+ tabIndex?: number;
14
+ href?: string;
15
+ };
16
+ export declare const useARIAButtonProps: <Tag extends ARIAButtonType>(tag: Tag, props?: ARIAButtonProps<Tag>) => ARIAButtonResultProps<Tag>;
@@ -0,0 +1,75 @@
1
+ const noop = () => { };
2
+ export const useARIAButtonProps = (tag, props = {}) => {
3
+ const { disabled, disabledFocusable, onClick, onKeyDown, onKeyUp, ...rest } = props;
4
+ const isDisabled = disabled || disabledFocusable;
5
+ const handleClick = (e) => {
6
+ if (isDisabled) {
7
+ e.preventDefault();
8
+ e.stopPropagation();
9
+ return;
10
+ }
11
+ onClick?.(e);
12
+ };
13
+ if (tag === 'button') {
14
+ const result = {
15
+ ...rest,
16
+ onClick: handleClick,
17
+ onKeyDown: isDisabled ? (e) => {
18
+ e.preventDefault();
19
+ e.stopPropagation();
20
+ } : onKeyDown,
21
+ onKeyUp: isDisabled ? (e) => {
22
+ e.preventDefault();
23
+ e.stopPropagation();
24
+ } : onKeyUp,
25
+ };
26
+ if (disabled && !disabledFocusable) {
27
+ result.disabled = '';
28
+ }
29
+ else if (disabledFocusable) {
30
+ result['aria-disabled'] = 'true';
31
+ }
32
+ return result;
33
+ }
34
+ const handleKeyDown = (e) => {
35
+ if (isDisabled) {
36
+ e.preventDefault();
37
+ e.stopPropagation();
38
+ return;
39
+ }
40
+ if (e.key === 'Enter') {
41
+ e.preventDefault();
42
+ e.target?.click();
43
+ }
44
+ onKeyDown?.(e);
45
+ };
46
+ const handleKeyUp = (e) => {
47
+ if (isDisabled) {
48
+ e.preventDefault();
49
+ e.stopPropagation();
50
+ return;
51
+ }
52
+ if (e.key === ' ') {
53
+ e.preventDefault();
54
+ e.target?.click();
55
+ }
56
+ onKeyUp?.(e);
57
+ };
58
+ const result = {
59
+ ...rest,
60
+ role: 'button',
61
+ onClick: handleClick,
62
+ onKeyDown: handleKeyDown,
63
+ onKeyUp: handleKeyUp,
64
+ };
65
+ if (isDisabled) {
66
+ result['aria-disabled'] = 'true';
67
+ if (tag === 'a') {
68
+ delete result.href;
69
+ }
70
+ }
71
+ if (!disabled || disabledFocusable) {
72
+ result.tabIndex = rest.tabIndex ?? 0;
73
+ }
74
+ return result;
75
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "components-test-pb",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -10,6 +10,7 @@ export type ButtonSize = 'small' | 'medium' | 'large';
10
10
  export type ButtonProps = ComponentProps<ButtonSlots> & {
11
11
  appearance?: 'secondary' | 'primary' | 'tertiary';
12
12
  disabled?: boolean;
13
+ disabledFocusable?: boolean;
13
14
  shape?: 'rounded' | 'circular' | 'square';
14
15
  size?: ButtonSize;
15
16
  };
@@ -20,6 +21,6 @@ export type ButtonState = ComponentState<ButtonSlots> &
20
21
  Required<
21
22
  Pick<
22
23
  ButtonProps,
23
- 'appearance' | 'disabled' | 'shape' | 'size'
24
+ 'appearance' | 'disabled' | 'disabledFocusable' | 'shape' | 'size'
24
25
  >
25
26
  >;
@@ -1,16 +1,27 @@
1
1
  import type { ButtonProps, ButtonState } from './Button.types.js';
2
+ import { useARIAButtonProps } from '../../utilities/useARIAButtonProps.js';
3
+ import type { ARIAButtonType } from '../../utilities/useARIAButtonProps.js';
2
4
 
3
5
  export const useButton = (props: ButtonProps): ButtonState => {
4
- const { appearance, shape, size, disabled, ...buttonProps } = props;
6
+ const { appearance, shape, size, disabled, disabledFocusable, ...buttonProps } = props;
7
+
8
+ const tag = (buttonProps.as ?? 'button') as ARIAButtonType;
9
+
10
+ const ariaButtonProps = useARIAButtonProps(tag, {
11
+ ...buttonProps,
12
+ disabled,
13
+ disabledFocusable,
14
+ });
5
15
 
6
16
  return {
7
17
  appearance: appearance ?? 'secondary',
8
18
  shape: shape ?? 'rounded',
9
19
  size: size ?? 'medium',
10
20
  disabled: disabled ?? false,
21
+ disabledFocusable: disabledFocusable ?? false,
11
22
 
12
- components: { root: buttonProps.as ?? 'button' },
23
+ components: { root: tag },
13
24
 
14
- root: { as: buttonProps.as ?? 'button', disabled: disabled ?? false, ...buttonProps } as ButtonState['root'],
25
+ root: { as: tag, ...ariaButtonProps } as ButtonState['root'],
15
26
  };
16
- };
27
+ };
@@ -117,10 +117,55 @@ const useRootStyles = makeStyles({
117
117
  });
118
118
 
119
119
  const useRootDisabledstyles = makeStyles({
120
- base: {},
121
- primary: {},
120
+ base: {
121
+ backgroundColor: Tokens.colorNeutralBackgroundDisabled,
122
+ ...shorthands.borderColor(Tokens.colorNeutralStrokeDisabled),
123
+ color: Tokens.colorNeutralForegroundDisabled,
124
+
125
+ cursor: 'not-allowed',
126
+
127
+ ':hover': {
128
+ backgroundColor: Tokens.colorNeutralBackgroundDisabled,
129
+ ...shorthands.borderColor(Tokens.colorNeutralStrokeDisabled),
130
+ color: Tokens.colorNeutralForegroundDisabled,
131
+
132
+ cursor: 'not-allowed'
133
+ },
134
+
135
+ ':hover:active,:active:focus-visible': {
136
+ backgroundColor: Tokens.colorNeutralBackgroundDisabled,
137
+ ...shorthands.borderColor(Tokens.colorNeutralStrokeDisabled),
138
+ color: Tokens.colorNeutralForegroundDisabled,
139
+
140
+ cursor: 'not-allowed'
141
+ }
142
+ },
143
+ primary: {
144
+ ...shorthands.borderColor('transparent'),
145
+
146
+ ':hover': {
147
+ ...shorthands.borderColor('transparent')
148
+ },
149
+
150
+ ':hover:active,:active:focus-visible': {
151
+ ...shorthands.borderColor('transparent')
152
+ }
153
+ },
122
154
  secondary: {},
123
- tertiary: {}
155
+ tertiary: {
156
+ backgroundColor: 'transparent',
157
+ ...shorthands.borderColor('transparent'),
158
+
159
+ ':hover': {
160
+ backgroundColor: 'transparent',
161
+ ...shorthands.borderColor('transparent')
162
+ },
163
+
164
+ ':hover:active,:active:focus-visible': {
165
+ backgroundColor: 'transparent',
166
+ ...shorthands.borderColor('transparent')
167
+ }
168
+ }
124
169
  });
125
170
 
126
171
  export const useButtonStyles = (state: ButtonState): ButtonState => {
@@ -130,7 +175,9 @@ export const useButtonStyles = (state: ButtonState): ButtonState => {
130
175
  const rootStyles = useRootStyles();
131
176
  const rootDisabledStyles = useRootDisabledstyles();
132
177
 
133
- const { appearance, disabled, shape, size } = state;
178
+ const { appearance, disabled, disabledFocusable, shape, size } = state;
179
+
180
+ const isDisabled = disabled || disabledFocusable;
134
181
 
135
182
  state.root.className = mergeClasses(
136
183
  buttonClassNames.root,
@@ -141,8 +188,8 @@ export const useButtonStyles = (state: ButtonState): ButtonState => {
141
188
  rootStyles[size],
142
189
  rootStyles[shape],
143
190
 
144
- disabled && rootDisabledStyles.base,
145
- appearance && disabled && rootDisabledStyles[appearance],
191
+ isDisabled && rootDisabledStyles.base,
192
+ appearance && isDisabled && rootDisabledStyles[appearance],
146
193
 
147
194
  state.root.className,
148
195
  );
package/src/index.ts CHANGED
@@ -26,4 +26,7 @@ export type {
26
26
  } from './Components/Button/index.js';
27
27
 
28
28
  export * from './Types/compose/index.js';
29
- export * from './Types/utils/index.js';
29
+ export * from './Types/utils/index.js';
30
+
31
+ export { useARIAButtonProps } from './utilities/index.js';
32
+ export type { ARIAButtonType, ARIAButtonProps, ARIAButtonResultProps } from './utilities/index.js';
@@ -0,0 +1,2 @@
1
+ export { useARIAButtonProps } from './useARIAButtonProps.js';
2
+ export type { ARIAButtonType, ARIAButtonProps, ARIAButtonResultProps } from './useARIAButtonProps.js';
@@ -0,0 +1,106 @@
1
+ import type { HTMLAttributes, IntrinsicElementKeys } from '../Types/utils/types.js';
2
+
3
+ export type ARIAButtonType = 'button' | 'a' | 'div';
4
+
5
+ export type ARIAButtonProps<Tag extends ARIAButtonType = 'button'> = HTMLAttributes<HTMLElement> & {
6
+ disabled?: boolean;
7
+ disabledFocusable?: boolean;
8
+ } & (Tag extends 'a' ? { href?: string } : {});
9
+
10
+ export type ARIAButtonResultProps<Tag extends ARIAButtonType = 'button'> = HTMLAttributes<HTMLElement> & {
11
+ disabled?: Tag extends 'button' ? '' | undefined : never;
12
+ 'aria-disabled'?: 'true';
13
+ role?: string;
14
+ tabIndex?: number;
15
+ href?: string;
16
+ };
17
+
18
+ const noop = () => { };
19
+
20
+ export const useARIAButtonProps = <Tag extends ARIAButtonType>(
21
+ tag: Tag,
22
+ props: ARIAButtonProps<Tag> = {} as ARIAButtonProps<Tag>,
23
+ ): ARIAButtonResultProps<Tag> => {
24
+ const { disabled, disabledFocusable, onClick, onKeyDown, onKeyUp, ...rest } = props as ARIAButtonProps & { href?: string };
25
+
26
+ const isDisabled = disabled || disabledFocusable;
27
+
28
+ const handleClick = (e: MouseEvent) => {
29
+ if (isDisabled) {
30
+ e.preventDefault();
31
+ e.stopPropagation();
32
+ return;
33
+ }
34
+ onClick?.(e);
35
+ };
36
+
37
+ if (tag === 'button') {
38
+ const result = {
39
+ ...rest,
40
+ onClick: handleClick,
41
+ onKeyDown: isDisabled ? (e: KeyboardEvent) => {
42
+ e.preventDefault();
43
+ e.stopPropagation();
44
+ } : onKeyDown,
45
+ onKeyUp: isDisabled ? (e: KeyboardEvent) => {
46
+ e.preventDefault();
47
+ e.stopPropagation();
48
+ } : onKeyUp,
49
+ } as ARIAButtonResultProps<Tag>;
50
+
51
+ if (disabled && !disabledFocusable) {
52
+ (result as any).disabled = '';
53
+ } else if (disabledFocusable) {
54
+ result['aria-disabled'] = 'true';
55
+ }
56
+
57
+ return result;
58
+ }
59
+
60
+ const handleKeyDown = (e: KeyboardEvent) => {
61
+ if (isDisabled) {
62
+ e.preventDefault();
63
+ e.stopPropagation();
64
+ return;
65
+ }
66
+ if (e.key === 'Enter') {
67
+ e.preventDefault();
68
+ (e.target as HTMLElement)?.click();
69
+ }
70
+ onKeyDown?.(e);
71
+ };
72
+
73
+ const handleKeyUp = (e: KeyboardEvent) => {
74
+ if (isDisabled) {
75
+ e.preventDefault();
76
+ e.stopPropagation();
77
+ return;
78
+ }
79
+ if (e.key === ' ') {
80
+ e.preventDefault();
81
+ (e.target as HTMLElement)?.click();
82
+ }
83
+ onKeyUp?.(e);
84
+ };
85
+
86
+ const result: ARIAButtonResultProps<Tag> = {
87
+ ...rest,
88
+ role: 'button',
89
+ onClick: handleClick,
90
+ onKeyDown: handleKeyDown,
91
+ onKeyUp: handleKeyUp,
92
+ } as ARIAButtonResultProps<Tag>;
93
+
94
+ if (isDisabled) {
95
+ result['aria-disabled'] = 'true';
96
+ if (tag === 'a') {
97
+ delete (result as any).href;
98
+ }
99
+ }
100
+
101
+ if (!disabled || disabledFocusable) {
102
+ result.tabIndex = rest.tabIndex ?? 0;
103
+ }
104
+
105
+ return result;
106
+ };