Skip to content

Commit

Permalink
refactor: use primitives in gloss form
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas-C committed Oct 11, 2024
1 parent 635b7fa commit 39bf859
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 245 deletions.
142 changes: 86 additions & 56 deletions src/containers/GlossPage/components/ExampleField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,29 @@
*/

import { useField } from "formik";
import { useEffect } from "react";
import { useEffect, useMemo } from "react";
import { useTranslation } from "react-i18next";
import styled from "@emotion/styled";
import { IconButtonV2 } from "@ndla/button";
import { spacing } from "@ndla/core";
import { Select, InputV3, FieldErrorMessage, Label } from "@ndla/forms";
import { Cross } from "@ndla/icons/action";
import { createListCollection } from "@ark-ui/react";
import { CloseLine } from "@ndla/icons/action";
import {
FieldErrorMessage,
FieldInput,
FieldLabel,
FieldRoot,
FieldsetLegend,
FieldsetRoot,
IconButton,
SelectContent,
SelectHiddenSelect,
SelectLabel,
SelectPositioner,
SelectRoot,
SelectValueText,
} from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { IGlossExample } from "@ndla/types-backend/concept-api";
import { Text } from "@ndla/typography";
import { FormControl, FormField } from "../../../components/FormField";
import { GenericSelectItem, GenericSelectTrigger } from "../../../components/abstractions/Select";
import { FormField } from "../../../components/FormField";
import { LANGUAGES } from "../glossData";

