diff --git a/src/components/PresentationContext.tsx b/src/components/PresentationContext.tsx index 2aa8cb00d..ae1ac675e 100644 --- a/src/components/PresentationContext.tsx +++ b/src/components/PresentationContext.tsx @@ -30,6 +30,7 @@ export interface PresentationFieldProps { } export type PresentationContextProps = { + /** `inputStylePalette` omitted because it is too dependent on the individual field use case to be controlled at this level */ fieldProps?: Omit; gridTableStyle?: GridStyle; // Defines whether content should be allowed to wrap or not. `undefined` is treated as true. diff --git a/src/inputs/SelectField.stories.tsx b/src/inputs/SelectField.stories.tsx index e59092fef..8b45d66bf 100644 --- a/src/inputs/SelectField.stories.tsx +++ b/src/inputs/SelectField.stories.tsx @@ -3,6 +3,7 @@ import { Meta } from "@storybook/react"; import { within } from "@storybook/test"; import { useState } from "react"; import { GridColumn, GridTable, Icon, IconKey, simpleHeader, SimpleHeaderAndData } from "src/components"; +import { InputStylePalette } from "src/components/PresentationContext"; import { Css } from "src/Css"; import { SelectField, SelectFieldProps } from "src/inputs/SelectField"; import { Value } from "src/inputs/Value"; @@ -233,7 +234,7 @@ export const Contrast = Template.bind({}); Contrast.args = { compact: true, contrast: true }; // @ts-ignore -function getInputStylePalette(v) { +function getInputStylePalette(v): InputStylePalette | undefined { if (v?.includes(1) || v?.includes("1")) return "success"; if (v?.includes(2) || v?.includes("2")) return "caution"; if (v?.includes(3) || v?.includes("3")) return "warning"; @@ -241,28 +242,22 @@ function getInputStylePalette(v) { return undefined; } -const standardColoredSelectArgs = { - options: coloredOptions, - // @ts-ignore - getInputStylePalette, -}; - export const Colored = Template.bind({}); // @ts-ignore -Colored.args = standardColoredSelectArgs; +Colored.args = { options: coloredOptions }; export const ColoredContrast = Template.bind({}); // @ts-ignore ColoredContrast.args = { contrast: true, - ...standardColoredSelectArgs, + options: coloredOptions, }; export const ColoredCompact = Template.bind({}); // @ts-ignore ColoredCompact.args = { compact: true, - ...standardColoredSelectArgs, + options: coloredOptions, }; const loadTestOptions: TestOption[] = zeroTo(1000).map((i) => ({ id: String(i), name: `Project ${i}` })); @@ -413,6 +408,10 @@ function TestSelectField( props: Optional, "onSelect">, "getOptionValue" | "getOptionLabel">, ): JSX.Element { const [selectedOption, setSelectedOption] = useState(props.value); + const [inputStylePalette, setInputStylePalette] = useState(); + + // @ts-ignore: Hacking around type props within the testSelectField instead of the SB Template + const shouldUseStylePalette: boolean = !!props.options?.some((o) => o.name.includes("style palette when selected")); return (
@@ -420,8 +419,12 @@ function TestSelectField( // The `as any` is due to something related to https://github.com/emotion-js/emotion/issues/2169 // We may have to redo the conditional getOptionValue/getOptionLabel {...(props as any)} + inputStylePalette={shouldUseStylePalette ? inputStylePalette : undefined} value={selectedOption} - onSelect={setSelectedOption} + onSelect={(v, opt) => { + setSelectedOption(v); + setInputStylePalette(getInputStylePalette(v)); + }} errorMsg={ selectedOption !== undefined || props.disabled ? "" diff --git a/src/inputs/internal/ComboBoxBase.tsx b/src/inputs/internal/ComboBoxBase.tsx index d3bf250b9..efbb111c9 100644 --- a/src/inputs/internal/ComboBoxBase.tsx +++ b/src/inputs/internal/ComboBoxBase.tsx @@ -5,7 +5,7 @@ import { useButton, useComboBox, useFilter, useOverlayPosition } from "react-ari import { Item, useComboBoxState, useMultipleSelectionState } from "react-stately"; import { resolveTooltip } from "src/components"; import { Popover } from "src/components/internal"; -import { InputStylePalette, PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; +import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; import { Css } from "src/Css"; import { ComboBoxInput } from "src/inputs/internal/ComboBoxInput"; import { ListBox } from "src/inputs/internal/ListBox"; @@ -20,8 +20,6 @@ export interface ComboBoxBaseProps extends BeamFocusableProp getOptionMenuLabel?: (opt: O, isUnsetOpt?: boolean, isAddNewOption?: boolean) => string | ReactNode; getOptionValue: (opt: O) => V; getOptionLabel: (opt: O) => string; - /** Sets an input style based on the option(s) selected if `inputStylePalette` is not set */ - getInputStylePalette?: (values: V[] | undefined) => InputStylePalette | undefined; /** The current value; it can be `undefined`, even if `V` cannot be. */ values: V[] | undefined; onSelect: (values: V[], opts: O[]) => void; @@ -95,7 +93,6 @@ export function ComboBoxBase(props: ComboBoxBaseProps) borderless, unsetLabel, inputStylePalette: propsInputStylePalette, - getInputStylePalette, getOptionLabel: propOptionLabel, getOptionValue: propOptionValue, getOptionMenuLabel: propOptionMenuLabel, @@ -151,14 +148,7 @@ export function ComboBoxBase(props: ComboBoxBaseProps) ); const values = useMemo(() => propValues ?? [], [propValues]); - const inputStylePalette = useMemo(() => { - if (propsInputStylePalette) { - return propsInputStylePalette; - } else if (getInputStylePalette) { - return getInputStylePalette(values); - } - return undefined; - }, [propsInputStylePalette, getInputStylePalette, values]); + const inputStylePalette = useMemo(() => propsInputStylePalette, [propsInputStylePalette]); const selectedOptionsRef = useRef(options.filter((o) => values.includes(getOptionValue(o)))); const selectedOptions = useMemo(() => {