@fairmint/ui 0.3.38 → 0.3.40
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/components/generic/EmptyState/EmptyState.cjs +35 -6
- package/dist/components/generic/EmptyState/EmptyState.cjs.map +1 -1
- package/dist/components/generic/EmptyState/EmptyState.d.ts +12 -4
- package/dist/components/generic/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/components/generic/EmptyState/EmptyState.js +36 -7
- package/dist/components/generic/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/generic/SearchInput/SearchInput.cjs +10 -8
- package/dist/components/generic/SearchInput/SearchInput.cjs.map +1 -1
- package/dist/components/generic/SearchInput/SearchInput.d.ts.map +1 -1
- package/dist/components/generic/SearchInput/SearchInput.js +10 -8
- package/dist/components/generic/SearchInput/SearchInput.js.map +1 -1
- package/dist/components/layout/MobileNav/MobileNavHeader.cjs +2 -1
- package/dist/components/layout/MobileNav/MobileNavHeader.cjs.map +1 -1
- package/dist/components/layout/MobileNav/MobileNavHeader.d.ts.map +1 -1
- package/dist/components/layout/MobileNav/MobileNavHeader.js +2 -1
- package/dist/components/layout/MobileNav/MobileNavHeader.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
-
const index = require("../../../theme/index.cjs");
|
|
5
4
|
const colors = require("../../../theme/colors.cjs");
|
|
5
|
+
const Avatar = require("../../primitives/Avatar/Avatar.cjs");
|
|
6
6
|
const Button = require("../../primitives/Button/Button.cjs");
|
|
7
7
|
const layout = require("../../primitives/layout.cjs");
|
|
8
|
-
const Title = require("../../../node_modules/@mantine/core/esm/components/Title/Title.cjs");
|
|
9
8
|
const Text = require("../../../node_modules/@mantine/core/esm/components/Text/Text.cjs");
|
|
9
|
+
const EMPTY_STATE_AVATAR_SIZE = 56;
|
|
10
|
+
const EMPTY_STATE_ICON_SIZE = 28;
|
|
11
|
+
function EmptyStateAvatar({ avatar, icon }) {
|
|
12
|
+
if (avatar) {
|
|
13
|
+
return avatar;
|
|
14
|
+
}
|
|
15
|
+
if (!icon) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19
|
+
Avatar.Avatar,
|
|
20
|
+
{
|
|
21
|
+
"aria-hidden": true,
|
|
22
|
+
color: colors.colors.neutral,
|
|
23
|
+
radius: "xl",
|
|
24
|
+
size: EMPTY_STATE_AVATAR_SIZE,
|
|
25
|
+
styles: {
|
|
26
|
+
root: {
|
|
27
|
+
"& svg": {
|
|
28
|
+
height: EMPTY_STATE_ICON_SIZE,
|
|
29
|
+
width: EMPTY_STATE_ICON_SIZE
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
variant: "light",
|
|
34
|
+
children: icon
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}
|
|
10
38
|
function EmptyState({
|
|
39
|
+
avatar,
|
|
11
40
|
icon,
|
|
12
41
|
title,
|
|
13
42
|
description,
|
|
@@ -16,10 +45,10 @@ function EmptyState({
|
|
|
16
45
|
actionColor = colors.colors.primary
|
|
17
46
|
}) {
|
|
18
47
|
return /* @__PURE__ */ jsxRuntime.jsxs(layout.Stack, { align: "center", gap: "md", py: "xl", role: "status", children: [
|
|
19
|
-
|
|
20
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21
|
-
description && /* @__PURE__ */ jsxRuntime.jsx(Text.Text, { c:
|
|
22
|
-
actionLabel && onAction && /* @__PURE__ */ jsxRuntime.jsx(Button.Button, {
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx(EmptyStateAvatar, { avatar, icon }),
|
|
49
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text.Text, { fw: 500, size: "lg", ta: "center", children: title }),
|
|
50
|
+
description && /* @__PURE__ */ jsxRuntime.jsx(Text.Text, { c: "dimmed", maw: 360, size: "sm", ta: "center", children: description }),
|
|
51
|
+
actionLabel && onAction && /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { color: actionColor, onClick: onAction, variant: "light", children: actionLabel })
|
|
23
52
|
] });
|
|
24
53
|
}
|
|
25
54
|
exports.EmptyState = EmptyState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.cjs","sources":["../../../../src/components/generic/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"EmptyState.cjs","sources":["../../../../src/components/generic/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { colors } from \"../../../theme/colors\";\nimport { Avatar } from \"../../primitives/Avatar/Avatar\";\nimport { Button } from \"../../primitives/Button/Button\";\nimport { Stack, Text } from \"../../primitives/layout\";\n\nconst EMPTY_STATE_AVATAR_SIZE = 56;\nconst EMPTY_STATE_ICON_SIZE = 28;\n\nexport interface EmptyStateProps {\n /**\n * Fully composed avatar (photo, initials, or custom node). Takes precedence\n * over `icon`. Use this when the empty state represents a person or entity.\n */\n avatar?: ReactNode;\n /**\n * Icon glyph (e.g. from `@tabler/icons-react`). Wrapped in the canonical\n * empty-state Avatar: 56px, light gray, circular.\n */\n icon?: ReactNode;\n /** Primary heading. */\n title: ReactNode;\n /** Supporting description. */\n description?: ReactNode;\n /** CTA button label. Rendered only when `onAction` is also provided. */\n actionLabel?: string;\n /** CTA button callback. The CTA is omitted unless this is set. */\n onAction?: () => void;\n /** CTA button color. @default colors.primary */\n actionColor?: string;\n}\n\nfunction EmptyStateAvatar({ avatar, icon }: Pick<EmptyStateProps, \"avatar\" | \"icon\">) {\n if (avatar) {\n return avatar;\n }\n if (!icon) {\n return null;\n }\n return (\n <Avatar\n aria-hidden\n color={colors.neutral}\n radius=\"xl\"\n size={EMPTY_STATE_AVATAR_SIZE}\n styles={{\n root: {\n \"& svg\": {\n height: EMPTY_STATE_ICON_SIZE,\n width: EMPTY_STATE_ICON_SIZE,\n },\n },\n }}\n variant=\"light\"\n >\n {icon}\n </Avatar>\n );\n}\n\nexport function EmptyState({\n avatar,\n icon,\n title,\n description,\n actionLabel,\n onAction,\n actionColor = colors.primary,\n}: EmptyStateProps) {\n return (\n <Stack align=\"center\" gap=\"md\" py=\"xl\" role=\"status\">\n <EmptyStateAvatar avatar={avatar} icon={icon} />\n <Text fw={500} size=\"lg\" ta=\"center\">\n {title}\n </Text>\n {description && (\n <Text c=\"dimmed\" maw={360} size=\"sm\" ta=\"center\">\n {description}\n </Text>\n )}\n {actionLabel && onAction && (\n <Button color={actionColor} onClick={onAction} variant=\"light\">\n {actionLabel}\n </Button>\n )}\n </Stack>\n );\n}\n"],"names":["jsx","Avatar","colors","jsxs","Stack","Text","Button"],"mappings":";;;;;;;;AAMA,MAAM,0BAA0B;AAChC,MAAM,wBAAwB;AAyB9B,SAAS,iBAAiB,EAAE,QAAQ,QAAkD;AACpF,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AACA,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,SACEA,2BAAAA;AAAAA,IAACC,OAAAA;AAAAA,IAAA;AAAA,MACC,eAAW;AAAA,MACX,OAAOC,OAAAA,OAAO;AAAA,MACd,QAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,MAAM;AAAA,UACJ,SAAS;AAAA,YACP,QAAQ;AAAA,YACR,OAAO;AAAA,UAAA;AAAA,QACT;AAAA,MACF;AAAA,MAEF,SAAQ;AAAA,MAEP,UAAA;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAcA,OAAAA,OAAO;AACvB,GAAoB;AAClB,SACEC,gCAACC,OAAAA,SAAM,OAAM,UAAS,KAAI,MAAK,IAAG,MAAK,MAAK,UAC1C,UAAA;AAAA,IAAAJ,2BAAAA,IAAC,kBAAA,EAAiB,QAAgB,KAAA,CAAY;AAAA,IAC9CA,2BAAAA,IAACK,KAAAA,QAAK,IAAI,KAAK,MAAK,MAAK,IAAG,UACzB,UAAA,MAAA,CACH;AAAA,IACC,eACCL,2BAAAA,IAACK,KAAAA,MAAA,EAAK,GAAE,UAAS,KAAK,KAAK,MAAK,MAAK,IAAG,UACrC,UAAA,YAAA,CACH;AAAA,IAED,eAAe,YACdL,2BAAAA,IAACM,OAAAA,QAAA,EAAO,OAAO,aAAa,SAAS,UAAU,SAAQ,SACpD,UAAA,YAAA,CACH;AAAA,EAAA,GAEJ;AAEJ;;"}
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
export interface EmptyStateProps {
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Fully composed avatar (photo, initials, or custom node). Takes precedence
|
|
5
|
+
* over `icon`. Use this when the empty state represents a person or entity.
|
|
6
|
+
*/
|
|
7
|
+
avatar?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Icon glyph (e.g. from `@tabler/icons-react`). Wrapped in the canonical
|
|
10
|
+
* empty-state Avatar: 56px, light gray, circular.
|
|
11
|
+
*/
|
|
4
12
|
icon?: ReactNode;
|
|
5
13
|
/** Primary heading. */
|
|
6
14
|
title: ReactNode;
|
|
7
15
|
/** Supporting description. */
|
|
8
16
|
description?: ReactNode;
|
|
9
|
-
/** CTA button label.
|
|
17
|
+
/** CTA button label. Rendered only when `onAction` is also provided. */
|
|
10
18
|
actionLabel?: string;
|
|
11
|
-
/** CTA button callback. */
|
|
19
|
+
/** CTA button callback. The CTA is omitted unless this is set. */
|
|
12
20
|
onAction?: () => void;
|
|
13
21
|
/** CTA button color. @default colors.primary */
|
|
14
22
|
actionColor?: string;
|
|
15
23
|
}
|
|
16
|
-
export declare function EmptyState({ icon, title, description, actionLabel, onAction, actionColor, }: EmptyStateProps): import("react").JSX.Element;
|
|
24
|
+
export declare function EmptyState({ avatar, icon, title, description, actionLabel, onAction, actionColor, }: EmptyStateProps): import("react").JSX.Element;
|
|
17
25
|
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../../src/components/generic/EmptyState/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../../src/components/generic/EmptyState/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uBAAuB;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8BD,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,IAAI,EACJ,KAAK,EACL,WAAW,EACX,WAAW,EACX,QAAQ,EACR,WAA4B,GAC7B,EAAE,eAAe,+BAmBjB"}
|
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fairmintVars } from "../../../theme/index.js";
|
|
3
2
|
import { colors } from "../../../theme/colors.js";
|
|
3
|
+
import { Avatar } from "../../primitives/Avatar/Avatar.js";
|
|
4
4
|
import { Button } from "../../primitives/Button/Button.js";
|
|
5
|
-
import { Stack
|
|
6
|
-
import { Title } from "../../../node_modules/@mantine/core/esm/components/Title/Title.js";
|
|
5
|
+
import { Stack } from "../../primitives/layout.js";
|
|
7
6
|
import { Text } from "../../../node_modules/@mantine/core/esm/components/Text/Text.js";
|
|
7
|
+
const EMPTY_STATE_AVATAR_SIZE = 56;
|
|
8
|
+
const EMPTY_STATE_ICON_SIZE = 28;
|
|
9
|
+
function EmptyStateAvatar({ avatar, icon }) {
|
|
10
|
+
if (avatar) {
|
|
11
|
+
return avatar;
|
|
12
|
+
}
|
|
13
|
+
if (!icon) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return /* @__PURE__ */ jsx(
|
|
17
|
+
Avatar,
|
|
18
|
+
{
|
|
19
|
+
"aria-hidden": true,
|
|
20
|
+
color: colors.neutral,
|
|
21
|
+
radius: "xl",
|
|
22
|
+
size: EMPTY_STATE_AVATAR_SIZE,
|
|
23
|
+
styles: {
|
|
24
|
+
root: {
|
|
25
|
+
"& svg": {
|
|
26
|
+
height: EMPTY_STATE_ICON_SIZE,
|
|
27
|
+
width: EMPTY_STATE_ICON_SIZE
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
variant: "light",
|
|
32
|
+
children: icon
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
8
36
|
function EmptyState({
|
|
37
|
+
avatar,
|
|
9
38
|
icon,
|
|
10
39
|
title,
|
|
11
40
|
description,
|
|
@@ -14,10 +43,10 @@ function EmptyState({
|
|
|
14
43
|
actionColor = colors.primary
|
|
15
44
|
}) {
|
|
16
45
|
return /* @__PURE__ */ jsxs(Stack, { align: "center", gap: "md", py: "xl", role: "status", children: [
|
|
17
|
-
|
|
18
|
-
/* @__PURE__ */ jsx(
|
|
19
|
-
description && /* @__PURE__ */ jsx(Text, { c:
|
|
20
|
-
actionLabel && onAction && /* @__PURE__ */ jsx(Button, {
|
|
46
|
+
/* @__PURE__ */ jsx(EmptyStateAvatar, { avatar, icon }),
|
|
47
|
+
/* @__PURE__ */ jsx(Text, { fw: 500, size: "lg", ta: "center", children: title }),
|
|
48
|
+
description && /* @__PURE__ */ jsx(Text, { c: "dimmed", maw: 360, size: "sm", ta: "center", children: description }),
|
|
49
|
+
actionLabel && onAction && /* @__PURE__ */ jsx(Button, { color: actionColor, onClick: onAction, variant: "light", children: actionLabel })
|
|
21
50
|
] });
|
|
22
51
|
}
|
|
23
52
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.js","sources":["../../../../src/components/generic/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"EmptyState.js","sources":["../../../../src/components/generic/EmptyState/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { colors } from \"../../../theme/colors\";\nimport { Avatar } from \"../../primitives/Avatar/Avatar\";\nimport { Button } from \"../../primitives/Button/Button\";\nimport { Stack, Text } from \"../../primitives/layout\";\n\nconst EMPTY_STATE_AVATAR_SIZE = 56;\nconst EMPTY_STATE_ICON_SIZE = 28;\n\nexport interface EmptyStateProps {\n /**\n * Fully composed avatar (photo, initials, or custom node). Takes precedence\n * over `icon`. Use this when the empty state represents a person or entity.\n */\n avatar?: ReactNode;\n /**\n * Icon glyph (e.g. from `@tabler/icons-react`). Wrapped in the canonical\n * empty-state Avatar: 56px, light gray, circular.\n */\n icon?: ReactNode;\n /** Primary heading. */\n title: ReactNode;\n /** Supporting description. */\n description?: ReactNode;\n /** CTA button label. Rendered only when `onAction` is also provided. */\n actionLabel?: string;\n /** CTA button callback. The CTA is omitted unless this is set. */\n onAction?: () => void;\n /** CTA button color. @default colors.primary */\n actionColor?: string;\n}\n\nfunction EmptyStateAvatar({ avatar, icon }: Pick<EmptyStateProps, \"avatar\" | \"icon\">) {\n if (avatar) {\n return avatar;\n }\n if (!icon) {\n return null;\n }\n return (\n <Avatar\n aria-hidden\n color={colors.neutral}\n radius=\"xl\"\n size={EMPTY_STATE_AVATAR_SIZE}\n styles={{\n root: {\n \"& svg\": {\n height: EMPTY_STATE_ICON_SIZE,\n width: EMPTY_STATE_ICON_SIZE,\n },\n },\n }}\n variant=\"light\"\n >\n {icon}\n </Avatar>\n );\n}\n\nexport function EmptyState({\n avatar,\n icon,\n title,\n description,\n actionLabel,\n onAction,\n actionColor = colors.primary,\n}: EmptyStateProps) {\n return (\n <Stack align=\"center\" gap=\"md\" py=\"xl\" role=\"status\">\n <EmptyStateAvatar avatar={avatar} icon={icon} />\n <Text fw={500} size=\"lg\" ta=\"center\">\n {title}\n </Text>\n {description && (\n <Text c=\"dimmed\" maw={360} size=\"sm\" ta=\"center\">\n {description}\n </Text>\n )}\n {actionLabel && onAction && (\n <Button color={actionColor} onClick={onAction} variant=\"light\">\n {actionLabel}\n </Button>\n )}\n </Stack>\n );\n}\n"],"names":[],"mappings":";;;;;;AAMA,MAAM,0BAA0B;AAChC,MAAM,wBAAwB;AAyB9B,SAAS,iBAAiB,EAAE,QAAQ,QAAkD;AACpF,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AACA,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAW;AAAA,MACX,OAAO,OAAO;AAAA,MACd,QAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,MAAM;AAAA,UACJ,SAAS;AAAA,YACP,QAAQ;AAAA,YACR,OAAO;AAAA,UAAA;AAAA,QACT;AAAA,MACF;AAAA,MAEF,SAAQ;AAAA,MAEP,UAAA;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc,OAAO;AACvB,GAAoB;AAClB,SACE,qBAAC,SAAM,OAAM,UAAS,KAAI,MAAK,IAAG,MAAK,MAAK,UAC1C,UAAA;AAAA,IAAA,oBAAC,kBAAA,EAAiB,QAAgB,KAAA,CAAY;AAAA,IAC9C,oBAAC,QAAK,IAAI,KAAK,MAAK,MAAK,IAAG,UACzB,UAAA,MAAA,CACH;AAAA,IACC,eACC,oBAAC,MAAA,EAAK,GAAE,UAAS,KAAK,KAAK,MAAK,MAAK,IAAG,UACrC,UAAA,YAAA,CACH;AAAA,IAED,eAAe,YACd,oBAAC,QAAA,EAAO,OAAO,aAAa,SAAS,UAAU,SAAQ,SACpD,UAAA,YAAA,CACH;AAAA,EAAA,GAEJ;AAEJ;"}
|
|
@@ -18,24 +18,26 @@ function SearchInput({
|
|
|
18
18
|
const [localValue, setLocalValue] = React.useState(value);
|
|
19
19
|
const [debounced] = useDebouncedValue.useDebouncedValue(localValue, debounceMs);
|
|
20
20
|
const mounted = React.useRef(false);
|
|
21
|
+
const lastEmitted = React.useRef(value);
|
|
22
|
+
const onChangeRef = React.useRef(onChange);
|
|
23
|
+
onChangeRef.current = onChange;
|
|
21
24
|
React.useEffect(() => {
|
|
22
25
|
setLocalValue(value);
|
|
26
|
+
lastEmitted.current = value;
|
|
23
27
|
}, [value]);
|
|
24
|
-
const skipNextDebounce = React.useRef(false);
|
|
25
28
|
React.useEffect(() => {
|
|
26
29
|
if (!mounted.current) {
|
|
27
30
|
mounted.current = true;
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}, [debounced, onChange]);
|
|
33
|
+
if (debounced !== localValue) return;
|
|
34
|
+
if (debounced === lastEmitted.current) return;
|
|
35
|
+
lastEmitted.current = debounced;
|
|
36
|
+
onChangeRef.current(debounced);
|
|
37
|
+
}, [debounced, localValue]);
|
|
36
38
|
const handleClear = () => {
|
|
37
39
|
setLocalValue("");
|
|
38
|
-
|
|
40
|
+
lastEmitted.current = "";
|
|
39
41
|
onChange("");
|
|
40
42
|
};
|
|
41
43
|
const defaultSearchIcon = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.cjs","sources":["../../../../src/components/generic/SearchInput/SearchInput.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { useDebouncedValue } from \"../../primitives/layout\";\nimport { TextInput, type TextInputProps } from \"../../primitives/TextInput/TextInput\";\n\nexport interface SearchInputProps extends Omit<TextInputProps, \"onChange\" | \"value\"> {\n /** Current search value (controlled). */\n value: string;\n /** Called with the debounced value after `debounceMs`. */\n onChange: (value: string) => void;\n /** Debounce delay in ms. @default 300 */\n debounceMs?: number;\n /** Left section icon. @default search icon SVG */\n searchIcon?: ReactNode;\n /** Clear button icon. @default × */\n clearIcon?: ReactNode;\n}\n\nexport function SearchInput({\n value,\n onChange,\n debounceMs = 300,\n searchIcon,\n clearIcon,\n placeholder = \"Search...\",\n ...rest\n}: SearchInputProps) {\n const [localValue, setLocalValue] = useState(value);\n const [debounced] = useDebouncedValue(localValue, debounceMs);\n const mounted = useRef(false);\n\n
|
|
1
|
+
{"version":3,"file":"SearchInput.cjs","sources":["../../../../src/components/generic/SearchInput/SearchInput.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { useDebouncedValue } from \"../../primitives/layout\";\nimport { TextInput, type TextInputProps } from \"../../primitives/TextInput/TextInput\";\n\nexport interface SearchInputProps extends Omit<TextInputProps, \"onChange\" | \"value\"> {\n /** Current search value (controlled). */\n value: string;\n /** Called with the debounced value after `debounceMs`. */\n onChange: (value: string) => void;\n /** Debounce delay in ms. @default 300 */\n debounceMs?: number;\n /** Left section icon. @default search icon SVG */\n searchIcon?: ReactNode;\n /** Clear button icon. @default × */\n clearIcon?: ReactNode;\n}\n\nexport function SearchInput({\n value,\n onChange,\n debounceMs = 300,\n searchIcon,\n clearIcon,\n placeholder = \"Search...\",\n ...rest\n}: SearchInputProps) {\n const [localValue, setLocalValue] = useState(value);\n const [debounced] = useDebouncedValue(localValue, debounceMs);\n const mounted = useRef(false);\n // Track the last value already reflected in the parent's `value` prop so we\n // never re-emit a stale debounced value after Clear (or after an external\n // `value` change) — the previous `skipNextDebounce` flag swallowed the *next*\n // debounced emit, which dropped pasted queries when `onChange` was a stable\n // callback (see ENG-535 regression test).\n const lastEmitted = useRef(value);\n // Keep `onChange` out of the emit effect deps. An inline callback would\n // otherwise re-run the effect on every parent render and restore a stale\n // `debounced`/`localValue` pair after an external `value` reset.\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n setLocalValue(value);\n lastEmitted.current = value;\n }, [value]);\n\n useEffect(() => {\n if (!mounted.current) {\n mounted.current = true;\n return;\n }\n // `debounced` lags `localValue`. Emitting while they disagree restores a\n // stale query — especially right after Clear, before the debounce catches up.\n if (debounced !== localValue) return;\n if (debounced === lastEmitted.current) return;\n lastEmitted.current = debounced;\n onChangeRef.current(debounced);\n }, [debounced, localValue]);\n\n const handleClear = () => {\n setLocalValue(\"\");\n lastEmitted.current = \"\";\n onChange(\"\");\n };\n\n const defaultSearchIcon = (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n );\n\n return (\n <TextInput\n value={localValue}\n onChange={(e) => setLocalValue(e.currentTarget.value)}\n placeholder={placeholder}\n leftSection={searchIcon ?? defaultSearchIcon}\n rightSection={\n localValue ? (\n <ActionIcon\n variant=\"subtle\"\n color={colors.neutral}\n size=\"sm\"\n onClick={handleClear}\n aria-label=\"Clear search\"\n >\n {clearIcon ?? \"×\"}\n </ActionIcon>\n ) : null\n }\n {...rest}\n />\n );\n}\n"],"names":["useState","useDebouncedValue","useRef","useEffect","jsxs","jsx","TextInput","ActionIcon","colors"],"mappings":";;;;;;;;AAmBO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,GAAG;AACL,GAAqB;AACnB,QAAM,CAAC,YAAY,aAAa,IAAIA,MAAAA,SAAS,KAAK;AAClD,QAAM,CAAC,SAAS,IAAIC,oCAAkB,YAAY,UAAU;AAC5D,QAAM,UAAUC,MAAAA,OAAO,KAAK;AAM5B,QAAM,cAAcA,MAAAA,OAAO,KAAK;AAIhC,QAAM,cAAcA,MAAAA,OAAO,QAAQ;AACnC,cAAY,UAAU;AAEtBC,QAAAA,UAAU,MAAM;AACd,kBAAc,KAAK;AACnB,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,KAAK,CAAC;AAEVA,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,QAAQ,SAAS;AACpB,cAAQ,UAAU;AAClB;AAAA,IACF;AAGA,QAAI,cAAc,WAAY;AAC9B,QAAI,cAAc,YAAY,QAAS;AACvC,gBAAY,UAAU;AACtB,gBAAY,QAAQ,SAAS;AAAA,EAC/B,GAAG,CAAC,WAAW,UAAU,CAAC;AAE1B,QAAM,cAAc,MAAM;AACxB,kBAAc,EAAE;AAChB,gBAAY,UAAU;AACtB,aAAS,EAAE;AAAA,EACb;AAEA,QAAM,oBACJC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAAC,+BAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9BA,2BAAAA,IAAC,QAAA,EAAK,GAAE,mBAAA,CAAmB;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAI/B,SACEA,2BAAAA;AAAAA,IAACC,UAAAA;AAAAA,IAAA;AAAA,MACC,OAAO;AAAA,MACP,UAAU,CAAC,MAAM,cAAc,EAAE,cAAc,KAAK;AAAA,MACpD;AAAA,MACA,aAAa,cAAc;AAAA,MAC3B,cACE,aACED,2BAAAA;AAAAA,QAACE,WAAAA;AAAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAOC,OAAAA,OAAO;AAAA,UACd,MAAK;AAAA,UACL,SAAS;AAAA,UACT,cAAW;AAAA,UAEV,UAAA,aAAa;AAAA,QAAA;AAAA,MAAA,IAEd;AAAA,MAEL,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.d.ts","sourceRoot":"","sources":["../../../../src/components/generic/SearchInput/SearchInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtF,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC;IAClF,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,oCAAoC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,UAAgB,EAChB,UAAU,EACV,SAAS,EACT,WAAyB,EACzB,GAAG,IAAI,EACR,EAAE,gBAAgB,+
|
|
1
|
+
{"version":3,"file":"SearchInput.d.ts","sourceRoot":"","sources":["../../../../src/components/generic/SearchInput/SearchInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtF,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC;IAClF,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,oCAAoC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,UAAgB,EAChB,UAAU,EACV,SAAS,EACT,WAAyB,EACzB,GAAG,IAAI,EACR,EAAE,gBAAgB,+BA+ElB"}
|
|
@@ -16,24 +16,26 @@ function SearchInput({
|
|
|
16
16
|
const [localValue, setLocalValue] = useState(value);
|
|
17
17
|
const [debounced] = useDebouncedValue(localValue, debounceMs);
|
|
18
18
|
const mounted = useRef(false);
|
|
19
|
+
const lastEmitted = useRef(value);
|
|
20
|
+
const onChangeRef = useRef(onChange);
|
|
21
|
+
onChangeRef.current = onChange;
|
|
19
22
|
useEffect(() => {
|
|
20
23
|
setLocalValue(value);
|
|
24
|
+
lastEmitted.current = value;
|
|
21
25
|
}, [value]);
|
|
22
|
-
const skipNextDebounce = useRef(false);
|
|
23
26
|
useEffect(() => {
|
|
24
27
|
if (!mounted.current) {
|
|
25
28
|
mounted.current = true;
|
|
26
29
|
return;
|
|
27
30
|
}
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}, [debounced, onChange]);
|
|
31
|
+
if (debounced !== localValue) return;
|
|
32
|
+
if (debounced === lastEmitted.current) return;
|
|
33
|
+
lastEmitted.current = debounced;
|
|
34
|
+
onChangeRef.current(debounced);
|
|
35
|
+
}, [debounced, localValue]);
|
|
34
36
|
const handleClear = () => {
|
|
35
37
|
setLocalValue("");
|
|
36
|
-
|
|
38
|
+
lastEmitted.current = "";
|
|
37
39
|
onChange("");
|
|
38
40
|
};
|
|
39
41
|
const defaultSearchIcon = /* @__PURE__ */ jsxs(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.js","sources":["../../../../src/components/generic/SearchInput/SearchInput.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { useDebouncedValue } from \"../../primitives/layout\";\nimport { TextInput, type TextInputProps } from \"../../primitives/TextInput/TextInput\";\n\nexport interface SearchInputProps extends Omit<TextInputProps, \"onChange\" | \"value\"> {\n /** Current search value (controlled). */\n value: string;\n /** Called with the debounced value after `debounceMs`. */\n onChange: (value: string) => void;\n /** Debounce delay in ms. @default 300 */\n debounceMs?: number;\n /** Left section icon. @default search icon SVG */\n searchIcon?: ReactNode;\n /** Clear button icon. @default × */\n clearIcon?: ReactNode;\n}\n\nexport function SearchInput({\n value,\n onChange,\n debounceMs = 300,\n searchIcon,\n clearIcon,\n placeholder = \"Search...\",\n ...rest\n}: SearchInputProps) {\n const [localValue, setLocalValue] = useState(value);\n const [debounced] = useDebouncedValue(localValue, debounceMs);\n const mounted = useRef(false);\n\n
|
|
1
|
+
{"version":3,"file":"SearchInput.js","sources":["../../../../src/components/generic/SearchInput/SearchInput.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { useDebouncedValue } from \"../../primitives/layout\";\nimport { TextInput, type TextInputProps } from \"../../primitives/TextInput/TextInput\";\n\nexport interface SearchInputProps extends Omit<TextInputProps, \"onChange\" | \"value\"> {\n /** Current search value (controlled). */\n value: string;\n /** Called with the debounced value after `debounceMs`. */\n onChange: (value: string) => void;\n /** Debounce delay in ms. @default 300 */\n debounceMs?: number;\n /** Left section icon. @default search icon SVG */\n searchIcon?: ReactNode;\n /** Clear button icon. @default × */\n clearIcon?: ReactNode;\n}\n\nexport function SearchInput({\n value,\n onChange,\n debounceMs = 300,\n searchIcon,\n clearIcon,\n placeholder = \"Search...\",\n ...rest\n}: SearchInputProps) {\n const [localValue, setLocalValue] = useState(value);\n const [debounced] = useDebouncedValue(localValue, debounceMs);\n const mounted = useRef(false);\n // Track the last value already reflected in the parent's `value` prop so we\n // never re-emit a stale debounced value after Clear (or after an external\n // `value` change) — the previous `skipNextDebounce` flag swallowed the *next*\n // debounced emit, which dropped pasted queries when `onChange` was a stable\n // callback (see ENG-535 regression test).\n const lastEmitted = useRef(value);\n // Keep `onChange` out of the emit effect deps. An inline callback would\n // otherwise re-run the effect on every parent render and restore a stale\n // `debounced`/`localValue` pair after an external `value` reset.\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n setLocalValue(value);\n lastEmitted.current = value;\n }, [value]);\n\n useEffect(() => {\n if (!mounted.current) {\n mounted.current = true;\n return;\n }\n // `debounced` lags `localValue`. Emitting while they disagree restores a\n // stale query — especially right after Clear, before the debounce catches up.\n if (debounced !== localValue) return;\n if (debounced === lastEmitted.current) return;\n lastEmitted.current = debounced;\n onChangeRef.current(debounced);\n }, [debounced, localValue]);\n\n const handleClear = () => {\n setLocalValue(\"\");\n lastEmitted.current = \"\";\n onChange(\"\");\n };\n\n const defaultSearchIcon = (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n );\n\n return (\n <TextInput\n value={localValue}\n onChange={(e) => setLocalValue(e.currentTarget.value)}\n placeholder={placeholder}\n leftSection={searchIcon ?? defaultSearchIcon}\n rightSection={\n localValue ? (\n <ActionIcon\n variant=\"subtle\"\n color={colors.neutral}\n size=\"sm\"\n onClick={handleClear}\n aria-label=\"Clear search\"\n >\n {clearIcon ?? \"×\"}\n </ActionIcon>\n ) : null\n }\n {...rest}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;AAmBO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,GAAG;AACL,GAAqB;AACnB,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,CAAC,SAAS,IAAI,kBAAkB,YAAY,UAAU;AAC5D,QAAM,UAAU,OAAO,KAAK;AAM5B,QAAM,cAAc,OAAO,KAAK;AAIhC,QAAM,cAAc,OAAO,QAAQ;AACnC,cAAY,UAAU;AAEtB,YAAU,MAAM;AACd,kBAAc,KAAK;AACnB,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ,SAAS;AACpB,cAAQ,UAAU;AAClB;AAAA,IACF;AAGA,QAAI,cAAc,WAAY;AAC9B,QAAI,cAAc,YAAY,QAAS;AACvC,gBAAY,UAAU;AACtB,gBAAY,QAAQ,SAAS;AAAA,EAC/B,GAAG,CAAC,WAAW,UAAU,CAAC;AAE1B,QAAM,cAAc,MAAM;AACxB,kBAAc,EAAE;AAChB,gBAAY,UAAU;AACtB,aAAS,EAAE;AAAA,EACb;AAEA,QAAM,oBACJ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9B,oBAAC,QAAA,EAAK,GAAE,mBAAA,CAAmB;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAI/B,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO;AAAA,MACP,UAAU,CAAC,MAAM,cAAc,EAAE,cAAc,KAAK;AAAA,MACpD;AAAA,MACA,aAAa,cAAc;AAAA,MAC3B,cACE,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAO,OAAO;AAAA,UACd,MAAK;AAAA,UACL,SAAS;AAAA,UACT,cAAW;AAAA,UAEV,UAAA,aAAa;AAAA,QAAA;AAAA,MAAA,IAEd;AAAA,MAEL,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -53,7 +53,8 @@ function MobileNavHeader({
|
|
|
53
53
|
wrap: "nowrap",
|
|
54
54
|
align: "center",
|
|
55
55
|
gap: 0,
|
|
56
|
-
|
|
56
|
+
w: "100%",
|
|
57
|
+
bg: "body",
|
|
57
58
|
children: [
|
|
58
59
|
/* @__PURE__ */ jsxRuntime.jsxs(Group.Group, { wrap: "nowrap", gap: MOBILE_NAV_BRAND_GAP, align: "center", children: [
|
|
59
60
|
mark,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileNavHeader.cjs","sources":["../../../../src/components/layout/MobileNav/MobileNavHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { colors } from \"../../../theme\";\nimport { FairmintLogo } from \"../../FairmintLogo/FairmintLogo\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Group } from \"../../primitives/layout\";\n\n/** Product-shell mobile header height (Studio + Investor). */\nexport const MOBILE_NAV_HEADER_HEIGHT = 60;\n/** Fairmint wordmark width in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_WIDTH = 120;\n/** Fairmint wordmark height in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_HEIGHT = 28;\n/** Space between the wordmark and the menu control. */\nexport const MOBILE_NAV_BRAND_GAP = 16;\n/** Header horizontal padding. */\nexport const MOBILE_NAV_HEADER_PADDING_X = 16;\n/** Menu control hit target (Mantine `lg`). */\nexport const MOBILE_NAV_MENU_SIZE = 36;\n\nconst defaultMenuIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6h16\" />\n <path d=\"M4 12h16\" />\n <path d=\"M4 18h16\" />\n </svg>\n);\n\nexport interface MobileNavHeaderProps {\n /**\n * Override the default Fairmint wordmark (white-label portals).\n * When omitted and `onMenuClick` is set, the canonical 120×28 Fairmint logo is used.\n */\n logo?: ReactNode;\n /** Opens the MobileNav sheet. Omit on desktop where SideNav owns destinations. */\n onMenuClick?: () => void;\n /** Right-aligned header actions (notifications, Ask AI). */\n rightSection?: ReactNode;\n /** Menu glyph. Defaults to an outlined hamburger so the component never imports an icon library. */\n menuIcon?: ReactNode;\n}\n\n/**\n * Canonical mobile page header for Fairmint product shells.\n *\n * Logo then hamburger at a 16px gap, optional actions on the far right.\n * Pixel metrics are fixed so Studio and Investor cannot drift via theme tokens\n * or extra wrappers.\n */\nexport function MobileNavHeader({\n logo,\n onMenuClick,\n rightSection,\n menuIcon,\n}: MobileNavHeaderProps) {\n const mark =\n logo ??\n (onMenuClick ? (\n <FairmintLogo\n width={MOBILE_NAV_LOGO_WIDTH}\n height={MOBILE_NAV_LOGO_HEIGHT}\n style={{ display: \"block\" }}\n />\n ) : null);\n\n return (\n <Group\n h={MOBILE_NAV_HEADER_HEIGHT}\n px={MOBILE_NAV_HEADER_PADDING_X}\n justify=\"space-between\"\n wrap=\"nowrap\"\n align=\"center\"\n gap={0}\n
|
|
1
|
+
{"version":3,"file":"MobileNavHeader.cjs","sources":["../../../../src/components/layout/MobileNav/MobileNavHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { colors } from \"../../../theme\";\nimport { FairmintLogo } from \"../../FairmintLogo/FairmintLogo\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Group } from \"../../primitives/layout\";\n\n/** Product-shell mobile header height (Studio + Investor). */\nexport const MOBILE_NAV_HEADER_HEIGHT = 60;\n/** Fairmint wordmark width in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_WIDTH = 120;\n/** Fairmint wordmark height in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_HEIGHT = 28;\n/** Space between the wordmark and the menu control. */\nexport const MOBILE_NAV_BRAND_GAP = 16;\n/** Header horizontal padding. */\nexport const MOBILE_NAV_HEADER_PADDING_X = 16;\n/** Menu control hit target (Mantine `lg`). */\nexport const MOBILE_NAV_MENU_SIZE = 36;\n\nconst defaultMenuIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6h16\" />\n <path d=\"M4 12h16\" />\n <path d=\"M4 18h16\" />\n </svg>\n);\n\nexport interface MobileNavHeaderProps {\n /**\n * Override the default Fairmint wordmark (white-label portals).\n * When omitted and `onMenuClick` is set, the canonical 120×28 Fairmint logo is used.\n */\n logo?: ReactNode;\n /** Opens the MobileNav sheet. Omit on desktop where SideNav owns destinations. */\n onMenuClick?: () => void;\n /** Right-aligned header actions (notifications, Ask AI). */\n rightSection?: ReactNode;\n /** Menu glyph. Defaults to an outlined hamburger so the component never imports an icon library. */\n menuIcon?: ReactNode;\n}\n\n/**\n * Canonical mobile page header for Fairmint product shells.\n *\n * Logo then hamburger at a 16px gap, optional actions on the far right.\n * Pixel metrics are fixed so Studio and Investor cannot drift via theme tokens\n * or extra wrappers.\n */\nexport function MobileNavHeader({\n logo,\n onMenuClick,\n rightSection,\n menuIcon,\n}: MobileNavHeaderProps) {\n const mark =\n logo ??\n (onMenuClick ? (\n <FairmintLogo\n width={MOBILE_NAV_LOGO_WIDTH}\n height={MOBILE_NAV_LOGO_HEIGHT}\n style={{ display: \"block\" }}\n />\n ) : null);\n\n return (\n <Group\n h={MOBILE_NAV_HEADER_HEIGHT}\n px={MOBILE_NAV_HEADER_PADDING_X}\n justify=\"space-between\"\n wrap=\"nowrap\"\n align=\"center\"\n gap={0}\n w=\"100%\"\n bg=\"body\"\n >\n <Group wrap=\"nowrap\" gap={MOBILE_NAV_BRAND_GAP} align=\"center\">\n {mark}\n {onMenuClick ? (\n <ActionIcon\n type=\"button\"\n aria-label=\"Open navigation\"\n color={colors.neutral}\n variant=\"subtle\"\n w={MOBILE_NAV_MENU_SIZE}\n h={MOBILE_NAV_MENU_SIZE}\n onClick={onMenuClick}\n >\n {menuIcon ?? defaultMenuIcon}\n </ActionIcon>\n ) : null}\n </Group>\n {rightSection}\n </Group>\n );\n}\n"],"names":["jsxs","jsx","FairmintLogo","Group","ActionIcon","colors"],"mappings":";;;;;;;AAOO,MAAM,2BAA2B;AAEjC,MAAM,wBAAwB;AAE9B,MAAM,yBAAyB;AAE/B,MAAM,uBAAuB;AAE7B,MAAM,8BAA8B;AAEpC,MAAM,uBAAuB;AAEpC,MAAM,kBACJA,2BAAAA;AAAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,QAAO;AAAA,IACP,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAY;AAAA,IACZ,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,eAAY;AAAA,IAEZ,UAAA;AAAA,MAAAC,2BAAAA,IAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,MAClBA,2BAAAA,IAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,MACnBA,2BAAAA,IAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,IAAA;AAAA,EAAA;AACrB;AAwBK,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,OACJ,SACC,cACCA,2BAAAA;AAAAA,IAACC,aAAAA;AAAAA,IAAA;AAAA,MACC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,EAAE,SAAS,QAAA;AAAA,IAAQ;AAAA,EAAA,IAE1B;AAEN,SACEF,2BAAAA;AAAAA,IAACG,MAAAA;AAAAA,IAAA;AAAA,MACC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,KAAK;AAAA,MACL,GAAE;AAAA,MACF,IAAG;AAAA,MAEH,UAAA;AAAA,QAAAH,gCAACG,MAAAA,SAAM,MAAK,UAAS,KAAK,sBAAsB,OAAM,UACnD,UAAA;AAAA,UAAA;AAAA,UACA,cACCF,2BAAAA;AAAAA,YAACG,WAAAA;AAAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAW;AAAA,cACX,OAAOC,OAAAA,OAAO;AAAA,cACd,SAAQ;AAAA,cACR,GAAG;AAAA,cACH,GAAG;AAAA,cACH,SAAS;AAAA,cAER,UAAA,YAAY;AAAA,YAAA;AAAA,UAAA,IAEb;AAAA,QAAA,GACN;AAAA,QACC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileNavHeader.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/MobileNav/MobileNavHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,iCAAiC;AACjC,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C,8CAA8C;AAC9C,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAoBvC,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,EAAE,oBAAoB,+
|
|
1
|
+
{"version":3,"file":"MobileNavHeader.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/MobileNav/MobileNavHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,iCAAiC;AACjC,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C,8CAA8C;AAC9C,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAoBvC,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,EAAE,oBAAoB,+BAyCtB"}
|
|
@@ -51,7 +51,8 @@ function MobileNavHeader({
|
|
|
51
51
|
wrap: "nowrap",
|
|
52
52
|
align: "center",
|
|
53
53
|
gap: 0,
|
|
54
|
-
|
|
54
|
+
w: "100%",
|
|
55
|
+
bg: "body",
|
|
55
56
|
children: [
|
|
56
57
|
/* @__PURE__ */ jsxs(Group, { wrap: "nowrap", gap: MOBILE_NAV_BRAND_GAP, align: "center", children: [
|
|
57
58
|
mark,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileNavHeader.js","sources":["../../../../src/components/layout/MobileNav/MobileNavHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { colors } from \"../../../theme\";\nimport { FairmintLogo } from \"../../FairmintLogo/FairmintLogo\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Group } from \"../../primitives/layout\";\n\n/** Product-shell mobile header height (Studio + Investor). */\nexport const MOBILE_NAV_HEADER_HEIGHT = 60;\n/** Fairmint wordmark width in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_WIDTH = 120;\n/** Fairmint wordmark height in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_HEIGHT = 28;\n/** Space between the wordmark and the menu control. */\nexport const MOBILE_NAV_BRAND_GAP = 16;\n/** Header horizontal padding. */\nexport const MOBILE_NAV_HEADER_PADDING_X = 16;\n/** Menu control hit target (Mantine `lg`). */\nexport const MOBILE_NAV_MENU_SIZE = 36;\n\nconst defaultMenuIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6h16\" />\n <path d=\"M4 12h16\" />\n <path d=\"M4 18h16\" />\n </svg>\n);\n\nexport interface MobileNavHeaderProps {\n /**\n * Override the default Fairmint wordmark (white-label portals).\n * When omitted and `onMenuClick` is set, the canonical 120×28 Fairmint logo is used.\n */\n logo?: ReactNode;\n /** Opens the MobileNav sheet. Omit on desktop where SideNav owns destinations. */\n onMenuClick?: () => void;\n /** Right-aligned header actions (notifications, Ask AI). */\n rightSection?: ReactNode;\n /** Menu glyph. Defaults to an outlined hamburger so the component never imports an icon library. */\n menuIcon?: ReactNode;\n}\n\n/**\n * Canonical mobile page header for Fairmint product shells.\n *\n * Logo then hamburger at a 16px gap, optional actions on the far right.\n * Pixel metrics are fixed so Studio and Investor cannot drift via theme tokens\n * or extra wrappers.\n */\nexport function MobileNavHeader({\n logo,\n onMenuClick,\n rightSection,\n menuIcon,\n}: MobileNavHeaderProps) {\n const mark =\n logo ??\n (onMenuClick ? (\n <FairmintLogo\n width={MOBILE_NAV_LOGO_WIDTH}\n height={MOBILE_NAV_LOGO_HEIGHT}\n style={{ display: \"block\" }}\n />\n ) : null);\n\n return (\n <Group\n h={MOBILE_NAV_HEADER_HEIGHT}\n px={MOBILE_NAV_HEADER_PADDING_X}\n justify=\"space-between\"\n wrap=\"nowrap\"\n align=\"center\"\n gap={0}\n
|
|
1
|
+
{"version":3,"file":"MobileNavHeader.js","sources":["../../../../src/components/layout/MobileNav/MobileNavHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { colors } from \"../../../theme\";\nimport { FairmintLogo } from \"../../FairmintLogo/FairmintLogo\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Group } from \"../../primitives/layout\";\n\n/** Product-shell mobile header height (Studio + Investor). */\nexport const MOBILE_NAV_HEADER_HEIGHT = 60;\n/** Fairmint wordmark width in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_WIDTH = 120;\n/** Fairmint wordmark height in the mobile header and sheet. */\nexport const MOBILE_NAV_LOGO_HEIGHT = 28;\n/** Space between the wordmark and the menu control. */\nexport const MOBILE_NAV_BRAND_GAP = 16;\n/** Header horizontal padding. */\nexport const MOBILE_NAV_HEADER_PADDING_X = 16;\n/** Menu control hit target (Mantine `lg`). */\nexport const MOBILE_NAV_MENU_SIZE = 36;\n\nconst defaultMenuIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6h16\" />\n <path d=\"M4 12h16\" />\n <path d=\"M4 18h16\" />\n </svg>\n);\n\nexport interface MobileNavHeaderProps {\n /**\n * Override the default Fairmint wordmark (white-label portals).\n * When omitted and `onMenuClick` is set, the canonical 120×28 Fairmint logo is used.\n */\n logo?: ReactNode;\n /** Opens the MobileNav sheet. Omit on desktop where SideNav owns destinations. */\n onMenuClick?: () => void;\n /** Right-aligned header actions (notifications, Ask AI). */\n rightSection?: ReactNode;\n /** Menu glyph. Defaults to an outlined hamburger so the component never imports an icon library. */\n menuIcon?: ReactNode;\n}\n\n/**\n * Canonical mobile page header for Fairmint product shells.\n *\n * Logo then hamburger at a 16px gap, optional actions on the far right.\n * Pixel metrics are fixed so Studio and Investor cannot drift via theme tokens\n * or extra wrappers.\n */\nexport function MobileNavHeader({\n logo,\n onMenuClick,\n rightSection,\n menuIcon,\n}: MobileNavHeaderProps) {\n const mark =\n logo ??\n (onMenuClick ? (\n <FairmintLogo\n width={MOBILE_NAV_LOGO_WIDTH}\n height={MOBILE_NAV_LOGO_HEIGHT}\n style={{ display: \"block\" }}\n />\n ) : null);\n\n return (\n <Group\n h={MOBILE_NAV_HEADER_HEIGHT}\n px={MOBILE_NAV_HEADER_PADDING_X}\n justify=\"space-between\"\n wrap=\"nowrap\"\n align=\"center\"\n gap={0}\n w=\"100%\"\n bg=\"body\"\n >\n <Group wrap=\"nowrap\" gap={MOBILE_NAV_BRAND_GAP} align=\"center\">\n {mark}\n {onMenuClick ? (\n <ActionIcon\n type=\"button\"\n aria-label=\"Open navigation\"\n color={colors.neutral}\n variant=\"subtle\"\n w={MOBILE_NAV_MENU_SIZE}\n h={MOBILE_NAV_MENU_SIZE}\n onClick={onMenuClick}\n >\n {menuIcon ?? defaultMenuIcon}\n </ActionIcon>\n ) : null}\n </Group>\n {rightSection}\n </Group>\n );\n}\n"],"names":[],"mappings":";;;;;AAOO,MAAM,2BAA2B;AAEjC,MAAM,wBAAwB;AAE9B,MAAM,yBAAyB;AAE/B,MAAM,uBAAuB;AAE7B,MAAM,8BAA8B;AAEpC,MAAM,uBAAuB;AAEpC,MAAM,kBACJ;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,QAAO;AAAA,IACP,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAY;AAAA,IACZ,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,eAAY;AAAA,IAEZ,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,MAClB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,MACnB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,IAAA;AAAA,EAAA;AACrB;AAwBK,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,OACJ,SACC,cACC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,EAAE,SAAS,QAAA;AAAA,IAAQ;AAAA,EAAA,IAE1B;AAEN,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,KAAK;AAAA,MACL,GAAE;AAAA,MACF,IAAG;AAAA,MAEH,UAAA;AAAA,QAAA,qBAAC,SAAM,MAAK,UAAS,KAAK,sBAAsB,OAAM,UACnD,UAAA;AAAA,UAAA;AAAA,UACA,cACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAW;AAAA,cACX,OAAO,OAAO;AAAA,cACd,SAAQ;AAAA,cACR,GAAG;AAAA,cACH,GAAG;AAAA,cACH,SAAS;AAAA,cAER,UAAA,YAAY;AAAA,YAAA;AAAA,UAAA,IAEb;AAAA,QAAA,GACN;AAAA,QACC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP;"}
|