interface Props {
Expand All @@ -27,27 +40,25 @@ interface Props {
onRemoveExample: () => void;
}

const Wrapper = styled.fieldset`
width: 100%;
border: none;
padding: 0px;
margin: 0px;
`;
const FieldWrapper = styled("div", {
base: {
display: "grid",
gridTemplateColumns: "1fr auto auto",
gap: "xsmall",
},
});

const FieldWrapper = styled.div`
display: flex;
gap: ${spacing.small};
width: 100%;
`;
const StyledFieldsetRoot = styled(FieldsetRoot, {
base: {
width: "100%",
},
});

const StyledFormControl = styled(FormControl)`
flex: 1;
`;

const RemoveButton = styled(IconButtonV2)`
height: ${spacing.large};
width: ${spacing.large};
`;
const StyledGenericSelectTrigger = styled(GenericSelectTrigger, {
base: {
width: "surface.xxsmall",
},
});

const ExampleField = ({ example, name, index, exampleIndex, onRemoveExample }: Props) => {
const { t } = useTranslation();
Expand All @@ -60,6 +71,16 @@ const ExampleField = ({ example, name, index, exampleIndex, onRemoveExample }: P
index: exampleIndex + 1,
});

const collection = useMemo(
() =>
createListCollection({
items: LANGUAGES,
itemToString: (item) => t(`languages.${item}`),
itemToValue: (item) => item,
}),
[t],
);

useEffect(() => {
if (exampleIndex === 0) {
languageHelpers.setValue(originalLanguageField.value, true);
Expand All @@ -69,50 +90,59 @@ const ExampleField = ({ example, name, index, exampleIndex, onRemoveExample }: P
}, [exampleIndex, languageField.value, languageHelpers, originalLanguageField.value]);

return (
<Wrapper>
<Text element="legend" textStyle="label-small">
<StyledFieldsetRoot>
<FieldsetLegend textStyle="label.small">
{t("form.gloss.examples.exampleOnLanguage", {
index: labelIndex,
language: t(`languages.${languageField.value}`).toLowerCase(),
})}
</Text>
</FieldsetLegend>
<FieldWrapper>
<FormField name={`${name}.example`}>
{({ field, meta }) => (
<StyledFormControl isRequired isInvalid={!!meta.error}>
<Label textStyle="label-small" margin="none" visuallyHidden>
<FieldRoot required invalid={!!meta.error}>
<FieldLabel srOnly>
{t("form.gloss.examples.exampleTextLabel", {
index: labelIndex,
language: t(`languages.${languageField.value}`).toLowerCase(),
})}
</Label>
<InputV3 type="text" placeholder={t("form.gloss.example")} {...field} />
</FieldLabel>
<FieldInput type="text" placeholder={t("form.gloss.example")} {...field} />
<FieldErrorMessage>{meta.error}</FieldErrorMessage>
</StyledFormControl>
</FieldRoot>
)}
</FormField>
<FormControl isRequired isDisabled={exampleIndex === 0} isInvalid={!!languageMeta.error}>
<Select {...languageField}>
{!example.language && (
<option>
{t("form.gloss.choose", {
label: t("form.gloss.language").toLowerCase(),
})}
</option>
)}
{LANGUAGES.map((language, languageIndex) => (
<option value={language} key={languageIndex}>
{t(`languages.${language}`)}
</option>
))}
</Select>
<FieldErrorMessage>{languageMeta.error}</FieldErrorMessage>
</FormControl>
<RemoveButton colorTheme="light" aria-label={removeLabel} title={removeLabel} onClick={onRemoveExample}>
<Cross />
</RemoveButton>
<FieldRoot required disabled={exampleIndex === 0} invalid={!!languageMeta.error}>
<SelectRoot
collection={collection}
positioning={{ sameWidth: true }}
value={[languageField.value]}
onValueChange={(details) => languageHelpers.setValue(details.value[0])}
>
<SelectLabel srOnly>{t("form.gloss.language")}</SelectLabel>
<FieldErrorMessage>{languageMeta.error}</FieldErrorMessage>
<StyledGenericSelectTrigger>
<SelectValueText
placeholder={t("form.gloss.choose", { label: t("form.gloss.language").toLowerCase() })}
/>
</StyledGenericSelectTrigger>
<SelectPositioner>
<SelectContent>
{collection.items.map((language) => (
<GenericSelectItem key={language} item={language}>
{t(`languages.${language}`)}
</GenericSelectItem>
))}
</SelectContent>
</SelectPositioner>
<SelectHiddenSelect />
</SelectRoot>
</FieldRoot>
<IconButton variant="danger" aria-label={removeLabel} title={removeLabel} onClick={onRemoveExample}>
<CloseLine />
</IconButton>
</FieldWrapper>
</Wrapper>
</StyledFieldsetRoot>
);
};

Expand Down
77 changes: 44 additions & 33 deletions src/containers/GlossPage/components/ExamplesFieldArray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,36 @@

import { FieldArray, useField } from "formik";
import { useTranslation } from "react-i18next";
import styled from "@emotion/styled";
import { ButtonV2 } from "@ndla/button";
import { spacing } from "@ndla/core";
import { Button, FieldsetHelper, FieldsetLegend, FieldsetRoot } from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { IGlossExample } from "@ndla/types-backend/concept-api";
import { Text } from "@ndla/typography";

import LanguageVariantFieldArray from "./LanguageVariantFieldArray";
import { FormField } from "../../../components/FormField";
import { emptyGlossExample } from "../glossData";

const StyledFieldset = styled.fieldset`
border: none;
display: flex;
align-items: flex-start;
flex-direction: column;
gap: ${spacing.small};
width: 100%;
padding: 0px;
`;
const StyledFieldsetRoot = styled(FieldsetRoot, {
base: {
alignItems: "flex-start",
width: "100%",
gap: "xsmall",
},
});

const ArrayWrapper = styled("div", {
base: {
display: "flex",
flexDirection: "column",
gap: "large",
width: "100%",
},
});

const StyledButton = styled(Button, {
base: {
marginBlockStart: "medium",
},
});

interface Props {
name: string;
Expand All @@ -41,24 +52,24 @@ const ExamplesFieldArray = ({ name }: Props) => {
<FieldArray
name={name}
render={(arrayHelpers) => (
<StyledFieldset>
<Text element="legend" textStyle="label-large">
{t("form.gloss.examples.title")}
</Text>
<Text textStyle="meta-text-medium">{t("form.gloss.examples.description")}</Text>
{value?.map((languageVariantExamples, index) => (
<FormField key={`${name}.${index}`} name={`${name}.${index}`}>
{({ field }) => (
<LanguageVariantFieldArray
examples={languageVariantExamples}
index={index}
{...field}
removeFromParentArray={() => arrayHelpers.remove(index)}
/>
)}
</FormField>
))}
<ButtonV2
<StyledFieldsetRoot>
<FieldsetLegend textStyle="title.medium">{t("form.gloss.examples.title")}</FieldsetLegend>
<FieldsetHelper>{t("form.gloss.examples.description")}</FieldsetHelper>
<ArrayWrapper>
{value?.map((languageVariantExamples, index) => (
<FormField key={`${name}.${index}`} name={`${name}.${index}`}>
{({ field }) => (
<LanguageVariantFieldArray
examples={languageVariantExamples}
index={index}
{...field}
removeFromParentArray={() => arrayHelpers.remove(index)}
/>
)}
</FormField>
))}
</ArrayWrapper>
<StyledButton
disabled={!originalLanguageField.value}
onClick={() => {
arrayHelpers.push([emptyGlossExample]);
Expand All @@ -67,8 +78,8 @@ const ExamplesFieldArray = ({ name }: Props) => {
{t("form.gloss.add", {
label: t(`form.gloss.example`).toLowerCase(),
})}
</ButtonV2>
</StyledFieldset>
</StyledButton>
</StyledFieldsetRoot>
)}
/>
);
Expand Down
Loading

0 comments on commit 39bf859

Please sign in to comment.