Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiComboBox] Update to dogfood EuiTextTruncate #7028

Merged
merged 49 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
23aba4c
:lipstick: Move end truncation in separate class
dej611 Aug 2, 2023
00720dc
:heavy_plus_sign: Add canvas mock library for jest
dej611 Aug 2, 2023
8b67204
:sparkles: Add truncation middle feature
dej611 Aug 2, 2023
00241ea
:memo: Update documentation
dej611 Aug 2, 2023
df85489
Merge remote-tracking branch 'origin/master' into fix/5997
dej611 Aug 2, 2023
83bd86a
:ok_hand: Remove canvas usage + remove dependency
dej611 Aug 3, 2023
ea1be6c
:fire: Remove ellipsis
dej611 Aug 3, 2023
cb37976
:recycle: Reduce append operations
dej611 Aug 3, 2023
e269b00
Merge branch 'main' into fix/5997
cee-chen Aug 20, 2023
1aeec8c
Revert yarn.lock changes
cee-chen Aug 20, 2023
e07791d
revert jest config file changes
cee-chen Aug 21, 2023
6131706
Set up `EuiTextTruncate` component
cee-chen Aug 21, 2023
ce0bf7e
export / rest spread
cee-chen Aug 21, 2023
0261f23
Merge branch 'main' into fix/5997
cee-chen Aug 21, 2023
79cb351
More component cleanup/changes
cee-chen Aug 21, 2023
3f9671f
Add `onResize` callback + resize observer story
cee-chen Aug 21, 2023
d5d6f3d
Add startEnd anchor position logic needed for combobox search
cee-chen Aug 21, 2023
006eefa
[DX] Make the render prop optional
cee-chen Aug 21, 2023
0c0703c
[typing] Make `truncation` prop optional
cee-chen Aug 22, 2023
572ce0c
Rename `startEndAnchor` to `truncationPosition` + other cleanup
cee-chen Aug 22, 2023
09cc1c3
Write tests
cee-chen Aug 22, 2023
b45b719
Add docs page and examples for new component
cee-chen Aug 22, 2023
17047d1
Fix/workaround two crashing `truncationOffset` loops
cee-chen Aug 22, 2023
1af3b49
Improve screen reader and copy UX
cee-chen Aug 22, 2023
f46b348
Revert EuiComboBox changes to main
cee-chen Aug 22, 2023
8491224
Add new `truncationProps` and `renderTruncatedOption` logic
cee-chen Aug 22, 2023
c69441a
Add docs section for combobox truncation
cee-chen Aug 22, 2023
10dc0e2
Attempt to fix Cypress CI failures caused by fonts
cee-chen Aug 23, 2023
f219119
[REFACTOR] Move truncation string logic to a separate vanilla JS class
cee-chen Aug 23, 2023
64aaebd
Clean up `truncationOffset` edge case behavior
cee-chen Aug 23, 2023
7d5ce5a
Fix storybook controls
cee-chen Aug 23, 2023
5fd309e
it's hard to word good
cee-chen Aug 23, 2023
a5837bb
[PR feedback] Expand utilities for to specify DOM vs. canvas render m…
cee-chen Aug 23, 2023
767a44e
[misc cleanup] fix `truncateStart` typing
cee-chen Aug 23, 2023
4cd6ad5
Naming things is hard
cee-chen Aug 23, 2023
85ccc1c
Fix CI font issues again :|
cee-chen Aug 24, 2023
a1c487d
[PR feedback] Improve perf of DOM measurement
cee-chen Aug 24, 2023
b6b67b0
Update `EuiTextTruncate` to support using `TruncationUtilsForCanvas`
cee-chen Aug 24, 2023
f4a9af4
Add documentation section and warnings around performance
cee-chen Aug 24, 2023
4a96de8
[misc cleanup] improve tests
cee-chen Aug 24, 2023
879b38e
Add CSS comments/dev documentation
cee-chen Aug 25, 2023
30196af
Minor test cleanup
cee-chen Aug 25, 2023
6718b37
Merge branch 'main' into fix/5997
cee-chen Sep 1, 2023
5098c4c
changelog
cee-chen Sep 1, 2023
3cb8c0d
Make docs example less confusing
cee-chen Sep 1, 2023
e28a66e
Merge branch 'main' into fix/5997
cee-chen Sep 18, 2023
998ecb1
Add tests
cee-chen Sep 18, 2023
d188bb5
[Cypress] Fix font calculation
cee-chen Sep 18, 2023
b971297
Add `shouldRenderCustomStyles` Jest tests
cee-chen Sep 18, 2023
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
"html-webpack-plugin": "^5.5.0",
"inquirer": "^9.1.4",
"jest": "^24.1.0",
"jest-canvas-mock": "^2.5.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature adopts the Canvas api to measure text, so I had to add the jest-canvas-mock library for unit tests.
(I think this could be also implemented without the canvas, but it was easier that way).

