diff --git a/src/components/DataTable/SWRDataTable/index.tsx b/src/components/DataTable/SWRDataTable/index.tsx index 0a67fce..e16fe26 100644 --- a/src/components/DataTable/SWRDataTable/index.tsx +++ b/src/components/DataTable/SWRDataTable/index.tsx @@ -8,6 +8,7 @@ import { } from "@tanstack/react-table"; import { useNavigate } from "react-router-dom"; import useSWR from "swr"; +import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons"; import { Badge, Table, @@ -57,7 +58,13 @@ const renderCell = ({ filters, column, row }) => { switch (column.columnDef.type) { case "text": - return
{value}
; + return
{value}
; + case "boolean": + return value ? ( + + ) : ( + + ); case "badge": // TODO: needs to be refactored switch (value) { diff --git a/src/components/FormBuilder/fields/RadioGroupField.tsx b/src/components/FormBuilder/fields/RadioGroupField.tsx index 0b26a4d..d6cdcfa 100644 --- a/src/components/FormBuilder/fields/RadioGroupField.tsx +++ b/src/components/FormBuilder/fields/RadioGroupField.tsx @@ -1,4 +1,6 @@ import React from "react"; +import { cva } from "class-variance-authority"; +import { cn } from "@/lib/utils"; import { FormControl, FormDescription, @@ -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 { @@ -23,56 +25,137 @@ export interface RadioGroupFieldProps extends BaseField { }>; } -export const RadioGroupField = withConditional( - ({ 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 ( ( - + rules={field.required ? { required: true } : {}} + render={() => ( + {field.label} - {field.description} + {field.description} -
- {field.sections.map((section) => ( -
- -

- {section.description} -

-
- {section.options.map((option) => ( - - - - - - {option.label} - - - ))} -
-
- ))} -
+ {field.options.map((option, optionIdx) => ( + + + + + {option.label} + + ))}
+ + {hasClearButton && ( + + )}
)} /> - ) + ); +}; + +export const RadioGroupField = withConditional( + ({ form, field }) => { + const hasSections = field.sections?.length > 0; + if (!hasSections) return ; + + return ( + ( + + {field.label} + {field.description} + + +
+ {field.sections.map((section) => ( +
+ +

+ {section.description} +

+
+ {section.options.map((option) => ( + + + + + + {option.label} + + + ))} +
+
+ ))} +
+
+
+ +
+ )} + /> + ); + } ); diff --git a/src/components/RailsApp/context.tsx b/src/components/RailsApp/context.tsx new file mode 100644 index 0000000..e5d0e22 --- /dev/null +++ b/src/components/RailsApp/context.tsx @@ -0,0 +1,11 @@ +import React, { createContext, useContext } from "react"; + +export const RailsAppContext = createContext(""); + +export const RailsAppProvider = ({ children, csrfToken }) => ( + + {children} + +); + +export const useRailsApp = () => useContext(RailsAppContext); diff --git a/src/components/RailsApp/index.tsx b/src/components/RailsApp/index.tsx new file mode 100644 index 0000000..2edd280 --- /dev/null +++ b/src/components/RailsApp/index.tsx @@ -0,0 +1 @@ +export * from "./context"; diff --git a/src/components/index.ts b/src/components/index.ts index 8dacc37..deaa0b4 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -5,3 +5,4 @@ export * from "./ThemeToggle"; export * from "./DataTable"; export * from "./FormBuilder"; export * from "./ui"; +export * from "./RailsApp"; diff --git a/src/components/ui/Form.tsx b/src/components/ui/Form.tsx index af9d453..b7b87f5 100644 --- a/src/components/ui/Form.tsx +++ b/src/components/ui/Form.tsx @@ -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, @@ -25,17 +26,15 @@ const Form = ({ action, method, encType = "application/x-www-form-urlencoded", - csrfToken, ...props }: React.ComponentProps & { action: string; children: React.ReactNode; className?: string; - csrfToken?: string; encType?: string; method?: "post" | "get"; }) => { - // const csrfToken = ReactOnRails.authenticityToken(); + const csrfToken = useRailsApp(); if (!csrfToken) { throw new Error("Missing authenticity_token"); @@ -55,7 +54,6 @@ const Form = ({ ); }; - const FormFieldContext = React.createContext( {} as FormFieldContextValue ); @@ -112,15 +110,12 @@ const FormItemContext = React.createContext( const FormItem = React.forwardRef< HTMLDivElement, React.HTMLAttributes ->(({ className, ...props }, ref) => { - const id = React.useMemo(() => ({ id: React.useId() }), []); - - return ( - -
- - ); -}); +>(({ className, ...props }, ref) => ( + // eslint-disable-next-line react/jsx-no-constructed-context-values + +
+ +)); FormItem.displayName = "FormItem"; const FormLabel = React.forwardRef< diff --git a/src/components/ui/Tooltip.tsx b/src/components/ui/Tooltip.tsx index b35a629..d80f0df 100644 --- a/src/components/ui/Tooltip.tsx +++ b/src/components/ui/Tooltip.tsx @@ -17,7 +17,7 @@ const TooltipContent = React.forwardRef< ref={ref} sideOffset={sideOffset} className={cn( - "bleu-ui-z-50 bleu-ui-overflow-hidden bleu-ui-rounded-md bleu-ui-bg-primary bleu-ui-px-3 bleu-ui-py-1.5 bleu-ui-text-xs bleu-ui-text-primary-foreground bleu-ui-animate-in bleu-ui-fade-in-0 bleu-ui-zoom-in-95 data-[state=closed]:bleu-ui-animate-out data-[state=closed]:bleu-ui-fade-out-0 data-[state=closed]:bleu-ui-zoom-out-95 data-[side=bottom]:bleu-ui-slide-in-from-top-2 data-[side=left]:bleu-ui-slide-in-from-right-2 data-[side=right]:bleu-ui-slide-in-from-left-2 data-[side=top]:bleu-ui-slide-in-from-bottom-2", + "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className )} {...props} diff --git a/src/tailwind.css b/src/tailwind.css index d2c1f44..3640b06 100644 --- a/src/tailwind.css +++ b/src/tailwind.css @@ -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; diff --git a/tailwind.config.js b/tailwind.config.js index cea50f7..a938562 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -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: {