Skip to content

Commit d9d293b

Browse files
fix(ui): improved isReadOnly and isDisabled functionality and styling
1 parent 553d485 commit d9d293b

File tree

5 files changed

+130
-62
lines changed

5 files changed

+130
-62
lines changed

packages/ui/src/checkbox/Checkbox.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,18 @@ import { classNames } from "../utils";
1515
// Checkbox Component
1616

1717
export const checkboxClasses = cva(
18-
"border-secondary-400 dark:border-secondary-700 focus-visible:ring-ring data-[state=checked]:bg-primary-500 data-[state=checked]:border-primary-500 dark:data-[state=checked]:bg-primary-300 dark:data-[state=checked]:border-primary-300 relative shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 focus:ring-2",
18+
"border-secondary-400 dark:border-secondary-700 focus-visible:ring-ring data-[state=checked]:bg-primary-500 data-[state=checked]:border-primary-500 dark:data-[state=checked]:bg-primary-300 dark:data-[state=checked]:border-primary-300 relative shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus:ring-2",
1919
{
2020
variants: {
2121
size: { sm: "size-4", md: "size-5", lg: "size-6" },
22+
disabled: {
23+
true: "cursor-not-allowed opacity-70",
24+
false: "",
25+
},
2226
},
2327
defaultVariants: {
2428
size: "md",
29+
disabled: false,
2530
},
2631
},
2732
);
@@ -50,15 +55,18 @@ const checkboxLabelClasses = cva("", {
5055
lg: "pl-2.5 text-base leading-snug",
5156
},
5257
disabled: {
53-
true: "cursor-not-allowed opacity-50",
58+
true: "cursor-not-allowed opacity-70",
5459
false: "",
5560
},
5661
},
62+
defaultVariants: {
63+
size: "md",
64+
disabled: false,
65+
},
5766
});
5867

