Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a413324
fix(Button): unify all button styles into a single object
tenphi Jan 6, 2023
2befa93
fix(Button): add useAction hook and special theme
tenphi Jan 6, 2023
29c647b
fix(Button): add useAction hook and special theme * 2
tenphi Jan 6, 2023
17c8b4e
fix(Select): styles rework
tenphi Jan 6, 2023
d2e43fd
fix(Button): special neutral styles
tenphi Jan 6, 2023
727ac3c
fix(Button): style props
tenphi Jan 6, 2023
213d3c8
fix(Button): style props * 2
tenphi Jan 7, 2023
d60a4ef
fix(Button): remove border in link type
tenphi Jan 7, 2023
c9022d0
refactor(tasty): additional optimizations to cache
tenphi Jan 7, 2023
352bf80
fix(Button): focus state
tenphi Jan 7, 2023
58f1dc2
refactor(Action): use tasty element
tenphi Jan 7, 2023
279055a
fix(Select): type typings
tenphi Jan 7, 2023
c28edb0
chore: simplify ComplexForm story
tenphi Jan 7, 2023
04a7d60
chore: simplify ComplexForm story * 2
tenphi Jan 7, 2023
56a3a16
refactor(tasty): cache optimization
tenphi Jan 9, 2023
22b69e5
chore: do not render ComplexForm story in chromatic
tenphi Jan 9, 2023
6ec194d
chore: do not render ComplexForm story in chromatic * 2
tenphi Jan 9, 2023
1a97f83
chore: do not render ComplexForm story in chromatic * 3
tenphi Jan 9, 2023
118e96e
chore: render ComplexForm story in chromatic
tenphi Jan 9, 2023
009facb
chore: improve tests speed
tenphi Jan 9, 2023
86d3274
fix(Button): fix size in icon-only variant
tenphi Jan 11, 2023
63fd411
fix(Title): add ellipsis where it is required
tenphi Jan 12, 2023
4061b1d
fix(Action): as prop and styles
tenphi Jan 13, 2023
f4f4502
fix(use-action): label passing
tenphi Jan 16, 2023
37fbd1a
fix(Button): secondary special styles
tenphi Jan 16, 2023
dfdf2de
feat(Select): add special theme
tenphi Jan 16, 2023
6b8b639
fix(Button): special neutral styles
tenphi Jan 16, 2023
03f6c6b
fix(Button): special neutral styles * 2
tenphi Jan 16, 2023
b4f7512
fix(Button): link disabled fill style
tenphi Jan 16, 2023
485fd0e
fix(Select): limited width state
tenphi Jan 17, 2023
fc56b51
feat(Select): ellipsis prop
tenphi Jan 17, 2023
4a2cce4
fix(RangeSlider): input api
tenphi Jan 17, 2023
846c17a
Create warm-donkeys-joke.md
tenphi Jan 18, 2023
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/warm-donkeys-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@cube-dev/ui-kit": patch
---

