@axenstudio/axen-form 0.1.17 → 0.1.18
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 +34 -3
- package/dist/adapters/yupAdapter.cjs +29 -10
- package/dist/adapters/yupAdapter.d.ts +1 -2
- package/dist/adapters/yupAdapter.js +29 -10
- package/dist/adapters/zodAdapter.cjs +29 -10
- package/dist/adapters/zodAdapter.d.ts +1 -2
- package/dist/adapters/zodAdapter.js +29 -10
- package/dist/core/dateUtils.d.ts +0 -1
- package/dist/core/formStore.cjs +110 -39
- package/dist/core/formStore.d.ts +1 -1
- package/dist/core/formStore.js +110 -39
- package/dist/core/numberUtils.d.ts +0 -1
- package/dist/core/pathUtils.d.ts +0 -1
- package/dist/core/payloadUtils.d.ts +0 -1
- package/dist/core/semanticValidation.cjs +69 -0
- package/dist/core/semanticValidation.d.ts +5 -0
- package/dist/core/semanticValidation.js +69 -0
- package/dist/core/validation.cjs +4 -3
- package/dist/core/validation.d.ts +0 -1
- package/dist/core/validation.js +4 -3
- package/dist/fields/AutocompleteField/AutocompleteField.d.ts +1 -2
- package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts +1 -2
- package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts +1 -2
- package/dist/fields/CheckboxField/CheckboxField.d.ts +1 -2
- package/dist/fields/ColorField/ColorField.d.ts +1 -2
- package/dist/fields/CurrencyField/CurrencyField.d.ts +1 -2
- package/dist/fields/DateField/DateField.d.ts +1 -2
- package/dist/fields/DateField/DatePicker.d.ts +1 -2
- package/dist/fields/DateTimeField/DateTimeField.d.ts +1 -2
- package/dist/fields/EmailField/EmailField.d.ts +1 -2
- package/dist/fields/NumberField/NumberField.d.ts +1 -2
- package/dist/fields/PasswordField/PasswordField.d.ts +1 -2
- package/dist/fields/PhoneField/PhoneField.d.ts +1 -2
- package/dist/fields/RadioField/RadioField.d.ts +1 -2
- package/dist/fields/SelectField/SelectField.d.ts +1 -2
- package/dist/fields/SliderField/SliderField.d.ts +1 -2
- package/dist/fields/SwitchField/SwitchField.d.ts +1 -2
- package/dist/fields/TextField/TextField.d.ts +1 -2
- package/dist/fields/TextareaField/TextareaField.d.ts +1 -2
- package/dist/fields/TimeField/TimeField.d.ts +1 -2
- package/dist/fields/TimeField/TimePicker.d.ts +1 -2
- package/dist/fields/defaultComponentMap.cjs +3 -0
- package/dist/fields/defaultComponentMap.d.ts +0 -1
- package/dist/fields/defaultComponentMap.js +3 -0
- package/dist/fields/defaultPlaceholders.d.ts +0 -1
- package/dist/fields/fieldBase.module.css.cjs +92 -70
- package/dist/fields/fieldBase.module.css.js +92 -70
- package/dist/fields/fieldUtils.d.ts +0 -1
- package/dist/fields/iconUtils.d.ts +0 -1
- package/dist/fields/icons.d.ts +3 -4
- package/dist/index.cjs +31 -22
- package/dist/index.d.ts +3 -2
- package/dist/index.js +32 -23
- package/dist/layout/Box/Box.d.ts +1 -2
- package/dist/layout/Divider/Divider.d.ts +1 -2
- package/dist/layout/Grid/Grid.d.ts +1 -2
- package/dist/layout/Spacer/Spacer.d.ts +1 -2
- package/dist/layout/Stack/Stack.d.ts +1 -2
- package/dist/layout/index.d.ts +0 -1
- package/dist/react/AxenArrayField.d.ts +1 -2
- package/dist/react/AxenField.d.ts +1 -2
- package/dist/react/AxenForm.cjs +29 -23
- package/dist/react/AxenForm.d.ts +0 -1
- package/dist/react/AxenForm.js +30 -24
- package/dist/react/FormContext.d.ts +0 -1
- package/dist/react/useAxenForm.cjs +11 -4
- package/dist/react/useAxenForm.d.ts +1 -2
- package/dist/react/useAxenForm.js +11 -4
- package/dist/react/useField.cjs +3 -0
- package/dist/react/useField.d.ts +0 -1
- package/dist/react/useField.js +3 -0
- package/dist/react/useFieldArray.cjs +19 -13
- package/dist/react/useFieldArray.d.ts +0 -1
- package/dist/react/useFieldArray.js +19 -13
- package/dist/react/useFormState.cjs +18 -0
- package/dist/react/useFormState.d.ts +5 -0
- package/dist/react/useFormState.js +18 -0
- package/dist/types.d.ts +18 -2
- package/package.json +5 -2
- package/dist/adapters/yupAdapter.d.ts.map +0 -1
- package/dist/adapters/zodAdapter.d.ts.map +0 -1
- package/dist/core/dateUtils.d.ts.map +0 -1
- package/dist/core/formStore.d.ts.map +0 -1
- package/dist/core/numberUtils.d.ts.map +0 -1
- package/dist/core/pathUtils.d.ts.map +0 -1
- package/dist/core/payloadUtils.d.ts.map +0 -1
- package/dist/core/validation.d.ts.map +0 -1
- package/dist/fields/AutocompleteField/AutocompleteField.d.ts.map +0 -1
- package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts.map +0 -1
- package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts.map +0 -1
- package/dist/fields/CheckboxField/CheckboxField.d.ts.map +0 -1
- package/dist/fields/ColorField/ColorField.d.ts.map +0 -1
- package/dist/fields/CurrencyField/CurrencyField.d.ts.map +0 -1
- package/dist/fields/DateField/DateField.d.ts.map +0 -1
- package/dist/fields/DateField/DatePicker.d.ts.map +0 -1
- package/dist/fields/DateTimeField/DateTimeField.d.ts.map +0 -1
- package/dist/fields/EmailField/EmailField.d.ts.map +0 -1
- package/dist/fields/NumberField/NumberField.d.ts.map +0 -1
- package/dist/fields/PasswordField/PasswordField.d.ts.map +0 -1
- package/dist/fields/PhoneField/PhoneField.d.ts.map +0 -1
- package/dist/fields/RadioField/RadioField.d.ts.map +0 -1
- package/dist/fields/SelectField/SelectField.d.ts.map +0 -1
- package/dist/fields/SliderField/SliderField.d.ts.map +0 -1
- package/dist/fields/SwitchField/SwitchField.d.ts.map +0 -1
- package/dist/fields/TextField/TextField.d.ts.map +0 -1
- package/dist/fields/TextareaField/TextareaField.d.ts.map +0 -1
- package/dist/fields/TimeField/TimeField.d.ts.map +0 -1
- package/dist/fields/TimeField/TimePicker.d.ts.map +0 -1
- package/dist/fields/defaultComponentMap.d.ts.map +0 -1
- package/dist/fields/defaultPlaceholders.d.ts.map +0 -1
- package/dist/fields/fieldUtils.d.ts.map +0 -1
- package/dist/fields/iconUtils.d.ts.map +0 -1
- package/dist/fields/icons.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/layout/Box/Box.d.ts.map +0 -1
- package/dist/layout/Divider/Divider.d.ts.map +0 -1
- package/dist/layout/Grid/Grid.d.ts.map +0 -1
- package/dist/layout/Spacer/Spacer.d.ts.map +0 -1
- package/dist/layout/Stack/Stack.d.ts.map +0 -1
- package/dist/layout/index.d.ts.map +0 -1
- package/dist/react/AxenArrayField.d.ts.map +0 -1
- package/dist/react/AxenField.d.ts.map +0 -1
- package/dist/react/AxenForm.d.ts.map +0 -1
- package/dist/react/FormContext.d.ts.map +0 -1
- package/dist/react/useAxenForm.d.ts.map +0 -1
- package/dist/react/useField.d.ts.map +0 -1
- package/dist/react/useFieldArray.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,20 +5,21 @@
|
|
|
5
5
|
var elementStyle = document.createElement("style");
|
|
6
6
|
elementStyle.appendChild(document.createTextNode(`/* ═══════════════════════════════════════════════
|
|
7
7
|
axen-form CSS Reset
|
|
8
|
-
|
|
8
|
+
Reset only inside an Axen form or an explicit data-axen-theme wrapper
|
|
9
9
|
═══════════════════════════════════════════════ */
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*::
|
|
11
|
+
:where([data-axen-theme]),
|
|
12
|
+
:where([data-axen-theme]) *,
|
|
13
|
+
:where([data-axen-theme]) *::before,
|
|
14
|
+
:where([data-axen-theme]) *::after {
|
|
14
15
|
box-sizing: border-box;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
/* Reset form element defaults */
|
|
18
|
-
input,
|
|
19
|
-
textarea,
|
|
20
|
-
select,
|
|
21
|
-
button {
|
|
19
|
+
:where([data-axen-theme]) input,
|
|
20
|
+
:where([data-axen-theme]) textarea,
|
|
21
|
+
:where([data-axen-theme]) select,
|
|
22
|
+
:where([data-axen-theme]) button {
|
|
22
23
|
font-family: inherit;
|
|
23
24
|
font-size: inherit;
|
|
24
25
|
line-height: inherit;
|
|
@@ -27,46 +28,46 @@ button {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/* Remove default styling from number inputs */
|
|
30
|
-
input[type='number']::-webkit-inner-spin-button,
|
|
31
|
-
input[type='number']::-webkit-outer-spin-button {
|
|
31
|
+
:where([data-axen-theme]) input[type='number']::-webkit-inner-spin-button,
|
|
32
|
+
:where([data-axen-theme]) input[type='number']::-webkit-outer-spin-button {
|
|
32
33
|
-webkit-appearance: none;
|
|
33
34
|
margin: 0;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
input[type='number'] {
|
|
37
|
+
:where([data-axen-theme]) input[type='number'] {
|
|
37
38
|
-moz-appearance: textfield;
|
|
38
39
|
appearance: textfield;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/* Remove default date/time input icons if using custom components */
|
|
42
|
-
input[type='date']::-webkit-calendar-picker-indicator,
|
|
43
|
-
input[type='time']::-webkit-calendar-picker-indicator,
|
|
44
|
-
input[type='datetime-local']::-webkit-calendar-picker-indicator {
|
|
43
|
+
:where([data-axen-theme]) input[type='date']::-webkit-calendar-picker-indicator,
|
|
44
|
+
:where([data-axen-theme]) input[type='time']::-webkit-calendar-picker-indicator,
|
|
45
|
+
:where([data-axen-theme]) input[type='datetime-local']::-webkit-calendar-picker-indicator {
|
|
45
46
|
cursor: pointer;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/* Ensure fieldset/legend reset */
|
|
49
|
-
fieldset {
|
|
50
|
+
:where([data-axen-theme]) fieldset {
|
|
50
51
|
border: none;
|
|
51
52
|
padding: 0;
|
|
52
53
|
margin: 0;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
legend {
|
|
56
|
+
:where([data-axen-theme]) legend {
|
|
56
57
|
padding: 0;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/* Remove textarea resize handle (can be overridden) */
|
|
60
|
-
textarea {
|
|
61
|
+
:where([data-axen-theme]) textarea {
|
|
61
62
|
resize: vertical;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/* Focus visible only — keyboard navigation (A11y) */
|
|
65
|
-
:focus:not(:focus-visible) {
|
|
66
|
+
:where([data-axen-theme]) :focus:not(:focus-visible) {
|
|
66
67
|
outline: none;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
:focus-visible {
|
|
70
|
+
:where([data-axen-theme]) :focus-visible {
|
|
70
71
|
outline: var(--axen-focus-ring-width, 2px) solid
|
|
71
72
|
var(--axen-focus-ring-color, rgba(25, 118, 210, 0.5));
|
|
72
73
|
outline-offset: var(--axen-focus-ring-offset, 2px);
|
|
@@ -108,9 +109,6 @@ textarea {
|
|
|
108
109
|
═══════════════════════════════════════════════ */
|
|
109
110
|
|
|
110
111
|
:root {
|
|
111
|
-
/* Force light rendering for all native form controls (select, date, etc.) */
|
|
112
|
-
color-scheme: light;
|
|
113
|
-
|
|
114
112
|
/* ── Color Palette ─────────────────────────── */
|
|
115
113
|
--axen-color-primary: #1976d2;
|
|
116
114
|
--axen-color-primary-hover: #1565c0;
|
|
@@ -189,6 +187,11 @@ textarea {
|
|
|
189
187
|
--axen-z-tooltip: 200;
|
|
190
188
|
}
|
|
191
189
|
|
|
190
|
+
:where([data-axen-theme]) {
|
|
191
|
+
/* Keep native Axen controls light without changing the host document. */
|
|
192
|
+
color-scheme: light;
|
|
193
|
+
}
|
|
194
|
+
|
|
192
195
|
/* ── Dark Mode ───────────────────────────────
|
|
193
196
|
Removed: axen-form ships as light-only by default.
|
|
194
197
|
Form elements are locked to color-scheme: light above.
|
|
@@ -231,10 +234,12 @@ import { calculateCursorPosition, formatNumber, getDecimalSeparator, getGroupSep
|
|
|
231
234
|
import { get, pathToString, set, toPathArray } from "./core/pathUtils.js";
|
|
232
235
|
import { getStrippedFields, mapPayload, pickFields } from "./core/payloadUtils.js";
|
|
233
236
|
import { simpleValidator } from "./core/validation.js";
|
|
237
|
+
import { validateSemanticValue, withValidationPolicy } from "./core/semanticValidation.js";
|
|
234
238
|
import { FormContext, useFormContext } from "./react/FormContext.js";
|
|
235
239
|
import { useAxenForm } from "./react/useAxenForm.js";
|
|
236
240
|
import { useField } from "./react/useField.js";
|
|
237
241
|
import { useFieldArray } from "./react/useFieldArray.js";
|
|
242
|
+
import { useFormState, useWatch } from "./react/useFormState.js";
|
|
238
243
|
import { AxenArrayField } from "./react/AxenArrayField.js";
|
|
239
244
|
import { AxenField } from "./react/AxenField.js";
|
|
240
245
|
import { AxenForm } from "./react/AxenForm.js";
|
|
@@ -333,5 +338,9 @@ export {
|
|
|
333
338
|
useAxenForm,
|
|
334
339
|
useField,
|
|
335
340
|
useFieldArray,
|
|
336
|
-
useFormContext
|
|
341
|
+
useFormContext,
|
|
342
|
+
useFormState,
|
|
343
|
+
useWatch,
|
|
344
|
+
validateSemanticValue,
|
|
345
|
+
withValidationPolicy
|
|
337
346
|
};
|
package/dist/layout/Box/Box.d.ts
CHANGED
|
@@ -2,5 +2,4 @@ import { BoxProps } from '../../types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Utility box component for flex/block layout + spacing.
|
|
4
4
|
*/
|
|
5
|
-
export declare function Box({ children, component: Component, display, flexDirection, justifyContent, alignItems, flexWrap, gap, p, px, py, m, mx, my, className, style: userStyle, }: Readonly<BoxProps>): import("react
|
|
6
|
-
//# sourceMappingURL=Box.d.ts.map
|
|
5
|
+
export declare function Box({ children, component: Component, display, flexDirection, justifyContent, alignItems, flexWrap, gap, p, px, py, m, mx, my, className, style: userStyle, }: Readonly<BoxProps>): import("react").JSX.Element;
|
|
@@ -2,5 +2,4 @@ import { DividerProps } from '../../types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Visual divider line — horizontal or vertical.
|
|
4
4
|
*/
|
|
5
|
-
export declare function Divider({ orientation, className, style }: Readonly<DividerProps>): import("react
|
|
6
|
-
//# sourceMappingURL=Divider.d.ts.map
|
|
5
|
+
export declare function Divider({ orientation, className, style }: Readonly<DividerProps>): import("react").JSX.Element;
|
|
@@ -3,5 +3,4 @@ import { GridProps } from '../../types';
|
|
|
3
3
|
* CSS Grid-based layout component (MUI v7 Grid API).
|
|
4
4
|
* 12-column responsive grid system.
|
|
5
5
|
*/
|
|
6
|
-
export declare function Grid({ children, container, columns, spacing, rowSpacing, columnSpacing, size: sizeProp, xs: xsProp, sm: smProp, md: mdProp, lg: lgProp, xl: xlProp, offset, className, style: userStyle, }: Readonly<GridProps>): import("react
|
|
7
|
-
//# sourceMappingURL=Grid.d.ts.map
|
|
6
|
+
export declare function Grid({ children, container, columns, spacing, rowSpacing, columnSpacing, size: sizeProp, xs: xsProp, sm: smProp, md: mdProp, lg: lgProp, xl: xlProp, offset, className, style: userStyle, }: Readonly<GridProps>): import("react").JSX.Element;
|
|
@@ -17,5 +17,4 @@ import { SpacerProps } from '../../types';
|
|
|
17
17
|
* // Flex basis (fixed space in flex container)
|
|
18
18
|
* <Spacer basis={4} /> // 32px flex-basis
|
|
19
19
|
*/
|
|
20
|
-
export declare function Spacer({ x, y, basis, grow, className, style: userStyle, }: Readonly<SpacerProps>): import("react
|
|
21
|
-
//# sourceMappingURL=Spacer.d.ts.map
|
|
20
|
+
export declare function Spacer({ x, y, basis, grow, className, style: userStyle, }: Readonly<SpacerProps>): import("react").JSX.Element;
|
|
@@ -3,5 +3,4 @@ import { StackProps } from '../../types';
|
|
|
3
3
|
* Stack component — arranges children in a row or column with spacing.
|
|
4
4
|
* Optionally inserts a divider between items.
|
|
5
5
|
*/
|
|
6
|
-
export declare function Stack({ children, direction, spacing, alignItems, justifyContent, divider, className, style: userStyle, }: Readonly<StackProps>): import("react
|
|
7
|
-
//# sourceMappingURL=Stack.d.ts.map
|
|
6
|
+
export declare function Stack({ children, direction, spacing, alignItems, justifyContent, divider, className, style: userStyle, }: Readonly<StackProps>): import("react").JSX.Element;
|
package/dist/layout/index.d.ts
CHANGED
|
@@ -11,5 +11,4 @@ export interface AxenArrayFieldProps {
|
|
|
11
11
|
/**
|
|
12
12
|
* Array field component for repeating field groups.
|
|
13
13
|
*/
|
|
14
|
-
export declare function AxenArrayField({ name, config, children }: Readonly<AxenArrayFieldProps>): import("react
|
|
15
|
-
//# sourceMappingURL=AxenArrayField.d.ts.map
|
|
14
|
+
export declare function AxenArrayField({ name, config, children }: Readonly<AxenArrayFieldProps>): import("react").JSX.Element;
|
|
@@ -9,5 +9,4 @@ export interface AxenFieldProps {
|
|
|
9
9
|
* Standalone field component — can be used outside AxenForm grid
|
|
10
10
|
* when you need fine-grained placement.
|
|
11
11
|
*/
|
|
12
|
-
export declare function AxenField({ name, config, component, children }: Readonly<AxenFieldProps>): import("react
|
|
13
|
-
//# sourceMappingURL=AxenField.d.ts.map
|
|
12
|
+
export declare function AxenField({ name, config, component, children }: Readonly<AxenFieldProps>): import("react").JSX.Element | null;
|
package/dist/react/AxenForm.cjs
CHANGED
|
@@ -5,20 +5,21 @@
|
|
|
5
5
|
var elementStyle = document.createElement("style");
|
|
6
6
|
elementStyle.appendChild(document.createTextNode(`/* ═══════════════════════════════════════════════
|
|
7
7
|
axen-form CSS Reset
|
|
8
|
-
|
|
8
|
+
Reset only inside an Axen form or an explicit data-axen-theme wrapper
|
|
9
9
|
═══════════════════════════════════════════════ */
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*::
|
|
11
|
+
:where([data-axen-theme]),
|
|
12
|
+
:where([data-axen-theme]) *,
|
|
13
|
+
:where([data-axen-theme]) *::before,
|
|
14
|
+
:where([data-axen-theme]) *::after {
|
|
14
15
|
box-sizing: border-box;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
/* Reset form element defaults */
|
|
18
|
-
input,
|
|
19
|
-
textarea,
|
|
20
|
-
select,
|
|
21
|
-
button {
|
|
19
|
+
:where([data-axen-theme]) input,
|
|
20
|
+
:where([data-axen-theme]) textarea,
|
|
21
|
+
:where([data-axen-theme]) select,
|
|
22
|
+
:where([data-axen-theme]) button {
|
|
22
23
|
font-family: inherit;
|
|
23
24
|
font-size: inherit;
|
|
24
25
|
line-height: inherit;
|
|
@@ -27,46 +28,46 @@ button {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/* Remove default styling from number inputs */
|
|
30
|
-
input[type='number']::-webkit-inner-spin-button,
|
|
31
|
-
input[type='number']::-webkit-outer-spin-button {
|
|
31
|
+
:where([data-axen-theme]) input[type='number']::-webkit-inner-spin-button,
|
|
32
|
+
:where([data-axen-theme]) input[type='number']::-webkit-outer-spin-button {
|
|
32
33
|
-webkit-appearance: none;
|
|
33
34
|
margin: 0;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
input[type='number'] {
|
|
37
|
+
:where([data-axen-theme]) input[type='number'] {
|
|
37
38
|
-moz-appearance: textfield;
|
|
38
39
|
appearance: textfield;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/* Remove default date/time input icons if using custom components */
|
|
42
|
-
input[type='date']::-webkit-calendar-picker-indicator,
|
|
43
|
-
input[type='time']::-webkit-calendar-picker-indicator,
|
|
44
|
-
input[type='datetime-local']::-webkit-calendar-picker-indicator {
|
|
43
|
+
:where([data-axen-theme]) input[type='date']::-webkit-calendar-picker-indicator,
|
|
44
|
+
:where([data-axen-theme]) input[type='time']::-webkit-calendar-picker-indicator,
|
|
45
|
+
:where([data-axen-theme]) input[type='datetime-local']::-webkit-calendar-picker-indicator {
|
|
45
46
|
cursor: pointer;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/* Ensure fieldset/legend reset */
|
|
49
|
-
fieldset {
|
|
50
|
+
:where([data-axen-theme]) fieldset {
|
|
50
51
|
border: none;
|
|
51
52
|
padding: 0;
|
|
52
53
|
margin: 0;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
legend {
|
|
56
|
+
:where([data-axen-theme]) legend {
|
|
56
57
|
padding: 0;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/* Remove textarea resize handle (can be overridden) */
|
|
60
|
-
textarea {
|
|
61
|
+
:where([data-axen-theme]) textarea {
|
|
61
62
|
resize: vertical;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/* Focus visible only — keyboard navigation (A11y) */
|
|
65
|
-
:focus:not(:focus-visible) {
|
|
66
|
+
:where([data-axen-theme]) :focus:not(:focus-visible) {
|
|
66
67
|
outline: none;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
:focus-visible {
|
|
70
|
+
:where([data-axen-theme]) :focus-visible {
|
|
70
71
|
outline: var(--axen-focus-ring-width, 2px) solid
|
|
71
72
|
var(--axen-focus-ring-color, rgba(25, 118, 210, 0.5));
|
|
72
73
|
outline-offset: var(--axen-focus-ring-offset, 2px);
|
|
@@ -108,9 +109,6 @@ textarea {
|
|
|
108
109
|
═══════════════════════════════════════════════ */
|
|
109
110
|
|
|
110
111
|
:root {
|
|
111
|
-
/* Force light rendering for all native form controls (select, date, etc.) */
|
|
112
|
-
color-scheme: light;
|
|
113
|
-
|
|
114
112
|
/* ── Color Palette ─────────────────────────── */
|
|
115
113
|
--axen-color-primary: #1976d2;
|
|
116
114
|
--axen-color-primary-hover: #1565c0;
|
|
@@ -189,6 +187,11 @@ textarea {
|
|
|
189
187
|
--axen-z-tooltip: 200;
|
|
190
188
|
}
|
|
191
189
|
|
|
190
|
+
:where([data-axen-theme]) {
|
|
191
|
+
/* Keep native Axen controls light without changing the host document. */
|
|
192
|
+
color-scheme: light;
|
|
193
|
+
}
|
|
194
|
+
|
|
192
195
|
/* ── Dark Mode ───────────────────────────────
|
|
193
196
|
Removed: axen-form ships as light-only by default.
|
|
194
197
|
Form elements are locked to color-scheme: light above.
|
|
@@ -243,6 +246,7 @@ function AxenFormInner(props, ref) {
|
|
|
243
246
|
onSubmit,
|
|
244
247
|
components,
|
|
245
248
|
validationAdapter,
|
|
249
|
+
validationPolicy,
|
|
246
250
|
payloadFields,
|
|
247
251
|
payloadDiscriminator,
|
|
248
252
|
columns = 12,
|
|
@@ -270,6 +274,7 @@ function AxenFormInner(props, ref) {
|
|
|
270
274
|
config,
|
|
271
275
|
onSubmit: wrappedOnSubmit,
|
|
272
276
|
validationAdapter,
|
|
277
|
+
validationPolicy,
|
|
273
278
|
validateOnChange,
|
|
274
279
|
validateOnBlur
|
|
275
280
|
});
|
|
@@ -366,7 +371,8 @@ function AxenFieldRenderer({
|
|
|
366
371
|
}) {
|
|
367
372
|
const { store, components } = FormContext.useFormContext();
|
|
368
373
|
const { value, error, touched, onChange, onBlur } = useField.useField(config.name);
|
|
369
|
-
const
|
|
374
|
+
const getHidden = () => typeof config.hidden === "function" ? Boolean(config.hidden(store.getState().values)) : Boolean(config.hidden);
|
|
375
|
+
const hidden = react.useSyncExternalStore(store.subscribe, getHidden, getHidden);
|
|
370
376
|
if (hidden) return null;
|
|
371
377
|
const Component = config.component ?? components[config.type];
|
|
372
378
|
if (!Component) {
|
package/dist/react/AxenForm.d.ts
CHANGED
package/dist/react/AxenForm.js
CHANGED
|
@@ -5,20 +5,21 @@
|
|
|
5
5
|
var elementStyle = document.createElement("style");
|
|
6
6
|
elementStyle.appendChild(document.createTextNode(`/* ═══════════════════════════════════════════════
|
|
7
7
|
axen-form CSS Reset
|
|
8
|
-
|
|
8
|
+
Reset only inside an Axen form or an explicit data-axen-theme wrapper
|
|
9
9
|
═══════════════════════════════════════════════ */
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*::
|
|
11
|
+
:where([data-axen-theme]),
|
|
12
|
+
:where([data-axen-theme]) *,
|
|
13
|
+
:where([data-axen-theme]) *::before,
|
|
14
|
+
:where([data-axen-theme]) *::after {
|
|
14
15
|
box-sizing: border-box;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
/* Reset form element defaults */
|
|
18
|
-
input,
|
|
19
|
-
textarea,
|
|
20
|
-
select,
|
|
21
|
-
button {
|
|
19
|
+
:where([data-axen-theme]) input,
|
|
20
|
+
:where([data-axen-theme]) textarea,
|
|
21
|
+
:where([data-axen-theme]) select,
|
|
22
|
+
:where([data-axen-theme]) button {
|
|
22
23
|
font-family: inherit;
|
|
23
24
|
font-size: inherit;
|
|
24
25
|
line-height: inherit;
|
|
@@ -27,46 +28,46 @@ button {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/* Remove default styling from number inputs */
|
|
30
|
-
input[type='number']::-webkit-inner-spin-button,
|
|
31
|
-
input[type='number']::-webkit-outer-spin-button {
|
|
31
|
+
:where([data-axen-theme]) input[type='number']::-webkit-inner-spin-button,
|
|
32
|
+
:where([data-axen-theme]) input[type='number']::-webkit-outer-spin-button {
|
|
32
33
|
-webkit-appearance: none;
|
|
33
34
|
margin: 0;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
input[type='number'] {
|
|
37
|
+
:where([data-axen-theme]) input[type='number'] {
|
|
37
38
|
-moz-appearance: textfield;
|
|
38
39
|
appearance: textfield;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/* Remove default date/time input icons if using custom components */
|
|
42
|
-
input[type='date']::-webkit-calendar-picker-indicator,
|
|
43
|
-
input[type='time']::-webkit-calendar-picker-indicator,
|
|
44
|
-
input[type='datetime-local']::-webkit-calendar-picker-indicator {
|
|
43
|
+
:where([data-axen-theme]) input[type='date']::-webkit-calendar-picker-indicator,
|
|
44
|
+
:where([data-axen-theme]) input[type='time']::-webkit-calendar-picker-indicator,
|
|
45
|
+
:where([data-axen-theme]) input[type='datetime-local']::-webkit-calendar-picker-indicator {
|
|
45
46
|
cursor: pointer;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/* Ensure fieldset/legend reset */
|
|
49
|
-
fieldset {
|
|
50
|
+
:where([data-axen-theme]) fieldset {
|
|
50
51
|
border: none;
|
|
51
52
|
padding: 0;
|
|
52
53
|
margin: 0;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
legend {
|
|
56
|
+
:where([data-axen-theme]) legend {
|
|
56
57
|
padding: 0;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/* Remove textarea resize handle (can be overridden) */
|
|
60
|
-
textarea {
|
|
61
|
+
:where([data-axen-theme]) textarea {
|
|
61
62
|
resize: vertical;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/* Focus visible only — keyboard navigation (A11y) */
|
|
65
|
-
:focus:not(:focus-visible) {
|
|
66
|
+
:where([data-axen-theme]) :focus:not(:focus-visible) {
|
|
66
67
|
outline: none;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
:focus-visible {
|
|
70
|
+
:where([data-axen-theme]) :focus-visible {
|
|
70
71
|
outline: var(--axen-focus-ring-width, 2px) solid
|
|
71
72
|
var(--axen-focus-ring-color, rgba(25, 118, 210, 0.5));
|
|
72
73
|
outline-offset: var(--axen-focus-ring-offset, 2px);
|
|
@@ -108,9 +109,6 @@ textarea {
|
|
|
108
109
|
═══════════════════════════════════════════════ */
|
|
109
110
|
|
|
110
111
|
:root {
|
|
111
|
-
/* Force light rendering for all native form controls (select, date, etc.) */
|
|
112
|
-
color-scheme: light;
|
|
113
|
-
|
|
114
112
|
/* ── Color Palette ─────────────────────────── */
|
|
115
113
|
--axen-color-primary: #1976d2;
|
|
116
114
|
--axen-color-primary-hover: #1565c0;
|
|
@@ -189,6 +187,11 @@ textarea {
|
|
|
189
187
|
--axen-z-tooltip: 200;
|
|
190
188
|
}
|
|
191
189
|
|
|
190
|
+
:where([data-axen-theme]) {
|
|
191
|
+
/* Keep native Axen controls light without changing the host document. */
|
|
192
|
+
color-scheme: light;
|
|
193
|
+
}
|
|
194
|
+
|
|
192
195
|
/* ── Dark Mode ───────────────────────────────
|
|
193
196
|
Removed: axen-form ships as light-only by default.
|
|
194
197
|
Form elements are locked to color-scheme: light above.
|
|
@@ -222,7 +225,7 @@ textarea {
|
|
|
222
225
|
}
|
|
223
226
|
})();
|
|
224
227
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
225
|
-
import { forwardRef, useMemo, useImperativeHandle } from "react";
|
|
228
|
+
import { forwardRef, useMemo, useImperativeHandle, useSyncExternalStore } from "react";
|
|
226
229
|
import { mapPayload } from "../core/payloadUtils.js";
|
|
227
230
|
import { defaultComponentMap } from "../fields/defaultComponentMap.js";
|
|
228
231
|
import { defaultPlaceholders } from "../fields/defaultPlaceholders.js";
|
|
@@ -241,6 +244,7 @@ function AxenFormInner(props, ref) {
|
|
|
241
244
|
onSubmit,
|
|
242
245
|
components,
|
|
243
246
|
validationAdapter,
|
|
247
|
+
validationPolicy,
|
|
244
248
|
payloadFields,
|
|
245
249
|
payloadDiscriminator,
|
|
246
250
|
columns = 12,
|
|
@@ -268,6 +272,7 @@ function AxenFormInner(props, ref) {
|
|
|
268
272
|
config,
|
|
269
273
|
onSubmit: wrappedOnSubmit,
|
|
270
274
|
validationAdapter,
|
|
275
|
+
validationPolicy,
|
|
271
276
|
validateOnChange,
|
|
272
277
|
validateOnBlur
|
|
273
278
|
});
|
|
@@ -364,7 +369,8 @@ function AxenFieldRenderer({
|
|
|
364
369
|
}) {
|
|
365
370
|
const { store, components } = useFormContext();
|
|
366
371
|
const { value, error, touched, onChange, onBlur } = useField(config.name);
|
|
367
|
-
const
|
|
372
|
+
const getHidden = () => typeof config.hidden === "function" ? Boolean(config.hidden(store.getState().values)) : Boolean(config.hidden);
|
|
373
|
+
const hidden = useSyncExternalStore(store.subscribe, getHidden, getHidden);
|
|
368
374
|
if (hidden) return null;
|
|
369
375
|
const Component = config.component ?? components[config.type];
|
|
370
376
|
if (!Component) {
|
|
@@ -3,25 +3,32 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const react = require("react");
|
|
4
4
|
const formStore = require("../core/formStore.cjs");
|
|
5
5
|
const validation = require("../core/validation.cjs");
|
|
6
|
+
const semanticValidation = require("../core/semanticValidation.cjs");
|
|
7
|
+
const types = require("../types.cjs");
|
|
6
8
|
function useAxenForm(props) {
|
|
7
9
|
const {
|
|
8
10
|
config,
|
|
9
11
|
onSubmit,
|
|
10
12
|
validationAdapter,
|
|
13
|
+
validationPolicy,
|
|
11
14
|
validateOnChange = true,
|
|
12
15
|
validateOnBlur = true
|
|
13
16
|
} = props;
|
|
14
|
-
const adapter = validationAdapter ?? validation.simpleValidator;
|
|
17
|
+
const adapter = semanticValidation.withValidationPolicy(validationAdapter ?? validation.simpleValidator, validationPolicy ?? config.validationPolicy);
|
|
18
|
+
const onSubmitRef = react.useRef(onSubmit);
|
|
19
|
+
onSubmitRef.current = onSubmit;
|
|
20
|
+
const isUpdateRef = react.useRef(config.isUpdate ?? false);
|
|
21
|
+
isUpdateRef.current = config.isUpdate ?? false;
|
|
15
22
|
const storeRef = react.useRef(null);
|
|
16
23
|
storeRef.current ?? (storeRef.current = formStore.createFormStore({
|
|
17
24
|
initialValues: config.initialValues,
|
|
18
25
|
validationAdapter: adapter,
|
|
19
|
-
fields: config.fields,
|
|
26
|
+
fields: config.fields.flatMap((item) => types.isFieldGroup(item) ? item.fields : [item]),
|
|
20
27
|
validateOnChange,
|
|
21
28
|
validateOnBlur,
|
|
22
29
|
onSubmit: async (values) => {
|
|
23
|
-
await
|
|
24
|
-
isUpdate:
|
|
30
|
+
await onSubmitRef.current(values, {
|
|
31
|
+
isUpdate: isUpdateRef.current,
|
|
25
32
|
resetForm: () => {
|
|
26
33
|
var _a;
|
|
27
34
|
return (_a = storeRef.current) == null ? void 0 : _a.resetForm();
|
|
@@ -4,5 +4,4 @@ export interface UseAxenFormReturn<TValues extends Record<string, unknown>> {
|
|
|
4
4
|
store: FormStore<TValues>;
|
|
5
5
|
formApi: FormApi<TValues>;
|
|
6
6
|
}
|
|
7
|
-
export declare function useAxenForm<TValues extends Record<string, unknown>>(props: Pick<AxenFormProps<TValues>, 'config' | 'onSubmit' | 'validationAdapter' | 'validateOnChange' | 'validateOnBlur' | 'payloadFields' | 'payloadDiscriminator'>): UseAxenFormReturn<TValues>;
|
|
8
|
-
//# sourceMappingURL=useAxenForm.d.ts.map
|
|
7
|
+
export declare function useAxenForm<TValues extends Record<string, unknown>>(props: Pick<AxenFormProps<TValues>, 'config' | 'onSubmit' | 'validationAdapter' | 'validationPolicy' | 'validateOnChange' | 'validateOnBlur' | 'payloadFields' | 'payloadDiscriminator'>): UseAxenFormReturn<TValues>;
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
import { useRef, useMemo } from "react";
|
|
2
2
|
import { createFormStore } from "../core/formStore.js";
|
|
3
3
|
import { simpleValidator } from "../core/validation.js";
|
|
4
|
+
import { withValidationPolicy } from "../core/semanticValidation.js";
|
|
5
|
+
import { isFieldGroup } from "../types.js";
|
|
4
6
|
function useAxenForm(props) {
|
|
5
7
|
const {
|
|
6
8
|
config,
|
|
7
9
|
onSubmit,
|
|
8
10
|
validationAdapter,
|
|
11
|
+
validationPolicy,
|
|
9
12
|
validateOnChange = true,
|
|
10
13
|
validateOnBlur = true
|
|
11
14
|
} = props;
|
|
12
|
-
const adapter = validationAdapter ?? simpleValidator;
|
|
15
|
+
const adapter = withValidationPolicy(validationAdapter ?? simpleValidator, validationPolicy ?? config.validationPolicy);
|
|
16
|
+
const onSubmitRef = useRef(onSubmit);
|
|
17
|
+
onSubmitRef.current = onSubmit;
|
|
18
|
+
const isUpdateRef = useRef(config.isUpdate ?? false);
|
|
19
|
+
isUpdateRef.current = config.isUpdate ?? false;
|
|
13
20
|
const storeRef = useRef(null);
|
|
14
21
|
storeRef.current ?? (storeRef.current = createFormStore({
|
|
15
22
|
initialValues: config.initialValues,
|
|
16
23
|
validationAdapter: adapter,
|
|
17
|
-
fields: config.fields,
|
|
24
|
+
fields: config.fields.flatMap((item) => isFieldGroup(item) ? item.fields : [item]),
|
|
18
25
|
validateOnChange,
|
|
19
26
|
validateOnBlur,
|
|
20
27
|
onSubmit: async (values) => {
|
|
21
|
-
await
|
|
22
|
-
isUpdate:
|
|
28
|
+
await onSubmitRef.current(values, {
|
|
29
|
+
isUpdate: isUpdateRef.current,
|
|
23
30
|
resetForm: () => {
|
|
24
31
|
var _a;
|
|
25
32
|
return (_a = storeRef.current) == null ? void 0 : _a.resetForm();
|
package/dist/react/useField.cjs
CHANGED
|
@@ -6,14 +6,17 @@ function useField(name) {
|
|
|
6
6
|
const { store } = FormContext.useFormContext();
|
|
7
7
|
const value = react.useSyncExternalStore(
|
|
8
8
|
(cb) => store.subscribeField(name, cb),
|
|
9
|
+
() => store.getFieldValue(name),
|
|
9
10
|
() => store.getFieldValue(name)
|
|
10
11
|
);
|
|
11
12
|
const error = react.useSyncExternalStore(
|
|
12
13
|
(cb) => store.subscribeField(name, cb),
|
|
14
|
+
() => store.getFieldError(name),
|
|
13
15
|
() => store.getFieldError(name)
|
|
14
16
|
);
|
|
15
17
|
const touched = react.useSyncExternalStore(
|
|
16
18
|
(cb) => store.subscribeField(name, cb),
|
|
19
|
+
() => store.getFieldTouched(name),
|
|
17
20
|
() => store.getFieldTouched(name)
|
|
18
21
|
);
|
|
19
22
|
const onChange = react.useCallback(
|
package/dist/react/useField.d.ts
CHANGED
package/dist/react/useField.js
CHANGED
|
@@ -4,14 +4,17 @@ function useField(name) {
|
|
|
4
4
|
const { store } = useFormContext();
|
|
5
5
|
const value = useSyncExternalStore(
|
|
6
6
|
(cb) => store.subscribeField(name, cb),
|
|
7
|
+
() => store.getFieldValue(name),
|
|
7
8
|
() => store.getFieldValue(name)
|
|
8
9
|
);
|
|
9
10
|
const error = useSyncExternalStore(
|
|
10
11
|
(cb) => store.subscribeField(name, cb),
|
|
12
|
+
() => store.getFieldError(name),
|
|
11
13
|
() => store.getFieldError(name)
|
|
12
14
|
);
|
|
13
15
|
const touched = useSyncExternalStore(
|
|
14
16
|
(cb) => store.subscribeField(name, cb),
|
|
17
|
+
() => store.getFieldTouched(name),
|
|
15
18
|
() => store.getFieldTouched(name)
|
|
16
19
|
);
|
|
17
20
|
const onChange = useCallback(
|