Skip to content

Commit 90cc2f8

Browse files
authored
fix(Button): unify all button styles into a single object (#271)
1 parent 32d062a commit 90cc2f8

File tree

27 files changed

+778
-500
lines changed

27 files changed

+778
-500
lines changed

.changeset/warm-donkeys-joke.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@cube-dev/ui-kit": patch
3+
---
4+
5+
Add new `special` theme for `Button` and `Select` components.
6+
Allow single input layout for `RangeSlider` component.
7+
Add `ellipsis` property to `Select` component to allow text overflow of selected value.

.storybook/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const config = {
5050
},
5151
],
5252
webpackFinal: (config) => {
53-
config.plugins.push(new webpack.DefinePlugin({ SC_DISABLE_SPEEDY: true }));
53+
config.plugins.push(new webpack.DefinePlugin({ SC_DISABLE_SPEEDY: false }));
5454
config.performance.hints = false;
5555

5656
return config;

jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
process.env.SC_DISABLE_SPEEDY = 'false';
2+
13
/** @type {import('@jest/types').Config.InitialOptions} */
24
const config = {
35
coverageDirectory: './coverage/',

src/components/actions/Action.tsx

Lines changed: 18 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
1-
import { forwardRef, MouseEventHandler, useCallback, useContext } from 'react';
2-
import { useHover } from '@react-aria/interactions';
3-
import { useButton } from '@react-aria/button';
1+
import { forwardRef, MouseEventHandler } from 'react';
42
import { AriaButtonProps } from '@react-types/button';
5-
import { useFocusableRef } from '@react-spectrum/utils';
63
import { FocusableRef } from '@react-types/shared';
74

8-
import { UIKitContext } from '../../provider';
9-
import { mergeProps } from '../../utils/react';
10-
import { useFocus } from '../../utils/react/interactions';
115
import {
126
BaseProps,
137
BaseStyleProps,
148
CONTAINER_STYLES,
159
ContainerStyleProps,
1610
extractStyles,
17-
filterBaseProps,
1811
Styles,
1912
TagNameProps,
2013
TEXT_STYLES,
2114
TextStyleProps,
22-
Element,
15+
tasty,
2316
} from '../../tasty';
2417

18+
import { useAction } from './use-action';
19+
2520
export interface CubeActionProps
2621
extends BaseProps,
2722
TagNameProps,
@@ -37,92 +32,11 @@ export interface CubeActionProps
3732
onMouseLeave?: MouseEventHandler;
3833
}
3934

40-
const FILTER_OPTIONS = { propNames: new Set(['onMouseEnter', 'onMouseLeave']) };
41-
42-
/**
43-
* Helper to open link.
44-
* @param {String} href
45-
* @param {String|Boolean} [target]
46-
*/
47-
export function openLink(href, target?) {
48-
const link = document.createElement('a');
49-
50-
link.href = href;
51-
52-
if (target) {
53-
link.target = target === true ? '_blank' : target;
54-
}
55-
56-
document.body.appendChild(link);
57-
58-
link.click();
59-
60-
document.body.removeChild(link);
61-
}
62-
63-
export function parseTo(to): {
64-
newTab: boolean;
65-
nativeRoute: boolean;
66-
href: string | undefined;
67-
} {
68-
const newTab = to && typeof to === 'string' && to.startsWith('!');
69-
const nativeRoute = to && typeof to === 'string' && to.startsWith('@');
70-
const href: string | undefined =
71-
to && typeof to === 'string'
72-
? newTab || nativeRoute
73-
? to.slice(1)
74-
: to
75-
: undefined;
76-
77-
return {
78-
newTab,
79-
nativeRoute,
80-
href,
81-
};
82-
}
83-
84-
export function performClickHandler(evt, router, to, onPress) {
85-
const { newTab, nativeRoute, href } = parseTo(to);
86-
87-
onPress?.(evt);
88-
89-
if (!to) return;
90-
91-
if (evt.shiftKey || evt.metaKey || newTab) {
92-
openLink(href, true);
93-
94-
return;
95-
}
96-
97-
if (nativeRoute) {
98-
openLink(href || window.location.href);
99-
} else if (href && href.startsWith('#')) {
100-
const id = href.slice(1);
101-
const element = document.getElementById(id);
102-
103-
if (element) {
104-
element.scrollIntoView({
105-
behavior: 'smooth',
106-
block: 'start',
107-
inline: 'nearest',
108-
});
109-
110-
return;
111-
}
112-
}
113-
114-
if (router) {
115-
router.push(href);
116-
} else if (href) {
117-
window.location.href = href;
118-
}
119-
}
120-
121-
const DEFAULT_STYLES: Styles = {
35+
const DEFAULT_ACTION_STYLES: Styles = {
12236
reset: 'button',
12337
position: 'relative',
12438
margin: 0,
125-
fontFamily: 'var(--font)',
39+
preset: 'inherit',
12640
border: 0,
12741
padding: 0,
12842
outline: {
@@ -131,74 +45,27 @@ const DEFAULT_STYLES: Styles = {
13145
},
13246
transition: 'theme',
13347
cursor: 'pointer',
48+
textDecoration: 'none',
49+
fill: '#clear',
13450
} as const;
13551

52+
const ActionElement = tasty({
53+
as: 'button',
54+
styles: DEFAULT_ACTION_STYLES,
55+
});
56+
13657
const STYLE_PROPS = [...CONTAINER_STYLES, ...TEXT_STYLES];
13758

13859
export const Action = forwardRef(function Action(
13960
{ to, as, htmlType, label, theme, mods, onPress, ...props }: CubeActionProps,
14061
ref: FocusableRef<HTMLElement>,
14162
) {
142-
as = to ? 'a' : as || 'button';
143-
144-
const router = useContext(UIKitContext).router;
145-
const isDisabled = props.isDisabled;
146-
const { newTab, href } = parseTo(to);
147-
const target = newTab ? '_blank' : undefined;
148-
const domRef = useFocusableRef(ref);
149-
const styles = extractStyles(props, STYLE_PROPS, DEFAULT_STYLES);
150-
151-
const customOnPress = useCallback(
152-
(evt) => {
153-
performClickHandler(evt, router, to, onPress);
154-
},
155-
[router, to, onPress],
63+
const { actionProps } = useAction(
64+
{ to, as, htmlType, label, onPress, mods, ...props },
65+
ref,
15666
);
15767

158-
let { buttonProps, isPressed } = useButton(
159-
{
160-
...props,
161-
onPress: customOnPress,
162-
},
163-
domRef,
164-
);
165-
let { hoverProps, isHovered } = useHover({ isDisabled });
166-
let { focusProps, isFocused } = useFocus({ isDisabled }, true);
167-
168-
const customProps = to
169-
? {
170-
onClick(evt) {
171-
evt.preventDefault();
172-
},
173-
}
174-
: {};
68+
const styles = extractStyles(props, STYLE_PROPS);
17569

176-
return (
177-
<Element
178-
mods={{
179-
hovered: isHovered && !isDisabled,
180-
pressed: isPressed && !isDisabled,
181-
focused: isFocused && !isDisabled,
182-
disabled: isDisabled,
183-
...mods,
184-
}}
185-
aria-label={label}
186-
data-theme={theme}
187-
{...mergeProps(
188-
buttonProps,
189-
hoverProps,
190-
focusProps,
191-
customProps,
192-
filterBaseProps(props, FILTER_OPTIONS),
193-
)}
194-
ref={domRef}
195-
type={htmlType || 'button'}
196-
rel={as === 'a' && newTab ? 'rel="noopener noreferrer"' : undefined}
197-
as={as}
198-
isDisabled={isDisabled}
199-
styles={styles}
200-
target={target}
201-
href={href}
202-
/>
203-
);
70+
return <ActionElement data-theme={theme} {...actionProps} styles={styles} />;
20471
});

0 commit comments

Comments
 (0)