@fanvue/ui 1.3.0 → 1.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/dist/cjs/components/Alert/Alert.cjs +1 -1
- package/dist/cjs/components/Alert/Alert.cjs.map +1 -1
- package/dist/cjs/components/AudioUpload/AudioUpload.cjs +286 -0
- package/dist/cjs/components/AudioUpload/AudioUpload.cjs.map +1 -0
- package/dist/cjs/components/AudioUpload/AudioWaveform.cjs +121 -0
- package/dist/cjs/components/AudioUpload/AudioWaveform.cjs.map +1 -0
- package/dist/cjs/components/AudioUpload/audioUtils.cjs +44 -0
- package/dist/cjs/components/AudioUpload/audioUtils.cjs.map +1 -0
- package/dist/cjs/components/AudioUpload/constants.cjs +21 -0
- package/dist/cjs/components/AudioUpload/constants.cjs.map +1 -0
- package/dist/cjs/components/AudioUpload/useAudioRecorder.cjs +191 -0
- package/dist/cjs/components/AudioUpload/useAudioRecorder.cjs.map +1 -0
- package/dist/cjs/components/Badge/Badge.cjs +2 -2
- package/dist/cjs/components/Badge/Badge.cjs.map +1 -1
- package/dist/cjs/components/Button/Button.cjs +1 -1
- package/dist/cjs/components/Button/Button.cjs.map +1 -1
- package/dist/cjs/components/DatePicker/DatePicker.cjs +1 -1
- package/dist/cjs/components/DatePicker/DatePicker.cjs.map +1 -1
- package/dist/cjs/components/Icons/CheckOutlineIcon.cjs +55 -0
- package/dist/cjs/components/Icons/CheckOutlineIcon.cjs.map +1 -0
- package/dist/cjs/components/Icons/ChevronDownIcon.cjs +49 -0
- package/dist/cjs/components/Icons/ChevronDownIcon.cjs.map +1 -0
- package/dist/cjs/components/Icons/SearchIcon.cjs +63 -0
- package/dist/cjs/components/Icons/SearchIcon.cjs.map +1 -0
- package/dist/cjs/components/Icons/SpinnerIcon.cjs.map +1 -1
- package/dist/cjs/components/Icons/UploadCloudIcon.cjs +61 -0
- package/dist/cjs/components/Icons/UploadCloudIcon.cjs.map +1 -0
- package/dist/cjs/components/Loader/Loader.cjs +59 -0
- package/dist/cjs/components/Loader/Loader.cjs.map +1 -0
- package/dist/cjs/components/SearchField/SearchField.cjs +98 -0
- package/dist/cjs/components/SearchField/SearchField.cjs.map +1 -0
- package/dist/cjs/components/Select/Select.cjs +212 -0
- package/dist/cjs/components/Select/Select.cjs.map +1 -0
- package/dist/cjs/components/TextArea/TextArea.cjs +235 -0
- package/dist/cjs/components/TextArea/TextArea.cjs.map +1 -0
- package/dist/cjs/components/TextField/TextField.cjs +26 -34
- package/dist/cjs/components/TextField/TextField.cjs.map +1 -1
- package/dist/cjs/date-picker.cjs +6 -0
- package/dist/cjs/date-picker.cjs.map +1 -0
- package/dist/cjs/index.cjs +25 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/Alert/Alert.mjs +1 -1
- package/dist/components/Alert/Alert.mjs.map +1 -1
- package/dist/components/AudioUpload/AudioUpload.mjs +269 -0
- package/dist/components/AudioUpload/AudioUpload.mjs.map +1 -0
- package/dist/components/AudioUpload/AudioWaveform.mjs +104 -0
- package/dist/components/AudioUpload/AudioWaveform.mjs.map +1 -0
- package/dist/components/AudioUpload/audioUtils.mjs +44 -0
- package/dist/components/AudioUpload/audioUtils.mjs.map +1 -0
- package/dist/components/AudioUpload/constants.mjs +21 -0
- package/dist/components/AudioUpload/constants.mjs.map +1 -0
- package/dist/components/AudioUpload/useAudioRecorder.mjs +174 -0
- package/dist/components/AudioUpload/useAudioRecorder.mjs.map +1 -0
- package/dist/components/Badge/Badge.mjs +2 -2
- package/dist/components/Badge/Badge.mjs.map +1 -1
- package/dist/components/Button/Button.mjs +1 -1
- package/dist/components/Button/Button.mjs.map +1 -1
- package/dist/components/DatePicker/DatePicker.mjs +1 -1
- package/dist/components/DatePicker/DatePicker.mjs.map +1 -1
- package/dist/components/Icons/CheckOutlineIcon.mjs +38 -0
- package/dist/components/Icons/CheckOutlineIcon.mjs.map +1 -0
- package/dist/components/Icons/ChevronDownIcon.mjs +32 -0
- package/dist/components/Icons/ChevronDownIcon.mjs.map +1 -0
- package/dist/components/Icons/SearchIcon.mjs +46 -0
- package/dist/components/Icons/SearchIcon.mjs.map +1 -0
- package/dist/components/Icons/SpinnerIcon.mjs.map +1 -1
- package/dist/components/Icons/UploadCloudIcon.mjs +44 -0
- package/dist/components/Icons/UploadCloudIcon.mjs.map +1 -0
- package/dist/components/Loader/Loader.mjs +42 -0
- package/dist/components/Loader/Loader.mjs.map +1 -0
- package/dist/components/SearchField/SearchField.mjs +81 -0
- package/dist/components/SearchField/SearchField.mjs.map +1 -0
- package/dist/components/Select/Select.mjs +194 -0
- package/dist/components/Select/Select.mjs.map +1 -0
- package/dist/components/TextArea/TextArea.mjs +218 -0
- package/dist/components/TextArea/TextArea.mjs.map +1 -0
- package/dist/components/TextField/TextField.mjs +26 -34
- package/dist/components/TextField/TextField.mjs.map +1 -1
- package/dist/date-picker.d.ts +75 -0
- package/dist/date-picker.mjs +6 -0
- package/dist/date-picker.mjs.map +1 -0
- package/dist/index.d.ts +320 -52
- package/dist/index.mjs +26 -3
- package/dist/index.mjs.map +1 -1
- package/dist/styles/theme.css +16 -4
- package/package.json +15 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const React = require("react");
|
|
6
|
+
const cn = require("../../utils/cn.cjs");
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
8
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
9
|
+
if (e) {
|
|
10
|
+
for (const k in e) {
|
|
11
|
+
if (k !== "default") {
|
|
12
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: () => e[k]
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
24
|
+
const UploadCloudIcon = React__namespace.forwardRef(
|
|
25
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26
|
+
"svg",
|
|
27
|
+
{
|
|
28
|
+
ref,
|
|
29
|
+
viewBox: "0 0 20 20",
|
|
30
|
+
fill: "none",
|
|
31
|
+
"aria-hidden": "true",
|
|
32
|
+
className: cn.cn("size-5", className),
|
|
33
|
+
...props,
|
|
34
|
+
children: [
|
|
35
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36
|
+
"path",
|
|
37
|
+
{
|
|
38
|
+
d: "M6.667 13.333 10 10m0 0 3.333 3.333M10 10v7.5",
|
|
39
|
+
stroke: "currentColor",
|
|
40
|
+
strokeWidth: 1.5,
|
|
41
|
+
strokeLinecap: "round",
|
|
42
|
+
strokeLinejoin: "round"
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
46
|
+
"path",
|
|
47
|
+
{
|
|
48
|
+
d: "M16.992 14.825a4.167 4.167 0 0 0-2.159-7.158 5.835 5.835 0 0 0-10.75 2.916A3.333 3.333 0 0 0 5 17.5h11.167a4.167 4.167 0 0 0 .825-2.675Z",
|
|
49
|
+
stroke: "currentColor",
|
|
50
|
+
strokeWidth: 1.5,
|
|
51
|
+
strokeLinecap: "round",
|
|
52
|
+
strokeLinejoin: "round"
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
UploadCloudIcon.displayName = "UploadCloudIcon";
|
|
60
|
+
exports.UploadCloudIcon = UploadCloudIcon;
|
|
61
|
+
//# sourceMappingURL=UploadCloudIcon.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UploadCloudIcon.cjs","sources":["../../../../src/components/Icons/UploadCloudIcon.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport type { IconProps } from \"./types\";\n\n/** An upload-to-cloud icon with an upward arrow (20 × 20). */\nexport const UploadCloudIcon = React.forwardRef<SVGSVGElement, IconProps>(\n ({ className, ...props }, ref) => (\n <svg\n ref={ref}\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n aria-hidden=\"true\"\n className={cn(\"size-5\", className)}\n {...props}\n >\n <path\n d=\"M6.667 13.333 10 10m0 0 3.333 3.333M10 10v7.5\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M16.992 14.825a4.167 4.167 0 0 0-2.159-7.158 5.835 5.835 0 0 0-10.75 2.916A3.333 3.333 0 0 0 5 17.5h11.167a4.167 4.167 0 0 0 .825-2.675Z\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n ),\n);\n\nUploadCloudIcon.displayName = \"UploadCloudIcon\";\n"],"names":["React","jsxs","cn","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAKO,MAAM,kBAAkBA,iBAAM;AAAA,EACnC,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QACxBC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,eAAY;AAAA,MACZ,WAAWC,GAAAA,GAAG,UAAU,SAAS;AAAA,MAChC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAAC,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,GAAE;AAAA,YACF,QAAO;AAAA,YACP,aAAa;AAAA,YACb,eAAc;AAAA,YACd,gBAAe;AAAA,UAAA;AAAA,QAAA;AAAA,QAEjBA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,GAAE;AAAA,YACF,QAAO;AAAA,YACP,aAAa;AAAA,YACb,eAAc;AAAA,YACd,gBAAe;AAAA,UAAA;AAAA,QAAA;AAAA,MACjB;AAAA,IAAA;AAAA,EAAA;AAGN;AAEA,gBAAgB,cAAc;;"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const React = require("react");
|
|
6
|
+
const cn = require("../../utils/cn.cjs");
|
|
7
|
+
const SpinnerIcon = require("../Icons/SpinnerIcon.cjs");
|
|
8
|
+
function _interopNamespaceDefault(e) {
|
|
9
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
10
|
+
if (e) {
|
|
11
|
+
for (const k in e) {
|
|
12
|
+
if (k !== "default") {
|
|
13
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: () => e[k]
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
25
|
+
const Loader = React__namespace.forwardRef(
|
|
26
|
+
({ show = true, ariaLabel, minHeight = "100%", center, centerX, centerY, className, ...props }, ref) => {
|
|
27
|
+
if (!show) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const shouldCenterX = center || centerX;
|
|
31
|
+
const shouldCenterY = center || centerY;
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
33
|
+
"div",
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
className: cn.cn("relative", className),
|
|
37
|
+
style: {
|
|
38
|
+
minHeight: typeof minHeight === "number" ? `${minHeight}px` : minHeight
|
|
39
|
+
},
|
|
40
|
+
...props,
|
|
41
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42
|
+
"output",
|
|
43
|
+
{
|
|
44
|
+
className: cn.cn(
|
|
45
|
+
"absolute flex size-[60px] items-center justify-center",
|
|
46
|
+
shouldCenterX && "left-1/2 -translate-x-1/2",
|
|
47
|
+
shouldCenterY && "top-1/2 -translate-y-1/2"
|
|
48
|
+
),
|
|
49
|
+
"aria-label": ariaLabel ?? "loading",
|
|
50
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon.SpinnerIcon, { className: "size-9 animate-spin text-body-200" })
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
Loader.displayName = "Loader";
|
|
58
|
+
exports.Loader = Loader;
|
|
59
|
+
//# sourceMappingURL=Loader.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Loader.cjs","sources":["../../../../src/components/Loader/Loader.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { SpinnerIcon } from \"../Icons/SpinnerIcon\";\n\nexport interface LoaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether the loader is visible. When `false`, renders nothing. @default true */\n show?: boolean;\n /** Accessible label for the loading indicator. @default \"loading\" */\n ariaLabel?: string;\n /** Minimum height of the container. Numbers are treated as pixels. @default \"100%\" */\n minHeight?: number | string;\n /** Center the spinner horizontally. @default false */\n center?: boolean;\n /** Center the spinner horizontally. @default false */\n centerX?: boolean;\n /** Center the spinner vertically. @default false */\n centerY?: boolean;\n}\n\n/**\n * A layout-aware loading indicator that renders a centered `SpinnerIcon` inside\n * a relatively-positioned container. Drop-in replacement for the Olympus `Loader`.\n *\n * @example\n * ```tsx\n * <Loader show center />\n * <Loader show centerX minHeight={200} />\n * ```\n */\nexport const Loader = React.forwardRef<HTMLDivElement, LoaderProps>(\n (\n { show = true, ariaLabel, minHeight = \"100%\", center, centerX, centerY, className, ...props },\n ref,\n ) => {\n if (!show) {\n return null;\n }\n\n const shouldCenterX = center || centerX;\n const shouldCenterY = center || centerY;\n\n return (\n <div\n ref={ref}\n className={cn(\"relative\", className)}\n style={{\n minHeight: typeof minHeight === \"number\" ? `${minHeight}px` : minHeight,\n }}\n {...props}\n >\n <output\n className={cn(\n \"absolute flex size-[60px] items-center justify-center\",\n shouldCenterX && \"left-1/2 -translate-x-1/2\",\n shouldCenterY && \"top-1/2 -translate-y-1/2\",\n )}\n aria-label={ariaLabel ?? \"loading\"}\n >\n <SpinnerIcon className=\"size-9 animate-spin text-body-200\" />\n </output>\n </div>\n );\n },\n);\n\nLoader.displayName = \"Loader\";\n"],"names":["React","jsx","cn","SpinnerIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6BO,MAAM,SAASA,iBAAM;AAAA,EAC1B,CACE,EAAE,OAAO,MAAM,WAAW,YAAY,QAAQ,QAAQ,SAAS,SAAS,WAAW,GAAG,MAAA,GACtF,QACG;AACH,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAEA,UAAM,gBAAgB,UAAU;AAChC,UAAM,gBAAgB,UAAU;AAEhC,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAWC,GAAAA,GAAG,YAAY,SAAS;AAAA,QACnC,OAAO;AAAA,UACL,WAAW,OAAO,cAAc,WAAW,GAAG,SAAS,OAAO;AAAA,QAAA;AAAA,QAE/D,GAAG;AAAA,QAEJ,UAAAD,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWC,GAAAA;AAAAA,cACT;AAAA,cACA,iBAAiB;AAAA,cACjB,iBAAiB;AAAA,YAAA;AAAA,YAEnB,cAAY,aAAa;AAAA,YAEzB,UAAAD,2BAAAA,IAACE,YAAAA,aAAA,EAAY,WAAU,oCAAA,CAAoC;AAAA,UAAA;AAAA,QAAA;AAAA,MAC7D;AAAA,IAAA;AAAA,EAGN;AACF;AAEA,OAAO,cAAc;;"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const React = require("react");
|
|
6
|
+
const IconButton = require("../IconButton/IconButton.cjs");
|
|
7
|
+
const CloseIcon = require("../Icons/CloseIcon.cjs");
|
|
8
|
+
const SearchIcon = require("../Icons/SearchIcon.cjs");
|
|
9
|
+
const TextField = require("../TextField/TextField.cjs");
|
|
10
|
+
function _interopNamespaceDefault(e) {
|
|
11
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
12
|
+
if (e) {
|
|
13
|
+
for (const k in e) {
|
|
14
|
+
if (k !== "default") {
|
|
15
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: () => e[k]
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
27
|
+
const SearchField = React__namespace.forwardRef(
|
|
28
|
+
({ disabled, onClear, value, debounceMs, minChars, onChange, ...props }, ref) => {
|
|
29
|
+
const [internalValue, setInternalValue] = React__namespace.useState(value ?? "");
|
|
30
|
+
const timeoutRef = React__namespace.useRef(void 0);
|
|
31
|
+
React__namespace.useEffect(() => {
|
|
32
|
+
if (value !== void 0) {
|
|
33
|
+
setInternalValue(value);
|
|
34
|
+
}
|
|
35
|
+
}, [value]);
|
|
36
|
+
React__namespace.useEffect(() => {
|
|
37
|
+
return () => {
|
|
38
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
const shouldFireChange = React__namespace.useCallback(
|
|
42
|
+
(val) => !minChars || val.length >= minChars,
|
|
43
|
+
[minChars]
|
|
44
|
+
);
|
|
45
|
+
const handleChange = React__namespace.useCallback(
|
|
46
|
+
(e) => {
|
|
47
|
+
const val = e.target.value;
|
|
48
|
+
if (!debounceMs) {
|
|
49
|
+
setInternalValue(val);
|
|
50
|
+
if (shouldFireChange(val)) onChange?.(e);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
setInternalValue(val);
|
|
54
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
55
|
+
timeoutRef.current = setTimeout(() => {
|
|
56
|
+
if (shouldFireChange(val)) onChange?.(e);
|
|
57
|
+
}, debounceMs);
|
|
58
|
+
},
|
|
59
|
+
[debounceMs, onChange, shouldFireChange]
|
|
60
|
+
);
|
|
61
|
+
const handleClear = React__namespace.useCallback(() => {
|
|
62
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
63
|
+
setInternalValue("");
|
|
64
|
+
onClear?.();
|
|
65
|
+
}, [onClear]);
|
|
66
|
+
const displayValue = debounceMs || minChars ? internalValue : value;
|
|
67
|
+
const leftIcon = /* @__PURE__ */ jsxRuntime.jsx(SearchIcon.SearchIcon, {});
|
|
68
|
+
const showClearButton = onClear && displayValue !== void 0 && displayValue !== "";
|
|
69
|
+
const rightIcon = showClearButton ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
70
|
+
IconButton.IconButton,
|
|
71
|
+
{
|
|
72
|
+
variant: "tertiary",
|
|
73
|
+
size: "24",
|
|
74
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon.CloseIcon, {}),
|
|
75
|
+
"aria-label": "Clear search",
|
|
76
|
+
disabled,
|
|
77
|
+
onClick: handleClear
|
|
78
|
+
}
|
|
79
|
+
) : void 0;
|
|
80
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
81
|
+
TextField.TextField,
|
|
82
|
+
{
|
|
83
|
+
ref,
|
|
84
|
+
type: "search",
|
|
85
|
+
disabled,
|
|
86
|
+
leftIcon,
|
|
87
|
+
rightIcon,
|
|
88
|
+
value: displayValue,
|
|
89
|
+
onChange: handleChange,
|
|
90
|
+
"aria-label": !props.label ? "Search field" : void 0,
|
|
91
|
+
...props
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
SearchField.displayName = "SearchField";
|
|
97
|
+
exports.SearchField = SearchField;
|
|
98
|
+
//# sourceMappingURL=SearchField.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchField.cjs","sources":["../../../../src/components/SearchField/SearchField.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SearchIcon } from \"../Icons/SearchIcon\";\nimport { TextField, type TextFieldProps } from \"../TextField/TextField\";\n\nexport type SearchFieldSize = \"48\" | \"40\" | \"32\";\n\nexport interface SearchFieldProps extends Omit<TextFieldProps, \"type\" | \"leftIcon\"> {\n /** Size variant of the search field. @default \"48\" */\n size?: SearchFieldSize;\n /** Callback fired when the clear button is clicked. If provided, a clear button appears when the field has a value. */\n onClear?: () => void;\n /** Debounce delay in milliseconds for the onChange callback. When set, the input maintains internal state for responsive typing while debouncing onChange to the parent. */\n debounceMs?: number;\n /** Minimum number of characters required before onChange fires. The input still updates visually, but onChange is suppressed until the threshold is met. Clearing always fires onClear regardless. */\n minChars?: number;\n}\n\n/**\n * A text input field with a search icon and optional clear button.\n *\n * @example\n * ```tsx\n * <SearchField\n * placeholder=\"Search...\"\n * value={query}\n * onChange={(e) => setQuery(e.target.value)}\n * onClear={() => setQuery(\"\")}\n * debounceMs={500}\n * minChars={3}\n * />\n * ```\n */\nexport const SearchField = React.forwardRef<HTMLInputElement, SearchFieldProps>(\n ({ disabled, onClear, value, debounceMs, minChars, onChange, ...props }, ref) => {\n const [internalValue, setInternalValue] = React.useState(value ?? \"\");\n const timeoutRef = React.useRef<ReturnType<typeof setTimeout>>(undefined);\n\n React.useEffect(() => {\n if (value !== undefined) {\n setInternalValue(value);\n }\n }, [value]);\n\n React.useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n const shouldFireChange = React.useCallback(\n (val: string) => !minChars || val.length >= minChars,\n [minChars],\n );\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n\n if (!debounceMs) {\n setInternalValue(val);\n if (shouldFireChange(val)) onChange?.(e);\n return;\n }\n\n setInternalValue(val);\n\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n\n timeoutRef.current = setTimeout(() => {\n if (shouldFireChange(val)) onChange?.(e);\n }, debounceMs);\n },\n [debounceMs, onChange, shouldFireChange],\n );\n\n const handleClear = React.useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n setInternalValue(\"\");\n onClear?.();\n }, [onClear]);\n\n const displayValue = debounceMs || minChars ? internalValue : value;\n const leftIcon = <SearchIcon />;\n\n const showClearButton = onClear && displayValue !== undefined && displayValue !== \"\";\n\n const rightIcon = showClearButton ? (\n <IconButton\n variant=\"tertiary\"\n size=\"24\"\n icon={<CloseIcon />}\n aria-label=\"Clear search\"\n disabled={disabled}\n onClick={handleClear}\n />\n ) : undefined;\n\n return (\n <TextField\n ref={ref}\n type=\"search\"\n disabled={disabled}\n leftIcon={leftIcon}\n rightIcon={rightIcon}\n value={displayValue}\n onChange={handleChange}\n aria-label={!props.label ? \"Search field\" : undefined}\n {...props}\n />\n );\n },\n);\n\nSearchField.displayName = \"SearchField\";\n"],"names":["React","SearchIcon","jsx","IconButton","CloseIcon","TextField"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkCO,MAAM,cAAcA,iBAAM;AAAA,EAC/B,CAAC,EAAE,UAAU,SAAS,OAAO,YAAY,UAAU,UAAU,GAAG,MAAA,GAAS,QAAQ;AAC/E,UAAM,CAAC,eAAe,gBAAgB,IAAIA,iBAAM,SAAS,SAAS,EAAE;AACpE,UAAM,aAAaA,iBAAM,OAAsC,MAAS;AAExEA,qBAAM,UAAU,MAAM;AACpB,UAAI,UAAU,QAAW;AACvB,yBAAiB,KAAK;AAAA,MACxB;AAAA,IACF,GAAG,CAAC,KAAK,CAAC;AAEVA,qBAAM,UAAU,MAAM;AACpB,aAAO,MAAM;AACX,YAAI,WAAW,QAAS,cAAa,WAAW,OAAO;AAAA,MACzD;AAAA,IACF,GAAG,CAAA,CAAE;AAEL,UAAM,mBAAmBA,iBAAM;AAAA,MAC7B,CAAC,QAAgB,CAAC,YAAY,IAAI,UAAU;AAAA,MAC5C,CAAC,QAAQ;AAAA,IAAA;AAGX,UAAM,eAAeA,iBAAM;AAAA,MACzB,CAAC,MAA2C;AAC1C,cAAM,MAAM,EAAE,OAAO;AAErB,YAAI,CAAC,YAAY;AACf,2BAAiB,GAAG;AACpB,cAAI,iBAAiB,GAAG,EAAG,YAAW,CAAC;AACvC;AAAA,QACF;AAEA,yBAAiB,GAAG;AAEpB,YAAI,WAAW,QAAS,cAAa,WAAW,OAAO;AAEvD,mBAAW,UAAU,WAAW,MAAM;AACpC,cAAI,iBAAiB,GAAG,EAAG,YAAW,CAAC;AAAA,QACzC,GAAG,UAAU;AAAA,MACf;AAAA,MACA,CAAC,YAAY,UAAU,gBAAgB;AAAA,IAAA;AAGzC,UAAM,cAAcA,iBAAM,YAAY,MAAM;AAC1C,UAAI,WAAW,QAAS,cAAa,WAAW,OAAO;AACvD,uBAAiB,EAAE;AACnB,gBAAA;AAAA,IACF,GAAG,CAAC,OAAO,CAAC;AAEZ,UAAM,eAAe,cAAc,WAAW,gBAAgB;AAC9D,UAAM,0CAAYC,WAAAA,YAAA,EAAW;AAE7B,UAAM,kBAAkB,WAAW,iBAAiB,UAAa,iBAAiB;AAElF,UAAM,YAAY,kBAChBC,2BAAAA;AAAAA,MAACC,WAAAA;AAAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,qCAAOC,UAAAA,WAAA,EAAU;AAAA,QACjB,cAAW;AAAA,QACX;AAAA,QACA,SAAS;AAAA,MAAA;AAAA,IAAA,IAET;AAEJ,WACEF,2BAAAA;AAAAA,MAACG,UAAAA;AAAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,UAAU;AAAA,QACV,cAAY,CAAC,MAAM,QAAQ,iBAAiB;AAAA,QAC3C,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,YAAY,cAAc;;"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const SelectPrimitive = require("@radix-ui/react-select");
|
|
6
|
+
const React = require("react");
|
|
7
|
+
const cn = require("../../utils/cn.cjs");
|
|
8
|
+
const CheckIcon = require("../Icons/CheckIcon.cjs");
|
|
9
|
+
const ChevronDownIcon = require("../Icons/ChevronDownIcon.cjs");
|
|
10
|
+
function _interopNamespaceDefault(e) {
|
|
11
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
12
|
+
if (e) {
|
|
13
|
+
for (const k in e) {
|
|
14
|
+
if (k !== "default") {
|
|
15
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: () => e[k]
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
const SelectPrimitive__namespace = /* @__PURE__ */ _interopNamespaceDefault(SelectPrimitive);
|
|
27
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
28
|
+
const SelectContext = React__namespace.createContext({
|
|
29
|
+
size: "48",
|
|
30
|
+
error: false
|
|
31
|
+
});
|
|
32
|
+
const TRIGGER_HEIGHT = {
|
|
33
|
+
"48": "h-12",
|
|
34
|
+
"40": "h-10",
|
|
35
|
+
"32": "h-8"
|
|
36
|
+
};
|
|
37
|
+
const TRIGGER_PADDING_X = {
|
|
38
|
+
"48": "px-4",
|
|
39
|
+
"40": "px-4",
|
|
40
|
+
"32": "px-3"
|
|
41
|
+
};
|
|
42
|
+
const TRIGGER_GAP = {
|
|
43
|
+
"48": "gap-3",
|
|
44
|
+
"40": "gap-3",
|
|
45
|
+
"32": "gap-2"
|
|
46
|
+
};
|
|
47
|
+
const TRIGGER_TYPOGRAPHY = {
|
|
48
|
+
"48": "typography-body-1-regular",
|
|
49
|
+
"40": "typography-body-1-regular",
|
|
50
|
+
"32": "typography-body-2-regular"
|
|
51
|
+
};
|
|
52
|
+
const Select = React__namespace.forwardRef(
|
|
53
|
+
({
|
|
54
|
+
label,
|
|
55
|
+
helperText,
|
|
56
|
+
size = "48",
|
|
57
|
+
error = false,
|
|
58
|
+
errorMessage,
|
|
59
|
+
placeholder,
|
|
60
|
+
leftIcon,
|
|
61
|
+
fullWidth = false,
|
|
62
|
+
className,
|
|
63
|
+
id,
|
|
64
|
+
disabled,
|
|
65
|
+
children,
|
|
66
|
+
"aria-label": ariaLabel,
|
|
67
|
+
"aria-labelledby": ariaLabelledby,
|
|
68
|
+
...props
|
|
69
|
+
}, ref) => {
|
|
70
|
+
const generatedId = React__namespace.useId();
|
|
71
|
+
const triggerId = id ?? generatedId;
|
|
72
|
+
const helperTextId = `${triggerId}-helper`;
|
|
73
|
+
const bottomText = error && errorMessage ? errorMessage : helperText;
|
|
74
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SelectContext.Provider, { value: { size, error, disabled }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
75
|
+
"div",
|
|
76
|
+
{
|
|
77
|
+
className: cn.cn("flex flex-col", fullWidth && "w-full", className),
|
|
78
|
+
"data-disabled": disabled ? "" : void 0,
|
|
79
|
+
"data-error": error ? "" : void 0,
|
|
80
|
+
children: [
|
|
81
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(
|
|
82
|
+
"label",
|
|
83
|
+
{
|
|
84
|
+
htmlFor: triggerId,
|
|
85
|
+
className: "typography-caption-semibold px-1 pt-1 pb-2 text-body-100",
|
|
86
|
+
children: label
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SelectPrimitive__namespace.Root, { disabled, ...props, children: [
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
91
|
+
SelectPrimitive__namespace.Trigger,
|
|
92
|
+
{
|
|
93
|
+
ref,
|
|
94
|
+
id: triggerId,
|
|
95
|
+
"aria-label": ariaLabel,
|
|
96
|
+
"aria-labelledby": ariaLabelledby,
|
|
97
|
+
"aria-describedby": bottomText ? helperTextId : void 0,
|
|
98
|
+
"aria-invalid": error || void 0,
|
|
99
|
+
className: cn.cn(
|
|
100
|
+
"flex w-full cursor-pointer items-center justify-between rounded-xl border bg-neutral-100 outline-none motion-safe:transition-colors",
|
|
101
|
+
TRIGGER_HEIGHT[size],
|
|
102
|
+
TRIGGER_PADDING_X[size],
|
|
103
|
+
TRIGGER_GAP[size],
|
|
104
|
+
TRIGGER_TYPOGRAPHY[size],
|
|
105
|
+
error ? "border-error-500" : "border-transparent",
|
|
106
|
+
!disabled && !error && "hover:border-neutral-400 data-[state=open]:border-neutral-400",
|
|
107
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
108
|
+
),
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
111
|
+
leftIcon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
112
|
+
"span",
|
|
113
|
+
{
|
|
114
|
+
className: "flex size-5 shrink-0 items-center justify-center text-body-200",
|
|
115
|
+
"data-testid": "left-icon",
|
|
116
|
+
children: leftIcon
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
120
|
+
SelectPrimitive__namespace.Value,
|
|
121
|
+
{
|
|
122
|
+
placeholder,
|
|
123
|
+
className: "min-w-0 flex-1 truncate text-left text-body-100 data-placeholder:text-body-200 data-placeholder:opacity-40"
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon.ChevronDownIcon, {}) })
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
),
|
|
131
|
+
children
|
|
132
|
+
] }),
|
|
133
|
+
bottomText && /* @__PURE__ */ jsxRuntime.jsx(
|
|
134
|
+
"p",
|
|
135
|
+
{
|
|
136
|
+
id: helperTextId,
|
|
137
|
+
className: cn.cn(
|
|
138
|
+
"typography-caption-regular px-2 pt-1 pb-0.5",
|
|
139
|
+
error ? "text-error-500" : "text-body-200"
|
|
140
|
+
),
|
|
141
|
+
children: bottomText
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
) });
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
Select.displayName = "Select";
|
|
150
|
+
const SelectContent = React__namespace.forwardRef(({ className, children, position = "popper", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
151
|
+
SelectPrimitive__namespace.Content,
|
|
152
|
+
{
|
|
153
|
+
ref,
|
|
154
|
+
position,
|
|
155
|
+
sideOffset,
|
|
156
|
+
className: cn.cn(
|
|
157
|
+
"relative z-50 min-w-(--radix-select-trigger-width) overflow-hidden rounded-xl border border-neutral-200 bg-background-inverse-solid text-body-100 shadow-[0_4px_16px_rgba(0,0,0,0.10)]",
|
|
158
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
159
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
160
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
161
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
|
|
162
|
+
className
|
|
163
|
+
),
|
|
164
|
+
...props,
|
|
165
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Viewport, { className: "p-1", children })
|
|
166
|
+
}
|
|
167
|
+
) }));
|
|
168
|
+
SelectContent.displayName = "SelectContent";
|
|
169
|
+
const SelectItem = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
170
|
+
SelectPrimitive__namespace.Item,
|
|
171
|
+
{
|
|
172
|
+
ref,
|
|
173
|
+
className: cn.cn(
|
|
174
|
+
"typography-body-1-regular relative flex w-full cursor-pointer select-none items-center gap-2 rounded-lg py-2 pr-2 pl-3 text-body-100 outline-none",
|
|
175
|
+
"focus:bg-neutral-100 data-disabled:pointer-events-none data-disabled:opacity-50",
|
|
176
|
+
className
|
|
177
|
+
),
|
|
178
|
+
...props,
|
|
179
|
+
children: [
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children }),
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { className: "ml-auto flex size-4 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon.CheckIcon, { className: "size-4 text-body-100" }) })
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
));
|
|
185
|
+
SelectItem.displayName = "SelectItem";
|
|
186
|
+
const SelectGroup = SelectPrimitive__namespace.Group;
|
|
187
|
+
SelectGroup.displayName = "SelectGroup";
|
|
188
|
+
const SelectLabel = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
189
|
+
SelectPrimitive__namespace.Label,
|
|
190
|
+
{
|
|
191
|
+
ref,
|
|
192
|
+
className: cn.cn("typography-caption-semibold px-3 py-1.5 text-body-200", className),
|
|
193
|
+
...props
|
|
194
|
+
}
|
|
195
|
+
));
|
|
196
|
+
SelectLabel.displayName = "SelectLabel";
|
|
197
|
+
const SelectSeparator = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
198
|
+
SelectPrimitive__namespace.Separator,
|
|
199
|
+
{
|
|
200
|
+
ref,
|
|
201
|
+
className: cn.cn("-mx-1 my-1 h-px bg-neutral-200", className),
|
|
202
|
+
...props
|
|
203
|
+
}
|
|
204
|
+
));
|
|
205
|
+
SelectSeparator.displayName = "SelectSeparator";
|
|
206
|
+
exports.Select = Select;
|
|
207
|
+
exports.SelectContent = SelectContent;
|
|
208
|
+
exports.SelectGroup = SelectGroup;
|
|
209
|
+
exports.SelectItem = SelectItem;
|
|
210
|
+
exports.SelectLabel = SelectLabel;
|
|
211
|
+
exports.SelectSeparator = SelectSeparator;
|
|
212
|
+
//# sourceMappingURL=Select.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select.cjs","sources":["../../../../src/components/Select/Select.tsx"],"sourcesContent":["import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\n\n/** Select field height in pixels. */\nexport type SelectSize = \"48\" | \"40\" | \"32\";\n\ntype SelectContextValue = {\n size: SelectSize;\n error: boolean;\n disabled?: boolean;\n};\n\nconst SelectContext = React.createContext<SelectContextValue>({\n size: \"48\",\n error: false,\n});\n\nconst TRIGGER_HEIGHT: Record<SelectSize, string> = {\n \"48\": \"h-12\",\n \"40\": \"h-10\",\n \"32\": \"h-8\",\n};\n\nconst TRIGGER_PADDING_X: Record<SelectSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst TRIGGER_GAP: Record<SelectSize, string> = {\n \"48\": \"gap-3\",\n \"40\": \"gap-3\",\n \"32\": \"gap-2\",\n};\n\nconst TRIGGER_TYPOGRAPHY: Record<SelectSize, string> = {\n \"48\": \"typography-body-1-regular\",\n \"40\": \"typography-body-1-regular\",\n \"32\": \"typography-body-2-regular\",\n};\n\nexport interface SelectProps extends Omit<SelectPrimitive.SelectProps, \"dir\"> {\n /** Label text displayed above the trigger. Also used as the accessible name. */\n label?: string;\n /** Accessible name applied directly to the trigger button when no visible `label` is provided. */\n \"aria-label\"?: string;\n /** ID of an external element that labels the trigger button. */\n \"aria-labelledby\"?: string;\n /** Helper text displayed below the trigger. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Height of the select field in pixels. @default \"48\" */\n size?: SelectSize;\n /** Whether the field is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the trigger. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Placeholder shown when no value is selected. */\n placeholder?: string;\n /** Icon element displayed at the left side of the trigger. */\n leftIcon?: React.ReactNode;\n /** Whether the field stretches to fill its container width. @default false */\n fullWidth?: boolean;\n /** Wraps the `className` of the outermost container div. */\n className?: string;\n /** HTML `id` applied to the trigger button. Auto-generated if omitted. */\n id?: string;\n}\n\n/**\n * A select field with optional label, helper/error text, and an icon slot,\n * built on Radix UI Select for full accessibility and keyboard navigation.\n *\n * Pair with {@link SelectContent} and {@link SelectItem} to provide options.\n *\n * @example\n * ```tsx\n * <Select label=\"Country\" placeholder=\"Select a country\">\n * <SelectContent>\n * <SelectItem value=\"us\">United States</SelectItem>\n * <SelectItem value=\"uk\">United Kingdom</SelectItem>\n * </SelectContent>\n * </Select>\n * ```\n */\nexport const Select = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Trigger>,\n SelectProps\n>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n className,\n id,\n disabled,\n children,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const triggerId = id ?? generatedId;\n const helperTextId = `${triggerId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <SelectContext.Provider value={{ size, error, disabled }}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={triggerId}\n className=\"typography-caption-semibold px-1 pt-1 pb-2 text-body-100\"\n >\n {label}\n </label>\n )}\n\n <SelectPrimitive.Root disabled={disabled} {...props}>\n <SelectPrimitive.Trigger\n ref={ref}\n id={triggerId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n aria-describedby={bottomText ? helperTextId : undefined}\n aria-invalid={error || undefined}\n className={cn(\n \"flex w-full cursor-pointer items-center justify-between rounded-xl border bg-neutral-100 outline-none motion-safe:transition-colors\",\n TRIGGER_HEIGHT[size],\n TRIGGER_PADDING_X[size],\n TRIGGER_GAP[size],\n TRIGGER_TYPOGRAPHY[size],\n error ? \"border-error-500\" : \"border-transparent\",\n !disabled &&\n !error &&\n \"hover:border-neutral-400 data-[state=open]:border-neutral-400\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <div className=\"flex items-center gap-2\">\n {leftIcon && (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center text-body-200\"\n data-testid=\"left-icon\"\n >\n {leftIcon}\n </span>\n )}\n <SelectPrimitive.Value\n placeholder={placeholder}\n className=\"min-w-0 flex-1 truncate text-left text-body-100 data-placeholder:text-body-200 data-placeholder:opacity-40\"\n />\n </div>\n\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n {children}\n </SelectPrimitive.Root>\n\n {bottomText && (\n <p\n id={helperTextId}\n className={cn(\n \"typography-caption-regular px-2 pt-1 pb-0.5\",\n error ? \"text-error-500\" : \"text-body-200\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </SelectContext.Provider>\n );\n },\n);\n\nSelect.displayName = \"Select\";\n\nexport interface SelectContentProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> {}\n\n/**\n * The dropdown panel rendered inside a portal. Place {@link SelectItem} elements\n * (and optionally {@link SelectGroup} / {@link SelectLabel}) as children.\n */\nexport const SelectContent = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Content>,\n SelectContentProps\n>(({ className, children, position = \"popper\", sideOffset = 4, ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n sideOffset={sideOffset}\n className={cn(\n \"relative z-50 min-w-(--radix-select-trigger-width) overflow-hidden rounded-xl border border-neutral-200 bg-background-inverse-solid text-body-100 shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.Viewport className=\"p-1\">{children}</SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\n\nSelectContent.displayName = \"SelectContent\";\n\nexport interface SelectItemProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {}\n\n/**\n * An individual option inside {@link SelectContent}.\n */\nexport const SelectItem = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Item>,\n SelectItemProps\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"typography-body-1-regular relative flex w-full cursor-pointer select-none items-center gap-2 rounded-lg py-2 pr-2 pl-3 text-body-100 outline-none\",\n \"focus:bg-neutral-100 data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator className=\"ml-auto flex size-4 shrink-0 items-center justify-center\">\n <CheckIcon className=\"size-4 text-body-100\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n));\n\nSelectItem.displayName = \"SelectItem\";\n\n/** Props for {@link SelectGroup}. */\nexport type SelectGroupProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group>;\n\n/**\n * Groups related {@link SelectItem} elements under a {@link SelectLabel}.\n */\nexport const SelectGroup = SelectPrimitive.Group;\nSelectGroup.displayName = \"SelectGroup\";\n\nexport interface SelectLabelProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> {}\n\n/**\n * A non-interactive label shown above a {@link SelectGroup}.\n */\nexport const SelectLabel = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Label>,\n SelectLabelProps\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\"typography-caption-semibold px-3 py-1.5 text-body-200\", className)}\n {...props}\n />\n));\n\nSelectLabel.displayName = \"SelectLabel\";\n\nexport interface SelectSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> {}\n\n/** A horizontal rule that visually separates groups in {@link SelectContent}. */\nexport const SelectSeparator = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Separator>,\n SelectSeparatorProps\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-neutral-200\", className)}\n {...props}\n />\n));\n\nSelectSeparator.displayName = \"SelectSeparator\";\n"],"names":["React","jsx","jsxs","cn","SelectPrimitive","ChevronDownIcon","CheckIcon"],"mappings":"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"}
|