59-
export type Checkbox = Omit<
60-
ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
61-
"disabled" | "required"
68+
export type Checkbox = ComponentPropsWithoutRef<
69+
typeof CheckboxPrimitive.Root
6270
> & {
6371
size?: "sm" | "md" | "lg";
6472
isReadOnly?: BooleanOrFunction;
@@ -82,23 +90,29 @@ export const Checkbox = forwardRef<
8290
},
8391
forwardedref,
8492
) => {
85-
const context = useFieldControlContext() ?? {};
93+
const fieldControlContext = useFieldControlContext() ?? {};
94+
95+
const name = props.name || fieldControlContext.name;
8696

87-
const name = props.name || context.name;
8897
const disabled =
8998
getValue(isDisabled) ||
90-
context.isDisabled ||
91-
getValue(isReadOnly) ||
92-
context.isReadOnly;
93-
const required = getValue(isRequired) ?? context.isRequired;
99+
fieldControlContext.isDisabled ||
100+
props.disabled ||
101+
fieldControlContext.isLoading;
102+
103+
const readonly = getValue(isReadOnly) || fieldControlContext.isReadOnly;
104+
105+
const required =
106+
(getValue(isRequired) || props.required) ??
107+
fieldControlContext.isRequired;
94108

95109
const checkbox = (
96110
<CheckboxPrimitive.Root
97111
{...props}
98112
name={name}
99-
disabled={disabled}
113+
disabled={disabled || readonly}
100114
required={required}
101-
className={classNames(checkboxClasses({ size }), className)}
115+
className={classNames(checkboxClasses({ size, disabled }), className)}
102116
ref={forwardedref}
103117
>
104118
<CheckboxPrimitive.Indicator className="group flex h-full items-center justify-center">

packages/ui/src/checkbox/checkbox.stories.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const meta: Meta<typeof Checkbox> = {
99
size: "md",
1010
isDisabled: false,
1111
isRequired: false,
12+
isReadOnly: false,
1213
},
1314
argTypes: {
1415
size: {
@@ -22,28 +23,34 @@ export default meta;
2223
type Story = StoryObj<typeof Checkbox>;
2324

2425
export const Default: Story = {
25-
render: ({ size, isDisabled, isRequired }) => {
26+
render: ({ size, isDisabled, isRequired, isReadOnly }) => {
2627
return (
27-
<Checkbox isDisabled={isDisabled} size={size} isRequired={isRequired} />
28+
<Checkbox
29+
isDisabled={isDisabled}
30+
size={size}
31+
isRequired={isRequired}
32+
isReadOnly={isReadOnly}
33+
/>
2834
);
2935
},
3036
};
3137

3238
export const WithChildren: Story = {
33-
render: ({ size, isDisabled, isRequired }) => (
39+
render: ({ size, isDisabled, isRequired, isReadOnly }) => (
3440
<Checkbox
3541
id="name"
3642
size={size}
3743
isDisabled={isDisabled}
3844
isRequired={isRequired}
45+
isReadOnly={isReadOnly}
3946
>
4047
Name
4148
</Checkbox>
4249
),
4350
};
4451

4552
export const Indeterminate: Story = {
46-
render: ({ size, isDisabled, isRequired }) => {
53+
render: ({ size, isDisabled, isRequired, isReadOnly }) => {
4754
const [state, setState] = useState<CheckedState>("indeterminate");
4855

4956
return (
@@ -53,6 +60,7 @@ export const Indeterminate: Story = {
5360
checked={state}
5461
isDisabled={isDisabled}
5562
isRequired={isRequired}
63+
isReadOnly={isReadOnly}
5664
onCheckedChange={(checked) =>
5765
checked ? setState(true) : setState("indeterminate")
5866
}

packages/ui/src/input-field/InputField.tsx

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useInputGroupContext } from "../input-group";
77
import { classNames } from "../utils";
88

99
export const inputFieldClasses = cva(
10-
"w-full z-[1] appearance-none outline-none dark:text-secondary-200 transition-all disabled:bg-secondary-100 disabled:dark:bg-secondary-800 disabled:cursor-not-allowed",
10+
"w-full z-[1] border appearance-none outline-none dark:text-secondary-200 transition-all",
1111
{
1212
variants: {
1313
size: {
@@ -16,10 +16,17 @@ export const inputFieldClasses = cva(
1616
lg: "py-2 text-lg",
1717
},
1818
variant: {
19-
solid: "bg-secondary-50 dark:bg-secondary-800/20",
20-
outline:
21-
"read-only:focus:border-secondary-300 dark:read-only:focus:border-secondary-700 read-only:focus:ring-0",
22-
ghost: "border border-transparent",
19+
solid: "",
20+
outline: "",
21+
ghost: "",
22+
},
23+
disabled: {
24+
true: "",
25+
false: "",
26+
},
27+
readonly: {
28+
true: "",
29+
false: "",
2330
},
2431
invalid: {
2532
true: "border-red-500 focus:ring-red-200 dark:border-red-400 dark:focus:ring-red-100/20",
@@ -38,21 +45,42 @@ export const inputFieldClasses = cva(
3845
},
3946
},
4047
compoundVariants: [
48+
{
49+
variant: "solid",
50+
disabled: false,
51+
readonly: false,
52+
className: "bg-secondary-50 dark:bg-secondary-900",
53+
},
54+
{
55+
disabled: true,
56+
readonly: false,
57+
className: "bg-secondary-100 dark:bg-secondary-800 cursor-not-allowed",
58+
},
4159
{
4260
variant: ["solid", "outline"],
43-
size: ["sm", "md", "lg"],
44-
className: classNames(
45-
"border border-secondary-300 dark:border-secondary-700 outline-none",
46-
"hover:border-primary-500 dark:hover:border-primary-400 disabled:hover:border-secondary-300 dark:disabled:hover:border-secondary-700",
47-
"focus:border-primary-500 dark:focus:border-primary-400",
48-
"focus:ring-2 focus:ring-primary-200 dark:focus:ring-primary-100/20",
49-
),
61+
disabled: false,
62+
className: "hover:border-primary-500 dark:hover:border-primary-400",
63+
},
64+
{
65+
variant: ["solid", "outline"],
66+
className: "border-secondary-300 dark:border-zinc-700",
67+
},
68+
{
69+
disabled: false,
70+
readonly: false,
71+
className:
72+
"focus:ring-primary-200 focus:border-primary-500 dark:focus:ring-primary-100/20 dark:focus:border-primary-400 focus:ring-2",
5073
},
5174
{
5275
variant: ["outline", "ghost"],
53-
size: ["sm", "md", "lg"],
76+
disabled: false,
77+
readonly: false,
5478
className: "bg-transparent",
5579
},
80+
{
81+
variant: "ghost",
82+
className: "border-transparent",
83+
},
5684
{
5785
size: "sm",
5886
isLeftAddon: false,
@@ -186,7 +214,12 @@ export const InputField = forwardRef<HTMLInputElement, InputField>(
186214
},
187215
forwardedRef,
188216
) => {
189-
const fieldControlContext = useFieldControlContext() ?? {};
217+
const fieldControlContext = useFieldControlContext() ?? {
218+
isDisabled: false,
219+
isLoading: false,
220+
isReadOnly: false,
221+
isRequired: false,
222+
};
190223

191224
const name = props.name || fieldControlContext.name;
192225
const disabled =
@@ -224,6 +257,8 @@ export const InputField = forwardRef<HTMLInputElement, InputField>(
224257
inputFieldClasses({
225258
size: inputGroupContext.size,
226259
variant,
260+
disabled,
261+
readonly,
227262
invalid,
228263
isLeftAddon: inputGroupContext.isLeftAddon,
229264
isRightAddon: inputGroupContext.isRightAddon,

packages/ui/src/select/Select.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,39 +47,31 @@ const selectClasses = cva(
4747
className: "bg-secondary-50 dark:bg-secondary-900",
4848
},
4949
{
50-
variant: ["solid", "outline", "ghost"],
5150
disabled: true,
5251
readonly: false,
5352
className: "bg-secondary-100 dark:bg-secondary-800 cursor-not-allowed",
5453
},
55-
{
56-
variant: ["solid", "outline", "ghost"],
57-
disabled: false,
58-
readonly: true,
59-
className: "bg-secondary-100 dark:bg-secondary-800",
60-
},
6154
{
6255
variant: ["solid", "outline"],
6356
disabled: false,
64-
readonly: false,
6557
className:
66-
"group-hover:border-primary-500 dark:group-hover:border-primary-400 focus:ring-primary-200 focus:border-primary-500 dark:focus:ring-primary-100/20 dark:focus:border-primary-400 focus:ring-2",
58+
"group-hover:border-primary-500 dark:group-hover:border-primary-400",
6759
},
6860
{
6961
variant: ["solid", "outline"],
7062
className: "border-secondary-300 dark:border-zinc-700",
7163
},
7264
{
73-
variant: ["solid", "outline", "ghost"],
7465
disabled: false,
7566
readonly: false,
76-
className: "cursor-pointer",
67+
className:
68+
"cursor-pointer focus:ring-primary-200 focus:border-primary-500 dark:focus:ring-primary-100/20 dark:focus:border-primary-400 focus:ring-2",
7769
},
7870
{
7971
variant: ["outline", "ghost"],
8072
disabled: false,
8173
readonly: false,
82-
className: "bg-transparent dark:bg-secondary-900",
74+
className: "bg-transparent",
8375
},
8476
{
8577
variant: "ghost",

packages/ui/src/textarea/Textarea.tsx

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useFieldControlContext } from "../field-control";
66
import { classNames } from "../utils";
77

88
export const textareaClasses = cva(
9-
"w-full border appearance-none min-h-[80px] outline-none dark:text-secondary-200 transition-all disabled:bg-secondary-100 disabled:dark:bg-secondary-800 disabled:cursor-not-allowed",
9+
"w-full border appearance-none min-h-[80px] outline-none dark:text-secondary-200 transition-all",
1010
{
1111
variants: {
1212
size: {
@@ -19,43 +19,55 @@ export const textareaClasses = cva(
1919
outline: "",
2020
ghost: "",
2121
},
22-
invalid: {
22+
disabled: {
2323
true: "",
2424
false: "",
2525
},
26+
readonly: {
27+
true: "",
28+
false: "",
29+
},
30+
invalid: {
31+
true: "border-red-500 focus:ring-red-200 dark:border-red-400 dark:focus:ring-red-100/20",
32+
},
2633
},
2734
compoundVariants: [
2835
{
2936
variant: "solid",
30-
invalid: false,
37+
disabled: false,
38+
readonly: false,
3139
className: "bg-secondary-50 dark:bg-secondary-900",
3240
},
3341
{
34-
variant: "ghost",
35-
invalid: false,
36-
className: "border-transparent",
42+
disabled: true,
43+
readonly: false,
44+
className: "bg-secondary-100 dark:bg-secondary-800 cursor-not-allowed",
3745
},
3846
{
39-
variant: ["solid", "outline", "ghost"],
40-
invalid: true,
41-
className:
42-
"border-red-500 focus:ring-red-200 dark:border-red-400 dark:focus:ring-red-100/20",
47+
variant: ["solid", "outline"],
48+
disabled: false,
49+
className: "hover:border-primary-500 dark:hover:border-primary-400",
4350
},
4451
{
4552
variant: ["solid", "outline"],
46-
size: ["sm", "md", "lg"],
47-
className: classNames(
48-
"border border-secondary-300 dark:border-secondary-700 outline-none",
49-
"hover:border-primary-500 dark:hover:border-primary-400 disabled:hover:border-secondary-300 dark:disabled:hover:border-secondary-700",
50-
"focus:border-primary-500 dark:focus:border-primary-400",
51-
"focus:ring-2 focus:ring-primary-200 dark:focus:ring-primary-100/20",
52-
),
53+
className: "border-secondary-300 dark:border-zinc-700",
54+
},
55+
{
56+
disabled: false,
57+
readonly: false,
58+
className:
59+
"focus:ring-primary-200 focus:border-primary-500 dark:focus:ring-primary-100/20 dark:focus:border-primary-400 focus:ring-2",
5360
},
5461
{
5562
variant: ["outline", "ghost"],
56-
invalid: false,
63+
disabled: false,
64+
readonly: false,
5765
className: "bg-transparent",
5866
},
67+
{
68+
variant: "ghost",
69+
className: "border-transparent",
70+
},
5971
],
6072
defaultVariants: {
6173
size: "md",
@@ -96,7 +108,12 @@ export const Textarea = forwardRef<HTMLTextAreaElement, Textarea>(
96108
},
97109
forwardedRef,
98110
) => {
99-
const context = useFieldControlContext() ?? {};
111+
const context = useFieldControlContext() ?? {
112+
isDisabled: false,
113+
isLoading: false,
114+
isReadOnly: false,
115+
isRequired: false,
116+
};
100117

101118
const name = props.name || context.name;
102119
const disabled =
@@ -125,6 +142,8 @@ export const Textarea = forwardRef<HTMLTextAreaElement, Textarea>(
125142
textareaClasses({
126143
size,
127144
variant,
145+
disabled,
146+
readonly,
128147
invalid,
129148
}),
130149
className,

0 commit comments

Comments
 (0)