@dashforge/tw 1.7.0 → 1.7.1
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
CHANGED
|
@@ -12,6 +12,37 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
12
12
|
> duplicated intentionally — no shared "lowest common denominator" headless
|
|
13
13
|
> layer.
|
|
14
14
|
|
|
15
|
+
## [1.7.1] — 2026-09-25
|
|
16
|
+
|
|
17
|
+
Patch: closes the half of BUG 17 that never reached this package.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **An explicit `helperText` no longer swallows the field's validation
|
|
22
|
+
message** (BUG 32). This package carries its own copy of the
|
|
23
|
+
validation resolver at
|
|
24
|
+
`src/components/_shared/resolveValidationState.ts`, and it kept the
|
|
25
|
+
inverted precedence that BUG 17 corrected on the MUI side back on
|
|
26
|
+
2026-09-15. The effect: any bridge-managed field given a constant
|
|
27
|
+
hint painted the danger state and set `aria-invalid="true"` while
|
|
28
|
+
still rendering the hint text, so the user saw a red field with no
|
|
29
|
+
stated reason. **Fourteen components route through that resolver**
|
|
30
|
+
(Autocomplete, Checkbox, DatePicker, DateRangePicker, DateTimePicker,
|
|
31
|
+
NumberField, OTPField, RadioGroup, Select, Slider, Switch, TextField,
|
|
32
|
+
Textarea, TimePicker), so a single line fixes all of them.
|
|
33
|
+
`helperText` now reads `autoMessage ?? explicitHelperText`: the
|
|
34
|
+
validation message wins while it is showing, the hint is the fallback
|
|
35
|
+
for the no-error state. The `error` boolean is unchanged — an
|
|
36
|
+
explicit prop still forces the visual.
|
|
37
|
+
|
|
38
|
+
The resolver's docstring previously advertised itself as matching the
|
|
39
|
+
MUI side "byte-for-byte", which is what let the divergence survive
|
|
40
|
+
ten days. It now carries an explicit warning that the two files are
|
|
41
|
+
hand-kept copies. New regression suite at
|
|
42
|
+
`src/components/_shared/resolveValidationState.test.ts` (7 assertions)
|
|
43
|
+
mirrors the MUI-side one, and each docstring points at the other.
|
|
44
|
+
See `README-BUG.md` § BUG 32.
|
|
45
|
+
|
|
15
46
|
## [1.7.0] — 2026-09-22
|
|
16
47
|
|
|
17
48
|
### Added
|
package/dist/index.esm.js
CHANGED
|
@@ -870,23 +870,33 @@ const tooltipVariants = tv({
|
|
|
870
870
|
/**
|
|
871
871
|
* Compute `error` + `helperText` for a bridge-managed field.
|
|
872
872
|
*
|
|
873
|
-
* **Renderer-agnostic
|
|
874
|
-
* `textField.validation.ts`. Promoted to a
|
|
875
|
-
* `@dashforge/tw` so all
|
|
876
|
-
*
|
|
873
|
+
* **Renderer-agnostic.** Mirrors the MUI-side
|
|
874
|
+
* `ui/src/components/TextField/textField.validation.ts`. Promoted to a
|
|
875
|
+
* `_shared/` directory inside `@dashforge/tw` so all 14 bridge-managed
|
|
876
|
+
* form components reuse the same precedence without depending on a
|
|
877
877
|
* specific component folder.
|
|
878
878
|
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
879
|
+
* ⚠️ This file is a COPY, not an import. The two sides have to be kept
|
|
880
|
+
* in step by hand, and once already were not: BUG 17 (2026-09-15)
|
|
881
|
+
* inverted the `helperText` precedence on the MUI side only, and this
|
|
882
|
+
* copy kept the broken order for ten days until BUG 32 caught it. The
|
|
883
|
+
* verification that missed it was a grep for imports of the MUI file,
|
|
884
|
+
* which by construction cannot reach a copy. **When you change the
|
|
885
|
+
* precedence here, change it there too — and vice versa.**
|
|
886
|
+
*
|
|
887
|
+
* Precedence rules:
|
|
888
|
+
*
|
|
889
|
+
* 1. **`error`: the explicit prop wins.** An author who passes `error`
|
|
890
|
+
* is forcing the visual state, so it overrides the auto-gate.
|
|
891
|
+
* 2. **`helperText`: the validation message wins while it is showing;
|
|
892
|
+
* the explicit prop is the fallback for the no-error state.** A
|
|
893
|
+
* constant hint ("Unique, uppercase") must not swallow the reason a
|
|
894
|
+
* required field was rejected — that leaves the user looking at a
|
|
895
|
+
* red field with no explanation. See README-BUG.md § BUG 17 / § BUG 32.
|
|
896
|
+
* 3. **Auto values are gated by interaction.** The bridge's error is
|
|
884
897
|
* surfaced only when the field is `touched` OR the form has been
|
|
885
898
|
* submitted at least once (`submitCount > 0`). This prevents the
|
|
886
899
|
* "error spam while typing" anti-pattern.
|
|
887
|
-
* 3. **`error === false` explicitly clears the bridge's error message
|
|
888
|
-
* text.** Useful for forcing a "valid" visual state regardless of
|
|
889
|
-
* bridge state.
|
|
890
900
|
*
|
|
891
901
|
* @param name field name registered with the bridge
|
|
892
902
|
* @param bridge active `DashFormBridge` (guaranteed non-null at
|
|
@@ -899,8 +909,16 @@ const tooltipVariants = tv({
|
|
|
899
909
|
const autoTouched = (_bridge_isTouched = bridge.isTouched(name)) != null ? _bridge_isTouched : false;
|
|
900
910
|
const submitCount = (_bridge_submitCount = bridge.submitCount) != null ? _bridge_submitCount : 0;
|
|
901
911
|
const allowAutoError = autoTouched || submitCount > 0;
|
|
912
|
+
// `error` still lets an explicit prop force the visual state.
|
|
902
913
|
const error = explicitError != null ? explicitError : Boolean(autoErr) && allowAutoError;
|
|
903
|
-
|
|
914
|
+
// BUG 32: the validation message wins over the explicit hint while it
|
|
915
|
+
// is showing. The previous order (`explicitHelperText ?? autoMessage`)
|
|
916
|
+
// short-circuited on the hint, so any field carrying one painted the
|
|
917
|
+
// danger state and `aria-invalid="true"` while still rendering the
|
|
918
|
+
// hint text — a red field with no stated reason. Identical inversion
|
|
919
|
+
// to the one BUG 17 landed on the MUI side.
|
|
920
|
+
const autoMessage = allowAutoError ? autoErr == null ? void 0 : autoErr.message : undefined;
|
|
921
|
+
const helperText = autoMessage != null ? autoMessage : explicitHelperText;
|
|
904
922
|
return {
|
|
905
923
|
error,
|
|
906
924
|
helperText
|
|
@@ -14,23 +14,33 @@ export interface ValidationState {
|
|
|
14
14
|
/**
|
|
15
15
|
* Compute `error` + `helperText` for a bridge-managed field.
|
|
16
16
|
*
|
|
17
|
-
* **Renderer-agnostic
|
|
18
|
-
* `textField.validation.ts`. Promoted to a
|
|
19
|
-
* `@dashforge/tw` so all
|
|
20
|
-
*
|
|
17
|
+
* **Renderer-agnostic.** Mirrors the MUI-side
|
|
18
|
+
* `ui/src/components/TextField/textField.validation.ts`. Promoted to a
|
|
19
|
+
* `_shared/` directory inside `@dashforge/tw` so all 14 bridge-managed
|
|
20
|
+
* form components reuse the same precedence without depending on a
|
|
21
21
|
* specific component folder.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
23
|
+
* ⚠️ This file is a COPY, not an import. The two sides have to be kept
|
|
24
|
+
* in step by hand, and once already were not: BUG 17 (2026-09-15)
|
|
25
|
+
* inverted the `helperText` precedence on the MUI side only, and this
|
|
26
|
+
* copy kept the broken order for ten days until BUG 32 caught it. The
|
|
27
|
+
* verification that missed it was a grep for imports of the MUI file,
|
|
28
|
+
* which by construction cannot reach a copy. **When you change the
|
|
29
|
+
* precedence here, change it there too — and vice versa.**
|
|
24
30
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
31
|
+
* Precedence rules:
|
|
32
|
+
*
|
|
33
|
+
* 1. **`error`: the explicit prop wins.** An author who passes `error`
|
|
34
|
+
* is forcing the visual state, so it overrides the auto-gate.
|
|
35
|
+
* 2. **`helperText`: the validation message wins while it is showing;
|
|
36
|
+
* the explicit prop is the fallback for the no-error state.** A
|
|
37
|
+
* constant hint ("Unique, uppercase") must not swallow the reason a
|
|
38
|
+
* required field was rejected — that leaves the user looking at a
|
|
39
|
+
* red field with no explanation. See README-BUG.md § BUG 17 / § BUG 32.
|
|
40
|
+
* 3. **Auto values are gated by interaction.** The bridge's error is
|
|
28
41
|
* surfaced only when the field is `touched` OR the form has been
|
|
29
42
|
* submitted at least once (`submitCount > 0`). This prevents the
|
|
30
43
|
* "error spam while typing" anti-pattern.
|
|
31
|
-
* 3. **`error === false` explicitly clears the bridge's error message
|
|
32
|
-
* text.** Useful for forcing a "valid" visual state regardless of
|
|
33
|
-
* bridge state.
|
|
34
44
|
*
|
|
35
45
|
* @param name field name registered with the bridge
|
|
36
46
|
* @param bridge active `DashFormBridge` (guaranteed non-null at
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveValidationState.d.ts","sourceRoot":"","sources":["../../../../src/components/_shared/resolveValidationState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,SAAS,CAAC;CACvB;AAED
|
|
1
|
+
{"version":3,"file":"resolveValidationState.d.ts","sourceRoot":"","sources":["../../../../src/components/_shared/resolveValidationState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,aAAa,EAAE,OAAO,GAAG,SAAS,EAClC,kBAAkB,EAAE,SAAS,GAAG,SAAS,GACxC,eAAe,CAoBjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dashforge/tw",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.esm.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"tailwind-merge": "^3.0.0",
|
|
36
36
|
"tailwind-variants": "^3.1.1",
|
|
37
37
|
"@dashforge/calendar-core": "1.0.0",
|
|
38
|
-
"@dashforge/rbac": "1.0.0",
|
|
39
38
|
"@dashforge/forms": "1.2.0",
|
|
40
|
-
"@dashforge/ui-core": "1.2.0"
|
|
39
|
+
"@dashforge/ui-core": "1.2.0",
|
|
40
|
+
"@dashforge/rbac": "1.0.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"react": "^18.0.0 || ^19.0.0",
|