@k8o/arte-odyssey 4.2.0 → 5.0.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.
Files changed (73) hide show
  1. package/dist/components/buttons/button/button.mjs +1 -1
  2. package/dist/components/buttons/link-button/link-button.mjs +1 -1
  3. package/dist/components/data-display/accordion/context.mjs +5 -6
  4. package/dist/components/data-display/card/card.mjs +1 -1
  5. package/dist/components/data-display/card/interactive-card.mjs +1 -1
  6. package/dist/components/form/autocomplete/autocomplete.d.mts +1 -0
  7. package/dist/components/form/autocomplete/autocomplete.mjs +140 -133
  8. package/dist/components/form/checkbox/checkbox.d.mts +1 -0
  9. package/dist/components/form/checkbox/checkbox.mjs +2 -2
  10. package/dist/components/form/checkbox-card/checkbox-card.d.mts +1 -0
  11. package/dist/components/form/checkbox-card/checkbox-card.mjs +3 -2
  12. package/dist/components/form/checkbox-group/checkbox-group.mjs +8 -7
  13. package/dist/components/form/checkbox-group/index.d.mts +1 -0
  14. package/dist/components/form/file-field/file-field.mjs +1 -1
  15. package/dist/components/form/number-field/number-field.d.mts +1 -0
  16. package/dist/components/form/number-field/number-field.mjs +5 -4
  17. package/dist/components/form/password-input/password-input.mjs +4 -6
  18. package/dist/components/form/radio/radio.d.mts +1 -0
  19. package/dist/components/form/radio/radio.mjs +2 -2
  20. package/dist/components/form/radio-card/radio-card.d.mts +1 -0
  21. package/dist/components/form/radio-card/radio-card.mjs +9 -5
  22. package/dist/components/form/select/select.d.mts +1 -0
  23. package/dist/components/form/select/select.mjs +3 -2
  24. package/dist/components/form/slider/slider.mjs +7 -10
  25. package/dist/components/form/text-field/text-field.mjs +1 -1
  26. package/dist/components/form/textarea/textarea.mjs +1 -1
  27. package/dist/components/navigation/tabs/tabs.mjs +1 -1
  28. package/dist/components/overlays/modal/modal.mjs +1 -1
  29. package/dist/components/overlays/popover/hooks.mjs +3 -2
  30. package/dist/components/overlays/popover/popover.mjs +8 -16
  31. package/dist/hooks/breakpoint/index.d.mts +5 -0
  32. package/dist/hooks/breakpoint/index.mjs +24 -0
  33. package/dist/hooks/click-away/index.d.mts +1 -1
  34. package/dist/hooks/click-away/index.mjs +7 -5
  35. package/dist/hooks/controllable-state/index.d.mts +13 -0
  36. package/dist/hooks/controllable-state/index.mjs +21 -0
  37. package/dist/hooks/debounce/index.d.mts +6 -0
  38. package/dist/hooks/debounce/index.mjs +35 -0
  39. package/dist/hooks/disclosure/index.d.mts +10 -0
  40. package/dist/hooks/disclosure/index.mjs +14 -0
  41. package/dist/hooks/hover/index.d.mts +12 -0
  42. package/dist/hooks/hover/index.mjs +15 -0
  43. package/dist/hooks/index.d.mts +11 -1
  44. package/dist/hooks/index.mjs +11 -1
  45. package/dist/hooks/intersection-observer/index.d.mts +3 -0
  46. package/dist/hooks/intersection-observer/index.mjs +3 -0
  47. package/dist/hooks/intersection-observer/use-in-view.d.mts +12 -0
  48. package/dist/hooks/intersection-observer/use-in-view.mjs +17 -0
  49. package/dist/hooks/intersection-observer/use-intersection-observer.d.mts +12 -0
  50. package/dist/hooks/intersection-observer/use-intersection-observer.mjs +33 -0
  51. package/dist/hooks/local-storage/index.mjs +5 -4
  52. package/dist/hooks/resize/index.d.mts +1 -1
  53. package/dist/hooks/resize/index.mjs +2 -3
  54. package/dist/hooks/scroll-direction/index.mjs +47 -22
  55. package/dist/hooks/scroll-lock/index.d.mts +8 -0
  56. package/dist/hooks/scroll-lock/index.mjs +44 -0
  57. package/dist/hooks/session-storage/index.d.mts +4 -0
  58. package/dist/hooks/session-storage/index.mjs +46 -0
  59. package/dist/hooks/throttle/index.d.mts +6 -0
  60. package/dist/hooks/throttle/index.mjs +53 -0
  61. package/dist/hooks/window-size/index.mjs +26 -19
  62. package/dist/index.d.mts +11 -1
  63. package/dist/index.mjs +11 -1
  64. package/dist/styles/index.css +186 -137
  65. package/docs/GUIDE.md +52 -33
  66. package/docs/references/color.md +71 -36
  67. package/docs/references/components.md +555 -181
  68. package/docs/references/helpers.md +120 -0
  69. package/docs/references/hooks.md +295 -0
  70. package/docs/references/interaction-design.md +24 -6
  71. package/docs/references/spatial-design.md +69 -33
  72. package/docs/references/typography.md +31 -17
  73. package/package.json +18 -18
