@geckou/ui-react 0.4.0 → 0.5.0
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 +21 -0
- package/dist/components/CheckBox.js +41 -54
- package/dist/components/DatePicker.d.ts +8 -1
- package/dist/components/DatePicker.js +86 -79
- package/dist/components/DateSelector.d.ts +8 -1
- package/dist/components/DateSelector.js +84 -77
- package/dist/components/LabeledCheckbox.js +11 -11
- package/dist/components/ModalBox.js +36 -32
- package/dist/components/SearchableSelectBox.d.ts +3 -1
- package/dist/components/SearchableSelectBox.js +86 -43
- package/dist/components/TextBox.d.ts +15 -2
- package/dist/components/TextBox.js +54 -38
- package/dist/components/ToggleButton.js +45 -52
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -84,6 +84,16 @@ props は Vue 版(`@geckou/ui-vue`)と揃えている。`v-model` にあた
|
|
|
84
84
|
| `DateRangePicker` | `{ start: string; end: string }` | `DatePicker` と同じ(開始日と終了日の min / max が自動連動)。各入力の name は `<name>Start` / `<name>End` |
|
|
85
85
|
| `DateSelector` | `string`(`YYYY-MM-DD` / `type="month"` なら `YYYY-MM`) | `name` / `isRequired` / `type` / `formValidationStore` |
|
|
86
86
|
|
|
87
|
+
`DatePicker` / `DateSelector` の年月日欄の読み上げ名は、既定では `name` から作られます
|
|
88
|
+
(`name="startedOn"` なら「startedOnの年」)。`CheckBox` と同じ `ariaLabel` / `ariaLabelledBy`
|
|
89
|
+
を渡すと、そちらを土台に「の年」「の月」「の日」を繋げます。可視ラベルがあるなら
|
|
90
|
+
`ariaLabelledBy` でその要素を指してください(WCAG 2.5.3 Label in Name)。
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<DatePicker name="startedOn" ariaLabel="開始日" /> {/* 「開始日の年」 */}
|
|
94
|
+
<DatePicker name="startedOn" ariaLabelledBy={labelId} /> {/* 可視ラベル + 「の年」 */}
|
|
95
|
+
```
|
|
96
|
+
|
|
87
97
|
## 収録コンポーネント
|
|
88
98
|
|
|
89
99
|
フォーム系 25 種(`TextBox` / `TextArea` / `SelectBox` / `SearchableSelectBox` / `CheckBox` 系 /
|
|
@@ -98,6 +108,17 @@ props は Vue 版(`@geckou/ui-vue`)と揃えている。`v-model` にあた
|
|
|
98
108
|
yarn workspace @geckou/ui-react test
|
|
99
109
|
```
|
|
100
110
|
|
|
111
|
+
## 0.5.0 の変更
|
|
112
|
+
|
|
113
|
+
- `DatePicker` / `DateSelector` が `ariaLabel` / `ariaLabelledBy` を受ける
|
|
114
|
+
(未指定なら従来どおり `name` から読み上げ名を作る)
|
|
115
|
+
- `CheckBox` / `ToggleButton` が `<button>` の中に `<input>` を置かなくなった。
|
|
116
|
+
状態は `<button>` の `data-checked` / `disabled` で表し、送信用の入力は
|
|
117
|
+
チェック時だけ `<input type="hidden">` として `<button>` の外に描かれる。
|
|
118
|
+
DOM を辿っているテストやスタイルがあれば追従が要る
|
|
119
|
+
- `ModalBox` が開いている間、Tab / Shift+Tab をダイアログ内で循環させる(フォーカストラップ)
|
|
120
|
+
- `SearchableSelectBox` が WAI-ARIA の Combobox パターンに沿い、↑↓ / Enter / Escape で操作できる
|
|
121
|
+
|
|
101
122
|
## 0.4.0 の変更
|
|
102
123
|
|
|
103
124
|
- `RadioButtons` が必須エラー(「必須項目です」)を描画する。Vue 版と同じく、
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import { CheckIcon as
|
|
2
|
+
import { jsxs as v, Fragment as C, jsx as i } from "react/jsx-runtime";
|
|
3
|
+
import { CheckIcon as _ } from "./icons/CheckIcon.js";
|
|
4
4
|
import { COLOR as t } from "@geckou/ui-core";
|
|
5
|
-
function
|
|
5
|
+
function j({
|
|
6
6
|
name: l,
|
|
7
|
-
checked:
|
|
8
|
-
onChange:
|
|
7
|
+
checked: s,
|
|
8
|
+
onChange: c,
|
|
9
9
|
isDisabled: e,
|
|
10
|
-
cssStyle:
|
|
11
|
-
isDisableAnimation:
|
|
12
|
-
check:
|
|
13
|
-
ariaLabel:
|
|
14
|
-
ariaLabelledBy:
|
|
10
|
+
cssStyle: r,
|
|
11
|
+
isDisableAnimation: f,
|
|
12
|
+
check: k,
|
|
13
|
+
ariaLabel: p,
|
|
14
|
+
ariaLabelledBy: a
|
|
15
15
|
}) {
|
|
16
|
-
var n,
|
|
17
|
-
const
|
|
16
|
+
var n, u, b;
|
|
17
|
+
const o = s ?? !1, h = e ? r == null ? void 0 : r.disabled : r == null ? void 0 : r.default, d = {
|
|
18
18
|
textColor: e ? t.darkGray : t.blue,
|
|
19
19
|
backgroundColor: e ? t.lightGray : t.white,
|
|
20
20
|
border: {
|
|
@@ -22,57 +22,44 @@ function g({
|
|
|
22
22
|
size: "1px",
|
|
23
23
|
radius: ".25rem"
|
|
24
24
|
},
|
|
25
|
-
...
|
|
26
|
-
},
|
|
27
|
-
"--text-color":
|
|
28
|
-
"--border-color": (n =
|
|
29
|
-
"--border-size": (
|
|
30
|
-
"--radius-size": (b =
|
|
31
|
-
"--background-color":
|
|
32
|
-
"--duration":
|
|
25
|
+
...h
|
|
26
|
+
}, x = {
|
|
27
|
+
"--text-color": d.textColor,
|
|
28
|
+
"--border-color": (n = d.border) == null ? void 0 : n.color,
|
|
29
|
+
"--border-size": (u = d.border) == null ? void 0 : u.size,
|
|
30
|
+
"--radius-size": (b = d.border) == null ? void 0 : b.radius,
|
|
31
|
+
"--background-color": d.backgroundColor,
|
|
32
|
+
"--duration": f ? "0s" : ".3s"
|
|
33
33
|
};
|
|
34
|
-
return /* @__PURE__ */
|
|
35
|
-
/* @__PURE__ */
|
|
36
|
-
/* @__PURE__ */
|
|
34
|
+
return /* @__PURE__ */ v(C, { children: [
|
|
35
|
+
/* @__PURE__ */ i("style", { children: "@keyframes uiCheckPop{0%{scale:1}10%{scale:.8}50%{scale:1.1}100%{scale:1}}" }),
|
|
36
|
+
/* @__PURE__ */ i(
|
|
37
37
|
"button",
|
|
38
38
|
{
|
|
39
39
|
type: "button",
|
|
40
|
-
style:
|
|
40
|
+
style: x,
|
|
41
41
|
role: "checkbox",
|
|
42
|
-
"aria-checked":
|
|
43
|
-
"
|
|
44
|
-
"aria-
|
|
42
|
+
"aria-checked": o,
|
|
43
|
+
"data-checked": o,
|
|
44
|
+
"aria-labelledby": a,
|
|
45
|
+
"aria-label": a ? void 0 : p ?? l,
|
|
45
46
|
disabled: e,
|
|
46
|
-
onClick: (
|
|
47
|
-
|
|
47
|
+
onClick: (m) => {
|
|
48
|
+
m.stopPropagation(), e || c == null || c(!o);
|
|
48
49
|
},
|
|
49
|
-
className: `relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-(--radius-size) border-none shadow-[0_0_0_var(--border-size)_var(--border-color)_inset] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--border-color)
|
|
50
|
-
children:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
disabled: e,
|
|
58
|
-
onChange: (a) => {
|
|
59
|
-
e || r == null || r(a.target.checked);
|
|
60
|
-
},
|
|
61
|
-
className: "hidden"
|
|
62
|
-
}
|
|
63
|
-
),
|
|
64
|
-
/* @__PURE__ */ d(
|
|
65
|
-
"div",
|
|
66
|
-
{
|
|
67
|
-
className: `flex h-4 w-4 items-center justify-center [&>*]:fill-current [&>*]:text-current ${i ? "text-(--background-color)" : "text-(--border-color)"}`,
|
|
68
|
-
children: h ?? /* @__PURE__ */ d(z, {})
|
|
69
|
-
}
|
|
70
|
-
)
|
|
71
|
-
]
|
|
50
|
+
className: `relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-(--radius-size) border-none shadow-[0_0_0_var(--border-size)_var(--border-color)_inset] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--border-color) disabled:pointer-events-none disabled:before:pointer-events-auto disabled:before:absolute disabled:before:inset-0 disabled:before:cursor-not-allowed disabled:before:content-[''] ${o ? "animate-[uiCheckPop_var(--duration)_ease-out] bg-(--border-color)" : "bg-(--background-color)"}`,
|
|
51
|
+
children: /* @__PURE__ */ i(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
className: `flex h-4 w-4 items-center justify-center [&>*]:fill-current [&>*]:text-current ${o ? "text-(--background-color)" : "text-(--border-color)"}`,
|
|
55
|
+
children: k ?? /* @__PURE__ */ i(_, {})
|
|
56
|
+
}
|
|
57
|
+
)
|
|
72
58
|
}
|
|
73
|
-
)
|
|
59
|
+
),
|
|
60
|
+
o && /* @__PURE__ */ i("input", { type: "hidden", name: l, value: "on", disabled: e })
|
|
74
61
|
] });
|
|
75
62
|
}
|
|
76
63
|
export {
|
|
77
|
-
|
|
64
|
+
j as CheckBox
|
|
78
65
|
};
|
|
@@ -13,6 +13,13 @@ type Props = {
|
|
|
13
13
|
maxDate?: string;
|
|
14
14
|
size?: 'small' | 'medium';
|
|
15
15
|
type?: 'date' | 'month';
|
|
16
|
+
/**
|
|
17
|
+
* 年月日それぞれの読み上げ名の土台。「の年」「の月」「の日」を後ろに繋げる。
|
|
18
|
+
* 可視ラベルがあるなら ariaLabelledBy でその要素を指すこと。
|
|
19
|
+
* どちらも無いときだけ name を使う(機械名でも無いよりはマシ)
|
|
20
|
+
*/
|
|
21
|
+
ariaLabel?: string;
|
|
22
|
+
ariaLabelledBy?: string;
|
|
16
23
|
};
|
|
17
|
-
export declare function DatePicker({ name, value, onChange, cssStyle, isDisabled, isRequired, formValidationStore, minDate, maxDate, size, type, }: Props): import("react").JSX.Element;
|
|
24
|
+
export declare function DatePicker({ name, value, onChange, cssStyle, isDisabled, isRequired, formValidationStore, minDate, maxDate, size, type, ariaLabel, ariaLabelledBy, }: Props): import("react").JSX.Element;
|
|
18
25
|
export {};
|
|
@@ -1,131 +1,138 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import { formatDateValue as
|
|
4
|
-
import { useState as
|
|
5
|
-
import { InputBox as
|
|
6
|
-
import { ErrorMessage as
|
|
7
|
-
import { CalendarIcon as
|
|
8
|
-
import { useRegisterValidation as
|
|
9
|
-
function
|
|
10
|
-
name:
|
|
2
|
+
import { jsxs as j, jsx as r } from "react/jsx-runtime";
|
|
3
|
+
import { formatDateValue as V, splitDate as w, COLOR as H, MESSAGES as J, composeDateValue as K, validateDateObject as Q } from "@geckou/ui-core";
|
|
4
|
+
import { useState as m, useRef as T, useEffect as U, useId as W } from "react";
|
|
5
|
+
import { InputBox as X } from "./InputBox.js";
|
|
6
|
+
import { ErrorMessage as Y } from "./ErrorMessage.js";
|
|
7
|
+
import { CalendarIcon as Z } from "./icons/CalendarIcon.js";
|
|
8
|
+
import { useRegisterValidation as _ } from "../hooks/useFormValidation.js";
|
|
9
|
+
function le({
|
|
10
|
+
name: o,
|
|
11
11
|
value: a,
|
|
12
12
|
onChange: s,
|
|
13
|
-
cssStyle:
|
|
13
|
+
cssStyle: M,
|
|
14
14
|
isDisabled: i,
|
|
15
|
-
isRequired:
|
|
16
|
-
formValidationStore:
|
|
17
|
-
minDate:
|
|
18
|
-
maxDate:
|
|
19
|
-
size:
|
|
20
|
-
type:
|
|
15
|
+
isRequired: d,
|
|
16
|
+
formValidationStore: D,
|
|
17
|
+
minDate: L = "",
|
|
18
|
+
maxDate: z = "",
|
|
19
|
+
size: P = "medium",
|
|
20
|
+
type: t = "date",
|
|
21
|
+
ariaLabel: A,
|
|
22
|
+
ariaLabelledBy: p
|
|
21
23
|
}) {
|
|
22
|
-
const [
|
|
23
|
-
() => a ?
|
|
24
|
-
), [
|
|
25
|
-
() => a ?
|
|
26
|
-
), [
|
|
27
|
-
|
|
28
|
-
if (
|
|
24
|
+
const [y, u] = m(
|
|
25
|
+
() => a ? V(a, t) : ""
|
|
26
|
+
), [l, f] = m(
|
|
27
|
+
() => a ? w(V(a, t)) : { year: "", month: "", day: "" }
|
|
28
|
+
), [v, O] = m(""), [G, h] = m(!0), N = T(a);
|
|
29
|
+
U(() => {
|
|
30
|
+
if (N.current === a)
|
|
29
31
|
return;
|
|
30
|
-
|
|
31
|
-
const e = a ?
|
|
32
|
-
|
|
33
|
-
}, [a,
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const { message:
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
const { isValid:
|
|
42
|
-
if (
|
|
43
|
-
const
|
|
44
|
-
|
|
32
|
+
N.current = a;
|
|
33
|
+
const e = a ? V(a, t) : "";
|
|
34
|
+
u(e), f(w(e)), h(!0);
|
|
35
|
+
}, [a, t]);
|
|
36
|
+
const I = (e) => !e && d ? { isValid: !1, message: J.required } : { isValid: !0, message: "" }, R = (e) => Q(e, { type: t, isRequired: d }), q = (e) => {
|
|
37
|
+
u(e), f(w(e));
|
|
38
|
+
const { message: $ } = I(e);
|
|
39
|
+
O($), h(!0), s == null || s(e);
|
|
40
|
+
}, b = (e, $) => {
|
|
41
|
+
const k = { ...l, [e]: $ };
|
|
42
|
+
f(k);
|
|
43
|
+
const { isValid: E, message: F } = R(k);
|
|
44
|
+
if (O(F), h(E), E) {
|
|
45
|
+
const S = K(k, t);
|
|
46
|
+
u(S), s == null || s(S);
|
|
45
47
|
}
|
|
46
48
|
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
_(
|
|
50
|
+
D,
|
|
51
|
+
o,
|
|
52
|
+
I(y).isValid && G
|
|
51
53
|
);
|
|
52
|
-
const
|
|
53
|
-
return /* @__PURE__ */
|
|
54
|
-
|
|
54
|
+
const c = W(), x = (e) => p ? { "aria-labelledby": `${p} ${c}-${e}` } : { "aria-label": `${A ?? o}の${e}` }, n = P === "small", g = `flex-none! ${n ? "px-[var(--sp-small,0.375rem)]! py-[var(--sp-min,0.1875rem)]! text-[length:var(--fs-small,0.6875rem)]" : "p-[var(--sp-medium,0.75rem)]!"}`, C = { "--icon-color": H.blue };
|
|
55
|
+
return /* @__PURE__ */ j(
|
|
56
|
+
X,
|
|
55
57
|
{
|
|
56
|
-
cssStyle:
|
|
58
|
+
cssStyle: M,
|
|
57
59
|
isDisabled: i,
|
|
58
|
-
isErrored: !!
|
|
59
|
-
className: `flex w-full items-center leading-none ${
|
|
60
|
+
isErrored: !!v,
|
|
61
|
+
className: `flex w-full items-center leading-none ${n ? "h-[calc(var(--bv,0.375rem)*5)] px-[var(--sp-min,0.1875rem)]" : "h-[calc(var(--bv,0.375rem)*6)] px-[var(--sp-small,0.375rem)]"}`,
|
|
60
62
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
/* @__PURE__ */
|
|
63
|
-
|
|
63
|
+
/* @__PURE__ */ j("div", { className: "relative flex-none", style: C, children: [
|
|
64
|
+
/* @__PURE__ */ r(
|
|
65
|
+
Z,
|
|
64
66
|
{
|
|
65
|
-
className: `pointer-events-none absolute inset-y-0 left-[var(--sp-small,0.375rem)] m-auto fill-(--icon-color) ${
|
|
67
|
+
className: `pointer-events-none absolute inset-y-0 left-[var(--sp-small,0.375rem)] m-auto fill-(--icon-color) ${n ? "size-[var(--icon-small,0.9375rem)]" : "size-[var(--icon-medium,1.125rem)]"}`
|
|
66
68
|
}
|
|
67
69
|
),
|
|
68
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ r(
|
|
69
71
|
"input",
|
|
70
72
|
{
|
|
71
|
-
type:
|
|
72
|
-
name:
|
|
73
|
-
value:
|
|
74
|
-
max:
|
|
75
|
-
min:
|
|
76
|
-
required:
|
|
73
|
+
type: t,
|
|
74
|
+
name: o,
|
|
75
|
+
value: y,
|
|
76
|
+
max: z,
|
|
77
|
+
min: L,
|
|
78
|
+
required: d,
|
|
77
79
|
disabled: i,
|
|
78
|
-
onChange: (e) =>
|
|
79
|
-
className: `w-[calc(var(--icon-medium,1.125rem)+var(--sp-small,0.375rem)*2)]! cursor-pointer px-[var(--sp-small,0.375rem)]! opacity-0 [&::-webkit-calendar-picker-indicator]:absolute [&::-webkit-calendar-picker-indicator]:left-0 [&::-webkit-calendar-picker-indicator]:h-full [&::-webkit-calendar-picker-indicator]:w-full [&::-webkit-calendar-picker-indicator]:cursor-pointer [&::-webkit-calendar-picker-indicator]:opacity-0 ${
|
|
80
|
+
onChange: (e) => q(e.target.value),
|
|
81
|
+
className: `w-[calc(var(--icon-medium,1.125rem)+var(--sp-small,0.375rem)*2)]! cursor-pointer px-[var(--sp-small,0.375rem)]! opacity-0 [&::-webkit-calendar-picker-indicator]:absolute [&::-webkit-calendar-picker-indicator]:left-0 [&::-webkit-calendar-picker-indicator]:h-full [&::-webkit-calendar-picker-indicator]:w-full [&::-webkit-calendar-picker-indicator]:cursor-pointer [&::-webkit-calendar-picker-indicator]:opacity-0 ${n ? "py-[var(--sp-min,0.1875rem)]!" : "py-[var(--sp-medium,0.75rem)]!"}`
|
|
80
82
|
}
|
|
81
83
|
)
|
|
82
84
|
] }),
|
|
83
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ r(
|
|
84
86
|
"input",
|
|
85
87
|
{
|
|
86
|
-
value:
|
|
88
|
+
value: l.year,
|
|
87
89
|
placeholder: "年",
|
|
88
|
-
"
|
|
90
|
+
...x("年"),
|
|
89
91
|
maxLength: 4,
|
|
90
92
|
type: "text",
|
|
91
93
|
disabled: i,
|
|
92
|
-
onChange: (e) =>
|
|
93
|
-
className: `w-[calc(var(--sp-medium,0.75rem)*2+5ch)]! ${
|
|
94
|
+
onChange: (e) => b("year", e.target.value),
|
|
95
|
+
className: `w-[calc(var(--sp-medium,0.75rem)*2+5ch)]! ${g}`
|
|
94
96
|
}
|
|
95
97
|
),
|
|
96
98
|
"/",
|
|
97
|
-
/* @__PURE__ */
|
|
99
|
+
/* @__PURE__ */ r(
|
|
98
100
|
"input",
|
|
99
101
|
{
|
|
100
|
-
value:
|
|
102
|
+
value: l.month,
|
|
101
103
|
placeholder: "月",
|
|
102
|
-
"
|
|
104
|
+
...x("月"),
|
|
103
105
|
maxLength: 2,
|
|
104
106
|
type: "text",
|
|
105
107
|
disabled: i,
|
|
106
|
-
onChange: (e) =>
|
|
107
|
-
className: `w-[calc(var(--sp-medium,0.75rem)*2+3ch)]! ${
|
|
108
|
+
onChange: (e) => b("month", e.target.value),
|
|
109
|
+
className: `w-[calc(var(--sp-medium,0.75rem)*2+3ch)]! ${g}`
|
|
108
110
|
}
|
|
109
111
|
),
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
t === "date" && /* @__PURE__ */ r("span", { children: "/" }),
|
|
113
|
+
t === "date" && /* @__PURE__ */ r(
|
|
112
114
|
"input",
|
|
113
115
|
{
|
|
114
|
-
value:
|
|
116
|
+
value: l.day,
|
|
115
117
|
placeholder: "日",
|
|
116
|
-
"
|
|
118
|
+
...x("日"),
|
|
117
119
|
maxLength: 2,
|
|
118
120
|
type: "text",
|
|
119
121
|
disabled: i,
|
|
120
|
-
onChange: (e) =>
|
|
121
|
-
className: `w-[calc(var(--sp-medium,0.75rem)*2+3ch)]! ${
|
|
122
|
+
onChange: (e) => b("day", e.target.value),
|
|
123
|
+
className: `w-[calc(var(--sp-medium,0.75rem)*2+3ch)]! ${g}`
|
|
122
124
|
}
|
|
123
125
|
),
|
|
124
|
-
/* @__PURE__ */
|
|
126
|
+
p && /* @__PURE__ */ j("span", { className: "sr-only", children: [
|
|
127
|
+
/* @__PURE__ */ r("span", { id: `${c}-年`, children: "の年" }),
|
|
128
|
+
/* @__PURE__ */ r("span", { id: `${c}-月`, children: "の月" }),
|
|
129
|
+
/* @__PURE__ */ r("span", { id: `${c}-日`, children: "の日" })
|
|
130
|
+
] }),
|
|
131
|
+
/* @__PURE__ */ r(Y, { errorMessages: v ? [v] : void 0 })
|
|
125
132
|
]
|
|
126
133
|
}
|
|
127
134
|
);
|
|
128
135
|
}
|
|
129
136
|
export {
|
|
130
|
-
|
|
137
|
+
le as DatePicker
|
|
131
138
|
};
|
|
@@ -11,6 +11,13 @@ type Props = {
|
|
|
11
11
|
/** 選べる年の下限・上限。既定は「今年 -100 〜 今年 -14」(生年月日向け) */
|
|
12
12
|
minYear?: number;
|
|
13
13
|
maxYear?: number;
|
|
14
|
+
/**
|
|
15
|
+
* 年月日それぞれの読み上げ名の土台。「の年」「の月」「の日」を後ろに繋げる。
|
|
16
|
+
* 可視ラベルがあるなら ariaLabelledBy でその要素を指すこと。
|
|
17
|
+
* どちらも無いときだけ name を使う(機械名でも無いよりはマシ)
|
|
18
|
+
*/
|
|
19
|
+
ariaLabel?: string;
|
|
20
|
+
ariaLabelledBy?: string;
|
|
14
21
|
};
|
|
15
|
-
export declare function DateSelector({ name, value, onChange, isRequired, formValidationStore, type, minYear, maxYear, }: Props): import("react").JSX.Element;
|
|
22
|
+
export declare function DateSelector({ name, value, onChange, isRequired, formValidationStore, type, minYear, maxYear, ariaLabel, ariaLabelledBy, }: Props): import("react").JSX.Element;
|
|
16
23
|
export {};
|
|
@@ -1,134 +1,141 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import { useState as
|
|
4
|
-
import { splitDate as
|
|
5
|
-
import { InputBox as
|
|
6
|
-
import { KeyboardArrowDownIcon as
|
|
7
|
-
import { useRegisterValidation as
|
|
8
|
-
const
|
|
9
|
-
function
|
|
10
|
-
name:
|
|
11
|
-
value:
|
|
12
|
-
onChange:
|
|
2
|
+
import { jsxs as o, jsx as r } from "react/jsx-runtime";
|
|
3
|
+
import { useState as H, useEffect as K, useId as L } from "react";
|
|
4
|
+
import { splitDate as V, COLOR as O, daysInMonth as q } from "@geckou/ui-core";
|
|
5
|
+
import { InputBox as G } from "./InputBox.js";
|
|
6
|
+
import { KeyboardArrowDownIcon as g } from "./icons/KeyboardArrowDownIcon.js";
|
|
7
|
+
import { useRegisterValidation as J } from "../hooks/useFormValidation.js";
|
|
8
|
+
const S = { year: "", month: "", day: "" };
|
|
9
|
+
function ee({
|
|
10
|
+
name: n,
|
|
11
|
+
value: m,
|
|
12
|
+
onChange: s,
|
|
13
13
|
isRequired: c,
|
|
14
|
-
formValidationStore:
|
|
15
|
-
type:
|
|
16
|
-
minYear:
|
|
17
|
-
maxYear:
|
|
14
|
+
formValidationStore: k,
|
|
15
|
+
type: d = "date",
|
|
16
|
+
minYear: B,
|
|
17
|
+
maxYear: E,
|
|
18
|
+
ariaLabel: T,
|
|
19
|
+
ariaLabelledBy: u
|
|
18
20
|
}) {
|
|
19
|
-
const [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
c ?
|
|
24
|
-
),
|
|
25
|
-
|
|
26
|
-
}, [
|
|
27
|
-
const
|
|
28
|
-
{ length: Math.max(
|
|
29
|
-
(e, a) => (
|
|
30
|
-
).map((e) => ({ label: e, value: e })),
|
|
21
|
+
const [l, p] = H(S), $ = !!(l.year && l.month && (d === "month" || l.day)), Y = !l.year && !l.month && !l.day;
|
|
22
|
+
J(
|
|
23
|
+
k,
|
|
24
|
+
n,
|
|
25
|
+
c ? $ : $ || Y
|
|
26
|
+
), K(() => {
|
|
27
|
+
p(m ? V(m) : S);
|
|
28
|
+
}, [m]);
|
|
29
|
+
const w = (/* @__PURE__ */ new Date()).getFullYear(), D = B ?? w - 100, _ = E ?? w - 14, j = Array.from(
|
|
30
|
+
{ length: Math.max(_ - D + 1, 0) },
|
|
31
|
+
(e, a) => (D + a).toString()
|
|
32
|
+
).map((e) => ({ label: e, value: e })), C = Array.from({ length: 12 }, (e, a) => {
|
|
31
33
|
const t = (a + 1).toString();
|
|
32
34
|
return { label: t, value: t.padStart(2, "0") };
|
|
33
|
-
}),
|
|
35
|
+
}), I = (e, a) => q(Number(e) || 2e3, Number(a)), F = I(l.year, l.month), P = Array.from({ length: F }, (e, a) => {
|
|
34
36
|
const t = (a + 1).toString();
|
|
35
37
|
return { label: t, value: t.padStart(2, "0") };
|
|
36
|
-
}),
|
|
37
|
-
|
|
38
|
-
const a =
|
|
38
|
+
}), x = (e) => {
|
|
39
|
+
p(e);
|
|
40
|
+
const a = d === "month" ? [e.year, e.month] : [e.year, e.month, e.day];
|
|
39
41
|
if (!e.year && !e.month && !e.day)
|
|
40
|
-
|
|
42
|
+
s == null || s("");
|
|
41
43
|
else {
|
|
42
44
|
if (a.some((t) => !t))
|
|
43
45
|
return;
|
|
44
|
-
|
|
46
|
+
s == null || s(a.join("-"));
|
|
45
47
|
}
|
|
46
|
-
},
|
|
47
|
-
const t = { ...
|
|
48
|
+
}, h = (e, a) => {
|
|
49
|
+
const t = { ...l, [e]: a };
|
|
48
50
|
if (e !== "day" && t.day && t.month) {
|
|
49
|
-
const
|
|
50
|
-
Number(t.day) >
|
|
51
|
+
const M = I(t.year, t.month);
|
|
52
|
+
Number(t.day) > M && (t.day = String(M).padStart(2, "0"));
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
+
x(t);
|
|
55
|
+
}, y = (e) => {
|
|
54
56
|
const t = e.currentTarget.firstElementChild;
|
|
55
57
|
t && t.click();
|
|
56
|
-
},
|
|
57
|
-
return /* @__PURE__ */
|
|
58
|
-
/* @__PURE__ */
|
|
59
|
-
/* @__PURE__ */
|
|
58
|
+
}, i = L(), v = (e) => u ? { "aria-labelledby": `${u} ${i}-${e}` } : { "aria-label": `${T ?? n}の${e}` }, f = "relative w-max [&:has(select:focus)>svg]:rotate-180", b = "pointer-events-none absolute inset-y-0 right-[var(--sp-small,0.375rem)] m-auto size-[var(--icon-medium,1.125rem)] fill-(--icon-color)", A = "w-[calc(3ch+var(--sp-medium,0.75rem)*2+var(--icon-medium,1.125rem))]! p-[var(--sp-medium,0.75rem)]! pe-[calc(var(--sp-small,0.375rem)*2+var(--icon-medium,1.125rem))]! cursor-pointer", N = { "--icon-color": O.blue }, z = { "--caution-color": O.red };
|
|
59
|
+
return /* @__PURE__ */ o(G, { className: "flex w-max items-center [&>*:not(:last-of-type)]:after:content-['/']", children: [
|
|
60
|
+
/* @__PURE__ */ o("div", { className: f, style: N, onClick: y, children: [
|
|
61
|
+
/* @__PURE__ */ o(
|
|
60
62
|
"select",
|
|
61
63
|
{
|
|
62
|
-
value:
|
|
63
|
-
name: `${
|
|
64
|
-
"
|
|
64
|
+
value: l.year,
|
|
65
|
+
name: `${n}-year`,
|
|
66
|
+
...v("年"),
|
|
65
67
|
required: c,
|
|
66
|
-
onChange: (e) =>
|
|
68
|
+
onChange: (e) => h("year", e.target.value),
|
|
67
69
|
className: "w-[calc(5ch+var(--sp-medium,0.75rem)*2+var(--icon-medium,1.125rem))]! cursor-pointer p-[var(--sp-medium,0.75rem)]! pe-[calc(var(--sp-small,0.375rem)*2+var(--icon-medium,1.125rem))]!",
|
|
68
70
|
children: [
|
|
69
|
-
/* @__PURE__ */
|
|
70
|
-
|
|
71
|
+
/* @__PURE__ */ r("option", { disabled: !0, value: "", children: "年" }),
|
|
72
|
+
j.map((e) => /* @__PURE__ */ r("option", { value: e.value, children: e.label }, e.value))
|
|
71
73
|
]
|
|
72
74
|
}
|
|
73
75
|
),
|
|
74
|
-
/* @__PURE__ */
|
|
76
|
+
/* @__PURE__ */ r(g, { className: b })
|
|
75
77
|
] }),
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ o("div", { className: f, style: N, onClick: y, children: [
|
|
79
|
+
/* @__PURE__ */ o(
|
|
78
80
|
"select",
|
|
79
81
|
{
|
|
80
|
-
value:
|
|
81
|
-
name: `${
|
|
82
|
-
"
|
|
82
|
+
value: l.month,
|
|
83
|
+
name: `${n}-month`,
|
|
84
|
+
...v("月"),
|
|
83
85
|
required: c,
|
|
84
|
-
onChange: (e) =>
|
|
85
|
-
className:
|
|
86
|
+
onChange: (e) => h("month", e.target.value),
|
|
87
|
+
className: A,
|
|
86
88
|
children: [
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
-
|
|
89
|
+
/* @__PURE__ */ r("option", { disabled: !0, value: "", children: "月" }),
|
|
90
|
+
C.map((e) => /* @__PURE__ */ r("option", { value: e.value, children: e.label }, e.value))
|
|
89
91
|
]
|
|
90
92
|
}
|
|
91
93
|
),
|
|
92
|
-
/* @__PURE__ */
|
|
94
|
+
/* @__PURE__ */ r(g, { className: b })
|
|
93
95
|
] }),
|
|
94
|
-
|
|
96
|
+
d === "date" && /* @__PURE__ */ o(
|
|
95
97
|
"div",
|
|
96
98
|
{
|
|
97
|
-
className:
|
|
98
|
-
style:
|
|
99
|
-
onClick:
|
|
99
|
+
className: f,
|
|
100
|
+
style: N,
|
|
101
|
+
onClick: y,
|
|
100
102
|
children: [
|
|
101
|
-
/* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ o(
|
|
102
104
|
"select",
|
|
103
105
|
{
|
|
104
|
-
value:
|
|
105
|
-
name: `${
|
|
106
|
-
"
|
|
106
|
+
value: l.day,
|
|
107
|
+
name: `${n}-day`,
|
|
108
|
+
...v("日"),
|
|
107
109
|
required: c,
|
|
108
|
-
onChange: (e) =>
|
|
109
|
-
className:
|
|
110
|
+
onChange: (e) => h("day", e.target.value),
|
|
111
|
+
className: A,
|
|
110
112
|
children: [
|
|
111
|
-
/* @__PURE__ */
|
|
112
|
-
|
|
113
|
+
/* @__PURE__ */ r("option", { disabled: !0, value: "", children: "日" }),
|
|
114
|
+
P.map((e) => /* @__PURE__ */ r("option", { value: e.value, children: e.label }, e.value))
|
|
113
115
|
]
|
|
114
116
|
}
|
|
115
117
|
),
|
|
116
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ r(g, { className: b })
|
|
117
119
|
]
|
|
118
120
|
}
|
|
119
121
|
),
|
|
120
|
-
/* @__PURE__ */
|
|
122
|
+
u && /* @__PURE__ */ o("span", { className: "sr-only", children: [
|
|
123
|
+
/* @__PURE__ */ r("span", { id: `${i}-年`, children: "の年" }),
|
|
124
|
+
/* @__PURE__ */ r("span", { id: `${i}-月`, children: "の月" }),
|
|
125
|
+
/* @__PURE__ */ r("span", { id: `${i}-日`, children: "の日" })
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ r(
|
|
121
128
|
"button",
|
|
122
129
|
{
|
|
123
130
|
type: "button",
|
|
124
|
-
style:
|
|
131
|
+
style: z,
|
|
125
132
|
className: "mx-[var(--sp-medium,0.75rem)] inline-flex cursor-pointer items-center gap-[var(--sp-min,0.1875rem)] text-[length:var(--fs-small,0.6875rem)] text-(--caution-color)",
|
|
126
|
-
onClick: () =>
|
|
133
|
+
onClick: () => x(S),
|
|
127
134
|
children: "削除"
|
|
128
135
|
}
|
|
129
136
|
)
|
|
130
137
|
] });
|
|
131
138
|
}
|
|
132
139
|
export {
|
|
133
|
-
|
|
140
|
+
ee as DateSelector
|
|
134
141
|
};
|