@geckou/ui-react 0.3.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 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,29 @@ 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
+
122
+ ## 0.4.0 の変更
123
+
124
+ - `RadioButtons` が必須エラー(「必須項目です」)を描画する。Vue 版と同じく、
125
+ 値が空へ変化したときに出る
126
+ - `CheckBox` / `ToggleButton` のロールが `aria-pressed` から
127
+ `role="checkbox" + aria-checked` / `role="switch" + aria-checked` に変わった。
128
+ アクセシブル名は `ariaLabel` / `ariaLabelledBy` で渡せる(未指定なら従来どおり `name`)
129
+ - `DateSelector` に `minYear` / `maxYear` を追加(既定は従来どおり「今年 -100 〜 今年 -14」)
130
+ - `DateRangePicker` が範囲(開始 > 終了)を検証し、`<name>Range` という名前で
131
+ `FormValidationStore` に登録する。`invalidNames` を見ている場合は増える
132
+ - `TabUI` の `color.text` を配線した
133
+
101
134
  ## License
102
135
 
103
136
  [MIT](../../LICENSE)
@@ -8,6 +8,12 @@ type Props = {
8
8
  cssStyle?: CheckBoxStyleForEachStatus;
9
9
  isDisableAnimation?: boolean;
10
10
  check?: ReactNode;
11
+ /**
12
+ * アクセシブル名。可視ラベルがあるなら ariaLabelledBy でその要素を指すこと。
13
+ * どちらも無いときだけ name を名前として使う(機械名でも無いよりはマシ)
14
+ */
15
+ ariaLabel?: string;
16
+ ariaLabelledBy?: string;
11
17
  };
12
- export declare function CheckBox({ name, checked, onChange, isDisabled, cssStyle, isDisableAnimation, check, }: Props): import("react").JSX.Element;
18
+ export declare function CheckBox({ name, checked, onChange, isDisabled, cssStyle, isDisableAnimation, check, ariaLabel, ariaLabelledBy, }: Props): import("react").JSX.Element;
13
19
  export {};
@@ -1,18 +1,20 @@
1
1
  "use client";