Add new `special` theme for `Button` and `Select` components.
Allow single input layout for `RangeSlider` component.
Add `ellipsis` property to `Select` component to allow text overflow of selected value.
2 changes: 1 addition & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const config = {
},
],
webpackFinal: (config) => {
config.plugins.push(new webpack.DefinePlugin({ SC_DISABLE_SPEEDY: true }));
config.plugins.push(new webpack.DefinePlugin({ SC_DISABLE_SPEEDY: false }));
config.performance.hints = false;

return config;
Expand Down
2 changes: 2 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
process.env.SC_DISABLE_SPEEDY = 'false';

/** @type {import('@jest/types').Config.InitialOptions} */
const config = {
coverageDirectory: './coverage/',
Expand Down
169 changes: 18 additions & 151 deletions src/components/actions/Action.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import { forwardRef, MouseEventHandler, useCallback, useContext } from 'react';
import { useHover } from '@react-aria/interactions';
import { useButton } from '@react-aria/button';
import { forwardRef, MouseEventHandler } from 'react';
import { AriaButtonProps } from '@react-types/button';
import { useFocusableRef } from '@react-spectrum/utils';
import { FocusableRef } from '@react-types/shared';

import { UIKitContext } from '../../provider';
import { mergeProps } from '../../utils/react';
import { useFocus } from '../../utils/react/interactions';
import {
BaseProps,
BaseStyleProps,
CONTAINER_STYLES,
ContainerStyleProps,
extractStyles,
filterBaseProps,
Styles,
TagNameProps,
TEXT_STYLES,
TextStyleProps,
Element,
tasty,
} from '../../tasty';

import { useAction } from './use-action';

export interface CubeActionProps
extends BaseProps,
TagNameProps,
Expand All @@ -37,92 +32,11 @@ export interface CubeActionProps
onMouseLeave?: MouseEventHandler;
}

const FILTER_OPTIONS = { propNames: new Set(['onMouseEnter', 'onMouseLeave']) };

/**
* Helper to open link.
* @param {String} href
* @param {String|Boolean} [target]
*/
export function openLink(href, target?) {
const link = document.createElement('a');

link.href = href;

if (target) {
link.target = target === true ? '_blank' : target;
}

document.body.appendChild(link);

link.click();

document.body.removeChild(link);
}

export function parseTo(to): {
newTab: boolean;
nativeRoute: boolean;
href: string | undefined;
} {
const newTab = to && typeof to === 'string' && to.startsWith('!');
const nativeRoute = to && typeof to === 'string' && to.startsWith('@');
const href: string | undefined =
to && typeof to === 'string'
? newTab || nativeRoute
? to.slice(1)
: to
: undefined;

return {
newTab,
nativeRoute,
href,
};
}

export function performClickHandler(evt, router, to, onPress) {
const { newTab, nativeRoute, href } = parseTo(to);

onPress?.(evt);

if (!to) return;

if (evt.shiftKey || evt.metaKey || newTab) {
openLink(href, true);

return;
}

if (nativeRoute) {
openLink(href || window.location.href);
} else if (href && href.startsWith('#')) {
const id = href.slice(1);
const element = document.getElementById(id);

if (element) {
element.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest',
});

return;
}
}

if (router) {
router.push(href);
} else if (href) {
window.location.href = href;
}
}

const DEFAULT_STYLES: Styles = {
const DEFAULT_ACTION_STYLES: Styles = {
reset: 'button',
position: 'relative',
margin: 0,
fontFamily: 'var(--font)',
preset: 'inherit',
border: 0,
padding: 0,
outline: {
Expand All @@ -131,74 +45,27 @@ const DEFAULT_STYLES: Styles = {
},
transition: 'theme',
cursor: 'pointer',
textDecoration: 'none',
fill: '#clear',
} as const;

const ActionElement = tasty({
as: 'button',
styles: DEFAULT_ACTION_STYLES,
});

const STYLE_PROPS = [...CONTAINER_STYLES, ...TEXT_STYLES];

export const Action = forwardRef(function Action(
{ to, as, htmlType, label, theme, mods, onPress, ...props }: CubeActionProps,
ref: FocusableRef<HTMLElement>,
) {
as = to ? 'a' : as || 'button';

const router = useContext(UIKitContext).router;
const isDisabled = props.isDisabled;
const { newTab, href } = parseTo(to);
const target = newTab ? '_blank' : undefined;
const domRef = useFocusableRef(ref);
const styles = extractStyles(props, STYLE_PROPS, DEFAULT_STYLES);

const customOnPress = useCallback(
(evt) => {
performClickHandler(evt, router, to, onPress);
},
[router, to, onPress],
const { actionProps } = useAction(
{ to, as, htmlType, label, onPress, mods, ...props },
ref,
);

let { buttonProps, isPressed } = useButton(
{
...props,
onPress: customOnPress,
},
domRef,
);
let { hoverProps, isHovered } = useHover({ isDisabled });
let { focusProps, isFocused } = useFocus({ isDisabled }, true);

const customProps = to
? {
onClick(evt) {
evt.preventDefault();
},
}
: {};
const styles = extractStyles(props, STYLE_PROPS);

return (
<Element
mods={{
hovered: isHovered && !isDisabled,
pressed: isPressed && !isDisabled,
focused: isFocused && !isDisabled,
disabled: isDisabled,
...mods,
}}
aria-label={label}
data-theme={theme}
{...mergeProps(
buttonProps,
hoverProps,
focusProps,
customProps,
filterBaseProps(props, FILTER_OPTIONS),
)}
ref={domRef}
type={htmlType || 'button'}
rel={as === 'a' && newTab ? 'rel="noopener noreferrer"' : undefined}
as={as}
isDisabled={isDisabled}
styles={styles}
target={target}
href={href}
/>
);
return <ActionElement data-theme={theme} {...actionProps} styles={styles} />;
});
Loading