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

fix: Updating handling of ComboboxInput to better handle multiline variants #1032

Merged
merged 2 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 5 additions & 2 deletions src/Css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3966,12 +3966,15 @@ class CssBuilder<T extends Properties> {
}

// visuallyHidden
/** Sets `position: "absolute"; overflow: "hidden"; clip: "inset(50%)"; clipPath: ""; border: 0; height: "1px"; margin: "-1px"; width: "1px"; padding: 0; whiteSpace: "nowrap"`. */
/** Sets `position: "absolute"; overflow: "hidden"; clip: "inset(50%)"; clipPath: ""; border: 0; height: "1px"; margin: "-1px"; width: "1px"; padding: 0; whiteSpace: "nowrap"; opacity: 0`. */
Copy link
Contributor

Choose a reason for hiding this comment

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

curious: This comment doesn't seem add additional value over reading the code 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These JSDoc comments are automatically generated by Truss. They make it easier to hover over a Truss property in your IDE and see what it's setting.

get visuallyHidden() {
return this.add("position", "absolute").add("overflow", "hidden").add("clip", "inset(50%)").add("clipPath", "").add(
"border",
0,
).add("height", "1px").add("margin", "-1px").add("width", "1px").add("padding", 0).add("whiteSpace", "nowrap");
).add("height", "1px").add("margin", "-1px").add("width", "1px").add("padding", 0).add("whiteSpace", "nowrap").add(
"opacity",
0,
);
}

// contentEmpty
Expand Down
5 changes: 3 additions & 2 deletions src/components/Chips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ export interface ChipsProps<X> {
values: string[] | ChipValue[];
xss?: X;
compact?: boolean;
wrap?: boolean;
}

/** Renders a list of `Chip`s, with wrapping & appropriate margin between each `Chip`. */
export function Chips<X extends Only<ChipsXss, X>>(props: ChipsProps<X>) {
const { wrap } = usePresentationContext();
const { values, compact, xss = {} } = props;
const { wrap: presentationWrap } = usePresentationContext();
const { values, compact, xss = {}, wrap = presentationWrap } = props;
return (
<div
css={{
Expand Down
22 changes: 17 additions & 5 deletions src/inputs/TextFieldBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,7 @@ export function TextFieldBase<X extends Only<TextFieldXss, X>>(props: TextFieldB
container: Css.df.fdc.w100.maxw(fieldMaxWidth).relative.if(labelStyle === "left").maxw100.fdr.gap2.jcsb.aic.$,
inputWrapper: {
...Css[typeScale].df.aic.br4.px1.w100
.hPx(fieldHeight - maybeSmaller)
.if(compact)
.hPx(compactFieldHeight - maybeSmaller).$,
...Css.bgColor(bgColor)
.bgColor(bgColor)
.gray900.if(contrast)
.white.if(labelStyle === "left").w50.$,
// When borderless then perceived vertical alignments are misaligned. As there is no longer a border, then the field looks oddly indented.
Expand All @@ -141,6 +138,15 @@ export function TextFieldBase<X extends Only<TextFieldXss, X>>(props: TextFieldB
: Css.bGray300.if(contrast).bGray700.$),
// Do not add borders to compound fields. A compound field is responsible for drawing its own borders
...(!compound ? Css.ba.$ : {}),
// When multiline is true, then we want to allow the field to grow to the height of the content, but not shrink below the minHeight
// Otherwise, set fixed heights values accordingly.
...(multiline
? Css.mhPx(fieldHeight - maybeSmaller)
.if(compact)
.mhPx(compactFieldHeight - maybeSmaller).$
: Css.hPx(fieldHeight - maybeSmaller)
.if(compact)
.hPx(compactFieldHeight - maybeSmaller).$),
},
inputWrapperReadOnly: {
...Css[typeScale].df.aic.w100.gray900.if(contrast).white.if(labelStyle === "left").w50.$,
Expand Down Expand Up @@ -255,9 +261,15 @@ export function TextFieldBase<X extends Only<TextFieldXss, X>>(props: TextFieldB
{startAdornment && <span css={Css.df.aic.asc.fs0.br4.pr1.$}>{startAdornment}</span>}
{unfocusedPlaceholder && (
<div
// Setting -1 tabIndex as this is a scrollable container, which is focusable by default.
// However, we want the user's focus to move to the field element, which will hide this container.
tabIndex={-1}
{...tid.unfocusedPlaceholderContainer}
css={{
...Css.df.asc.w100.maxh100.overflowAuto.$,
...Css.df.asc.w100.maxhPx(74).overflowAuto.$,
...fieldStyles.input,
...(showHover ? fieldStyles.hover : {}),
...(inputProps.disabled ? fieldStyles.disabled : {}),
...(isFocused && Css.visuallyHidden.$),
}}
>
Expand Down
10 changes: 8 additions & 2 deletions src/inputs/hooks/useGrowingTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ export function useGrowingTextField({ inputRef, inputWrapRef, value, disabled }:
}, [inputRef, disabled, inputWrapRef]);

useLayoutEffect(() => {
if (disabled) return;
if (disabled) {
// reset the height property if it was flipped to disabled
if (inputWrapRef.current) {
inputWrapRef.current.style.removeProperty("height");
}
return;
}

if (inputRef.current) {
// Temp hack until we can figure out a better way to ensure proper measurements when rendered through a portal (i.e. Modals)
Expand All @@ -37,5 +43,5 @@ export function useGrowingTextField({ inputRef, inputWrapRef, value, disabled }:
}
onHeightChange();
}
}, [onHeightChange, value, inputRef, disabled]);
}, [onHeightChange, value, inputRef, disabled, inputWrapRef]);
}
14 changes: 13 additions & 1 deletion src/inputs/internal/ComboBoxInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useTreeSelectFieldProvider } from "src/inputs/TreeSelectField/TreeSelec
import { isLeveledNode } from "src/inputs/TreeSelectField/utils";
import { Value } from "src/inputs/Value";
import { maybeCall } from "src/utils";
import { useGrowingTextField } from "src/inputs/hooks/useGrowingTextField";

interface ComboBoxInputProps<O, V extends Value> extends PresentationFieldProps {
buttonProps: any;
Expand Down Expand Up @@ -94,11 +95,22 @@ export function ComboBoxInput<O, V extends Value>(props: ComboBoxInputProps<O, V

const chipLabels = isTree ? selectedOptionsLabels || [] : selectedOptions.map((o) => getOptionLabel(o));

useGrowingTextField({
// This says: When using a multiselect, then only enable the growing textfield when we are focused on it.
// Because otherwise, we're not displaying the input element that dictates the height (we're displaying <Chips/>). This would cause incorrect calculations
disabled: (isMultiSelect && (!allowWrap || !isFocused)) || (!isMultiSelect && !allowWrap),
inputRef,
inputWrapRef,
value: inputProps.value,
});

return (
<TextFieldBase
{...otherProps}
{...multilineProps}
unfocusedPlaceholder={showChipSelection && <Chips compact={otherProps.compact} values={chipLabels} />}
unfocusedPlaceholder={
showChipSelection && <Chips compact={otherProps.compact} values={chipLabels} wrap={allowWrap} />
}
inputRef={inputRef}
inputWrapRef={inputWrapRef}
errorMsg={errorMsg}
Expand Down
1 change: 1 addition & 0 deletions truss-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const sections: Sections = {
width: "1px",
padding: 0,
whiteSpace: "nowrap",
opacity: 0,
}),
],
contentEmpty: () => [newMethod("contentEmpty", { content: "''" })],
Expand Down
Loading