2
- import { jsxs as b, Fragment as x, jsx as c } from "react/jsx-runtime";
3
- import { CheckIcon as v } from "./icons/CheckIcon.js";
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
5
  function j({
6
6
  name: l,
7
- checked: f,
8
- onChange: r,
7
+ checked: s,
8
+ onChange: c,
9
9
  isDisabled: e,
10
- cssStyle: o,
11
- isDisableAnimation: p,
12
- check: k
10
+ cssStyle: r,
11
+ isDisableAnimation: f,
12
+ check: k,
13
+ ariaLabel: p,
14
+ ariaLabelledBy: a
13
15
  }) {
14
- var u, s, n;
15
- const i = f ?? !1, h = e ? o == null ? void 0 : o.disabled : o == null ? void 0 : o.default, d = {
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 = {
16
18
  textColor: e ? t.darkGray : t.blue,
17
19
  backgroundColor: e ? t.lightGray : t.white,
18
20
  border: {
@@ -21,52 +23,41 @@ function j({
21
23
  radius: ".25rem"
22
24
  },
23
25
  ...h
24
- }, m = {
26
+ }, x = {
25
27
  "--text-color": d.textColor,
26
- "--border-color": (u = d.border) == null ? void 0 : u.color,
27
- "--border-size": (s = d.border) == null ? void 0 : s.size,
28
- "--radius-size": (n = d.border) == null ? void 0 : n.radius,
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,
29
31
  "--background-color": d.backgroundColor,
30
- "--duration": p ? "0s" : ".3s"
32
+ "--duration": f ? "0s" : ".3s"
31
33
  };
32
- return /* @__PURE__ */ b(x, { children: [
33
- /* @__PURE__ */ c("style", { children: "@keyframes uiCheckPop{0%{scale:1}10%{scale:.8}50%{scale:1.1}100%{scale:1}}" }),
34
- /* @__PURE__ */ b(
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(
35
37
  "button",
36
38
  {
37
39
  type: "button",
38
- style: m,
39
- "aria-label": l,
40
- "aria-pressed": i,
40
+ style: x,
41
+ role: "checkbox",
42
+ "aria-checked": o,
43
+ "data-checked": o,
44
+ "aria-labelledby": a,
45
+ "aria-label": a ? void 0 : p ?? l,
41
46
  disabled: e,
42
- onClick: (a) => {
43
- a.stopPropagation(), e || r == null || r(!i);
47
+ onClick: (m) => {
48
+ m.stopPropagation(), e || c == null || c(!o);
44
49
  },
45
- 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) has-[input:disabled]:pointer-events-none has-[input:disabled]:before:pointer-events-auto has-[input:disabled]:before:absolute has-[input:disabled]:before:inset-0 has-[input:disabled]:before:cursor-not-allowed has-[input:disabled]:before:content-[''] ${i ? "animate-[uiCheckPop_var(--duration)_ease-out] bg-(--border-color)" : "bg-(--background-color)"}`,
46
- children: [
47
- /* @__PURE__ */ c(
48
- "input",
49
- {
50
- type: "checkbox",
51
- name: l,
52
- checked: i,
53
- disabled: e,
54
- onChange: (a) => {
55
- e || r == null || r(a.target.checked);
56
- },
57
- className: "hidden"
58
- }
59
- ),
60
- /* @__PURE__ */ c(
61
- "div",
62
- {
63
- className: `flex h-4 w-4 items-center justify-center [&>*]:fill-current [&>*]:text-current ${i ? "text-(--background-color)" : "text-(--border-color)"}`,
64
- children: k ?? /* @__PURE__ */ c(v, {})
65
- }
66
- )
67
- ]
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
+ )
68
58
  }
69
- )
59
+ ),
60
+ o && /* @__PURE__ */ i("input", { type: "hidden", name: l, value: "on", disabled: e })
70
61
  ] });
71
62
  }
72
63
  export {
@@ -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 V, jsx as t } from "react/jsx-runtime";
3
- import { formatDateValue as b, splitDate as h, COLOR as A, MESSAGES as B, composeDateValue as G, validateDateObject as R } from "@geckou/ui-core";
4
- import { useState as g, useRef as q, useEffect as C } from "react";
5
- import { InputBox as F } from "./InputBox.js";
6
- import { ErrorMessage as H } from "./ErrorMessage.js";
7
- import { CalendarIcon as J } from "./icons/CalendarIcon.js";
8
- import { useRegisterValidation as K } from "../hooks/useFormValidation.js";
9
- function _({
10
- name: l,
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: N,
13
+ cssStyle: M,
14
14
  isDisabled: i,
15
- isRequired: o,
16
- formValidationStore: O,
17
- minDate: E = "",
18
- maxDate: S = "",
19
- size: M = "medium",
20
- type: r = "date"
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 [k, n] = g(
23
- () => a ? b(a, r) : ""
24
- ), [c, d] = g(
25
- () => a ? h(b(a, r)) : { year: "", month: "", day: "" }
26
- ), [p, $] = g(""), w = q(a);
27
- C(() => {
28
- if (w.current === a)
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
- w.current = a;
31
- const e = a ? b(a, r) : "";
32
- n(e), d(h(e));
33
- }, [a, r]);
34
- const y = (e) => !e && o ? { isValid: !1, message: B.required } : { isValid: !0, message: "" }, D = (e) => R(e, { type: r, isRequired: o }), I = (e) => {
35
- n(e), d(h(e));
36
- const { message: v } = y(e);
37
- $(v), s == null || s(e);
38
- }, u = (e, v) => {
39
- const x = { ...c, [e]: v };
40
- d(x);
41
- const { isValid: z, message: P } = D(x);
42
- if ($(P), z) {
43
- const j = G(x, r);
44
- n(j), s == null || s(j);
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
- K(
48
- O,
49
- l,
50
- y(k).isValid
49
+ _(
50
+ D,
51
+ o,
52
+ I(y).isValid && G
51
53
  );
52
- const m = M === "small", f = `flex-none! ${m ? "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)]!"}`, L = { "--icon-color": A.blue };
53
- return /* @__PURE__ */ V(
54
- F,
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: N,
58
+ cssStyle: M,
57
59
  isDisabled: i,
58
- isErrored: !!p,
59
- className: `flex w-full items-center leading-none ${m ? "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
+ 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__ */ V("div", { className: "relative flex-none", style: L, children: [
62
- /* @__PURE__ */ t(
63
- J,
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) ${m ? "size-[var(--icon-small,0.9375rem)]" : "size-[var(--icon-medium,1.125rem)]"}`
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__ */ t(
70
+ /* @__PURE__ */ r(
69
71
  "input",
70
72
  {
71
- type: r,
72
- name: l,
73
- value: k,
74
- max: S,
75
- min: E,
76
- required: o,
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) => I(e.target.value),
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 ${m ? "py-[var(--sp-min,0.1875rem)]!" : "py-[var(--sp-medium,0.75rem)]!"}`
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__ */ t(
85
+ /* @__PURE__ */ r(
84
86
  "input",
85
87
  {
86
- value: c.year,
88
+ value: l.year,
87
89
  placeholder: "年",
88
- "aria-label": `${l}の年`,
90
+ ...x(""),
89
91
  maxLength: 4,
90
92
  type: "text",
91
93
  disabled: i,
92
- onChange: (e) => u("year", e.target.value),
93
- className: `w-[calc(var(--sp-medium,0.75rem)*2+5ch)]! ${f}`
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__ */ t(
99
+ /* @__PURE__ */ r(
98
100
  "input",
99
101
  {
100
- value: c.month,
102
+ value: l.month,
101
103
  placeholder: "月",
102
- "aria-label": `${l}の月`,
104
+ ...x(""),
103
105
  maxLength: 2,
104
106
  type: "text",
105
107
  disabled: i,
106
- onChange: (e) => u("month", e.target.value),
107
- className: `w-[calc(var(--sp-medium,0.75rem)*2+3ch)]! ${f}`
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
- r === "date" && /* @__PURE__ */ t("span", { children: "/" }),
111
- r === "date" && /* @__PURE__ */ t(
112
+ t === "date" && /* @__PURE__ */ r("span", { children: "/" }),
113
+ t === "date" && /* @__PURE__ */ r(
112
114
  "input",
113
115
  {
114
- value: c.day,
116
+ value: l.day,
115
117
  placeholder: "日",
116
- "aria-label": `${l}の日`,
118
+ ...x(""),
117
119
  maxLength: 2,
118
120
  type: "text",
119
121
  disabled: i,
120
- onChange: (e) => u("day", e.target.value),
121
- className: `w-[calc(var(--sp-medium,0.75rem)*2+3ch)]! ${f}`
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__ */ t(H, { errorMessages: p ? [p] : void 0 })
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
- _ as DatePicker
137
+ le as DatePicker
131
138
  };
@@ -1,65 +1,75 @@
1
1
  "use client";
2
- import { jsxs as g, jsx as d } from "react/jsx-runtime";
3
- import { DatePicker as b } from "./DatePicker.js";
4
- import { COLOR as f } from "@geckou/ui-core";
5
- const h = { start: "", end: "" };
6
- function N({
7
- name: c,
8
- value: r = h,
9
- onChange: t,
10
- isDisabled: n,
11
- isRequired: a,
12
- formValidationStore: o,
13
- minDate: s = "",
14
- maxDate: l = "",
15
- size: m = "medium",
16
- type: i = "date"
2
+ import { jsxs as b, jsx as t } from "react/jsx-runtime";
3
+ import { COLOR as g, MESSAGES as R } from "@geckou/ui-core";
4
+ import { DatePicker as x } from "./DatePicker.js";
5
+ import { ErrorMessage as k } from "./ErrorMessage.js";
6
+ import { useRegisterValidation as u } from "../hooks/useFormValidation.js";
7
+ const M = { start: "", end: "" };
8
+ function $({
9
+ name: d,
10
+ value: r = M,
11
+ onChange: e,
12
+ isDisabled: a,
13
+ isRequired: c,
14
+ formValidationStore: s,
15
+ minDate: o = "",
16
+ maxDate: i = "",
17
+ size: l = "medium",
18
+ type: m = "date"
17
19
  }) {
18
- const x = (e) => t == null ? void 0 : t({ start: e, end: r.end }), u = (e) => t == null ? void 0 : t({ start: r.start, end: e }), v = {
19
- "--range-background-color": f.white,
20
- "--range-border-color": f.gray
20
+ const f = !(r.start && r.end && r.start > r.end);
21
+ u(s, `${d}Range`, f);
22
+ const E = (n) => e == null ? void 0 : e({ start: n, end: r.end }), p = (n) => e == null ? void 0 : e({ start: r.start, end: n }), h = {
23
+ "--range-background-color": g.white,
24
+ "--range-border-color": g.gray
21
25
  };
22
- return /* @__PURE__ */ g(
23
- "div",
24
- {
25
- style: v,
26
- className: "flex bg-(--range-background-color) [&>*]:flex-auto [&>*]:rounded-none! [&>*:first-child]:rounded-s-[calc(var(--bv,0.375rem)/2)]! [&>*:last-child]:rounded-e-[calc(var(--bv,0.375rem)/2)]! [&>*:not(:last-child)]:border-e [&>*:not(:last-child)]:border-(--range-border-color)",
27
- children: [
28
- /* @__PURE__ */ d(
29
- b,
26
+ return (
27
+ // 角丸・区切り線は :first-child / :last-child で割り当てるため、
28
+ // ErrorMessage を同じ階層に置くとエラー表示時だけ枠の見た目が変わる。
29
+ // 入力群を内側にまとめ、ErrorMessage は外側(relative)に置く
30
+ /* @__PURE__ */ b("div", { style: h, className: "relative", children: [
31
+ /* @__PURE__ */ b("div", { className: "flex bg-(--range-background-color) [&>*]:flex-auto [&>*]:rounded-none! [&>*:first-child]:rounded-s-[calc(var(--bv,0.375rem)/2)]! [&>*:last-child]:rounded-e-[calc(var(--bv,0.375rem)/2)]! [&>*:not(:last-child)]:border-e [&>*:not(:last-child)]:border-(--range-border-color)", children: [
32
+ /* @__PURE__ */ t(
33
+ x,
30
34
  {
31
- name: `${c}Start`,
35
+ name: `${d}Start`,
32
36
  value: r.start,
33
- isDisabled: n,
34
- isRequired: a,
35
- formValidationStore: o,
36
- minDate: s,
37
- maxDate: r.end || l,
38
- size: m,
39
- type: i,
40
- onChange: x
37
+ isDisabled: a,
38
+ isRequired: c,
39
+ formValidationStore: s,
40
+ minDate: o,
41
+ maxDate: r.end || i,
42
+ size: l,
43
+ type: m,
44
+ onChange: E
41
45
  }
42
46
  ),
43
- /* @__PURE__ */ d("div", { className: "flex flex-none! items-center px-[var(--bv,0.375rem)]", children: "〜" }),
44
- /* @__PURE__ */ d(
45
- b,
47
+ /* @__PURE__ */ t("div", { className: "flex flex-none! items-center px-[var(--bv,0.375rem)]", children: "〜" }),
48
+ /* @__PURE__ */ t(
49
+ x,
46
50
  {
47
- name: `${c}End`,
51
+ name: `${d}End`,
48
52
  value: r.end,
49
- isDisabled: n,
50
- isRequired: a,
51
- formValidationStore: o,
52
- minDate: r.start || s,
53
- maxDate: l,
54
- size: m,
55
- type: i,
56
- onChange: u
53
+ isDisabled: a,
54
+ isRequired: c,
55
+ formValidationStore: s,
56
+ minDate: r.start || o,
57
+ maxDate: i,
58
+ size: l,
59
+ type: m,
60
+ onChange: p
57
61
  }
58
62
  )
59
- ]
60
- }
63
+ ] }),
64
+ /* @__PURE__ */ t(
65
+ k,
66
+ {
67
+ errorMessages: f ? void 0 : [R.startAfterEnd]
68
+ }
69
+ )
70
+ ] })
61
71
  );
62
72
  }
63
73
  export {
64
- N as DateRangePicker
74
+ $ as DateRangePicker
65
75
  };
@@ -8,6 +8,16 @@ type Props = {
8
8
  formValidationStore?: FormValidationStore | null;
9
9
  /** 'month' なら日の選択を出さない(Vue 版と揃える) */
10
10
  type?: 'date' | 'month';
11
+ /** 選べる年の下限・上限。既定は「今年 -100 〜 今年 -14」(生年月日向け) */
12
+ minYear?: number;
13
+ maxYear?: number;
14
+ /**
15
+ * 年月日それぞれの読み上げ名の土台。「の年」「の月」「の日」を後ろに繋げる。
16
+ * 可視ラベルがあるなら ariaLabelledBy でその要素を指すこと。
17
+ * どちらも無いときだけ name を使う(機械名でも無いよりはマシ)
18
+ */
19
+ ariaLabel?: string;
20
+ ariaLabelledBy?: string;
11
21
  };
12
- export declare function DateSelector({ name, value, onChange, isRequired, formValidationStore, type, }: 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;
13
23
  export {};