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

feat(components): refactor components and remove tailwind prefix #7

Merged
merged 8 commits into from
Jan 23, 2024
8 changes: 7 additions & 1 deletion src/components/DataTable/SWRDataTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ const renderCell = ({ filters, column, row }) => {

switch (column.columnDef.type) {
case "text":
return <div>{value}</div>;
return <div className="max-w-[400px] truncate">{value}</div>;
case "boolean":
return (
<Badge variant={value ? "default" : "secondary"}>
{value ? "True" : "False"}
Copy link
Contributor

Choose a reason for hiding this comment

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

😬 this is a bit odd, right? I'd even use emojis ❌ and ✅ instead of True and False strings. I think only technical users would digest that 😅

</Badge>
);
case "badge":
// TODO: needs to be refactored
switch (value) {
Expand Down
161 changes: 122 additions & 39 deletions src/components/FormBuilder/fields/RadioGroupField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from "react";
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils";
import {
FormControl,
FormDescription,
Expand All @@ -9,7 +11,7 @@ import {
} from "@/components/ui/Form";
import { Label } from "@/components/ui/Label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/RadioGroup";

import { Button } from "@/components/ui/Button";
import { BaseField, withConditional } from "../fields";

export interface RadioGroupFieldProps extends BaseField {
Expand All @@ -23,56 +25,137 @@ export interface RadioGroupFieldProps extends BaseField {
}>;
}

export const RadioGroupField = withConditional<RadioGroupFieldProps>(
({ form, field }) => (
// TODO: handle this case
// const hasSections = field.sections.length > 0;
// if (!hasSections) return;
const radioGroupVariants = cva("w-full", {
variants: {
layout: {
stack: "flex flex-col justify-between items-start",
inline: "flex flex-row justify-start items-center space-x-4",
},
gap: {
small: "gap-1",
medium: "gap-2",
large: "gap-4",
},
},
defaultVariants: {
layout: "inline",
gap: "medium",
},
});

const RadioGroupWithoutSection = ({ form, field }) => {
const hasClearButton = field.show_clear_button;
const [selectedValue, setSelectedValue] = React.useState(
form.getValues(field.name)
);

React.useEffect(() => {
setSelectedValue(form.getValues(field.name));
}, [form, field.name]);

const handleChange = (value) => {
setSelectedValue(value);
form.setValue(field.name, value);
};

const clearSelection = () => {
setSelectedValue(null);
form.setValue(field.name, null);
};

return (
<FormField
control={form.control}
name={field.name}
rules={field.required ? { required: true } : undefined}
render={({ field: formField }) => (
<FormItem className="space-y-0">
rules={field.required ? { required: true } : {}}
render={() => (
<FormItem className="space-y-0 w-full">
<FormLabel>{field.label}</FormLabel>
<FormDescription className="">{field.description}</FormDescription>
<FormDescription>{field.description}</FormDescription>
<FormControl>
<RadioGroup
onValueChange={formField.onChange}
defaultValue={formField.value}
className="py-2"
onValueChange={handleChange}
value={selectedValue}
className={cn(radioGroupVariants(field), "py-2")}
>
<div className="grid grid-cols-2 gap-4">
{field.sections.map((section) => (
<div key={section.label} className="space-y-2">
<Label>{section.label}</Label>
<p className="text-muted-foreground text-sm">
{section.description}
</p>
<div className="flex flex-col gap-1 rounded-md border-red-800 p-2">
{section.options.map((option) => (
<FormItem
key={option.value}
className="flex items-center space-x-3 space-y-0"
>
<FormControl>
<RadioGroupItem value={option.value} />
</FormControl>
<FormLabel className="font-normal">
{option.label}
</FormLabel>
</FormItem>
))}
</div>
</div>
))}
</div>
{field.options.map((option, optionIdx) => (
<FormItem
// eslint-disable-next-line react/no-array-index-key
key={optionIdx}
className="flex items-center space-x-1 space-y-0"
>
<FormControl>
<RadioGroupItem value={option.value} />
</FormControl>
<FormLabel className="font-normal">{option.label}</FormLabel>
</FormItem>
))}
</RadioGroup>
</FormControl>
<FormMessage />

{hasClearButton && (
<Button type="button" onClick={clearSelection}>
Clear
</Button>
)}
</FormItem>
)}
/>
)
);
};

export const RadioGroupField = withConditional<RadioGroupFieldProps>(
({ form, field }) => {
const hasSections = field.sections?.length > 0;
if (!hasSections) return <RadioGroupWithoutSection {...{ form, field }} />;

return (
<FormField
control={form.control}
name={field.name}
rules={field.required ? { required: true } : undefined}
render={({ field: formField }) => (
<FormItem className="space-y-0">
<FormLabel>{field.label}</FormLabel>
<FormDescription className="">{field.description}</FormDescription>
<FormControl>
<RadioGroup
onValueChange={formField.onChange}
defaultValue={formField.value}
className="py-2"
>
<div className="grid grid-cols-2 gap-4">
{field.sections.map((section) => (
<div key={section.label} className="space-y-2">
<Label>{section.label}</Label>
<p className="text-muted-foreground text-sm">
{section.description}
</p>
<div className="flex flex-col gap-1 rounded-md border-red-800 p-2">
{section.options.map((option) => (
<FormItem
key={option.value}
className="flex items-center space-x-3 space-y-0"
>
<FormControl>
<RadioGroupItem value={option.value} />
</FormControl>
<FormLabel className="font-normal">
{option.label}
</FormLabel>
</FormItem>
))}
</div>
</div>
))}
</div>
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
}
);
11 changes: 11 additions & 0 deletions src/components/RailsApp/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { createContext, useContext } from "react";

export const RailsAppContext = createContext("");

export const RailsAppProvider = ({ children, csrfToken }) => (
<RailsAppContext.Provider value={csrfToken}>
{children}
</RailsAppContext.Provider>
);

export const useRailsApp = () => useContext(RailsAppContext);
1 change: 1 addition & 0 deletions src/components/RailsApp/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./context";
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from "./ThemeToggle";
export * from "./DataTable";
export * from "./FormBuilder";
export * from "./ui";
export * from "./RailsApp";
21 changes: 8 additions & 13 deletions src/components/ui/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "react-hook-form";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/Label";
import { useRailsApp } from "@/components/RailsApp/context";

type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
Expand All @@ -25,17 +26,15 @@ const Form = ({
action,
method,
encType = "application/x-www-form-urlencoded",
csrfToken,
...props
}: React.ComponentProps<typeof FormProvider> & {
action: string;
children: React.ReactNode;
className?: string;
csrfToken?: string;
encType?: string;
method?: "post" | "get";
}) => {
// const csrfToken = ReactOnRails.authenticityToken();
const csrfToken = useRailsApp();
Copy link
Contributor

@ribeirojose ribeirojose Jan 22, 2024

Choose a reason for hiding this comment

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

#would try to not make this mandatory here so that we could use this project in bleu's nextjs projects as well


if (!csrfToken) {
throw new Error("Missing authenticity_token");
Expand All @@ -55,7 +54,6 @@ const Form = ({
</FormProvider>
);
};

const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
);
Expand Down Expand Up @@ -112,15 +110,12 @@ const FormItemContext = React.createContext<FormItemContextValue>(
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useMemo(() => ({ id: React.useId() }), []);

return (
<FormItemContext.Provider value={id}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
);
});
>(({ className, ...props }, ref) => (
// eslint-disable-next-line react/jsx-no-constructed-context-values
<FormItemContext.Provider value={{ id: React.useId() }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
));
FormItem.displayName = "FormItem";

const FormLabel = React.forwardRef<
Expand Down
4 changes: 2 additions & 2 deletions src/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@

@layer base {
* {
@apply bleu-ui-border-border;
@apply border-border;
}
body {
@apply bleu-ui-bg-background bleu-ui-text-foreground;
@apply bg-background text-foreground;
font-feature-settings:
"rlig" 1,
"calt" 1;
Expand Down
4 changes: 1 addition & 3 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
const { fontFamily } = require("tailwindcss/defaultTheme");

const CLASSES_PREFIX = "bleu-ui-";

/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
prefix: CLASSES_PREFIX,
prefix: "",
// important: "#bleu-ui",
content: ["src/**/*.{ts,tsx}"],
corePlugins: {
Expand Down
Loading