@k8ordo/form 0.1.0 → 1.0.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/docs/llms.txt CHANGED
@@ -16,17 +16,68 @@ When installed via npm, these docs live under `node_modules/@k8ordo/form/docs/`.
16
16
  what the package guarantees, what it does not do yet, and how it pairs with
17
17
  `@k8ordo/ui` without depending on it.
18
18
 
19
+ ## Not supported
20
+
21
+ `z.array(z.file())` derives repeated single-file rows, not one `multiple` input.
22
+ Constraints behind a `.transform()` (or a `.pipe()` whose output JSON Schema
23
+ cannot describe) are not derived: the field becomes a bare text input and is
24
+ listed in `dropped`. There is no input masking. A schema no control could
25
+ satisfy is refused at derive time rather than left to fail on every
26
+ submission: `z.number()` and `z.literal(1)` (use `z.coerce.number()`),
27
+ `z.date()`, and `z.bigint()`; so is a `z.stringbool().default(true)` checkbox,
28
+ which could never submit `false`. A `z.custom()` that rejects strings cannot be refused at derive
29
+ time: it derives as a text input, is listed in `dropped`, and fails on the
30
+ server. Of `.refine()` / `.superRefine()` checks, `dropped` counts only the ones
31
+ on the schema as a whole, not those on a single field, a nested object, or a
32
+ row. Rules cannot target fields inside repeated rows.
33
+
19
34
  ## Entry points
20
35
 
