@fanvue/ui 3.15.0 → 3.16.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/AudioRecordButton/AudioRecordButton.cjs +54 -0
- package/dist/cjs/components/AudioRecordButton/AudioRecordButton.cjs.map +1 -0
- package/dist/cjs/components/AudioUpload/AudioUpload.cjs +5 -5
- package/dist/cjs/components/AudioUpload/AudioUpload.cjs.map +1 -1
- package/dist/cjs/components/ChatInput/ChatInput.cjs +6 -11
- package/dist/cjs/components/ChatInput/ChatInput.cjs.map +1 -1
- package/dist/cjs/components/ChatMessage/ChatMessage.cjs +228 -0
- package/dist/cjs/components/ChatMessage/ChatMessage.cjs.map +1 -0
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs +160 -71
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/cjs/components/Icons/DenseGridViewIcon.cjs +52 -0
- package/dist/cjs/components/Icons/DenseGridViewIcon.cjs.map +1 -0
- package/dist/cjs/components/MediaStatusIndicator/MediaStatusIndicator.cjs +66 -0
- package/dist/cjs/components/MediaStatusIndicator/MediaStatusIndicator.cjs.map +1 -0
- package/dist/cjs/components/Select/Select.cjs +61 -17
- package/dist/cjs/components/Select/Select.cjs.map +1 -1
- package/dist/cjs/components/SubscribeButton/SubscribeButton.cjs +53 -0
- package/dist/cjs/components/SubscribeButton/SubscribeButton.cjs.map +1 -0
- package/dist/cjs/index.cjs +10 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/AudioRecordButton/AudioRecordButton.mjs +37 -0
- package/dist/components/AudioRecordButton/AudioRecordButton.mjs.map +1 -0
- package/dist/components/AudioUpload/AudioUpload.mjs +5 -5
- package/dist/components/AudioUpload/AudioUpload.mjs.map +1 -1
- package/dist/components/ChatInput/ChatInput.mjs +6 -11
- package/dist/components/ChatInput/ChatInput.mjs.map +1 -1
- package/dist/components/ChatMessage/ChatMessage.mjs +211 -0
- package/dist/components/ChatMessage/ChatMessage.mjs.map +1 -0
- package/dist/components/DropdownMenu/DropdownMenu.mjs +161 -72
- package/dist/components/DropdownMenu/DropdownMenu.mjs.map +1 -1
- package/dist/components/Icons/DenseGridViewIcon.mjs +35 -0
- package/dist/components/Icons/DenseGridViewIcon.mjs.map +1 -0
- package/dist/components/MediaStatusIndicator/MediaStatusIndicator.mjs +49 -0
- package/dist/components/MediaStatusIndicator/MediaStatusIndicator.mjs.map +1 -0
- package/dist/components/Select/Select.mjs +61 -17
- package/dist/components/Select/Select.mjs.map +1 -1
- package/dist/components/SubscribeButton/SubscribeButton.mjs +36 -0
- package/dist/components/SubscribeButton/SubscribeButton.mjs.map +1 -0
- package/dist/index.d.ts +245 -4
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -1
- package/dist/styles/theme.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
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 BaseIcon = require("./BaseIcon.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 VARIANTS = {
|
|
25
|
+
16: {
|
|
26
|
+
outlined: [
|
|
27
|
+
{
|
|
28
|
+
d: "M5.18 2.333a.667.667 0 0 0-.667-.666H2.5a.667.667 0 0 0-.667.666v2c0 .369.299.667.667.667h2.013a.667.667 0 0 0 .667-.667zm0 4.334A.667.667 0 0 0 4.513 6H2.5a.667.667 0 0 0-.667.667V9c0 .368.299.667.667.667h2.013A.667.667 0 0 0 5.18 9zm0 4.666a.667.667 0 0 0-.667-.666H2.5a.667.667 0 0 0-.667.666v2c0 .368.299.667.667.667h2.013a.667.667 0 0 0 .667-.667zm4.667-9a.667.667 0 0 0-.667-.666H6.847a.667.667 0 0 0-.667.666v2c0 .369.299.667.667.667H9.18a.667.667 0 0 0 .667-.667zm4.32 0a.667.667 0 0 0-.667-.666h-1.987a.667.667 0 0 0-.666.666v2c0 .369.298.667.666.667H13.5a.667.667 0 0 0 .667-.667zm-4.32 4.334A.667.667 0 0 0 9.18 6H6.847a.667.667 0 0 0-.667.667V9c0 .368.299.667.667.667H9.18A.667.667 0 0 0 9.847 9zm0 4.666a.667.667 0 0 0-.667-.666H6.847a.667.667 0 0 0-.667.666v2c0 .368.299.667.667.667H9.18a.667.667 0 0 0 .667-.667zm4.32 0a.667.667 0 0 0-.667-.666h-1.987a.667.667 0 0 0-.666.666v2c0 .368.298.667.666.667H13.5a.667.667 0 0 0 .667-.667zm0-4.666A.667.667 0 0 0 13.5 6h-1.987a.667.667 0 0 0-.666.667V9c0 .368.298.667.666.667H13.5A.667.667 0 0 0 14.167 9z"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
24: {
|
|
33
|
+
outlined: [
|
|
34
|
+
{
|
|
35
|
+
d: "M7.77 3.5a1 1 0 0 0-1-1H3.75a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.02a1 1 0 0 0 1-1zm0 6.5a1 1 0 0 0-1-1H3.75a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h3.02a1 1 0 0 0 1-1zm0 7a1 1 0 0 0-1-1H3.75a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.02a1 1 0 0 0 1-1zm7-13.5a1 1 0 0 0-1-1h-3.5a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.5a1 1 0 0 0 1-1zm6.48 0a1 1 0 0 0-1-1h-2.98a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h2.98a1 1 0 0 0 1-1zM14.77 10a1 1 0 0 0-1-1h-3.5a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h3.5a1 1 0 0 0 1-1zm0 7a1 1 0 0 0-1-1h-3.5a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.5a1 1 0 0 0 1-1zm6.48 0a1 1 0 0 0-1-1h-2.98a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h2.98a1 1 0 0 0 1-1zm0-7a1 1 0 0 0-1-1h-2.98a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h2.98a1 1 0 0 0 1-1z"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
32: {
|
|
40
|
+
outlined: [
|
|
41
|
+
{
|
|
42
|
+
d: "M10.36 4.667c0-.737-.597-1.334-1.333-1.334H5c-.736 0-1.333.597-1.333 1.334v4C3.667 9.403 4.264 10 5 10h4.027c.736 0 1.333-.597 1.333-1.333zm0 8.666c0-.736-.597-1.333-1.333-1.333H5c-.736 0-1.333.597-1.333 1.333V18c0 .736.597 1.333 1.333 1.333h4.027c.736 0 1.333-.597 1.333-1.333zm0 9.334c0-.737-.597-1.334-1.333-1.334H5c-.736 0-1.333.597-1.333 1.334v4C3.667 27.403 4.264 28 5 28h4.027c.736 0 1.333-.597 1.333-1.333zm9.333-18c0-.737-.597-1.334-1.333-1.334h-4.667c-.736 0-1.333.597-1.333 1.334v4c0 .736.597 1.333 1.333 1.333h4.667c.736 0 1.333-.597 1.333-1.333zm8.64 0c0-.737-.597-1.334-1.333-1.334h-3.973c-.737 0-1.334.597-1.334 1.334v4c0 .736.597 1.333 1.334 1.333H27c.736 0 1.333-.597 1.333-1.333zm-8.64 8.666c0-.736-.597-1.333-1.333-1.333h-4.667c-.736 0-1.333.597-1.333 1.333V18c0 .736.597 1.333 1.333 1.333h4.667c.736 0 1.333-.597 1.333-1.333zm0 9.334c0-.737-.597-1.334-1.333-1.334h-4.667c-.736 0-1.333.597-1.333 1.334v4c0 .736.597 1.333 1.333 1.333h4.667c.736 0 1.333-.597 1.333-1.333zm8.64 0c0-.737-.597-1.334-1.333-1.334h-3.973c-.737 0-1.334.597-1.334 1.334v4c0 .736.597 1.333 1.334 1.333H27c.736 0 1.333-.597 1.333-1.333zm0-9.334c0-.736-.597-1.333-1.333-1.333h-3.973c-.737 0-1.334.597-1.334 1.333V18c0 .736.597 1.333 1.334 1.333H27c.736 0 1.333-.597 1.333-1.333z"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const DenseGridViewIcon = React__namespace.forwardRef(
|
|
48
|
+
(props, ref) => /* @__PURE__ */ jsxRuntime.jsx(BaseIcon.BaseIcon, { ref, variants: VARIANTS, ...props })
|
|
49
|
+
);
|
|
50
|
+
DenseGridViewIcon.displayName = "DenseGridViewIcon";
|
|
51
|
+
exports.DenseGridViewIcon = DenseGridViewIcon;
|
|
52
|
+
//# sourceMappingURL=DenseGridViewIcon.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DenseGridViewIcon.cjs","sources":["../../../../src/components/Icons/DenseGridViewIcon.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { BaseIcon } from \"./BaseIcon\";\nimport type { BaseIconProps, IconVariants } from \"./types\";\n\nconst VARIANTS: IconVariants = {\n 16: {\n outlined: [\n {\n d: \"M5.18 2.333a.667.667 0 0 0-.667-.666H2.5a.667.667 0 0 0-.667.666v2c0 .369.299.667.667.667h2.013a.667.667 0 0 0 .667-.667zm0 4.334A.667.667 0 0 0 4.513 6H2.5a.667.667 0 0 0-.667.667V9c0 .368.299.667.667.667h2.013A.667.667 0 0 0 5.18 9zm0 4.666a.667.667 0 0 0-.667-.666H2.5a.667.667 0 0 0-.667.666v2c0 .368.299.667.667.667h2.013a.667.667 0 0 0 .667-.667zm4.667-9a.667.667 0 0 0-.667-.666H6.847a.667.667 0 0 0-.667.666v2c0 .369.299.667.667.667H9.18a.667.667 0 0 0 .667-.667zm4.32 0a.667.667 0 0 0-.667-.666h-1.987a.667.667 0 0 0-.666.666v2c0 .369.298.667.666.667H13.5a.667.667 0 0 0 .667-.667zm-4.32 4.334A.667.667 0 0 0 9.18 6H6.847a.667.667 0 0 0-.667.667V9c0 .368.299.667.667.667H9.18A.667.667 0 0 0 9.847 9zm0 4.666a.667.667 0 0 0-.667-.666H6.847a.667.667 0 0 0-.667.666v2c0 .368.299.667.667.667H9.18a.667.667 0 0 0 .667-.667zm4.32 0a.667.667 0 0 0-.667-.666h-1.987a.667.667 0 0 0-.666.666v2c0 .368.298.667.666.667H13.5a.667.667 0 0 0 .667-.667zm0-4.666A.667.667 0 0 0 13.5 6h-1.987a.667.667 0 0 0-.666.667V9c0 .368.298.667.666.667H13.5A.667.667 0 0 0 14.167 9z\",\n },\n ],\n },\n 24: {\n outlined: [\n {\n d: \"M7.77 3.5a1 1 0 0 0-1-1H3.75a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.02a1 1 0 0 0 1-1zm0 6.5a1 1 0 0 0-1-1H3.75a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h3.02a1 1 0 0 0 1-1zm0 7a1 1 0 0 0-1-1H3.75a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.02a1 1 0 0 0 1-1zm7-13.5a1 1 0 0 0-1-1h-3.5a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.5a1 1 0 0 0 1-1zm6.48 0a1 1 0 0 0-1-1h-2.98a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h2.98a1 1 0 0 0 1-1zM14.77 10a1 1 0 0 0-1-1h-3.5a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h3.5a1 1 0 0 0 1-1zm0 7a1 1 0 0 0-1-1h-3.5a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3.5a1 1 0 0 0 1-1zm6.48 0a1 1 0 0 0-1-1h-2.98a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h2.98a1 1 0 0 0 1-1zm0-7a1 1 0 0 0-1-1h-2.98a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h2.98a1 1 0 0 0 1-1z\",\n },\n ],\n },\n 32: {\n outlined: [\n {\n d: \"M10.36 4.667c0-.737-.597-1.334-1.333-1.334H5c-.736 0-1.333.597-1.333 1.334v4C3.667 9.403 4.264 10 5 10h4.027c.736 0 1.333-.597 1.333-1.333zm0 8.666c0-.736-.597-1.333-1.333-1.333H5c-.736 0-1.333.597-1.333 1.333V18c0 .736.597 1.333 1.333 1.333h4.027c.736 0 1.333-.597 1.333-1.333zm0 9.334c0-.737-.597-1.334-1.333-1.334H5c-.736 0-1.333.597-1.333 1.334v4C3.667 27.403 4.264 28 5 28h4.027c.736 0 1.333-.597 1.333-1.333zm9.333-18c0-.737-.597-1.334-1.333-1.334h-4.667c-.736 0-1.333.597-1.333 1.334v4c0 .736.597 1.333 1.333 1.333h4.667c.736 0 1.333-.597 1.333-1.333zm8.64 0c0-.737-.597-1.334-1.333-1.334h-3.973c-.737 0-1.334.597-1.334 1.334v4c0 .736.597 1.333 1.334 1.333H27c.736 0 1.333-.597 1.333-1.333zm-8.64 8.666c0-.736-.597-1.333-1.333-1.333h-4.667c-.736 0-1.333.597-1.333 1.333V18c0 .736.597 1.333 1.333 1.333h4.667c.736 0 1.333-.597 1.333-1.333zm0 9.334c0-.737-.597-1.334-1.333-1.334h-4.667c-.736 0-1.333.597-1.333 1.334v4c0 .736.597 1.333 1.333 1.333h4.667c.736 0 1.333-.597 1.333-1.333zm8.64 0c0-.737-.597-1.334-1.333-1.334h-3.973c-.737 0-1.334.597-1.334 1.334v4c0 .736.597 1.333 1.334 1.333H27c.736 0 1.333-.597 1.333-1.333zm0-9.334c0-.736-.597-1.333-1.333-1.333h-3.973c-.737 0-1.334.597-1.334 1.333V18c0 .736.597 1.333 1.334 1.333H27c.736 0 1.333-.597 1.333-1.333z\",\n },\n ],\n },\n};\n\n/** Props for {@link DenseGridViewIcon}. See {@link BaseIconProps} for the shared shape. */\nexport type DenseGridViewIconProps = BaseIconProps;\n\n/**\n * Dense grid view icon (3×3 tiles) — the compact-grid counterpart of\n * {@link GridViewIcon}. Renders at sizes 16, 24, or 32 px.\n *\n * @example\n * ```tsx\n * <DenseGridViewIcon size={24} />\n * ```\n */\nexport const DenseGridViewIcon = React.forwardRef<SVGSVGElement, DenseGridViewIconProps>(\n (props, ref) => <BaseIcon ref={ref} variants={VARIANTS} {...props} />,\n);\n\nDenseGridViewIcon.displayName = \"DenseGridViewIcon\";\n"],"names":["React","jsx","BaseIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,WAAyB;AAAA,EAC7B,IAAI;AAAA,IACF,UAAU;AAAA,MACR;AAAA,QACE,GAAG;AAAA,MAAA;AAAA,IACL;AAAA,EACF;AAAA,EAEF,IAAI;AAAA,IACF,UAAU;AAAA,MACR;AAAA,QACE,GAAG;AAAA,MAAA;AAAA,IACL;AAAA,EACF;AAAA,EAEF,IAAI;AAAA,IACF,UAAU;AAAA,MACR;AAAA,QACE,GAAG;AAAA,MAAA;AAAA,IACL;AAAA,EACF;AAEJ;AAcO,MAAM,oBAAoBA,iBAAM;AAAA,EACrC,CAAC,OAAO,QAAQC,2BAAAA,IAACC,SAAAA,YAAS,KAAU,UAAU,UAAW,GAAG,MAAA,CAAO;AACrE;AAEA,kBAAkB,cAAc;;"}
|
|
@@ -0,0 +1,66 @@
|
|
|
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 CloseIcon = require("../Icons/CloseIcon.cjs");
|
|
8
|
+
const EyeOffIcon = require("../Icons/EyeOffIcon.cjs");
|
|
9
|
+
const FlagIcon = require("../Icons/FlagIcon.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 STATUS_CONFIG = {
|
|
28
|
+
default: {
|
|
29
|
+
container: "bg-warning-surface text-warning-content",
|
|
30
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(FlagIcon.FlagIcon, { size: 16, filled: true }),
|
|
31
|
+
label: "Flagged"
|
|
32
|
+
},
|
|
33
|
+
removed: {
|
|
34
|
+
container: "border border-error-secondary bg-error-negative-content text-content-always-white",
|
|
35
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon.CloseIcon, { size: 16 }),
|
|
36
|
+
label: "Removed"
|
|
37
|
+
},
|
|
38
|
+
sensitive: {
|
|
39
|
+
container: "bg-buttons-overlay-default text-content-always-white",
|
|
40
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(EyeOffIcon.EyeOffIcon, { size: 16, filled: true }),
|
|
41
|
+
label: "Sensitive content"
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const MediaStatusIndicator = React__namespace.forwardRef(
|
|
45
|
+
({ status = "default", label, className, ...props }, ref) => {
|
|
46
|
+
const config = STATUS_CONFIG[status];
|
|
47
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
48
|
+
"span",
|
|
49
|
+
{
|
|
50
|
+
ref,
|
|
51
|
+
role: "img",
|
|
52
|
+
"aria-label": props["aria-label"] ?? label ?? config.label,
|
|
53
|
+
className: cn.cn(
|
|
54
|
+
"inline-flex items-center justify-center rounded-full p-2 [&>svg]:size-4",
|
|
55
|
+
config.container,
|
|
56
|
+
className
|
|
57
|
+
),
|
|
58
|
+
...props,
|
|
59
|
+
children: config.icon
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
MediaStatusIndicator.displayName = "MediaStatusIndicator";
|
|
65
|
+
exports.MediaStatusIndicator = MediaStatusIndicator;
|
|
66
|
+
//# sourceMappingURL=MediaStatusIndicator.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaStatusIndicator.cjs","sources":["../../../../src/components/MediaStatusIndicator/MediaStatusIndicator.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { EyeOffIcon } from \"../Icons/EyeOffIcon\";\nimport { FlagIcon } from \"../Icons/FlagIcon\";\n\n/**\n * State represented by the indicator.\n * - `\"default\"`: media flagged / pending review (amber).\n * - `\"removed\"`: media removed for a policy violation (red).\n * - `\"sensitive\"`: sensitive content hidden behind an overlay (dark).\n */\nexport type MediaStatusIndicatorStatus = \"default\" | \"removed\" | \"sensitive\";\n\nexport interface MediaStatusIndicatorProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Which media state to represent. @default \"default\" */\n status?: MediaStatusIndicatorStatus;\n /**\n * Accessible label announced by assistive tech. Defaults to a per-status\n * description; pass your own for localisation or extra context.\n */\n label?: string;\n}\n\ntype StatusConfig = { container: string; icon: React.ReactNode; label: string };\n\nconst STATUS_CONFIG: Record<MediaStatusIndicatorStatus, StatusConfig> = {\n default: {\n container: \"bg-warning-surface text-warning-content\",\n icon: <FlagIcon size={16} filled />,\n label: \"Flagged\",\n },\n removed: {\n container: \"border border-error-secondary bg-error-negative-content text-content-always-white\",\n icon: <CloseIcon size={16} />,\n label: \"Removed\",\n },\n sensitive: {\n container: \"bg-buttons-overlay-default text-content-always-white\",\n icon: <EyeOffIcon size={16} filled />,\n label: \"Sensitive content\",\n },\n};\n\n/**\n * A compact circular indicator that surfaces the moderation state of a piece of\n * media — flagged, removed, or sensitive. Typically overlaid on a thumbnail or\n * attachment.\n *\n * Renders as `role=\"img\"` with a descriptive `aria-label`; the inner glyph is\n * decorative.\n *\n * @example\n * ```tsx\n * <MediaStatusIndicator status=\"sensitive\" />\n * <MediaStatusIndicator status=\"removed\" label=\"Removed for violating guidelines\" />\n * ```\n */\nexport const MediaStatusIndicator = React.forwardRef<HTMLSpanElement, MediaStatusIndicatorProps>(\n ({ status = \"default\", label, className, ...props }, ref) => {\n const config = STATUS_CONFIG[status];\n return (\n <span\n ref={ref}\n role=\"img\"\n aria-label={props[\"aria-label\"] ?? label ?? config.label}\n className={cn(\n \"inline-flex items-center justify-center rounded-full p-2 [&>svg]:size-4\",\n config.container,\n className,\n )}\n {...props}\n >\n {config.icon}\n </span>\n );\n },\n);\n\nMediaStatusIndicator.displayName = \"MediaStatusIndicator\";\n"],"names":["jsx","FlagIcon","CloseIcon","EyeOffIcon","React","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,gBAAkE;AAAA,EACtE,SAAS;AAAA,IACP,WAAW;AAAA,IACX,MAAMA,2BAAAA,IAACC,mBAAA,EAAS,MAAM,IAAI,QAAM,MAAC;AAAA,IACjC,OAAO;AAAA,EAAA;AAAA,EAET,SAAS;AAAA,IACP,WAAW;AAAA,IACX,MAAMD,2BAAAA,IAACE,UAAAA,WAAA,EAAU,MAAM,GAAA,CAAI;AAAA,IAC3B,OAAO;AAAA,EAAA;AAAA,EAET,WAAW;AAAA,IACT,WAAW;AAAA,IACX,MAAMF,2BAAAA,IAACG,uBAAA,EAAW,MAAM,IAAI,QAAM,MAAC;AAAA,IACnC,OAAO;AAAA,EAAA;AAEX;AAgBO,MAAM,uBAAuBC,iBAAM;AAAA,EACxC,CAAC,EAAE,SAAS,WAAW,OAAO,WAAW,GAAG,MAAA,GAAS,QAAQ;AAC3D,UAAM,SAAS,cAAc,MAAM;AACnC,WACEJ,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,cAAY,MAAM,YAAY,KAAK,SAAS,OAAO;AAAA,QACnD,WAAWK,GAAAA;AAAAA,UACT;AAAA,UACA,OAAO;AAAA,UACP;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA,OAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAGd;AACF;AAEA,qBAAqB,cAAc;;"}
|
|
@@ -98,7 +98,7 @@ const Select = React__namespace.forwardRef(
|
|
|
98
98
|
"aria-describedby": bottomText ? helperTextId : void 0,
|
|
99
99
|
"aria-invalid": error || void 0,
|
|
100
100
|
className: cn.cn(
|
|
101
|
-
"flex w-full cursor-pointer items-center justify-between rounded-sm border bg-inputs-inputs-primary outline-none
|
|
101
|
+
"flex w-full cursor-pointer items-center justify-between rounded-sm border bg-inputs-inputs-primary outline-none focus-visible:shadow-focus-ring motion-safe:transition-colors",
|
|
102
102
|
TRIGGER_HEIGHT[size],
|
|
103
103
|
TRIGGER_PADDING_X[size],
|
|
104
104
|
TRIGGER_GAP[size],
|
|
@@ -173,22 +173,66 @@ const SelectContent = React__namespace.forwardRef(
|
|
|
173
173
|
) })
|
|
174
174
|
);
|
|
175
175
|
SelectContent.displayName = "SelectContent";
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
)
|
|
176
|
+
const ITEM_SIZE_CLASSES = {
|
|
177
|
+
"40": "min-h-10 py-2 typography-body-default-16px-regular",
|
|
178
|
+
"32": "min-h-8 py-[7px] typography-body-small-14px-regular"
|
|
179
|
+
};
|
|
180
|
+
const ITEM_DESCRIPTION_TYPOGRAPHY = {
|
|
181
|
+
"40": "typography-body-small-14px-regular",
|
|
182
|
+
"32": "typography-description-12px-regular"
|
|
183
|
+
};
|
|
184
|
+
function isRenderableNode(node) {
|
|
185
|
+
return node !== null && node !== void 0 && typeof node !== "boolean";
|
|
186
|
+
}
|
|
187
|
+
const SelectItem = React__namespace.forwardRef(({ className, children, size, leadingIcon, avatar, description, ...props }, ref) => {
|
|
188
|
+
const { size: triggerSize } = React__namespace.useContext(SelectContext);
|
|
189
|
+
const itemSize = size ?? (triggerSize === "32" ? "32" : "40");
|
|
190
|
+
const hasDescription = isRenderableNode(description);
|
|
191
|
+
const hasAvatar = isRenderableNode(avatar);
|
|
192
|
+
const hasLeadingIcon = isRenderableNode(leadingIcon);
|
|
193
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
194
|
+
SelectPrimitive__namespace.Item,
|
|
195
|
+
{
|
|
196
|
+
ref,
|
|
197
|
+
className: cn.cn(
|
|
198
|
+
"group relative flex w-full cursor-pointer select-none gap-2 rounded-xs px-3 text-content-primary outline-none",
|
|
199
|
+
hasDescription ? "items-start" : "items-center",
|
|
200
|
+
ITEM_SIZE_CLASSES[itemSize],
|
|
201
|
+
hasAvatar && !hasDescription && itemSize === "32" && "py-1",
|
|
202
|
+
"focus:bg-neutral-alphas-50 data-highlighted:bg-neutral-alphas-50",
|
|
203
|
+
"data-disabled:pointer-events-none data-disabled:text-content-disabled",
|
|
204
|
+
className
|
|
205
|
+
),
|
|
206
|
+
...props,
|
|
207
|
+
children: [
|
|
208
|
+
hasAvatar ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: avatar }) : hasLeadingIcon && (hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center pt-0.5 [&>svg]:size-4", children: leadingIcon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center [&>svg]:size-4", children: leadingIcon })),
|
|
209
|
+
hasDescription ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
210
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children }) }),
|
|
211
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
212
|
+
"span",
|
|
213
|
+
{
|
|
214
|
+
className: cn.cn(
|
|
215
|
+
"truncate text-content-secondary group-data-[disabled]:text-content-disabled",
|
|
216
|
+
ITEM_DESCRIPTION_TYPOGRAPHY[itemSize]
|
|
217
|
+
),
|
|
218
|
+
children: description
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children }) }),
|
|
222
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
223
|
+
SelectPrimitive__namespace.ItemIndicator,
|
|
224
|
+
{
|
|
225
|
+
className: cn.cn(
|
|
226
|
+
"ml-auto flex size-4 shrink-0 items-center justify-center",
|
|
227
|
+
hasDescription && "self-start"
|
|
228
|
+
),
|
|
229
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon.CheckIcon, { className: "size-4 text-content-primary group-data-[disabled]:text-content-disabled" })
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
});
|
|
192
236
|
SelectItem.displayName = "SelectItem";
|
|
193
237
|
const SelectGroup = SelectPrimitive__namespace.Group;
|
|
194
238
|
SelectGroup.displayName = "SelectGroup";
|
|
@@ -1 +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 { FLOATING_CONTENT_COLLISION_PADDING } from \"@/utils/floatingContentCollisionPadding\";\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-default-16px-regular\",\n \"40\": \"typography-body-default-16px-regular\",\n \"32\": \"typography-body-small-14px-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-description-12px-semibold pb-2 text-content-primary\"\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-sm border bg-inputs-inputs-primary outline-none motion-safe:transition-colors focus-visible:shadow-focus-ring\",\n TRIGGER_HEIGHT[size],\n TRIGGER_PADDING_X[size],\n TRIGGER_GAP[size],\n TRIGGER_TYPOGRAPHY[size],\n error ? \"border-error-content\" : \"border-border-primary\",\n !disabled &&\n !error &&\n \"hover:border-neutral-alphas-400 data-[state=open]:border-neutral-alphas-400\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n {leftIcon && (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center text-content-secondary\"\n data-testid=\"left-icon\"\n >\n {leftIcon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate text-left text-content-primary [&>[data-placeholder]]:text-content-tertiary\">\n <SelectPrimitive.Value placeholder={placeholder} />\n </span>\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-description-12px-regular px-2 pt-1 pb-0.5\",\n error ? \"text-error-content\" : \"text-content-secondary\",\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>(\n (\n {\n className,\n children,\n position = \"popper\",\n sideOffset = 4,\n collisionPadding = FLOATING_CONTENT_COLLISION_PADDING,\n style,\n ...props\n },\n ref,\n ) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"relative w-max min-w-(--radix-select-trigger-width) max-w-(--radix-select-content-available-width) overflow-hidden rounded-sm border border-neutral-alphas-200 bg-background-primary text-content-primary 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=\"max-h-[var(--radix-select-content-available-height)] overflow-y-auto p-1\">\n {children}\n </SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n ),\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-default-16px-regular relative flex w-full cursor-pointer select-none items-center gap-2 rounded-xs py-2 pr-2 pl-3 text-content-primary outline-none\",\n \"focus:bg-neutral-alphas-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-content-primary\" />\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(\n \"typography-description-12px-semibold px-3 py-1.5 text-content-secondary\",\n className,\n )}\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-alphas-200\", className)}\n {...props}\n />\n));\n\nSelectSeparator.displayName = \"SelectSeparator\";\n"],"names":["React","jsx","jsxs","cn","SelectPrimitive","ChevronDownIcon","FLOATING_CONTENT_COLLISION_PADDING","CheckIcon"],"mappings":"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"}
|
|
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 { FLOATING_CONTENT_COLLISION_PADDING } from \"@/utils/floatingContentCollisionPadding\";\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-default-16px-regular\",\n \"40\": \"typography-body-default-16px-regular\",\n \"32\": \"typography-body-small-14px-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-description-12px-semibold pb-2 text-content-primary\"\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-sm border bg-inputs-inputs-primary outline-none focus-visible:shadow-focus-ring 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-content\" : \"border-border-primary\",\n !disabled &&\n !error &&\n \"hover:border-neutral-alphas-400 data-[state=open]:border-neutral-alphas-400\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n {leftIcon && (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center text-content-secondary\"\n data-testid=\"left-icon\"\n >\n {leftIcon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate text-left text-content-primary [&>[data-placeholder]]:text-content-tertiary\">\n <SelectPrimitive.Value placeholder={placeholder} />\n </span>\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-description-12px-regular px-2 pt-1 pb-0.5\",\n error ? \"text-error-content\" : \"text-content-secondary\",\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>(\n (\n {\n className,\n children,\n position = \"popper\",\n sideOffset = 4,\n collisionPadding = FLOATING_CONTENT_COLLISION_PADDING,\n style,\n ...props\n },\n ref,\n ) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"relative w-max min-w-(--radix-select-trigger-width) max-w-(--radix-select-content-available-width) overflow-hidden rounded-sm border border-neutral-alphas-200 bg-background-primary text-content-primary 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=\"max-h-[var(--radix-select-content-available-height)] overflow-y-auto p-1\">\n {children}\n </SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n ),\n);\n\nSelectContent.displayName = \"SelectContent\";\n\n/** Dropdown row height in pixels, matching the V2 Menu Item spec. */\nexport type SelectItemSize = \"40\" | \"32\";\n\nconst ITEM_SIZE_CLASSES: Record<SelectItemSize, string> = {\n \"40\": \"min-h-10 py-2 typography-body-default-16px-regular\",\n \"32\": \"min-h-8 py-[7px] typography-body-small-14px-regular\",\n};\n\nconst ITEM_DESCRIPTION_TYPOGRAPHY: Record<SelectItemSize, string> = {\n \"40\": \"typography-body-small-14px-regular\",\n \"32\": \"typography-description-12px-regular\",\n};\n\nexport interface SelectItemProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {\n /** Row height. Defaults to the parent {@link Select} size (`48`/`40` → `40`, `32` → `32`). */\n size?: SelectItemSize;\n /** Icon (or other node) rendered before the label. Ignored when {@link SelectItemProps.avatar} is set. */\n leadingIcon?: React.ReactNode;\n /**\n * Leading avatar rendered in place of {@link SelectItemProps.leadingIcon}, for rows\n * representing a person or account. Pass an `Avatar` sized to `24`. Takes precedence over `leadingIcon`.\n */\n avatar?: React.ReactNode;\n /** Optional secondary text rendered on a second line below the label. */\n description?: React.ReactNode;\n}\n\n/**\n * Whether a `ReactNode` will actually render. Excludes `null`/`undefined` and\n * booleans so short-circuit props (e.g. `description={cond && \"…\"}`) don't flip\n * the item into a two-line/avatar layout when they resolve to `false`.\n */\nfunction isRenderableNode(node: React.ReactNode): boolean {\n return node !== null && node !== undefined && typeof node !== \"boolean\";\n}\n\n/**\n * An individual option inside {@link SelectContent}, following the V2 Menu Item spec.\n *\n * Supports a leading icon or avatar, an optional two-line layout via `description`,\n * and the standard hover / selected / disabled states. The selected row is marked\n * with a trailing check indicator.\n *\n * @example\n * ```tsx\n * <SelectItem value=\"jane\" avatar={<Avatar size={24} fallback=\"JD\" />} description=\"Product designer\">\n * Jane Doe\n * </SelectItem>\n * ```\n */\nexport const SelectItem = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Item>,\n SelectItemProps\n>(({ className, children, size, leadingIcon, avatar, description, ...props }, ref) => {\n const { size: triggerSize } = React.useContext(SelectContext);\n const itemSize: SelectItemSize = size ?? (triggerSize === \"32\" ? \"32\" : \"40\");\n const hasDescription = isRenderableNode(description);\n const hasAvatar = isRenderableNode(avatar);\n const hasLeadingIcon = isRenderableNode(leadingIcon);\n\n return (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"group relative flex w-full cursor-pointer select-none gap-2 rounded-xs px-3 text-content-primary outline-none\",\n hasDescription ? \"items-start\" : \"items-center\",\n ITEM_SIZE_CLASSES[itemSize],\n hasAvatar && !hasDescription && itemSize === \"32\" && \"py-1\",\n \"focus:bg-neutral-alphas-50 data-highlighted:bg-neutral-alphas-50\",\n \"data-disabled:pointer-events-none data-disabled:text-content-disabled\",\n className,\n )}\n {...props}\n >\n {hasAvatar ? (\n <span className=\"shrink-0\">{avatar}</span>\n ) : (\n hasLeadingIcon &&\n (hasDescription ? (\n <span className=\"flex shrink-0 items-center pt-0.5 [&>svg]:size-4\">{leadingIcon}</span>\n ) : (\n <span className=\"flex shrink-0 items-center [&>svg]:size-4\">{leadingIcon}</span>\n ))\n )}\n\n {hasDescription ? (\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <span className=\"truncate\">\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </span>\n <span\n className={cn(\n \"truncate text-content-secondary group-data-[disabled]:text-content-disabled\",\n ITEM_DESCRIPTION_TYPOGRAPHY[itemSize],\n )}\n >\n {description}\n </span>\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 truncate\">\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </span>\n )}\n\n <SelectPrimitive.ItemIndicator\n className={cn(\n \"ml-auto flex size-4 shrink-0 items-center justify-center\",\n hasDescription && \"self-start\",\n )}\n >\n <CheckIcon className=\"size-4 text-content-primary group-data-[disabled]:text-content-disabled\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n );\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(\n \"typography-description-12px-semibold px-3 py-1.5 text-content-secondary\",\n className,\n )}\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-alphas-200\", className)}\n {...props}\n />\n));\n\nSelectSeparator.displayName = \"SelectSeparator\";\n"],"names":["React","jsx","jsxs","cn","SelectPrimitive","ChevronDownIcon","FLOATING_CONTENT_COLLISION_PADDING","CheckIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
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 Button = require("../Button/Button.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 OLD_PRICE_TYPOGRAPHY = {
|
|
26
|
+
"48": "typography-body-small-14px-regular",
|
|
27
|
+
"40": "typography-body-small-14px-regular",
|
|
28
|
+
"32": "typography-description-12px-regular"
|
|
29
|
+
};
|
|
30
|
+
function warnMissingAccessibleName(hasTextLabel, ariaLabel) {
|
|
31
|
+
if (process.env.NODE_ENV !== "production" && !hasTextLabel && !ariaLabel) {
|
|
32
|
+
console.warn(
|
|
33
|
+
"SubscribeButton: no accessible name could be derived from a string `children`. Pass an `aria-label` so the action and price are announced."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const SubscribeButton = React__namespace.forwardRef(
|
|
38
|
+
({ variant = "primary", size = "48", price, discount, children = "Join now", ...props }, ref) => {
|
|
39
|
+
const labelText = typeof children === "string" ? children : void 0;
|
|
40
|
+
warnMissingAccessibleName(Boolean(labelText?.trim()), props["aria-label"]);
|
|
41
|
+
const accessibleName = props["aria-label"] ?? [labelText, price, discount ? `was ${discount}` : null].filter(Boolean).join(", ");
|
|
42
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Button.Button, { ref, variant, size, ...props, "aria-label": accessibleName, children: [
|
|
43
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children }),
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-2", "aria-hidden": "true", children: [
|
|
45
|
+
discount && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn.cn(OLD_PRICE_TYPOGRAPHY[size], "line-through"), children: discount }),
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: price })
|
|
47
|
+
] })
|
|
48
|
+
] });
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
SubscribeButton.displayName = "SubscribeButton";
|
|
52
|
+
exports.SubscribeButton = SubscribeButton;
|
|
53
|
+
//# sourceMappingURL=SubscribeButton.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscribeButton.cjs","sources":["../../../../src/components/SubscribeButton/SubscribeButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button, type ButtonProps } from \"../Button/Button\";\n\n/** Visual style variant of the subscribe button. Mirrors the V2 Subscribe Button \"Type\" set (`brand` is Figma's \"Upsell\"). */\nexport type SubscribeButtonVariant = \"primary\" | \"secondary\" | \"tertiary\" | \"outline\" | \"brand\";\n\n/** Height of the subscribe button in pixels. */\nexport type SubscribeButtonSize = \"48\" | \"40\" | \"32\";\n\nexport interface SubscribeButtonProps\n extends Omit<\n ButtonProps,\n \"variant\" | \"size\" | \"price\" | \"discount\" | \"leftIcon\" | \"rightIcon\" | \"asChild\"\n > {\n /** Visual style variant. `brand` is the Figma \"Upsell\" (green) type. @default \"primary\" */\n variant?: SubscribeButtonVariant;\n /** Height of the button in pixels. @default \"48\" */\n size?: SubscribeButtonSize;\n /** Current price shown on the trailing side (e.g. `\"$9.99/mo\"`). */\n price: string;\n /** Previous price rendered struck-through before {@link SubscribeButtonProps.price}. */\n discount?: string;\n /** Leading action label. @default \"Join now\" */\n children?: React.ReactNode;\n}\n\nconst OLD_PRICE_TYPOGRAPHY: Record<SubscribeButtonSize, string> = {\n \"48\": \"typography-body-small-14px-regular\",\n \"40\": \"typography-body-small-14px-regular\",\n \"32\": \"typography-description-12px-regular\",\n};\n\nfunction warnMissingAccessibleName(hasTextLabel: boolean, ariaLabel?: string) {\n if (process.env.NODE_ENV !== \"production\" && !hasTextLabel && !ariaLabel) {\n console.warn(\n \"SubscribeButton: no accessible name could be derived from a string `children`. Pass an `aria-label` so the action and price are announced.\",\n );\n }\n}\n\n/**\n * A subscription / purchase button pairing an action label with the current\n * price and an optional struck-through previous price. Built on {@link Button},\n * so it inherits the same variants, sizes, `negative` dark-surface treatment,\n * `fullWidth`, loading, and disabled behaviour.\n *\n * The accessible name defaults to the label plus pricing (e.g. `\"Join now, $9.99,\n * was $19.99\"`); pass `aria-label` to override.\n *\n * @example\n * ```tsx\n * <SubscribeButton price=\"$9.99/mo\" discount=\"$19.99\" variant=\"brand\" fullWidth>\n * Join now\n * </SubscribeButton>\n * ```\n */\nexport const SubscribeButton = React.forwardRef<HTMLButtonElement, SubscribeButtonProps>(\n ({ variant = \"primary\", size = \"48\", price, discount, children = \"Join now\", ...props }, ref) => {\n const labelText = typeof children === \"string\" ? children : undefined;\n warnMissingAccessibleName(Boolean(labelText?.trim()), props[\"aria-label\"]);\n\n const accessibleName =\n props[\"aria-label\"] ??\n [labelText, price, discount ? `was ${discount}` : null].filter(Boolean).join(\", \");\n\n return (\n <Button ref={ref} variant={variant} size={size} {...props} aria-label={accessibleName}>\n <span className=\"min-w-0 flex-1 truncate text-left\">{children}</span>\n <span className=\"flex shrink-0 items-center gap-2\" aria-hidden=\"true\">\n {discount && (\n <span className={cn(OLD_PRICE_TYPOGRAPHY[size], \"line-through\")}>{discount}</span>\n )}\n <span>{price}</span>\n </span>\n </Button>\n );\n },\n);\n\nSubscribeButton.displayName = \"SubscribeButton\";\n"],"names":["React","jsxs","Button","jsx","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,uBAA4D;AAAA,EAChE,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AACR;AAEA,SAAS,0BAA0B,cAAuB,WAAoB;AAC5E,MAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,gBAAgB,CAAC,WAAW;AACxE,YAAQ;AAAA,MACN;AAAA,IAAA;AAAA,EAEJ;AACF;AAkBO,MAAM,kBAAkBA,iBAAM;AAAA,EACnC,CAAC,EAAE,UAAU,WAAW,OAAO,MAAM,OAAO,UAAU,WAAW,YAAY,GAAG,MAAA,GAAS,QAAQ;AAC/F,UAAM,YAAY,OAAO,aAAa,WAAW,WAAW;AAC5D,8BAA0B,QAAQ,WAAW,KAAA,CAAM,GAAG,MAAM,YAAY,CAAC;AAEzE,UAAM,iBACJ,MAAM,YAAY,KAClB,CAAC,WAAW,OAAO,WAAW,OAAO,QAAQ,KAAK,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAEnF,WACEC,gCAACC,OAAAA,UAAO,KAAU,SAAkB,MAAa,GAAG,OAAO,cAAY,gBACrE,UAAA;AAAA,MAAAC,2BAAAA,IAAC,QAAA,EAAK,WAAU,qCAAqC,SAAA,CAAS;AAAA,MAC9DF,2BAAAA,KAAC,QAAA,EAAK,WAAU,oCAAmC,eAAY,QAC5D,UAAA;AAAA,QAAA,YACCE,2BAAAA,IAAC,UAAK,WAAWC,GAAAA,GAAG,qBAAqB,IAAI,GAAG,cAAc,GAAI,UAAA,SAAA,CAAS;AAAA,QAE7ED,2BAAAA,IAAC,UAAM,UAAA,MAAA,CAAM;AAAA,MAAA,EAAA,CACf;AAAA,IAAA,GACF;AAAA,EAEJ;AACF;AAEA,gBAAgB,cAAc;;"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -8,6 +8,7 @@ const AccordionItem = require("./components/Accordion/AccordionItem.cjs");
|
|
|
8
8
|
const AccordionTrigger = require("./components/Accordion/AccordionTrigger.cjs");
|
|
9
9
|
const Alert = require("./components/Alert/Alert.cjs");
|
|
10
10
|
const AudioPlayer = require("./components/AudioPlayer/AudioPlayer.cjs");
|
|
11
|
+
const AudioRecordButton = require("./components/AudioRecordButton/AudioRecordButton.cjs");
|
|
11
12
|
const AudioUpload = require("./components/AudioUpload/AudioUpload.cjs");
|
|
12
13
|
const useAudioRecorder = require("./components/AudioUpload/useAudioRecorder.cjs");
|
|
13
14
|
const Autocomplete = require("./components/Autocomplete/Autocomplete.cjs");
|
|
@@ -20,6 +21,7 @@ const Breadcrumb = require("./components/Breadcrumb/Breadcrumb.cjs");
|
|
|
20
21
|
const Button = require("./components/Button/Button.cjs");
|
|
21
22
|
const Card = require("./components/Card/Card.cjs");
|
|
22
23
|
const ChatInput = require("./components/ChatInput/ChatInput.cjs");
|
|
24
|
+
const ChatMessage = require("./components/ChatMessage/ChatMessage.cjs");
|
|
23
25
|
const Checkbox = require("./components/Checkbox/Checkbox.cjs");
|
|
24
26
|
const Chip = require("./components/Chip/Chip.cjs");
|
|
25
27
|
const Count = require("./components/Count/Count.cjs");
|
|
@@ -79,6 +81,7 @@ const CopyIcon = require("./components/Icons/CopyIcon.cjs");
|
|
|
79
81
|
const CrossCircleIcon = require("./components/Icons/CrossCircleIcon.cjs");
|
|
80
82
|
const CrossIcon = require("./components/Icons/CrossIcon.cjs");
|
|
81
83
|
const CrownIcon = require("./components/Icons/CrownIcon.cjs");
|
|
84
|
+
const DenseGridViewIcon = require("./components/Icons/DenseGridViewIcon.cjs");
|
|
82
85
|
const DiamondIcon = require("./components/Icons/DiamondIcon.cjs");
|
|
83
86
|
const DiscordIcon = require("./components/Icons/DiscordIcon.cjs");
|
|
84
87
|
const DiscountIcon = require("./components/Icons/DiscountIcon.cjs");
|
|
@@ -206,6 +209,7 @@ const InlineEdit = require("./components/InlineEdit/InlineEdit.cjs");
|
|
|
206
209
|
const Link = require("./components/Link/Link.cjs");
|
|
207
210
|
const Loader = require("./components/Loader/Loader.cjs");
|
|
208
211
|
const Logo = require("./components/Logo/Logo.cjs");
|
|
212
|
+
const MediaStatusIndicator = require("./components/MediaStatusIndicator/MediaStatusIndicator.cjs");
|
|
209
213
|
const MobileStepper = require("./components/MobileStepper/MobileStepper.cjs");
|
|
210
214
|
const OnlineBlinkingIcon = require("./components/OnlineBlinkingIcon/OnlineBlinkingIcon.cjs");
|
|
211
215
|
const PageSelector = require("./components/PageSelector/PageSelector.cjs");
|
|
@@ -229,6 +233,7 @@ const Slider = require("./components/Slider/Slider.cjs");
|
|
|
229
233
|
const Snackbar = require("./components/Snackbar/Snackbar.cjs");
|
|
230
234
|
const Stepper = require("./components/Stepper/Stepper.cjs");
|
|
231
235
|
const StepperStep = require("./components/Stepper/StepperStep.cjs");
|
|
236
|
+
const SubscribeButton = require("./components/SubscribeButton/SubscribeButton.cjs");
|
|
232
237
|
const Switch = require("./components/Switch/Switch.cjs");
|
|
233
238
|
const SwitchField = require("./components/SwitchField/SwitchField.cjs");
|
|
234
239
|
const SwitchToggle = require("./components/SwitchToggle/SwitchToggle.cjs");
|
|
@@ -262,6 +267,7 @@ exports.AccordionItem = AccordionItem.AccordionItem;
|
|
|
262
267
|
exports.AccordionTrigger = AccordionTrigger.AccordionTrigger;
|
|
263
268
|
exports.Alert = Alert.Alert;
|
|
264
269
|
exports.AudioPlayer = AudioPlayer.AudioPlayer;
|
|
270
|
+
exports.AudioRecordButton = AudioRecordButton.AudioRecordButton;
|
|
265
271
|
exports.AudioUpload = AudioUpload.AudioUpload;
|
|
266
272
|
exports.useAudioRecorder = useAudioRecorder.useAudioRecorder;
|
|
267
273
|
exports.Autocomplete = Autocomplete.Autocomplete;
|
|
@@ -287,6 +293,7 @@ exports.CardFooter = Card.CardFooter;
|
|
|
287
293
|
exports.CardHeader = Card.CardHeader;
|
|
288
294
|
exports.CardTitle = Card.CardTitle;
|
|
289
295
|
exports.ChatInput = ChatInput.ChatInput;
|
|
296
|
+
exports.ChatMessage = ChatMessage.ChatMessage;
|
|
290
297
|
exports.Checkbox = Checkbox.Checkbox;
|
|
291
298
|
exports.Chip = Chip.Chip;
|
|
292
299
|
exports.Count = Count.Count;
|
|
@@ -372,6 +379,7 @@ exports.CopyIcon = CopyIcon.CopyIcon;
|
|
|
372
379
|
exports.CrossCircleIcon = CrossCircleIcon.CrossCircleIcon;
|
|
373
380
|
exports.CrossIcon = CrossIcon.CrossIcon;
|
|
374
381
|
exports.CrownIcon = CrownIcon.CrownIcon;
|
|
382
|
+
exports.DenseGridViewIcon = DenseGridViewIcon.DenseGridViewIcon;
|
|
375
383
|
exports.DiamondIcon = DiamondIcon.DiamondIcon;
|
|
376
384
|
exports.DiscordIcon = DiscordIcon.DiscordIcon;
|
|
377
385
|
exports.DiscountIcon = DiscountIcon.DiscountIcon;
|
|
@@ -501,6 +509,7 @@ exports.InlineEdit = InlineEdit.InlineEdit;
|
|
|
501
509
|
exports.Link = Link.Link;
|
|
502
510
|
exports.Loader = Loader.Loader;
|
|
503
511
|
exports.Logo = Logo.Logo;
|
|
512
|
+
exports.MediaStatusIndicator = MediaStatusIndicator.MediaStatusIndicator;
|
|
504
513
|
exports.MobileStepper = MobileStepper.MobileStepper;
|
|
505
514
|
exports.OnlineBlinkingIcon = OnlineBlinkingIcon.OnlineBlinkingIcon;
|
|
506
515
|
exports.PageSelector = PageSelector.PageSelector;
|
|
@@ -529,6 +538,7 @@ exports.Slider = Slider.Slider;
|
|
|
529
538
|
exports.Snackbar = Snackbar.Snackbar;
|
|
530
539
|
exports.Stepper = Stepper.Stepper;
|
|
531
540
|
exports.StepperStep = StepperStep.StepperStep;
|
|
541
|
+
exports.SubscribeButton = SubscribeButton.SubscribeButton;
|
|
532
542
|
exports.Switch = Switch.Switch;
|
|
533
543
|
exports.SwitchField = SwitchField.SwitchField;
|
|
534
544
|
exports.SwitchToggle = SwitchToggle.SwitchToggle;
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { IconButton } from "../IconButton/IconButton.mjs";
|
|
5
|
+
import { MicrophoneIcon } from "../Icons/MicrophoneIcon.mjs";
|
|
6
|
+
import { StopIcon } from "../Icons/StopIcon.mjs";
|
|
7
|
+
const STATUS_VARIANT = {
|
|
8
|
+
idle: "primary",
|
|
9
|
+
recording: "error"
|
|
10
|
+
};
|
|
11
|
+
const STATUS_ICON = {
|
|
12
|
+
idle: /* @__PURE__ */ jsx(MicrophoneIcon, {}),
|
|
13
|
+
recording: /* @__PURE__ */ jsx(StopIcon, {})
|
|
14
|
+
};
|
|
15
|
+
const STATUS_LABEL = {
|
|
16
|
+
idle: "Record",
|
|
17
|
+
recording: "Stop recording"
|
|
18
|
+
};
|
|
19
|
+
const AudioRecordButton = React.forwardRef(
|
|
20
|
+
({ status = "idle", "aria-label": ariaLabel, ...props }, ref) => {
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
IconButton,
|
|
23
|
+
{
|
|
24
|
+
ref,
|
|
25
|
+
variant: STATUS_VARIANT[status],
|
|
26
|
+
icon: STATUS_ICON[status],
|
|
27
|
+
"aria-label": ariaLabel ?? STATUS_LABEL[status],
|
|
28
|
+
...props
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
AudioRecordButton.displayName = "AudioRecordButton";
|
|
34
|
+
export {
|
|
35
|
+
AudioRecordButton
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=AudioRecordButton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioRecordButton.mjs","sources":["../../../src/components/AudioRecordButton/AudioRecordButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { IconButton, type IconButtonProps, type IconButtonVariant } from \"../IconButton/IconButton\";\nimport { MicrophoneIcon } from \"../Icons/MicrophoneIcon\";\nimport { StopIcon } from \"../Icons/StopIcon\";\n\n/**\n * Recording state of the button. Drives the icon and colour: `idle` shows the\n * microphone to start a recording, `recording` shows the stop glyph with the\n * destructive treatment to end it.\n */\nexport type AudioRecordButtonStatus = \"idle\" | \"recording\";\n\nconst STATUS_VARIANT: Record<AudioRecordButtonStatus, IconButtonVariant> = {\n idle: \"primary\",\n recording: \"error\",\n};\n\nconst STATUS_ICON: Record<AudioRecordButtonStatus, React.ReactNode> = {\n idle: <MicrophoneIcon />,\n recording: <StopIcon />,\n};\n\nconst STATUS_LABEL: Record<AudioRecordButtonStatus, string> = {\n idle: \"Record\",\n recording: \"Stop recording\",\n};\n\nexport interface AudioRecordButtonProps\n extends Omit<IconButtonProps, \"icon\" | \"variant\" | \"aria-label\"> {\n /** Recording state; drives the icon and colour. @default \"idle\" */\n status?: AudioRecordButtonStatus;\n /**\n * Accessible name. Falls back to a status-aware default (\"Record\" /\n * \"Stop recording\") when omitted so screen readers announce the action.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * A circular icon button that toggles audio recording. It owns the record\n * lifecycle so consumers flip a single `status` prop instead of swapping an\n * {@link IconButton}'s icon and colour: `idle` shows the microphone to start,\n * `recording` turns destructive with a stop glyph to end. Used by\n * {@link AudioUpload} for its in-progress stop control.\n *\n * @example\n * ```tsx\n * <AudioRecordButton status={recording ? \"recording\" : \"idle\"} onClick={toggle} />\n * ```\n */\nexport const AudioRecordButton = React.forwardRef<HTMLButtonElement, AudioRecordButtonProps>(\n ({ status = \"idle\", \"aria-label\": ariaLabel, ...props }, ref) => {\n return (\n <IconButton\n ref={ref}\n variant={STATUS_VARIANT[status]}\n icon={STATUS_ICON[status]}\n aria-label={ariaLabel ?? STATUS_LABEL[status]}\n {...props}\n />\n );\n },\n);\n\nAudioRecordButton.displayName = \"AudioRecordButton\";\n"],"names":[],"mappings":";;;;;;AAYA,MAAM,iBAAqE;AAAA,EACzE,MAAM;AAAA,EACN,WAAW;AACb;AAEA,MAAM,cAAgE;AAAA,EACpE,0BAAO,gBAAA,EAAe;AAAA,EACtB,+BAAY,UAAA,CAAA,CAAS;AACvB;AAEA,MAAM,eAAwD;AAAA,EAC5D,MAAM;AAAA,EACN,WAAW;AACb;AAyBO,MAAM,oBAAoB,MAAM;AAAA,EACrC,CAAC,EAAE,SAAS,QAAQ,cAAc,WAAW,GAAG,MAAA,GAAS,QAAQ;AAC/D,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,SAAS,eAAe,MAAM;AAAA,QAC9B,MAAM,YAAY,MAAM;AAAA,QACxB,cAAY,aAAa,aAAa,MAAM;AAAA,QAC3C,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AAEA,kBAAkB,cAAc;"}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../../utils/cn.mjs";
|
|
5
|
+
import { AudioRecordButton } from "../AudioRecordButton/AudioRecordButton.mjs";
|
|
5
6
|
import { Button } from "../Button/Button.mjs";
|
|
6
7
|
import { MicrophoneIcon } from "../Icons/MicrophoneIcon.mjs";
|
|
7
|
-
import { StopIcon } from "../Icons/StopIcon.mjs";
|
|
8
8
|
import { UploadCloudIcon } from "../Icons/UploadCloudIcon.mjs";
|
|
9
9
|
import { AudioWaveform } from "./AudioWaveform.mjs";
|
|
10
10
|
import { formatAudioTime, validateAudioFile } from "./audioUtils.mjs";
|
|
@@ -179,14 +179,14 @@ const AudioUpload = React.forwardRef(
|
|
|
179
179
|
}
|
|
180
180
|
) }),
|
|
181
181
|
/* @__PURE__ */ jsx(
|
|
182
|
-
|
|
182
|
+
AudioRecordButton,
|
|
183
183
|
{
|
|
184
184
|
ref: stopButtonRef,
|
|
185
|
-
|
|
185
|
+
status: "recording",
|
|
186
|
+
size: "40",
|
|
186
187
|
onClick: handleStopClick,
|
|
187
|
-
className: "mt-1 flex size-11 items-center justify-center rounded-full bg-error-content text-content-always-white transition-colors hover:bg-error-content/80 focus:shadow-focus-ring focus-visible:outline-none",
|
|
188
188
|
"aria-label": stopButtonAriaLabel,
|
|
189
|
-
|
|
189
|
+
className: "mt-1"
|
|
190
190
|
}
|
|
191
191
|
)
|
|
192
192
|
]
|