@rachelallyson/hero-hook-form 2.1.1 → 2.1.2
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/CHANGELOG.md +13 -0
- package/dist/cypress/index.js +57 -29
- package/dist/index.d.ts +5 -1
- package/dist/index.js +16 -4
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.js +16 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.1.2] - 2025-01-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Date field helper**: Added `FormFieldHelpers.date()` method for creating date fields in forms
|
|
10
|
+
- Supports optional `dateProps` parameter for customizing the date input component
|
|
11
|
+
- Comprehensive test coverage for date field functionality
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **ZodForm FormProvider**: Wrapped ZodForm component with FormProvider to ensure form context is properly available
|
|
16
|
+
- Fixes issues with form context not being accessible in nested components
|
|
17
|
+
|
|
5
18
|
## [2.1.1] - 2025-01-28
|
|
6
19
|
|
|
7
20
|
### Fixed
|
package/dist/cypress/index.js
CHANGED
|
@@ -293,48 +293,72 @@ function expectNoValidationErrors() {
|
|
|
293
293
|
return cy.get("body").should("not.contain", "error").and("not.contain", "invalid");
|
|
294
294
|
}
|
|
295
295
|
function expectFieldError(fieldLabel, errorMessage) {
|
|
296
|
-
|
|
296
|
+
const fieldContainer = cy.contains("label", fieldLabel).closest("div");
|
|
297
|
+
if (errorMessage) {
|
|
298
|
+
return fieldContainer.should("contain", errorMessage);
|
|
299
|
+
}
|
|
300
|
+
return fieldContainer.should(($div) => {
|
|
301
|
+
const text = $div.text();
|
|
302
|
+
const hasError = text.includes("error") || text.includes("invalid") || text.includes("required") || $div.find('[class*="error"], [class*="invalid"], [class*="danger"]').length > 0;
|
|
303
|
+
expect(hasError, "Field should have an error").to.be.true;
|
|
304
|
+
});
|
|
297
305
|
}
|
|
298
306
|
function expectFieldValid(fieldLabel) {
|
|
299
307
|
return cy.contains("label", fieldLabel).closest("div").should("not.contain", "error").and("not.contain", "invalid");
|
|
300
308
|
}
|
|
301
309
|
function triggerValidation(submitButton = false) {
|
|
302
310
|
if (submitButton) {
|
|
303
|
-
return
|
|
311
|
+
return withRetry(() => {
|
|
312
|
+
cy.get("form").should("exist");
|
|
313
|
+
cy.get(HERO_UI_SELECTORS.button.submit).first().should("be.visible").should("not.be.disabled").click();
|
|
314
|
+
return cy.get("form");
|
|
315
|
+
}, DEFAULT_CONFIG);
|
|
304
316
|
}
|
|
305
317
|
return cy.get("input").first().blur();
|
|
306
318
|
}
|
|
307
319
|
function submitForm() {
|
|
308
|
-
return
|
|
320
|
+
return withRetry(() => {
|
|
321
|
+
cy.get("form").should("exist");
|
|
322
|
+
cy.get(HERO_UI_SELECTORS.button.submit).first().should("be.visible").should("not.be.disabled").click();
|
|
323
|
+
return cy.get("form");
|
|
324
|
+
}, DEFAULT_CONFIG);
|
|
309
325
|
}
|
|
310
326
|
function submitAndExpectSuccess(successIndicator) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
327
|
+
return withRetry(() => {
|
|
328
|
+
cy.get("form").should("exist");
|
|
329
|
+
cy.get(HERO_UI_SELECTORS.button.submit).first().should("be.visible").should("not.be.disabled").click();
|
|
330
|
+
if (successIndicator) {
|
|
331
|
+
cy.contains(successIndicator).should("be.visible");
|
|
332
|
+
} else {
|
|
333
|
+
cy.get("body").should("contain.one.of", ["success", "submitted", "complete", "thank you"]);
|
|
334
|
+
}
|
|
335
|
+
return cy.get("form");
|
|
336
|
+
}, DEFAULT_CONFIG);
|
|
316
337
|
}
|
|
317
338
|
function submitAndExpectErrors(errorMessage, formIndex = 0) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
cy.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
cy.log("
|
|
329
|
-
|
|
330
|
-
cy.log(
|
|
339
|
+
return withRetry(() => {
|
|
340
|
+
cy.get("form").should("exist");
|
|
341
|
+
cy.get(HERO_UI_SELECTORS.button.submit).eq(formIndex).should("be.visible").should("not.be.disabled").click();
|
|
342
|
+
cy.get("form").should("exist");
|
|
343
|
+
cy.wait(500);
|
|
344
|
+
if (errorMessage) {
|
|
345
|
+
cy.get("body").then(($body) => {
|
|
346
|
+
if ($body.text().includes(errorMessage)) {
|
|
347
|
+
cy.contains(errorMessage).should("be.visible");
|
|
348
|
+
} else {
|
|
349
|
+
cy.log("Expected error message not found:", errorMessage);
|
|
350
|
+
cy.get('[class*="text-danger"], [class*="text-red"], [class*="error"]').then(($errors) => {
|
|
351
|
+
cy.log("Found validation errors:", $errors.length);
|
|
352
|
+
$errors.each((index, error) => {
|
|
353
|
+
cy.log(`Error ${index}:`, error.textContent);
|
|
354
|
+
});
|
|
331
355
|
});
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
|
|
356
|
+
cy.contains(errorMessage).should("be.visible");
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
return cy.get("form");
|
|
361
|
+
}, DEFAULT_CONFIG);
|
|
338
362
|
}
|
|
339
363
|
function resetForm() {
|
|
340
364
|
return cy.get("body").then(($body) => {
|
|
@@ -348,7 +372,11 @@ function resetForm() {
|
|
|
348
372
|
}
|
|
349
373
|
function interceptFormSubmission(method, url, alias) {
|
|
350
374
|
cy.intercept(method, url).as(alias);
|
|
351
|
-
return
|
|
375
|
+
return withRetry(() => {
|
|
376
|
+
cy.get("form").should("exist");
|
|
377
|
+
cy.get(HERO_UI_SELECTORS.button.submit).first().should("be.visible").should("not.be.disabled").click();
|
|
378
|
+
return cy.get("form");
|
|
379
|
+
}, DEFAULT_CONFIG);
|
|
352
380
|
}
|
|
353
381
|
function verifyFormExists() {
|
|
354
382
|
return cy.get("form").should("exist");
|
|
@@ -365,7 +393,7 @@ function verifyFieldCount(selector, count) {
|
|
|
365
393
|
return cy.get(selector).filter(":visible").not('[type="hidden"]').should("have.length", count);
|
|
366
394
|
}
|
|
367
395
|
function getFormData() {
|
|
368
|
-
return extractFormData();
|
|
396
|
+
return extractFormData().then((data) => data);
|
|
369
397
|
}
|
|
370
398
|
function fillCompleteForm(formData) {
|
|
371
399
|
return cy.then(() => {
|
package/dist/index.d.ts
CHANGED
|
@@ -724,7 +724,7 @@ interface ZodFormProps<T extends FieldValues> {
|
|
|
724
724
|
values: T;
|
|
725
725
|
}) => React$1.ReactNode;
|
|
726
726
|
}
|
|
727
|
-
declare function ZodForm<T extends FieldValues>({ className, columns, config, layout, onError, onSubmit, onSuccess, render, resetButtonText, showResetButton, spacing, submitButtonProps, submitButtonText, subtitle, title, }: ZodFormProps<T>):
|
|
727
|
+
declare function ZodForm<T extends FieldValues>({ className, columns, config, layout, onError, onSubmit, onSuccess, render, resetButtonText, showResetButton, spacing, submitButtonProps, submitButtonText, subtitle, title, }: ZodFormProps<T>): React$1.JSX.Element;
|
|
728
728
|
|
|
729
729
|
/**
|
|
730
730
|
* Hook for using Zod validation with React Hook Form
|
|
@@ -781,6 +781,10 @@ declare const FormFieldHelpers: {
|
|
|
781
781
|
* Create a checkbox field
|
|
782
782
|
*/
|
|
783
783
|
checkbox: <T extends FieldValues>(name: Path<T>, label: string) => ZodFormFieldConfig<T>;
|
|
784
|
+
/**
|
|
785
|
+
* Create a date field
|
|
786
|
+
*/
|
|
787
|
+
date: <T extends FieldValues>(name: Path<T>, label: string, dateProps?: Record<string, string | number | boolean>) => ZodFormFieldConfig<T>;
|
|
784
788
|
/**
|
|
785
789
|
* Create an input field
|
|
786
790
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1855,6 +1855,9 @@ import { useFormContext as useFormContext5 } from "react-hook-form";
|
|
|
1855
1855
|
// src/components/ZodForm.tsx
|
|
1856
1856
|
import React21 from "react";
|
|
1857
1857
|
import { Button as Button5 } from "@heroui/react";
|
|
1858
|
+
import {
|
|
1859
|
+
FormProvider as FormProvider2
|
|
1860
|
+
} from "react-hook-form";
|
|
1858
1861
|
|
|
1859
1862
|
// src/zod-integration.ts
|
|
1860
1863
|
import { useForm as useForm2 } from "react-hook-form";
|
|
@@ -2182,16 +2185,16 @@ function ZodForm({
|
|
|
2182
2185
|
}
|
|
2183
2186
|
}, [form.formState.errors, config.onError]);
|
|
2184
2187
|
if (render) {
|
|
2185
|
-
return render({
|
|
2188
|
+
return /* @__PURE__ */ React21.createElement(FormProvider2, { ...form }, render({
|
|
2186
2189
|
errors: form.formState.errors,
|
|
2187
2190
|
form,
|
|
2188
2191
|
isSubmitted: enhancedState.status !== "idle",
|
|
2189
2192
|
isSubmitting: enhancedState.isSubmitting,
|
|
2190
2193
|
isSuccess: enhancedState.isSuccess,
|
|
2191
2194
|
values: form.getValues()
|
|
2192
|
-
});
|
|
2195
|
+
}));
|
|
2193
2196
|
}
|
|
2194
|
-
return /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
|
|
2197
|
+
return /* @__PURE__ */ React21.createElement(FormProvider2, { ...form }, /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
|
|
2195
2198
|
FormStatus,
|
|
2196
2199
|
{
|
|
2197
2200
|
state: enhancedState,
|
|
@@ -2217,7 +2220,7 @@ function ZodForm({
|
|
|
2217
2220
|
onPress: resetForm
|
|
2218
2221
|
},
|
|
2219
2222
|
resetButtonText
|
|
2220
|
-
)));
|
|
2223
|
+
))));
|
|
2221
2224
|
}
|
|
2222
2225
|
|
|
2223
2226
|
// src/builders/BasicFormBuilder.ts
|
|
@@ -2302,6 +2305,15 @@ var FormFieldHelpers = {
|
|
|
2302
2305
|
name,
|
|
2303
2306
|
type: "checkbox"
|
|
2304
2307
|
}),
|
|
2308
|
+
/**
|
|
2309
|
+
* Create a date field
|
|
2310
|
+
*/
|
|
2311
|
+
date: (name, label, dateProps) => ({
|
|
2312
|
+
dateProps,
|
|
2313
|
+
label,
|
|
2314
|
+
name,
|
|
2315
|
+
type: "date"
|
|
2316
|
+
}),
|
|
2305
2317
|
/**
|
|
2306
2318
|
* Create an input field
|
|
2307
2319
|
*/
|
package/dist/react/index.d.ts
CHANGED
|
@@ -716,7 +716,7 @@ interface ZodFormProps<T extends FieldValues> {
|
|
|
716
716
|
values: T;
|
|
717
717
|
}) => React$1.ReactNode;
|
|
718
718
|
}
|
|
719
|
-
declare function ZodForm<T extends FieldValues>({ className, columns, config, layout, onError, onSubmit, onSuccess, render, resetButtonText, showResetButton, spacing, submitButtonProps, submitButtonText, subtitle, title, }: ZodFormProps<T>):
|
|
719
|
+
declare function ZodForm<T extends FieldValues>({ className, columns, config, layout, onError, onSubmit, onSuccess, render, resetButtonText, showResetButton, spacing, submitButtonProps, submitButtonText, subtitle, title, }: ZodFormProps<T>): React$1.JSX.Element;
|
|
720
720
|
|
|
721
721
|
/**
|
|
722
722
|
* Hook for using Zod validation with React Hook Form
|
|
@@ -773,6 +773,10 @@ declare const FormFieldHelpers: {
|
|
|
773
773
|
* Create a checkbox field
|
|
774
774
|
*/
|
|
775
775
|
checkbox: <T extends FieldValues>(name: Path<T>, label: string) => ZodFormFieldConfig<T>;
|
|
776
|
+
/**
|
|
777
|
+
* Create a date field
|
|
778
|
+
*/
|
|
779
|
+
date: <T extends FieldValues>(name: Path<T>, label: string, dateProps?: Record<string, string | number | boolean>) => ZodFormFieldConfig<T>;
|
|
776
780
|
/**
|
|
777
781
|
* Create an input field
|
|
778
782
|
*/
|
package/dist/react/index.js
CHANGED
|
@@ -1860,6 +1860,9 @@ import { useFormContext as useFormContext5 } from "react-hook-form";
|
|
|
1860
1860
|
// src/components/ZodForm.tsx
|
|
1861
1861
|
import React21 from "react";
|
|
1862
1862
|
import { Button as Button5 } from "@heroui/react";
|
|
1863
|
+
import {
|
|
1864
|
+
FormProvider as FormProvider2
|
|
1865
|
+
} from "react-hook-form";
|
|
1863
1866
|
|
|
1864
1867
|
// src/zod-integration.ts
|
|
1865
1868
|
import { useForm as useForm2 } from "react-hook-form";
|
|
@@ -2187,16 +2190,16 @@ function ZodForm({
|
|
|
2187
2190
|
}
|
|
2188
2191
|
}, [form.formState.errors, config.onError]);
|
|
2189
2192
|
if (render) {
|
|
2190
|
-
return render({
|
|
2193
|
+
return /* @__PURE__ */ React21.createElement(FormProvider2, { ...form }, render({
|
|
2191
2194
|
errors: form.formState.errors,
|
|
2192
2195
|
form,
|
|
2193
2196
|
isSubmitted: enhancedState.status !== "idle",
|
|
2194
2197
|
isSubmitting: enhancedState.isSubmitting,
|
|
2195
2198
|
isSuccess: enhancedState.isSuccess,
|
|
2196
2199
|
values: form.getValues()
|
|
2197
|
-
});
|
|
2200
|
+
}));
|
|
2198
2201
|
}
|
|
2199
|
-
return /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
|
|
2202
|
+
return /* @__PURE__ */ React21.createElement(FormProvider2, { ...form }, /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
|
|
2200
2203
|
FormStatus,
|
|
2201
2204
|
{
|
|
2202
2205
|
state: enhancedState,
|
|
@@ -2222,7 +2225,7 @@ function ZodForm({
|
|
|
2222
2225
|
onPress: resetForm
|
|
2223
2226
|
},
|
|
2224
2227
|
resetButtonText
|
|
2225
|
-
)));
|
|
2228
|
+
))));
|
|
2226
2229
|
}
|
|
2227
2230
|
|
|
2228
2231
|
// src/builders/BasicFormBuilder.ts
|
|
@@ -2307,6 +2310,15 @@ var FormFieldHelpers = {
|
|
|
2307
2310
|
name,
|
|
2308
2311
|
type: "checkbox"
|
|
2309
2312
|
}),
|
|
2313
|
+
/**
|
|
2314
|
+
* Create a date field
|
|
2315
|
+
*/
|
|
2316
|
+
date: (name, label, dateProps) => ({
|
|
2317
|
+
dateProps,
|
|
2318
|
+
label,
|
|
2319
|
+
name,
|
|
2320
|
+
type: "date"
|
|
2321
|
+
}),
|
|
2310
2322
|
/**
|
|
2311
2323
|
* Create an input field
|
|
2312
2324
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rachelallyson/hero-hook-form",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Typed form helpers that combine React Hook Form and HeroUI components.",
|
|
5
5
|
"author": "Rachel Higley",
|
|
6
6
|
"homepage": "https://rachelallyson.github.io/hero-hook-form/",
|