@axenstudio/axen-form 0.1.10 → 0.1.12
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 +783 -270
- package/dist/core/dateUtils.cjs +7 -3
- package/dist/core/dateUtils.d.ts +1 -1
- package/dist/core/dateUtils.d.ts.map +1 -1
- package/dist/core/dateUtils.js +7 -3
- package/dist/core/validation.cjs +4 -1
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +4 -1
- package/dist/fields/AutocompleteField/AutocompleteField.cjs +32 -32
- package/dist/fields/AutocompleteField/AutocompleteField.js +32 -32
- package/dist/fields/AutocompleteField/AutocompleteField.module.css.cjs +34 -13
- package/dist/fields/AutocompleteField/AutocompleteField.module.css.js +34 -13
- package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.cjs +90 -88
- package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.d.ts.map +1 -1
- package/dist/fields/AutocompleteMultiField/AutocompleteMultiField.js +90 -88
- package/dist/fields/AutocompletePredictField/AutocompletePredictField.cjs +81 -64
- package/dist/fields/AutocompletePredictField/AutocompletePredictField.d.ts.map +1 -1
- package/dist/fields/AutocompletePredictField/AutocompletePredictField.js +81 -64
- package/dist/fields/CheckboxField/CheckboxField.module.css.cjs +12 -0
- package/dist/fields/CheckboxField/CheckboxField.module.css.js +12 -0
- package/dist/fields/ColorField/ColorField.module.css.cjs +12 -0
- package/dist/fields/ColorField/ColorField.module.css.js +12 -0
- package/dist/fields/DateField/DateField.cjs +56 -4
- package/dist/fields/DateField/DateField.d.ts +1 -1
- package/dist/fields/DateField/DateField.d.ts.map +1 -1
- package/dist/fields/DateField/DateField.js +56 -4
- package/dist/fields/DateField/DatePicker.cjs +194 -0
- package/dist/fields/DateField/DatePicker.d.ts +11 -0
- package/dist/fields/DateField/DatePicker.d.ts.map +1 -0
- package/dist/fields/DateField/DatePicker.js +194 -0
- package/dist/fields/DateField/DatePicker.module.css.cjs +62 -0
- package/dist/fields/DateField/DatePicker.module.css.js +62 -0
- package/dist/fields/DateTimeField/DateTimeField.cjs +126 -8
- package/dist/fields/DateTimeField/DateTimeField.d.ts +2 -1
- package/dist/fields/DateTimeField/DateTimeField.d.ts.map +1 -1
- package/dist/fields/DateTimeField/DateTimeField.js +126 -8
- package/dist/fields/PasswordField/PasswordField.module.css.cjs +12 -0
- package/dist/fields/PasswordField/PasswordField.module.css.js +12 -0
- package/dist/fields/RadioField/RadioField.module.css.cjs +12 -0
- package/dist/fields/RadioField/RadioField.module.css.js +12 -0
- package/dist/fields/SelectField/SelectField.cjs +6 -1
- package/dist/fields/SelectField/SelectField.d.ts.map +1 -1
- package/dist/fields/SelectField/SelectField.js +6 -1
- package/dist/fields/SliderField/SliderField.module.css.cjs +15 -3
- package/dist/fields/SliderField/SliderField.module.css.js +15 -3
- package/dist/fields/SwitchField/SwitchField.module.css.cjs +12 -0
- package/dist/fields/SwitchField/SwitchField.module.css.js +12 -0
- package/dist/fields/TimeField/TimeField.cjs +60 -5
- package/dist/fields/TimeField/TimeField.d.ts +2 -1
- package/dist/fields/TimeField/TimeField.d.ts.map +1 -1
- package/dist/fields/TimeField/TimeField.js +60 -5
- package/dist/fields/TimeField/TimePicker.cjs +182 -0
- package/dist/fields/TimeField/TimePicker.d.ts +11 -0
- package/dist/fields/TimeField/TimePicker.d.ts.map +1 -0
- package/dist/fields/TimeField/TimePicker.js +182 -0
- package/dist/fields/TimeField/TimePicker.module.css.cjs +50 -0
- package/dist/fields/TimeField/TimePicker.module.css.js +50 -0
- package/dist/fields/defaultPlaceholders.cjs +1 -0
- package/dist/fields/defaultPlaceholders.d.ts.map +1 -1
- package/dist/fields/defaultPlaceholders.js +1 -0
- package/dist/fields/fieldBase.module.css.cjs +373 -18
- package/dist/fields/fieldBase.module.css.js +373 -18
- package/dist/fields/icons.cjs +2 -0
- package/dist/fields/icons.d.ts +4 -0
- package/dist/fields/icons.d.ts.map +1 -1
- package/dist/fields/icons.js +2 -0
- package/dist/index.cjs +230 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +230 -3
- package/dist/layout/Box/Box.module.css.cjs +12 -0
- package/dist/layout/Box/Box.module.css.js +12 -0
- package/dist/layout/Divider/Divider.module.css.cjs +12 -0
- package/dist/layout/Divider/Divider.module.css.js +12 -0
- package/dist/layout/Grid/Grid.module.css.cjs +12 -0
- package/dist/layout/Grid/Grid.module.css.js +12 -0
- package/dist/layout/Stack/Stack.module.css.cjs +12 -0
- package/dist/layout/Stack/Stack.module.css.js +12 -0
- package/dist/react/AxenForm.cjs +228 -3
- package/dist/react/AxenForm.js +228 -3
- package/dist/react/fieldGroup.module.css.cjs +12 -0
- package/dist/react/fieldGroup.module.css.js +12 -0
- package/dist/react/gridCell.module.css.cjs +12 -0
- package/dist/react/gridCell.module.css.js +12 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -9
- package/dist/axen-form.css +0 -1057
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
(function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
try {
|
|
4
|
+
if (typeof document != "undefined") {
|
|
5
|
+
var elementStyle = document.createElement("style");
|
|
6
|
+
elementStyle.appendChild(document.createTextNode("._sliderWrap_1x3d4_1 {\n display: flex;\n align-items: center;\n gap: var(--axen-space-md);\n min-height: var(--axen-field-min-height);\n}\n\n._slider_1x3d4_1 {\n flex: 1;\n min-width: 0;\n width: 100%;\n height: 6px;\n appearance: none;\n background: var(--axen-color-border);\n border-radius: var(--axen-border-radius-pill);\n outline: none;\n cursor: pointer;\n transition: background var(--axen-transition-fast);\n}\n\n._slider_1x3d4_1::-webkit-slider-thumb {\n appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: var(--axen-color-primary);\n border: 2px solid var(--axen-color-bg);\n box-shadow: var(--axen-shadow-sm);\n cursor: pointer;\n transition:\n background var(--axen-transition-fast),\n transform var(--axen-transition-fast);\n}\n\n._slider_1x3d4_1::-webkit-slider-thumb:hover {\n background: var(--axen-color-primary-hover);\n transform: scale(1.15);\n}\n\n._slider_1x3d4_1:focus-visible::-webkit-slider-thumb {\n box-shadow: var(--axen-shadow-focus);\n}\n\n._slider_1x3d4_1::-moz-range-thumb {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: var(--axen-color-primary);\n border: 2px solid var(--axen-color-bg);\n box-shadow: var(--axen-shadow-sm);\n cursor: pointer;\n}\n\n._slider_1x3d4_1:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n._output_1x3d4_59 {\n min-width: 2.5em;\n text-align: center;\n font-size: var(--axen-font-size-sm);\n font-weight: var(--axen-font-weight-medium);\n color: var(--axen-color-text);\n}\n\n/* Touch target for mobile */\n@media (max-width: 599px) {\n ._slider_1x3d4_1::-webkit-slider-thumb {\n width: 28px;\n height: 28px;\n }\n\n ._slider_1x3d4_1::-moz-range-thumb {\n width: 28px;\n height: 28px;\n }\n}"));
|
|
7
|
+
document.head.appendChild(elementStyle);
|
|
8
|
+
}
|
|
9
|
+
} catch (e) {
|
|
10
|
+
console.error("vite-plugin-css-injected-by-js", e);
|
|
11
|
+
}
|
|
12
|
+
})();
|
|
13
|
+
const sliderWrap = "_sliderWrap_1x3d4_1";
|
|
14
|
+
const slider = "_slider_1x3d4_1";
|
|
15
|
+
const output = "_output_1x3d4_59";
|
|
4
16
|
const localStyles = {
|
|
5
17
|
sliderWrap,
|
|
6
18
|
slider,
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
try {
|
|
4
|
+
if (typeof document != "undefined") {
|
|
5
|
+
var elementStyle = document.createElement("style");
|
|
6
|
+
elementStyle.appendChild(document.createTextNode("._switchLabel_1itxk_1 {\n cursor: pointer;\n}\n\n._switchTrack_1itxk_5 {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 44px;\n height: 24px;\n background-color: var(--axen-color-border);\n border-radius: var(--axen-border-radius-pill);\n transition: background-color var(--axen-transition-fast);\n flex-shrink: 0;\n}\n\n._switchInput_1itxk_17 {\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n opacity: 0;\n cursor: pointer;\n}\n\n._switchInput_1itxk_17:checked + ._switchThumb_1itxk_27 {\n transform: translateX(20px);\n}\n\n._switchInput_1itxk_17:checked ~ ._switchThumb_1itxk_27 {\n transform: translateX(20px);\n}\n\n._switchTrack_1itxk_5:has(._switchInput_1itxk_17:checked) {\n background-color: var(--axen-color-primary);\n}\n\n._switchInput_1itxk_17:focus-visible ~ ._switchThumb_1itxk_27 {\n box-shadow: var(--axen-shadow-focus);\n}\n\n._switchInput_1itxk_17:disabled {\n cursor: not-allowed;\n}\n\n._switchTrack_1itxk_5:has(._switchInput_1itxk_17:disabled) {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n._switchThumb_1itxk_27 {\n position: absolute;\n left: 2px;\n width: 20px;\n height: 20px;\n background-color: var(--axen-color-bg);\n border-radius: 50%;\n box-shadow: var(--axen-shadow-sm);\n transition: transform var(--axen-transition-fast);\n pointer-events: none;\n}\n\n/* Mobile: larger touch target */\n@media (max-width: 599px) {\n ._switchTrack_1itxk_5 {\n width: 52px;\n height: 28px;\n }\n\n ._switchThumb_1itxk_27 {\n width: 24px;\n height: 24px;\n }\n\n ._switchInput_1itxk_17:checked ~ ._switchThumb_1itxk_27 {\n transform: translateX(24px);\n }\n}"));
|
|
7
|
+
document.head.appendChild(elementStyle);
|
|
8
|
+
}
|
|
9
|
+
} catch (e) {
|
|
10
|
+
console.error("vite-plugin-css-injected-by-js", e);
|
|
11
|
+
}
|
|
12
|
+
})();
|
|
1
13
|
"use strict";
|
|
2
14
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
15
|
const switchLabel = "_switchLabel_1itxk_1";
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
try {
|
|
4
|
+
if (typeof document != "undefined") {
|
|
5
|
+
var elementStyle = document.createElement("style");
|
|
6
|
+
elementStyle.appendChild(document.createTextNode("._switchLabel_1itxk_1 {\n cursor: pointer;\n}\n\n._switchTrack_1itxk_5 {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 44px;\n height: 24px;\n background-color: var(--axen-color-border);\n border-radius: var(--axen-border-radius-pill);\n transition: background-color var(--axen-transition-fast);\n flex-shrink: 0;\n}\n\n._switchInput_1itxk_17 {\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n opacity: 0;\n cursor: pointer;\n}\n\n._switchInput_1itxk_17:checked + ._switchThumb_1itxk_27 {\n transform: translateX(20px);\n}\n\n._switchInput_1itxk_17:checked ~ ._switchThumb_1itxk_27 {\n transform: translateX(20px);\n}\n\n._switchTrack_1itxk_5:has(._switchInput_1itxk_17:checked) {\n background-color: var(--axen-color-primary);\n}\n\n._switchInput_1itxk_17:focus-visible ~ ._switchThumb_1itxk_27 {\n box-shadow: var(--axen-shadow-focus);\n}\n\n._switchInput_1itxk_17:disabled {\n cursor: not-allowed;\n}\n\n._switchTrack_1itxk_5:has(._switchInput_1itxk_17:disabled) {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n._switchThumb_1itxk_27 {\n position: absolute;\n left: 2px;\n width: 20px;\n height: 20px;\n background-color: var(--axen-color-bg);\n border-radius: 50%;\n box-shadow: var(--axen-shadow-sm);\n transition: transform var(--axen-transition-fast);\n pointer-events: none;\n}\n\n/* Mobile: larger touch target */\n@media (max-width: 599px) {\n ._switchTrack_1itxk_5 {\n width: 52px;\n height: 28px;\n }\n\n ._switchThumb_1itxk_27 {\n width: 24px;\n height: 24px;\n }\n\n ._switchInput_1itxk_17:checked ~ ._switchThumb_1itxk_27 {\n transform: translateX(24px);\n }\n}"));
|
|
7
|
+
document.head.appendChild(elementStyle);
|
|
8
|
+
}
|
|
9
|
+
} catch (e) {
|
|
10
|
+
console.error("vite-plugin-css-injected-by-js", e);
|
|
11
|
+
}
|
|
12
|
+
})();
|
|
1
13
|
const switchLabel = "_switchLabel_1itxk_1";
|
|
2
14
|
const switchTrack = "_switchTrack_1itxk_5";
|
|
3
15
|
const switchInput = "_switchInput_1itxk_17";
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
4
5
|
const dateUtils = require("../../core/dateUtils.cjs");
|
|
5
6
|
const fieldBase_module = require("../fieldBase.module.css.cjs");
|
|
6
7
|
const fieldUtils = require("../fieldUtils.cjs");
|
|
7
8
|
const iconUtils = require("../iconUtils.cjs");
|
|
9
|
+
const TimePicker = require("./TimePicker.cjs");
|
|
8
10
|
function TimeField({
|
|
9
11
|
name,
|
|
10
12
|
value,
|
|
@@ -19,16 +21,46 @@ function TimeField({
|
|
|
19
21
|
required,
|
|
20
22
|
locale,
|
|
21
23
|
ampm,
|
|
22
|
-
icon
|
|
24
|
+
icon,
|
|
25
|
+
form,
|
|
26
|
+
showSeconds
|
|
23
27
|
}) {
|
|
28
|
+
const [isOpen, setIsOpen] = react.useState(false);
|
|
29
|
+
const wrapperRef = react.useRef(null);
|
|
24
30
|
const aria = fieldUtils.ariaProps(name, { error, helperText, required, label });
|
|
25
31
|
const resolvedLocale = locale ?? dateUtils.getDefaultLocale();
|
|
26
32
|
const resolvedIcon = iconUtils.resolveFieldIcon(icon, "time");
|
|
33
|
+
const resolvedShowSeconds = showSeconds === true;
|
|
27
34
|
const timeValue = typeof value === "string" ? value : "";
|
|
28
|
-
const displayText = timeValue ? dateUtils.formatTimeLocale(timeValue, resolvedLocale, ampm) : "";
|
|
35
|
+
const displayText = timeValue ? dateUtils.formatTimeLocale(timeValue, resolvedLocale, ampm, resolvedShowSeconds) : "";
|
|
29
36
|
const handleChange = (e) => {
|
|
30
37
|
onChange(e);
|
|
31
38
|
};
|
|
39
|
+
const openPicker = react.useCallback(() => {
|
|
40
|
+
if (!disabled && !readOnly) setIsOpen(true);
|
|
41
|
+
}, [disabled, readOnly]);
|
|
42
|
+
const handleApply = react.useCallback(
|
|
43
|
+
(isoTime) => {
|
|
44
|
+
form.setFieldValue(name, isoTime);
|
|
45
|
+
setIsOpen(false);
|
|
46
|
+
},
|
|
47
|
+
[form, name]
|
|
48
|
+
);
|
|
49
|
+
const handleClose = react.useCallback(() => {
|
|
50
|
+
setIsOpen(false);
|
|
51
|
+
}, []);
|
|
52
|
+
const handleBlur = react.useCallback(
|
|
53
|
+
(e) => {
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
var _a;
|
|
56
|
+
if (!((_a = wrapperRef.current) == null ? void 0 : _a.contains(document.activeElement))) {
|
|
57
|
+
setIsOpen(false);
|
|
58
|
+
onBlur(e);
|
|
59
|
+
}
|
|
60
|
+
}, 150);
|
|
61
|
+
},
|
|
62
|
+
[onBlur]
|
|
63
|
+
);
|
|
32
64
|
const inputEl = /* @__PURE__ */ jsxRuntime.jsx(
|
|
33
65
|
"input",
|
|
34
66
|
{
|
|
@@ -36,8 +68,9 @@ function TimeField({
|
|
|
36
68
|
type: "time",
|
|
37
69
|
name,
|
|
38
70
|
value: timeValue,
|
|
71
|
+
step: resolvedShowSeconds ? 1 : 60,
|
|
39
72
|
onChange: handleChange,
|
|
40
|
-
onBlur,
|
|
73
|
+
onBlur: handleBlur,
|
|
41
74
|
placeholder,
|
|
42
75
|
disabled,
|
|
43
76
|
readOnly,
|
|
@@ -45,7 +78,7 @@ function TimeField({
|
|
|
45
78
|
className: fieldUtils.cx(fieldBase_module.default.input, resolvedIcon && fieldBase_module.default.inputWithIcon, error && fieldBase_module.default.inputError)
|
|
46
79
|
}
|
|
47
80
|
);
|
|
48
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: fieldBase_module.default.wrapper, children: [
|
|
81
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: fieldBase_module.default.wrapper, ref: wrapperRef, style: { position: "relative" }, children: [
|
|
49
82
|
label && /* @__PURE__ */ jsxRuntime.jsx(
|
|
50
83
|
"label",
|
|
51
84
|
{
|
|
@@ -56,9 +89,31 @@ function TimeField({
|
|
|
56
89
|
}
|
|
57
90
|
),
|
|
58
91
|
resolvedIcon ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: fieldBase_module.default.inputIconWrapper, children: [
|
|
59
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
92
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
93
|
+
"button",
|
|
94
|
+
{
|
|
95
|
+
type: "button",
|
|
96
|
+
className: fieldBase_module.default.fieldIconClickable,
|
|
97
|
+
onClick: openPicker,
|
|
98
|
+
disabled: disabled || readOnly,
|
|
99
|
+
"aria-label": "Open time picker",
|
|
100
|
+
tabIndex: -1,
|
|
101
|
+
children: resolvedIcon
|
|
102
|
+
}
|
|
103
|
+
),
|
|
60
104
|
inputEl
|
|
61
105
|
] }) : inputEl,
|
|
106
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
107
|
+
TimePicker.TimePicker,
|
|
108
|
+
{
|
|
109
|
+
value: timeValue,
|
|
110
|
+
showSeconds: resolvedShowSeconds,
|
|
111
|
+
ampm: ampm === true,
|
|
112
|
+
pickerId: `${name}-timepicker`,
|
|
113
|
+
onApply: handleApply,
|
|
114
|
+
onClose: handleClose
|
|
115
|
+
}
|
|
116
|
+
),
|
|
62
117
|
displayText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: fieldBase_module.default.helperText, "aria-hidden": "true", children: displayText }),
|
|
63
118
|
helperText && /* @__PURE__ */ jsxRuntime.jsx(
|
|
64
119
|
"span",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FieldComponentProps } from '../../types';
|
|
2
|
-
export declare function TimeField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, locale, ampm, icon, }: Readonly<FieldComponentProps & {
|
|
2
|
+
export declare function TimeField({ name, value, onChange, onBlur, error, helperText, label, placeholder, disabled, readOnly, required, locale, ampm, icon, form, showSeconds, }: Readonly<FieldComponentProps & {
|
|
3
3
|
locale?: string;
|
|
4
4
|
ampm?: boolean;
|
|
5
|
+
showSeconds?: boolean;
|
|
5
6
|
}>): import("react/jsx-runtime").JSX.Element;
|
|
6
7
|
//# sourceMappingURL=TimeField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeField.d.ts","sourceRoot":"","sources":["../../../src/fields/TimeField/TimeField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeField.d.ts","sourceRoot":"","sources":["../../../src/fields/TimeField/TimeField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAMvD,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,UAAU,EACV,KAAK,EACL,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,WAAW,GACZ,EAAE,QAAQ,CAAC,mBAAmB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,2CAuH5F"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useCallback } from "react";
|
|
2
3
|
import { formatTimeLocale, getDefaultLocale } from "../../core/dateUtils.js";
|
|
3
4
|
import styles from "../fieldBase.module.css.js";
|
|
4
5
|
import { ariaProps, cx, labelId, helperId } from "../fieldUtils.js";
|
|
5
6
|
import { resolveFieldIcon } from "../iconUtils.js";
|
|
7
|
+
import { TimePicker } from "./TimePicker.js";
|
|
6
8
|
function TimeField({
|
|
7
9
|
name,
|
|
8
10
|
value,
|
|
@@ -17,16 +19,46 @@ function TimeField({
|
|
|
17
19
|
required,
|
|
18
20
|
locale,
|
|
19
21
|
ampm,
|
|
20
|
-
icon
|
|
22
|
+
icon,
|
|
23
|
+
form,
|
|
24
|
+
showSeconds
|
|
21
25
|
}) {
|
|
26
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
27
|
+
const wrapperRef = useRef(null);
|
|
22
28
|
const aria = ariaProps(name, { error, helperText, required, label });
|
|
23
29
|
const resolvedLocale = locale ?? getDefaultLocale();
|
|
24
30
|
const resolvedIcon = resolveFieldIcon(icon, "time");
|
|
31
|
+
const resolvedShowSeconds = showSeconds === true;
|
|
25
32
|
const timeValue = typeof value === "string" ? value : "";
|
|
26
|
-
const displayText = timeValue ? formatTimeLocale(timeValue, resolvedLocale, ampm) : "";
|
|
33
|
+
const displayText = timeValue ? formatTimeLocale(timeValue, resolvedLocale, ampm, resolvedShowSeconds) : "";
|
|
27
34
|
const handleChange = (e) => {
|
|
28
35
|
onChange(e);
|
|
29
36
|
};
|
|
37
|
+
const openPicker = useCallback(() => {
|
|
38
|
+
if (!disabled && !readOnly) setIsOpen(true);
|
|
39
|
+
}, [disabled, readOnly]);
|
|
40
|
+
const handleApply = useCallback(
|
|
41
|
+
(isoTime) => {
|
|
42
|
+
form.setFieldValue(name, isoTime);
|
|
43
|
+
setIsOpen(false);
|
|
44
|
+
},
|
|
45
|
+
[form, name]
|
|
46
|
+
);
|
|
47
|
+
const handleClose = useCallback(() => {
|
|
48
|
+
setIsOpen(false);
|
|
49
|
+
}, []);
|
|
50
|
+
const handleBlur = useCallback(
|
|
51
|
+
(e) => {
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
var _a;
|
|
54
|
+
if (!((_a = wrapperRef.current) == null ? void 0 : _a.contains(document.activeElement))) {
|
|
55
|
+
setIsOpen(false);
|
|
56
|
+
onBlur(e);
|
|
57
|
+
}
|
|
58
|
+
}, 150);
|
|
59
|
+
},
|
|
60
|
+
[onBlur]
|
|
61
|
+
);
|
|
30
62
|
const inputEl = /* @__PURE__ */ jsx(
|
|
31
63
|
"input",
|
|
32
64
|
{
|
|
@@ -34,8 +66,9 @@ function TimeField({
|
|
|
34
66
|
type: "time",
|
|
35
67
|
name,
|
|
36
68
|
value: timeValue,
|
|
69
|
+
step: resolvedShowSeconds ? 1 : 60,
|
|
37
70
|
onChange: handleChange,
|
|
38
|
-
onBlur,
|
|
71
|
+
onBlur: handleBlur,
|
|
39
72
|
placeholder,
|
|
40
73
|
disabled,
|
|
41
74
|
readOnly,
|
|
@@ -43,7 +76,7 @@ function TimeField({
|
|
|
43
76
|
className: cx(styles.input, resolvedIcon && styles.inputWithIcon, error && styles.inputError)
|
|
44
77
|
}
|
|
45
78
|
);
|
|
46
|
-
return /* @__PURE__ */ jsxs("div", { className: styles.wrapper, children: [
|
|
79
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.wrapper, ref: wrapperRef, style: { position: "relative" }, children: [
|
|
47
80
|
label && /* @__PURE__ */ jsx(
|
|
48
81
|
"label",
|
|
49
82
|
{
|
|
@@ -54,9 +87,31 @@ function TimeField({
|
|
|
54
87
|
}
|
|
55
88
|
),
|
|
56
89
|
resolvedIcon ? /* @__PURE__ */ jsxs("div", { className: styles.inputIconWrapper, children: [
|
|
57
|
-
/* @__PURE__ */ jsx(
|
|
90
|
+
/* @__PURE__ */ jsx(
|
|
91
|
+
"button",
|
|
92
|
+
{
|
|
93
|
+
type: "button",
|
|
94
|
+
className: styles.fieldIconClickable,
|
|
95
|
+
onClick: openPicker,
|
|
96
|
+
disabled: disabled || readOnly,
|
|
97
|
+
"aria-label": "Open time picker",
|
|
98
|
+
tabIndex: -1,
|
|
99
|
+
children: resolvedIcon
|
|
100
|
+
}
|
|
101
|
+
),
|
|
58
102
|
inputEl
|
|
59
103
|
] }) : inputEl,
|
|
104
|
+
isOpen && /* @__PURE__ */ jsx(
|
|
105
|
+
TimePicker,
|
|
106
|
+
{
|
|
107
|
+
value: timeValue,
|
|
108
|
+
showSeconds: resolvedShowSeconds,
|
|
109
|
+
ampm: ampm === true,
|
|
110
|
+
pickerId: `${name}-timepicker`,
|
|
111
|
+
onApply: handleApply,
|
|
112
|
+
onClose: handleClose
|
|
113
|
+
}
|
|
114
|
+
),
|
|
60
115
|
displayText && /* @__PURE__ */ jsx("span", { className: styles.helperText, "aria-hidden": "true", children: displayText }),
|
|
61
116
|
helperText && /* @__PURE__ */ jsx(
|
|
62
117
|
"span",
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const TimePicker_module = require("./TimePicker.module.css.cjs");
|
|
6
|
+
function pad2(n) {
|
|
7
|
+
return String(n).padStart(2, "0");
|
|
8
|
+
}
|
|
9
|
+
function parseTime(iso) {
|
|
10
|
+
if (!iso) {
|
|
11
|
+
const now = /* @__PURE__ */ new Date();
|
|
12
|
+
return { h: now.getHours(), m: now.getMinutes(), s: now.getSeconds() };
|
|
13
|
+
}
|
|
14
|
+
const parts = iso.split(":").map(Number);
|
|
15
|
+
return {
|
|
16
|
+
h: Number.isFinite(parts[0]) ? parts[0] : 0,
|
|
17
|
+
m: Number.isFinite(parts[1]) ? parts[1] : 0,
|
|
18
|
+
s: Number.isFinite(parts[2]) ? parts[2] : 0
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function to12h(h24) {
|
|
22
|
+
const period = h24 >= 12 ? "PM" : "AM";
|
|
23
|
+
const h12 = h24 % 12 || 12;
|
|
24
|
+
return { h12, period };
|
|
25
|
+
}
|
|
26
|
+
function to24h(h12, period) {
|
|
27
|
+
if (period === "AM") return h12 === 12 ? 0 : h12;
|
|
28
|
+
return h12 === 12 ? 12 : h12 + 12;
|
|
29
|
+
}
|
|
30
|
+
function range(count) {
|
|
31
|
+
return Array.from({ length: count }, (_, i) => i);
|
|
32
|
+
}
|
|
33
|
+
function Column({ label, items, selected, onSelect, ariaLabel }) {
|
|
34
|
+
const columnRef = react.useRef(null);
|
|
35
|
+
const selectedRef = react.useRef(null);
|
|
36
|
+
react.useEffect(() => {
|
|
37
|
+
var _a;
|
|
38
|
+
(_a = selectedRef.current) == null ? void 0 : _a.scrollIntoView({ block: "nearest" });
|
|
39
|
+
}, [selected]);
|
|
40
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
41
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.columnLabel, children: label }),
|
|
42
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.column, ref: columnRef, role: "radiogroup", "aria-label": ariaLabel, children: items.map((n) => {
|
|
43
|
+
const isSelected = n === selected;
|
|
44
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45
|
+
"button",
|
|
46
|
+
{
|
|
47
|
+
ref: isSelected ? selectedRef : void 0,
|
|
48
|
+
type: "button",
|
|
49
|
+
role: "radio",
|
|
50
|
+
"aria-checked": isSelected,
|
|
51
|
+
className: `${TimePicker_module.default.cell} ${isSelected ? TimePicker_module.default.cellSelected : ""}`,
|
|
52
|
+
onClick: () => onSelect(n),
|
|
53
|
+
children: pad2(n)
|
|
54
|
+
},
|
|
55
|
+
n
|
|
56
|
+
);
|
|
57
|
+
}) })
|
|
58
|
+
] });
|
|
59
|
+
}
|
|
60
|
+
function TimePicker({
|
|
61
|
+
value,
|
|
62
|
+
showSeconds,
|
|
63
|
+
ampm,
|
|
64
|
+
pickerId,
|
|
65
|
+
onApply,
|
|
66
|
+
onClose
|
|
67
|
+
}) {
|
|
68
|
+
const initial = parseTime(value);
|
|
69
|
+
const [hour24, setHour24] = react.useState(initial.h);
|
|
70
|
+
const [minute, setMinute] = react.useState(initial.m);
|
|
71
|
+
const [second, setSecond] = react.useState(initial.s);
|
|
72
|
+
const [period, setPeriod] = react.useState(() => to12h(initial.h).period);
|
|
73
|
+
const pickerRef = react.useRef(null);
|
|
74
|
+
const displayHour = ampm ? to12h(hour24).h12 : hour24;
|
|
75
|
+
const hourItems = ampm ? range(12).map((i) => i + 1) : range(24);
|
|
76
|
+
const handleHourSelect = react.useCallback(
|
|
77
|
+
(h) => {
|
|
78
|
+
if (ampm) {
|
|
79
|
+
setHour24(to24h(h, period));
|
|
80
|
+
} else {
|
|
81
|
+
setHour24(h);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
[ampm, period]
|
|
85
|
+
);
|
|
86
|
+
const handlePeriodToggle = react.useCallback(
|
|
87
|
+
(p) => {
|
|
88
|
+
setPeriod(p);
|
|
89
|
+
const h12 = to12h(hour24).h12;
|
|
90
|
+
setHour24(to24h(h12, p));
|
|
91
|
+
},
|
|
92
|
+
[hour24]
|
|
93
|
+
);
|
|
94
|
+
const handleNow = react.useCallback(() => {
|
|
95
|
+
const now = /* @__PURE__ */ new Date();
|
|
96
|
+
setHour24(now.getHours());
|
|
97
|
+
setMinute(now.getMinutes());
|
|
98
|
+
setSecond(now.getSeconds());
|
|
99
|
+
setPeriod(now.getHours() >= 12 ? "PM" : "AM");
|
|
100
|
+
}, []);
|
|
101
|
+
const handleApply = react.useCallback(() => {
|
|
102
|
+
const parts = [pad2(hour24), pad2(minute)];
|
|
103
|
+
if (showSeconds) parts.push(pad2(second));
|
|
104
|
+
onApply(parts.join(":"));
|
|
105
|
+
}, [hour24, minute, second, showSeconds, onApply]);
|
|
106
|
+
react.useEffect(() => {
|
|
107
|
+
const handleKeyDown = (e) => {
|
|
108
|
+
if (e.key === "Escape") onClose();
|
|
109
|
+
};
|
|
110
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
111
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
112
|
+
}, [onClose]);
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.overlay, onClick: onClose, "aria-hidden": "true" }),
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: TimePicker_module.default.picker, ref: pickerRef, id: pickerId, "aria-label": "Time picker", children: [
|
|
116
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: TimePicker_module.default.columns, children: [
|
|
117
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
118
|
+
Column,
|
|
119
|
+
{
|
|
120
|
+
label: "HH",
|
|
121
|
+
items: hourItems,
|
|
122
|
+
selected: displayHour,
|
|
123
|
+
onSelect: handleHourSelect,
|
|
124
|
+
ariaLabel: "Hours"
|
|
125
|
+
}
|
|
126
|
+
),
|
|
127
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.separator, "aria-hidden": "true", children: ":" }),
|
|
128
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
129
|
+
Column,
|
|
130
|
+
{
|
|
131
|
+
label: "MM",
|
|
132
|
+
items: range(60),
|
|
133
|
+
selected: minute,
|
|
134
|
+
onSelect: setMinute,
|
|
135
|
+
ariaLabel: "Minutes"
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
showSeconds && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
139
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.separator, "aria-hidden": "true", children: ":" }),
|
|
140
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
141
|
+
Column,
|
|
142
|
+
{
|
|
143
|
+
label: "SS",
|
|
144
|
+
items: range(60),
|
|
145
|
+
selected: second,
|
|
146
|
+
onSelect: setSecond,
|
|
147
|
+
ariaLabel: "Seconds"
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
] }),
|
|
151
|
+
ampm && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.columnLabel, children: "AP" }),
|
|
153
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: TimePicker_module.default.column, role: "radiogroup", "aria-label": "AM/PM", children: ["AM", "PM"].map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
154
|
+
"button",
|
|
155
|
+
{
|
|
156
|
+
type: "button",
|
|
157
|
+
role: "radio",
|
|
158
|
+
"aria-checked": p === period,
|
|
159
|
+
className: `${TimePicker_module.default.cell} ${p === period ? TimePicker_module.default.cellSelected : ""}`,
|
|
160
|
+
onClick: () => handlePeriodToggle(p),
|
|
161
|
+
children: p
|
|
162
|
+
},
|
|
163
|
+
p
|
|
164
|
+
)) })
|
|
165
|
+
] })
|
|
166
|
+
] }),
|
|
167
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: TimePicker_module.default.footer, children: [
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: TimePicker_module.default.footerBtn, onClick: handleNow, children: "Now" }),
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
170
|
+
"button",
|
|
171
|
+
{
|
|
172
|
+
type: "button",
|
|
173
|
+
className: `${TimePicker_module.default.footerBtn} ${TimePicker_module.default.footerBtnPrimary}`,
|
|
174
|
+
onClick: handleApply,
|
|
175
|
+
children: "Apply"
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
] })
|
|
179
|
+
] })
|
|
180
|
+
] });
|
|
181
|
+
}
|
|
182
|
+
exports.TimePicker = TimePicker;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface TimePickerProps {
|
|
2
|
+
value: string;
|
|
3
|
+
showSeconds: boolean;
|
|
4
|
+
ampm: boolean;
|
|
5
|
+
pickerId: string;
|
|
6
|
+
onApply: (isoTime: string) => void;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function TimePicker({ value, showSeconds, ampm, pickerId, onApply, onClose, }: Readonly<TimePickerProps>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=TimePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimePicker.d.ts","sourceRoot":"","sources":["../../../src/fields/TimeField/TimePicker.tsx"],"names":[],"mappings":"AAGA,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAmFD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,WAAW,EACX,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,OAAO,GACR,EAAE,QAAQ,CAAC,eAAe,CAAC,2CAiI3B"}
|