@k8o/arte-odyssey 4.2.0 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ import { FC } from "react";
4
4
  //#region src/components/form/autocomplete/autocomplete.d.ts
5
5
  type BaseProps = {
6
6
  id: string;
7
+ name?: string;
7
8
  describedbyId: string | undefined;
8
9
  isInvalid: boolean;
9
10
  isDisabled: boolean;
@@ -5,7 +5,7 @@ import { CloseIcon } from "../../icons/lucide.mjs";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useCallback, useEffect, useRef, useState } from "react";
7
7
  //#region src/components/form/autocomplete/autocomplete.tsx
8
- const Autocomplete = ({ id, describedbyId, isInvalid, isDisabled, isRequired, options, value, defaultValue, onChange }) => {
8
+ const Autocomplete = ({ id, name, describedbyId, isInvalid, isDisabled, isRequired, options, value, defaultValue, onChange }) => {
9
9
  const [internalValue, setInternalValue] = useState(defaultValue || []);
10
10
  const isControlled = value !== void 0;
11
11
  const currentValue = isControlled ? value : internalValue;
@@ -36,141 +36,149 @@ const Autocomplete = ({ id, describedbyId, isInvalid, isDisabled, isRequired, op
36
36
  return /* @__PURE__ */ jsxs("div", {
37
37
  className: cn("relative w-full rounded-lg border border-border-base bg-bg-base", "focus-within:border-transparent focus-within:outline-hidden focus-within:ring-2 focus-within:ring-border-info", "has-aria-invalid:border-border-error", "has-disabled:cursor-not-allowed has-disabled:border-border-mute has-disabled:bg-bg-mute has-disabled:has-hover:hover:bg-bg-mute"),
38
38
  ref,
39
- children: [/* @__PURE__ */ jsxs("div", {
40
- className: "flex min-h-12 items-center justify-between gap-2 px-3 py-2",
41
- children: [/* @__PURE__ */ jsxs("div", {
42
- className: "flex w-full flex-wrap gap-1",
43
- children: [currentValue.map((text) => {
44
- const label = options.find((option) => option.value === text)?.label;
45
- return /* @__PURE__ */ jsxs("div", {
46
- className: "inline-flex items-center gap-2 rounded-full bg-bg-mute px-3 py-1 font-medium text-sm",
47
- tabIndex: -1,
48
- children: [label, /* @__PURE__ */ jsx(IconButton, {
49
- label: "閉じる",
50
- onClick: (e) => {
51
- e.stopPropagation();
52
- reset();
53
- handleChange(currentValue.filter((v) => v !== text));
54
- },
55
- size: "sm",
56
- children: /* @__PURE__ */ jsx(CloseIcon, { size: "sm" })
57
- })]
58
- }, text);
59
- }), /* @__PURE__ */ jsx("input", {
60
- "aria-autocomplete": "list",
61
- "aria-controls": open ? `${id}_listbox` : void 0,
62
- "aria-describedby": describedbyId,
63
- "aria-expanded": open,
64
- "aria-invalid": isInvalid,
65
- "aria-required": isRequired,
66
- autoComplete: "off",
67
- className: cn("grow bg-transparent focus-visible:outline-hidden", "disabled:cursor-not-allowed"),
68
- disabled: isDisabled,
69
- id,
70
- onBlur: (e) => {
71
- if (e.relatedTarget?.id.startsWith(`${id}_option_`)) return;
72
- setOpen(false);
73
- },
74
- onChange: (e) => {
75
- setOpen(true);
76
- setText(e.target.value);
77
- setSelectIndex(void 0);
78
- },
79
- onClick: () => {
80
- if (open && text.length === 0) {
39
+ children: [
40
+ name ? currentValue.map((selectedValue) => /* @__PURE__ */ jsx("input", {
41
+ name,
42
+ type: "hidden",
43
+ value: selectedValue
44
+ }, selectedValue)) : null,
45
+ /* @__PURE__ */ jsxs("div", {
46
+ className: "flex min-h-12 items-center justify-between gap-2 px-3 py-2",
47
+ children: [/* @__PURE__ */ jsxs("div", {
48
+ className: "flex w-full flex-wrap gap-1",
49
+ children: [currentValue.map((text) => {
50
+ const label = options.find((option) => option.value === text)?.label;
51
+ return /* @__PURE__ */ jsxs("div", {
52
+ className: "inline-flex items-center gap-2 rounded-full bg-bg-mute px-3 py-1 font-medium text-sm",
53
+ tabIndex: -1,
54
+ children: [label, /* @__PURE__ */ jsx(IconButton, {
55
+ label: "閉じる",
56
+ onClick: (e) => {
57
+ e.stopPropagation();
58
+ reset();
59
+ handleChange(currentValue.filter((v) => v !== text));
60
+ },
61
+ size: "sm",
62
+ children: /* @__PURE__ */ jsx(CloseIcon, { size: "sm" })
63
+ })]
64
+ }, text);
65
+ }), /* @__PURE__ */ jsx("input", {
66
+ "aria-autocomplete": "list",
67
+ "aria-controls": open ? `${id}_listbox` : void 0,
68
+ "aria-describedby": describedbyId,
69
+ "aria-expanded": open,
70
+ "aria-invalid": isInvalid,
71
+ "aria-required": isRequired,
72
+ autoComplete: "off",
73
+ className: cn("grow bg-transparent focus-visible:outline-hidden", "disabled:cursor-not-allowed"),
74
+ disabled: isDisabled,
75
+ id,
76
+ onBlur: (e) => {
77
+ if (e.relatedTarget?.id.startsWith(`${id}_option_`)) return;
81
78
  setOpen(false);
82
- return;
83
- }
84
- setOpen(true);
85
- setSelectIndex(void 0);
86
- },
87
- onKeyDown: (e) => {
88
- if (e.key === "Backspace" && text.length === 0) {
89
- reset();
90
- handleChange(currentValue.slice(0, -1));
91
- return;
92
- }
93
- if (e.key === "ArrowDown") {
79
+ },
80
+ onChange: (e) => {
94
81
  setOpen(true);
95
- setSelectIndex((prev) => {
96
- if (prev === void 0) return 0;
97
- return Math.min(prev + 1, options.length - 1);
98
- });
99
- return;
100
- }
101
- if (e.key === "ArrowUp") {
82
+ setText(e.target.value);
83
+ setSelectIndex(void 0);
84
+ },
85
+ onClick: () => {
86
+ if (open && text.length === 0) {
87
+ setOpen(false);
88
+ return;
89
+ }
102
90
  setOpen(true);
103
- setSelectIndex((prev) => {
104
- if (prev === void 0) return 0;
105
- return Math.max(prev - 1, 0);
106
- });
107
- return;
108
- }
109
- if (e.key === "Enter" && selectIndex !== void 0 && selectIndex >= 0) {
110
- const selected = filteredOptions[selectIndex];
111
- if (!selected) return;
112
- if (currentValue.includes(selected.value)) {
113
- handleChange(currentValue.filter((v) => v !== selected.value));
91
+ setSelectIndex(void 0);
92
+ },
93
+ onKeyDown: (e) => {
94
+ if (e.key === "Backspace" && text.length === 0) {
114
95
  reset();
96
+ handleChange(currentValue.slice(0, -1));
115
97
  return;
116
98
  }
117
- handleChange([...currentValue, selected.value]);
118
- reset();
119
- return;
120
- }
121
- },
122
- placeholder: "入力して絞り込めます",
123
- role: "combobox",
124
- type: "text",
125
- value: text
126
- })]
127
- }), currentValue.length > 0 && /* @__PURE__ */ jsx(IconButton, {
128
- label: "すべて閉じる",
129
- onClick: (e) => {
130
- e.stopPropagation();
131
- handleChange([]);
132
- },
133
- size: "sm",
134
- children: /* @__PURE__ */ jsx(CloseIcon, { size: "sm" })
135
- })]
136
- }), /* @__PURE__ */ jsx("div", {
137
- className: "relative w-full",
138
- children: open && /* @__PURE__ */ jsx("div", {
139
- className: "absolute top-1 z-10 w-full rounded-lg border border-border-mute bg-bg-base shadow-md",
140
- role: "presentation",
141
- children: /* @__PURE__ */ jsxs("ul", {
142
- className: "max-h-96 py-2",
143
- id: `${id}_listbox`,
144
- children: [filteredOptions.length === 0 && /* @__PURE__ */ jsx("li", {
145
- className: "px-3 py-2 text-fg-mute",
146
- children: "該当なし"
147
- }), filteredOptions.map((option, idx) => {
148
- const selected = currentValue.includes(option.value);
149
- return /* @__PURE__ */ jsx("li", {
150
- className: cn("cursor-pointer px-3 py-2", selected && "bg-bg-mute", selectIndex === idx && !selected && "bg-bg-emphasize", selectIndex === idx && selected && "bg-bg-mute"),
151
- id: `${id}_option_${option.value}`,
152
- onClick: (e) => {
153
- e.stopPropagation();
154
- reset();
155
- if (selected) {
156
- handleChange(currentValue.filter((v) => v !== option.value));
99
+ if (e.key === "ArrowDown") {
100
+ setOpen(true);
101
+ setSelectIndex((prev) => {
102
+ if (prev === void 0) return 0;
103
+ return Math.min(prev + 1, options.length - 1);
104
+ });
105
+ return;
106
+ }
107
+ if (e.key === "ArrowUp") {
108
+ setOpen(true);
109
+ setSelectIndex((prev) => {
110
+ if (prev === void 0) return 0;
111
+ return Math.max(prev - 1, 0);
112
+ });
113
+ return;
114
+ }
115
+ if (e.key === "Enter" && selectIndex !== void 0 && selectIndex >= 0) {
116
+ const selected = filteredOptions[selectIndex];
117
+ if (!selected) return;
118
+ if (currentValue.includes(selected.value)) {
119
+ handleChange(currentValue.filter((v) => v !== selected.value));
120
+ reset();
157
121
  return;
158
122
  }
159
- handleChange([...currentValue, option.value]);
160
- },
161
- onKeyDown: (e) => {
162
- e.preventDefault();
163
- },
164
- onMouseEnter: () => {
165
- setSelectIndex(idx);
166
- },
167
- tabIndex: -1,
168
- children: option.label
169
- }, option.value);
123
+ handleChange([...currentValue, selected.value]);
124
+ reset();
125
+ return;
126
+ }
127
+ },
128
+ placeholder: "入力して絞り込めます",
129
+ role: "combobox",
130
+ type: "text",
131
+ value: text
170
132
  })]
133
+ }), currentValue.length > 0 && /* @__PURE__ */ jsx(IconButton, {
134
+ label: "すべて閉じる",
135
+ onClick: (e) => {
136
+ e.stopPropagation();
137
+ handleChange([]);
138
+ },
139
+ size: "sm",
140
+ children: /* @__PURE__ */ jsx(CloseIcon, { size: "sm" })
141
+ })]
142
+ }),
143
+ /* @__PURE__ */ jsx("div", {
144
+ className: "relative w-full",
145
+ children: open && /* @__PURE__ */ jsx("div", {
146
+ className: "absolute top-1 z-10 w-full rounded-lg border border-border-mute bg-bg-base shadow-md",
147
+ role: "presentation",
148
+ children: /* @__PURE__ */ jsxs("ul", {
149
+ className: "max-h-96 py-2",
150
+ id: `${id}_listbox`,
151
+ children: [filteredOptions.length === 0 && /* @__PURE__ */ jsx("li", {
152
+ className: "px-3 py-2 text-fg-mute",
153
+ children: "該当なし"
154
+ }), filteredOptions.map((option, idx) => {
155
+ const selected = currentValue.includes(option.value);
156
+ return /* @__PURE__ */ jsx("li", {
157
+ className: cn("cursor-pointer px-3 py-2", selected && "bg-bg-mute", selectIndex === idx && !selected && "bg-bg-emphasize", selectIndex === idx && selected && "bg-bg-mute"),
158
+ id: `${id}_option_${option.value}`,
159
+ onClick: (e) => {
160
+ e.stopPropagation();
161
+ reset();
162
+ if (selected) {
163
+ handleChange(currentValue.filter((v) => v !== option.value));
164
+ return;
165
+ }
166
+ handleChange([...currentValue, option.value]);
167
+ },
168
+ onKeyDown: (e) => {
169
+ e.preventDefault();
170
+ },
171
+ onMouseEnter: () => {
172
+ setSelectIndex(idx);
173
+ },
174
+ tabIndex: -1,
175
+ children: option.label
176
+ }, option.value);
177
+ })]
178
+ })
171
179
  })
172
180
  })
173
- })]
181
+ ]
174
182
  });
175
183
  };
176
184
  //#endregion
@@ -2,6 +2,7 @@ import { ChangeEventHandler, FC } from "react";
2
2
 
3
3
  //#region src/components/form/checkbox/checkbox.d.ts
4
4
  type BaseProps = {
5
+ name?: string;
5
6
  itemValue?: string;
6
7
  isDisabled?: boolean;
7
8
  label: string;
@@ -5,7 +5,7 @@ import { useCheckboxGroupContext } from "../checkbox-group/checkbox-group.mjs";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useState } from "react";
7
7
  //#region src/components/form/checkbox/checkbox.tsx
8
- const Checkbox = ({ itemValue, isDisabled = false, label, value, defaultChecked, onChange }) => {
8
+ const Checkbox = ({ name, itemValue, isDisabled = false, label, value, defaultChecked, onChange }) => {
9
9
  const groupContext = useCheckboxGroupContext();
10
10
  const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);
11
11
  const groupItemValue = itemValue ?? "";
@@ -25,7 +25,7 @@ const Checkbox = ({ itemValue, isDisabled = false, label, value, defaultChecked,
25
25
  className: "peer sr-only",
26
26
  defaultChecked: groupContext || isControlled ? void 0 : defaultChecked,
27
27
  disabled: isDisabledResolved,
28
- name: groupContext?.name,
28
+ name: groupContext?.name ?? name,
29
29
  onChange: (event) => {
30
30
  if (groupContext) {
31
31
  groupContext.toggleValue(groupItemValue);
@@ -10,6 +10,7 @@ type CheckboxCardOption = Readonly<{
10
10
  }>;
11
11
  type BaseProps = {
12
12
  labelId?: string;
13
+ name?: string;
13
14
  isDisabled: boolean;
14
15
  isInvalid?: boolean;
15
16
  options: readonly CheckboxCardOption[];
@@ -4,7 +4,7 @@ import { CheckIcon } from "../../icons/lucide.mjs";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { useId, useState } from "react";
6
6
  //#region src/components/form/checkbox-card/checkbox-card.tsx
7
- const CheckboxCard = ({ labelId, isDisabled, isInvalid = false, options, value, defaultValue, onChange }) => {
7
+ const CheckboxCard = ({ labelId, name, isDisabled, isInvalid = false, options, value, defaultValue, onChange }) => {
8
8
  const groupId = useId();
9
9
  const [internalValue, setInternalValue] = useState(defaultValue ?? []);
10
10
  const isControlled = value !== void 0;
@@ -30,6 +30,7 @@ const CheckboxCard = ({ labelId, isDisabled, isInvalid = false, options, value,
30
30
  checked,
31
31
  className: "sr-only",
32
32
  disabled,
33
+ name,
33
34
  onChange: (event) => {
34
35
  handleToggle(option.value, event.target.checked);
35
36
  },
@@ -39,6 +39,7 @@ declare const CheckboxGroup: react.FC<{
39
39
  })>;
40
40
  } & {
41
41
  Item: react.FC<{
42
+ name?: string;
42
43
  itemValue?: string;
43
44
  isDisabled?: boolean;
44
45
  label: string;
@@ -3,6 +3,7 @@ import { FC } from "react";
3
3
  //#region src/components/form/number-field/number-field.d.ts
4
4
  type BaseProps = {
5
5
  id?: string;
6
+ name?: string;
6
7
  describedbyId?: string | undefined;
7
8
  isInvalid: boolean;
8
9
  isDisabled: boolean;
@@ -7,7 +7,7 @@ import { cast } from "../../../helpers/number/cast.mjs";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { useState } from "react";
9
9
  //#region src/components/form/number-field/number-field.tsx
10
- const NumberField = ({ id, describedbyId, isInvalid, isDisabled, isRequired, value, defaultValue, onChange, step = 1, precision = 0, max = 9007199254740991, min = -9007199254740991, placeholder }) => {
10
+ const NumberField = ({ id, name, describedbyId, isInvalid, isDisabled, isRequired, value, defaultValue, onChange, step = 1, precision = 0, max = 9007199254740991, min = -9007199254740991, placeholder }) => {
11
11
  const isControlled = value !== void 0;
12
12
  const initialValue = defaultValue ?? value ?? 0;
13
13
  const [internalValue, setInternalValue] = useState(initialValue);
@@ -37,6 +37,7 @@ const NumberField = ({ id, describedbyId, isInvalid, isDisabled, isRequired, val
37
37
  disabled: isDisabled,
38
38
  id,
39
39
  inputMode: "decimal",
40
+ name,
40
41
  onBlur: () => {
41
42
  const newValue = between(cast(displayValue, precision), min, max);
42
43
  handleChange(newValue);
@@ -4,6 +4,7 @@ import { ChangeEventHandler, FC } from "react";
4
4
  //#region src/components/form/radio/radio.d.ts
5
5
  type BaseProps = {
6
6
  labelId: string;
7
+ name?: string;
7
8
  isDisabled: boolean;
8
9
  options: readonly Option[];
9
10
  };
@@ -3,7 +3,7 @@ import { cn } from "../../../helpers/cn.mjs";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { useState } from "react";
5
5
  //#region src/components/form/radio/radio.tsx
6
- const Radio = ({ labelId, isDisabled, value, defaultValue, onChange, options }) => {
6
+ const Radio = ({ labelId, name, isDisabled, value, defaultValue, onChange, options }) => {
7
7
  const [internalValue, setInternalValue] = useState(defaultValue);
8
8
  const isControlled = value !== void 0;
9
9
  const selectedValue = isControlled ? value : internalValue;
@@ -23,7 +23,7 @@ const Radio = ({ labelId, isDisabled, value, defaultValue, onChange, options })
23
23
  className: "peer sr-only",
24
24
  defaultChecked: isControlled ? void 0 : defaultValue === option.value,
25
25
  disabled: isDisabled,
26
- name: labelId,
26
+ name: name ?? labelId,
27
27
  onChange: () => {
28
28
  selectValue(option.value);
29
29
  },
@@ -10,6 +10,7 @@ type RadioCardOption = Readonly<{
10
10
  }>;
11
11
  type BaseProps = {
12
12
  labelId: string;
13
+ name?: string;
13
14
  isDisabled: boolean;
14
15
  isInvalid?: boolean;
15
16
  options: readonly RadioCardOption[];
@@ -3,7 +3,7 @@ import { cn } from "../../../helpers/cn.mjs";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { useId, useRef, useState } from "react";
5
5
  //#region src/components/form/radio-card/radio-card.tsx
6
- const RadioCard = ({ labelId, isDisabled, isInvalid = false, options, value, defaultValue, onChange }) => {
6
+ const RadioCard = ({ labelId, name, isDisabled, isInvalid = false, options, value, defaultValue, onChange }) => {
7
7
  const groupId = useId();
8
8
  const buttonRefs = useRef([]);
9
9
  const [internalValue, setInternalValue] = useState(defaultValue ?? options[0]?.value);
@@ -22,10 +22,14 @@ const RadioCard = ({ labelId, isDisabled, isInvalid = false, options, value, def
22
22
  if (nextIndex >= options.length) return 0;
23
23
  return nextIndex;
24
24
  };
25
- return /* @__PURE__ */ jsx("fieldset", {
25
+ return /* @__PURE__ */ jsxs("fieldset", {
26
26
  "aria-labelledby": labelId,
27
27
  className: cn("m-0 w-full min-w-0 border-0 p-0", "grid gap-3", isDisabled && "opacity-70"),
28
- children: options.map((option, index) => {
28
+ children: [name ? /* @__PURE__ */ jsx("input", {
29
+ name,
30
+ type: "hidden",
31
+ value: currentValue ?? ""
32
+ }) : null, options.map((option, index) => {
29
33
  const checked = currentValue === option.value;
30
34
  const disabled = isDisabled || option.disabled;
31
35
  const optionId = `${groupId}-${option.value}`;
@@ -79,7 +83,7 @@ const RadioCard = ({ labelId, isDisabled, isInvalid = false, options, value, def
79
83
  })
80
84
  ]
81
85
  }, option.value);
82
- })
86
+ })]
83
87
  });
84
88
  };
85
89
  //#endregion
@@ -4,6 +4,7 @@ import { ChangeEventHandler, FC } from "react";
4
4
  //#region src/components/form/select/select.d.ts
5
5
  type BaseProps = {
6
6
  id: string;
7
+ name?: string;
7
8
  describedbyId: string | undefined;
8
9
  isInvalid: boolean;
9
10
  isDisabled: boolean;
@@ -2,7 +2,7 @@ import { cn } from "../../../helpers/cn.mjs";
2
2
  import { ChevronIcon } from "../../icons/lucide.mjs";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/components/form/select/select.tsx
5
- const Select = ({ id, describedbyId, isInvalid, isDisabled, isRequired, options, value, defaultValue, onChange }) => {
5
+ const Select = ({ id, name, describedbyId, isInvalid, isDisabled, isRequired, options, value, defaultValue, onChange }) => {
6
6
  return /* @__PURE__ */ jsxs("div", {
7
7
  className: "relative h-fit w-full",
8
8
  children: [/* @__PURE__ */ jsx("select", {
@@ -13,6 +13,7 @@ const Select = ({ id, describedbyId, isInvalid, isDisabled, isRequired, options,
13
13
  defaultValue,
14
14
  disabled: isDisabled,
15
15
  id,
16
+ name,
16
17
  onChange,
17
18
  value,
18
19
  children: options.map((option) => /* @__PURE__ */ jsx("option", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8o/arte-odyssey",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
4
4
  "description": "k8o's react ui library",
5
5
  "keywords": [
6
6
  "components",
@@ -45,7 +45,7 @@
45
45
  "baseline-status": "1.1.1",
46
46
  "clsx": "2.1.1",
47
47
  "lucide-react": "0.577.0",
48
- "motion": "12.36.0",
48
+ "motion": "12.37.0",
49
49
  "tailwind-merge": "3.5.0"
50
50
  },
51
51
  "devDependencies": {