Skip to content

Commit

Permalink
Update Select and Dropdown components (#1160)
Browse files Browse the repository at this point in the history
* Update select component to match designs

* update menuitem to match designs

* fix FormFieldWrapper margin

* use new menuitem component

* fix icon positioning

* simplify simpleselect

* do not export Select from ol-components

* add a test, reorganize stories

* tweak mdx

* use simpleselect in resource drawer

* 4px menu border

* 4px autocomplete border
  • Loading branch information
ChristopherChudzicki authored Jun 25, 2024
1 parent 525230b commit 4bff2f5
Show file tree
Hide file tree
Showing 21 changed files with 554 additions and 305 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
BasicDialog,
styled,
RadioChoiceField,
MenuItem,
} from "ol-components"
import * as Yup from "yup"
import { PrivacyLevelEnum, type LearningPathResource, UserList } from "api"
Expand Down Expand Up @@ -222,6 +223,9 @@ const UpsertLearningPathDialog = NiceModal.create(
}
/>
)}
renderOption={(props, opt) => {
return <MenuItem {...props}>{opt.name}</MenuItem>
}}
/>
<BooleanRadioChoiceField
className="form-row"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import React from "react"

import {
Select,
MenuItem,
FormControl,
FormLabel,
SelectChangeEvent,
} from "ol-components"
import { FormControl, FormLabel, SimpleSelect } from "ol-components"
import type { SimpleSelectFieldProps, SimpleSelectOption } from "ol-components"
import { CurrentEducationEnum, CurrentEducationEnumDescriptions } from "api/v0"

import { ProfileFieldUpdateProps } from "./types"

const OPTIONS: SimpleSelectOption[] = [
{
label: <em>Please select</em>,
disabled: true,
value: "",
},
...Object.values(CurrentEducationEnum).map((value) => ({
value,
label: CurrentEducationEnumDescriptions[value],
})),
]

