Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pretty-goats-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cube-dev/ui-kit': minor
---

Always wrap Switch in a Field.
5 changes: 5 additions & 0 deletions .changeset/thick-horses-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cube-dev/ui-kit': minor
---

Always wrap Checkbox in a Field except checkbox group case.
47 changes: 25 additions & 22 deletions src/components/fields/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,33 @@ export default {
},
};

const Template = (props) => (
<Flow gap="2x">
<Checkbox
aria-label="Checkbox"
{...props}
defaultSelected={true}
onChange={(query) => console.log('onChange event', query)}
/>
<Checkbox
aria-label="Checkbox"
{...props}
defaultSelected={false}
onChange={(query) => console.log('onChange event', query)}
/>
</Flow>
);
const Template = (props) => {
return (
<Flow gap="2x">
<Checkbox
aria-label="Checkbox"
{...props}
defaultSelected={true}
onChange={(query) => console.log('onChange event', query)}
/>
<Checkbox
aria-label="Checkbox"
{...props}
defaultSelected={false}
onChange={(query) => console.log('onChange event', query)}
/>
</Flow>
);
};

export const Default = Template.bind({});
Default.args = { children: 'Checkbox' };

export const WithoutValue = Template.bind({});
WithoutValue.args = {
label: '',
};
export const WithLabel = Template.bind({});
WithLabel.args = { label: 'Checkbox' };

export const WithoutLabel = Template.bind({});
WithoutLabel.args = {};

