@kuraykaraaslan/kui-react 1.0.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.
- package/LICENSE +17 -0
- package/README.md +168 -0
- package/dist/AdvancedDataTable-F3DNXDKX.mjs +11 -0
- package/dist/DataTable-2G27T4E6.mjs +11 -0
- package/dist/DateRangePicker-AL32QB6L.mjs +11 -0
- package/dist/DropdownMenu-f5yV9dzM.d.mts +22 -0
- package/dist/DropdownMenu-f5yV9dzM.d.ts +22 -0
- package/dist/MapView-FERKPCDB.mjs +10 -0
- package/dist/ServerDataTable-RZV3K6KQ.mjs +11 -0
- package/dist/Tooltip-Bof5GvOc.d.mts +248 -0
- package/dist/Tooltip-Bof5GvOc.d.ts +248 -0
- package/dist/VideoPlayer-P3I6ESXJ.mjs +9 -0
- package/dist/app.d.mts +620 -0
- package/dist/app.d.ts +620 -0
- package/dist/app.js +7061 -0
- package/dist/app.mjs +100 -0
- package/dist/chunk-24BCQSLI.mjs +1 -0
- package/dist/chunk-45I3EDB2.mjs +90 -0
- package/dist/chunk-4IWCD7ID.mjs +1450 -0
- package/dist/chunk-5E2HXWFI.mjs +105 -0
- package/dist/chunk-C7AYI4XM.mjs +402 -0
- package/dist/chunk-J4D44TUA.mjs +1267 -0
- package/dist/chunk-KTEWZKNE.mjs +1020 -0
- package/dist/chunk-LMUQHL4Z.mjs +3829 -0
- package/dist/chunk-MD5OQ4J2.mjs +527 -0
- package/dist/chunk-MPJRPYIZ.mjs +1 -0
- package/dist/chunk-MPWUEQ7J.mjs +2422 -0
- package/dist/chunk-MTT5TKAJ.mjs +93 -0
- package/dist/chunk-RBDK7MWQ.mjs +46 -0
- package/dist/chunk-SVFQZPNZ.mjs +3648 -0
- package/dist/chunk-TZWBBMSG.mjs +1 -0
- package/dist/chunk-XA7J6PVJ.mjs +1488 -0
- package/dist/chunk-ZLYBRYWQ.mjs +726 -0
- package/dist/common.d.mts +921 -0
- package/dist/common.d.ts +921 -0
- package/dist/common.js +4991 -0
- package/dist/common.mjs +172 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +17563 -0
- package/dist/index.mjs +349 -0
- package/dist/ui.d.mts +937 -0
- package/dist/ui.d.ts +937 -0
- package/dist/ui.js +10095 -0
- package/dist/ui.mjs +163 -0
- package/package.json +114 -0
- package/styles/index.css +129 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-RBDK7MWQ.mjs";
|
|
5
|
+
|
|
6
|
+
// modules/ui/Spinner.tsx
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var sizeMap = {
|
|
9
|
+
xs: "h-3 w-3 border",
|
|
10
|
+
sm: "h-4 w-4 border-2",
|
|
11
|
+
md: "h-6 w-6 border-2",
|
|
12
|
+
lg: "h-8 w-8 border-[3px]",
|
|
13
|
+
xl: "h-12 w-12 border-4"
|
|
14
|
+
};
|
|
15
|
+
function Spinner({
|
|
16
|
+
size = "md",
|
|
17
|
+
className
|
|
18
|
+
}) {
|
|
19
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
"span",
|
|
22
|
+
{
|
|
23
|
+
"aria-hidden": "true",
|
|
24
|
+
className: cn(
|
|
25
|
+
"inline-block rounded-full border-border border-t-primary animate-spin",
|
|
26
|
+
sizeMap[size],
|
|
27
|
+
className
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading\u2026" })
|
|
32
|
+
] });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// modules/ui/SearchBar.tsx
|
|
36
|
+
import { useState } from "react";
|
|
37
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
38
|
+
import { faMagnifyingGlass, faXmark } from "@fortawesome/free-solid-svg-icons";
|
|
39
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
40
|
+
function SearchBar({
|
|
41
|
+
id = "search",
|
|
42
|
+
placeholder = "Search\u2026",
|
|
43
|
+
value,
|
|
44
|
+
onChange,
|
|
45
|
+
onClear,
|
|
46
|
+
className
|
|
47
|
+
}) {
|
|
48
|
+
const [internal, setInternal] = useState("");
|
|
49
|
+
const controlled = value !== void 0;
|
|
50
|
+
const currentValue = controlled ? value : internal;
|
|
51
|
+
function handleChange(e) {
|
|
52
|
+
if (!controlled) setInternal(e.target.value);
|
|
53
|
+
onChange == null ? void 0 : onChange(e.target.value);
|
|
54
|
+
}
|
|
55
|
+
function handleClear() {
|
|
56
|
+
if (!controlled) setInternal("");
|
|
57
|
+
onChange == null ? void 0 : onChange("");
|
|
58
|
+
onClear == null ? void 0 : onClear();
|
|
59
|
+
}
|
|
60
|
+
return /* @__PURE__ */ jsxs2("div", { className: cn("relative flex items-center", className), children: [
|
|
61
|
+
/* @__PURE__ */ jsx2(
|
|
62
|
+
"span",
|
|
63
|
+
{
|
|
64
|
+
"aria-hidden": "true",
|
|
65
|
+
className: "absolute left-3 text-text-disabled pointer-events-none",
|
|
66
|
+
children: /* @__PURE__ */ jsx2(FontAwesomeIcon, { icon: faMagnifyingGlass, className: "w-3.5 h-3.5" })
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
/* @__PURE__ */ jsx2(
|
|
70
|
+
"input",
|
|
71
|
+
{
|
|
72
|
+
id,
|
|
73
|
+
type: "text",
|
|
74
|
+
role: "searchbox",
|
|
75
|
+
value: currentValue,
|
|
76
|
+
onChange: handleChange,
|
|
77
|
+
placeholder,
|
|
78
|
+
autoComplete: "off",
|
|
79
|
+
"data-testid": `searchbar-${id}`,
|
|
80
|
+
className: cn(
|
|
81
|
+
"block w-full rounded-md border border-border bg-surface-base px-3 py-2 pl-8 text-sm",
|
|
82
|
+
"text-text-primary placeholder:text-text-disabled",
|
|
83
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:border-border-focus",
|
|
84
|
+
"transition-colors",
|
|
85
|
+
currentValue && "pr-8"
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
currentValue && /* @__PURE__ */ jsx2(
|
|
90
|
+
"button",
|
|
91
|
+
{
|
|
92
|
+
type: "button",
|
|
93
|
+
onClick: handleClear,
|
|
94
|
+
"aria-label": "Clear search",
|
|
95
|
+
className: "absolute right-2 text-text-disabled hover:text-text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded",
|
|
96
|
+
children: /* @__PURE__ */ jsx2(FontAwesomeIcon, { icon: faXmark, className: "w-3 h-3" })
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
] });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
Spinner,
|
|
104
|
+
SearchBar
|
|
105
|
+
};
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
__objRest,
|
|
4
|
+
__spreadValues,
|
|
5
|
+
cn
|
|
6
|
+
} from "./chunk-RBDK7MWQ.mjs";
|
|
7
|
+
|
|
8
|
+
// modules/ui/Input.tsx
|
|
9
|
+
import { forwardRef, useState } from "react";
|
|
10
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
11
|
+
import { faEye, faEyeSlash, faXmark, faChevronUp, faChevronDown } from "@fortawesome/free-solid-svg-icons";
|
|
12
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var Input = forwardRef(function Input2(_a, ref) {
|
|
14
|
+
var _b = _a, {
|
|
15
|
+
id,
|
|
16
|
+
label,
|
|
17
|
+
hint,
|
|
18
|
+
error,
|
|
19
|
+
success,
|
|
20
|
+
required,
|
|
21
|
+
prefixIcon,
|
|
22
|
+
suffixIcon,
|
|
23
|
+
clearable,
|
|
24
|
+
onClear,
|
|
25
|
+
showCount,
|
|
26
|
+
maxLength,
|
|
27
|
+
className,
|
|
28
|
+
value,
|
|
29
|
+
onChange,
|
|
30
|
+
readOnly,
|
|
31
|
+
type,
|
|
32
|
+
step,
|
|
33
|
+
min,
|
|
34
|
+
max
|
|
35
|
+
} = _b, props = __objRest(_b, [
|
|
36
|
+
"id",
|
|
37
|
+
"label",
|
|
38
|
+
"hint",
|
|
39
|
+
"error",
|
|
40
|
+
"success",
|
|
41
|
+
"required",
|
|
42
|
+
"prefixIcon",
|
|
43
|
+
"suffixIcon",
|
|
44
|
+
"clearable",
|
|
45
|
+
"onClear",
|
|
46
|
+
"showCount",
|
|
47
|
+
"maxLength",
|
|
48
|
+
"className",
|
|
49
|
+
"value",
|
|
50
|
+
"onChange",
|
|
51
|
+
"readOnly",
|
|
52
|
+
"type",
|
|
53
|
+
"step",
|
|
54
|
+
"min",
|
|
55
|
+
"max"
|
|
56
|
+
]);
|
|
57
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
58
|
+
const isPassword = type === "password";
|
|
59
|
+
const isNumber = type === "number";
|
|
60
|
+
const resolvedType = isPassword ? showPassword ? "text" : "password" : type;
|
|
61
|
+
const state = error ? "error" : success ? "success" : "default";
|
|
62
|
+
const describedBy = [
|
|
63
|
+
hint && !error && !success ? `${id}-hint` : null,
|
|
64
|
+
error ? `${id}-error` : null,
|
|
65
|
+
success && !error ? `${id}-success` : null
|
|
66
|
+
].filter(Boolean).join(" ");
|
|
67
|
+
const hasSuffix = suffixIcon || clearable && value || isPassword;
|
|
68
|
+
const hasPrefix = !!prefixIcon;
|
|
69
|
+
const inputBaseClass = cn(
|
|
70
|
+
"block w-full rounded-md border px-3 py-2 text-sm transition-colors",
|
|
71
|
+
"text-text-primary placeholder:text-text-disabled",
|
|
72
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
73
|
+
"disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-sunken",
|
|
74
|
+
"read-only:bg-surface-sunken read-only:cursor-default",
|
|
75
|
+
state === "error" && "border-error ring-1 ring-error bg-error-subtle",
|
|
76
|
+
state === "success" && "border-success ring-1 ring-success bg-success-subtle",
|
|
77
|
+
state === "default" && "border-border bg-surface-base",
|
|
78
|
+
hasPrefix && "pl-9",
|
|
79
|
+
(hasSuffix || isNumber) && "pr-9"
|
|
80
|
+
);
|
|
81
|
+
const charCount = typeof value === "string" ? value.length : 0;
|
|
82
|
+
function increment() {
|
|
83
|
+
const current = Number(value != null ? value : 0);
|
|
84
|
+
const stepVal = Number(step != null ? step : 1);
|
|
85
|
+
const maxVal = max !== void 0 ? Number(max) : Infinity;
|
|
86
|
+
const next = Math.min(current + stepVal, maxVal);
|
|
87
|
+
onChange == null ? void 0 : onChange({ target: { value: String(next) } });
|
|
88
|
+
}
|
|
89
|
+
function decrement() {
|
|
90
|
+
const current = Number(value != null ? value : 0);
|
|
91
|
+
const stepVal = Number(step != null ? step : 1);
|
|
92
|
+
const minVal = min !== void 0 ? Number(min) : -Infinity;
|
|
93
|
+
const next = Math.max(current - stepVal, minVal);
|
|
94
|
+
onChange == null ? void 0 : onChange({ target: { value: String(next) } });
|
|
95
|
+
}
|
|
96
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-1", className), children: [
|
|
97
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: id, className: "block text-sm font-medium text-text-primary", children: [
|
|
98
|
+
label,
|
|
99
|
+
required && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
100
|
+
/* @__PURE__ */ jsx("span", { className: "text-error ml-1", "aria-hidden": "true", children: "*" }),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "(required)" })
|
|
102
|
+
] }),
|
|
103
|
+
readOnly && /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-normal text-text-disabled", children: "(read-only)" })
|
|
104
|
+
] }),
|
|
105
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
106
|
+
prefixIcon && /* @__PURE__ */ jsx("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-disabled pointer-events-none", children: prefixIcon }),
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
"input",
|
|
109
|
+
__spreadValues({
|
|
110
|
+
ref,
|
|
111
|
+
id,
|
|
112
|
+
type: resolvedType,
|
|
113
|
+
required,
|
|
114
|
+
readOnly,
|
|
115
|
+
"aria-invalid": state === "error",
|
|
116
|
+
"aria-describedby": describedBy || void 0,
|
|
117
|
+
maxLength,
|
|
118
|
+
value,
|
|
119
|
+
onChange,
|
|
120
|
+
step,
|
|
121
|
+
min,
|
|
122
|
+
max,
|
|
123
|
+
className: cn(inputBaseClass, isNumber && "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none")
|
|
124
|
+
}, props)
|
|
125
|
+
),
|
|
126
|
+
isPassword && !readOnly && /* @__PURE__ */ jsx(
|
|
127
|
+
"button",
|
|
128
|
+
{
|
|
129
|
+
type: "button",
|
|
130
|
+
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
131
|
+
onClick: () => setShowPassword((v) => !v),
|
|
132
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-text-disabled hover:text-text-primary transition-colors focus-visible:outline-none text-sm",
|
|
133
|
+
children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: showPassword ? faEyeSlash : faEye, className: "w-3.5 h-3.5" })
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
clearable && value && !readOnly && !isPassword && /* @__PURE__ */ jsx(
|
|
137
|
+
"button",
|
|
138
|
+
{
|
|
139
|
+
type: "button",
|
|
140
|
+
"aria-label": "Clear",
|
|
141
|
+
onClick: onClear,
|
|
142
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-text-disabled hover:text-text-primary transition-colors focus-visible:outline-none",
|
|
143
|
+
children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faXmark, className: "w-3 h-3" })
|
|
144
|
+
}
|
|
145
|
+
),
|
|
146
|
+
suffixIcon && !clearable && !isPassword && /* @__PURE__ */ jsx("span", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-text-disabled pointer-events-none", children: suffixIcon }),
|
|
147
|
+
isNumber && !readOnly && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-0 h-full flex flex-col border-l border-border overflow-hidden rounded-r-md", children: [
|
|
148
|
+
/* @__PURE__ */ jsx(
|
|
149
|
+
"button",
|
|
150
|
+
{
|
|
151
|
+
type: "button",
|
|
152
|
+
"aria-label": "Increment",
|
|
153
|
+
onClick: increment,
|
|
154
|
+
tabIndex: -1,
|
|
155
|
+
className: "flex-1 px-2 text-text-secondary hover:bg-surface-overlay hover:text-text-primary transition-colors focus-visible:outline-none border-b border-border leading-none flex items-center justify-center",
|
|
156
|
+
children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faChevronUp, className: "w-2 h-2" })
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
/* @__PURE__ */ jsx(
|
|
160
|
+
"button",
|
|
161
|
+
{
|
|
162
|
+
type: "button",
|
|
163
|
+
"aria-label": "Decrement",
|
|
164
|
+
onClick: decrement,
|
|
165
|
+
tabIndex: -1,
|
|
166
|
+
className: "flex-1 px-2 text-text-secondary hover:bg-surface-overlay hover:text-text-primary transition-colors focus-visible:outline-none leading-none flex items-center justify-center",
|
|
167
|
+
children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faChevronDown, className: "w-2 h-2" })
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
] })
|
|
171
|
+
] }),
|
|
172
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
173
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
174
|
+
hint && !error && !success && /* @__PURE__ */ jsx("p", { id: `${id}-hint`, className: "text-xs text-text-secondary", children: hint }),
|
|
175
|
+
error && /* @__PURE__ */ jsx("p", { id: `${id}-error`, className: "text-xs text-error", role: "alert", children: error }),
|
|
176
|
+
success && !error && /* @__PURE__ */ jsx("p", { id: `${id}-success`, className: "text-xs text-success-fg", children: success })
|
|
177
|
+
] }),
|
|
178
|
+
showCount && maxLength && /* @__PURE__ */ jsxs("p", { className: cn("text-xs shrink-0", charCount >= maxLength ? "text-error" : "text-text-disabled"), children: [
|
|
179
|
+
charCount,
|
|
180
|
+
"/",
|
|
181
|
+
maxLength
|
|
182
|
+
] })
|
|
183
|
+
] })
|
|
184
|
+
] });
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// modules/ui/Textarea.tsx
|
|
188
|
+
import { forwardRef as forwardRef2 } from "react";
|
|
189
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
190
|
+
var Textarea = forwardRef2(function Textarea2(_a, ref) {
|
|
191
|
+
var _b = _a, {
|
|
192
|
+
id,
|
|
193
|
+
label,
|
|
194
|
+
hint,
|
|
195
|
+
error,
|
|
196
|
+
disabled,
|
|
197
|
+
required,
|
|
198
|
+
rows = 4,
|
|
199
|
+
className
|
|
200
|
+
} = _b, props = __objRest(_b, [
|
|
201
|
+
"id",
|
|
202
|
+
"label",
|
|
203
|
+
"hint",
|
|
204
|
+
"error",
|
|
205
|
+
"disabled",
|
|
206
|
+
"required",
|
|
207
|
+
"rows",
|
|
208
|
+
"className"
|
|
209
|
+
]);
|
|
210
|
+
const hintId = hint ? `${id}-hint` : void 0;
|
|
211
|
+
const errorId = error ? `${id}-error` : void 0;
|
|
212
|
+
const describedBy = [hintId, errorId].filter(Boolean).join(" ") || void 0;
|
|
213
|
+
return /* @__PURE__ */ jsxs2("div", { className: cn("space-y-1", className), children: [
|
|
214
|
+
/* @__PURE__ */ jsxs2("label", { htmlFor: id, className: "block text-sm font-medium text-text-primary", children: [
|
|
215
|
+
label,
|
|
216
|
+
required && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
217
|
+
/* @__PURE__ */ jsx2("span", { className: "text-error ml-1", "aria-hidden": "true", children: "*" }),
|
|
218
|
+
/* @__PURE__ */ jsx2("span", { className: "sr-only", children: "(required)" })
|
|
219
|
+
] })
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ jsx2(
|
|
222
|
+
"textarea",
|
|
223
|
+
__spreadValues({
|
|
224
|
+
ref,
|
|
225
|
+
id,
|
|
226
|
+
rows,
|
|
227
|
+
disabled,
|
|
228
|
+
required,
|
|
229
|
+
"aria-describedby": describedBy,
|
|
230
|
+
"aria-invalid": !!error,
|
|
231
|
+
"data-testid": `textarea-${id}`,
|
|
232
|
+
className: cn(
|
|
233
|
+
"block w-full rounded-md border px-3 py-2 text-sm transition-colors resize-y",
|
|
234
|
+
"text-text-primary placeholder:text-text-disabled",
|
|
235
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:border-border-focus",
|
|
236
|
+
"disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-sunken",
|
|
237
|
+
error ? "border-error ring-1 ring-error bg-error-subtle" : "border-border bg-surface-base"
|
|
238
|
+
)
|
|
239
|
+
}, props)
|
|
240
|
+
),
|
|
241
|
+
hint && !error && /* @__PURE__ */ jsx2("p", { id: hintId, className: "text-xs text-text-secondary", children: hint }),
|
|
242
|
+
error && /* @__PURE__ */ jsx2("p", { id: errorId, className: "text-xs text-error", role: "alert", children: error })
|
|
243
|
+
] });
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// modules/ui/Toggle.tsx
|
|
247
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
248
|
+
var sizeMap = {
|
|
249
|
+
sm: { track: "h-4 w-7", thumb: "h-3 w-3", on: "translate-x-3.5" },
|
|
250
|
+
md: { track: "h-5 w-9", thumb: "h-3.5 w-3.5", on: "translate-x-4" },
|
|
251
|
+
lg: { track: "h-6 w-11", thumb: "h-4 w-4", on: "translate-x-5" }
|
|
252
|
+
};
|
|
253
|
+
function Toggle({
|
|
254
|
+
id,
|
|
255
|
+
label,
|
|
256
|
+
description,
|
|
257
|
+
checked,
|
|
258
|
+
onChange,
|
|
259
|
+
disabled,
|
|
260
|
+
size = "md",
|
|
261
|
+
className
|
|
262
|
+
}) {
|
|
263
|
+
const { track, thumb, on } = sizeMap[size];
|
|
264
|
+
return /* @__PURE__ */ jsxs3(
|
|
265
|
+
"label",
|
|
266
|
+
{
|
|
267
|
+
htmlFor: id,
|
|
268
|
+
className: cn(
|
|
269
|
+
"flex items-start gap-3",
|
|
270
|
+
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
271
|
+
className
|
|
272
|
+
),
|
|
273
|
+
children: [
|
|
274
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative shrink-0 mt-0.5", children: [
|
|
275
|
+
/* @__PURE__ */ jsx3(
|
|
276
|
+
"input",
|
|
277
|
+
{
|
|
278
|
+
id,
|
|
279
|
+
type: "checkbox",
|
|
280
|
+
role: "switch",
|
|
281
|
+
checked,
|
|
282
|
+
onChange: (e) => onChange(e.target.checked),
|
|
283
|
+
disabled,
|
|
284
|
+
"aria-checked": checked,
|
|
285
|
+
"data-testid": `toggle-${id}`,
|
|
286
|
+
className: "sr-only"
|
|
287
|
+
}
|
|
288
|
+
),
|
|
289
|
+
/* @__PURE__ */ jsx3(
|
|
290
|
+
"div",
|
|
291
|
+
{
|
|
292
|
+
className: cn(
|
|
293
|
+
"rounded-full transition-colors duration-200",
|
|
294
|
+
track,
|
|
295
|
+
checked ? "bg-primary" : "bg-surface-sunken border border-border"
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
),
|
|
299
|
+
/* @__PURE__ */ jsx3(
|
|
300
|
+
"div",
|
|
301
|
+
{
|
|
302
|
+
className: cn(
|
|
303
|
+
"absolute top-0.5 left-0.5 rounded-full bg-white shadow-sm transition-transform duration-200",
|
|
304
|
+
thumb,
|
|
305
|
+
checked ? on : "translate-x-0"
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
)
|
|
309
|
+
] }),
|
|
310
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
311
|
+
/* @__PURE__ */ jsx3("span", { className: "text-sm font-medium text-text-primary", children: label }),
|
|
312
|
+
description && /* @__PURE__ */ jsx3("p", { className: "text-xs text-text-secondary mt-0.5", children: description })
|
|
313
|
+
] })
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// modules/ui/RadioGroup.tsx
|
|
320
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
321
|
+
function RadioGroup({
|
|
322
|
+
name,
|
|
323
|
+
legend,
|
|
324
|
+
options,
|
|
325
|
+
value,
|
|
326
|
+
onChange,
|
|
327
|
+
error,
|
|
328
|
+
disabled,
|
|
329
|
+
className,
|
|
330
|
+
optionClassName,
|
|
331
|
+
variant = "default",
|
|
332
|
+
columns = 1
|
|
333
|
+
}) {
|
|
334
|
+
return /* @__PURE__ */ jsxs4("fieldset", { className: cn("space-y-1", className), children: [
|
|
335
|
+
/* @__PURE__ */ jsx4("legend", { className: "mb-2 text-sm font-medium text-text-primary", children: legend }),
|
|
336
|
+
/* @__PURE__ */ jsx4(
|
|
337
|
+
"div",
|
|
338
|
+
{
|
|
339
|
+
className: cn(
|
|
340
|
+
columns === 1 && "space-y-2",
|
|
341
|
+
columns > 1 && "grid gap-2",
|
|
342
|
+
columns === 2 && "grid-cols-1 sm:grid-cols-2",
|
|
343
|
+
columns === 3 && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
|
|
344
|
+
),
|
|
345
|
+
children: options.map((opt) => {
|
|
346
|
+
const isSelected = value === opt.value;
|
|
347
|
+
return /* @__PURE__ */ jsxs4(
|
|
348
|
+
"label",
|
|
349
|
+
{
|
|
350
|
+
className: cn(
|
|
351
|
+
"flex items-start gap-2",
|
|
352
|
+
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
353
|
+
variant === "card" && [
|
|
354
|
+
"rounded-lg border border-border bg-surface-base p-3 transition-colors",
|
|
355
|
+
"hover:border-border-focus",
|
|
356
|
+
isSelected && "border-primary bg-primary/5",
|
|
357
|
+
error && "border-error"
|
|
358
|
+
],
|
|
359
|
+
optionClassName
|
|
360
|
+
),
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsx4(
|
|
363
|
+
"input",
|
|
364
|
+
{
|
|
365
|
+
type: "radio",
|
|
366
|
+
name,
|
|
367
|
+
value: opt.value,
|
|
368
|
+
checked: isSelected,
|
|
369
|
+
disabled,
|
|
370
|
+
onChange: () => onChange == null ? void 0 : onChange(opt.value),
|
|
371
|
+
"data-testid": `radio-${name}-${opt.value}`,
|
|
372
|
+
className: cn(
|
|
373
|
+
"mt-0.5 h-4 w-4 border-border text-primary",
|
|
374
|
+
"focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
375
|
+
error && "border-error"
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
),
|
|
379
|
+
/* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
|
|
380
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
381
|
+
opt.icon && /* @__PURE__ */ jsx4("span", { className: "text-lg leading-none text-text-secondary", children: opt.icon }),
|
|
382
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sm text-text-primary", children: opt.label })
|
|
383
|
+
] }),
|
|
384
|
+
opt.hint && /* @__PURE__ */ jsx4("p", { className: "mt-0.5 text-xs text-text-secondary", children: opt.hint })
|
|
385
|
+
] })
|
|
386
|
+
]
|
|
387
|
+
},
|
|
388
|
+
opt.value
|
|
389
|
+
);
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
),
|
|
393
|
+
error && /* @__PURE__ */ jsx4("p", { className: "mt-1 text-xs text-error", role: "alert", children: error })
|
|
394
|
+
] });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export {
|
|
398
|
+
Input,
|
|
399
|
+
Textarea,
|
|
400
|
+
Toggle,
|
|
401
|
+
RadioGroup
|
|
402
|
+
};
|