Skip to content

Commit

Permalink
feat: add generic select abstractions to reduce boilerplate
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas-C committed Oct 11, 2024
1 parent 7fc1ae1 commit 635b7fa
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 125 deletions.
32 changes: 7 additions & 25 deletions src/components/SlateEditor/plugins/audio/AudioEmbedForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,21 @@ import { Formik, useFormikContext } from "formik";
import { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { createListCollection } from "@ark-ui/react";
import { ArrowDownShortLine } from "@ndla/icons/common";
import { CheckLine } from "@ndla/icons/editor";
import { ModalBody, ModalHeader, ModalTitle } from "@ndla/modal";
import {
Button,
FieldErrorMessage,
FieldRoot,
SelectContent,
SelectControl,
SelectIndicator,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectLabel,
SelectPositioner,
SelectRoot,
SelectTrigger,
SelectValueText,
} from "@ndla/primitives";
import { IAudioMetaInformation } from "@ndla/types-backend/audio-api";
import { AudioEmbedData } from "@ndla/types-embed";
import { AudioPlayer } from "@ndla/ui";
import { GenericSelectItem, GenericSelectTrigger } from "../../../abstractions/Select";
import { FormField } from "../../../FormField";
import { FormActionsContainer, FormikForm } from "../../../FormikForm";
import validateFormik, { RulesType } from "../../../formikValidationSchema";
Expand Down Expand Up @@ -129,26 +122,15 @@ const EmbedForm = ({ onCancel, audio }: EmbedFormProps) => {
collection={collection}
>
<SelectLabel>{t("form.audio.chooseAudioType")}</SelectLabel>
<SelectControl>
<SelectTrigger asChild>
<Button variant="secondary">
<SelectValueText />

<SelectIndicator asChild>
<ArrowDownShortLine />
</SelectIndicator>
</Button>
</SelectTrigger>
</SelectControl>
<GenericSelectTrigger>
<SelectValueText />
</GenericSelectTrigger>
<SelectPositioner>
<SelectContent>
{collection.items.map((item) => (
<SelectItem item={item} key={item.value}>
<SelectItemText>{item.label}</SelectItemText>
<SelectItemIndicator asChild>
<CheckLine />
</SelectItemIndicator>
</SelectItem>
<GenericSelectItem item={item} key={item.value}>
{item.label}
</GenericSelectItem>
))}
</SelectContent>
</SelectPositioner>
Expand Down
31 changes: 7 additions & 24 deletions src/components/SlateEditor/plugins/codeBlock/CodeBlockEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,21 @@ import { ComponentProps, useCallback, useEffect, useMemo } from "react";
import { useTranslation } from "react-i18next";
import Editor from "react-simple-code-editor";
import { FieldContext, SelectHiddenSelect, createListCollection } from "@ark-ui/react";
import { ArrowDownShortLine } from "@ndla/icons/common";
import { CheckLine } from "@ndla/icons/editor";
import {
Button,
FieldErrorMessage,
FieldInput,
FieldLabel,
FieldRoot,
SelectContent,
SelectControl,
SelectIndicator,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectLabel,
SelectPositioner,
SelectRoot,
SelectTrigger,
SelectValueText,
} from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { languageOptions } from "./codeBlockOptions";
import { GenericSelectItem, GenericSelectTrigger } from "../../../abstractions/Select";
import { FormField } from "../../../FormField";
import { FormActionsContainer, FormikForm } from "../../../FormikForm";
import validateFormik, { RulesType } from "../../../formikValidationSchema";
Expand Down Expand Up @@ -168,25 +161,15 @@ const CodeBlockEditor = ({ onSave, onAbort, highlight, content, setShowWarning }
>
<SelectLabel>{t("codeEditor.languageSelect")}</SelectLabel>
<FieldErrorMessage>{meta.error}</FieldErrorMessage>
<SelectControl>
<SelectTrigger asChild>
<Button variant="secondary">
<SelectValueText />
<SelectIndicator asChild>
<ArrowDownShortLine />
</SelectIndicator>
</Button>
</SelectTrigger>
</SelectControl>
<GenericSelectTrigger>
<SelectValueText />
</GenericSelectTrigger>
<SelectPositioner>
<SelectContent>
{languageOptions.map((item) => (
<SelectItem key={item.format} item={item}>
<SelectItemText>{item.title}</SelectItemText>
<SelectItemIndicator asChild>
<CheckLine />
</SelectItemIndicator>
</SelectItem>
<GenericSelectItem key={item.format} item={item}>
{item.title}
</GenericSelectItem>
))}
</SelectContent>
</SelectPositioner>
Expand Down
66 changes: 66 additions & 0 deletions src/components/abstractions/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Copyright (c) 2024-present, NDLA.
*
* This source code is licensed under the GPLv3 license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import { forwardRef } from "react";
import {
SelectIndicatorProps,
SelectItemIndicator,
SelectItemIndicatorProps,
SelectItemProps,
SelectTriggerProps,
} from "@ark-ui/react";
import { ArrowDownShortLine } from "@ndla/icons/common";
import { CheckLine } from "@ndla/icons/editor";
import {
Button,
ButtonProps,
SelectControl,
SelectIndicator,
SelectItem,
SelectItemText,
SelectTrigger,
} from "@ndla/primitives";
import { JsxStyleProps } from "@ndla/styled-system/types";

export const GenericSelectTrigger = forwardRef<HTMLButtonElement, SelectTriggerProps & ButtonProps>(
({ children, variant = "secondary", ...props }, ref) => (
<SelectControl>
<SelectTrigger asChild ref={ref} {...props}>
<Button variant={variant}>
{children}
<GenericSelectIndicator />
</Button>
</SelectTrigger>
</SelectControl>
),
);

export const GenericSelectIndicator = forwardRef<HTMLDivElement, SelectIndicatorProps & JsxStyleProps>(
({ children, ...props }, ref) => (
<SelectIndicator ref={ref} {...props}>
{children ?? <ArrowDownShortLine />}
</SelectIndicator>
),
);

export const GenericSelectItem = forwardRef<HTMLDivElement, SelectItemProps & JsxStyleProps>(
({ children, ...props }, ref) => (
<SelectItem ref={ref} {...props}>
<SelectItemText>{children}</SelectItemText>
<GenericSelectItemIndicator />
</SelectItem>
),
);

export const GenericSelectItemIndicator = forwardRef<HTMLDivElement, SelectItemIndicatorProps & JsxStyleProps>(
({ children, ...props }, ref) => (
<SelectItemIndicator ref={ref} {...props} asChild>
{children ?? <CheckLine />}
</SelectItemIndicator>
),
);
35 changes: 9 additions & 26 deletions src/containers/App/components/FooterWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,9 @@ import { useTranslation } from "react-i18next";
import { createListCollection } from "@ark-ui/react";
import emotionStyled from "@emotion/styled";
import { spacing } from "@ndla/core";
import { ArrowDownShortLine } from "@ndla/icons/common";
import { CheckLine } from "@ndla/icons/editor";
import {
Button,
SelectContent,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectLabel,
SelectPositioner,
SelectRoot,
SelectTrigger,
Text,
} from "@ndla/primitives";
import { SelectContent, SelectLabel, SelectPositioner, SelectRoot, SelectValueText, Text } from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { GenericSelectItem, GenericSelectTrigger } from "../../../components/abstractions/Select";
import { supportedLanguages } from "../../../i18n2";
import { LocaleType } from "../../../interfaces";

Expand All @@ -38,7 +26,7 @@ export const FooterBlock = styled("footer", {
},
});

const LanguageSelectTrigger = styled(SelectTrigger, {
const StyledGenericSelectTrigger = styled(GenericSelectTrigger, {
base: {
width: "unset",
},
Expand Down Expand Up @@ -88,20 +76,15 @@ const FooterWrapper = ({ showLocaleSelector }: Props) => {
value={[i18n.language]}
>
<SelectLabel srOnly>{t("languages.prefixChangeLanguage")}</SelectLabel>
<LanguageSelectTrigger asChild>
<Button variant="secondary">
{t("languages.prefixChangeLanguage")} <ArrowDownShortLine />
</Button>
</LanguageSelectTrigger>
<StyledGenericSelectTrigger>
<SelectValueText>{t("languages.prefixChangeLanguage")}</SelectValueText>
</StyledGenericSelectTrigger>
<SelectPositioner>
<SelectContent>
{supportedLanguages.map((lang) => (
<SelectItem key={lang} item={lang}>
<SelectItemText>{t(`languages.${lang}`)}</SelectItemText>
<SelectItemIndicator>
<CheckLine />
</SelectItemIndicator>
</SelectItem>
<GenericSelectItem key={lang} item={lang}>
{t(`languages.${lang}`)}
</GenericSelectItem>
))}
</SelectContent>
</SelectPositioner>
Expand Down
31 changes: 7 additions & 24 deletions src/containers/FormikForm/components/ContributorsField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { createListCollection } from "@ark-ui/react";
import { CloseLine } from "@ndla/icons/action";
import { ArrowDownShortLine } from "@ndla/icons/common";
import { CheckLine } from "@ndla/icons/editor";
import { contributorGroups, contributorTypes } from "@ndla/licenses";
import {
Button,
Expand All @@ -22,20 +20,15 @@ import {
FieldsetLegend,
FieldsetRoot,
SelectContent,
SelectControl,
SelectHiddenSelect,
SelectIndicator,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectLabel,
SelectPositioner,
SelectRoot,
SelectTrigger,
SelectValueText,
} from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { IAuthor } from "@ndla/types-backend/draft-api";
import { GenericSelectItem, GenericSelectTrigger } from "../../../components/abstractions/Select";
import { FormField } from "../../../components/FormField";

type ContributorType = keyof typeof contributorGroups;
Expand Down Expand Up @@ -137,25 +130,15 @@ const Contributor = ({ type, onAddNew, onRemove }: ContributorProps) => {
>
<SelectLabel>{t("form.name.type")}</SelectLabel>
<FieldErrorMessage>{meta.error}</FieldErrorMessage>
<SelectControl>
<SelectTrigger asChild>
<Button variant="secondary">
<SelectValueText placeholder={t("form.name.type")} />
<SelectIndicator asChild>
<ArrowDownShortLine />
</SelectIndicator>
</Button>
</SelectTrigger>
</SelectControl>
<GenericSelectTrigger>
<SelectValueText placeholder={t("form.name.type")} />
</GenericSelectTrigger>
<SelectPositioner>
<SelectContent>
{collection.items.map((item) => (
<SelectItem key={item.type} item={item}>
<SelectItemText>{item.translation}</SelectItemText>
<SelectItemIndicator asChild>
<CheckLine />
</SelectItemIndicator>
</SelectItem>
<GenericSelectItem key={item.type} item={item}>
{item.translation}
</GenericSelectItem>
))}
</SelectContent>
</SelectPositioner>
Expand Down
34 changes: 8 additions & 26 deletions src/containers/FormikForm/components/LicenseField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,18 @@
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { createListCollection } from "@ark-ui/react";
import { ArrowDownShortLine } from "@ndla/icons/common";
import { CheckLine } from "@ndla/icons/editor";
import {
Button,
FieldErrorMessage,
FieldRoot,
SelectContent,
SelectControl,
SelectHiddenSelect,
SelectIndicator,
SelectItem,
SelectItemIndicator,
SelectItemText,
SelectLabel,
SelectPositioner,
SelectRoot,
SelectTrigger,
SelectValueText,
} from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { GenericSelectItem, GenericSelectTrigger } from "../../../components/abstractions/Select";
import { FormField } from "../../../components/FormField";
import { useLicenses } from "../../../modules/draft/draftQueries";
import { getLicensesWithTranslations } from "../../../util/licenseHelpers";
Expand All @@ -38,7 +30,7 @@ interface Props {
enableLicenseNA?: boolean;
}

const StyledSelectTrigger = styled(SelectTrigger, {
const StyledGenericSelectTrigger = styled(GenericSelectTrigger, {
base: {
width: "100%",
},
Expand Down Expand Up @@ -70,25 +62,15 @@ const LicenseField = ({ name = "license", enableLicenseNA }: Props) => {
>
<SelectLabel>{t("form.license.label")}</SelectLabel>
<FieldErrorMessage>{meta.error}</FieldErrorMessage>
<SelectControl>
<StyledSelectTrigger asChild>
<Button variant="secondary">
<SelectValueText placeholder={t("form.license.choose")} />
<SelectIndicator asChild>
<ArrowDownShortLine />
</SelectIndicator>
</Button>
</StyledSelectTrigger>
</SelectControl>
<StyledGenericSelectTrigger>
<SelectValueText placeholder={t("form.license.choose")} />
</StyledGenericSelectTrigger>
<SelectPositioner>
<SelectContent>
{collection.items.map((item) => (
<SelectItem key={item.license} item={item}>
<SelectItemText>{item.title}</SelectItemText>
<SelectItemIndicator asChild>
<CheckLine />
</SelectItemIndicator>
</SelectItem>
<GenericSelectItem key={item.license} item={item}>
{item.title}
</GenericSelectItem>
))}
</SelectContent>
</SelectPositioner>
Expand Down

0 comments on commit 635b7fa

Please sign in to comment.