const EducationLevelSelect: React.FC<
ProfileFieldUpdateProps<"current_education">
> = ({ label, value, onUpdate }) => {
const [educationLevel, setEducationLevel] = React.useState<
CurrentEducationEnum | ""
>(value || "")

const handleChange = (event: SelectChangeEvent<typeof educationLevel>) => {
const handleChange: SimpleSelectFieldProps["onChange"] = (event) => {
setEducationLevel(event.target.value as CurrentEducationEnum)
}

Expand All @@ -29,18 +36,11 @@ const EducationLevelSelect: React.FC<
return (
<FormControl component="fieldset" fullWidth>
<FormLabel component="label">{label}</FormLabel>
<Select displayEmpty onChange={handleChange} value={educationLevel}>
<MenuItem disabled value="">
<em>Please select</em>
</MenuItem>
{Object.values(CurrentEducationEnum).map((value, index) => {
return (
<MenuItem value={value} key={index}>
{CurrentEducationEnumDescriptions[value]}
</MenuItem>
)
})}
</Select>
<SimpleSelect
value={educationLevel}
onChange={handleChange}
options={OPTIONS}
/>
</FormControl>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from "react"
import {
RadioChoiceBoxField,
Select,
SelectChangeEvent,
MenuItem,
FormControl,
FormLabel,
SimpleSelect,
RadioChoiceBoxField,
} from "ol-components"
import type { SimpleSelectFieldProps, SimpleSelectOption } from "ol-components"
import { LearningFormatEnum, LearningFormatEnumDescriptions } from "api/v0"

import { ProfileFieldUpdateProps, ProfileFieldStateHook } from "./types"
Expand All @@ -20,6 +19,15 @@ const CHOICES = [
label: LearningFormatEnumDescriptions[value],
}))

const SELECT_OPTIONS: SimpleSelectOption[] = [
{
label: <em>Please select</em>,
disabled: true,
value: "",
},
...CHOICES,
]

type Props = ProfileFieldUpdateProps<"learning_format">
type State = LearningFormatEnum | ""

Expand Down Expand Up @@ -66,11 +74,8 @@ const LearningFormatChoiceBoxField: React.FC<Props> = ({
const LearningFormatSelect: React.FC<Props> = ({ label, value, onUpdate }) => {
const [learningFormat, setLearningFormat] = React.useState<State>(value || "")

const handleChange = (event: SelectChangeEvent<typeof learningFormat>) => {
setLearningFormat(() => {
const target = event.target as HTMLInputElement
return target.value as LearningFormatEnum
})
const handleChange: SimpleSelectFieldProps["onChange"] = (event) => {
setLearningFormat(event.target.value as LearningFormatEnum)
}
React.useEffect(() => {
onUpdate("learning_format", learningFormat)
Expand All @@ -79,16 +84,11 @@ const LearningFormatSelect: React.FC<Props> = ({ label, value, onUpdate }) => {
return (
<FormControl component="fieldset" fullWidth>
<FormLabel component="label">{label}</FormLabel>
<Select displayEmpty onChange={handleChange} value={learningFormat}>
<MenuItem disabled value="">
<em>Please select</em>
</MenuItem>
{CHOICES.map((choice) => (
<MenuItem value={choice.value} key={choice.value}>
{choice.label}
</MenuItem>
))}
</Select>
<SimpleSelect
options={SELECT_OPTIONS}
onChange={handleChange}
value={learningFormat}
/>
</FormControl>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import React from "react"
import {
FormControl,
FormLabel,
Select,
SelectChangeEvent,
MenuItem,
SimpleSelect,
RadioChoiceBoxField,
} from "ol-components"
import type { SimpleSelectFieldProps, SimpleSelectOption } from "ol-components"
import { TimeCommitmentEnum, TimeCommitmentEnumDescriptions } from "api/v0"

import { ProfileFieldUpdateProps } from "./types"
Expand All @@ -22,6 +21,15 @@ const CHOICES = [
label: TimeCommitmentEnumDescriptions[value],
}))

const SELECT_OPTIONS: SimpleSelectOption[] = [
{
label: <em>Please select</em>,
disabled: true,
value: "",
},
...CHOICES,
]

type Props = ProfileFieldUpdateProps<"time_commitment">
type State = TimeCommitmentEnum | ""

Expand Down Expand Up @@ -57,11 +65,8 @@ const TimeCommitmentRadioChoiceBoxField: React.FC<Props> = ({
const TimeCommitmentSelect: React.FC<Props> = ({ label, value, onUpdate }) => {
const [timeCommitment, setTimeCommitment] = React.useState<State>(value || "")

const handleChange = (event: SelectChangeEvent<typeof timeCommitment>) => {
setTimeCommitment(() => {
const target = event.target as HTMLInputElement
return target.value as TimeCommitmentEnum
})
const handleChange: SimpleSelectFieldProps["onChange"] = (event) => {
setTimeCommitment(event.target.value as TimeCommitmentEnum)
}
React.useEffect(() => {
onUpdate("time_commitment", timeCommitment)
Expand All @@ -70,16 +75,11 @@ const TimeCommitmentSelect: React.FC<Props> = ({ label, value, onUpdate }) => {
return (
<FormControl component="fieldset" fullWidth>
<FormLabel component="label">{label}</FormLabel>
<Select displayEmpty onChange={handleChange} value={timeCommitment}>
<MenuItem disabled value="">
<em>Please select</em>
</MenuItem>
{CHOICES.map((choice) => (
<MenuItem value={choice.value} key={choice.value}>
{choice.label}
</MenuItem>
))}
</Select>
<SimpleSelect
options={SELECT_OPTIONS}
onChange={handleChange}
value={timeCommitment}
/>
</FormControl>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,8 @@ import type { TabConfig } from "./ResourceTypeTabs"
import { ResourceListCard } from "../ResourceCard/ResourceCard"
import { useSearchParams } from "@mitodl/course-search-utils/react-router"

export const StyledDropdown = styled(SimpleSelect)`
margin-left: 8px;
margin-right: 0;
margin-top: 0;
export const StyledSelect = styled(SimpleSelect)`
min-width: 160px;
height: 32px;
background: ${({ theme }) => theme.custom.colors.white};
svg {
width: 0.75em;
height: 0.75em;
}
div {
min-height: 0 px;
padding-right: 1px !important;
font-size: 12px !important;
}
`

export const StyledResourceTabs = styled(ResourceTypeTabs.TabList)`
Expand All @@ -73,11 +57,6 @@ export const StyledResourceTabs = styled(ResourceTypeTabs.TabList)`
export const DesktopSortContainer = styled.div`
float: right;
div {
height: 32px;
bottom: 1px;
}
${({ theme }) => theme.breakpoints.down("md")} {
display: none;
}
Expand All @@ -87,11 +66,6 @@ export const MobileSortContainer = styled.div`
${({ theme }) => theme.breakpoints.up("md")} {
display: none;
}
div {
height: 32px;
bottom: -2px;
}
`

export const FacetStyles = styled.div`
Expand Down Expand Up @@ -484,19 +458,19 @@ export const ALL_RESOURCE_TABS = TABS.map((t) => t.resource_type)
export const SORT_OPTIONS = [
{
label: "Best Match",
key: "",
value: "",
},
{
label: "New",
key: "new",
value: "new",
},
{
label: "Popular",
key: "-views",
value: "-views",
},
{
label: "Upcoming",
key: "upcoming",
value: "upcoming",
},
]

Expand Down Expand Up @@ -597,15 +571,14 @@ const SearchDisplay: React.FC<SearchDisplayProps> = ({
)

const sortDropdown = (
<StyledDropdown
initialValue={requestParams.sortby || ""}
isMultiple={false}
<StyledSelect
size="small"
value={requestParams.sortby || ""}
onChange={(e) => setParamValue("sortby", e.target.value)}
options={SORT_OPTIONS}
className="sort-dropdown"
sx={{ fontSize: "small" }}
renderValue={(value) => {
const opt = SORT_OPTIONS.find((option) => option.key === value)
const opt = SORT_OPTIONS.find((option) => option.value === value)
return `Sort by: ${opt?.label}`
}}
/>
Expand Down
21 changes: 10 additions & 11 deletions frontends/mit-open/src/pages/FieldPage/FieldSearchFacetDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import type {
} from "@mitodl/course-search-utils"
import { BOOLEAN_FACET_NAMES } from "@mitodl/course-search-utils"
import { Skeleton, styled } from "ol-components"
import { StyledDropdown } from "@/page-components/SearchDisplay/SearchDisplay"

export type KeyWithLabel = { key: string; label: string }
import type { SimpleSelectOption } from "ol-components"
import { StyledSelect } from "@/page-components/SearchDisplay/SearchDisplay"

const StyledSkeleton = styled(Skeleton)`
display: inline-flex;
Expand Down Expand Up @@ -51,19 +50,19 @@ const filteredResultsWithLabels = (
results: Aggregation,
labelFunction: ((value: string) => string) | null | undefined,
constantsForFacet: string[] | null,
): KeyWithLabel[] => {
const newResults = [] as KeyWithLabel[]
): SimpleSelectOption[] => {
const newResults = [] as SimpleSelectOption[]
if (constantsForFacet) {
constantsForFacet.map((key: string) => {
newResults.push({
key: key,
value: key,
label: labelFunction ? labelFunction(key) : key,
})
})
} else {
results.map((singleFacet: Bucket) => {
newResults.push({
key: singleFacet.key,
value: singleFacet.key,
label: labelFunction ? labelFunction(singleFacet.key) : singleFacet.key,
})
})
Expand Down Expand Up @@ -113,15 +112,15 @@ const AvailableFacetsDropdowns: React.FC<
}

if (!isMultiple) {
facetItems.unshift({ key: "", label: "no selection" })
facetItems.unshift({ value: "", label: "no selection" })
}

return (
facetItems.length && (
<StyledDropdown
<StyledSelect
key={facetSetting.name}
initialValue={displayValue}
isMultiple={isMultiple}
value={displayValue}
multiple={isMultiple}
onChange={(e) => onFacetChange(facetSetting.name, e.target.value)}
renderValue={() => {
return facetSetting.title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ const ControlLabel: React.FC<ControlLabelProps> = ({
id,
}) => {
return (
<Typography id={id} component="label" htmlFor={htmlFor} variant="subtitle2">
<Typography
id={id}
component="label"
htmlFor={htmlFor}
variant="subtitle2"
sx={{ marginBottom: "4px" }}
>
{label}
{required ? <Required aria-hidden="true">*</Required> : null}
</Typography>
Expand Down
Loading

0 comments on commit 4bff2f5

Please sign in to comment.