jcicl 2.0.2 → 4.0.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/DesktopStepper/DesktopStepper.d.ts +6 -2
- package/DesktopStepper/DesktopStepper.js +166 -125
- 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/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
|
@@ -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
|