jcicl 2.0.1 → 3.0.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/FormFields/FormFields.js +4 -3
- package/FormInput/FormInput.d.ts +21 -0
- package/FormInput/FormInput.js +44 -33
- package/FormInput/index.d.ts +1 -1
- package/FormInput/index.js +3 -2
- package/LabeledCurrencyInput/LabeledCurrencyInput.d.ts +2 -4
- package/LabeledDateInput/LabeledDateInput.d.ts +13 -0
- package/LabeledDateInput/LabeledDateInput.js +75 -0
- package/LabeledDateInput/index.d.ts +1 -0
- package/LabeledDateInput/index.js +4 -0
- package/LabeledFormattedInput/LabeledFormattedInput.d.ts +2 -4
- package/LabeledFormattedInput/LabeledFormattedInput.js +52 -57
- package/LabeledInput/LabeledInput.d.ts +8 -4
- package/LabeledInput/LabeledInput.js +40 -26
- package/README.md +20 -0
- package/Table/Table.js +2013 -1998
- package/assets/style.css +1 -1
- package/assets/tailwind.css +1 -1
- package/index.d.ts +1 -0
- package/index.js +73 -71
- package/labeledFieldStyles.d.ts +18 -0
- package/labeledFieldStyles.js +12 -0
- package/package.json +1 -1
- package/utils.d.ts +1 -1
- package/utils.js +16 -14
- package/validators.d.ts +2 -0
- package/validators.js +24 -16
package/FormFields/FormFields.js
CHANGED
|
@@ -20,7 +20,8 @@ import "react-dom";
|
|
|
20
20
|
import "../Accordion/Accordion.js";
|
|
21
21
|
import "../ErrorBoundary/ErrorBoundary.js";
|
|
22
22
|
import "../InfoCard/InfoCard.js";
|
|
23
|
-
import "../
|
|
23
|
+
import "../theme.js";
|
|
24
|
+
import "../labeledFieldStyles.js";
|
|
24
25
|
import "../List/List.js";
|
|
25
26
|
import "../LogoLoop/LogoLoop.js";
|
|
26
27
|
import "../Pagination/Pagination.js";
|
|
@@ -35,7 +36,7 @@ import "../Nav/Nav.js";
|
|
|
35
36
|
import "../AuthContext/AuthProvider.js";
|
|
36
37
|
import "../AppContainer/AppContainer.js";
|
|
37
38
|
import "../DefaultTemplate/DefaultTemplate.js";
|
|
38
|
-
const
|
|
39
|
+
const Fo = ({
|
|
39
40
|
title: h,
|
|
40
41
|
fields: a,
|
|
41
42
|
columns: w,
|
|
@@ -104,5 +105,5 @@ const xo = ({
|
|
|
104
105
|
] });
|
|
105
106
|
};
|
|
106
107
|
export {
|
|
107
|
-
|
|
108
|
+
Fo as default
|
|
108
109
|
};
|
package/FormInput/FormInput.d.ts
CHANGED
|
@@ -22,5 +22,26 @@ export type FormInputProps = Partial<Omit<AllInputProps, ConflictingKeys | 'type
|
|
|
22
22
|
overrideValidation?: boolean;
|
|
23
23
|
customValidation?: InputValidationFunction;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* The field's validation message, or undefined when it passes. Pure and module-level so it can be
|
|
27
|
+
* exercised directly, and so the component doesn't have to hold it in state: validation is a
|
|
28
|
+
* function of the props, and the useEffect form it replaced cost a second render on every
|
|
29
|
+
* keystroke — callers routinely pass a fresh `customValidation` closure each render, which no
|
|
30
|
+
* dependency array can compare usefully. Computing it inline also lands the error on the same
|
|
31
|
+
* commit as the value rather than one render later.
|
|
32
|
+
*
|
|
33
|
+
* checkbox/radio wrap MUI Checkbox/Radio, which have no helper-text slot, so there's nowhere to
|
|
34
|
+
* surface a message — they're skipped entirely.
|
|
35
|
+
*/
|
|
36
|
+
export declare const resolveValidationError: ({ type, value, required, label, showError, overrideValidation, customValidation, }: {
|
|
37
|
+
type: FormInputType;
|
|
38
|
+
value: unknown;
|
|
39
|
+
required?: boolean;
|
|
40
|
+
label?: string;
|
|
41
|
+
showError?: boolean;
|
|
42
|
+
/** Skip the required and type-based rules, applying only `customValidation`. */
|
|
43
|
+
overrideValidation?: boolean;
|
|
44
|
+
customValidation?: InputValidationFunction;
|
|
45
|
+
}) => string | undefined;
|
|
25
46
|
export declare const FormInput: React.FC<FormInputProps>;
|
|
26
47
|
export default FormInput;
|
package/FormInput/FormInput.js
CHANGED
|
@@ -1,42 +1,53 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { LabeledCurrencyInput as
|
|
5
|
-
import { LabeledCheckbox as
|
|
6
|
-
import { LabeledRadio as
|
|
7
|
-
import { LabeledDropdown as
|
|
8
|
-
import { LabeledTextArea as
|
|
9
|
-
import { LabeledFormattedInput as
|
|
10
|
-
import { formattedOrMaskedTypes as
|
|
11
|
-
import { inputValidatorsByType as
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { LabeledInput as s } from "../LabeledInput/LabeledInput.js";
|
|
3
|
+
import { LabeledDateInput as u } from "../LabeledDateInput/LabeledDateInput.js";
|
|
4
|
+
import { LabeledCurrencyInput as c } from "../LabeledCurrencyInput/LabeledCurrencyInput.js";
|
|
5
|
+
import { LabeledCheckbox as b } from "../LabeledCheckbox/LabeledCheckbox.js";
|
|
6
|
+
import { LabeledRadio as x } from "../LabeledRadio/LabeledRadio.js";
|
|
7
|
+
import { LabeledDropdown as h } from "../LabeledDropdown/LabeledDropdown.js";
|
|
8
|
+
import { LabeledTextArea as L } from "../LabeledTextArea/LabeledTextArea.js";
|
|
9
|
+
import { LabeledFormattedInput as T } from "../LabeledFormattedInput/LabeledFormattedInput.js";
|
|
10
|
+
import { formattedOrMaskedTypes as v } from "../utils.js";
|
|
11
|
+
import { inputValidatorsByType as E } from "../validators.js";
|
|
12
|
+
const I = ({
|
|
13
|
+
type: o,
|
|
14
|
+
value: r,
|
|
15
|
+
required: m,
|
|
16
|
+
label: a,
|
|
17
|
+
showError: p,
|
|
18
|
+
overrideValidation: f = !1,
|
|
19
|
+
customValidation: d
|
|
20
|
+
}) => {
|
|
21
|
+
if (!p || o === "checkbox" || o === "radio") return;
|
|
22
|
+
const n = r === void 0 || r === "";
|
|
23
|
+
if (m && !f && n) return `${a ?? "This field"} is required.`;
|
|
24
|
+
if (n) return;
|
|
25
|
+
const e = f ? void 0 : E[o];
|
|
26
|
+
return (e == null ? void 0 : e(r)) ?? (d == null ? void 0 : d(r));
|
|
27
|
+
}, H = (o) => {
|
|
28
|
+
const { type: r = "text", required: m, label: a, value: p } = o, { customValidation: f, showError: d, overrideValidation: n = !1, ...e } = o, l = I({
|
|
29
|
+
type: r,
|
|
30
|
+
value: p,
|
|
31
|
+
required: m,
|
|
32
|
+
label: a,
|
|
33
|
+
showError: d,
|
|
34
|
+
overrideValidation: n,
|
|
35
|
+
customValidation: f
|
|
36
|
+
}), i = {
|
|
37
|
+
error: !!l || o.error,
|
|
38
|
+
helperText: l ?? o.helperText
|
|
29
39
|
};
|
|
30
|
-
return r === "dropdown" || r === "multiDropdown" ? /* @__PURE__ */
|
|
31
|
-
|
|
40
|
+
return r === "dropdown" || r === "multiDropdown" ? /* @__PURE__ */ t(h, { ...e, ...i }) : r === "checkbox" ? /* @__PURE__ */ t(b, { ...e }) : r === "radio" ? /* @__PURE__ */ t(x, { ...e }) : r === "currency" ? /* @__PURE__ */ t(c, { ...e, ...i }) : r === "textarea" ? /* @__PURE__ */ t(L, { ...e, ...i }) : r === "date" ? /* @__PURE__ */ t(u, { ...e, ...i }) : v.has(r) ? /* @__PURE__ */ t(
|
|
41
|
+
T,
|
|
32
42
|
{
|
|
33
43
|
...e,
|
|
34
44
|
type: r,
|
|
35
45
|
...i
|
|
36
46
|
}
|
|
37
|
-
) : /* @__PURE__ */
|
|
47
|
+
) : /* @__PURE__ */ t(s, { ...e, type: r, ...i });
|
|
38
48
|
};
|
|
39
49
|
export {
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
H as FormInput,
|
|
51
|
+
H as default,
|
|
52
|
+
I as resolveValidationError
|
|
42
53
|
};
|
package/FormInput/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default, type FormInputProps, type FormInputType } from './FormInput.tsx';
|
|
1
|
+
export { default, resolveValidationError, type FormInputProps, type FormInputType } from './FormInput.tsx';
|
package/FormInput/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { InputProps } from '../Input';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
displayMode?: boolean;
|
|
5
|
-
}
|
|
2
|
+
import { StyleProps } from '../labeledFieldStyles';
|
|
3
|
+
export type { StyleProps };
|
|
6
4
|
export type LabeledCurrencyInputProps = InputProps & StyleProps & {
|
|
7
5
|
label: string;
|
|
8
6
|
noLabel?: boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { InputProps } from '../Input';
|
|
2
|
+
import { StyleProps } from '../labeledFieldStyles';
|
|
3
|
+
export type { StyleProps };
|
|
4
|
+
export type LabeledDateInputProps = InputProps & StyleProps & {
|
|
5
|
+
label?: string;
|
|
6
|
+
noLabel?: boolean;
|
|
7
|
+
/** Earliest selectable date. Takes the `YYYY-MM-DD` a date input expects; widened to match LabeledInput. */
|
|
8
|
+
min?: string | number;
|
|
9
|
+
/** Latest selectable date. Takes the `YYYY-MM-DD` a date input expects; widened to match LabeledInput. */
|
|
10
|
+
max?: string | number;
|
|
11
|
+
};
|
|
12
|
+
export declare const LabeledDateInput: React.FC<LabeledDateInputProps>;
|
|
13
|
+
export default LabeledDateInput;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsxs as B, jsx as D } from "react/jsx-runtime";
|
|
2
|
+
import { useState as p, useRef as P } from "react";
|
|
3
|
+
import { cn as R } from "../cn.js";
|
|
4
|
+
import { Input as U } from "../Input/Input.js";
|
|
5
|
+
import j from "../theme.js";
|
|
6
|
+
import { muiDisabledClasses as q, labeledFieldClasses as G } from "../labeledFieldStyles.js";
|
|
7
|
+
const S = "That date doesn’t exist — check the day and month.", M = "That date doesn’t exist — your previous date was restored.", F = 1e3, L = (t) => /^\d{4}-\d{2}-\d{2}$/.test(t) && Number(t.slice(0, 4)) >= F, E = (t) => {
|
|
8
|
+
const [d, a, o] = String(t).split("-");
|
|
9
|
+
return a && o ? `${a}/${o}/${d}` : String(t);
|
|
10
|
+
}, K = ({
|
|
11
|
+
label: t,
|
|
12
|
+
grid: d = !0,
|
|
13
|
+
displayMode: a = !1,
|
|
14
|
+
noLabel: o = !1,
|
|
15
|
+
min: i,
|
|
16
|
+
max: u,
|
|
17
|
+
value: h,
|
|
18
|
+
...g
|
|
19
|
+
}) => {
|
|
20
|
+
var b;
|
|
21
|
+
const { onChange: m, onBlur: c, ...s } = g, [T, I] = p(null), [n, f] = p(void 0), v = P(null), _ = {
|
|
22
|
+
"--required-color": j.colors.gray,
|
|
23
|
+
"--input-base-width": d ? "100%" : "auto"
|
|
24
|
+
}, r = h == null ? "" : String(h), w = T ?? r, [N, V] = p(r);
|
|
25
|
+
r !== N && (V(r), r !== v.current && f(void 0));
|
|
26
|
+
const $ = (e) => {
|
|
27
|
+
if (e.validity.badInput)
|
|
28
|
+
return {
|
|
29
|
+
message: r ? M : S,
|
|
30
|
+
fromBadInput: !0
|
|
31
|
+
};
|
|
32
|
+
if (e.validity.rangeUnderflow && i != null)
|
|
33
|
+
return { message: `Date must be on or after ${E(i)}.`, fromBadInput: !1 };
|
|
34
|
+
if (e.validity.rangeOverflow && u != null)
|
|
35
|
+
return { message: `Date must be on or before ${E(u)}.`, fromBadInput: !1 };
|
|
36
|
+
}, y = (e) => {
|
|
37
|
+
v.current = e.target.value, m == null || m(e);
|
|
38
|
+
}, x = (e) => {
|
|
39
|
+
I(e.target.value), f(e.target.validity.badInput ? { message: S, fromBadInput: !0 } : void 0), L(e.target.value) && y(e);
|
|
40
|
+
}, A = (e) => {
|
|
41
|
+
const l = $(e.target);
|
|
42
|
+
I(null), f(l), !(l != null && l.fromBadInput) && e.target.value !== r && y(e), c == null || c(e);
|
|
43
|
+
}, C = n && (n.fromBadInput || !s.helperText) ? n.message : void 0;
|
|
44
|
+
return /* @__PURE__ */ B(
|
|
45
|
+
"div",
|
|
46
|
+
{
|
|
47
|
+
className: R("jcLabeledDateInput", G, a && q),
|
|
48
|
+
style: _,
|
|
49
|
+
children: [
|
|
50
|
+
!o && /* @__PURE__ */ B("span", { children: [
|
|
51
|
+
t,
|
|
52
|
+
g.required && /* @__PURE__ */ D("span", { className: "required", children: "*" }),
|
|
53
|
+
":"
|
|
54
|
+
] }),
|
|
55
|
+
/* @__PURE__ */ D(
|
|
56
|
+
U,
|
|
57
|
+
{
|
|
58
|
+
...s,
|
|
59
|
+
type: "date",
|
|
60
|
+
value: w,
|
|
61
|
+
onChange: x,
|
|
62
|
+
onBlur: A,
|
|
63
|
+
error: !!n || s.error,
|
|
64
|
+
helperText: C ?? s.helperText,
|
|
65
|
+
slotProps: { ...s.slotProps, htmlInput: { min: i, max: u, ...(b = s.slotProps) == null ? void 0 : b.htmlInput } }
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
export {
|
|
73
|
+
K as LabeledDateInput,
|
|
74
|
+
K as default
|
|
75
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, type LabeledDateInputProps } from './LabeledDateInput';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { InputProps } from '../Input';
|
|
2
2
|
import { FormatterFunction, MaskerFunction } from '../utils';
|
|
3
3
|
import { FormInputType } from '../inputTypes';
|
|
4
|
+
import { StyleProps } from '../labeledFieldStyles';
|
|
4
5
|
export type FormattedInputValue = string | undefined;
|
|
5
|
-
export
|
|
6
|
-
grid?: boolean;
|
|
7
|
-
displayMode?: boolean;
|
|
8
|
-
}
|
|
6
|
+
export type { StyleProps };
|
|
9
7
|
export type LabeledFormattedInputProps = InputProps & StyleProps & {
|
|
10
8
|
label?: string;
|
|
11
9
|
noLabel?: boolean;
|
|
@@ -1,88 +1,83 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { cn as
|
|
1
|
+
import { jsxs as b, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as B, useState as y, useLayoutEffect as G } from "react";
|
|
3
|
+
import { cn as E } from "../cn.js";
|
|
4
4
|
import { Input as H } from "../Input/Input.js";
|
|
5
5
|
import J from "../theme.js";
|
|
6
6
|
import "../utils.js";
|
|
7
7
|
import { findCursorFromDigitIndex as K } from "../cursorPositioning.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
label: q,
|
|
20
|
-
grid: B = !0,
|
|
21
|
-
displayMode: S = !1,
|
|
22
|
-
noLabel: k = !1,
|
|
23
|
-
limit: V,
|
|
8
|
+
import { muiDisabledClasses as Q, labeledFieldClasses as W } from "../labeledFieldStyles.js";
|
|
9
|
+
import { Button as X } from "../Button/Button.js";
|
|
10
|
+
import { formattersByType as Y } from "../formatters.js";
|
|
11
|
+
import { maskersByType as Z, defaultMasker as $ } from "../maskers.js";
|
|
12
|
+
import { E as ee, a as te } from "../.chunks/eye.js";
|
|
13
|
+
const fe = ({
|
|
14
|
+
label: N,
|
|
15
|
+
grid: R = !0,
|
|
16
|
+
displayMode: k = !1,
|
|
17
|
+
noLabel: w = !1,
|
|
18
|
+
limit: j,
|
|
24
19
|
type: t,
|
|
25
20
|
value: n,
|
|
26
|
-
defaultValue:
|
|
27
|
-
masked:
|
|
28
|
-
formatFunction:
|
|
29
|
-
maskFunction:
|
|
30
|
-
...
|
|
21
|
+
defaultValue: F,
|
|
22
|
+
masked: c,
|
|
23
|
+
formatFunction: q,
|
|
24
|
+
maskFunction: x,
|
|
25
|
+
...I
|
|
31
26
|
}) => {
|
|
32
|
-
const
|
|
27
|
+
const D = {
|
|
33
28
|
"--required-color": J.colors.gray,
|
|
34
|
-
"--input-base-width":
|
|
35
|
-
}, o =
|
|
29
|
+
"--input-base-width": R ? "100%" : "auto"
|
|
30
|
+
}, o = q ?? (t ? Y[t] : void 0);
|
|
36
31
|
let s;
|
|
37
|
-
|
|
38
|
-
const u = !!(
|
|
32
|
+
x ? s = x : c && (s = t && Z[t] || $);
|
|
33
|
+
const u = !!(c && s), { onChange: i, onFocus: m, onBlur: d, ...p } = I, f = B(null), h = B(null), [g, C] = y(null), [L, S] = y(!1), [M, T] = y(!1), r = !u || L || M, v = g ?? n ?? F, l = o ? o(v)[0] : String(v ?? ""), P = s ? s(v) : l, z = r ? l : P, O = (e) => {
|
|
39
34
|
const A = e.target.selectionStart ?? 0;
|
|
40
|
-
h.current = e.target.value.slice(0, A).replace(/\D/g, "").length,
|
|
41
|
-
}, O = (e) => {
|
|
42
|
-
F(!0), d == null || d(e);
|
|
35
|
+
h.current = e.target.value.slice(0, A).replace(/\D/g, "").length, C(e.target.value), i == null || i(e);
|
|
43
36
|
}, U = (e) => {
|
|
44
|
-
|
|
37
|
+
S(!0), m == null || m(e);
|
|
38
|
+
}, _ = (e) => {
|
|
39
|
+
S(!1), n !== void 0 && C(null), d == null || d(e);
|
|
45
40
|
};
|
|
46
41
|
G(() => {
|
|
47
42
|
if (!f.current || h.current == null || !r || !o)
|
|
48
43
|
return;
|
|
49
|
-
const e = K(
|
|
44
|
+
const e = K(l, h.current);
|
|
50
45
|
f.current.setSelectionRange(e, e);
|
|
51
|
-
}, [
|
|
52
|
-
const
|
|
53
|
-
return /* @__PURE__ */
|
|
46
|
+
}, [F, l, o, r, g, n]);
|
|
47
|
+
const V = u ? r ? ee : te : null;
|
|
48
|
+
return /* @__PURE__ */ b(
|
|
54
49
|
"div",
|
|
55
50
|
{
|
|
56
|
-
className:
|
|
57
|
-
style:
|
|
51
|
+
className: E("jcLabeledFormattedInput", W, k && Q),
|
|
52
|
+
style: D,
|
|
58
53
|
children: [
|
|
59
|
-
!
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
!w && /* @__PURE__ */ b("span", { children: [
|
|
55
|
+
N,
|
|
56
|
+
I.required && /* @__PURE__ */ a("span", { className: "required", children: "*" }),
|
|
62
57
|
":"
|
|
63
58
|
] }),
|
|
64
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ a(
|
|
65
60
|
H,
|
|
66
61
|
{
|
|
67
|
-
...
|
|
62
|
+
...p,
|
|
68
63
|
type: t,
|
|
69
64
|
inputRef: f,
|
|
70
|
-
value:
|
|
71
|
-
onChange:
|
|
72
|
-
onFocus:
|
|
73
|
-
onBlur:
|
|
74
|
-
autoComplete:
|
|
75
|
-
className:
|
|
76
|
-
slotProps: { htmlInput: { limit:
|
|
65
|
+
value: z,
|
|
66
|
+
onChange: O,
|
|
67
|
+
onFocus: U,
|
|
68
|
+
onBlur: _,
|
|
69
|
+
autoComplete: c ? "off" : void 0,
|
|
70
|
+
className: E(p.className, u && "[&_input]:pr-[20px]"),
|
|
71
|
+
slotProps: { htmlInput: { limit: j }, ...p.slotProps }
|
|
77
72
|
}
|
|
78
73
|
),
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
V && /* @__PURE__ */ a(
|
|
75
|
+
X,
|
|
81
76
|
{
|
|
82
77
|
variant: "unstyled",
|
|
83
|
-
onClick: () =>
|
|
78
|
+
onClick: () => T((e) => !e),
|
|
84
79
|
className: "!min-w-0 !max-h-[18px] !p-0 opacity-70 !ml-[-27px]",
|
|
85
|
-
children: /* @__PURE__ */
|
|
80
|
+
children: /* @__PURE__ */ a(V, { size: 18 })
|
|
86
81
|
}
|
|
87
82
|
)
|
|
88
83
|
]
|
|
@@ -90,6 +85,6 @@ const ee = "flex flex-nowrap gap-[9px] font-['Roboto',sans-serif]", te = "[&_spa
|
|
|
90
85
|
);
|
|
91
86
|
};
|
|
92
87
|
export {
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
fe as LabeledFormattedInput,
|
|
89
|
+
fe as default
|
|
95
90
|
};
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { InputProps } from '../Input';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
displayMode?: boolean;
|
|
5
|
-
}
|
|
2
|
+
import { StyleProps } from '../labeledFieldStyles';
|
|
3
|
+
export type { StyleProps };
|
|
6
4
|
export type LabeledInputProps = InputProps & StyleProps & {
|
|
7
5
|
label?: string;
|
|
8
6
|
noLabel?: boolean;
|
|
9
7
|
limit?: number;
|
|
8
|
+
/** @deprecated Use `min` — it accepts the same numbers and also the `YYYY-MM-DD` a date needs. */
|
|
10
9
|
minLimit?: number;
|
|
10
|
+
/** @deprecated Use `max` — it accepts the same numbers and also the `YYYY-MM-DD` a date needs. */
|
|
11
11
|
maxLimit?: number;
|
|
12
|
+
/** Lower bound on the underlying input. Only limits the number spinner; a lower value can still be typed. */
|
|
13
|
+
min?: string | number;
|
|
14
|
+
/** Upper bound on the underlying input. Only limits the number spinner; a higher value can still be typed. */
|
|
15
|
+
max?: string | number;
|
|
12
16
|
};
|
|
13
17
|
export declare const LabeledInput: React.FC<LabeledInputProps>;
|
|
14
18
|
export default LabeledInput;
|
|
@@ -1,44 +1,58 @@
|
|
|
1
|
-
import { jsxs as s, jsx as
|
|
2
|
-
import { cn as
|
|
3
|
-
import { Input as
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
x,
|
|
9
|
-
h,
|
|
10
|
-
_
|
|
11
|
-
), y = ({
|
|
12
|
-
label: o,
|
|
1
|
+
import { jsxs as s, jsx as l } from "react/jsx-runtime";
|
|
2
|
+
import { cn as f } from "../cn.js";
|
|
3
|
+
import { Input as h } from "../Input/Input.js";
|
|
4
|
+
import b from "../theme.js";
|
|
5
|
+
import { muiDisabledClasses as I, labeledFieldClasses as x } from "../labeledFieldStyles.js";
|
|
6
|
+
const L = ({
|
|
7
|
+
label: t,
|
|
13
8
|
grid: a = !0,
|
|
14
|
-
displayMode:
|
|
15
|
-
noLabel:
|
|
16
|
-
limit:
|
|
9
|
+
displayMode: o = !1,
|
|
10
|
+
noLabel: m = !1,
|
|
11
|
+
limit: i,
|
|
17
12
|
minLimit: d,
|
|
18
|
-
maxLimit:
|
|
13
|
+
maxLimit: n,
|
|
14
|
+
min: p,
|
|
15
|
+
max: c,
|
|
19
16
|
...e
|
|
20
17
|
}) => {
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
var r;
|
|
19
|
+
const u = {
|
|
20
|
+
"--required-color": b.colors.gray,
|
|
23
21
|
"--input-base-width": a ? "100%" : "auto"
|
|
24
22
|
};
|
|
25
23
|
return /* @__PURE__ */ s(
|
|
26
24
|
"div",
|
|
27
25
|
{
|
|
28
|
-
className:
|
|
29
|
-
style:
|
|
26
|
+
className: f("jcLabeledInput", x, o && I),
|
|
27
|
+
style: u,
|
|
30
28
|
children: [
|
|
31
|
-
!
|
|
32
|
-
|
|
33
|
-
e.required && /* @__PURE__ */
|
|
29
|
+
!m && /* @__PURE__ */ s("span", { children: [
|
|
30
|
+
t,
|
|
31
|
+
e.required && /* @__PURE__ */ l("span", { className: "required", children: "*" }),
|
|
34
32
|
":"
|
|
35
33
|
] }),
|
|
36
|
-
/* @__PURE__ */
|
|
34
|
+
/* @__PURE__ */ l(
|
|
35
|
+
h,
|
|
36
|
+
{
|
|
37
|
+
...e,
|
|
38
|
+
slotProps: {
|
|
39
|
+
...e.slotProps,
|
|
40
|
+
// Merged rather than replaced: overwriting the whole slotProps object left callers with
|
|
41
|
+
// no way to reach htmlInput, which is the only route to min/max on a date field.
|
|
42
|
+
htmlInput: {
|
|
43
|
+
limit: i,
|
|
44
|
+
min: p ?? d,
|
|
45
|
+
max: c ?? n,
|
|
46
|
+
...(r = e.slotProps) == null ? void 0 : r.htmlInput
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
)
|
|
37
51
|
]
|
|
38
52
|
}
|
|
39
53
|
);
|
|
40
54
|
};
|
|
41
55
|
export {
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
L as LabeledInput,
|
|
57
|
+
L as default
|
|
44
58
|
};
|
package/README.md
CHANGED
|
@@ -66,6 +66,26 @@ Factory function that creates typed React Context + Provider pairs for form stat
|
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
69
|
+
## Migrating to 3.0.0
|
|
70
|
+
|
|
71
|
+
`type="date"` fields changed behavior. Nothing needs renaming, but three things now act differently and are worth verifying in any app that has date inputs.
|
|
72
|
+
|
|
73
|
+
**1. Date fields are validated.** `date` is now registered in `inputValidatorsByType`, so a value that isn't a real calendar date in `YYYY-MM-DD` form fails validation — including `2025-02-29` and `2025-04-31`, which the browser silently blanks rather than rejecting. Apps that call `inputValidatorsByType` themselves (a submit-time `validateFormFields`, say) will start blocking saves that previously went through.
|
|
74
|
+
|
|
75
|
+
Any date field fed an ISO *datetime* (`2026-08-07T14:03:00`, typical of a `DateTime` rather than a `DateOnly` on the server) will now report as invalid. Trim it to the first ten characters before it reaches the field.
|
|
76
|
+
|
|
77
|
+
**2. `onChange` fires at different moments.** `FormInput` renders the new `LabeledDateInput` for `type="date"`, which no longer emits every keystroke. The native control reports each digit typed into the year segment as a whole date (typing `1985` emits `0001`, `0019`, `0198`, `1985`), and forwarding those intermediates made a controlled parent write the value back mid-edit and reset the browser's year buffer. It now fires only for a complete date, plus once on blur. Anything driven off a date field per keystroke — a fetch keyed on the date, an autofill extension — sees fewer calls with no partial garbage.
|
|
78
|
+
|
|
79
|
+
An impossible date is *not* committed: the field snaps back to its last valid value and shows the error, rather than propagating the empty string the browser produced and erasing the stored date.
|
|
80
|
+
|
|
81
|
+
**3. The wrapper class changed.** Date fields now render inside `.jcLabeledDateInput` instead of `.jcLabeledInput`. Only relevant if you target that class in a selector or `!`-prefixed override.
|
|
82
|
+
|
|
83
|
+
**4. `minLimit`/`maxLimit` are ignored on date fields.** They still work everywhere else, but the date field reads `min`/`max` only. If you bounded a date with `minLimit`, rename it — the bound is dropped silently otherwise, since neither is a real constraint the browser reports on.
|
|
84
|
+
|
|
85
|
+
Also in this release: `min`/`max` are exposed on `LabeledInput` (accepting the `YYYY-MM-DD` a date needs, not just numbers), and `slotProps` passed by a caller is merged rather than replaced — previously it was overwritten, which is what made `min`/`max` unreachable. `minLimit`/`maxLimit` still work but are deprecated in favor of `min`/`max` everywhere.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
69
89
|
## Development
|
|
70
90
|
|
|
71
91
|
### Getting started
|