Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ it according to semantic versioning. For example, if your PR adds a breaking cha
should change the heading of the (upcoming) version to include a major version bump.

-->
# 6.0.0-beta.15

## @rjsf/shadcn

- Update `README.md` with picture of the theme!
- Allow passing `className` props to `AddButton`, `BaseInputTemplate`, `CheckboxWidget`, `CheckboxesWidget`, `RadioWidget`, `SelectWidget`, `SubmitButton`, `TextareaWidget` for extra Tailwind CSS customization through `ui:className`

# 6.0.0-beta.14

## @rjsf/core
Expand Down
8 changes: 6 additions & 2 deletions packages/shadcn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
<a href="https://github.com/rjsf-team/react-jsonschema-form/issues">Request Feature</a>
</p>


<p align="center">
<img src="https://github.com/tuanphung2308/rjsf-shadcn-css/blob/main/shadcn-demo.png?raw=true" alt="Logo" width="720" height="240">
</p>

<!-- TABLE OF CONTENTS -->

## Table of Contents
Expand Down Expand Up @@ -134,8 +139,7 @@ Supported colors are:
#### Coloring

- Generate a theme from [official shadCN site](https://ui.shadcn.com/themes)
or [zippy starter's shadcn/ui theme generator](https://zippystarter.com/tools/shadcn-ui-theme-generator)
or [Railly](https://customizer.railly.dev/)
or [tweakcn](https://tweakcn.com/editor/theme)
- Navigate to shadcn/css, create a new file called [your-theme].css
- Replace the base layer code with your new color
- Follow the next section to build your CSS file
Expand Down
7 changes: 6 additions & 1 deletion packages/shadcn/src/AddButton/AddButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ import { FormContextType, IconButtonProps, RJSFSchema, StrictRJSFSchema, Transla
import { PlusCircle } from 'lucide-react';

import { Button } from '../components/ui/button';
import { cn } from '../lib/utils';

/**
* A button component for adding new items in a form
* @param uiSchema - The UI schema for the form, which can include custom properties
* @param registry - The registry object containing the form's configuration and utilities
* @param className - Allow custom class names to be passed for Tailwind CSS styling
* @param props - The component properties
*/
export default function AddButton<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
uiSchema,
registry,
className,
...props
}: IconButtonProps<T, S, F>) {
const { translateString } = registry;
return (
<div className='p-0 m-0'>
<Button {...props} className='w-fit gap-2' variant='outline' type='button'>
<Button {...props} className={cn('w-fit gap-2', className)} variant='outline' type='button'>
<PlusCircle size={16} /> {translateString(TranslatableString.AddItemButton)}
</Button>
</div>
Expand Down
3 changes: 2 additions & 1 deletion packages/shadcn/src/BaseInputTemplate/BaseInputTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function BaseInputTemplate<
rawErrors = [],
children,
extraProps,
className,
}: BaseInputTemplateProps<T, S, F>) {
const inputProps = {
...extraProps,
Expand All @@ -61,7 +62,7 @@ export default function BaseInputTemplate<
required={required}
disabled={disabled}
readOnly={readonly}
className={cn({ 'border-destructive focus-visible:ring-0': rawErrors.length > 0 })}
className={cn({ 'border-destructive focus-visible:ring-0': rawErrors.length > 0 }, className)}
list={schema.examples ? examplesId<T>(id) : undefined}
{...inputProps}
value={value || value === 0 ? value : ''}
Expand Down
2 changes: 2 additions & 0 deletions packages/shadcn/src/CheckboxWidget/CheckboxWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default function CheckboxWidget<
onFocus,
registry,
uiSchema,
className,
} = props;
// Because an unchecked checkbox will cause html5 validation to fail, only add
// the "required" attribute if the field value must be "true", due to the
Expand Down Expand Up @@ -78,6 +79,7 @@ export default function CheckboxWidget<
onCheckedChange={_onChange}
onBlur={_onBlur}
onFocus={_onFocus}
className={className}
/>
<Label className='leading-tight' htmlFor={id}>
{labelValue(label, hideLabel || !label)}
Expand Down
15 changes: 14 additions & 1 deletion packages/shadcn/src/CheckboxesWidget/CheckboxesWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@ export default function CheckboxesWidget<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any,
>({ id, disabled, options, value, autofocus, readonly, required, onChange, onBlur, onFocus }: WidgetProps<T, S, F>) {
>({
id,
disabled,
options,
value,
autofocus,
readonly,
required,
onChange,
onBlur,
onFocus,
className,
}: WidgetProps<T, S, F>) {
const { enumOptions, enumDisabled, inline, emptyValue } = options;
const checkboxesValues = Array.isArray(value) ? value : [value];

Expand Down Expand Up @@ -56,6 +68,7 @@ export default function CheckboxesWidget<
onChange(enumOptionsDeselectValue<S>(index, checkboxesValues, enumOptions));
}
}}
className={className}
checked={checked}
autoFocus={autofocus && index === 0}
onBlur={_onBlur}
Expand Down
3 changes: 2 additions & 1 deletion packages/shadcn/src/RadioWidget/RadioWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSc
onChange,
onBlur,
onFocus,
className,
}: WidgetProps<T, S, F>) {
const { enumOptions, enumDisabled, emptyValue } = options;

Expand All @@ -53,7 +54,7 @@ export default function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSc
onFocus={_onFocus}
aria-describedby={ariaDescribedByIds<T>(id)}
orientation={inline ? 'horizontal' : 'vertical'}
className={cn('flex flex-wrap', { 'flex-col': !inline })}
className={cn('flex flex-wrap', { 'flex-col': !inline }, className)}
>
{Array.isArray(enumOptions) &&
enumOptions.map((option, index) => {
Expand Down
7 changes: 5 additions & 2 deletions packages/shadcn/src/SelectWidget/SelectWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default function SelectWidget<
defaultValue,
placeholder,
rawErrors = [],
className,
}: WidgetProps<T, S, F>) {
const { enumOptions, enumDisabled, emptyValue: optEmptyValue } = options;

Expand All @@ -54,6 +55,8 @@ export default function SelectWidget<
disabled: Array.isArray(enumDisabled) && enumDisabled.includes(value),
}));

const cnClassName = cn({ 'border-destructive': rawErrors.length > 0 }, className);

return (
<div className='p-0.5'>
{!multiple ? (
Expand All @@ -67,7 +70,7 @@ export default function SelectWidget<
disabled={disabled || readonly}
required={required}
placeholder={placeholder}
className={cn({ 'border-destructive': rawErrors.length > 0 })}
className={cnClassName}
onFocus={_onFancyFocus}
onBlur={_onFancyBlur}
ariaDescribedby={ariaDescribedByIds<T>(id)}
Expand All @@ -78,7 +81,7 @@ export default function SelectWidget<
autoFocus={autofocus}
disabled={disabled || readonly}
multiple
className={rawErrors.length > 0 ? 'border-destructive' : ''}
className={cnClassName}
items={items}
selected={value}
onValueChange={(values) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/shadcn/src/SubmitButton/SubmitButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FormContextType, getSubmitButtonOptions, RJSFSchema, StrictRJSFSchema, SubmitButtonProps } from '@rjsf/utils';

import { Button } from '../components/ui/button';
import { cn } from '../lib/utils';

/** The `SubmitButton` renders a button that represent the `Submit` action on a form
*/
Expand All @@ -13,7 +14,7 @@ export default function SubmitButton<T = any, S extends StrictRJSFSchema = RJSFS
}
return (
<div>
<Button type='submit' {...submitButtonProps} className='my-2'>
<Button type='submit' {...submitButtonProps} className={cn('my-2', submitButtonProps?.className)}>
{submitText}
</Button>
</div>
Expand Down
2 changes: 2 additions & 0 deletions packages/shadcn/src/TextareaWidget/TextareaWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function TextareaWidget<
onFocus,
onChange,
options,
className,
}: CustomWidgetProps<T, S, F>) {
const _onChange = ({ target: { value } }: ChangeEvent<HTMLTextAreaElement>) =>
onChange(value === '' ? options.emptyValue : value);
Expand All @@ -53,6 +54,7 @@ export default function TextareaWidget<
onBlur={_onBlur}
onFocus={_onFocus}
aria-describedby={ariaDescribedByIds<T>(id)}
className={className}
/>
</div>
);
Expand Down
Loading