Skip to content

Commit

Permalink
Refactor icons padding affordance with CSS variables and calc()
Browse files Browse the repository at this point in the history
- use inline styles to set the CSS variables dynamically based on props, which lets us reduce compressed overrides

- store icon size affordances in variable obj
  • Loading branch information
cee-chen committed May 20, 2024
1 parent 5501d49 commit 4ddc0ef
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports[`EuiFieldText is rendered 1`] = `
<eui-validatable-control>
<input
aria-label="aria-label"
class="euiFieldText testClass1 testClass2 euiFieldText--withIcon emotion-euiFieldText-euiTestCss"
class="euiFieldText testClass1 testClass2 emotion-euiFieldText-euiTestCss"
data-test-subj="test subject string"
id="1"
name="elastic"
Expand Down Expand Up @@ -54,7 +54,7 @@ exports[`EuiFieldText props isInvalid is rendered 1`] = `
isinvalid="true"
>
<input
class="euiFieldText euiFormControlLayout--1icons emotion-euiFieldText"
class="euiFieldText emotion-euiFieldText"
type="text"
value=""
/>
Expand All @@ -69,7 +69,7 @@ exports[`EuiFieldText props isLoading is rendered 1`] = `
>
<eui-validatable-control>
<input
class="euiFieldText euiFormControlLayout--1icons euiFieldText-isLoading emotion-euiFieldText"
class="euiFieldText euiFieldText-isLoading emotion-euiFieldText"
type="text"
value=""
/>
Expand Down
7 changes: 0 additions & 7 deletions packages/eui/src/components/form/field_text/_field_text.scss
Original file line number Diff line number Diff line change
@@ -1,7 +0,0 @@
.euiFieldText {
@include euiFormControlWithIcon($isIconOptional: true, $side: 'left');
}

.euiFieldText--withIcon.euiFieldText--compressed {
@include euiFormControlWithIcon($isIconOptional: false, $side: 'left', $compressed: true);
}
33 changes: 16 additions & 17 deletions packages/eui/src/components/form/field_text/field_text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
* Side Public License, v 1.
*/

import React, { InputHTMLAttributes, Ref, FunctionComponent } from 'react';
import React, {
InputHTMLAttributes,
Ref,
FunctionComponent,
useMemo,
} from 'react';
import classNames from 'classnames';

import { useEuiMemoizedStyles } from '../../../services';
Expand All @@ -16,10 +21,7 @@ import {
EuiFormControlLayoutProps,
} from '../form_control_layout';
import { EuiValidatableControl } from '../validatable_control';
import {
isRightSideIcon,
getFormControlClassNameForIconCount,
} from '../form_control_layout/_num_icons';
import { getIconAffordanceStyles } from '../form_control_layout/_num_icons';
import { useFormContext } from '../eui_form_context';

import { euiFieldTextStyles } from './field_text.styles';
Expand Down Expand Up @@ -70,6 +72,7 @@ export const EuiFieldText: FunctionComponent<EuiFieldTextProps> = (props) => {
placeholder,
value,
className,
style,
icon,
isInvalid,
inputRef,
Expand All @@ -83,19 +86,8 @@ export const EuiFieldText: FunctionComponent<EuiFieldTextProps> = (props) => {
...rest
} = props;

const hasRightSideIcon = isRightSideIcon(icon);

const numIconsClass = controlOnly
? false
: getFormControlClassNameForIconCount({
isInvalid,
isLoading,
icon: hasRightSideIcon,
});

const classes = classNames('euiFieldText', className, numIconsClass, {
const classes = classNames('euiFieldText', className, {
...(!controlOnly && {
'euiFieldText--withIcon': icon && !hasRightSideIcon,
'euiFieldText--inGroup': prepend || append,
}),
'euiFieldText-isLoading': isLoading,
Expand All @@ -108,6 +100,12 @@ export const EuiFieldText: FunctionComponent<EuiFieldTextProps> = (props) => {
fullWidth ? styles.fullWidth : styles.formWidth,
];

const iconAffordanceStyles = useMemo(() => {
return !controlOnly
? getIconAffordanceStyles({ icon, isInvalid, isLoading })
: undefined;
}, [controlOnly, icon, isInvalid, isLoading]);

const control = (
<EuiValidatableControl isInvalid={isInvalid}>
<input
Expand All @@ -117,6 +115,7 @@ export const EuiFieldText: FunctionComponent<EuiFieldTextProps> = (props) => {
placeholder={placeholder}
className={classes}
css={cssStyles}
style={{ ...iconAffordanceStyles, ...style }}
value={value}
ref={inputRef}
readOnly={readOnly}
Expand Down
10 changes: 8 additions & 2 deletions packages/eui/src/components/form/form.styles.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ describe('euiFormVariables', () => {
"controlPlaceholderText": "#646a77",
"customControlBorderColor": "#f5f7fc",
"customControlDisabledIconColor": "#cacfd8",
"iconAffordance": "24px",
"iconCompressedAffordance": "18px",
"inputGroupBorder": "none",
"inputGroupLabelBackground": "#e9edf3",
"maxWidth": "400px",
Expand Down Expand Up @@ -89,7 +91,9 @@ describe('euiFormControlStyles', () => {
}",
"compressed": "
block-size: 32px;
padding: 8px;
padding-block: 8px;
padding-inline-start: calc(8px + (18px * var(--euiFormControlLeftIconsCount, 0)));
padding-inline-end: calc(8px + (18px * var(--euiFormControlRightIconsCount, 0)));
border-radius: 4px;
",
"disabled": "
Expand Down Expand Up @@ -203,7 +207,9 @@ describe('euiFormControlStyles', () => {
",
"uncompressed": "
block-size: 40px;
padding: 12px;
padding-block: 12px;
padding-inline-start: calc(12px + (24px * var(--euiFormControlLeftIconsCount, 0)));
padding-inline-end: calc(12px + (24px * var(--euiFormControlRightIconsCount, 0)));
border-radius: 6px;
",
}
Expand Down
22 changes: 20 additions & 2 deletions packages/eui/src/components/form/form.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export const euiFormVariables = (euiThemeContext: UseEuiTheme) => {
controlCompressedPadding: euiTheme.size.s,
controlBorderRadius: euiTheme.border.radius.medium,
controlCompressedBorderRadius: euiTheme.border.radius.small,
iconAffordance: mathWithUnits(euiTheme.size.base, (x) => x * 1.5),
iconCompressedAffordance: mathWithUnits(euiTheme.size.m, (x) => x * 1.5),
};

const colors = {
Expand Down Expand Up @@ -118,12 +120,28 @@ export const euiFormControlStyles = (euiThemeContext: UseEuiTheme) => {
// Sizes
uncompressed: `
${logicalCSS('height', form.controlHeight)}
padding: ${form.controlPadding};
${logicalCSS('padding-vertical', form.controlPadding)}
${logicalCSS(
'padding-left',
`calc(${form.controlPadding} + (${form.iconAffordance} * var(--euiFormControlLeftIconsCount, 0)))`
)}
${logicalCSS(
'padding-right',
`calc(${form.controlPadding} + (${form.iconAffordance} * var(--euiFormControlRightIconsCount, 0)))`
)}
border-radius: ${form.controlBorderRadius};
`,
compressed: `
${logicalCSS('height', form.controlCompressedHeight)}
padding: ${form.controlCompressedPadding};
${logicalCSS('padding-vertical', form.controlCompressedPadding)}
${logicalCSS(
'padding-left',
`calc(${form.controlCompressedPadding} + (${form.iconCompressedAffordance} * var(--euiFormControlLeftIconsCount, 0)))`
)}
${logicalCSS(
'padding-right',
`calc(${form.controlCompressedPadding} + (${form.iconCompressedAffordance} * var(--euiFormControlRightIconsCount, 0)))`
)}
border-radius: ${form.controlCompressedBorderRadius};
`,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,68 @@
import {
getFormControlClassNameForIconCount,
isRightSideIcon,
getIconAffordanceStyles,
} from './_num_icons';

describe('getIconAffordanceStyles', () => {
const noIcons = {
icon: undefined,
clear: false,
isLoading: false,
isInvalid: false,
isDropdown: false,
};
const allIcons = {
icon: { type: 'search', side: 'right' as const },
clear: true,
isLoading: true,
isInvalid: true,
isDropdown: true,
};

test('empty object', () => {
const styles = getIconAffordanceStyles({});
expect(styles).toEqual(undefined);
});

test('false values', () => {
const styles = getIconAffordanceStyles(noIcons);
expect(styles).toEqual(undefined);
});

test('all icons', () => {
const styles = getIconAffordanceStyles(allIcons);
expect(styles).toMatchInlineSnapshot(`
Object {
"--euiFormControlRightIconsCount": 5,
}
`);
});

test('some icons', () => {
const styles = getIconAffordanceStyles({
isLoading: true,
isInvalid: true,
});
expect(styles).toMatchInlineSnapshot(`
Object {
"--euiFormControlRightIconsCount": 2,
}
`);
});

test('left icon', () => {
const styles = getIconAffordanceStyles({
icon: 'search',
});
expect(styles).toMatchInlineSnapshot(`
Object {
"--euiFormControlLeftIconsCount": 1,
}
`);
});
});

describe('getFormControlClassNameForIconCount', () => {
it('should return undefined if object is empty', () => {
const numberClass = getFormControlClassNameForIconCount({});
Expand Down
37 changes: 37 additions & 0 deletions packages/eui/src/components/form/form_control_layout/_num_icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,40 @@ export const isRightSideIcon = (
): boolean => {
return !!icon && isIconShape(icon) && icon.side === 'right';
};

export const getIconAffordanceStyles = ({
icon,
clear,
isLoading,
isInvalid,
isDropdown,
}: {
icon?: EuiFormControlLayoutIconsProps['icon'];
clear?: boolean;
isLoading?: boolean;
isInvalid?: boolean;
isDropdown?: boolean;
}) => {
const cssVariables = {
'--euiFormControlLeftIconsCount': 0,
'--euiFormControlRightIconsCount': 0,
};

if (icon) {
if (isRightSideIcon(icon)) {
cssVariables['--euiFormControlRightIconsCount']++;
} else {
cssVariables['--euiFormControlLeftIconsCount']++;
}
}

if (clear) cssVariables['--euiFormControlRightIconsCount']++;
if (isLoading) cssVariables['--euiFormControlRightIconsCount']++;
if (isInvalid) cssVariables['--euiFormControlRightIconsCount']++;
if (isDropdown) cssVariables['--euiFormControlRightIconsCount']++;

const filtered = Object.entries(cssVariables).filter(
([, count]) => count > 0
);
return filtered.length ? Object.fromEntries(filtered) : undefined;
};

0 comments on commit 4ddc0ef

Please sign in to comment.