21
- - `@k8ordo/form` — client. `useForm(fields, state)` takes the whole
22
- `formFields` result and returns props for the `<form>` element, a
36
+ - `@k8ordo/form` — client. `useForm(fields, state?)` takes the whole
37
+ `formFields` result (and the action's state, when there is one) and
38
+ returns props for the `<form>` element — which also hear a reset, React's
39
+ own after every form action included — a
23
40
  `field(path)` accessor giving input attributes, the current error, and
24
- `invalid` / `required`, an `array(path)` accessor for repeated rows, and
25
- `isDirty`. Also `useAsyncCheck` for server-answered per-field checks and
26
- `HiddenValue` for components that render no input of their own.
27
- - `@k8ordo/form/server` — server. `formFields(schema)` derives serializable
28
- fields plus a `dropped` list of checks HTML cannot express, and throws on a
29
- schema no form can represent; `parseForm(schema, formData)` validates a
30
- submission and returns typed data or per-field errors with the submitted
31
- values. `defineForm(schema, rules)` attaches cross-field rules (`sameAs`,
32
- `minChecked`, `requiredWhen`) typed against the schema's paths.
41
+ `invalid` / `required`, an `array(path)` accessor for repeated rows (its
42
+ `error` is the array's own message, with `errorProps` to let focus land on
43
+ it), `formError` (the message no field owns, with the props that let focus
44
+ land on it), and `isDirty`. On submit it checks every field — untouched ones
45
+ and the rules included — and stops a failing submission, a GET form with no
46
+ action as much as one with (a `formNoValidate` button skips the check);
47
+ after a submission stopped here or failed on the server, focus moves to the
48
+ first failure in document order, and a first failure the hook has no
49
+ message for (a control outside the schema) is reported by the browser
50
+ itself through `reportValidity()`. Also `useAsyncCheck` for server-answered
51
+ per-field checks and `HiddenValue` for components that render no input of
52
+ their own. The types
53
+ of the `formFields` result (`FormFields`, `DerivedField`, `DerivedArray`,
54
+ `DroppedCheck`, `FieldInput`, `StringCheckboxInput`, `ValidityFlag`, `Rule`,
55
+ `DerivedRule`, `RuleMessage`) are exported here as
56
+ well, since the result crosses to the client as a prop, and so are
57
+ `FormState` and the return types (`UseFormReturn`, `FieldView`, `ArrayView`,
58
+ `RowView`, `FormErrorView`, `AsyncCheck`).
59
+ - `@k8ordo/form/server` — server. `formFields(schemaOrDefinition)` derives
60
+ serializable fields plus a `dropped` list of checks HTML cannot express
61
+ (outside production the list is also logged once per schema with
62
+ `console.warn`), and throws on a schema no form can represent (including a
63
+ leaf that could never accept a submitted string, such as `z.number()`);
64
+ `parseForm(schemaOrDefinition, formData)` validates a submission and returns
65
+ typed data or per-field errors with the submitted values. An untouched
66
+ control reaches the schema as what it actually submits: `''` for text,
67
+ `false` for a checkbox, and nothing at all for a number, a
68
+ `z.coerce.bigint()`, a file, a choice (a radio group with none selected, a
69
+ `<select>` on a `value=""` placeholder), or a `z.stringbool()` checkbox —
70
+ which, checked, submits the `value` derived from the schema's own spelling of
71
+ `true`, the same string `@k8ordo/state` writes into a URL — so `z.coerce.number()` cannot read a
72
+ blank field as 0 and `z.enum([…]).optional()` can be left empty. A checkbox
73
+ group always echoes as an array.
74
+ `defineForm(schema, rules)` attaches cross-field rules (`sameAs`,
75
+ `minChecked`, `requiredWhen`) typed against the schema's paths; a rule's
76
+ message is a string or a function called when the rule is reported
77
+ (`formFields` calls it while deriving, so a rule crosses to the client as a
78
+ `DerivedRule` with the text in it; `parseForm` calls it when the rule
79
+ breaks), which keeps a localized definition at module scope. Types:
80
+ `ParseResult`, `FormDefinition`, `Rule`, `RuleMessage`, `FormState`, and the
81
+ `formFields` result's `FormFields`, `DerivedField`, `DerivedArray`,
82
+ `DerivedRule`, `DroppedCheck`, `FieldInput`, `StringCheckboxInput`,
83
+ `ValidityFlag`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8ordo/form",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Derive HTML constraint attributes and per-field errors from one zod schema. Works without JavaScript.",
5
5
  "keywords": [
6
6
  "constraint-validation",
@@ -11,6 +11,9 @@
11
11
  "zod"
12
12
  ],
13
13
  "homepage": "https://ordo.k8o.me",
14
+ "bugs": {
15
+ "url": "https://github.com/k35o/k8ordo/issues"
16
+ },
14
17
  "license": "MIT",
15
18
  "author": "k8o <kosakanoki@gmail.com>",
16
19
  "repository": {
@@ -39,23 +42,26 @@
39
42
  "registry": "https://registry.npmjs.org"
40
43
  },
41
44
  "devDependencies": {
42
- "@types/react": "19.2.18",
43
- "@vitejs/plugin-react": "6.0.5",
44
- "@vitest/browser-playwright": "4.1.10",
45
- "react": "19.2.8",
46
- "react-dom": "19.2.8",
45
+ "@arethetypeswrong/cli": "0.18.5",
46
+ "@k8ordo/state": "^1.0.0",
47
+ "@types/react": "19.3.0",
48
+ "@vitejs/plugin-react": "6.1.2",
49
+ "@vitest/browser-playwright": "5.0.3",
50
+ "publint": "0.3.25",
51
+ "react": "19.3.0",
52
+ "react-dom": "19.3.0",
47
53
  "typescript": "7.0.2",
48
- "vite": "8.2.1",
49
- "vite-plus": "0.2.9",
50
- "vitest": "4.1.10",
51
- "vitest-browser-react": "2.2.0",
52
- "zod": "4.4.3"
54
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
55
+ "vite-plus": "1.1.0",
56
+ "vitest": "5.0.3",
57
+ "vitest-browser-react": "2.3.0",
58
+ "zod": "4.6.5"
53
59
  },
54
60
  "peerDependencies": {
55
- "@types/react": ">=19.2.18",
56
- "react": ">=19.2.6",
57
- "react-dom": ">=19.2.6",
58
- "typescript": ">=7.0.2",
61
+ "@types/react": ">=19.3.0",
62
+ "react": ">=19.3.0",
63
+ "react-dom": ">=19.3.0",
64
+ "typescript": ">=7.0.0",
59
65
  "zod": "^4.4.3"
60
66
  },
61
67
  "peerDependenciesMeta": {
@@ -71,6 +77,7 @@
71
77
  "test": "vp test",
72
78
  "typecheck": "tsc --noEmit",
73
79
  "check": "vp check",
74
- "check:write": "vp check --fix"
80
+ "check:write": "vp check --fix",
81
+ "check:package": "publint && attw --pack . --profile esm-only"
75
82
  }
76
83
  }