export const Intermediate = Template.bind({});
Intermediate.args = {
Expand All @@ -54,11 +57,11 @@ Intermediate.args = {
export const Disabled = Template.bind({});
Disabled.args = {
isDisabled: true,
label: 'Checkbox',
children: 'Checkbox',
};

export const Invalid = Template.bind({});
Invalid.args = {
validationState: 'invalid',
label: 'Checkbox',
children: 'Checkbox',
};
29 changes: 15 additions & 14 deletions src/components/fields/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const CheckboxElement = tasty({
styles: {
display: 'grid',
placeItems: 'center',
radius: '.25x',
radius: '.5r',
fill: {
'': '#white',
'checked | indeterminate': '#purple-text',
Expand Down Expand Up @@ -165,10 +165,10 @@ function Checkbox(

labelStyles = useMemo(
() => ({
...(insideForm ? LABEL_STYLES : INLINE_LABEL_STYLES),
...(!groupState ? LABEL_STYLES : INLINE_LABEL_STYLES),
...labelStyles,
}),
[insideForm, labelStyles],
[groupState, labelStyles],
);

let { isFocused, focusProps } = useFocus({ isDisabled }, true);
Expand Down Expand Up @@ -234,12 +234,8 @@ function Checkbox(
'inside-form': insideForm,
};

const checkboxField = (
<CheckboxWrapperElement
isHidden={isHidden}
mods={mods}
styles={{ position: 'relative' }}
>
const checkbox = (
<>
<HiddenInput
data-qa="HiddenInput"
{...mergeProps(inputProps, focusProps)}
Expand All @@ -248,11 +244,17 @@ function Checkbox(
<CheckboxElement qa={qa || 'Checkbox'} mods={mods} styles={inputStyles}>
{markIcon}
</CheckboxElement>
</>
);

const checkboxField = (
<CheckboxWrapperElement isHidden={isHidden} mods={mods}>
{checkbox}
{children && <Text nowrap>{children}</Text>}
</CheckboxWrapperElement>
);

if (insideForm && !groupState) {
if (!groupState) {
return wrapWithField(checkboxField, domRef, {
...props,
children: null,
Expand All @@ -264,15 +266,14 @@ function Checkbox(

return (
<CheckboxWrapperElement
as="label"
styles={styles}
isHidden={isHidden}
{...hoverProps}
{...filterBaseProps(otherProps)}
ref={domRef}
>
{checkboxField}
{label ? (
{checkbox}
{label ?? children ? (
<Element
styles={labelStyles}
mods={{
Expand All @@ -282,7 +283,7 @@ function Checkbox(
}}
{...filterBaseProps(labelProps)}
>
{label}
{label ?? children}
</Element>
) : null}
</CheckboxWrapperElement>
Expand Down
24 changes: 20 additions & 4 deletions src/components/fields/Switch/Switch.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,37 @@ const Template = (args) => (

export const Default = Template.bind({});
Default.args = {
children: 'Switch',
};

export const WithLabel = Template.bind({});
WithLabel.args = {
label: 'Switch',
};

export const Small = Template.bind({});
Small.args = {
label: 'Switch',
children: 'Switch',
size: 'small',
};

export const WithoutLabel = Template.bind({});
WithoutLabel.args = {
label: '',
};
WithoutLabel.args = {};

export const Disabled = Template.bind({});
Disabled.args = {
children: 'Switch',
isDisabled: true,
};

export const Invalid = Template.bind({});
Invalid.args = {
children: 'Switch',
validationState: 'invalid',
};

export const Loading = Template.bind({});
Loading.args = {
children: 'Switch',
isLoading: true,
};
96 changes: 20 additions & 76 deletions src/components/fields/Switch/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef, useMemo, useRef } from 'react';
import { forwardRef, useRef } from 'react';
import { useFocusableRef } from '@react-spectrum/utils';
import { useSwitch, useHover, AriaSwitchProps } from 'react-aria';
import { useToggleState } from 'react-stately';
Expand All @@ -8,9 +8,7 @@ import {
BaseProps,
BLOCK_STYLES,
BlockStyleProps,
Element,
extractStyles,
filterBaseProps,
OUTER_STYLES,
OuterStyleProps,
Styles,
Expand All @@ -25,13 +23,7 @@ import {
castNullableIsSelected,
WithNullableSelected,
} from '../../../utils/react/nullableValue';
import {
useFieldProps,
useFormProps,
wrapWithField,
INLINE_LABEL_STYLES,
LABEL_STYLES,
} from '../../form';
import { useFieldProps, useFormProps, wrapWithField } from '../../form';
import { LoadingIcon } from '../../../icons';

const SwitchWrapperElement = tasty({
Expand All @@ -49,23 +41,6 @@ const SwitchWrapperElement = tasty({
},
});

const SwitchLabelElement = tasty({
as: 'label',
qa: 'SwitchLabel',
styles: {
position: 'relative',
display: 'flex',
placeItems: 'center',
gap: '1x',
flow: 'row',
preset: 'input',
width: 'min-content',
cursor: 'pointer',
verticalAlign: 'baseline',
color: '#dark-02',
},
});

const SwitchElement = tasty({
qa: 'Switch',
styles: {
Expand Down Expand Up @@ -94,6 +69,10 @@ const SwitchElement = tasty({
},
transition: 'theme',
cursor: 'pointer',
shadow: {
'': '0 0 0 0 #clear',
invalid: '0 0 0 1bw #white, 0 0 0 1ow #danger',
},

Thumb: {
position: 'absolute',
Expand Down Expand Up @@ -152,29 +131,19 @@ function Switch(props: WithNullableSelected<CubeSwitchProps>, ref) {
isDisabled = false,
children,
label,
labelProps,
labelStyles,
insideForm,
isLoading,
labelPosition,
inputStyles,
validationState,
size = 'large',
...otherProps
} = props;

let styles = extractStyles(props, OUTER_STYLES);

inputStyles = extractStyles(props, BLOCK_STYLES, inputStyles);

labelStyles = useMemo(
() => ({
...(insideForm ? LABEL_STYLES : INLINE_LABEL_STYLES),
...labelStyles,
}),
[insideForm, labelStyles],
);

let { isFocused, focusProps } = useFocus({ isDisabled }, true);
let { hoverProps, isHovered } = useHover({ isDisabled });

Expand Down Expand Up @@ -205,7 +174,7 @@ function Switch(props: WithNullableSelected<CubeSwitchProps>, ref) {
};

const switchField = (
<SwitchWrapperElement mods={mods} data-size={size}>
<SwitchWrapperElement mods={mods} data-size={size} {...hoverProps}>
<HiddenInput
data-qa="HiddenInput"
{...mergeProps(inputProps, focusProps)}
Expand All @@ -220,47 +189,22 @@ function Switch(props: WithNullableSelected<CubeSwitchProps>, ref) {
<div data-element="Thumb" aria-hidden="true" />
</SwitchElement>
{children ? <Text nowrap>{children}</Text> : null}
{isLoading ? (
<>
{label ? <>&nbsp;</> : null}
<LoadingIcon />
</>
) : null}
</SwitchWrapperElement>
);

if (insideForm) {
return wrapWithField(switchField, domRef, {
...props,
children: null,
labelStyles,
inputStyles,
styles,
});
}

return (
<SwitchLabelElement
styles={styles}
mods={mods}
{...hoverProps}
{...filterBaseProps(otherProps)}
ref={domRef}
>
{switchField}
{label ? (
<Element
styles={labelStyles}
mods={{
disabled: isDisabled,
}}
{...filterBaseProps(labelProps)}
>
{label}
{isLoading ? (
<>
{label ? <>&nbsp;</> : null}
<LoadingIcon />
</>
) : null}
</Element>
) : null}
</SwitchLabelElement>
);
return wrapWithField(switchField, domRef, {
...props,
children: null,
labelStyles,
inputStyles,
styles,
});
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/components/form/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const INTL_MESSAGES = {
export const INLINE_LABEL_STYLES: Styles = {
preset: 't3',
color: {
'': '#dark.85',
'': '#dark-02',
invalid: '#danger-text',
},
whiteSpace: 'nowrap',
Expand Down
Loading