@@ -3,7 +3,7 @@ import { jsxs } from "react/jsx-runtime";
3
3
  //#region src/components/buttons/button/button.tsx
4
4
  const Button = ({ ref, children, type = "button", size = "md", color = "primary", variant = "contained", disabled = false, fullWidth = false, onClick, startIcon, endIcon, ...rest }) => {
5
5
  return /* @__PURE__ */ jsxs("button", {
6
- className: cn("cursor-pointer rounded-lg border-2 text-center font-bold transition-colors", {
6
+ className: cn("cursor-pointer rounded-full border-2 text-center font-bold transition-colors", {
7
7
  "border-transparent bg-primary-bg text-fg hover:bg-primary-bg/90 active:bg-primary-bg/80": variant === "contained" && color === "primary",
8
8
  "border-transparent bg-bg-subtle text-fg-base hover:bg-bg-mute active:bg-bg-emphasize": variant === "contained" && color === "gray",
9
9
  "cursor-not-allowed opacity-35 hover:bg-primary-bg active:bg-primary-bg": disabled && variant === "contained",
@@ -12,7 +12,7 @@ const LinkButton = ({ children, size = "md", color = "primary", variant = "conta
12
12
  };
13
13
  return renderAnchor({
14
14
  href,
15
- className: cn("rounded-lg border-2 text-center font-bold transition-colors", {
15
+ className: cn("rounded-full border-2 text-center font-bold transition-colors", {
16
16
  "border-transparent bg-primary-bg text-fg hover:bg-primary-bg/90 active:bg-primary-bg/80": variant === "contained" && color === "primary",
17
17
  "border-transparent bg-bg-subtle text-fg-base hover:bg-bg-mute active:bg-bg-emphasize": variant === "contained" && color === "gray",
18
18
  "border-primary-border bg-bg-base text-primary-fg hover:bg-bg-subtle active:bg-bg-emphasize": variant === "outlined" && color === "primary",
@@ -1,6 +1,7 @@
1
1
  "use client";
2
+ import { useDisclosure } from "../../../hooks/disclosure/index.mjs";
2
3
  import { jsx } from "react/jsx-runtime";
3
- import { createContext, use, useCallback, useState } from "react";
4
+ import { createContext, use } from "react";
4
5
  //#region src/components/data-display/accordion/context.tsx
5
6
  const OpenContext = createContext(false);
6
7
  const ToggleOpenContext = createContext(void 0);
@@ -17,13 +18,11 @@ const useItemId = () => {
17
18
  return id;
18
19
  };
19
20
  const AccordionItemProvider = ({ defaultOpen = false, id, children }) => {
20
- const [open, setOpen] = useState(defaultOpen);
21
+ const { isOpen, toggle } = useDisclosure(defaultOpen);
21
22
  return /* @__PURE__ */ jsx(OpenContext, {
22
- value: open,
23
+ value: isOpen,
23
24
  children: /* @__PURE__ */ jsx(ToggleOpenContext, {
24
- value: useCallback(() => {
25
- setOpen((open) => !open);
26
- }, []),
25
+ value: toggle,
27
26
  children: /* @__PURE__ */ jsx(ItemIdContext, {
28
27
  value: id,
29
28
  children
@@ -2,7 +2,7 @@ import { cn } from "../../../helpers/cn.mjs";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  //#region src/components/data-display/card/card.tsx
4
4
  const Card = ({ children, variant = "primary", width = "full", appearance = "shadow" }) => /* @__PURE__ */ jsx("div", {
5
- className: cn("rounded-lg", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit", variant === "primary" && "bg-bg-base", variant === "secondary" && "bg-bg-mute"),
5
+ className: cn("rounded-xl", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit", variant === "primary" && "bg-bg-base", variant === "secondary" && "bg-bg-mute"),
6
6
  children
7
7
  });
8
8
  //#endregion
@@ -2,7 +2,7 @@ import { cn } from "../../../helpers/cn.mjs";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  //#region src/components/data-display/card/interactive-card.tsx
4
4
  const InteractiveCard = ({ children, variant = "primary", width = "full", appearance = "shadow" }) => /* @__PURE__ */ jsx("div", {
5
- className: cn("rounded-lg transition-transform hover:scale-[1.02] active:scale-[0.98]", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit", variant === "primary" && "bg-bg-base", variant === "secondary" && "bg-bg-mute"),
5
+ className: cn("rounded-xl transition-transform hover:scale-[1.02] active:scale-[0.98]", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit", variant === "primary" && "bg-bg-base", variant === "secondary" && "bg-bg-mute"),
6
6
  children
7
7
  });
8
8
  //#endregion
@@ -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;
@@ -2,21 +2,20 @@
2
2
  import { cn } from "../../../helpers/cn.mjs";
3
3
  import { IconButton } from "../../buttons/icon-button/icon-button.mjs";
4
4
  import { CloseIcon } from "../../icons/lucide.mjs";
5
+ import { useControllableState } from "../../../hooks/controllable-state/index.mjs";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { useCallback, useEffect, useRef, useState } from "react";
7
8
  //#region src/components/form/autocomplete/autocomplete.tsx
8
- const Autocomplete = ({ id, describedbyId, isInvalid, isDisabled, isRequired, options, value, defaultValue, onChange }) => {
9
- const [internalValue, setInternalValue] = useState(defaultValue || []);
10
- const isControlled = value !== void 0;
11
- const currentValue = isControlled ? value : internalValue;
9
+ const Autocomplete = ({ id, name, describedbyId, isInvalid, isDisabled, isRequired, options, value, defaultValue, onChange }) => {
10
+ const [currentValue, handleChange] = useControllableState({
11
+ value,
12
+ defaultValue: defaultValue || [],
13
+ onChange
14
+ });
12
15
  const ref = useRef(null);
13
16
  const [open, setOpen] = useState(false);
14
17
  const [text, setText] = useState("");
15
18
  const [selectIndex, setSelectIndex] = useState();
16
- const handleChange = useCallback((newValue) => {
17
- if (!isControlled) setInternalValue(newValue);
18
- onChange?.(newValue);
19
- }, [isControlled, onChange]);
20
19
  const filteredOptions = options.filter((option) => option.label.includes(text));
21
20
  const reset = useCallback(() => {
22
21
  setText("");
@@ -34,143 +33,151 @@ const Autocomplete = ({ id, describedbyId, isInvalid, isDisabled, isRequired, op
34
33
  };
35
34
  }, [reset]);
36
35
  return /* @__PURE__ */ jsxs("div", {
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"),
36
+ className: cn("relative w-full rounded-xl 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
37
  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) {
38
+ children: [
39
+ name ? currentValue.map((selectedValue) => /* @__PURE__ */ jsx("input", {
40
+ name,
41
+ type: "hidden",
42
+ value: selectedValue
43
+ }, selectedValue)) : null,
44
+ /* @__PURE__ */ jsxs("div", {
45
+ className: "flex min-h-12 items-center justify-between gap-2 px-3 py-2",
46
+ children: [/* @__PURE__ */ jsxs("div", {
47
+ className: "flex w-full flex-wrap gap-1",
48
+ children: [currentValue.map((text) => {
49
+ const label = options.find((option) => option.value === text)?.label;
50
+ return /* @__PURE__ */ jsxs("div", {
51
+ className: "inline-flex items-center gap-2 rounded-full bg-bg-mute px-3 py-1 font-medium text-sm",
52
+ tabIndex: -1,
53
+ children: [label, /* @__PURE__ */ jsx(IconButton, {
54
+ label: "閉じる",
55
+ onClick: (e) => {
56
+ e.stopPropagation();
57
+ reset();
58
+ handleChange(currentValue.filter((v) => v !== text));
59
+ },
60
+ size: "sm",
61
+ children: /* @__PURE__ */ jsx(CloseIcon, { size: "sm" })
62
+ })]
63
+ }, text);
64
+ }), /* @__PURE__ */ jsx("input", {
65
+ "aria-autocomplete": "list",
66
+ "aria-controls": open ? `${id}_listbox` : void 0,
67
+ "aria-describedby": describedbyId,
68
+ "aria-expanded": open,
69
+ "aria-invalid": isInvalid,
70
+ "aria-required": isRequired,
71
+ autoComplete: "off",
72
+ className: cn("grow bg-transparent focus-visible:outline-hidden", "disabled:cursor-not-allowed"),
73
+ disabled: isDisabled,
74
+ id,
75
+ onBlur: (e) => {
76
+ if (e.relatedTarget?.id.startsWith(`${id}_option_`)) return;
81
77
  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") {
78
+ },
79
+ onChange: (e) => {
94
80
  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") {
81
+ setText(e.target.value);
82
+ setSelectIndex(void 0);
83
+ },
84
+ onClick: () => {
85
+ if (open && text.length === 0) {
86
+ setOpen(false);
87
+ return;
88
+ }
102
89
  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));
90
+ setSelectIndex(void 0);
91
+ },
92
+ onKeyDown: (e) => {
93
+ if (e.key === "Backspace" && text.length === 0) {
114
94
  reset();
95
+ handleChange(currentValue.slice(0, -1));
115
96
  return;
116
97
  }
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));
98
+ if (e.key === "ArrowDown") {
99
+ setOpen(true);
100
+ setSelectIndex((prev) => {
101
+ if (prev === void 0) return 0;
102
+ return Math.min(prev + 1, options.length - 1);
103
+ });
104
+ return;
105
+ }
106
+ if (e.key === "ArrowUp") {
107
+ setOpen(true);
108
+ setSelectIndex((prev) => {
109
+ if (prev === void 0) return 0;
110
+ return Math.max(prev - 1, 0);
111
+ });
112
+ return;
113
+ }
114
+ if (e.key === "Enter" && selectIndex !== void 0 && selectIndex >= 0) {
115
+ const selected = filteredOptions[selectIndex];
116
+ if (!selected) return;
117
+ if (currentValue.includes(selected.value)) {
118
+ handleChange(currentValue.filter((v) => v !== selected.value));
119
+ reset();
157
120
  return;
158
121
  }
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);
122
+ handleChange([...currentValue, selected.value]);
123
+ reset();
124
+ return;
125
+ }
126
+ },
127
+ placeholder: "入力して絞り込めます",
128
+ role: "combobox",
129
+ type: "text",
130
+ value: text
170
131
  })]
132
+ }), currentValue.length > 0 && /* @__PURE__ */ jsx(IconButton, {
133
+ label: "すべて閉じる",
134
+ onClick: (e) => {
135
+ e.stopPropagation();
136
+ handleChange([]);
137
+ },
138
+ size: "sm",
139
+ children: /* @__PURE__ */ jsx(CloseIcon, { size: "sm" })
140
+ })]
141
+ }),
142
+ /* @__PURE__ */ jsx("div", {
143
+ className: "relative w-full",
144
+ children: open && /* @__PURE__ */ jsx("div", {
145
+ className: "absolute top-1 z-10 w-full rounded-xl border border-border-mute bg-bg-base shadow-md",
146
+ role: "presentation",
147
+ children: /* @__PURE__ */ jsxs("ul", {
148
+ className: "max-h-96 py-2",
149
+ id: `${id}_listbox`,
150
+ children: [filteredOptions.length === 0 && /* @__PURE__ */ jsx("li", {
151
+ className: "px-3 py-2 text-fg-mute",
152
+ children: "該当なし"
153
+ }), filteredOptions.map((option, idx) => {
154
+ const selected = currentValue.includes(option.value);
155
+ return /* @__PURE__ */ jsx("li", {
156
+ className: cn("cursor-pointer px-3 py-2", selected && "bg-bg-mute", selectIndex === idx && !selected && "bg-bg-emphasize", selectIndex === idx && selected && "bg-bg-mute"),
157
+ id: `${id}_option_${option.value}`,
158
+ onClick: (e) => {
159
+ e.stopPropagation();
160
+ reset();
161
+ if (selected) {
162
+ handleChange(currentValue.filter((v) => v !== option.value));
163
+ return;
164
+ }
165
+ handleChange([...currentValue, option.value]);
166
+ },
167
+ onKeyDown: (e) => {
168
+ e.preventDefault();
169
+ },
170
+ onMouseEnter: () => {
171
+ setSelectIndex(idx);
172
+ },
173
+ tabIndex: -1,
174
+ children: option.label
175
+ }, option.value);
176
+ })]
177
+ })
171
178
  })
172
179
  })
173
- })]
180
+ ]
174
181
  });
175
182
  };
176
183
  //#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;
@@ -22,7 +22,7 @@ const CheckboxCard = ({ labelId, isDisabled, isInvalid = false, options, value,
22
22
  const disabled = isDisabled || option.disabled;
23
23
  const optionId = `${groupId}-${option.value}`;
24
24
  return /* @__PURE__ */ jsxs("label", {
25
- className: cn("flex w-full min-w-0 rounded-lg border bg-bg-base p-4 text-left transition-colors", "has-[input:focus-visible]:outline-hidden has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-border-info", checked && "border-border-info bg-bg-subtle", isInvalid ? "border-border-error" : "border-border-mute hover:bg-bg-mute", disabled && "cursor-not-allowed border-border-mute bg-bg-subtle text-fg-mute"),
25
+ className: cn("flex w-full min-w-0 rounded-xl border bg-bg-base p-4 text-left transition-colors", "has-[input:focus-visible]:outline-hidden has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-border-info", checked && "border-border-info bg-bg-subtle", isInvalid ? "border-border-error" : "border-border-mute hover:bg-bg-mute", disabled && "cursor-not-allowed border-border-mute bg-bg-subtle text-fg-mute"),
26
26
  id: optionId,
27
27
  children: [
28
28
  /* @__PURE__ */ jsx("input", {
@@ -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
  },
@@ -1,18 +1,19 @@
1
1
  "use client";
2
2
  import { cn } from "../../../helpers/cn.mjs";
3
+ import { useControllableState } from "../../../hooks/controllable-state/index.mjs";
3
4
  import { jsx } from "react/jsx-runtime";
4
- import { createContext, use, useState } from "react";
5
+ import { createContext, use } from "react";
5
6
  //#region src/components/form/checkbox-group/checkbox-group.tsx
6
7
  const CheckboxGroupContext = createContext(void 0);
7
8
  const useCheckboxGroupContext = () => use(CheckboxGroupContext);
8
9
  const Root = ({ children, describedbyId, defaultValue, isDisabled = false, isInvalid = false, isRequired = false, labelId, name, onChange, value }) => {
9
- const isControlled = value !== void 0;
10
- const [internalValue, setInternalValue] = useState(defaultValue ?? []);
11
- const currentValue = isControlled ? value : internalValue;
10
+ const [currentValue, setCurrentValue] = useControllableState({
11
+ value,
12
+ defaultValue: defaultValue ?? [],
13
+ onChange
14
+ });
12
15
  const toggleValue = (targetValue) => {
13
- const nextValue = currentValue.includes(targetValue) ? currentValue.filter((item) => item !== targetValue) : [...currentValue, targetValue];
14
- if (!isControlled) setInternalValue(nextValue);
15
- onChange?.(nextValue);
16
+ setCurrentValue(currentValue.includes(targetValue) ? currentValue.filter((item) => item !== targetValue) : [...currentValue, targetValue]);
16
17
  };
17
18
  return /* @__PURE__ */ jsx("fieldset", {
18
19
  "aria-describedby": describedbyId,
@@ -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;
@@ -100,7 +100,7 @@ const ItemList = ({ showWebkitRelativePath, clearable }) => {
100
100
  const onDelete = () => onFileDelete(id);
101
101
  const sizeInKB = (file.size / 1024).toFixed(2);
102
102
  return /* @__PURE__ */ jsxs("li", {
103
- className: "flex items-center justify-between rounded-lg border border-border-base bg-bg-base px-3 py-2",
103
+ className: "flex items-center justify-between rounded-xl border border-border-base bg-bg-base px-3 py-2",
104
104
  children: [/* @__PURE__ */ jsxs("div", {
105
105
  className: "flex flex-col gap-1",
106
106
  children: [/* @__PURE__ */ jsx("span", {
@@ -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);
@@ -23,7 +23,7 @@ const NumberField = ({ id, describedbyId, isInvalid, isDisabled, isRequired, val
23
23
  onChange?.(newValue);
24
24
  };
25
25
  return /* @__PURE__ */ jsxs("div", {
26
- className: cn("relative flex h-12 w-full items-center justify-between gap-2 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"),
26
+ className: cn("relative flex h-12 w-full items-center justify-between gap-2 rounded-xl 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"),
27
27
  children: [/* @__PURE__ */ jsx("input", {
28
28
  "aria-describedby": describedbyId,
29
29
  "aria-invalid": isInvalid,
@@ -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);
@@ -67,7 +68,7 @@ const NumberField = ({ id, describedbyId, isInvalid, isDisabled, isRequired, val
67
68
  "aria-hidden": "true",
68
69
  className: "absolute right-0 flex h-full flex-col",
69
70
  children: [/* @__PURE__ */ jsxs("button", {
70
- className: cn("flex w-6 grow items-center justify-center rounded-tr-lg border-border-base border-b border-l bg-bg-mute", "disabled:cursor-not-allowed"),
71
+ className: cn("flex w-6 grow items-center justify-center rounded-tr-xl border-border-base border-b border-l bg-bg-mute", "disabled:cursor-not-allowed"),
71
72
  disabled: isDisabled,
72
73
  onClick: () => {
73
74
  const newValue = between(toPrecision(cast(displayValue, precision) + step, precision), min, max);
@@ -81,7 +82,7 @@ const NumberField = ({ id, describedbyId, isInvalid, isDisabled, isRequired, val
81
82
  children: "増やす"
82
83
  }), /* @__PURE__ */ jsx(PlusIcon, { size: "sm" })]
83
84
  }), /* @__PURE__ */ jsxs("button", {
84
- className: cn("flex w-6 grow items-center justify-center rounded-br-lg border-border-base border-l bg-bg-mute", "disabled:cursor-not-allowed"),
85
+ className: cn("flex w-6 grow items-center justify-center rounded-br-xl border-border-base border-l bg-bg-mute", "disabled:cursor-not-allowed"),
85
86
  disabled: isDisabled,
86
87
  onClick: () => {
87
88
  const newValue = between(toPrecision(cast(displayValue, precision) - step, precision), min, max);
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import { cn } from "../../../helpers/cn.mjs";
3
3
  import { ViewIcon, ViewOffIcon } from "../../icons/lucide.mjs";
4
+ import { useDisclosure } from "../../../hooks/disclosure/index.mjs";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { useState } from "react";
6
6
  //#region src/components/form/password-input/password-input.tsx
7
7
  const PasswordInput = ({ id, name, describedbyId, isInvalid, isDisabled, isRequired, placeholder, autoComplete = "current-password", showLabel = "Show password", hideLabel = "Hide password", defaultValue, value, onChange }) => {
8
- const [isVisible, setIsVisible] = useState(false);
8
+ const { isOpen: isVisible, toggle: toggleVisible } = useDisclosure();
9
9
  return /* @__PURE__ */ jsxs("div", {
10
10
  className: "relative w-full",
11
11
  children: [/* @__PURE__ */ jsx("input", {
@@ -13,7 +13,7 @@ const PasswordInput = ({ id, name, describedbyId, isInvalid, isDisabled, isRequi
13
13
  "aria-invalid": isInvalid,
14
14
  "aria-required": isRequired,
15
15
  autoComplete,
16
- className: cn("w-full rounded-lg border border-border-base bg-bg-base px-3 py-2 pr-12", "aria-invalid:border-border-error", "disabled:cursor-not-allowed disabled:border-border-mute disabled:bg-bg-mute disabled:hover:bg-bg-mute", "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info"),
16
+ className: cn("w-full rounded-xl border border-border-base bg-bg-base px-3 py-2 pr-12", "aria-invalid:border-border-error", "disabled:cursor-not-allowed disabled:border-border-mute disabled:bg-bg-mute disabled:hover:bg-bg-mute", "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info"),
17
17
  defaultValue,
18
18
  disabled: isDisabled,
19
19
  id,
@@ -27,9 +27,7 @@ const PasswordInput = ({ id, name, describedbyId, isInvalid, isDisabled, isRequi
27
27
  "aria-label": isVisible ? hideLabel : showLabel,
28
28
  className: cn("absolute top-1/2 right-2 inline-flex -translate-y-1/2 items-center justify-center rounded-md p-1 text-fg-mute transition-colors", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info", !isDisabled && "hover:bg-bg-mute hover:text-fg-base", isDisabled && "cursor-not-allowed text-fg-mute/70"),
29
29
  disabled: isDisabled,
30
- onClick: () => {
31
- setIsVisible((current) => !current);
32
- },
30
+ onClick: toggleVisible,
33
31
  type: "button",
34
32
  children: isVisible ? /* @__PURE__ */ jsx(ViewOffIcon, { size: "sm" }) : /* @__PURE__ */ jsx(ViewIcon, { size: "sm" })
35
33
  })]
@@ -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[];