react-smart-fields 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,6 +28,9 @@ yarn add react-smart-fields
28
28
  ## Quick Start
29
29
 
30
30
  ```tsx
31
+ // 1. Import the default styles once (e.g. in your root layout or App.tsx)
32
+ import 'react-smart-fields/styles.css';
33
+
31
34
  import { DynamicFields, FieldConfig } from "react-smart-fields";
32
35
 
33
36
  const fields: FieldConfig[] = [
package/dist/index.cjs CHANGED
@@ -113,88 +113,88 @@ var buildInitialValues = (fields, defaultValues, controlledValues) => {
113
113
  };
114
114
  var baseTheme = {
115
115
  default: {
116
- wrapper: "w-full max-w-2xl mx-auto p-6 bg-white dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800 shadow-sm",
117
- title: "text-2xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
118
- description: "text-sm text-zinc-500 dark:text-zinc-400",
119
- fieldsContainer: "space-y-4",
120
- field: "w-full space-y-2",
121
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
122
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
123
- control: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
124
- textarea: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 transition-colors min-h-[80px] resize-none",
125
- select: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
126
- option: "text-zinc-950 dark:text-zinc-50 bg-white dark:bg-zinc-950",
127
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-900 dark:border-zinc-50 bg-white dark:bg-zinc-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50",
128
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-900 dark:border-zinc-50 bg-white dark:bg-zinc-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50",
129
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
116
+ wrapper: "rsf-wrapper",
117
+ title: "rsf-title",
118
+ description: "rsf-description",
119
+ fieldsContainer: "rsf-fields-container",
120
+ field: "rsf-field",
121
+ label: "rsf-label",
122
+ help: "rsf-help",
123
+ control: "rsf-input",
124
+ textarea: "rsf-textarea",
125
+ select: "rsf-select",
126
+ option: "",
127
+ checkbox: "rsf-checkbox",
128
+ radio: "rsf-radio",
129
+ error: "rsf-error"
130
130
  },
131
131
  minimal: {
132
- wrapper: "w-full max-w-2xl mx-auto",
133
- title: "text-xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
134
- description: "text-sm text-zinc-500 dark:text-zinc-400",
135
- fieldsContainer: "space-y-4",
136
- field: "w-full space-y-2",
137
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
138
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
139
- control: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
140
- textarea: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors min-h-[80px] resize-none",
141
- select: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-transparent text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
142
- option: "text-zinc-950 dark:text-zinc-50",
143
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-200 dark:border-zinc-800 bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
144
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-200 dark:border-zinc-800 bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
145
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
132
+ wrapper: "rsf-wrapper rsf-wrapper--minimal",
133
+ title: "rsf-title",
134
+ description: "rsf-description",
135
+ fieldsContainer: "rsf-fields-container",
136
+ field: "rsf-field",
137
+ label: "rsf-label",
138
+ help: "rsf-help",
139
+ control: "rsf-input",
140
+ textarea: "rsf-textarea",
141
+ select: "rsf-select",
142
+ option: "",
143
+ checkbox: "rsf-checkbox",
144
+ radio: "rsf-radio",
145
+ error: "rsf-error"
146
146
  },
147
147
  filled: {
148
- wrapper: "w-full max-w-2xl mx-auto p-6 bg-zinc-50 dark:bg-zinc-900 rounded-lg border border-zinc-100 dark:border-zinc-800",
149
- title: "text-2xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
150
- description: "text-sm text-zinc-500 dark:text-zinc-400",
151
- fieldsContainer: "space-y-4",
152
- field: "w-full space-y-2",
153
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
154
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
155
- control: "w-full rounded-md border border-zinc-100 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-800 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
156
- textarea: "w-full rounded-md border border-zinc-100 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-800 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50 transition-colors min-h-[80px] resize-none",
157
- select: "w-full rounded-md border border-zinc-100 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-800 text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
158
- option: "text-zinc-950 dark:text-zinc-50 bg-white dark:bg-zinc-900",
159
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-200 dark:border-zinc-700 bg-zinc-100 dark:bg-zinc-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50",
160
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-100 dark:bg-zinc-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50",
161
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
148
+ wrapper: "rsf-wrapper rsf-wrapper--filled",
149
+ title: "rsf-title",
150
+ description: "rsf-description",
151
+ fieldsContainer: "rsf-fields-container",
152
+ field: "rsf-field",
153
+ label: "rsf-label",
154
+ help: "rsf-help",
155
+ control: "rsf-input",
156
+ textarea: "rsf-textarea",
157
+ select: "rsf-select",
158
+ option: "",
159
+ checkbox: "rsf-checkbox",
160
+ radio: "rsf-radio",
161
+ error: "rsf-error"
162
162
  },
163
163
  underline: {
164
- wrapper: "w-full max-w-2xl mx-auto py-4",
165
- title: "text-xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
166
- description: "text-sm text-zinc-500 dark:text-zinc-400",
167
- fieldsContainer: "space-y-4",
168
- field: "w-full space-y-2",
169
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
170
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
171
- control: "w-full border-0 border-b border-zinc-200 dark:border-zinc-700 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 rounded-none focus-visible:outline-none focus-visible:ring-0 focus-visible:border-zinc-950 dark:focus-visible:border-zinc-300 disabled:cursor-not-allowed disabled:opacity-50 transition-colors px-0",
172
- textarea: "w-full border-0 border-b border-zinc-200 dark:border-zinc-700 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 rounded-none focus-visible:outline-none focus-visible:ring-0 focus-visible:border-zinc-950 dark:focus-visible:border-zinc-300 disabled:cursor-not-allowed disabled:opacity-50 transition-colors px-0 min-h-[80px] resize-none",
173
- select: "w-full border-0 border-b border-zinc-200 dark:border-zinc-700 bg-transparent text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-0 focus-visible:border-zinc-950 dark:focus-visible:border-zinc-300 disabled:cursor-not-allowed disabled:opacity-50 transition-colors rounded-none px-0",
174
- option: "text-zinc-950 dark:text-zinc-50",
175
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-200 dark:border-zinc-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
176
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-200 dark:border-zinc-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
177
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
164
+ wrapper: "rsf-wrapper rsf-wrapper--underline",
165
+ title: "rsf-title",
166
+ description: "rsf-description",
167
+ fieldsContainer: "rsf-fields-container",
168
+ field: "rsf-field",
169
+ label: "rsf-label",
170
+ help: "rsf-help",
171
+ control: "rsf-input",
172
+ textarea: "rsf-textarea",
173
+ select: "rsf-select",
174
+ option: "",
175
+ checkbox: "rsf-checkbox",
176
+ radio: "rsf-radio",
177
+ error: "rsf-error"
178
178
  }
179
179
  };
180
180
  var sizeMap = {
181
181
  sm: {
182
- control: "px-3 py-1.5 text-xs",
183
- label: "text-xs",
184
- help: "text-[0.7rem]",
185
- error: "text-xs"
182
+ control: "rsf-input--sm",
183
+ label: "",
184
+ help: "",
185
+ error: ""
186
186
  },
187
187
  md: {
188
- control: "px-3 py-2 text-sm",
189
- label: "text-sm",
190
- help: "text-[0.8rem]",
191
- error: "text-[0.8rem]"
188
+ control: "",
189
+ label: "",
190
+ help: "",
191
+ error: ""
192
192
  },
193
193
  lg: {
194
- control: "px-4 py-2.5 text-base",
195
- label: "text-base",
196
- help: "text-sm",
197
- error: "text-sm"
194
+ control: "rsf-input--lg",
195
+ label: "",
196
+ help: "",
197
+ error: ""
198
198
  }
199
199
  };
200
200
  var DynamicFields = ({
@@ -417,7 +417,7 @@ var DynamicFields = ({
417
417
  error: cn(defaultUi.error, sizeClasses.error, errorClassName, field?.errorClassName, ui?.error, field?.ui?.error)
418
418
  });
419
419
  const buildStateClassName = (field, hasError, disabled, readOnly) => cn(
420
- hasError && (stateClassNames?.invalid ?? "border-red-500 dark:border-red-500 focus-visible:ring-red-500 dark:focus-visible:ring-red-500"),
420
+ hasError && (stateClassNames?.invalid ?? "rsf-input--invalid"),
421
421
  disabled && stateClassNames?.disabled,
422
422
  readOnly && stateClassNames?.readonly,
423
423
  dirtyMap[field.name] && stateClassNames?.dirty,
@@ -478,12 +478,12 @@ var DynamicFields = ({
478
478
  );
479
479
  }
480
480
  if (field.type === "radio") {
481
- return /* @__PURE__ */ import_react.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" }, options.map((option) => /* @__PURE__ */ import_react.default.createElement(
481
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "rsf-radio-group" }, options.map((option) => /* @__PURE__ */ import_react.default.createElement(
482
482
  "label",
483
483
  {
484
484
  key: `${field.name}-${String(option.value)}`,
485
485
  htmlFor: `${field.name}-${String(option.value)}`,
486
- className: "flex items-center gap-2 cursor-pointer select-none"
486
+ className: "rsf-radio-item"
487
487
  },
488
488
  /* @__PURE__ */ import_react.default.createElement(
489
489
  "input",
@@ -500,7 +500,7 @@ var DynamicFields = ({
500
500
  className: cn(classes.radio, controlStateClass)
501
501
  }
502
502
  ),
503
- /* @__PURE__ */ import_react.default.createElement("span", { className: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-70" }, option.label)
503
+ /* @__PURE__ */ import_react.default.createElement("span", { className: "rsf-radio-label" }, option.label)
504
504
  )));
505
505
  }
506
506
  if (field.type === "checkbox") {
@@ -542,7 +542,7 @@ var DynamicFields = ({
542
542
  }
543
543
  );
544
544
  };
545
- return /* @__PURE__ */ import_react.default.createElement("div", { className: resolveUi().wrapper }, title && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col space-y-1.5 pb-6 mb-6 border-b border-zinc-200 dark:border-zinc-800" }, /* @__PURE__ */ import_react.default.createElement("h2", { className: resolveUi().title }, title), description && /* @__PURE__ */ import_react.default.createElement("p", { className: resolveUi().description }, description)), /* @__PURE__ */ import_react.default.createElement("div", { className: resolveUi().fieldsContainer }, visibleFields.map((field) => {
545
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: resolveUi().wrapper }, title && /* @__PURE__ */ import_react.default.createElement("div", { className: "rsf-header" }, /* @__PURE__ */ import_react.default.createElement("h2", { className: resolveUi().title }, title), description && /* @__PURE__ */ import_react.default.createElement("p", { className: resolveUi().description }, description)), /* @__PURE__ */ import_react.default.createElement("div", { className: resolveUi().fieldsContainer }, visibleFields.map((field) => {
546
546
  const classes = resolveUi(field);
547
547
  const storedValue = getIn(values, field.name);
548
548
  const renderedValue = field.transformIn ? field.transformIn(storedValue, values) : storedValue;
@@ -570,7 +570,7 @@ var DynamicFields = ({
570
570
  handleBlur: () => handleFieldBlur(field)
571
571
  };
572
572
  const requiredMark = field.required || field.requiredWhen?.(values);
573
- const labelNode = field.type === "checkbox" ? null : renderLabel ? renderLabel(context) : field.label ? /* @__PURE__ */ import_react.default.createElement("label", { htmlFor: field.name, className: classes.label }, field.label, requiredMark && /* @__PURE__ */ import_react.default.createElement("span", { className: "text-red-500 ml-1" }, "*")) : null;
573
+ const labelNode = field.type === "checkbox" ? null : renderLabel ? renderLabel(context) : field.label ? /* @__PURE__ */ import_react.default.createElement("label", { htmlFor: field.name, className: classes.label }, field.label, requiredMark && /* @__PURE__ */ import_react.default.createElement("span", { className: "rsf-required-mark" }, "*")) : null;
574
574
  const helpNode = renderDescription ? renderDescription(context) : field.description ? /* @__PURE__ */ import_react.default.createElement("p", { className: classes.help }, field.description) : null;
575
575
  const errorNode = canShowError ? renderError ? renderError(context) : /* @__PURE__ */ import_react.default.createElement("p", { className: classes.error, role: "alert" }, error) : null;
576
576
  const controlNode = field.renderControl?.(context) ?? renderControl?.(context) ?? renderDefaultControl(context);
@@ -584,7 +584,7 @@ var DynamicFields = ({
584
584
  }));
585
585
  }
586
586
  if (field.type === "checkbox") {
587
- return /* @__PURE__ */ import_react.default.createElement("div", { key: field.name, className: classes.field }, /* @__PURE__ */ import_react.default.createElement("label", { htmlFor: field.name, className: "inline-flex items-start gap-2 cursor-pointer select-none" }, controlNode, /* @__PURE__ */ import_react.default.createElement("span", { className: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-70" }, field.label, requiredMark && /* @__PURE__ */ import_react.default.createElement("span", { className: "text-red-500 ml-1" }, "*"))), helpNode, errorNode);
587
+ return /* @__PURE__ */ import_react.default.createElement("div", { key: field.name, className: classes.field }, /* @__PURE__ */ import_react.default.createElement("label", { htmlFor: field.name, className: "rsf-checkbox-item" }, controlNode, /* @__PURE__ */ import_react.default.createElement("span", { className: "rsf-checkbox-label" }, field.label, requiredMark && /* @__PURE__ */ import_react.default.createElement("span", { className: "rsf-required-mark" }, "*"))), helpNode, errorNode);
588
588
  }
589
589
  return /* @__PURE__ */ import_react.default.createElement("div", { key: field.name, className: classes.field }, labelNode, helpNode, controlNode, errorNode);
590
590
  })));
package/dist/index.js CHANGED
@@ -77,88 +77,88 @@ var buildInitialValues = (fields, defaultValues, controlledValues) => {
77
77
  };
78
78
  var baseTheme = {
79
79
  default: {
80
- wrapper: "w-full max-w-2xl mx-auto p-6 bg-white dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800 shadow-sm",
81
- title: "text-2xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
82
- description: "text-sm text-zinc-500 dark:text-zinc-400",
83
- fieldsContainer: "space-y-4",
84
- field: "w-full space-y-2",
85
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
86
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
87
- control: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
88
- textarea: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 transition-colors min-h-[80px] resize-none",
89
- select: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
90
- option: "text-zinc-950 dark:text-zinc-50 bg-white dark:bg-zinc-950",
91
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-900 dark:border-zinc-50 bg-white dark:bg-zinc-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50",
92
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-900 dark:border-zinc-50 bg-white dark:bg-zinc-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-white dark:ring-offset-zinc-950 disabled:cursor-not-allowed disabled:opacity-50",
93
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
80
+ wrapper: "rsf-wrapper",
81
+ title: "rsf-title",
82
+ description: "rsf-description",
83
+ fieldsContainer: "rsf-fields-container",
84
+ field: "rsf-field",
85
+ label: "rsf-label",
86
+ help: "rsf-help",
87
+ control: "rsf-input",
88
+ textarea: "rsf-textarea",
89
+ select: "rsf-select",
90
+ option: "",
91
+ checkbox: "rsf-checkbox",
92
+ radio: "rsf-radio",
93
+ error: "rsf-error"
94
94
  },
95
95
  minimal: {
96
- wrapper: "w-full max-w-2xl mx-auto",
97
- title: "text-xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
98
- description: "text-sm text-zinc-500 dark:text-zinc-400",
99
- fieldsContainer: "space-y-4",
100
- field: "w-full space-y-2",
101
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
102
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
103
- control: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
104
- textarea: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors min-h-[80px] resize-none",
105
- select: "w-full rounded-md border border-zinc-200 dark:border-zinc-800 bg-transparent text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
106
- option: "text-zinc-950 dark:text-zinc-50",
107
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-200 dark:border-zinc-800 bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
108
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-200 dark:border-zinc-800 bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
109
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
96
+ wrapper: "rsf-wrapper rsf-wrapper--minimal",
97
+ title: "rsf-title",
98
+ description: "rsf-description",
99
+ fieldsContainer: "rsf-fields-container",
100
+ field: "rsf-field",
101
+ label: "rsf-label",
102
+ help: "rsf-help",
103
+ control: "rsf-input",
104
+ textarea: "rsf-textarea",
105
+ select: "rsf-select",
106
+ option: "",
107
+ checkbox: "rsf-checkbox",
108
+ radio: "rsf-radio",
109
+ error: "rsf-error"
110
110
  },
111
111
  filled: {
112
- wrapper: "w-full max-w-2xl mx-auto p-6 bg-zinc-50 dark:bg-zinc-900 rounded-lg border border-zinc-100 dark:border-zinc-800",
113
- title: "text-2xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
114
- description: "text-sm text-zinc-500 dark:text-zinc-400",
115
- fieldsContainer: "space-y-4",
116
- field: "w-full space-y-2",
117
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
118
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
119
- control: "w-full rounded-md border border-zinc-100 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-800 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
120
- textarea: "w-full rounded-md border border-zinc-100 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-800 text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50 transition-colors min-h-[80px] resize-none",
121
- select: "w-full rounded-md border border-zinc-100 dark:border-zinc-800 bg-zinc-100 dark:bg-zinc-800 text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50 transition-colors",
122
- option: "text-zinc-950 dark:text-zinc-50 bg-white dark:bg-zinc-900",
123
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-200 dark:border-zinc-700 bg-zinc-100 dark:bg-zinc-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50",
124
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-100 dark:bg-zinc-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ring-offset-zinc-50 dark:ring-offset-zinc-900 disabled:cursor-not-allowed disabled:opacity-50",
125
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
112
+ wrapper: "rsf-wrapper rsf-wrapper--filled",
113
+ title: "rsf-title",
114
+ description: "rsf-description",
115
+ fieldsContainer: "rsf-fields-container",
116
+ field: "rsf-field",
117
+ label: "rsf-label",
118
+ help: "rsf-help",
119
+ control: "rsf-input",
120
+ textarea: "rsf-textarea",
121
+ select: "rsf-select",
122
+ option: "",
123
+ checkbox: "rsf-checkbox",
124
+ radio: "rsf-radio",
125
+ error: "rsf-error"
126
126
  },
127
127
  underline: {
128
- wrapper: "w-full max-w-2xl mx-auto py-4",
129
- title: "text-xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50",
130
- description: "text-sm text-zinc-500 dark:text-zinc-400",
131
- fieldsContainer: "space-y-4",
132
- field: "w-full space-y-2",
133
- label: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50",
134
- help: "text-[0.8rem] text-zinc-500 dark:text-zinc-400",
135
- control: "w-full border-0 border-b border-zinc-200 dark:border-zinc-700 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 rounded-none focus-visible:outline-none focus-visible:ring-0 focus-visible:border-zinc-950 dark:focus-visible:border-zinc-300 disabled:cursor-not-allowed disabled:opacity-50 transition-colors px-0",
136
- textarea: "w-full border-0 border-b border-zinc-200 dark:border-zinc-700 bg-transparent text-zinc-950 dark:text-zinc-50 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 rounded-none focus-visible:outline-none focus-visible:ring-0 focus-visible:border-zinc-950 dark:focus-visible:border-zinc-300 disabled:cursor-not-allowed disabled:opacity-50 transition-colors px-0 min-h-[80px] resize-none",
137
- select: "w-full border-0 border-b border-zinc-200 dark:border-zinc-700 bg-transparent text-zinc-950 dark:text-zinc-50 focus-visible:outline-none focus-visible:ring-0 focus-visible:border-zinc-950 dark:focus-visible:border-zinc-300 disabled:cursor-not-allowed disabled:opacity-50 transition-colors rounded-none px-0",
138
- option: "text-zinc-950 dark:text-zinc-50",
139
- checkbox: "h-4 w-4 shrink-0 rounded-sm border border-zinc-200 dark:border-zinc-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
140
- radio: "h-4 w-4 shrink-0 rounded-full border border-zinc-200 dark:border-zinc-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 dark:focus-visible:ring-zinc-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
141
- error: "text-[0.8rem] font-medium text-red-500 dark:text-red-400"
128
+ wrapper: "rsf-wrapper rsf-wrapper--underline",
129
+ title: "rsf-title",
130
+ description: "rsf-description",
131
+ fieldsContainer: "rsf-fields-container",
132
+ field: "rsf-field",
133
+ label: "rsf-label",
134
+ help: "rsf-help",
135
+ control: "rsf-input",
136
+ textarea: "rsf-textarea",
137
+ select: "rsf-select",
138
+ option: "",
139
+ checkbox: "rsf-checkbox",
140
+ radio: "rsf-radio",
141
+ error: "rsf-error"
142
142
  }
143
143
  };
144
144
  var sizeMap = {
145
145
  sm: {
146
- control: "px-3 py-1.5 text-xs",
147
- label: "text-xs",
148
- help: "text-[0.7rem]",
149
- error: "text-xs"
146
+ control: "rsf-input--sm",
147
+ label: "",
148
+ help: "",
149
+ error: ""
150
150
  },
151
151
  md: {
152
- control: "px-3 py-2 text-sm",
153
- label: "text-sm",
154
- help: "text-[0.8rem]",
155
- error: "text-[0.8rem]"
152
+ control: "",
153
+ label: "",
154
+ help: "",
155
+ error: ""
156
156
  },
157
157
  lg: {
158
- control: "px-4 py-2.5 text-base",
159
- label: "text-base",
160
- help: "text-sm",
161
- error: "text-sm"
158
+ control: "rsf-input--lg",
159
+ label: "",
160
+ help: "",
161
+ error: ""
162
162
  }
163
163
  };
164
164
  var DynamicFields = ({
@@ -381,7 +381,7 @@ var DynamicFields = ({
381
381
  error: cn(defaultUi.error, sizeClasses.error, errorClassName, field?.errorClassName, ui?.error, field?.ui?.error)
382
382
  });
383
383
  const buildStateClassName = (field, hasError, disabled, readOnly) => cn(
384
- hasError && (stateClassNames?.invalid ?? "border-red-500 dark:border-red-500 focus-visible:ring-red-500 dark:focus-visible:ring-red-500"),
384
+ hasError && (stateClassNames?.invalid ?? "rsf-input--invalid"),
385
385
  disabled && stateClassNames?.disabled,
386
386
  readOnly && stateClassNames?.readonly,
387
387
  dirtyMap[field.name] && stateClassNames?.dirty,
@@ -442,12 +442,12 @@ var DynamicFields = ({
442
442
  );
443
443
  }
444
444
  if (field.type === "radio") {
445
- return /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" }, options.map((option) => /* @__PURE__ */ React.createElement(
445
+ return /* @__PURE__ */ React.createElement("div", { className: "rsf-radio-group" }, options.map((option) => /* @__PURE__ */ React.createElement(
446
446
  "label",
447
447
  {
448
448
  key: `${field.name}-${String(option.value)}`,
449
449
  htmlFor: `${field.name}-${String(option.value)}`,
450
- className: "flex items-center gap-2 cursor-pointer select-none"
450
+ className: "rsf-radio-item"
451
451
  },
452
452
  /* @__PURE__ */ React.createElement(
453
453
  "input",
@@ -464,7 +464,7 @@ var DynamicFields = ({
464
464
  className: cn(classes.radio, controlStateClass)
465
465
  }
466
466
  ),
467
- /* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-70" }, option.label)
467
+ /* @__PURE__ */ React.createElement("span", { className: "rsf-radio-label" }, option.label)
468
468
  )));
469
469
  }
470
470
  if (field.type === "checkbox") {
@@ -506,7 +506,7 @@ var DynamicFields = ({
506
506
  }
507
507
  );
508
508
  };
509
- return /* @__PURE__ */ React.createElement("div", { className: resolveUi().wrapper }, title && /* @__PURE__ */ React.createElement("div", { className: "flex flex-col space-y-1.5 pb-6 mb-6 border-b border-zinc-200 dark:border-zinc-800" }, /* @__PURE__ */ React.createElement("h2", { className: resolveUi().title }, title), description && /* @__PURE__ */ React.createElement("p", { className: resolveUi().description }, description)), /* @__PURE__ */ React.createElement("div", { className: resolveUi().fieldsContainer }, visibleFields.map((field) => {
509
+ return /* @__PURE__ */ React.createElement("div", { className: resolveUi().wrapper }, title && /* @__PURE__ */ React.createElement("div", { className: "rsf-header" }, /* @__PURE__ */ React.createElement("h2", { className: resolveUi().title }, title), description && /* @__PURE__ */ React.createElement("p", { className: resolveUi().description }, description)), /* @__PURE__ */ React.createElement("div", { className: resolveUi().fieldsContainer }, visibleFields.map((field) => {
510
510
  const classes = resolveUi(field);
511
511
  const storedValue = getIn(values, field.name);
512
512
  const renderedValue = field.transformIn ? field.transformIn(storedValue, values) : storedValue;
@@ -534,7 +534,7 @@ var DynamicFields = ({
534
534
  handleBlur: () => handleFieldBlur(field)
535
535
  };
536
536
  const requiredMark = field.required || field.requiredWhen?.(values);
537
- const labelNode = field.type === "checkbox" ? null : renderLabel ? renderLabel(context) : field.label ? /* @__PURE__ */ React.createElement("label", { htmlFor: field.name, className: classes.label }, field.label, requiredMark && /* @__PURE__ */ React.createElement("span", { className: "text-red-500 ml-1" }, "*")) : null;
537
+ const labelNode = field.type === "checkbox" ? null : renderLabel ? renderLabel(context) : field.label ? /* @__PURE__ */ React.createElement("label", { htmlFor: field.name, className: classes.label }, field.label, requiredMark && /* @__PURE__ */ React.createElement("span", { className: "rsf-required-mark" }, "*")) : null;
538
538
  const helpNode = renderDescription ? renderDescription(context) : field.description ? /* @__PURE__ */ React.createElement("p", { className: classes.help }, field.description) : null;
539
539
  const errorNode = canShowError ? renderError ? renderError(context) : /* @__PURE__ */ React.createElement("p", { className: classes.error, role: "alert" }, error) : null;
540
540
  const controlNode = field.renderControl?.(context) ?? renderControl?.(context) ?? renderDefaultControl(context);
@@ -548,7 +548,7 @@ var DynamicFields = ({
548
548
  }));
549
549
  }
550
550
  if (field.type === "checkbox") {
551
- return /* @__PURE__ */ React.createElement("div", { key: field.name, className: classes.field }, /* @__PURE__ */ React.createElement("label", { htmlFor: field.name, className: "inline-flex items-start gap-2 cursor-pointer select-none" }, controlNode, /* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium leading-none text-zinc-950 dark:text-zinc-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-70" }, field.label, requiredMark && /* @__PURE__ */ React.createElement("span", { className: "text-red-500 ml-1" }, "*"))), helpNode, errorNode);
551
+ return /* @__PURE__ */ React.createElement("div", { key: field.name, className: classes.field }, /* @__PURE__ */ React.createElement("label", { htmlFor: field.name, className: "rsf-checkbox-item" }, controlNode, /* @__PURE__ */ React.createElement("span", { className: "rsf-checkbox-label" }, field.label, requiredMark && /* @__PURE__ */ React.createElement("span", { className: "rsf-required-mark" }, "*"))), helpNode, errorNode);
552
552
  }
553
553
  return /* @__PURE__ */ React.createElement("div", { key: field.name, className: classes.field }, labelNode, helpNode, controlNode, errorNode);
554
554
  })));
@@ -0,0 +1,468 @@
1
+ /* src/styles.css */
2
+ .rsf-wrapper *,
3
+ .rsf-wrapper *::before,
4
+ .rsf-wrapper *::after {
5
+ box-sizing: border-box;
6
+ }
7
+ .rsf-wrapper {
8
+ font-family: var(--font-sans, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif);
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ color: var(--foreground, hsl(240 10% 3.9%));
12
+ background-color: var(--card, hsl(0 0% 100%));
13
+ border-radius: var(--radius, 0.5rem);
14
+ border: 1px solid var(--border, hsl(240 5.9% 90%));
15
+ box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.07), 0 1px 2px -1px rgb(0 0 0 / 0.07);
16
+ padding: 1.5rem;
17
+ width: 100%;
18
+ max-width: 42rem;
19
+ margin-left: auto;
20
+ margin-right: auto;
21
+ }
22
+ .rsf-header {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 0.375rem;
26
+ padding-bottom: 1.5rem;
27
+ margin-bottom: 1.5rem;
28
+ border-bottom: 1px solid var(--border, hsl(240 5.9% 90%));
29
+ }
30
+ .rsf-title {
31
+ font-size: 1.5rem;
32
+ font-weight: 600;
33
+ line-height: 1;
34
+ letter-spacing: -0.025em;
35
+ color: var(--card-foreground, hsl(240 10% 3.9%));
36
+ }
37
+ .rsf-description {
38
+ font-size: 0.875rem;
39
+ color: var(--muted-foreground, hsl(240 3.8% 46.1%));
40
+ line-height: 1.5;
41
+ }
42
+ .rsf-fields-container {
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: 1rem;
46
+ }
47
+ .rsf-field {
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: 0.5rem;
51
+ width: 100%;
52
+ }
53
+ .rsf-label {
54
+ font-size: 0.875rem;
55
+ font-weight: 500;
56
+ line-height: 1;
57
+ color: var(--foreground, hsl(240 10% 3.9%));
58
+ cursor: default;
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 0;
62
+ }
63
+ .rsf-label[data-disabled=true] {
64
+ cursor: not-allowed;
65
+ opacity: 0.7;
66
+ }
67
+ .rsf-required-mark {
68
+ color: var(--destructive, hsl(0 84.2% 60.2%));
69
+ margin-left: 0.25rem;
70
+ }
71
+ .rsf-help {
72
+ font-size: 0.8rem;
73
+ color: var(--muted-foreground, hsl(240 3.8% 46.1%));
74
+ line-height: 1.5;
75
+ }
76
+ .rsf-error {
77
+ font-size: 0.8rem;
78
+ font-weight: 500;
79
+ color: var(--destructive, hsl(0 84.2% 60.2%));
80
+ line-height: 1.25;
81
+ }
82
+ .rsf-input {
83
+ display: flex;
84
+ height: 2.5rem;
85
+ width: 100%;
86
+ border-radius: calc(var(--radius, 0.5rem) - 2px);
87
+ border: 1px solid var(--input, hsl(240 5.9% 90%));
88
+ background-color: var(--background, hsl(0 0% 100%));
89
+ padding: 0.5rem 0.75rem;
90
+ font-size: 0.875rem;
91
+ font-family: inherit;
92
+ color: var(--foreground, hsl(240 10% 3.9%));
93
+ line-height: 1.25;
94
+ transition: border-color 150ms ease, box-shadow 150ms ease;
95
+ outline: none;
96
+ -webkit-appearance: none;
97
+ appearance: none;
98
+ }
99
+ .rsf-input::placeholder {
100
+ color: var(--muted-foreground, hsl(240 3.8% 46.1%));
101
+ }
102
+ .rsf-input:focus-visible {
103
+ outline: none;
104
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--ring, hsl(240 10% 3.9%));
105
+ }
106
+ .rsf-input:disabled {
107
+ cursor: not-allowed;
108
+ opacity: 0.5;
109
+ background-color: var(--muted, hsl(240 4.8% 95.9%));
110
+ }
111
+ .rsf-input[readonly] {
112
+ cursor: default;
113
+ background-color: var(--muted, hsl(240 4.8% 95.9%));
114
+ }
115
+ .rsf-input--invalid {
116
+ border-color: var(--destructive, hsl(0 84.2% 60.2%));
117
+ }
118
+ .rsf-input--invalid:focus-visible {
119
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--destructive, hsl(0 84.2% 60.2%));
120
+ }
121
+ .rsf-input--sm {
122
+ height: 2rem;
123
+ padding: 0.375rem 0.625rem;
124
+ font-size: 0.75rem;
125
+ }
126
+ .rsf-input--lg {
127
+ height: 2.75rem;
128
+ padding: 0.625rem 1rem;
129
+ font-size: 1rem;
130
+ }
131
+ .rsf-textarea {
132
+ display: flex;
133
+ min-height: 5rem;
134
+ width: 100%;
135
+ border-radius: calc(var(--radius, 0.5rem) - 2px);
136
+ border: 1px solid var(--input, hsl(240 5.9% 90%));
137
+ background-color: var(--background, hsl(0 0% 100%));
138
+ padding: 0.5rem 0.75rem;
139
+ font-size: 0.875rem;
140
+ font-family: inherit;
141
+ color: var(--foreground, hsl(240 10% 3.9%));
142
+ line-height: 1.5;
143
+ transition: border-color 150ms ease, box-shadow 150ms ease;
144
+ outline: none;
145
+ resize: none;
146
+ }
147
+ .rsf-textarea::placeholder {
148
+ color: var(--muted-foreground, hsl(240 3.8% 46.1%));
149
+ }
150
+ .rsf-textarea:focus-visible {
151
+ outline: none;
152
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--ring, hsl(240 10% 3.9%));
153
+ }
154
+ .rsf-textarea:disabled {
155
+ cursor: not-allowed;
156
+ opacity: 0.5;
157
+ }
158
+ .rsf-textarea--invalid {
159
+ border-color: var(--destructive, hsl(0 84.2% 60.2%));
160
+ }
161
+ .rsf-textarea--invalid:focus-visible {
162
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--destructive, hsl(0 84.2% 60.2%));
163
+ }
164
+ .rsf-select {
165
+ display: flex;
166
+ height: 2.5rem;
167
+ width: 100%;
168
+ border-radius: calc(var(--radius, 0.5rem) - 2px);
169
+ border: 1px solid var(--input, hsl(240 5.9% 90%));
170
+ background-color: var(--background, hsl(0 0% 100%));
171
+ padding: 0 0.75rem;
172
+ padding-right: 2rem;
173
+ font-size: 0.875rem;
174
+ font-family: inherit;
175
+ color: var(--foreground, hsl(240 10% 3.9%));
176
+ line-height: 1.25;
177
+ cursor: pointer;
178
+ transition: border-color 150ms ease, box-shadow 150ms ease;
179
+ outline: none;
180
+ -webkit-appearance: none;
181
+ appearance: none;
182
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
183
+ background-repeat: no-repeat;
184
+ background-position: right 0.625rem center;
185
+ background-size: 1rem;
186
+ }
187
+ .rsf-select:focus-visible {
188
+ outline: none;
189
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--ring, hsl(240 10% 3.9%));
190
+ }
191
+ .rsf-select:disabled {
192
+ cursor: not-allowed;
193
+ opacity: 0.5;
194
+ }
195
+ .rsf-select--invalid {
196
+ border-color: var(--destructive, hsl(0 84.2% 60.2%));
197
+ }
198
+ .rsf-select--invalid:focus-visible {
199
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--destructive, hsl(0 84.2% 60.2%));
200
+ }
201
+ .rsf-select--sm {
202
+ height: 2rem;
203
+ font-size: 0.75rem;
204
+ }
205
+ .rsf-select--lg {
206
+ height: 2.75rem;
207
+ font-size: 1rem;
208
+ }
209
+ .rsf-radio-group {
210
+ display: flex;
211
+ flex-direction: column;
212
+ gap: 0.625rem;
213
+ }
214
+ .rsf-radio-item {
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 0.5rem;
218
+ cursor: pointer;
219
+ user-select: none;
220
+ }
221
+ .rsf-radio-item:has(input:disabled) {
222
+ cursor: not-allowed;
223
+ opacity: 0.5;
224
+ }
225
+ .rsf-radio {
226
+ width: 1rem;
227
+ height: 1rem;
228
+ border-radius: 9999px;
229
+ border: 1px solid var(--primary, hsl(240 5.9% 10%));
230
+ background-color: var(--background, hsl(0 0% 100%));
231
+ flex-shrink: 0;
232
+ cursor: pointer;
233
+ transition: border-color 150ms ease, box-shadow 150ms ease;
234
+ outline: none;
235
+ -webkit-appearance: none;
236
+ appearance: none;
237
+ position: relative;
238
+ }
239
+ .rsf-radio:checked {
240
+ background-color: var(--primary, hsl(240 5.9% 10%));
241
+ border-color: var(--primary, hsl(240 5.9% 10%));
242
+ }
243
+ .rsf-radio:checked::after {
244
+ content: "";
245
+ position: absolute;
246
+ top: 50%;
247
+ left: 50%;
248
+ transform: translate(-50%, -50%);
249
+ width: 0.375rem;
250
+ height: 0.375rem;
251
+ border-radius: 9999px;
252
+ background-color: var(--primary-foreground, hsl(0 0% 98%));
253
+ }
254
+ .rsf-radio:focus-visible {
255
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--ring, hsl(240 10% 3.9%));
256
+ }
257
+ .rsf-radio:disabled {
258
+ cursor: not-allowed;
259
+ opacity: 0.5;
260
+ }
261
+ .rsf-radio-label {
262
+ font-size: 0.875rem;
263
+ font-weight: 500;
264
+ line-height: 1;
265
+ color: var(--foreground, hsl(240 10% 3.9%));
266
+ }
267
+ .rsf-checkbox-item {
268
+ display: flex;
269
+ align-items: flex-start;
270
+ gap: 0.625rem;
271
+ cursor: pointer;
272
+ user-select: none;
273
+ }
274
+ .rsf-checkbox-item:has(input:disabled) {
275
+ cursor: not-allowed;
276
+ opacity: 0.5;
277
+ }
278
+ .rsf-checkbox {
279
+ width: 1rem;
280
+ height: 1rem;
281
+ flex-shrink: 0;
282
+ border-radius: 0.2rem;
283
+ border: 1px solid var(--primary, hsl(240 5.9% 10%));
284
+ background-color: var(--background, hsl(0 0% 100%));
285
+ cursor: pointer;
286
+ transition:
287
+ border-color 150ms ease,
288
+ background-color 150ms ease,
289
+ box-shadow 150ms ease;
290
+ outline: none;
291
+ -webkit-appearance: none;
292
+ appearance: none;
293
+ position: relative;
294
+ margin-top: 0.0625rem;
295
+ }
296
+ .rsf-checkbox:checked {
297
+ background-color: var(--primary, hsl(240 5.9% 10%));
298
+ border-color: var(--primary, hsl(240 5.9% 10%));
299
+ }
300
+ .rsf-checkbox:checked::after {
301
+ content: "";
302
+ position: absolute;
303
+ top: 50%;
304
+ left: 50%;
305
+ transform: translate(-50%, -55%) rotate(45deg);
306
+ width: 0.3rem;
307
+ height: 0.55rem;
308
+ border: 2px solid var(--primary-foreground, hsl(0 0% 98%));
309
+ border-top: none;
310
+ border-left: none;
311
+ }
312
+ .rsf-checkbox:focus-visible {
313
+ box-shadow: 0 0 0 2px var(--background, hsl(0 0% 100%)), 0 0 0 4px var(--ring, hsl(240 10% 3.9%));
314
+ }
315
+ .rsf-checkbox:disabled {
316
+ cursor: not-allowed;
317
+ opacity: 0.5;
318
+ }
319
+ .rsf-checkbox-label {
320
+ font-size: 0.875rem;
321
+ font-weight: 500;
322
+ line-height: 1.25;
323
+ color: var(--foreground, hsl(240 10% 3.9%));
324
+ }
325
+ @media (prefers-color-scheme: dark) {
326
+ .rsf-wrapper {
327
+ color: var(--foreground, hsl(0 0% 98%));
328
+ background-color: var(--card, hsl(240 10% 3.9%));
329
+ border-color: var(--border, hsl(240 3.7% 15.9%));
330
+ }
331
+ .rsf-header {
332
+ border-bottom-color: var(--border, hsl(240 3.7% 15.9%));
333
+ }
334
+ .rsf-title {
335
+ color: var(--card-foreground, hsl(0 0% 98%));
336
+ }
337
+ .rsf-description,
338
+ .rsf-help {
339
+ color: var(--muted-foreground, hsl(240 5% 64.9%));
340
+ }
341
+ .rsf-label,
342
+ .rsf-radio-label,
343
+ .rsf-checkbox-label {
344
+ color: var(--foreground, hsl(0 0% 98%));
345
+ }
346
+ .rsf-input,
347
+ .rsf-textarea,
348
+ .rsf-select {
349
+ background-color: var(--background, hsl(240 10% 3.9%));
350
+ border-color: var(--input, hsl(240 3.7% 15.9%));
351
+ color: var(--foreground, hsl(0 0% 98%));
352
+ }
353
+ .rsf-input::placeholder,
354
+ .rsf-textarea::placeholder {
355
+ color: var(--muted-foreground, hsl(240 5% 64.9%));
356
+ }
357
+ .rsf-input:focus-visible,
358
+ .rsf-textarea:focus-visible,
359
+ .rsf-select:focus-visible,
360
+ .rsf-radio:focus-visible,
361
+ .rsf-checkbox:focus-visible {
362
+ box-shadow: 0 0 0 2px var(--background, hsl(240 10% 3.9%)), 0 0 0 4px var(--ring, hsl(240 4.9% 83.9%));
363
+ }
364
+ .rsf-input:disabled,
365
+ .rsf-textarea:disabled,
366
+ .rsf-select:disabled {
367
+ background-color: var(--muted, hsl(240 3.7% 15.9%));
368
+ }
369
+ .rsf-radio {
370
+ border-color: var(--primary, hsl(0 0% 98%));
371
+ background-color: var(--background, hsl(240 10% 3.9%));
372
+ }
373
+ .rsf-radio:checked {
374
+ background-color: var(--primary, hsl(0 0% 98%));
375
+ border-color: var(--primary, hsl(0 0% 98%));
376
+ }
377
+ .rsf-radio:checked::after {
378
+ background-color: var(--primary-foreground, hsl(240 5.9% 10%));
379
+ }
380
+ .rsf-checkbox {
381
+ border-color: var(--primary, hsl(0 0% 98%));
382
+ background-color: var(--background, hsl(240 10% 3.9%));
383
+ }
384
+ .rsf-checkbox:checked {
385
+ background-color: var(--primary, hsl(0 0% 98%));
386
+ border-color: var(--primary, hsl(0 0% 98%));
387
+ }
388
+ .rsf-checkbox:checked::after {
389
+ border-color: var(--primary-foreground, hsl(240 5.9% 10%));
390
+ }
391
+ .rsf-select {
392
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
393
+ }
394
+ }
395
+ .rsf-wrapper--minimal {
396
+ background-color: transparent;
397
+ border: none;
398
+ box-shadow: none;
399
+ padding: 0;
400
+ border-radius: 0;
401
+ }
402
+ .rsf-wrapper--minimal .rsf-header {
403
+ border-bottom: none;
404
+ padding-bottom: 0.75rem;
405
+ margin-bottom: 0.75rem;
406
+ }
407
+ .rsf-wrapper--filled {
408
+ background-color: var(--muted, hsl(240 4.8% 95.9%));
409
+ border-color: transparent;
410
+ }
411
+ .rsf-wrapper--filled .rsf-input,
412
+ .rsf-wrapper--filled .rsf-textarea,
413
+ .rsf-wrapper--filled .rsf-select {
414
+ background-color: var(--background, hsl(0 0% 100%));
415
+ border-color: transparent;
416
+ }
417
+ @media (prefers-color-scheme: dark) {
418
+ .rsf-wrapper--filled {
419
+ background-color: var(--muted, hsl(240 3.7% 15.9%));
420
+ }
421
+ .rsf-wrapper--filled .rsf-input,
422
+ .rsf-wrapper--filled .rsf-textarea,
423
+ .rsf-wrapper--filled .rsf-select {
424
+ background-color: var(--card, hsl(240 10% 3.9%));
425
+ }
426
+ }
427
+ .rsf-wrapper--underline {
428
+ background-color: transparent;
429
+ border: none;
430
+ box-shadow: none;
431
+ padding-left: 0;
432
+ padding-right: 0;
433
+ border-radius: 0;
434
+ max-width: 42rem;
435
+ }
436
+ .rsf-wrapper--underline .rsf-input,
437
+ .rsf-wrapper--underline .rsf-textarea,
438
+ .rsf-wrapper--underline .rsf-select {
439
+ border-radius: 0;
440
+ border: none;
441
+ border-bottom: 1px solid var(--input, hsl(240 5.9% 90%));
442
+ background-color: transparent;
443
+ padding-left: 0;
444
+ padding-right: 0;
445
+ }
446
+ .rsf-wrapper--underline .rsf-input:focus-visible,
447
+ .rsf-wrapper--underline .rsf-textarea:focus-visible,
448
+ .rsf-wrapper--underline .rsf-select:focus-visible {
449
+ box-shadow: none;
450
+ border-bottom-color: var(--ring, hsl(240 10% 3.9%));
451
+ }
452
+ .rsf-wrapper--underline .rsf-input--invalid,
453
+ .rsf-wrapper--underline .rsf-textarea--invalid,
454
+ .rsf-wrapper--underline .rsf-select--invalid {
455
+ border-bottom-color: var(--destructive, hsl(0 84.2% 60.2%));
456
+ }
457
+ @media (prefers-color-scheme: dark) {
458
+ .rsf-wrapper--underline .rsf-input,
459
+ .rsf-wrapper--underline .rsf-textarea,
460
+ .rsf-wrapper--underline .rsf-select {
461
+ border-bottom-color: var(--input, hsl(240 3.7% 15.9%));
462
+ }
463
+ .rsf-wrapper--underline .rsf-input:focus-visible,
464
+ .rsf-wrapper--underline .rsf-textarea:focus-visible,
465
+ .rsf-wrapper--underline .rsf-select:focus-visible {
466
+ border-bottom-color: var(--ring, hsl(240 4.9% 83.9%));
467
+ }
468
+ }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-smart-fields",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "A flexible and highly customizable dynamic form builder for React with validation, conditional fields, theming, and headless rendering.",
5
5
  "license": "MIT",
6
6
  "author": "Pratik Panchal",
@@ -13,14 +13,15 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js",
15
15
  "require": "./dist/index.cjs"
16
- }
16
+ },
17
+ "./styles.css": "./dist/styles.css"
17
18
  },
18
19
  "files": [
19
20
  "dist"
20
21
  ],
21
- "sideEffects": false,
22
+ "sideEffects": ["*.css"],
22
23
  "scripts": {
23
- "build": "tsup src/index.ts --format esm,cjs --dts --clean",
24
+ "build": "tsup src/index.ts src/styles.css --format esm,cjs --dts --clean",
24
25
  "build:types": "tsc --emitDeclarationOnly"
25
26
  },
26
27
  "repository": {