I would personally lean towards avoiding the canvas API for this unless there's a strong reason to do so. My reasoning against is that it avoids an extra dependency and also because it's not something the EUI team is familiar with, and thus would be more difficult for us to maintain than just vanilla JS.

If canvas is absolutely the way to go, I'd then strongly prefer to use Cypress to test the functionality over adding a Jest dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change the code to not use Canvas API. I think same can be achieved using a div element as well.

"jest-cli": "^24.1.0",
"moment": "^2.27.0",
"moment-timezone": "^0.5.31",
Expand Down
18 changes: 16 additions & 2 deletions src-docs/src/views/combo_box/combo_box.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';

import { EuiComboBox } from '../../../../src/components';
import { EuiComboBox, EuiSwitch } from '../../../../src/components';
import { DisplayToggles } from '../form_controls/display_toggles';

const optionsStatic = [
Expand Down Expand Up @@ -40,6 +40,7 @@ const optionsStatic = [
];
export default () => {
const [options, setOptions] = useState(optionsStatic);
const [canTruncate, setCanTruncate] = useState(false);
const [selectedOptions, setSelected] = useState([options[2], options[4]]);

const onChange = (selectedOptions) => {
Expand Down Expand Up @@ -72,7 +73,19 @@ export default () => {

return (
/* DisplayToggles wrapper for Docs only */
<DisplayToggles canDisabled={false} canReadOnly={false} canIsDisabled>
<DisplayToggles
canDisabled={false}
canReadOnly={false}
canIsDisabled
extras={[
<EuiSwitch
compressed
label={'middle truncation'}
checked={canTruncate}
onChange={(e) => setCanTruncate(e.target.checked)}
/>,
]}
>
<EuiComboBox
aria-label="Accessible screen reader label"
placeholder="Select or create options"
Expand All @@ -83,6 +96,7 @@ export default () => {
isClearable={true}
data-test-subj="demoComboBox"
autoFocus
truncation={canTruncate ? 'middle' : undefined}
/>
</DisplayToggles>
);
Expand Down
34 changes: 25 additions & 9 deletions src/components/combo_box/__snapshots__/combo_box.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ exports[`EuiComboBox is rendered 1`] = `
<div
class="euiComboBox testClass1 testClass2 emotion-euiTestCss"
data-test-subj="test subject string"
truncation="end"
>
<div
class="euiFormControlLayout"
Expand Down Expand Up @@ -64,6 +65,7 @@ exports[`props aria-label attribute is rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
aria-label="Test label"
Expand Down Expand Up @@ -99,6 +101,7 @@ exports[`props aria-labelledby attribute is rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
aria-labelledby="test-heading-id"
Expand Down Expand Up @@ -134,6 +137,7 @@ exports[`props autoFocus is rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -177,6 +181,7 @@ exports[`props custom ID is rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -220,6 +225,7 @@ exports[`props delimiter is rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -263,6 +269,7 @@ exports[`props full width is rendered 1`] = `
className="euiComboBox euiComboBox--fullWidth"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -303,6 +310,7 @@ exports[`props isClearable=false disallows user from clearing input when no opti
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -336,6 +344,7 @@ exports[`props isClearable=false disallows user from clearing input when options
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -378,6 +387,7 @@ exports[`props isDisabled is rendered 1`] = `
className="euiComboBox euiComboBox-isDisabled"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -611,6 +621,7 @@ exports[`props options list is rendered 1`] = `
<div
class="euiComboBox euiComboBox-isOpen"
data-test-subj="alsoGetsAppliedToOptionsList"
truncation="end"
>
<div
class="euiFormControlLayout"
Expand Down Expand Up @@ -668,6 +679,7 @@ exports[`props options list is rendered 1`] = `
data-popover-panel="true"
data-test-subj="comboBoxOptionsList alsoGetsAppliedToOptionsList-optionsList"
style="z-index: 100;"
truncation="end"
>
<div
class="euiComboBoxOptionsList__rowWrap"
Expand Down Expand Up @@ -702,7 +714,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Titan
</span>
Expand All @@ -729,7 +741,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Enceladus
</span>
Expand All @@ -756,7 +768,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Mimas
</span>
Expand All @@ -783,7 +795,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Dione
</span>
Expand All @@ -810,7 +822,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Iapetus
</span>
Expand All @@ -837,7 +849,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Phoebe
</span>
Expand All @@ -864,7 +876,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Rhea
</span>
Expand All @@ -891,7 +903,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Pandora is one of Saturn's moons, named for a Titaness of Greek mythology
</span>
Expand All @@ -918,7 +930,7 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOption__contentWrapper"
>
<span
class="euiComboBoxOption__content"
class="euiComboBoxOption__content euiComboBoxOption-truncationEnd"
>
Tethys
</span>
Expand All @@ -938,6 +950,7 @@ exports[`props selectedOptions are rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -981,6 +994,7 @@ exports[`props singleSelection is rendered 1`] = `
className="euiComboBox"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down Expand Up @@ -1021,6 +1035,7 @@ exports[`props singleSelection prepend and append is rendered 1`] = `
className="euiComboBox euiComboBox--prepended euiComboBox--appended euiComboBox-isOpen"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
append="String"
Expand Down Expand Up @@ -1065,6 +1080,7 @@ exports[`props singleSelection selects existing option when opened 1`] = `
className="euiComboBox euiComboBox-isOpen"
onBlur={[Function]}
onKeyDown={[Function]}
truncation="end"
>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
Expand Down
27 changes: 27 additions & 0 deletions src/components/combo_box/combo_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
EuiComboBoxOptionOption,
EuiComboBoxOptionsListPosition,
EuiComboBoxSingleSelectionShape,
EuiComboBoxTruncation,
} from './types';
import { EuiFilterSelectItemClass } from '../filter_group/filter_select_item';
import AutosizeInput from 'react-input-autosize';
Expand Down Expand Up @@ -156,6 +157,10 @@ export interface _EuiComboBoxProps<T>
* supplied by `aria-label` or from [EuiFormRow](/#/forms/form-layouts).
*/
'aria-labelledby'?: string;
/**
* Controls the truncation of the label text.
*/
truncation: EuiComboBoxTruncation;
}

/**
Expand Down Expand Up @@ -189,6 +194,7 @@ interface EuiComboBoxState<T> {
matchingOptions: Array<EuiComboBoxOptionOption<T>>;
searchValue: string;
width: number;
font: string;
}

const initialSearchValue = '';
Expand All @@ -208,6 +214,7 @@ export class EuiComboBox<T> extends Component<
prepend: undefined,
append: undefined,
sortMatchesBy: 'none' as const,
truncation: 'end',
};

state: EuiComboBoxState<T> = {
Expand All @@ -228,6 +235,7 @@ export class EuiComboBox<T> extends Component<
}),
searchValue: initialSearchValue,
width: 0,
font: '',
};

_isMounted = false;
Expand All @@ -242,6 +250,7 @@ export class EuiComboBox<T> extends Component<
const comboBoxBounds = this.comboBoxRefInstance.getBoundingClientRect();
this.setState({
width: comboBoxBounds.width,
font: this.getFont(),
});
}
};
Expand Down Expand Up @@ -820,6 +829,22 @@ export class EuiComboBox<T> extends Component<
return stateUpdate;
}

getFont = () => {
if (this.comboBoxRefInstance) {
const css = window.getComputedStyle(this.comboBoxRefInstance);
return [
'font-style',
'font-variant',
'font-weight',
'font-size',
'font-family',
]
.map((prop) => css.getPropertyValue(prop))
.join(' ');
}
return '';
};

updateMatchingOptionsIfDifferent = (
newMatchingOptions: Array<EuiComboBoxOptionOption<T>>
) => {
Expand Down Expand Up @@ -1007,6 +1032,8 @@ export class EuiComboBox<T> extends Component<
getSelectedOptionForSearchValue
}
listboxAriaLabel={listboxAriaLabel}
font={this.state.font}
truncation={this.props.truncation}
/>
)}
</EuiI18n>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
margin-left: $euiSizeXS;
}

.euiComboBoxOption__content {
overflow: hidden;
white-space: nowrap;
flex: 1;
text-align: left;

&__prepend {
margin-right: $euiSizeS;
}
Expand All @@ -69,4 +75,8 @@
display: block;
}
}
}

&.euiComboBoxOption-truncationEnd {
text-overflow: ellipsis;
}
}
Loading
Loading